aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Benedict Torvalds <torvalds@klaava.Helsinki.FI>1992-03-08 14:43:12 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:02 -0400
commit741d52384b75d810b8a04d7f16733b9a6ff809a5 (patch)
tree0c1c295237dfd711541e0a70bebfc4a7823d6da1
parent26d73589f54a0ffa39ca6b16cfe4a46a63f6b781 (diff)
downloadarchive-741d52384b75d810b8a04d7f16733b9a6ff809a5.tar.gz
Linux-0.95v0.95
All right: it's three days late, but finally 0.95 has been sent to nic.funet.fi. As usual, it will probably take a few days to find it's way into a readable directory, so don't start ftp'ing right now. I'm sure arl will inform people when it's available. I'm also pretty sure there will be problems setting things up again: some things have changed, and the docs are up to their usual wonderful standard. For people that have used 0.12, there shouldn't be too many surprises, although the new harddisk names/numbers can be confusing. Many bugs have been corrected, but there are probably new ones that have taken their place. One bad thing with the new setup (which will confuse new users) is that the rootdisk finally got too small for everything, and compress+tar aren't on the disk any more. Talk about confusing, but if you have 0.12 installed on your system, everything should be mostly a case of "boot from floppy, drop in the new things, and reboot with the harddisk". Re: patches. There were 5 major patches (VC's, VFS, swapon, ptrace and faster floppies) that were installed, and of these only ptrace and VC's got installed without any major changes (pmacdona has had three releases to learn my coding style, and it seems to have paid off :). The other patches are so heavily edited as to be totally unrecognizeable, and I expect my changes weren't always for the better: but I'd rather be over-conservative than use a patch even if it's great. I expect they will still have to be edited, and hope none of the authors mind me changing their code heavily (sorry also to all those that have used the VFS routines: they'll have to wait for the next release before getting all the functionality in the alpha-VFS patches.) Re: recompiling the kernel. I've used most of the last week to make the kernel compileable by gcc-2, as that is what I use now. The bootimage I've made available is compiled totally with 2.0, and the source-files are set up for that compiler. For people without gcc-2, the kernel can still be compiled with 1.40, but you'll have to add the flag -fcombine-regs to some makefiles (without it gcc-1.40 runs out of registers, and aborts). I'm including the file RELNOTES-0.95, which is just the old 0.12 RELNOTES edited for a new release. I'm lazy. Linus ============================== RELEASE NOTES FOR LINUX v0.95 Linus Torvalds, March 7, 1992 This is file mostly contains info on changed features of Linux, and using old versions as a help-reference might be a good idea. COPYRIGHT Linux-0.95 is NOT public domain software, but is copyrighted by me. The copyright conditions are the same as those imposed by the GNU copyleft: get a copy of the GNU copyleft at any major ftp-site (if it carries linux, it probably carries a lot of GNU software anyway, and they all contain the copyright). The copyleft is pretty detailed, but it mostly just means that you may freely copy linux for your own use, and redistribute all/parts of it, as long as you make source available (not necessarily in the same distribution, but you make it clear how people can get it for nothing more than copying costs). Any changes you make that you distribute will also automatically fall under the GNU copyleft. NOTE! The linux unistd library-functions (the low-level interface to linux: system calls etc) are excempt from the copyright - you may use them as you wish, and using those in your binary files won't mean that your files are automatically under the GNU copyleft. This concerns /only/ the unistd-library and those (few) other library functions I have written: most of the rest of the library has it's own copyrights (or is public domain). See the library sources for details of those. INSTALLATION This is a SHORT install-note. The installation is very similar to 0.11 and 0.12, so you should read INSTALL-0.11 too. There are a couple of programs you will need to install linux: something that writes disk images (rawrite.exe or NU or...) and something that can create harddisk partitions (fdisk under xenix or older versions of dos, edpart.exe or something like that). NOTE! Repartitioning your harddisk will destroy all data on it (well, not exactly, but if you know enough to get back the data you probably didn't need this warning). So be careful. READ THIS THROUGH, THEN READ INSTALL-0.11, AND IF YOU ARE SURE YOU KNOW WHAT YOU ARE DOING, CONTINUE. OTHERWISE, PANIC. OR WRITE ME FOR EXPLANATIONS. OR DO ANYTHING BUT INSTALL LINUX - IT'S VERY SIMPLE, BUT IF YOU DON'T KNOW WHAT YOU ARE DOING YOU'LL PROBABLY BE SORRY. I'D RATHER ANSWER A FEW UNNECESSARY MAILS THAN GET MAIL SAYING "YOU KILLED MY HARDDISK, BASTARD. I'M GOING TO FIND YOU, AND YOU'LL BE SORRY WHEN I DO". Minumum files needed: RELNOTES-0.95 (this file) INSTALL-0.11 (+ any other docs you might find: the FAQ etc) bootimage-0.96.Z rootimage-0.95.Z rootimage-0.12.Z (for tar+compress) rawrite.exe some disk partitioner 1) back up everything you have on your harddisk - linux-0.95 is still in beta and might do weird things. The only thing I guarantee is that it has worked fine on /my/ machine - for all I know it might eat your harddisk and spit it out in small pieces on any other hardware. 2) Test out the linux boot-disk with the root file system. If it doesn't work, check the hardware requirements, and mail me if you still think it should work. I might not be able to help you, but your bug-report would still be appreciated. Linux-0.95 now has an init/login: there should be 4 logins started on the first 4 virtual consoles. Log in as root (no password), and test it out. Change to the other logins by pressing left-alt + FN[1-4]. Note that booting up with a floppy as root is S..L..O..W.. - the floppy driver has been optimized for sequential access (backups etc), and trashes somewhat with demand-loading. Test that linux can read your harddisk at least partly: run the fdisk program on the root-disk, and see if it barfs. If it tells you about any partitions at all, linux can successfully read at least part of your harddisk. NOTE! Harddisk device names and numbers have changed between versions 0.12 and 0.95: the new numbering system was needed for the extended partitions, and a new naming scheme was in order so that people wouldn't cunfuse the old devices with the new ones. The new harddisk device names are: /dev/hd followed by an 'a' for the first drive, or a 'b' for the second one. After that comes the partition number, 1-4 for the primary partitions, 5- for possible extended partitions. No number means the complete disk. Like this: /dev/hda the whole first harddisk (old: /dev/hd0) /dev/hdb3 partition nr 3 on the second disk (old: /dev/hd8) 3) Make sure that you have a free /primary/ partition. There can be 4 primary partitions per drive: newer DOS fdisks seem to be able to create only 2 (one primary and one extended). In that case use some other partitioning software: edpart.exe etc. Linux fdisk currently only tells you the partition info - it doesn't write to the disk. Remember to check how big your partition was, as that can be used to tell which device Linux thinks it is. NOTE! Linux-0.95 /might/ recognize extended partitions: but the code for this is utterly untested, as I don't have any of those. Do NOT use the extended partitions unless you can verify that they are indeed correctly set up - if my routines are wrong, writing to the extended partitions might just overwrite some other partition instead. Not nice. 4) Boot up linux again, fdisk to make sure you now have the new partition, and use mkfs to make a filesystem on one of the partitions fdisk reports. Write "mkfs -c /dev/hdX nnn" where X is the device number reported by linux fdisk, and nnn is the size - also reported by fdisk. nnn is the size in /blocks/, ie kilobytes. You should be able to use the size info to determine which partition is represented by which device name. 5) Mount the new disk partition: "mount /dev/hdX /mnt". Copy over the root filesystem to the harddisk, eg like this: # for i in bin dev etc usr tmp # do # cp +recursive /$i /mnt # done You caanot use just "cp +recursive / /mnt", as that will result in a loop. 6) Sync the filesystem after you have played around enough, and reboot. # sync # lo (none) login: sync <wait for it to sync> ctrl-alt-del THIS IS IMPORTANT! NEVER EVER FORGET TO SYNC BEFORE KILLING THE MACHINE. 7) Change the bootdisk to understand which partition it should use as a root filesystem. See INSTALL-0.11: it's still the word at offset 508 into the image. You should be up and running. 8) When you've successfully started up with your harddisk as root, you can mount the older rootimage (rootimage-0.12) from a floppy, and copy over any files you find there that weren't on the newer root-image. Mounting a floppy is easy: make the directory /floppy, and write: # mount /dev/PS0 /floppy (if you have a 3.5" drive) or # mount /dev/at0 /floppy (for 5.25" floppies) After that the files can be copied to your harddisk, eg: # cp /floppy/usr/bin/compress /usr/bin # ln -s /usr/bin/compress /usr/bin/compress # cp /floppy/usr/bin/tar.Z /usr/bin # uncompress /usr/bin/tar.Z That's it. Now go back and read the INSTALL-0.11, until you are sure you know what you are doing. New features of 0.95, in order of appearance (ie in the order you see them) Init/login Yeah, thanks to poe (Peter Orbaeck (sp?)), linux now boots up like a real unix with a login-prompt. Login as root (no passwd), and change your /etc/passwd to your hearts delight (and add other logins in /etc/inittab etc). Bash is even bigger It's really a bummer to boot up from floppies: bash takes a long time to load. Bash is also now so big that I couldn't fit compress and tar onto the root-floppy: You'll probably want the old rootimage-0.12 just in order to get tar+compress onto your harddisk. If anybody has pointers to a simple shell that is freely distributable, it might be a good idea to use that for the root-diskette. Especially with a small buffer-cache, things aren't fun. Don't worry: linux runs much better on a harddisk. Virtual consoles on any (?) hardware. You can select one of several consoles by pressing the left alt-key and a function key at the same time. Linux should report the number of virtual consoles available upon bootup. /dev/tty0 is now "the current" screen, /dev/tty1 is the main console, and /dev/tty2-8 can exist depending on your text-mode or card. The virtual consoles also have some new screen-handling commands: they confirm better to vt200 control codes. Special graphic characters, and the PF1-4 keys work somewhat in the application-key mode. Symbolic links. 0.95 now allows symlinks to point to other symlinks etc (the maximum depth is a rather arbitrary 5 links). 0.12 didn't like more than one level of indirection. Virtual memory. VM under 0.95 should be better than under 0.12: no more lockups (as far as I have seen), and you can now swap to the filesystem as well as to a special partition. There are two programs to handle this: mkswap to set up a swap-file/partition and swapon to start up swapping. mkswap needs either a partition or a file that already exists to make a swap-area. To make a swap-file, do this: # dd bs=1024 count=NN if=/dev/hda of=swapfile # mkswap swapfile NN The first command just makes a file that is NN blocks long (initializing it from /dev/hda, but that could be anything). The second command then writes the necessary setup-info into the file. To start swapping, write # swapon swapfile NOTE! 'dd' isn't on the rootdisk: you have to install some things onto the harddisk before you can get up and running. NOTE2! When linux runs totally out of virtual memory, things slow down dramatically. It tries to keep on running as long as it can, but at least it shouldn't lock up any more. ^C should work, although you might have to wait a while for it.. Faster floppies Ok, you don't notice this much when booting up from a floppy: bash has grown, so it takes longer to load, and the optimizations work mostly with sequential accesses. When you start un-taring floppies to get the programs onto your harddisk, you'll notice that it's much faster now. That should be about the only use for floppies under a unix: nobody in their right mind uses floppies as filesystems. Better FS-independence Hopefully you'll never even notice this, but the filesystem has been partly rewritten to make it less minix-fs-specific. I haven't implemented all the VFS-patches I got, so it's still not ready, but it's getting there, slowly. And that's it, I think. Happy hacking. Linus (torvalds@kruuna.helsinki.fi)
-rw-r--r--Makefile34
-rw-r--r--boot/bootsect.S2
-rw-r--r--boot/head.s53
-rw-r--r--boot/setup.S13
-rw-r--r--fs/Makefile55
-rw-r--r--fs/block_dev.c28
-rw-r--r--fs/buffer.c105
-rw-r--r--fs/char_dev.c56
-rw-r--r--fs/exec.c24
-rw-r--r--fs/fcntl.c6
-rw-r--r--fs/inode.c226
-rw-r--r--fs/ioctl.c4
-rw-r--r--fs/minix/Makefile69
-rw-r--r--fs/minix/bitmap.c184
-rw-r--r--fs/minix/file_dev.c105
-rw-r--r--fs/minix/inode.c145
-rw-r--r--fs/minix/minix_op.c38
-rw-r--r--fs/minix/namei.c795
-rw-r--r--fs/minix/truncate.c154
-rw-r--r--fs/namei.c758
-rw-r--r--fs/open.c71
-rw-r--r--fs/pipe.c25
-rw-r--r--fs/read_write.c74
-rw-r--r--fs/select.c22
-rw-r--r--fs/stat.c40
-rw-r--r--fs/super.c68
-rw-r--r--include/asm/io.h45
-rw-r--r--include/asm/segment.h12
-rw-r--r--include/asm/system.h10
-rw-r--r--include/errno.h1
-rw-r--r--include/fcntl.h2
-rw-r--r--include/linux/config.h11
-rw-r--r--include/linux/fs.h133
-rw-r--r--include/linux/hdreg.h18
-rw-r--r--include/linux/kernel.h9
-rw-r--r--include/linux/math_emu.h19
-rw-r--r--include/linux/minix_fs.h78
-rw-r--r--include/linux/mm.h12
-rw-r--r--include/linux/sched.h55
-rw-r--r--include/linux/sys.h4
-rw-r--r--include/linux/timer.h44
-rw-r--r--include/linux/tty.h8
-rw-r--r--include/signal.h20
-rw-r--r--include/string.h32
-rw-r--r--include/sys/ptrace.h52
-rw-r--r--include/sys/time.h1
-rw-r--r--include/sys/types.h3
-rw-r--r--include/termios.h1
-rw-r--r--include/time.h2
-rw-r--r--include/unistd.h29
-rw-r--r--init/main.c20
-rw-r--r--kernel/Makefile32
-rw-r--r--kernel/asm.s107
-rw-r--r--kernel/blk_drv/Makefile23
-rw-r--r--kernel/blk_drv/blk.h17
-rw-r--r--kernel/blk_drv/floppy.c125
-rw-r--r--kernel/blk_drv/hd.c107
-rw-r--r--kernel/blk_drv/ll_rw_blk.c82
-rw-r--r--kernel/blk_drv/ramdisk.c5
-rw-r--r--kernel/chr_drv/Makefile25
-rw-r--r--kernel/chr_drv/console.c457
-rw-r--r--kernel/chr_drv/keyboard.S348
-rw-r--r--kernel/chr_drv/rs_io.s11
-rw-r--r--kernel/chr_drv/serial.c56
-rw-r--r--kernel/chr_drv/tty_io.c80
-rw-r--r--kernel/chr_drv/tty_ioctl.c130
-rw-r--r--kernel/exit.c81
-rw-r--r--kernel/fork.c53
-rw-r--r--kernel/math/Makefile47
-rw-r--r--kernel/math/convert.c73
-rw-r--r--kernel/math/error.c2
-rw-r--r--kernel/math/get_put.c2
-rw-r--r--kernel/math/math_emulate.c30
-rw-r--r--kernel/math/mul.c2
-rw-r--r--kernel/ptrace.c322
-rw-r--r--kernel/sched.c71
-rw-r--r--kernel/signal.c25
-rw-r--r--kernel/sys.c48
-rw-r--r--kernel/sys_call.s168
-rw-r--r--kernel/traps.c28
-rw-r--r--lib/Makefile13
-rw-r--r--lib/_exit.c3
-rw-r--r--lib/open.c5
-rw-r--r--mm/Makefile20
-rw-r--r--mm/memory.c185
-rw-r--r--mm/swap.c165
-rw-r--r--tools/build.c38
87 files changed, 4667 insertions, 2094 deletions
diff --git a/Makefile b/Makefile
index 1cb2861..8bedb81 100644
--- a/Makefile
+++ b/Makefile
@@ -2,31 +2,30 @@
# if you want the ram-disk device, define this to be the
# size in blocks.
#
-RAMDISK = #-DRAMDISK=512
+#RAMDISK = -DRAMDISK=512
AS86 =as86 -0 -a
LD86 =ld86 -0
-AS =gas
-LD =gld
+AS =as
+LD =ld
LDFLAGS =-s -x -M
CC =gcc $(RAMDISK)
-CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \
--fcombine-regs -mstring-insns
+CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer
CPP =cpp -nostdinc -Iinclude
#
# ROOT_DEV specifies the default root-device when making the image.
# This can be either FLOPPY, /dev/xxxx or empty, in which case the
-# default of /dev/hd6 is used by 'build'.
+# default of FLOPPY is used by 'build'.
#
-ROOT_DEV=/dev/hd6
-SWAP_DEV=/dev/hd2
+ROOT_DEV=/dev/hdb1
-ARCHIVES=kernel/kernel.o mm/mm.o fs/fs.o
-DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a
-MATH =kernel/math/math.a
-LIBS =lib/lib.a
+ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o
+FILESYSTEMS =fs/minix/minix.o
+DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a
+MATH =kernel/math/math.a
+LIBS =lib/lib.a
.c.s:
$(CC) $(CFLAGS) \
@@ -40,8 +39,7 @@ LIBS =lib/lib.a
all: Image
Image: boot/bootsect boot/setup tools/system tools/build
- tools/build boot/bootsect boot/setup tools/system $(ROOT_DEV) \
- $(SWAP_DEV) > Image
+ tools/build boot/bootsect boot/setup tools/system $(ROOT_DEV) > Image
sync
disk: Image
@@ -54,9 +52,10 @@ tools/build: tools/build.c
boot/head.o: boot/head.s
tools/system: boot/head.o init/main.o \
- $(ARCHIVES) $(DRIVERS) $(MATH) $(LIBS)
+ $(ARCHIVES) $(FILESYSTEMS) $(DRIVERS) $(MATH) $(LIBS)
$(LD) $(LDFLAGS) boot/head.o init/main.o \
$(ARCHIVES) \
+ $(FILESYSTEMS) \
$(DRIVERS) \
$(MATH) \
$(LIBS) \
@@ -80,6 +79,9 @@ mm/mm.o:
fs/fs.o:
(cd fs; make)
+fs/minix/minix.o:
+ (cd fs/minix; make)
+
lib/lib.a:
(cd lib; make)
@@ -99,7 +101,7 @@ boot/bootsect: boot/bootsect.s
clean:
rm -f Image System.map tmp_make core boot/bootsect boot/setup \
- boot/bootsect.s boot/setup.s
+ boot/bootsect.s boot/setup.s init/main.s
rm -f init/*.o tools/system tools/build boot/*.o
(cd mm;make clean)
(cd fs;make clean)
diff --git a/boot/bootsect.S b/boot/bootsect.S
index 1df6c23..8a8ecb8 100644
--- a/boot/bootsect.S
+++ b/boot/bootsect.S
@@ -53,6 +53,7 @@ start:
mov cx,#256
sub si,si
sub di,di
+ cld
rep
movw
jmpi go,INITSEG
@@ -83,7 +84,6 @@ go: mov ax,cs
* fs = 0, gs = parameter table segment
*/
-
push #0
pop fs
mov bx,#0x78 ! fs:bx is parameter table address
diff --git a/boot/head.s b/boot/head.s
index de56a74..0377139 100644
--- a/boot/head.s
+++ b/boot/head.s
@@ -12,9 +12,10 @@
* the page directory.
*/
.text
-.globl _idt,_gdt,_pg_dir,_tmp_floppy_area
+.globl _idt,_gdt,_pg_dir,_tmp_floppy_area,_floppy_track_buffer
_pg_dir:
startup_32:
+ cld
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
@@ -34,17 +35,39 @@ startup_32:
movl %eax,0x000000 # loop forever if it isn't
cmpl %eax,0x100000
je 1b
+/* check if it is 486 or 386. */
+ movl %esp,%edi # save stack pointer
+ andl $0xfffffffc,%esp # align stack to avoid AC fault
+ pushfl # push EFLAGS
+ popl %eax # get EFLAGS
+ movl %eax,%ecx # save original EFLAGS
+ xorl $0x40000,%eax # flip AC bit in EFLAGS
+ pushl %eax # copy to EFLAGS
+ popfl # set EFLAGS
+ pushfl # get new EFLAGS
+ popl %eax # put it in eax
+ xorl %ecx,%eax # check if AC bit is changed. zero is 486.
+ jz 1f # 486
+ pushl %ecx # restore original EFLAGS
+ popfl
+ movl %edi,%esp # restore esp
+ movl %cr0,%eax # 386
+ andl $0x80000011,%eax # Save PG,PE,ET
+ orl $2,%eax # set MP
+ jmp 2f
/*
* NOTE! 486 should set bit 16, to check for write-protect in supervisor
* mode. Then it would be unnecessary with the "verify_area()"-calls.
* 486 users probably want to set the NE (#5) bit also, so as to use
* int 16 for math errors.
*/
- movl %cr0,%eax # check math chip
+1: pushl %ecx # restore original EFLAGS
+ popfl
+ movl %edi,%esp # restore esp
+ movl %cr0,%eax # 486
andl $0x80000011,%eax # Save PG,PE,ET
-/* "orl $0x10020,%eax" here for 486 might be good */
- orl $2,%eax # set MP
- movl %eax,%cr0
+ orl $0x10022,%eax # set NE and MP
+2: movl %eax,%cr0
call check_x87
jmp after_page_tables
@@ -55,8 +78,8 @@ check_x87:
fninit
fstsw %ax
cmpb $0,%al
- je 1f /* no coprocessor: have to set bits */
- movl %cr0,%eax
+ je 1f
+ movl %cr0,%eax /* no coprocessor: have to set bits */
xorl $6,%eax /* reset MP, set EM */
movl %eax,%cr0
ret
@@ -131,14 +154,22 @@ pg3:
*/
_tmp_floppy_area:
.fill 1024,1,0
+/*
+ * floppy_track_buffer is used to buffer one track of floppy data: it
+ * has to be separate from the tmp_floppy area, as otherwise a single-
+ * sector read/write can mess it up. It can contain one full track of
+ * data (18*2*512 bytes).
+ */
+_floppy_track_buffer:
+ .fill 512*2*18,1,0
after_page_tables:
+ call setup_paging
pushl $0 # These are the parameters to main :-)
pushl $0
pushl $0
- pushl $L6 # return address for main, if it decides to.
- pushl $_main
- jmp setup_paging
+ cld # gcc2 wants the direction flag cleared at all times
+ call _start_kernel
L6:
jmp L6 # main should never return here, but
# just in case, we know what happens.
@@ -148,6 +179,7 @@ int_msg:
.asciz "Unknown interrupt\n\r"
.align 2
ignore_int:
+ cld
pushl %eax
pushl %ecx
pushl %edx
@@ -210,6 +242,7 @@ setup_paging:
1: stosl /* fill pages backwards - more efficient :-) */
subl $0x1000,%eax
jge 1b
+ cld
xorl %eax,%eax /* pg_dir is at 0x0000 */
movl %eax,%cr3 /* cr3 - page directory start */
movl %cr0,%eax
diff --git a/boot/setup.S b/boot/setup.S
index 093f96c..1befd14 100644
--- a/boot/setup.S
+++ b/boot/setup.S
@@ -77,6 +77,7 @@ novga: mov [14],ax
mov es,ax
mov di,#0x0080
mov cx,#0x10
+ cld
rep
movsb
@@ -89,6 +90,7 @@ novga: mov [14],ax
mov es,ax
mov di,#0x0090
mov cx,#0x10
+ cld
rep
movsb
@@ -106,6 +108,7 @@ no_disk1:
mov di,#0x0090
mov cx,#0x10
mov ax,#0x00
+ cld
rep
stosb
is_disk1:
@@ -220,6 +223,10 @@ chsvga: cld
mov es,ax
lea si,msg1
call prtstr
+flush: in al,#0x60 ! Flush the keyboard buffer
+ cmp al,#0x82
+ jb nokey
+ jmp flush
nokey: in al,#0x60
cmp al,#0x82
jb nokey
@@ -230,7 +237,8 @@ nokey: in al,#0x60
mov ax,#0x5019
pop ds
ret
-svga: lea si,idati ! Check ATI 'clues'
+svga: cld
+ lea si,idati ! Check ATI 'clues'
mov di,#0x31
mov cx,#0x09
repe
@@ -354,7 +362,8 @@ l1: inc si
lea di,mogenoa
lea cx,selmod
jmp cx
-nogen: lea si,idparadise ! Check Paradise 'clues'
+nogen: cld
+ lea si,idparadise ! Check Paradise 'clues'
mov di,#0x7d
mov cx,#0x04
repe
diff --git a/fs/Makefile b/fs/Makefile
index 96d8de1..55bcd62 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -1,9 +1,9 @@
-AR =gar
-AS =gas
+AR =ar
+AS =as
CC =gcc
-LD =gld
-CFLAGS =-Wall -O -fstrength-reduce -fcombine-regs -fomit-frame-pointer \
- -fno-defer-pop -mstring-insns -nostdinc -I../include
+LD =ld
+CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \
+ -fno-defer-pop -nostdinc -I../include
CPP =gcc -E -nostdinc -I../include
.c.s:
@@ -16,8 +16,8 @@ CPP =gcc -E -nostdinc -I../include
$(AS) -o $*.o $<
OBJS= open.o read_write.o inode.o file_table.o buffer.o super.o \
- block_dev.o char_dev.o file_dev.o stat.o exec.o pipe.o namei.o \
- bitmap.o fcntl.o ioctl.o truncate.o select.o
+ block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \
+ fcntl.o ioctl.o select.o
fs.o: $(OBJS)
$(LD) -r -o fs.o $(OBJS)
@@ -25,18 +25,15 @@ fs.o: $(OBJS)
clean:
rm -f core *.o *.a tmp_make
for i in *.c;do rm -f `basename $$i .c`.s;done
+ cd minix; make clean
dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
(for i in *.c;do $(CPP) -M $$i;done) >> tmp_make
cp tmp_make Makefile
+ cd minix; make dep
### Dependencies:
-bitmap.o : bitmap.c ../include/string.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
- ../include/sys/param.h ../include/sys/time.h ../include/time.h \
- ../include/sys/resource.h
block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
@@ -65,17 +62,13 @@ fcntl.o : fcntl.c ../include/string.h ../include/errno.h \
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/asm/segment.h \
../include/fcntl.h ../include/sys/stat.h
-file_dev.o : file_dev.c ../include/errno.h ../include/fcntl.h \
- ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \
- ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \
- ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
- ../include/time.h ../include/sys/resource.h ../include/asm/segment.h
file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h
inode.o : inode.c ../include/string.h ../include/sys/stat.h \
../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
- ../include/time.h ../include/sys/resource.h ../include/asm/system.h
+ ../include/time.h ../include/sys/resource.h ../include/linux/minix_fs.h \
+ ../include/asm/system.h
ioctl.o : ioctl.c ../include/string.h ../include/errno.h \
../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
@@ -85,20 +78,21 @@ namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
../include/sys/time.h ../include/time.h ../include/sys/resource.h \
- ../include/asm/segment.h ../include/string.h ../include/fcntl.h \
- ../include/errno.h ../include/const.h ../include/sys/stat.h
+ ../include/linux/minix_fs.h ../include/asm/segment.h ../include/string.h \
+ ../include/fcntl.h ../include/errno.h ../include/const.h \
+ ../include/sys/stat.h
open.o : open.c ../include/string.h ../include/errno.h ../include/fcntl.h \
../include/sys/types.h ../include/utime.h ../include/sys/stat.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
- ../include/sys/resource.h ../include/linux/tty.h ../include/termios.h \
- ../include/asm/segment.h
+ ../include/sys/resource.h ../include/asm/segment.h
pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \
- ../include/errno.h ../include/termios.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
- ../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \
- ../include/time.h ../include/sys/resource.h ../include/asm/segment.h
+ ../include/errno.h ../include/termios.h ../include/fcntl.h \
+ ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+ ../include/asm/segment.h
read_write.o : read_write.c ../include/sys/stat.h ../include/sys/types.h \
../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
@@ -120,10 +114,5 @@ super.o : super.c ../include/linux/config.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
- ../include/sys/resource.h ../include/asm/system.h ../include/errno.h \
- ../include/sys/stat.h
-truncate.o : truncate.c ../include/linux/sched.h ../include/linux/head.h \
- ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
- ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
- ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
- ../include/sys/stat.h
+ ../include/sys/resource.h ../include/linux/minix_fs.h \
+ ../include/asm/system.h ../include/errno.h ../include/sys/stat.h
diff --git a/fs/block_dev.c b/fs/block_dev.c
index af7cbda..e4a4e9e 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -13,23 +13,25 @@
extern int *blk_size[];
-int block_write(int dev, long * pos, char * buf, int count)
+int block_write(struct inode * inode, struct file * filp, char * buf, int count)
{
- int block = *pos >> BLOCK_SIZE_BITS;
- int offset = *pos & (BLOCK_SIZE-1);
+ int block = filp->f_pos >> BLOCK_SIZE_BITS;
+ int offset = filp->f_pos & (BLOCK_SIZE-1);
int chars;
int written = 0;
int size;
+ unsigned int dev;
struct buffer_head * bh;
register char * p;
+ dev = inode->i_rdev;
if (blk_size[MAJOR(dev)])
size = blk_size[MAJOR(dev)][MINOR(dev)];
else
size = 0x7fffffff;
while (count>0) {
if (block >= size)
- return written?written:-EIO;
+ return written;
chars = BLOCK_SIZE - offset;
if (chars > count)
chars=count;
@@ -42,7 +44,7 @@ int block_write(int dev, long * pos, char * buf, int count)
return written?written:-EIO;
p = offset + bh->b_data;
offset = 0;
- *pos += chars;
+ filp->f_pos += chars;
written += chars;
count -= chars;
while (chars-->0)
@@ -53,23 +55,25 @@ int block_write(int dev, long * pos, char * buf, int count)
return written;
}
-int block_read(int dev, unsigned long * pos, char * buf, int count)
+int block_read(struct inode * inode, struct file * filp, char * buf, int count)
{
- int block = *pos >> BLOCK_SIZE_BITS;
- int offset = *pos & (BLOCK_SIZE-1);
- int chars;
- int size;
+ unsigned int block = filp->f_pos >> BLOCK_SIZE_BITS;
+ unsigned int offset = filp->f_pos & (BLOCK_SIZE-1);
+ unsigned int chars;
+ unsigned int size;
+ unsigned int dev;
int read = 0;
struct buffer_head * bh;
register char * p;
+ dev = inode->i_rdev;
if (blk_size[MAJOR(dev)])
size = blk_size[MAJOR(dev)][MINOR(dev)];
else
size = 0x7fffffff;
while (count>0) {
if (block >= size)
- return read?read:-EIO;
+ return read;
chars = BLOCK_SIZE-offset;
if (chars > count)
chars = count;
@@ -78,7 +82,7 @@ int block_read(int dev, unsigned long * pos, char * buf, int count)
block++;
p = offset + bh->b_data;
offset = 0;
- *pos += chars;
+ filp->f_pos += chars;
read += chars;
count -= chars;
while (chars-->0)
diff --git a/fs/buffer.c b/fs/buffer.c
index f0f3fb3..2ece779 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -41,43 +41,39 @@ static inline void wait_on_buffer(struct buffer_head * bh)
sti();
}
-int sys_sync(void)
+static void sync_buffers(int dev)
{
int i;
struct buffer_head * bh;
- sync_inodes(); /* write out inodes into buffers */
- bh = start_buffer;
- for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
+ bh = free_list;
+ for (i=0 ; i<NR_BUFFERS ; i++,bh = bh->b_next_free) {
+#if 0
+ if (dev && (bh->b_dev != dev))
+ continue;
+#endif
wait_on_buffer(bh);
+#if 0
+ if (dev && (bh->b_dev != dev))
+ continue;
+#endif
if (bh->b_dirt)
ll_rw_block(WRITE,bh);
}
+}
+
+int sys_sync(void)
+{
+ sync_inodes(); /* write out inodes into buffers */
+ sync_buffers(0);
return 0;
}
int sync_dev(int dev)
{
- int i;
- struct buffer_head * bh;
-
- bh = start_buffer;
- for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
- if (bh->b_dev != dev)
- continue;
- wait_on_buffer(bh);
- if (bh->b_dev == dev && bh->b_dirt)
- ll_rw_block(WRITE,bh);
- }
+ sync_buffers(dev);
sync_inodes();
- bh = start_buffer;
- for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
- if (bh->b_dev != dev)
- continue;
- wait_on_buffer(bh);
- if (bh->b_dev == dev && bh->b_dirt)
- ll_rw_block(WRITE,bh);
- }
+ sync_buffers(dev);
return 0;
}
@@ -128,22 +124,61 @@ void check_disk_change(int dev)
#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
#define hash(dev,block) hash_table[_hashfn(dev,block)]
-static inline void remove_from_queues(struct buffer_head * bh)
+static inline void remove_from_hash_queue(struct buffer_head * bh)
{
-/* remove from hash-queue */
if (bh->b_next)
bh->b_next->b_prev = bh->b_prev;
if (bh->b_prev)
bh->b_prev->b_next = bh->b_next;
if (hash(bh->b_dev,bh->b_blocknr) == bh)
hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
-/* remove from free list */
+ bh->b_next = bh->b_prev = NULL;
+}
+
+static inline void remove_from_free_list(struct buffer_head * bh)
+{
if (!(bh->b_prev_free) || !(bh->b_next_free))
panic("Free block list corrupted");
bh->b_prev_free->b_next_free = bh->b_next_free;
bh->b_next_free->b_prev_free = bh->b_prev_free;
if (free_list == bh)
free_list = bh->b_next_free;
+ bh->b_next_free = bh->b_prev_free = NULL;
+}
+
+static inline void remove_from_queues(struct buffer_head * bh)
+{
+ remove_from_hash_queue(bh);
+ remove_from_free_list(bh);
+}
+
+static inline void put_first_free(struct buffer_head * bh)
+{
+ if (!bh || (bh == free_list))
+ return;
+ remove_from_free_list(bh);
+/* add to front of free list */
+ bh->b_next_free = free_list;
+ bh->b_prev_free = free_list->b_prev_free;
+ free_list->b_prev_free->b_next_free = bh;
+ free_list->b_prev_free = bh;
+ free_list = bh;
+}
+
+static inline void put_last_free(struct buffer_head * bh)
+{
+ if (!bh)
+ return;
+ if (bh == free_list) {
+ free_list = bh->b_next_free;
+ return;
+ }
+ remove_from_free_list(bh);
+/* add to back of free list */
+ bh->b_next_free = free_list;
+ bh->b_prev_free = free_list->b_prev_free;
+ free_list->b_prev_free->b_next_free = bh;
+ free_list->b_prev_free = bh;
}
static inline void insert_into_queues(struct buffer_head * bh)
@@ -189,8 +224,10 @@ struct buffer_head * get_hash_table(int dev, int block)
return NULL;
bh->b_count++;
wait_on_buffer(bh);
- if (bh->b_dev == dev && bh->b_blocknr == block)
+ if (bh->b_dev == dev && bh->b_blocknr == block) {
+ put_last_free(bh);
return bh;
+ }
bh->b_count--;
}
}
@@ -201,17 +238,23 @@ struct buffer_head * get_hash_table(int dev, int block)
* so it should be much more efficient than it looks.
*
* The algoritm is changed: hopefully better, and an elusive bug removed.
+ *
+ * 14.02.92: changed it to sync dirty buffers a bit: better performance
+ * when the filesystem starts to get full of dirty blocks (I hope).
*/
#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
struct buffer_head * getblk(int dev,int block)
{
- struct buffer_head * tmp, * bh;
+ struct buffer_head * bh, * tmp;
+ int buffers;
repeat:
if (bh = get_hash_table(dev,block))
return bh;
+ buffers = NR_BUFFERS;
tmp = free_list;
do {
+ tmp = tmp->b_next_free;
if (tmp->b_count)
continue;
if (!bh || BADNESS(tmp)<BADNESS(bh)) {
@@ -219,8 +262,10 @@ repeat:
if (!BADNESS(tmp))
break;
}
+ if (tmp->b_dirt)
+ ll_rw_block(WRITEA,tmp);
/* and repeat until we find something good */
- } while ((tmp = tmp->b_next_free) != free_list);
+ } while (buffers--);
if (!bh) {
sleep_on(&buffer_wait);
goto repeat;
@@ -377,5 +422,5 @@ void buffer_init(long buffer_end)
free_list->b_prev_free = h;
h->b_next_free = free_list;
for (i=0;i<NR_HASH;i++)
- hash_table[i]=NULL;
+ hash_table[i] = NULL;
}
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 7b07cc9..daf0269 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -13,22 +13,22 @@
#include <asm/segment.h>
#include <asm/io.h>
-extern int tty_read(unsigned minor,char * buf,int count);
+extern int tty_read(unsigned minor,char * buf,int count,unsigned short flags);
extern int tty_write(unsigned minor,char * buf,int count);
-typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count,off_t * pos);
+typedef (*crw_ptr)(int,unsigned,char *,int,off_t *,unsigned short);
-static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos)
+static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos, unsigned short flags)
{
- return ((rw==READ)?tty_read(minor,buf,count):
+ return ((rw==READ)?tty_read(minor,buf,count,flags):
tty_write(minor,buf,count));
}
-static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos)
+static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos, unsigned short flags)
{
if (current->tty<0)
return -EPERM;
- return rw_ttyx(rw,current->tty,buf,count,pos);
+ return rw_ttyx(rw,current->tty,buf,count,pos,flags);
}
static int rw_ram(int rw,char * buf, int count, off_t *pos)
@@ -43,7 +43,21 @@ static int rw_mem(int rw,char * buf, int count, off_t * pos)
static int rw_kmem(int rw,char * buf, int count, off_t * pos)
{
- return -EIO;
+ /* kmem by Damiano */
+ int i = *pos; /* Current position where to read */
+
+ /* i can go from 0 to LOW_MEM (See include/linux/mm.h */
+ /* I am not shure about it but it doesn't mem fault :-) */
+ while ( (count-- > 0) && (i <LOW_MEM) ) {
+ if (rw==READ)
+ put_fs_byte( *(char *)i ,buf++);
+ else
+ return (-EIO);
+ i++;
+ }
+ i -= *pos; /* Count how many read or write */
+ *pos += i; /* Update position */
+ return (i); /* Return number read */
}
static int rw_port(int rw,char * buf, int count, off_t * pos)
@@ -62,7 +76,8 @@ static int rw_port(int rw,char * buf, int count, off_t * pos)
return i;
}
-static int rw_memory(int rw, unsigned minor, char * buf, int count, off_t * pos)
+static int rw_memory(int rw, unsigned minor, char * buf, int count,
+ off_t * pos, unsigned short flags)
{
switch(minor) {
case 0:
@@ -92,13 +107,30 @@ static crw_ptr crw_table[]={
NULL, /* /dev/lp */
NULL}; /* unnamed pipes */
-int rw_char(int rw,int dev, char * buf, int count, off_t * pos)
+int char_read(struct inode * inode, struct file * filp, char * buf, int count)
+{
+ unsigned int major,minor;
+ crw_ptr call_addr;
+
+ major = MAJOR(inode->i_rdev);
+ minor = MINOR(inode->i_rdev);
+ if (major >= NRDEVS)
+ return -ENODEV;
+ if (!(call_addr = crw_table[major]))
+ return -ENODEV;
+ return call_addr(READ,minor,buf,count,&filp->f_pos,filp->f_flags);
+}
+
+int char_write(struct inode * inode, struct file * filp, char * buf, int count)
{
+ unsigned int major,minor;
crw_ptr call_addr;
- if (MAJOR(dev)>=NRDEVS)
+ major = MAJOR(inode->i_rdev);
+ minor = MINOR(inode->i_rdev);
+ if (major >= NRDEVS)
return -ENODEV;
- if (!(call_addr=crw_table[MAJOR(dev)]))
+ if (!(call_addr=crw_table[major]))
return -ENODEV;
- return call_addr(rw,MINOR(dev),buf,count,pos);
+ return call_addr(WRITE,minor,buf,count,&filp->f_pos,filp->f_flags);
}
diff --git a/fs/exec.c b/fs/exec.c
index d5136f2..2195ff9 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -41,7 +41,7 @@ extern int sys_close(int fd);
int sys_uselib(const char * library)
{
- struct m_inode * inode;
+ struct inode * inode;
unsigned long base;
if (get_limit(0x17) != TASK_SIZE)
@@ -148,7 +148,7 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
do {
len++;
} while (get_fs_byte(tmp++));
- if (p-len < 0) { /* this shouldn't happen - 128kB */
+ if (p < len) { /* this shouldn't happen - 128kB */
set_fs(old_fs);
return 0;
}
@@ -207,7 +207,7 @@ static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
int do_execve(unsigned long * eip,long tmp,char * filename,
char ** argv, char ** envp)
{
- struct m_inode * inode;
+ struct inode * inode;
struct buffer_head * bh;
struct exec ex;
unsigned long page[MAX_ARG_PAGES];
@@ -232,18 +232,24 @@ restart_interp:
goto exec_error2;
}
i = inode->i_mode;
- e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
- e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
+ /* make sure we don't let suid, sgid files be ptraced. */
+ if (current->flags & PF_PTRACED) {
+ e_uid = current->euid;
+ e_gid = current->egid;
+ } else {
+ e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
+ e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
+ }
if (current->euid == inode->i_uid)
i >>= 6;
else if (in_group_p(inode->i_gid))
i >>= 3;
if (!(i & 1) &&
!((inode->i_mode & 0111) && suser())) {
- retval = -ENOEXEC;
+ retval = -EACCES;
goto exec_error2;
}
- if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
+ if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
retval = -EACCES;
goto exec_error2;
}
@@ -367,11 +373,13 @@ restart_interp:
current->brk = ex.a_bss +
(current->end_data = ex.a_data +
(current->end_code = ex.a_text));
- current->start_stack = p & 0xfffff000;
+ current->start_stack = p;
current->suid = current->euid = e_uid;
current->sgid = current->egid = e_gid;
eip[0] = ex.a_entry; /* eip, magic happens :-) */
eip[3] = p; /* stack pointer */
+ if (current->flags & PF_PTRACED)
+ send_sig(SIGTRAP, current, 0);
return 0;
exec_error2:
iput(inode);
diff --git a/fs/fcntl.c b/fs/fcntl.c
index c201aa8..ab7fe1f 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -35,6 +35,8 @@ static int dupfd(unsigned int fd, unsigned int arg)
int sys_dup2(unsigned int oldfd, unsigned int newfd)
{
+ if (newfd == oldfd)
+ return newfd;
sys_close(newfd);
return dupfd(oldfd,newfd);
}
@@ -68,8 +70,8 @@ int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
filp->f_flags |= arg & (O_APPEND | O_NONBLOCK);
return 0;
case F_GETLK: case F_SETLK: case F_SETLKW:
- return -1;
+ return -ENOSYS;
default:
- return -1;
+ return -EINVAL;
}
}
diff --git a/fs/inode.c b/fs/inode.c
index 5c56663..dd68b1d 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -8,18 +8,17 @@
#include <sys/stat.h>
#include <linux/sched.h>
+#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/system.h>
-extern int *blk_size[];
+struct inode inode_table[NR_INODE]={{0,},};
-struct m_inode inode_table[NR_INODE]={{0,},};
+extern void minix_read_inode(struct inode * inode);
+extern void minix_write_inode(struct inode * inode);
-static void read_inode(struct m_inode * inode);
-static void write_inode(struct m_inode * inode);
-
-static inline void wait_on_inode(struct m_inode * inode)
+static inline void wait_on_inode(struct inode * inode)
{
cli();
while (inode->i_lock)
@@ -27,7 +26,7 @@ static inline void wait_on_inode(struct m_inode * inode)
sti();
}
-static inline void lock_inode(struct m_inode * inode)
+static inline void lock_inode(struct inode * inode)
{
cli();
while (inode->i_lock)
@@ -36,16 +35,39 @@ static inline void lock_inode(struct m_inode * inode)
sti();
}
-static inline void unlock_inode(struct m_inode * inode)
+static inline void unlock_inode(struct inode * inode)
{
inode->i_lock=0;
wake_up(&inode->i_wait);
}
+static void write_inode(struct inode * inode)
+{
+ lock_inode(inode);
+ if (!inode->i_dirt || !inode->i_dev) {
+ unlock_inode(inode);
+ return;
+ }
+ minix_write_inode(inode);
+ unlock_inode(inode);
+}
+
+static void read_inode(struct inode * inode)
+{
+ lock_inode(inode);
+ minix_read_inode(inode);
+ unlock_inode(inode);
+}
+
+int bmap(struct inode * inode, int block)
+{
+ return minix_bmap(inode,block);
+}
+
void invalidate_inodes(int dev)
{
int i;
- struct m_inode * inode;
+ struct inode * inode;
inode = 0+inode_table;
for(i=0 ; i<NR_INODE ; i++,inode++) {
@@ -61,7 +83,7 @@ void invalidate_inodes(int dev)
void sync_inodes(void)
{
int i;
- struct m_inode * inode;
+ struct inode * inode;
inode = 0+inode_table;
for(i=0 ; i<NR_INODE ; i++,inode++) {
@@ -71,85 +93,7 @@ void sync_inodes(void)
}
}
-static int _bmap(struct m_inode * inode,int block,int create)
-{
- struct buffer_head * bh;
- int i;
-
- if (block<0)
- panic("_bmap: block<0");
- if (block >= 7+512+512*512)
- panic("_bmap: block>big");
- if (block<7) {
- if (create && !inode->i_zone[block])
- if (inode->i_zone[block]=new_block(inode->i_dev)) {
- inode->i_ctime=CURRENT_TIME;
- inode->i_dirt=1;
- }
- return inode->i_zone[block];
- }
- block -= 7;
- if (block<512) {
- if (create && !inode->i_zone[7])
- if (inode->i_zone[7]=new_block(inode->i_dev)) {
- inode->i_dirt=1;
- inode->i_ctime=CURRENT_TIME;
- }
- if (!inode->i_zone[7])
- return 0;
- if (!(bh = bread(inode->i_dev,inode->i_zone[7])))
- return 0;
- i = ((unsigned short *) (bh->b_data))[block];
- if (create && !i)
- if (i=new_block(inode->i_dev)) {
- ((unsigned short *) (bh->b_data))[block]=i;
- bh->b_dirt=1;
- }
- brelse(bh);
- return i;
- }
- block -= 512;
- if (create && !inode->i_zone[8])
- if (inode->i_zone[8]=new_block(inode->i_dev)) {
- inode->i_dirt=1;
- inode->i_ctime=CURRENT_TIME;
- }
- if (!inode->i_zone[8])
- return 0;
- if (!(bh=bread(inode->i_dev,inode->i_zone[8])))
- return 0;
- i = ((unsigned short *)bh->b_data)[block>>9];
- if (create && !i)
- if (i=new_block(inode->i_dev)) {
- ((unsigned short *) (bh->b_data))[block>>9]=i;
- bh->b_dirt=1;
- }
- brelse(bh);
- if (!i)
- return 0;
- if (!(bh=bread(inode->i_dev,i)))
- return 0;
- i = ((unsigned short *)bh->b_data)[block&511];
- if (create && !i)
- if (i=new_block(inode->i_dev)) {
- ((unsigned short *) (bh->b_data))[block&511]=i;
- bh->b_dirt=1;
- }
- brelse(bh);
- return i;
-}
-
-int bmap(struct m_inode * inode,int block)
-{
- return _bmap(inode,block,0);
-}
-
-int create_block(struct m_inode * inode, int block)
-{
- return _bmap(inode,block,1);
-}
-
-void iput(struct m_inode * inode)
+void iput(struct inode * inode)
{
if (!inode)
return;
@@ -172,7 +116,7 @@ void iput(struct m_inode * inode)
return;
}
if (S_ISBLK(inode->i_mode)) {
- sync_dev(inode->i_zone[0]);
+ sync_dev(inode->i_rdev);
wait_on_inode(inode);
}
repeat:
@@ -180,9 +124,9 @@ repeat:
inode->i_count--;
return;
}
- if (!inode->i_nlinks) {
- truncate(inode);
- free_inode(inode);
+ if (!inode->i_nlink) {
+ minix_truncate(inode);
+ minix_free_inode(inode);
return;
}
if (inode->i_dirt) {
@@ -194,10 +138,10 @@ repeat:
return;
}
-struct m_inode * get_empty_inode(void)
+struct inode * get_empty_inode(void)
{
- struct m_inode * inode;
- static struct m_inode * last_inode = inode_table;
+ struct inode * inode;
+ static struct inode * last_inode = inode_table;
int i;
do {
@@ -213,8 +157,8 @@ struct m_inode * get_empty_inode(void)
}
if (!inode) {
for (i=0 ; i<NR_INODE ; i++)
- printk("%04x: %6d\t",inode_table[i].i_dev,
- inode_table[i].i_num);
+ printk("(%04x: %d (%o)) ",inode_table[i].i_dev,
+ inode_table[i].i_ino,inode_table[i].i_mode);
panic("No free inodes in mem");
}
wait_on_inode(inode);
@@ -228,9 +172,9 @@ struct m_inode * get_empty_inode(void)
return inode;
}
-struct m_inode * get_pipe_inode(void)
+struct inode * get_pipe_inode(void)
{
- struct m_inode * inode;
+ struct inode * inode;
if (!(inode = get_empty_inode()))
return NULL;
@@ -244,21 +188,21 @@ struct m_inode * get_pipe_inode(void)
return inode;
}
-struct m_inode * iget(int dev,int nr)
+struct inode * iget(int dev,int nr)
{
- struct m_inode * inode, * empty;
+ struct inode * inode, * empty;
if (!dev)
panic("iget with dev==0");
empty = get_empty_inode();
inode = inode_table;
while (inode < NR_INODE+inode_table) {
- if (inode->i_dev != dev || inode->i_num != nr) {
+ if (inode->i_dev != dev || inode->i_ino != nr) {
inode++;
continue;
}
wait_on_inode(inode);
- if (inode->i_dev != dev || inode->i_num != nr) {
+ if (inode->i_dev != dev || inode->i_ino != nr) {
inode = inode_table;
continue;
}
@@ -267,7 +211,7 @@ struct m_inode * iget(int dev,int nr)
int i;
for (i = 0 ; i<NR_SUPER ; i++)
- if (super_block[i].s_imount==inode)
+ if (super_block[i].s_covered==inode)
break;
if (i >= NR_SUPER) {
printk("Mounted inode hasn't got sb\n");
@@ -276,10 +220,12 @@ struct m_inode * iget(int dev,int nr)
return inode;
}
iput(inode);
- dev = super_block[i].s_dev;
- nr = ROOT_INO;
- inode = inode_table;
- continue;
+ if (!(inode = super_block[i].s_mounted))
+ printk("iget: mounted dev has no rootinode\n");
+ else {
+ inode->i_count++;
+ wait_on_inode(inode);
+ }
}
if (empty)
iput(empty);
@@ -287,62 +233,14 @@ struct m_inode * iget(int dev,int nr)
}
if (!empty)
return (NULL);
- inode=empty;
+ inode = empty;
+ if (!(inode->i_sb = get_super(dev))) {
+ printk("iget: gouldn't get super-block\n\t");
+ iput(inode);
+ return NULL;
+ }
inode->i_dev = dev;
- inode->i_num = nr;
+ inode->i_ino = nr;
read_inode(inode);
return inode;
}
-
-static void read_inode(struct m_inode * inode)
-{
- struct super_block * sb;
- struct buffer_head * bh;
- int block;
-
- lock_inode(inode);
- if (!(sb=get_super(inode->i_dev)))
- panic("trying to read inode without dev");
- block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
- (inode->i_num-1)/INODES_PER_BLOCK;
- if (!(bh=bread(inode->i_dev,block)))
- panic("unable to read i-node block");
- *(struct d_inode *)inode =
- ((struct d_inode *)bh->b_data)
- [(inode->i_num-1)%INODES_PER_BLOCK];
- brelse(bh);
- if (S_ISBLK(inode->i_mode)) {
- int i = inode->i_zone[0];
- if (blk_size[MAJOR(i)])
- inode->i_size = 1024*blk_size[MAJOR(i)][MINOR(i)];
- else
- inode->i_size = 0x7fffffff;
- }
- unlock_inode(inode);
-}
-
-static void write_inode(struct m_inode * inode)
-{
- struct super_block * sb;
- struct buffer_head * bh;
- int block;
-
- lock_inode(inode);
- if (!inode->i_dirt || !inode->i_dev) {
- unlock_inode(inode);
- return;
- }
- if (!(sb=get_super(inode->i_dev)))
- panic("trying to write inode without device");
- block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
- (inode->i_num-1)/INODES_PER_BLOCK;
- if (!(bh=bread(inode->i_dev,block)))
- panic("unable to read i-node block");
- ((struct d_inode *)bh->b_data)
- [(inode->i_num-1)%INODES_PER_BLOCK] =
- *(struct d_inode *)inode;
- bh->b_dirt=1;
- inode->i_dirt=0;
- brelse(bh);
- unlock_inode(inode);
-}
diff --git a/fs/ioctl.c b/fs/ioctl.c
index c7b41eb..d293a92 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -11,7 +11,7 @@
#include <linux/sched.h>
extern int tty_ioctl(int dev, int cmd, int arg);
-extern int pipe_ioctl(struct m_inode *pino, int cmd, int arg);
+extern int pipe_ioctl(struct inode *pino, int cmd, int arg);
typedef int (*ioctl_ptr)(int dev,int cmd,int arg);
@@ -40,7 +40,7 @@ int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
mode=filp->f_inode->i_mode;
if (!S_ISCHR(mode) && !S_ISBLK(mode))
return -EINVAL;
- dev = filp->f_inode->i_zone[0];
+ dev = filp->f_inode->i_rdev;
if (MAJOR(dev) >= NRDEVS)
return -ENODEV;
if (!ioctl_table[MAJOR(dev)])
diff --git a/fs/minix/Makefile b/fs/minix/Makefile
new file mode 100644
index 0000000..967bda5
--- /dev/null
+++ b/fs/minix/Makefile
@@ -0,0 +1,69 @@
+AR =ar
+AS =as
+CC =gcc
+LD =ld
+CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \
+ -nostdinc -I../../include
+CPP =gcc -E -nostdinc -I../../include
+
+.c.s:
+ $(CC) $(CFLAGS) \
+ -S -o $*.s $<
+.c.o:
+ $(CC) $(CFLAGS) \
+ -c -o $*.o $<
+.s.o:
+ $(AS) -o $*.o $<
+
+OBJS= minix_op.o bitmap.o truncate.o namei.o inode.o file_dev.o
+
+minix.o: $(OBJS)
+ $(LD) -r -o minix.o $(OBJS)
+
+clean:
+ rm -f core *.o *.a tmp_make
+ for i in *.c;do rm -f `basename $$i .c`.s;done
+
+dep:
+ sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
+ (for i in *.c;do $(CPP) -M $$i;done) >> tmp_make
+ cp tmp_make Makefile
+
+### Dependencies:
+bitmap.o : bitmap.c ../../include/string.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h \
+ ../../include/sys/types.h ../../include/linux/mm.h \
+ ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/linux/minix_fs.h
+file_dev.o : file_dev.c ../../include/errno.h ../../include/fcntl.h \
+ ../../include/sys/types.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h \
+ ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
+ ../../include/time.h ../../include/sys/resource.h \
+ ../../include/linux/minix_fs.h ../../include/asm/segment.h
+inode.o : inode.c ../../include/string.h ../../include/sys/stat.h \
+ ../../include/sys/types.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h \
+ ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
+ ../../include/time.h ../../include/sys/resource.h \
+ ../../include/linux/minix_fs.h ../../include/asm/system.h
+minix_op.o : minix_op.c ../../include/linux/fs.h ../../include/sys/types.h \
+ ../../include/linux/minix_fs.h
+namei.o : namei.c ../../include/linux/sched.h ../../include/linux/head.h \
+ ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
+ ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/linux/minix_fs.h \
+ ../../include/asm/segment.h ../../include/string.h ../../include/fcntl.h \
+ ../../include/errno.h ../../include/const.h ../../include/sys/stat.h
+truncate.o : truncate.c ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h \
+ ../../include/sys/types.h ../../include/linux/mm.h \
+ ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/linux/minix_fs.h \
+ ../../include/linux/tty.h ../../include/termios.h ../../include/errno.h \
+ ../../include/fcntl.h ../../include/sys/stat.h
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
new file mode 100644
index 0000000..645db74
--- /dev/null
+++ b/fs/minix/bitmap.c
@@ -0,0 +1,184 @@
+/*
+ * linux/fs/bitmap.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/* bitmap.c contains the code that handles the inode and block bitmaps */
+#include <string.h>
+
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/kernel.h>
+
+#define clear_block(addr) \
+__asm__("cld\n\t" \
+ "rep\n\t" \
+ "stosl" \
+ ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
+
+#define set_bit(nr,addr) ({\
+char res; \
+__asm__ __volatile__("btsl %1,%2\n\tsetb %0": \
+"=q" (res):"r" (nr),"m" (*(addr))); \
+res;})
+
+#define clear_bit(nr,addr) ({\
+char res; \
+__asm__ __volatile__("btrl %1,%2\n\tsetnb %0": \
+"=q" (res):"r" (nr),"m" (*(addr))); \
+res;})
+
+#define find_first_zero(addr) ({ \
+int __res; \
+__asm__("cld\n" \
+ "1:\tlodsl\n\t" \
+ "notl %%eax\n\t" \
+ "bsfl %%eax,%%edx\n\t" \
+ "jne 2f\n\t" \
+ "addl $32,%%ecx\n\t" \
+ "cmpl $8192,%%ecx\n\t" \
+ "jl 1b\n\t" \
+ "xorl %%edx,%%edx\n" \
+ "2:\taddl %%edx,%%ecx" \
+ :"=c" (__res):"0" (0),"S" (addr):"ax","dx","si"); \
+__res;})
+
+int minix_free_block(int dev, int block)
+{
+ struct super_block * sb;
+ struct buffer_head * bh;
+ unsigned int bit,zone;
+
+ if (!(sb = get_super(dev)))
+ panic("trying to free block on nonexistent device");
+ if (block < sb->s_firstdatazone || block >= sb->s_nzones)
+ panic("trying to free block not in datazone");
+ bh = get_hash_table(dev,block);
+ if (bh) {
+ if (bh->b_count > 1) {
+ brelse(bh);
+ return 0;
+ }
+ bh->b_dirt=0;
+ bh->b_uptodate=0;
+ if (bh->b_count)
+ brelse(bh);
+ }
+ zone = block - sb->s_firstdatazone + 1;
+ bit = zone & 8191;
+ zone >>= 13;
+ bh = sb->s_zmap[zone];
+ if (clear_bit(bit,bh->b_data))
+ printk("free_block (%04x:%d): bit already cleared\n",dev,block);
+ bh->b_dirt = 1;
+ return 1;
+}
+
+int minix_new_block(int dev)
+{
+ struct buffer_head * bh;
+ struct super_block * sb;
+ int i,j;
+
+ if (!(sb = get_super(dev)))
+ panic("trying to get new block from nonexistant device");
+ j = 8192;
+ for (i=0 ; i<8 ; i++)
+ if (bh=sb->s_zmap[i])
+ if ((j=find_first_zero(bh->b_data))<8192)
+ break;
+ if (i>=8 || !bh || j>=8192)
+ return 0;
+ if (set_bit(j,bh->b_data))
+ panic("new_block: bit already set");
+ bh->b_dirt = 1;
+ j += i*8192 + sb->s_firstdatazone-1;
+ if (j >= sb->s_nzones)
+ return 0;
+ if (!(bh=getblk(dev,j)))
+ panic("new_block: cannot get block");
+ if (bh->b_count != 1)
+ panic("new block: count is != 1");
+ clear_block(bh->b_data);
+ bh->b_uptodate = 1;
+ bh->b_dirt = 1;
+ brelse(bh);
+ return j;
+}
+
+void minix_free_inode(struct inode * inode)
+{
+ struct buffer_head * bh;
+
+ if (!inode)
+ return;
+ if (!inode->i_dev) {
+ memset(inode,0,sizeof(*inode));
+ return;
+ }
+ if (inode->i_count>1) {
+ printk("free_inode: inode has count=%d\n",inode->i_count);
+ return;
+ }
+ if (inode->i_nlink) {
+ printk("free_inode: inode has nlink=%d\n",inode->i_nlink);
+ return;
+ }
+ if (!inode->i_sb) {
+ printk("free_inode: inode on nonexistent device\n");
+ return;
+ }
+ if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->s_ninodes) {
+ printk("free_inode: inode 0 or nonexistent inode\n");
+ return;
+ }
+ if (!(bh=inode->i_sb->s_imap[inode->i_ino>>13])) {
+ printk("free_inode: nonexistent imap in superblock\n");
+ return;
+ }
+ if (clear_bit(inode->i_ino&8191,bh->b_data))
+ printk("free_inode: bit already cleared.\n\r");
+ bh->b_dirt = 1;
+ memset(inode,0,sizeof(*inode));
+}
+
+struct inode * minix_new_inode(int dev)
+{
+ struct inode * inode;
+ struct buffer_head * bh;
+ int i,j;
+
+ if (!(inode=get_empty_inode()))
+ return NULL;
+ if (!(inode->i_sb = get_super(dev))) {
+ printk("new_inode: unknown device\n");
+ iput(inode);
+ return NULL;
+ }
+ j = 8192;
+ for (i=0 ; i<8 ; i++)
+ if (bh=inode->i_sb->s_imap[i])
+ if ((j=find_first_zero(bh->b_data))<8192)
+ break;
+ if (!bh || j >= 8192 || j+i*8192 > inode->i_sb->s_ninodes) {
+ iput(inode);
+ return NULL;
+ }
+ if (set_bit(j,bh->b_data)) { /* shouldn't happen */
+ printk("new_inode: bit already set");
+ iput(inode);
+ return NULL;
+ }
+ bh->b_dirt = 1;
+ inode->i_count = 1;
+ inode->i_nlink = 1;
+ inode->i_dev = dev;
+ inode->i_uid = current->euid;
+ inode->i_gid = current->egid;
+ inode->i_dirt = 1;
+ inode->i_ino = j + i*8192;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_op = &minix_inode_operations;
+ return inode;
+}
diff --git a/fs/minix/file_dev.c b/fs/minix/file_dev.c
new file mode 100644
index 0000000..646ba0e
--- /dev/null
+++ b/fs/minix/file_dev.c
@@ -0,0 +1,105 @@
+/*
+ * linux/fs/file_dev.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count)
+{
+ int read,left,chars,nr;
+ struct buffer_head * bh;
+
+ if (filp->f_pos > inode->i_size)
+ left = 0;
+ else
+ left = inode->i_size - filp->f_pos;
+ if (left > count)
+ left = count;
+ read = 0;
+ while (left > 0) {
+ if (nr = bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS)) {
+ if (!(bh=bread(inode->i_dev,nr)))
+ return read?read:-EIO;
+ } else
+ bh = NULL;
+ nr = filp->f_pos & (BLOCK_SIZE-1);
+ chars = MIN( BLOCK_SIZE-nr , left );
+ filp->f_pos += chars;
+ left -= chars;
+ read += chars;
+ if (bh) {
+ char * p = nr + bh->b_data;
+ while (chars-->0)
+ put_fs_byte(*(p++),buf++);
+ brelse(bh);
+ } else {
+ while (chars-->0)
+ put_fs_byte(0,buf++);
+ }
+ }
+ inode->i_atime = CURRENT_TIME;
+ return read;
+}
+
+int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
+{
+ off_t pos;
+ int written,block,c;
+ struct buffer_head * bh;
+ char * p;
+
+/*
+ * ok, append may not work when many processes are writing at the same time
+ * but so what. That way leads to madness anyway.
+ */
+ if (filp->f_flags & O_APPEND)
+ pos = inode->i_size;
+ else
+ pos = filp->f_pos;
+ written = 0;
+ while (written<count) {
+ if (!(block = minix_create_block(inode,pos/BLOCK_SIZE))) {
+ if (!written)
+ written = -ENOSPC;
+ break;
+ }
+ if (!(bh=bread(inode->i_dev,block))) {
+ if (!written)
+ written = -EIO;
+ break;
+ }
+ c = pos % BLOCK_SIZE;
+ p = c + bh->b_data;
+ bh->b_dirt = 1;
+ c = BLOCK_SIZE-c;
+ if (c > count-written)
+ c = count-written;
+ pos += c;
+ if (pos > inode->i_size) {
+ inode->i_size = pos;
+ inode->i_dirt = 1;
+ }
+ written += c;
+ while (c-->0)
+ *(p++) = get_fs_byte(buf++);
+ brelse(bh);
+ }
+ inode->i_mtime = CURRENT_TIME;
+ if (!(filp->f_flags & O_APPEND)) {
+ filp->f_pos = pos;
+ inode->i_ctime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
+ return written;
+}
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
new file mode 100644
index 0000000..a4dab05
--- /dev/null
+++ b/fs/minix/inode.c
@@ -0,0 +1,145 @@
+/*
+ * linux/fs/minix/inode.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+#include <string.h>
+#include <sys/stat.h>
+
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/system.h>
+
+static int _bmap(struct inode * inode,int block,int create)
+{
+ struct buffer_head * bh;
+ int i;
+
+ if (block<0)
+ panic("_bmap: block<0");
+ if (block >= 7+512+512*512)
+ panic("_bmap: block>big");
+ if (block<7) {
+ if (create && !inode->i_data[block])
+ if (inode->i_data[block]=minix_new_block(inode->i_dev)) {
+ inode->i_ctime=CURRENT_TIME;
+ inode->i_dirt=1;
+ }
+ return inode->i_data[block];
+ }
+ block -= 7;
+ if (block<512) {
+ if (create && !inode->i_data[7])
+ if (inode->i_data[7]=minix_new_block(inode->i_dev)) {
+ inode->i_dirt=1;
+ inode->i_ctime=CURRENT_TIME;
+ }
+ if (!inode->i_data[7])
+ return 0;
+ if (!(bh = bread(inode->i_dev,inode->i_data[7])))
+ return 0;
+ i = ((unsigned short *) (bh->b_data))[block];
+ if (create && !i)
+ if (i=minix_new_block(inode->i_dev)) {
+ ((unsigned short *) (bh->b_data))[block]=i;
+ bh->b_dirt=1;
+ }
+ brelse(bh);
+ return i;
+ }
+ block -= 512;
+ if (create && !inode->i_data[8])
+ if (inode->i_data[8]=minix_new_block(inode->i_dev)) {
+ inode->i_dirt=1;
+ inode->i_ctime=CURRENT_TIME;
+ }
+ if (!inode->i_data[8])
+ return 0;
+ if (!(bh=bread(inode->i_dev,inode->i_data[8])))
+ return 0;
+ i = ((unsigned short *)bh->b_data)[block>>9];
+ if (create && !i)
+ if (i=minix_new_block(inode->i_dev)) {
+ ((unsigned short *) (bh->b_data))[block>>9]=i;
+ bh->b_dirt=1;
+ }
+ brelse(bh);
+ if (!i)
+ return 0;
+ if (!(bh=bread(inode->i_dev,i)))
+ return 0;
+ i = ((unsigned short *)bh->b_data)[block&511];
+ if (create && !i)
+ if (i=minix_new_block(inode->i_dev)) {
+ ((unsigned short *) (bh->b_data))[block&511]=i;
+ bh->b_dirt=1;
+ }
+ brelse(bh);
+ return i;
+}
+
+int minix_bmap(struct inode * inode,int block)
+{
+ return _bmap(inode,block,0);
+}
+
+int minix_create_block(struct inode * inode, int block)
+{
+ return _bmap(inode,block,1);
+}
+
+void minix_read_inode(struct inode * inode)
+{
+ struct buffer_head * bh;
+ struct minix_inode * raw_inode;
+ int block;
+
+ block = 2 + inode->i_sb->s_imap_blocks + inode->i_sb->s_zmap_blocks +
+ (inode->i_ino-1)/MINIX_INODES_PER_BLOCK;
+ if (!(bh=bread(inode->i_dev,block)))
+ panic("unable to read i-node block");
+ raw_inode = ((struct minix_inode *) bh->b_data) +
+ (inode->i_ino-1)%MINIX_INODES_PER_BLOCK;
+ inode->i_mode = raw_inode->i_mode;
+ inode->i_uid = raw_inode->i_uid;
+ inode->i_gid = raw_inode->i_gid;
+ inode->i_nlink = raw_inode->i_nlinks;
+ inode->i_size = raw_inode->i_size;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = raw_inode->i_time;
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ inode->i_rdev = raw_inode->i_zone[0];
+ else for (block = 0; block < 9; block++)
+ inode->i_data[block] = raw_inode->i_zone[block];
+ brelse(bh);
+ inode->i_op = &minix_inode_operations;
+}
+
+void minix_write_inode(struct inode * inode)
+{
+ struct buffer_head * bh;
+ struct minix_inode * raw_inode;
+ int block;
+
+ block = 2 + inode->i_sb->s_imap_blocks + inode->i_sb->s_zmap_blocks +
+ (inode->i_ino-1)/MINIX_INODES_PER_BLOCK;
+ if (!(bh=bread(inode->i_dev,block)))
+ panic("unable to read i-node block");
+ raw_inode = ((struct minix_inode *)bh->b_data) +
+ (inode->i_ino-1)%MINIX_INODES_PER_BLOCK;
+ raw_inode->i_mode = inode->i_mode;
+ raw_inode->i_uid = inode->i_uid;
+ raw_inode->i_gid = inode->i_gid;
+ raw_inode->i_nlinks = inode->i_nlink;
+ raw_inode->i_size = inode->i_size;
+ raw_inode->i_time = inode->i_mtime;
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ raw_inode->i_zone[0] = inode->i_rdev;
+ else for (block = 0; block < 9; block++)
+ raw_inode->i_zone[block] = inode->i_data[block];
+ bh->b_dirt=1;
+ inode->i_dirt=0;
+ brelse(bh);
+}
diff --git a/fs/minix/minix_op.c b/fs/minix/minix_op.c
new file mode 100644
index 0000000..a85e3a8
--- /dev/null
+++ b/fs/minix/minix_op.c
@@ -0,0 +1,38 @@
+/*
+ * linux/fs/minix/minix_op.c
+ *
+ * structures for the minix super_block/inode/file-operations
+ */
+
+#include <linux/fs.h>
+#include <linux/minix_fs.h>
+
+/*
+ * These are the low-level inode operations for minix filesystem inodes.
+ */
+struct inode_operations minix_inode_operations = {
+ minix_create,
+ minix_lookup,
+ minix_link,
+ minix_unlink,
+ minix_symlink,
+ minix_mkdir,
+ minix_rmdir,
+ minix_mknod,
+ minix_rename,
+ minix_readlink,
+ minix_open,
+ minix_release,
+ minix_follow_link
+};
+
+/*
+ * We have just NULL's here: the current defaults are ok for
+ * the minix filesystem.
+ */
+struct file_operations minix_file_operations = {
+ NULL, /* lseek */
+ NULL, /* read */
+ NULL /* write */
+};
+
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
new file mode 100644
index 0000000..d3c0224
--- /dev/null
+++ b/fs/minix/namei.c
@@ -0,0 +1,795 @@
+/*
+ * linux/fs/minix/namei.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <const.h>
+#include <sys/stat.h>
+
+extern int permission(struct inode * inode,int mask);
+extern struct inode * _namei(const char * filename, struct inode * base,
+ int follow_links);
+
+/*
+ * comment out this line if you want names > MINIX_NAME_LEN chars to be
+ * truncated. Else they will be disallowed.
+ */
+/* #define NO_TRUNCATE */
+
+/*
+ * ok, we cannot use strncmp, as the name is not in our data space.
+ * Thus we'll have to use minix_match. No big problem. Match also makes
+ * some sanity tests.
+ *
+ * NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure.
+ */
+static int minix_match(int len,const char * name,struct minix_dir_entry * de)
+{
+ register int same __asm__("ax");
+
+ if (!de || !de->inode || len > MINIX_NAME_LEN)
+ return 0;
+ /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
+ if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
+ return 1;
+ if (len < MINIX_NAME_LEN && de->name[len])
+ return 0;
+ __asm__("cld\n\t"
+ "fs ; repe ; cmpsb\n\t"
+ "setz %%al"
+ :"=a" (same)
+ :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
+ :"cx","di","si");
+ return same;
+}
+
+/*
+ * minix_find_entry()
+ *
+ * finds an entry in the specified directory with the wanted name. It
+ * returns the cache buffer in which the entry was found, and the entry
+ * itself (as a parameter - res_dir). It does NOT read the inode of the
+ * entry - you'll have to do that yourself if you want to.
+ */
+static struct buffer_head * minix_find_entry(struct inode * dir,
+ const char * name, int namelen, struct minix_dir_entry ** res_dir)
+{
+ int entries;
+ int block,i;
+ struct buffer_head * bh;
+ struct minix_dir_entry * de;
+
+ *res_dir = NULL;
+ if (!dir)
+ return NULL;
+#ifdef NO_TRUNCATE
+ if (namelen > MINIX_NAME_LEN)
+ return NULL;
+#else
+ if (namelen > MINIX_NAME_LEN)
+ namelen = MINIX_NAME_LEN;
+#endif
+ entries = dir->i_size / (sizeof (struct minix_dir_entry));
+ if (!(block = dir->i_data[0]))
+ return NULL;
+ if (!(bh = bread(dir->i_dev,block)))
+ return NULL;
+ i = 0;
+ de = (struct minix_dir_entry *) bh->b_data;
+ while (i < entries) {
+ if ((char *)de >= BLOCK_SIZE+bh->b_data) {
+ brelse(bh);
+ bh = NULL;
+ if (!(block = bmap(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK)) ||
+ !(bh = bread(dir->i_dev,block))) {
+ i += MINIX_DIR_ENTRIES_PER_BLOCK;
+ continue;
+ }
+ de = (struct minix_dir_entry *) bh->b_data;
+ }
+ if (minix_match(namelen,name,de)) {
+ *res_dir = de;
+ return bh;
+ }
+ de++;
+ i++;
+ }
+ brelse(bh);
+ return NULL;
+}
+
+struct inode * minix_follow_link(struct inode * dir, struct inode * inode)
+{
+ unsigned short fs;
+ struct buffer_head * bh;
+
+ if (!dir) {
+ dir = current->root;
+ dir->i_count++;
+ }
+ if (!inode) {
+ iput(dir);
+ return NULL;
+ }
+ if (!S_ISLNK(inode->i_mode)) {
+ iput(dir);
+ return inode;
+ }
+ __asm__("mov %%fs,%0":"=r" (fs));
+ if ((current->link_count > 5) || !inode->i_data[0] ||
+ !(bh = bread(inode->i_dev, inode->i_data[0]))) {
+ iput(dir);
+ iput(inode);
+ return NULL;
+ }
+ iput(inode);
+ __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
+ current->link_count++;
+ inode = _namei(bh->b_data,dir,1);
+ current->link_count--;
+ __asm__("mov %0,%%fs"::"r" (fs));
+ brelse(bh);
+ return inode;
+}
+
+int minix_lookup(struct inode * dir,const char * name, int len,
+ struct inode ** result)
+{
+ int ino;
+ struct minix_dir_entry * de;
+ struct buffer_head * bh;
+
+ *result = NULL;
+ if (!dir)
+ return -ENOENT;
+ if (!S_ISDIR(dir->i_mode)) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (!(bh = minix_find_entry(dir,name,len,&de))) {
+ iput(dir);
+ return -ENOENT;
+ }
+ ino = de->inode;
+ brelse(bh);
+ if (!(*result = iget(dir->i_dev,ino))) {
+ iput(dir);
+ return -EACCES;
+ }
+ iput(dir);
+ return 0;
+}
+
+/*
+ * minix_add_entry()
+ *
+ * adds a file entry to the specified directory, using the same
+ * semantics as minix_find_entry(). It returns NULL if it failed.
+ *
+ * NOTE!! The inode part of 'de' is left at 0 - which means you
+ * may not sleep between calling this and putting something into
+ * the entry, as someone else might have used it while you slept.
+ */
+static struct buffer_head * minix_add_entry(struct inode * dir,
+ const char * name, int namelen, struct minix_dir_entry ** res_dir)
+{
+ int block,i;
+ struct buffer_head * bh;
+ struct minix_dir_entry * de;
+
+ *res_dir = NULL;
+ if (!dir)
+ return NULL;
+#ifdef NO_TRUNCATE
+ if (namelen > MINIX_NAME_LEN)
+ return NULL;
+#else
+ if (namelen > MINIX_NAME_LEN)
+ namelen = MINIX_NAME_LEN;
+#endif
+ if (!namelen)
+ return NULL;
+ if (!(block = dir->i_data[0]))
+ return NULL;
+ if (!(bh = bread(dir->i_dev,block)))
+ return NULL;
+ i = 0;
+ de = (struct minix_dir_entry *) bh->b_data;
+ while (1) {
+ if ((char *)de >= BLOCK_SIZE+bh->b_data) {
+ brelse(bh);
+ bh = NULL;
+ block = minix_create_block(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK);
+ if (!block)
+ return NULL;
+ if (!(bh = bread(dir->i_dev,block))) {
+ i += MINIX_DIR_ENTRIES_PER_BLOCK;
+ continue;
+ }
+ de = (struct minix_dir_entry *) bh->b_data;
+ }
+ if (i*sizeof(struct minix_dir_entry) >= dir->i_size) {
+ de->inode=0;
+ dir->i_size = (i+1)*sizeof(struct minix_dir_entry);
+ dir->i_dirt = 1;
+ dir->i_ctime = CURRENT_TIME;
+ }
+ if (!de->inode) {
+ dir->i_mtime = CURRENT_TIME;
+ for (i=0; i < MINIX_NAME_LEN ; i++)
+ de->name[i]=(i<namelen)?get_fs_byte(name+i):0;
+ bh->b_dirt = 1;
+ *res_dir = de;
+ return bh;
+ }
+ de++;
+ i++;
+ }
+ brelse(bh);
+ return NULL;
+}
+
+int minix_create(struct inode * dir,const char * name, int len, int mode,
+ struct inode ** result)
+{
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct minix_dir_entry * de;
+
+ *result = NULL;
+ if (!dir)
+ return -ENOENT;
+ inode = minix_new_inode(dir->i_dev);
+ if (!inode) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_mode = mode;
+ inode->i_dirt = 1;
+ bh = minix_add_entry(dir,name,len,&de);
+ if (!bh) {
+ inode->i_nlink--;
+ iput(inode);
+ iput(dir);
+ return -ENOSPC;
+ }
+ de->inode = inode->i_ino;
+ bh->b_dirt = 1;
+ brelse(bh);
+ iput(dir);
+ *result = inode;
+ return 0;
+}
+
+int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
+{
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct minix_dir_entry * de;
+
+ if (!dir)
+ return -ENOENT;
+ bh = minix_find_entry(dir,name,len,&de);
+ if (bh) {
+ brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ inode = minix_new_inode(dir->i_dev);
+ if (!inode) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_uid = current->euid;
+ inode->i_mode = mode;
+ if (S_ISBLK(mode) || S_ISCHR(mode))
+ inode->i_rdev = rdev;
+ inode->i_mtime = inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ bh = minix_add_entry(dir,name,len,&de);
+ if (!bh) {
+ inode->i_nlink--;
+ iput(inode);
+ iput(dir);
+ return -ENOSPC;
+ }
+ de->inode = inode->i_ino;
+ bh->b_dirt = 1;
+ brelse(bh);
+ iput(dir);
+ iput(inode);
+ return 0;
+}
+
+int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
+{
+ struct inode * inode;
+ struct buffer_head * bh, *dir_block;
+ struct minix_dir_entry * de;
+
+ bh = minix_find_entry(dir,name,len,&de);
+ if (bh) {
+ brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ inode = minix_new_inode(dir->i_dev);
+ if (!inode) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_size = 32;
+ inode->i_dirt = 1;
+ inode->i_mtime = inode->i_atime = CURRENT_TIME;
+ if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) {
+ iput(dir);
+ inode->i_nlink--;
+ iput(inode);
+ return -ENOSPC;
+ }
+ inode->i_dirt = 1;
+ if (!(dir_block = bread(inode->i_dev,inode->i_data[0]))) {
+ iput(dir);
+ inode->i_nlink--;
+ iput(inode);
+ return -ERROR;
+ }
+ de = (struct minix_dir_entry *) dir_block->b_data;
+ de->inode=inode->i_ino;
+ strcpy(de->name,".");
+ de++;
+ de->inode = dir->i_ino;
+ strcpy(de->name,"..");
+ inode->i_nlink = 2;
+ dir_block->b_dirt = 1;
+ brelse(dir_block);
+ inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask);
+ inode->i_dirt = 1;
+ bh = minix_add_entry(dir,name,len,&de);
+ if (!bh) {
+ iput(dir);
+ inode->i_nlink=0;
+ iput(inode);
+ return -ENOSPC;
+ }
+ de->inode = inode->i_ino;
+ bh->b_dirt = 1;
+ dir->i_nlink++;
+ dir->i_dirt = 1;
+ iput(dir);
+ iput(inode);
+ brelse(bh);
+ return 0;
+}
+
+/*
+ * routine to check that the specified directory is empty (for rmdir)
+ */
+static int empty_dir(struct inode * inode)
+{
+ int nr,block;
+ int len;
+ struct buffer_head * bh;
+ struct minix_dir_entry * de;
+
+ len = inode->i_size / sizeof (struct minix_dir_entry);
+ if (len<2 || !inode->i_data[0] ||
+ !(bh=bread(inode->i_dev,inode->i_data[0]))) {
+ printk("warning - bad directory on dev %04x\n",inode->i_dev);
+ return 0;
+ }
+ de = (struct minix_dir_entry *) bh->b_data;
+ if (de[0].inode != inode->i_ino || !de[1].inode ||
+ strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
+ printk("warning - bad directory on dev %04x\n",inode->i_dev);
+ return 0;
+ }
+ nr = 2;
+ de += 2;
+ while (nr<len) {
+ if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
+ brelse(bh);
+ block=bmap(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK);
+ if (!block) {
+ nr += MINIX_DIR_ENTRIES_PER_BLOCK;
+ continue;
+ }
+ if (!(bh=bread(inode->i_dev,block)))
+ return 0;
+ de = (struct minix_dir_entry *) bh->b_data;
+ }
+ if (de->inode) {
+ brelse(bh);
+ return 0;
+ }
+ de++;
+ nr++;
+ }
+ brelse(bh);
+ return 1;
+}
+
+int minix_rmdir(struct inode * dir, const char * name, int len)
+{
+ int retval;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct minix_dir_entry * de;
+
+ inode = NULL;
+ bh = minix_find_entry(dir,name,len,&de);
+ retval = -ENOENT;
+ if (!bh)
+ goto end_rmdir;
+ retval = -EPERM;
+ if (!(inode = iget(dir->i_dev, de->inode)))
+ goto end_rmdir;
+ if ((dir->i_mode & S_ISVTX) && current->euid &&
+ inode->i_uid != current->euid)
+ goto end_rmdir;
+ if (inode->i_dev != dir->i_dev)
+ goto end_rmdir;
+ if (inode == dir) /* we may not delete ".", but "../dir" is ok */
+ goto end_rmdir;
+ if (!S_ISDIR(inode->i_mode)) {
+ retval = -ENOTDIR;
+ goto end_rmdir;
+ }
+ if (!empty_dir(inode)) {
+ retval = -ENOTEMPTY;
+ goto end_rmdir;
+ }
+ if (inode->i_count > 1) {
+ retval = -EBUSY;
+ goto end_rmdir;
+ }
+ if (inode->i_nlink != 2)
+ printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
+ de->inode = 0;
+ bh->b_dirt = 1;
+ inode->i_nlink=0;
+ inode->i_dirt=1;
+ dir->i_nlink--;
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_dirt=1;
+ retval = 0;
+end_rmdir:
+ iput(dir);
+ iput(inode);
+ brelse(bh);
+ return retval;
+}
+
+int minix_unlink(struct inode * dir, const char * name, int len)
+{
+ int retval;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct minix_dir_entry * de;
+
+ retval = -ENOENT;
+ inode = NULL;
+ bh = minix_find_entry(dir,name,len,&de);
+ if (!bh)
+ goto end_unlink;
+ if (!(inode = iget(dir->i_dev, de->inode)))
+ goto end_unlink;
+ retval = -EPERM;
+ if ((dir->i_mode & S_ISVTX) && !suser() &&
+ current->euid != inode->i_uid &&
+ current->euid != dir->i_uid)
+ goto end_unlink;
+ if (S_ISDIR(inode->i_mode))
+ goto end_unlink;
+ if (!inode->i_nlink) {
+ printk("Deleting nonexistent file (%04x:%d), %d\n",
+ inode->i_dev,inode->i_ino,inode->i_nlink);
+ inode->i_nlink=1;
+ }
+ de->inode = 0;
+ bh->b_dirt = 1;
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ inode->i_ctime = CURRENT_TIME;
+ retval = 0;
+end_unlink:
+ brelse(bh);
+ iput(inode);
+ iput(dir);
+ return retval;
+}
+
+int minix_symlink(struct inode * dir, const char * name, int len, const char * symname)
+{
+ struct minix_dir_entry * de;
+ struct inode * inode = NULL;
+ struct buffer_head * bh = NULL, * name_block = NULL;
+ int i;
+ char c;
+
+ if (!(inode = minix_new_inode(dir->i_dev))) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_mode = S_IFLNK | 0777;
+ inode->i_dirt = 1;
+ if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) {
+ iput(dir);
+ inode->i_nlink--;
+ iput(inode);
+ return -ENOSPC;
+ }
+ inode->i_dirt = 1;
+ if (!(name_block = bread(inode->i_dev,inode->i_data[0]))) {
+ iput(dir);
+ inode->i_nlink--;
+ iput(inode);
+ return -ERROR;
+ }
+ i = 0;
+ while (i < 1023 && (c=get_fs_byte(symname++)))
+ name_block->b_data[i++] = c;
+ name_block->b_data[i] = 0;
+ name_block->b_dirt = 1;
+ brelse(name_block);
+ inode->i_size = i;
+ inode->i_dirt = 1;
+ bh = minix_find_entry(dir,name,len,&de);
+ if (bh) {
+ inode->i_nlink--;
+ iput(inode);
+ brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ bh = minix_add_entry(dir,name,len,&de);
+ if (!bh) {
+ inode->i_nlink--;
+ iput(inode);
+ iput(dir);
+ return -ENOSPC;
+ }
+ de->inode = inode->i_ino;
+ bh->b_dirt = 1;
+ brelse(bh);
+ iput(dir);
+ iput(inode);
+ return 0;
+}
+
+int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
+{
+ struct minix_dir_entry * de;
+ struct buffer_head * bh;
+
+ if (S_ISDIR(oldinode->i_mode)) {
+ iput(oldinode);
+ iput(dir);
+ return -EPERM;
+ }
+ bh = minix_find_entry(dir,name,len,&de);
+ if (bh) {
+ brelse(bh);
+ iput(dir);
+ iput(oldinode);
+ return -EEXIST;
+ }
+ bh = minix_add_entry(dir,name,len,&de);
+ if (!bh) {
+ iput(dir);
+ iput(oldinode);
+ return -ENOSPC;
+ }
+ de->inode = oldinode->i_ino;
+ bh->b_dirt = 1;
+ brelse(bh);
+ iput(dir);
+ oldinode->i_nlink++;
+ oldinode->i_ctime = CURRENT_TIME;
+ oldinode->i_dirt = 1;
+ iput(oldinode);
+ return 0;
+}
+
+static int subdir(struct inode * new, struct inode * old)
+{
+ unsigned short fs;
+ int ino;
+ int result;
+
+ __asm__("mov %%fs,%0":"=r" (fs));
+ __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
+ new->i_count++;
+ result = 0;
+ for (;;) {
+ if (new == old) {
+ result = 1;
+ break;
+ }
+ if (new->i_dev != old->i_dev)
+ break;
+ ino = new->i_ino;
+ if (minix_lookup(new,"..",2,&new))
+ break;
+ if (new->i_ino == ino)
+ break;
+ }
+ iput(new);
+ __asm__("mov %0,%%fs"::"r" (fs));
+ return result;
+}
+
+#define PARENT_INO(buffer) \
+(((struct minix_dir_entry *) (buffer))[1].inode)
+
+#define PARENT_NAME(buffer) \
+(((struct minix_dir_entry *) (buffer))[1].name)
+
+/*
+ * rename uses retrying to avoid race-conditions: at least they should be minimal.
+ * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
+ * checks fail, it tries to restart itself again. Very practical - no changes
+ * are done until we know everything works ok.. and then all the changes can be
+ * done in one fell swoop when we have claimed all the buffers needed.
+ *
+ * Anybody can rename anything with this: the permission checks are left to the
+ * higher-level routines.
+ */
+static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len,
+ struct inode * new_dir, const char * new_name, int new_len)
+{
+ struct inode * old_inode, * new_inode;
+ struct buffer_head * old_bh, * new_bh, * dir_bh;
+ struct minix_dir_entry * old_de, * new_de;
+ int retval;
+
+ goto start_up;
+try_again:
+ brelse(old_bh);
+ brelse(new_bh);
+ brelse(dir_bh);
+ iput(old_inode);
+ iput(new_inode);
+ current->counter = 0;
+ schedule();
+start_up:
+ old_inode = new_inode = NULL;
+ old_bh = new_bh = dir_bh = NULL;
+ old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de);
+ retval = -ENOENT;
+ if (!old_bh)
+ goto end_rename;
+ old_inode = iget(old_dir->i_dev, old_de->inode);
+ if (!old_inode)
+ goto end_rename;
+ new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
+ if (new_bh) {
+ new_inode = iget(new_dir->i_dev, new_de->inode);
+ if (!new_inode) {
+ brelse(new_bh);
+ new_bh = NULL;
+ }
+ }
+ if (new_inode == old_inode) {
+ retval = 0;
+ goto end_rename;
+ }
+ if (S_ISDIR(old_inode->i_mode)) {
+ retval = -EEXIST;
+ if (new_bh)
+ goto end_rename;
+ retval = -EACCES;
+ if (!permission(old_inode, MAY_WRITE))
+ goto end_rename;
+ retval = -EINVAL;
+ if (subdir(new_dir, old_inode))
+ goto end_rename;
+ retval = -EIO;
+ if (!old_inode->i_data[0])
+ goto end_rename;
+ if (!(dir_bh = bread(old_inode->i_dev, old_inode->i_data[0])))
+ goto end_rename;
+ if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
+ goto end_rename;
+ }
+ if (!new_bh)
+ new_bh = minix_add_entry(new_dir,new_name,new_len,&new_de);
+ retval = -ENOSPC;
+ if (!new_bh)
+ goto end_rename;
+/* sanity checking before doing the rename - avoid races */
+ if (new_inode && (new_de->inode != new_inode->i_ino))
+ goto try_again;
+ if (new_de->inode && !new_inode)
+ goto try_again;
+ if (old_de->inode != old_inode->i_ino)
+ goto try_again;
+/* ok, that's it */
+ old_de->inode = 0;
+ new_de->inode = old_inode->i_ino;
+ if (new_inode)
+ new_inode->i_nlink--;
+ old_bh->b_dirt = 1;
+ new_bh->b_dirt = 1;
+ if (dir_bh) {
+ PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
+ dir_bh->b_dirt = 1;
+ old_dir->i_nlink--;
+ new_dir->i_nlink++;
+ old_dir->i_dirt = 1;
+ new_dir->i_dirt = 1;
+ }
+ retval = 0;
+end_rename:
+ brelse(dir_bh);
+ brelse(old_bh);
+ brelse(new_bh);
+ iput(old_inode);
+ iput(new_inode);
+ iput(old_dir);
+ iput(new_dir);
+ return retval;
+}
+
+/*
+ * Ok, rename also locks out other renames, as they can change the parent of
+ * a directory, and we don't want any races. Other races are checked for by
+ * "do_rename()", which restarts if there are inconsistencies.
+ *
+ * Note that there is no race between different filesystems: it's only within
+ * the same device that races occur: many renames can happen at once, as long
+ * as they are on different partitions.
+ */
+int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
+ struct inode * new_dir, const char * new_name, int new_len)
+{
+ static struct task_struct * wait = NULL;
+ static int lock = 0;
+ int result;
+
+ while (lock)
+ sleep_on(&wait);
+ lock = 1;
+ result = do_minix_rename(old_dir, old_name, old_len,
+ new_dir, new_name, new_len);
+ lock = 0;
+ wake_up(&wait);
+ return result;
+}
+
+int minix_readlink(struct inode * inode, char * buffer, int buflen)
+{
+ struct buffer_head * bh;
+ int i;
+ char c;
+
+ if (!S_ISLNK(inode->i_mode)) {
+ iput(inode);
+ return -EINVAL;
+ }
+ if (buflen > 1023)
+ buflen = 1023;
+ if (inode->i_data[0])
+ bh = bread(inode->i_dev, inode->i_data[0]);
+ else
+ bh = NULL;
+ iput(inode);
+ if (!bh)
+ return 0;
+ i = 0;
+ while (i<buflen && (c = bh->b_data[i])) {
+ i++;
+ put_fs_byte(c,buffer++);
+ }
+ brelse(bh);
+ return i;
+}
diff --git a/fs/minix/truncate.c b/fs/minix/truncate.c
new file mode 100644
index 0000000..4f163bd
--- /dev/null
+++ b/fs/minix/truncate.c
@@ -0,0 +1,154 @@
+/*
+ * linux/fs/truncate.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/tty.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+static int minix_free_ind(int dev,int block)
+{
+ struct buffer_head * bh;
+ unsigned short * p;
+ int i;
+ int block_busy;
+
+ if (!block)
+ return 1;
+ block_busy = 0;
+ if (bh=bread(dev,block)) {
+ p = (unsigned short *) bh->b_data;
+ for (i=0;i<512;i++,p++)
+ if (*p)
+ if (minix_free_block(dev,*p)) {
+ *p = 0;
+ bh->b_dirt = 1;
+ } else
+ block_busy = 1;
+ brelse(bh);
+ }
+ if (block_busy)
+ return 0;
+ else
+ return minix_free_block(dev,block);
+}
+
+static int minix_free_dind(int dev,int block)
+{
+ struct buffer_head * bh;
+ unsigned short * p;
+ int i;
+ int block_busy;
+
+ if (!block)
+ return 1;
+ block_busy = 0;
+ if (bh=bread(dev,block)) {
+ p = (unsigned short *) bh->b_data;
+ for (i=0;i<512;i++,p++)
+ if (*p)
+ if (minix_free_ind(dev,*p)) {
+ *p = 0;
+ bh->b_dirt = 1;
+ } else
+ block_busy = 1;
+ brelse(bh);
+ }
+ if (block_busy)
+ return 0;
+ else
+ return minix_free_block(dev,block);
+}
+
+void minix_truncate(struct inode * inode)
+{
+ int i;
+ int block_busy;
+
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)))
+ return;
+repeat:
+ block_busy = 0;
+ for (i=0;i<7;i++)
+ if (inode->i_data[i]) {
+ if (minix_free_block(inode->i_dev,inode->i_data[i]))
+ inode->i_data[i]=0;
+ else
+ block_busy = 1;
+ }
+ if (minix_free_ind(inode->i_dev,inode->i_data[7]))
+ inode->i_data[7] = 0;
+ else
+ block_busy = 1;
+ if (minix_free_dind(inode->i_dev,inode->i_data[8]))
+ inode->i_data[8] = 0;
+ else
+ block_busy = 1;
+ inode->i_dirt = 1;
+ if (block_busy) {
+ current->counter = 0;
+ schedule();
+ goto repeat;
+ }
+ inode->i_size = 0;
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+}
+
+/*
+ * Called when a inode is released. Note that this is different
+ * from minix_open: open gets called at every open, but release
+ * gets called only when /all/ the files are closed.
+ */
+void minix_release(struct inode * inode, struct file * filp)
+{
+ printk("minix_release not implemented\n");
+}
+
+static int check_char_dev(struct inode * inode, struct file * filp)
+{
+ struct tty_struct *tty;
+ int min, dev;
+
+ dev = inode->i_rdev;
+ if (MAJOR(dev) == 4 || MAJOR(dev) == 5) {
+ if (MAJOR(dev) == 5)
+ min = current->tty;
+ else
+ min = MINOR(dev);
+ if (min < 0)
+ return -1;
+ if ((IS_A_PTY_MASTER(min)) && (inode->i_count>1))
+ return -1;
+ tty = TTY_TABLE(min);
+ if (!(filp->f_flags & O_NOCTTY) &&
+ current->leader &&
+ current->tty<0 &&
+ tty->session==0) {
+ current->tty = min;
+ tty->session= current->session;
+ tty->pgrp = current->pgrp;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Called every time a minix-file is opened
+ */
+int minix_open(struct inode * inode, struct file * filp)
+{
+ if (S_ISCHR(inode->i_mode)) {
+ if (check_char_dev(inode,filp))
+ return -EAGAIN;
+ } else if (S_ISBLK(inode->i_mode))
+ check_disk_change(inode->i_rdev);
+ filp->f_op = &minix_file_operations;
+ return 0;
+}
diff --git a/fs/namei.c b/fs/namei.c
index 8b99d70..f1a0e8f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -9,6 +9,7 @@
*/
#include <linux/sched.h>
+#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <asm/segment.h>
@@ -18,21 +19,17 @@
#include <const.h>
#include <sys/stat.h>
-static struct m_inode * _namei(const char * filename, struct m_inode * base,
+struct inode * _namei(const char * filename, struct inode * base,
int follow_links);
#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])
/*
- * comment out this line if you want names > NAME_LEN chars to be
+ * comment out this line if you want names > MINIX_NAME_LEN chars to be
* truncated. Else they will be disallowed.
*/
/* #define NO_TRUNCATE */
-#define MAY_EXEC 1
-#define MAY_WRITE 2
-#define MAY_READ 4
-
/*
* permission()
*
@@ -40,14 +37,14 @@ static struct m_inode * _namei(const char * filename, struct m_inode * base,
* I don't know if we should look at just the euid or both euid and
* uid, but that should be easily changed.
*/
-static int permission(struct m_inode * inode,int mask)
+int permission(struct inode * inode,int mask)
{
int mode = inode->i_mode;
/* special case: not even root can read/write a deleted file */
- if (inode->i_dev && !inode->i_nlinks)
+ if (inode->i_dev && !inode->i_nlink)
return 0;
- else if (current->euid==inode->i_uid)
+ else if (current->euid == inode->i_uid)
mode >>= 6;
else if (in_group_p(inode->i_gid))
mode >>= 3;
@@ -57,300 +54,113 @@ static int permission(struct m_inode * inode,int mask)
}
/*
- * ok, we cannot use strncmp, as the name is not in our data space.
- * Thus we'll have to use match. No big problem. Match also makes
- * some sanity tests.
- *
- * NOTE! unlike strncmp, match returns 1 for success, 0 for failure.
- */
-static int match(int len,const char * name,struct dir_entry * de)
-{
- register int same __asm__("ax");
-
- if (!de || !de->inode || len > NAME_LEN)
- return 0;
- /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
- if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
- return 1;
- if (len < NAME_LEN && de->name[len])
- return 0;
- __asm__("cld\n\t"
- "fs ; repe ; cmpsb\n\t"
- "setz %%al"
- :"=a" (same)
- :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
- :"cx","di","si");
- return same;
-}
-
-/*
- * find_entry()
- *
- * finds an entry in the specified directory with the wanted name. It
- * returns the cache buffer in which the entry was found, and the entry
- * itself (as a parameter - res_dir). It does NOT read the inode of the
- * entry - you'll have to do that yourself if you want to.
- *
- * This also takes care of the few special cases due to '..'-traversal
- * over a pseudo-root and a mount point.
+ * lookup() looks up one part of a pathname, using the fs-dependent
+ * routines (currently minix_lookup) for it. It also checks for
+ * fathers (pseudo-roots, mount-points)
*/
-static struct buffer_head * find_entry(struct m_inode ** dir,
- const char * name, int namelen, struct dir_entry ** res_dir)
+int lookup(struct inode * dir,const char * name, int len,
+ struct inode ** result)
{
- int entries;
- int block,i;
- struct buffer_head * bh;
- struct dir_entry * de;
struct super_block * sb;
-#ifdef NO_TRUNCATE
- if (namelen > NAME_LEN)
- return NULL;
-#else
- if (namelen > NAME_LEN)
- namelen = NAME_LEN;
-#endif
- entries = (*dir)->i_size / (sizeof (struct dir_entry));
- *res_dir = NULL;
-/* check for '..', as we might have to do some "magic" for it */
- if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') {
-/* '..' in a pseudo-root results in a faked '.' (just change namelen) */
- if ((*dir) == current->root)
- namelen=1;
- else if ((*dir)->i_num == ROOT_INO) {
-/* '..' over a mount-point results in 'dir' being exchanged for the mounted
- directory-inode. NOTE! We set mounted, so that we can iput the new dir */
- sb=get_super((*dir)->i_dev);
- if (sb->s_imount) {
- iput(*dir);
- (*dir)=sb->s_imount;
- (*dir)->i_count++;
- }
+ *result = NULL;
+ if (len==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') {
+ if (dir == current->root)
+ len = 1;
+ else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) {
+ sb = dir->i_sb;
+ iput(dir);
+ if (dir = sb->s_covered)
+ dir->i_count++;
}
}
- if (!(block = (*dir)->i_zone[0]))
- return NULL;
- if (!(bh = bread((*dir)->i_dev,block)))
- return NULL;
- i = 0;
- de = (struct dir_entry *) bh->b_data;
- while (i < entries) {
- if ((char *)de >= BLOCK_SIZE+bh->b_data) {
- brelse(bh);
- bh = NULL;
- if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) ||
- !(bh = bread((*dir)->i_dev,block))) {
- i += DIR_ENTRIES_PER_BLOCK;
- continue;
- }
- de = (struct dir_entry *) bh->b_data;
- }
- if (match(namelen,name,de)) {
- *res_dir = de;
- return bh;
- }
- de++;
- i++;
+ if (!dir)
+ return -ENOENT;
+ if (!permission(dir,MAY_EXEC)) {
+ iput(dir);
+ return -EACCES;
}
- brelse(bh);
- return NULL;
-}
-
-/*
- * add_entry()
- *
- * adds a file entry to the specified directory, using the same
- * semantics as find_entry(). It returns NULL if it failed.
- *
- * NOTE!! The inode part of 'de' is left at 0 - which means you
- * may not sleep between calling this and putting something into
- * the entry, as someone else might have used it while you slept.
- */
-static struct buffer_head * add_entry(struct m_inode * dir,
- const char * name, int namelen, struct dir_entry ** res_dir)
-{
- int block,i;
- struct buffer_head * bh;
- struct dir_entry * de;
-
- *res_dir = NULL;
-#ifdef NO_TRUNCATE
- if (namelen > NAME_LEN)
- return NULL;
-#else
- if (namelen > NAME_LEN)
- namelen = NAME_LEN;
-#endif
- if (!namelen)
- return NULL;
- if (!(block = dir->i_zone[0]))
- return NULL;
- if (!(bh = bread(dir->i_dev,block)))
- return NULL;
- i = 0;
- de = (struct dir_entry *) bh->b_data;
- while (1) {
- if ((char *)de >= BLOCK_SIZE+bh->b_data) {
- brelse(bh);
- bh = NULL;
- block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK);
- if (!block)
- return NULL;
- if (!(bh = bread(dir->i_dev,block))) {
- i += DIR_ENTRIES_PER_BLOCK;
- continue;
- }
- de = (struct dir_entry *) bh->b_data;
- }
- if (i*sizeof(struct dir_entry) >= dir->i_size) {
- de->inode=0;
- dir->i_size = (i+1)*sizeof(struct dir_entry);
- dir->i_dirt = 1;
- dir->i_ctime = CURRENT_TIME;
- }
- if (!de->inode) {
- dir->i_mtime = CURRENT_TIME;
- for (i=0; i < NAME_LEN ; i++)
- de->name[i]=(i<namelen)?get_fs_byte(name+i):0;
- bh->b_dirt = 1;
- *res_dir = de;
- return bh;
- }
- de++;
- i++;
+ if (!len) {
+ *result = dir;
+ return 0;
+ }
+ if (!dir->i_op || !dir->i_op->lookup) {
+ iput(dir);
+ return -ENOENT;
}
- brelse(bh);
- return NULL;
+ return dir->i_op->lookup(dir,name,len,result);
}
-static struct m_inode * follow_link(struct m_inode * dir, struct m_inode * inode)
+struct inode * follow_link(struct inode * dir, struct inode * inode)
{
- unsigned short fs;
- struct buffer_head * bh;
-
- if (!dir) {
- dir = current->root;
- dir->i_count++;
- }
- if (!inode) {
+ if (!dir || !inode) {
iput(dir);
+ iput(inode);
return NULL;
}
- if (!S_ISLNK(inode->i_mode)) {
+ if (!inode->i_op || !inode->i_op->follow_link) {
iput(dir);
return inode;
}
- __asm__("mov %%fs,%0":"=r" (fs));
- if (fs != 0x17 || !inode->i_zone[0] ||
- !(bh = bread(inode->i_dev, inode->i_zone[0]))) {
- iput(dir);
- iput(inode);
- return NULL;
- }
- iput(inode);
- __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
- inode = _namei(bh->b_data,dir,0);
- __asm__("mov %0,%%fs"::"r" (fs));
- brelse(bh);
- return inode;
+ return inode->i_op->follow_link(dir,inode);
}
/*
- * get_dir()
+ * dir_namei()
*
- * Getdir traverses the pathname until it hits the topmost directory.
- * It returns NULL on failure.
+ * dir_namei() returns the inode of the directory of the
+ * specified name, and the name within that directory.
*/
-static struct m_inode * get_dir(const char * pathname, struct m_inode * inode)
+static struct inode * dir_namei(const char * pathname,
+ int * namelen, const char ** name, struct inode * base)
{
char c;
const char * thisname;
- struct buffer_head * bh;
- int namelen,inr;
- struct dir_entry * de;
- struct m_inode * dir;
+ int len,error;
+ struct inode * inode;
- if (!inode) {
- inode = current->pwd;
- inode->i_count++;
+ if (!base) {
+ base = current->pwd;
+ base->i_count++;
}
if ((c=get_fs_byte(pathname))=='/') {
- iput(inode);
- inode = current->root;
+ iput(base);
+ base = current->root;
pathname++;
- inode->i_count++;
+ base->i_count++;
}
while (1) {
thisname = pathname;
- if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) {
- iput(inode);
- return NULL;
- }
- for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++)
+ for(len=0;(c=get_fs_byte(pathname++))&&(c!='/');len++)
/* nothing */ ;
if (!c)
- return inode;
- if (!(bh = find_entry(&inode,thisname,namelen,&de))) {
- iput(inode);
- return NULL;
- }
- inr = de->inode;
- brelse(bh);
- dir = inode;
- if (!(inode = iget(dir->i_dev,inr))) {
- iput(dir);
+ break;
+ base->i_count++;
+ error = lookup(base,thisname,len,&inode);
+ if (error) {
+ iput(base);
return NULL;
}
- if (!(inode = follow_link(dir,inode)))
+ if (!(base = follow_link(base,inode)))
return NULL;
}
+ *name = thisname;
+ *namelen = len;
+ return base;
}
-/*
- * dir_namei()
- *
- * dir_namei() returns the inode of the directory of the
- * specified name, and the name within that directory.
- */
-static struct m_inode * dir_namei(const char * pathname,
- int * namelen, const char ** name, struct m_inode * base)
-{
- char c;
- const char * basename;
- struct m_inode * dir;
-
- if (!(dir = get_dir(pathname,base)))
- return NULL;
- basename = pathname;
- while (c=get_fs_byte(pathname++))
- if (c=='/')
- basename=pathname;
- *namelen = pathname-basename-1;
- *name = basename;
- return dir;
-}
-
-struct m_inode * _namei(const char * pathname, struct m_inode * base,
+struct inode * _namei(const char * pathname, struct inode * base,
int follow_links)
{
const char * basename;
- int inr,namelen;
- struct m_inode * inode;
- struct buffer_head * bh;
- struct dir_entry * de;
+ int namelen,error;
+ struct inode * inode;
if (!(base = dir_namei(pathname,&namelen,&basename,base)))
return NULL;
- if (!namelen) /* special case: '/usr/' etc */
- return base;
- bh = find_entry(&base,basename,namelen,&de);
- if (!bh) {
- iput(base);
- return NULL;
- }
- inr = de->inode;
- brelse(bh);
- if (!(inode = iget(base->i_dev,inr))) {
+ base->i_count++; /* lookup uses up base */
+ error = lookup(base,basename,namelen,&inode);
+ if (error) {
iput(base);
return NULL;
}
@@ -358,12 +168,14 @@ struct m_inode * _namei(const char * pathname, struct m_inode * base,
inode = follow_link(base,inode);
else
iput(base);
- inode->i_atime=CURRENT_TIME;
- inode->i_dirt=1;
+ if (inode) {
+ inode->i_atime=CURRENT_TIME;
+ inode->i_dirt=1;
+ }
return inode;
}
-struct m_inode * lnamei(const char * pathname)
+struct inode * lnamei(const char * pathname)
{
return _namei(pathname, NULL, 0);
}
@@ -375,7 +187,7 @@ struct m_inode * lnamei(const char * pathname)
* Open, link etc use their own routines, but this is enough for things
* like 'chmod' etc.
*/
-struct m_inode * namei(const char * pathname)
+struct inode * namei(const char * pathname)
{
return _namei(pathname,NULL,1);
}
@@ -386,13 +198,11 @@ struct m_inode * namei(const char * pathname)
* namei for open - this is in fact almost the whole open-routine.
*/
int open_namei(const char * pathname, int flag, int mode,
- struct m_inode ** res_inode)
+ struct inode ** res_inode)
{
const char * basename;
- int inr,dev,namelen;
- struct m_inode * dir, *inode;
- struct buffer_head * bh;
- struct dir_entry * de;
+ int namelen,error;
+ struct inode * dir, *inode;
if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
flag |= O_WRONLY;
@@ -408,47 +218,30 @@ int open_namei(const char * pathname, int flag, int mode,
iput(dir);
return -EISDIR;
}
- bh = find_entry(&dir,basename,namelen,&de);
- if (!bh) {
+ dir->i_count++; /* lookup eats the dir */
+ error = lookup(dir,basename,namelen,&inode);
+ if (error) {
if (!(flag & O_CREAT)) {
iput(dir);
- return -ENOENT;
+ return error;
}
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EACCES;
}
- inode = new_inode(dir->i_dev);
- if (!inode) {
- iput(dir);
- return -ENOSPC;
- }
- inode->i_uid = current->euid;
- inode->i_mode = mode;
- inode->i_dirt = 1;
- bh = add_entry(dir,basename,namelen,&de);
- if (!bh) {
- inode->i_nlinks--;
- iput(inode);
+ if (!dir->i_op || !dir->i_op->create) {
iput(dir);
- return -ENOSPC;
+ return -EACCES;
}
- de->inode = inode->i_num;
- bh->b_dirt = 1;
- brelse(bh);
- iput(dir);
- *res_inode = inode;
- return 0;
+ return dir->i_op->create(dir,basename,namelen,mode,res_inode);
}
- inr = de->inode;
- dev = dir->i_dev;
- brelse(bh);
if (flag & O_EXCL) {
iput(dir);
+ iput(inode);
return -EEXIST;
}
- if (!(inode = follow_link(dir,iget(dev,inr))))
- return -EACCES;
+ if (!(inode = follow_link(dir,inode)))
+ return -ELOOP;
if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
!permission(inode,ACC_MODE(flag))) {
iput(inode);
@@ -456,7 +249,7 @@ int open_namei(const char * pathname, int flag, int mode,
}
inode->i_atime = CURRENT_TIME;
if (flag & O_TRUNC)
- truncate(inode);
+ minix_truncate(inode);
*res_inode = inode;
return 0;
}
@@ -465,9 +258,7 @@ int sys_mknod(const char * filename, int mode, int dev)
{
const char * basename;
int namelen;
- struct m_inode * dir, * inode;
- struct buffer_head * bh;
- struct dir_entry * de;
+ struct inode * dir;
if (!suser())
return -EPERM;
@@ -481,44 +272,18 @@ int sys_mknod(const char * filename, int mode, int dev)
iput(dir);
return -EPERM;
}
- bh = find_entry(&dir,basename,namelen,&de);
- if (bh) {
- brelse(bh);
+ if (!dir->i_op || !dir->i_op->mknod) {
iput(dir);
- return -EEXIST;
- }
- inode = new_inode(dir->i_dev);
- if (!inode) {
- iput(dir);
- return -ENOSPC;
- }
- inode->i_mode = mode;
- if (S_ISBLK(mode) || S_ISCHR(mode))
- inode->i_zone[0] = dev;
- inode->i_mtime = inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- bh = add_entry(dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- inode->i_nlinks=0;
- iput(inode);
- return -ENOSPC;
+ return -EPERM;
}
- de->inode = inode->i_num;
- bh->b_dirt = 1;
- iput(dir);
- iput(inode);
- brelse(bh);
- return 0;
+ return dir->i_op->mknod(dir,basename,namelen,mode,dev);
}
int sys_mkdir(const char * pathname, int mode)
{
const char * basename;
int namelen;
- struct m_inode * dir, * inode;
- struct buffer_head * bh, *dir_block;
- struct dir_entry * de;
+ struct inode * dir;
if (!(dir = dir_namei(pathname,&namelen,&basename, NULL)))
return -ENOENT;
@@ -530,115 +295,18 @@ int sys_mkdir(const char * pathname, int mode)
iput(dir);
return -EPERM;
}
- bh = find_entry(&dir,basename,namelen,&de);
- if (bh) {
- brelse(bh);
- iput(dir);
- return -EEXIST;
- }
- inode = new_inode(dir->i_dev);
- if (!inode) {
- iput(dir);
- return -ENOSPC;
- }
- inode->i_size = 32;
- inode->i_dirt = 1;
- inode->i_mtime = inode->i_atime = CURRENT_TIME;
- if (!(inode->i_zone[0]=new_block(inode->i_dev))) {
+ if (!dir->i_op || !dir->i_op->mkdir) {
iput(dir);
- inode->i_nlinks--;
- iput(inode);
- return -ENOSPC;
- }
- inode->i_dirt = 1;
- if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) {
- iput(dir);
- inode->i_nlinks--;
- iput(inode);
- return -ERROR;
- }
- de = (struct dir_entry *) dir_block->b_data;
- de->inode=inode->i_num;
- strcpy(de->name,".");
- de++;
- de->inode = dir->i_num;
- strcpy(de->name,"..");
- inode->i_nlinks = 2;
- dir_block->b_dirt = 1;
- brelse(dir_block);
- inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask);
- inode->i_dirt = 1;
- bh = add_entry(dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- inode->i_nlinks=0;
- iput(inode);
- return -ENOSPC;
- }
- de->inode = inode->i_num;
- bh->b_dirt = 1;
- dir->i_nlinks++;
- dir->i_dirt = 1;
- iput(dir);
- iput(inode);
- brelse(bh);
- return 0;
-}
-
-/*
- * routine to check that the specified directory is empty (for rmdir)
- */
-static int empty_dir(struct m_inode * inode)
-{
- int nr,block;
- int len;
- struct buffer_head * bh;
- struct dir_entry * de;
-
- len = inode->i_size / sizeof (struct dir_entry);
- if (len<2 || !inode->i_zone[0] ||
- !(bh=bread(inode->i_dev,inode->i_zone[0]))) {
- printk("warning - bad directory on dev %04x\n",inode->i_dev);
- return 0;
- }
- de = (struct dir_entry *) bh->b_data;
- if (de[0].inode != inode->i_num || !de[1].inode ||
- strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
- printk("warning - bad directory on dev %04x\n",inode->i_dev);
- return 0;
- }
- nr = 2;
- de += 2;
- while (nr<len) {
- if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
- brelse(bh);
- block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK);
- if (!block) {
- nr += DIR_ENTRIES_PER_BLOCK;
- continue;
- }
- if (!(bh=bread(inode->i_dev,block)))
- return 0;
- de = (struct dir_entry *) bh->b_data;
- }
- if (de->inode) {
- brelse(bh);
- return 0;
- }
- de++;
- nr++;
+ return -EPERM;
}
- brelse(bh);
- return 1;
+ return dir->i_op->mkdir(dir,basename,namelen,mode);
}
int sys_rmdir(const char * name)
{
const char * basename;
int namelen;
- struct m_inode * dir, * inode;
- struct buffer_head * bh;
- struct dir_entry * de;
+ struct inode * dir;
if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
return -ENOENT;
@@ -650,69 +318,18 @@ int sys_rmdir(const char * name)
iput(dir);
return -EPERM;
}
- bh = find_entry(&dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- return -ENOENT;
- }
- if (!(inode = iget(dir->i_dev, de->inode))) {
+ if (!dir->i_op || !dir->i_op->rmdir) {
iput(dir);
- brelse(bh);
return -EPERM;
}
- if ((dir->i_mode & S_ISVTX) && current->euid &&
- inode->i_uid != current->euid) {
- iput(dir);
- iput(inode);
- brelse(bh);
- return -EPERM;
- }
- if (inode->i_dev != dir->i_dev || inode->i_count>1) {
- iput(dir);
- iput(inode);
- brelse(bh);
- return -EPERM;
- }
- if (inode == dir) { /* we may not delete ".", but "../dir" is ok */
- iput(inode);
- iput(dir);
- brelse(bh);
- return -EPERM;
- }
- if (!S_ISDIR(inode->i_mode)) {
- iput(inode);
- iput(dir);
- brelse(bh);
- return -ENOTDIR;
- }
- if (!empty_dir(inode)) {
- iput(inode);
- iput(dir);
- brelse(bh);
- return -ENOTEMPTY;
- }
- if (inode->i_nlinks != 2)
- printk("empty directory has nlink!=2 (%d)",inode->i_nlinks);
- de->inode = 0;
- bh->b_dirt = 1;
- brelse(bh);
- inode->i_nlinks=0;
- inode->i_dirt=1;
- dir->i_nlinks--;
- dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->i_dirt=1;
- iput(dir);
- iput(inode);
- return 0;
+ return dir->i_op->rmdir(dir,basename,namelen);
}
int sys_unlink(const char * name)
{
const char * basename;
int namelen;
- struct m_inode * dir, * inode;
- struct buffer_head * bh;
- struct dir_entry * de;
+ struct inode * dir;
if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
return -ENOENT;
@@ -724,54 +341,18 @@ int sys_unlink(const char * name)
iput(dir);
return -EPERM;
}
- bh = find_entry(&dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- return -ENOENT;
- }
- if (!(inode = iget(dir->i_dev, de->inode))) {
- iput(dir);
- brelse(bh);
- return -ENOENT;
- }
- if ((dir->i_mode & S_ISVTX) && !suser() &&
- current->euid != inode->i_uid &&
- current->euid != dir->i_uid) {
- iput(dir);
- iput(inode);
- brelse(bh);
- return -EPERM;
- }
- if (S_ISDIR(inode->i_mode)) {
- iput(inode);
+ if (!dir->i_op || !dir->i_op->unlink) {
iput(dir);
- brelse(bh);
return -EPERM;
}
- if (!inode->i_nlinks) {
- printk("Deleting nonexistent file (%04x:%d), %d\n",
- inode->i_dev,inode->i_num,inode->i_nlinks);
- inode->i_nlinks=1;
- }
- de->inode = 0;
- bh->b_dirt = 1;
- brelse(bh);
- inode->i_nlinks--;
- inode->i_dirt = 1;
- inode->i_ctime = CURRENT_TIME;
- iput(inode);
- iput(dir);
- return 0;
+ return dir->i_op->unlink(dir,basename,namelen);
}
int sys_symlink(const char * oldname, const char * newname)
{
- struct dir_entry * de;
- struct m_inode * dir, * inode;
- struct buffer_head * bh, * name_block;
+ struct inode * dir;
const char * basename;
- int namelen, i;
- char c;
+ int namelen;
dir = dir_namei(newname,&namelen,&basename, NULL);
if (!dir)
@@ -782,73 +363,24 @@ int sys_symlink(const char * oldname, const char * newname)
}
if (!permission(dir,MAY_WRITE)) {
iput(dir);
- return -EACCES;
- }
- if (!(inode = new_inode(dir->i_dev))) {
- iput(dir);
- return -ENOSPC;
- }
- inode->i_mode = S_IFLNK | (0777 & ~current->umask);
- inode->i_dirt = 1;
- if (!(inode->i_zone[0]=new_block(inode->i_dev))) {
- iput(dir);
- inode->i_nlinks--;
- iput(inode);
- return -ENOSPC;
- }
- inode->i_dirt = 1;
- if (!(name_block=bread(inode->i_dev,inode->i_zone[0]))) {
- iput(dir);
- inode->i_nlinks--;
- iput(inode);
- return -ERROR;
- }
- i = 0;
- while (i < 1023 && (c=get_fs_byte(oldname++)))
- name_block->b_data[i++] = c;
- name_block->b_data[i] = 0;
- name_block->b_dirt = 1;
- brelse(name_block);
- inode->i_size = i;
- inode->i_dirt = 1;
- bh = find_entry(&dir,basename,namelen,&de);
- if (bh) {
- inode->i_nlinks--;
- iput(inode);
- brelse(bh);
- iput(dir);
- return -EEXIST;
+ return -EPERM;
}
- bh = add_entry(dir,basename,namelen,&de);
- if (!bh) {
- inode->i_nlinks--;
- iput(inode);
+ if (!dir->i_op || !dir->i_op->symlink) {
iput(dir);
- return -ENOSPC;
+ return -EPERM;
}
- de->inode = inode->i_num;
- bh->b_dirt = 1;
- brelse(bh);
- iput(dir);
- iput(inode);
- return 0;
+ return dir->i_op->symlink(dir,basename,namelen,oldname);
}
int sys_link(const char * oldname, const char * newname)
{
- struct dir_entry * de;
- struct m_inode * oldinode, * dir;
- struct buffer_head * bh;
+ struct inode * oldinode, * dir;
const char * basename;
int namelen;
- oldinode=namei(oldname);
+ oldinode = namei(oldname);
if (!oldinode)
return -ENOENT;
- if (S_ISDIR(oldinode->i_mode)) {
- iput(oldinode);
- return -EPERM;
- }
dir = dir_namei(newname,&namelen,&basename, NULL);
if (!dir) {
iput(oldinode);
@@ -869,26 +401,60 @@ int sys_link(const char * oldname, const char * newname)
iput(oldinode);
return -EACCES;
}
- bh = find_entry(&dir,basename,namelen,&de);
- if (bh) {
- brelse(bh);
+ if (!dir->i_op || !dir->i_op->link) {
iput(dir);
iput(oldinode);
- return -EEXIST;
+ return -EPERM;
}
- bh = add_entry(dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- iput(oldinode);
- return -ENOSPC;
- }
- de->inode = oldinode->i_num;
- bh->b_dirt = 1;
- brelse(bh);
- iput(dir);
- oldinode->i_nlinks++;
- oldinode->i_ctime = CURRENT_TIME;
- oldinode->i_dirt = 1;
- iput(oldinode);
- return 0;
+ return dir->i_op->link(oldinode, dir, basename, namelen);
+}
+
+int sys_rename(const char * oldname, const char * newname)
+{
+ struct inode * old_dir, * new_dir;
+ const char * old_base, * new_base;
+ int old_len, new_len;
+
+ old_dir = dir_namei(oldname,&old_len,&old_base, NULL);
+ if (!old_dir)
+ return -ENOENT;
+ if (!permission(old_dir,MAY_WRITE)) {
+ iput(old_dir);
+ return -EACCES;
+ }
+ if (!old_len || (get_fs_byte(old_base) == '.' &&
+ (old_len == 1 || (get_fs_byte(old_base+1) == '.' &&
+ old_len == 2)))) {
+ iput(old_dir);
+ return -EPERM;
+ }
+ new_dir = dir_namei(newname,&new_len,&new_base, NULL);
+ if (!new_dir) {
+ iput(old_dir);
+ return -ENOENT;
+ }
+ if (!permission(new_dir,MAY_WRITE)) {
+ iput(old_dir);
+ iput(new_dir);
+ return -EACCES;
+ }
+ if (!new_len || (get_fs_byte(new_base) == '.' &&
+ (new_len == 1 || (get_fs_byte(new_base+1) == '.' &&
+ new_len == 2)))) {
+ iput(old_dir);
+ iput(new_dir);
+ return -EPERM;
+ }
+ if (new_dir->i_dev != old_dir->i_dev) {
+ iput(old_dir);
+ iput(new_dir);
+ return -EXDEV;
+ }
+ if (!old_dir->i_op || !old_dir->i_op->rename) {
+ iput(old_dir);
+ iput(new_dir);
+ return -EPERM;
+ }
+ return old_dir->i_op->rename(old_dir, old_base, old_len,
+ new_dir, new_base, new_len);
}
diff --git a/fs/open.c b/fs/open.c
index 92c8973..9653b83 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -12,7 +12,6 @@
#include <sys/stat.h>
#include <linux/sched.h>
-#include <linux/tty.h>
#include <linux/kernel.h>
#include <asm/segment.h>
@@ -24,7 +23,7 @@ int sys_ustat(int dev, struct ustat * ubuf)
int sys_utime(char * filename, struct utimbuf * times)
{
- struct m_inode * inode;
+ struct inode * inode;
long actime,modtime;
if (!(inode=namei(filename)))
@@ -47,7 +46,7 @@ int sys_utime(char * filename, struct utimbuf * times)
*/
int sys_access(const char * filename,int mode)
{
- struct m_inode * inode;
+ struct inode * inode;
int res, i_mode;
mode &= 0007;
@@ -75,7 +74,7 @@ int sys_access(const char * filename,int mode)
int sys_chdir(const char * filename)
{
- struct m_inode * inode;
+ struct inode * inode;
if (!(inode = namei(filename)))
return -ENOENT;
@@ -90,7 +89,7 @@ int sys_chdir(const char * filename)
int sys_chroot(const char * filename)
{
- struct m_inode * inode;
+ struct inode * inode;
if (!(inode=namei(filename)))
return -ENOENT;
@@ -105,7 +104,7 @@ int sys_chroot(const char * filename)
int sys_chmod(const char * filename,int mode)
{
- struct m_inode * inode;
+ struct inode * inode;
if (!(inode=namei(filename)))
return -ENOENT;
@@ -121,7 +120,7 @@ int sys_chmod(const char * filename,int mode)
int sys_chown(const char * filename,int uid,int gid)
{
- struct m_inode * inode;
+ struct inode * inode;
if (!(inode=namei(filename)))
return -ENOENT;
@@ -136,45 +135,12 @@ int sys_chown(const char * filename,int uid,int gid)
return 0;
}
-static int check_char_dev(struct m_inode * inode, int dev, int flag)
-{
- struct tty_struct *tty;
- int min;
-
- if (MAJOR(dev) == 4 || MAJOR(dev) == 5) {
- if (MAJOR(dev) == 5)
- min = current->tty;
- else
- min = MINOR(dev);
- if (min < 0)
- return -1;
- if ((IS_A_PTY_MASTER(min)) && (inode->i_count>1))
- return -1;
- tty = TTY_TABLE(min);
- if (!(flag & O_NOCTTY) &&
- current->leader &&
- current->tty<0 &&
- tty->session==0) {
- current->tty = min;
- tty->session= current->session;
- tty->pgrp = current->pgrp;
- }
- if (flag & O_NONBLOCK) {
- TTY_TABLE(min)->termios.c_cc[VMIN] =0;
- TTY_TABLE(min)->termios.c_cc[VTIME] =0;
- TTY_TABLE(min)->termios.c_lflag &= ~ICANON;
- }
- }
- return 0;
-}
-
int sys_open(const char * filename,int flag,int mode)
{
- struct m_inode * inode;
+ struct inode * inode;
struct file * f;
int i,fd;
- mode &= 0777 & ~current->umask;
for(fd=0 ; fd<NR_OPEN ; fd++)
if (!current->filp[fd])
break;
@@ -192,28 +158,25 @@ int sys_open(const char * filename,int flag,int mode)
f->f_count=0;
return i;
}
-/* ttys are somewhat special (ttyxx major==4, tty major==5) */
- if (S_ISCHR(inode->i_mode))
- if (check_char_dev(inode,inode->i_zone[0],flag)) {
- iput(inode);
- current->filp[fd]=NULL;
- f->f_count=0;
- return -EAGAIN;
- }
-/* Likewise with block-devices: check for floppy_change */
- if (S_ISBLK(inode->i_mode))
- check_disk_change(inode->i_zone[0]);
- f->f_mode = inode->i_mode;
+ f->f_op = NULL;
+ f->f_mode = "\001\002\003\000"[flag & O_ACCMODE];
f->f_flags = flag;
f->f_count = 1;
f->f_inode = inode;
f->f_pos = 0;
+ if (inode->i_op && inode->i_op->open)
+ if (i = inode->i_op->open(inode,f)) {
+ iput(inode);
+ f->f_count=0;
+ current->filp[fd]=NULL;
+ return i;
+ }
return (fd);
}
int sys_creat(const char * pathname, int mode)
{
- return sys_open(pathname, O_CREAT | O_TRUNC, mode);
+ return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
}
int sys_close(unsigned int fd)
diff --git a/fs/pipe.c b/fs/pipe.c
index 38ea99d..d1b6e7c 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -7,25 +7,26 @@
#include <signal.h>
#include <errno.h>
#include <termios.h>
+#include <fcntl.h>
#include <linux/sched.h>
-#include <linux/mm.h> /* for get_free_page */
#include <asm/segment.h>
#include <linux/kernel.h>
-int read_pipe(struct m_inode * inode, char * buf, int count)
+int pipe_read(struct inode * inode, struct file * filp, char * buf, int count)
{
int chars, size, read = 0;
- while (count>0) {
- while (!(size=PIPE_SIZE(*inode))) {
+ if (!(filp->f_flags & O_NONBLOCK))
+ while (!PIPE_SIZE(*inode)) {
wake_up(& PIPE_WRITE_WAIT(*inode));
if (inode->i_count != 2) /* are there any writers? */
- return read;
+ return 0;
if (current->signal & ~current->blocked)
- return read?read:-ERESTARTSYS;
+ return -ERESTARTSYS;
interruptible_sleep_on(& PIPE_READ_WAIT(*inode));
}
+ while (count>0 && (size = PIPE_SIZE(*inode))) {
chars = PAGE_SIZE-PIPE_TAIL(*inode);
if (chars > count)
chars = count;
@@ -43,7 +44,7 @@ int read_pipe(struct m_inode * inode, char * buf, int count)
return read;
}
-int write_pipe(struct m_inode * inode, char * buf, int count)
+int pipe_write(struct inode * inode, struct file * filp, char * buf, int count)
{
int chars, size, written = 0;
@@ -52,9 +53,11 @@ int write_pipe(struct m_inode * inode, char * buf, int count)
wake_up(& PIPE_READ_WAIT(*inode));
if (inode->i_count != 2) { /* no readers */
current->signal |= (1<<(SIGPIPE-1));
- return written?written:-1;
+ return written?written:-EINTR;
}
- sleep_on(& PIPE_WRITE_WAIT(*inode));
+ if (current->signal & ~current->blocked)
+ return written?written:-EINTR;
+ interruptible_sleep_on(&PIPE_WRITE_WAIT(*inode));
}
chars = PAGE_SIZE-PIPE_HEAD(*inode);
if (chars > count)
@@ -75,7 +78,7 @@ int write_pipe(struct m_inode * inode, char * buf, int count)
int sys_pipe(unsigned long * fildes)
{
- struct m_inode * inode;
+ struct inode * inode;
struct file * f[2];
int fd[2];
int i,j;
@@ -115,7 +118,7 @@ int sys_pipe(unsigned long * fildes)
return 0;
}
-int pipe_ioctl(struct m_inode *pino, int cmd, int arg)
+int pipe_ioctl(struct inode *pino, int cmd, int arg)
{
switch (cmd) {
case FIONREAD:
diff --git a/fs/read_write.c b/fs/read_write.c
index 341274a..da81a6f 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -12,26 +12,20 @@
#include <linux/sched.h>
#include <asm/segment.h>
-extern int rw_char(int rw,int dev, char * buf, int count, off_t * pos);
-extern int read_pipe(struct m_inode * inode, char * buf, int count);
-extern int write_pipe(struct m_inode * inode, char * buf, int count);
-extern int block_read(int dev, off_t * pos, char * buf, int count);
-extern int block_write(int dev, off_t * pos, char * buf, int count);
-extern int file_read(struct m_inode * inode, struct file * filp,
- char * buf, int count);
-extern int file_write(struct m_inode * inode, struct file * filp,
- char * buf, int count);
-
-int sys_lseek(unsigned int fd,off_t offset, int origin)
+int sys_lseek(unsigned int fd,off_t offset, unsigned int origin)
{
struct file * file;
int tmp;
- if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode)
- || !IS_SEEKABLE(MAJOR(file->f_inode->i_dev)))
+ if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode))
return -EBADF;
+ if (origin > 2)
+ return -EINVAL;
if (file->f_inode->i_pipe)
return -ESPIPE;
+ if (file->f_op && file->f_op->lseek)
+ return file->f_op->lseek(file->f_inode,file,offset,origin);
+/* this is the default handler if no lseek handler is present */
switch (origin) {
case 0:
if (offset<0) return -EINVAL;
@@ -45,59 +39,59 @@ int sys_lseek(unsigned int fd,off_t offset, int origin)
if ((tmp=file->f_inode->i_size+offset) < 0)
return -EINVAL;
file->f_pos = tmp;
- break;
- default:
- return -EINVAL;
}
return file->f_pos;
}
-int sys_read(unsigned int fd,char * buf,int count)
+int sys_read(unsigned int fd,char * buf,unsigned int count)
{
struct file * file;
- struct m_inode * inode;
+ struct inode * inode;
- if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd]))
- return -EINVAL;
+ if (fd>=NR_OPEN || !(file=current->filp[fd]) || !(inode=file->f_inode))
+ return -EBADF;
+ if (!(file->f_mode & 1))
+ return -EBADF;
if (!count)
return 0;
verify_area(buf,count);
- inode = file->f_inode;
+ if (file->f_op && file->f_op->read)
+ return file->f_op->read(inode,file,buf,count);
+/* these are the default read-functions */
if (inode->i_pipe)
- return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO;
+ return pipe_read(inode,file,buf,count);
if (S_ISCHR(inode->i_mode))
- return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos);
+ return char_read(inode,file,buf,count);
if (S_ISBLK(inode->i_mode))
- return block_read(inode->i_zone[0],&file->f_pos,buf,count);
- if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {
- if (count+file->f_pos > inode->i_size)
- count = inode->i_size - file->f_pos;
- if (count<=0)
- return 0;
- return file_read(inode,file,buf,count);
- }
+ return block_read(inode,file,buf,count);
+ if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode))
+ return minix_file_read(inode,file,buf,count);
printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
return -EINVAL;
}
-int sys_write(unsigned int fd,char * buf,int count)
+int sys_write(unsigned int fd,char * buf,unsigned int count)
{
struct file * file;
- struct m_inode * inode;
+ struct inode * inode;
- if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd]))
- return -EINVAL;
+ if (fd>=NR_OPEN || !(file=current->filp[fd]) || !(inode=file->f_inode))
+ return -EBADF;
+ if (!(file->f_mode&2))
+ return -EBADF;
if (!count)
return 0;
- inode=file->f_inode;
+ if (file->f_op && file->f_op->write)
+ return file->f_op->write(inode,file,buf,count);
+/* these are the default read-functions */
if (inode->i_pipe)
- return (file->f_mode&2)?write_pipe(inode,buf,count):-EIO;
+ return pipe_write(inode,file,buf,count);
if (S_ISCHR(inode->i_mode))
- return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos);
+ return char_write(inode,file,buf,count);
if (S_ISBLK(inode->i_mode))
- return block_write(inode->i_zone[0],&file->f_pos,buf,count);
+ return block_write(inode,file,buf,count);
if (S_ISREG(inode->i_mode))
- return file_write(inode,file,buf,count);
+ return minix_file_write(inode,file,buf,count);
printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode);
return -EINVAL;
}
diff --git a/fs/select.c b/fs/select.c
index 24c84ef..053b1ab 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -79,18 +79,18 @@ static void free_wait(select_table * p)
p->nr = 0;
}
-static struct tty_struct * get_tty(struct m_inode * inode)
+static struct tty_struct * get_tty(struct inode * inode)
{
int major, minor;
if (!S_ISCHR(inode->i_mode))
return NULL;
- if ((major = MAJOR(inode->i_zone[0])) != 5 && major != 4)
+ if ((major = MAJOR(inode->i_rdev)) != 5 && major != 4)
return NULL;
if (major == 5)
minor = current->tty;
else
- minor = MINOR(inode->i_zone[0]);
+ minor = MINOR(inode->i_rdev);
if (minor < 0)
return NULL;
return TTY_TABLE(minor);
@@ -100,7 +100,7 @@ static struct tty_struct * get_tty(struct m_inode * inode)
* The check_XX functions check out a file. We know it's either
* a pipe, a character device or a fifo (fifo's not implemented)
*/
-static int check_in(select_table * wait, struct m_inode * inode)
+static int check_in(select_table * wait, struct inode * inode)
{
struct tty_struct * tty;
@@ -110,14 +110,14 @@ static int check_in(select_table * wait, struct m_inode * inode)
else
add_wait(&tty->secondary->proc_list, wait);
else if (inode->i_pipe)
- if (!PIPE_EMPTY(*inode))
+ if (!PIPE_EMPTY(*inode) || inode->i_count < 2)
return 1;
else
add_wait(&inode->i_wait, wait);
return 0;
}
-static int check_out(select_table * wait, struct m_inode * inode)
+static int check_out(select_table * wait, struct inode * inode)
{
struct tty_struct * tty;
@@ -134,7 +134,7 @@ static int check_out(select_table * wait, struct m_inode * inode)
return 0;
}
-static int check_ex(select_table * wait, struct m_inode * inode)
+static int check_ex(select_table * wait, struct inode * inode)
{
struct tty_struct * tty;
@@ -198,7 +198,7 @@ repeat:
}
}
if (!(current->signal & ~current->blocked) &&
- (wait_table.nr || current->timeout) && !count) {
+ current->timeout && !count) {
current->state = TASK_INTERRUPTIBLE;
schedule();
free_wait(&wait_table);
@@ -224,7 +224,11 @@ int sys_select( unsigned long *buffer )
struct timeval *tvp;
unsigned long timeout;
- mask = ~((~0) << get_fs_long(buffer++));
+ mask = get_fs_long(buffer++);
+ if (mask >= 32)
+ mask = ~0;
+ else
+ mask = ~((~0) << mask);
inp = (fd_set *) get_fs_long(buffer++);
outp = (fd_set *) get_fs_long(buffer++);
exp = (fd_set *) get_fs_long(buffer++);
diff --git a/fs/stat.c b/fs/stat.c
index b4f36fe..029ec2f 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -12,19 +12,19 @@
#include <linux/kernel.h>
#include <asm/segment.h>
-static void cp_stat(struct m_inode * inode, struct stat * statbuf)
+static void cp_stat(struct inode * inode, struct stat * statbuf)
{
struct stat tmp;
int i;
verify_area(statbuf,sizeof (struct stat));
tmp.st_dev = inode->i_dev;
- tmp.st_ino = inode->i_num;
+ tmp.st_ino = inode->i_ino;
tmp.st_mode = inode->i_mode;
- tmp.st_nlink = inode->i_nlinks;
+ tmp.st_nlink = inode->i_nlink;
tmp.st_uid = inode->i_uid;
tmp.st_gid = inode->i_gid;
- tmp.st_rdev = inode->i_zone[0];
+ tmp.st_rdev = inode->i_rdev;
tmp.st_size = inode->i_size;
tmp.st_atime = inode->i_atime;
tmp.st_mtime = inode->i_mtime;
@@ -35,7 +35,7 @@ static void cp_stat(struct m_inode * inode, struct stat * statbuf)
int sys_stat(char * filename, struct stat * statbuf)
{
- struct m_inode * inode;
+ struct inode * inode;
if (!(inode=namei(filename)))
return -ENOENT;
@@ -46,7 +46,7 @@ int sys_stat(char * filename, struct stat * statbuf)
int sys_lstat(char * filename, struct stat * statbuf)
{
- struct m_inode * inode;
+ struct inode * inode;
if (!(inode = lnamei(filename)))
return -ENOENT;
@@ -58,7 +58,7 @@ int sys_lstat(char * filename, struct stat * statbuf)
int sys_fstat(unsigned int fd, struct stat * statbuf)
{
struct file * f;
- struct m_inode * inode;
+ struct inode * inode;
if (fd >= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode))
return -EBADF;
@@ -68,30 +68,16 @@ int sys_fstat(unsigned int fd, struct stat * statbuf)
int sys_readlink(const char * path, char * buf, int bufsiz)
{
- struct m_inode * inode;
- struct buffer_head * bh;
- int i;
- char c;
+ struct inode * inode;
if (bufsiz <= 0)
- return -EBADF;
- if (bufsiz > 1023)
- bufsiz = 1023;
+ return -EINVAL;
verify_area(buf,bufsiz);
if (!(inode = lnamei(path)))
return -ENOENT;
- if (inode->i_zone[0])
- bh = bread(inode->i_dev, inode->i_zone[0]);
- else
- bh = NULL;
- iput(inode);
- if (!bh)
- return 0;
- i = 0;
- while (i<bufsiz && (c = bh->b_data[i])) {
- i++;
- put_fs_byte(c,buf++);
+ if (!inode->i_op || !inode->i_op->readlink) {
+ iput(inode);
+ return -EINVAL;
}
- brelse(bh);
- return i;
+ return inode->i_op->readlink(inode,buf,bufsiz);
}
diff --git a/fs/super.c b/fs/super.c
index 20c1c9b..eedff32 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -9,6 +9,7 @@
*/
#include <linux/config.h>
#include <linux/sched.h>
+#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <asm/system.h>
@@ -82,15 +83,15 @@ void put_super(int dev)
}
if (!(sb = get_super(dev)))
return;
- if (sb->s_imount) {
+ if (sb->s_covered) {
printk("Mounted disk changed - tssk, tssk\n\r");
return;
}
lock_super(sb);
sb->s_dev = 0;
- for(i=0;i<I_MAP_SLOTS;i++)
+ for(i=0;i<MINIX_I_MAP_SLOTS;i++)
brelse(sb->s_imap[i]);
- for(i=0;i<Z_MAP_SLOTS;i++)
+ for(i=0;i<MINIX_Z_MAP_SLOTS;i++)
brelse(sb->s_zmap[i]);
free_super(sb);
return;
@@ -114,8 +115,8 @@ static struct super_block * read_super(int dev)
break;
}
s->s_dev = dev;
- s->s_isup = NULL;
- s->s_imount = NULL;
+ s->s_mounted = NULL;
+ s->s_covered = NULL;
s->s_time = 0;
s->s_rd_only = 0;
s->s_dirt = 0;
@@ -125,17 +126,17 @@ static struct super_block * read_super(int dev)
free_super(s);
return NULL;
}
- *((struct d_super_block *) s) =
- *((struct d_super_block *) bh->b_data);
+ *((struct minix_super_block *) s) =
+ *((struct minix_super_block *) bh->b_data);
brelse(bh);
- if (s->s_magic != SUPER_MAGIC) {
+ if (s->s_magic != MINIX_SUPER_MAGIC) {
s->s_dev = 0;
free_super(s);
return NULL;
}
- for (i=0;i<I_MAP_SLOTS;i++)
+ for (i=0;i < MINIX_I_MAP_SLOTS;i++)
s->s_imap[i] = NULL;
- for (i=0;i<Z_MAP_SLOTS;i++)
+ for (i=0;i < MINIX_Z_MAP_SLOTS;i++)
s->s_zmap[i] = NULL;
block=2;
for (i=0 ; i < s->s_imap_blocks ; i++)
@@ -149,9 +150,9 @@ static struct super_block * read_super(int dev)
else
break;
if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) {
- for(i=0;i<I_MAP_SLOTS;i++)
+ for(i=0;i<MINIX_I_MAP_SLOTS;i++)
brelse(s->s_imap[i]);
- for(i=0;i<Z_MAP_SLOTS;i++)
+ for(i=0;i<MINIX_Z_MAP_SLOTS;i++)
brelse(s->s_zmap[i]);
s->s_dev=0;
free_super(s);
@@ -165,13 +166,13 @@ static struct super_block * read_super(int dev)
int sys_umount(char * dev_name)
{
- struct m_inode * inode;
+ struct inode * inode;
struct super_block * sb;
int dev;
if (!(inode=namei(dev_name)))
return -ENOENT;
- dev = inode->i_zone[0];
+ dev = inode->i_rdev;
if (!S_ISBLK(inode->i_mode)) {
iput(inode);
return -ENOTBLK;
@@ -179,18 +180,21 @@ int sys_umount(char * dev_name)
iput(inode);
if (dev==ROOT_DEV)
return -EBUSY;
- if (!(sb=get_super(dev)) || !(sb->s_imount))
+ if (!(sb=get_super(dev)) || !(sb->s_covered))
return -ENOENT;
- if (!sb->s_imount->i_mount)
+ if (!sb->s_covered->i_mount)
printk("Mounted inode has i_mount=0\n");
for (inode=inode_table+0 ; inode<inode_table+NR_INODE ; inode++)
if (inode->i_dev==dev && inode->i_count)
+ if (inode == sb->s_mounted && inode->i_count == 1)
+ continue;
+ else
return -EBUSY;
- sb->s_imount->i_mount=0;
- iput(sb->s_imount);
- sb->s_imount = NULL;
- iput(sb->s_isup);
- sb->s_isup = NULL;
+ sb->s_covered->i_mount=0;
+ iput(sb->s_covered);
+ sb->s_covered = NULL;
+ iput(sb->s_mounted);
+ sb->s_mounted = NULL;
put_super(dev);
sync_dev(dev);
return 0;
@@ -198,13 +202,13 @@ int sys_umount(char * dev_name)
int sys_mount(char * dev_name, char * dir_name, int rw_flag)
{
- struct m_inode * dev_i, * dir_i;
+ struct inode * dev_i, * dir_i;
struct super_block * sb;
int dev;
if (!(dev_i=namei(dev_name)))
return -ENOENT;
- dev = dev_i->i_zone[0];
+ dev = dev_i->i_rdev;
if (!S_ISBLK(dev_i->i_mode)) {
iput(dev_i);
return -EPERM;
@@ -212,7 +216,7 @@ int sys_mount(char * dev_name, char * dir_name, int rw_flag)
iput(dev_i);
if (!(dir_i=namei(dir_name)))
return -ENOENT;
- if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO) {
+ if (dir_i->i_count != 1 || dir_i->i_ino == MINIX_ROOT_INO) {
iput(dir_i);
return -EBUSY;
}
@@ -224,7 +228,7 @@ int sys_mount(char * dev_name, char * dir_name, int rw_flag)
iput(dir_i);
return -EBUSY;
}
- if (sb->s_imount) {
+ if (sb->s_covered) {
iput(dir_i);
return -EBUSY;
}
@@ -232,7 +236,11 @@ int sys_mount(char * dev_name, char * dir_name, int rw_flag)
iput(dir_i);
return -EPERM;
}
- sb->s_imount=dir_i;
+ if (!(sb->s_mounted = iget(dev,MINIX_ROOT_INO))) {
+ iput(dir_i);
+ return -EPERM;
+ }
+ sb->s_covered=dir_i;
dir_i->i_mount=1;
dir_i->i_dirt=1; /* NOTE! we don't iput(dir_i) */
return 0; /* we do that in umount */
@@ -242,9 +250,9 @@ void mount_root(void)
{
int i,free;
struct super_block * p;
- struct m_inode * mi;
+ struct inode * mi;
- if (32 != sizeof (struct d_inode))
+ if (32 != sizeof (struct minix_inode))
panic("bad i-node size");
for(i=0;i<NR_FILE;i++)
file_table[i].f_count=0;
@@ -259,10 +267,10 @@ void mount_root(void)
}
if (!(p=read_super(ROOT_DEV)))
panic("Unable to mount root");
- if (!(mi=iget(ROOT_DEV,ROOT_INO)))
+ if (!(mi=iget(ROOT_DEV,MINIX_ROOT_INO)))
panic("Unable to read root i-node");
mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
- p->s_isup = p->s_imount = mi;
+ p->s_mounted = p->s_covered = mi;
current->pwd = mi;
current->root = mi;
free=0;
diff --git a/include/asm/io.h b/include/asm/io.h
index d5cc42a..118249a 100644
--- a/include/asm/io.h
+++ b/include/asm/io.h
@@ -1,24 +1,27 @@
-#define outb(value,port) \
-__asm__ ("outb %%al,%%dx"::"a" (value),"d" (port))
+static void inline outb(char value, unsigned short port)
+{
+__asm__ volatile ("outb %0,%1"::"a" (value),"d" (port));
+}
+static void inline outb_p(char value, unsigned short port)
+{
+__asm__ volatile ("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"
+ ::"a" (value),"d" (port));
+}
-#define inb(port) ({ \
-unsigned char _v; \
-__asm__ volatile ("inb %%dx,%%al":"=a" (_v):"d" (port)); \
-_v; \
-})
+static unsigned char inline inb(unsigned short port)
+{
+ unsigned char _v;
+ __asm__ volatile ("inb %1,%0":"=a" (_v):"d" (port));
+ return _v;
+}
-#define outb_p(value,port) \
-__asm__ ("outb %%al,%%dx\n" \
- "\tjmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:"::"a" (value),"d" (port))
-
-#define inb_p(port) ({ \
-unsigned char _v; \
-__asm__ volatile ("inb %%dx,%%al\n" \
- "\tjmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:":"=a" (_v):"d" (port)); \
-_v; \
-})
+static unsigned char inb_p(unsigned short port)
+{
+ unsigned char _v;
+ __asm__ volatile ("inb %1,%0\n"
+ "\tjmp 1f\n"
+ "1:\tjmp 1f\n"
+ "1:":"=a" (_v):"d" ((unsigned short) port));
+ return _v;
+}
diff --git a/include/asm/segment.h b/include/asm/segment.h
index c03657f..5efc9e7 100644
--- a/include/asm/segment.h
+++ b/include/asm/segment.h
@@ -2,7 +2,7 @@ extern inline unsigned char get_fs_byte(const char * addr)
{
unsigned register char _v;
- __asm__ ("movb %%fs:%1,%0":"=r" (_v):"m" (*addr));
+ __asm__ ("movb %%fs:%1,%0":"=q" (_v):"m" (*addr));
return _v;
}
@@ -24,7 +24,7 @@ extern inline unsigned long get_fs_long(const unsigned long *addr)
extern inline void put_fs_byte(char val,char *addr)
{
-__asm__ ("movb %0,%%fs:%1"::"r" (val),"m" (*addr));
+__asm__ ("movb %0,%%fs:%1"::"q" (val),"m" (*addr));
}
extern inline void put_fs_word(short val,short * addr)
@@ -41,25 +41,25 @@ __asm__ ("movl %0,%%fs:%1"::"r" (val),"m" (*addr));
* Someone who knows GNU asm better than I should double check the followig.
* It seems to work, but I don't know if I'm doing something subtly wrong.
* --- TYT, 11/24/91
- * [ nothing wrong here, Linus ]
+ * [ nothing wrong here, Linus: I just changed the ax to be any reg ]
*/
extern inline unsigned long get_fs()
{
unsigned short _v;
- __asm__("mov %%fs,%%ax":"=a" (_v):);
+ __asm__("mov %%fs,%0":"=r" (_v):);
return _v;
}
extern inline unsigned long get_ds()
{
unsigned short _v;
- __asm__("mov %%ds,%%ax":"=a" (_v):);
+ __asm__("mov %%ds,%0":"=r" (_v):);
return _v;
}
extern inline void set_fs(unsigned long val)
{
- __asm__("mov %0,%%fs"::"a" ((unsigned short) val));
+ __asm__("mov %0,%%fs"::"r" ((unsigned short) val));
}
diff --git a/include/asm/system.h b/include/asm/system.h
index c112e10..6f5f670 100644
--- a/include/asm/system.h
+++ b/include/asm/system.h
@@ -24,11 +24,11 @@ __asm__ ("movw %%dx,%%ax\n\t" \
"movw %0,%%dx\n\t" \
"movl %%eax,%1\n\t" \
"movl %%edx,%2" \
- : \
- : "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
- "o" (*((char *) (gate_addr))), \
- "o" (*(4+(char *) (gate_addr))), \
- "d" ((char *) (addr)),"a" (0x00080000))
+ :: "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
+ "m" (*((char *) (gate_addr))), \
+ "m" (*(4+(char *) (gate_addr))), \
+ "d" ((char *) (addr)),"a" (0x00080000) \
+ :"ax","dx")
#define set_intr_gate(n,addr) \
_set_gate(&idt[n],14,0,addr)
diff --git a/include/errno.h b/include/errno.h
index 6f35d03..a38b78f 100644
--- a/include/errno.h
+++ b/include/errno.h
@@ -56,6 +56,7 @@ extern int errno;
#define ENOLCK 37
#define ENOSYS 38
#define ENOTEMPTY 39
+#define ELOOP 40
/* Should never be seen by user programs */
#define ERESTARTSYS 512
diff --git a/include/fcntl.h b/include/fcntl.h
index a5bf9af..4bc0c10 100644
--- a/include/fcntl.h
+++ b/include/fcntl.h
@@ -13,7 +13,7 @@
#define O_NOCTTY 00400 /* not fcntl */
#define O_TRUNC 01000 /* not fcntl */
#define O_APPEND 02000
-#define O_NONBLOCK 04000 /* not fcntl */
+#define O_NONBLOCK 04000
#define O_NDELAY O_NONBLOCK
/* Defines for fcntl-commands. Note that currently
diff --git a/include/linux/config.h b/include/linux/config.h
index a30130e..ca364b6 100644
--- a/include/linux/config.h
+++ b/include/linux/config.h
@@ -2,6 +2,15 @@
#define _CONFIG_H
/*
+ * Define this if you want the math-emulation code: if this is undefined,
+ * the kernel will be smaller, but you'll get FPU exceptions if you don't
+ * have a 387 and are trying to use math.
+ */
+
+#define KERNEL_MATH_EMULATION
+
+
+/*
* Defines for what uname() should return
*/
#define UTS_SYSNAME "Linux"
@@ -14,7 +23,7 @@
#define DEF_INITSEG 0x9000
#define DEF_SYSSEG 0x1000
#define DEF_SETUPSEG 0x9020
-#define DEF_SYSSIZE 0x3000
+#define DEF_SYSSIZE 0x4000
/*
* The root-device is no longer hard-coded. You can change the default
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 5e6768f..0c7b2e9 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -23,6 +23,10 @@
#define IS_SEEKABLE(x) ((x)>=1 && (x)<=3)
+#define MAY_EXEC 1
+#define MAY_WRITE 2
+#define MAY_READ 4
+
#define READ 0
#define WRITE 1
#define READA 2 /* read-ahead - don't pause */
@@ -33,15 +37,8 @@ void buffer_init(long buffer_end);
#define MAJOR(a) (((unsigned)(a))>>8)
#define MINOR(a) ((a)&0xff)
-#define NAME_LEN 14
-#define ROOT_INO 1
-
-#define I_MAP_SLOTS 8
-#define Z_MAP_SLOTS 8
-#define SUPER_MAGIC 0x137F
-
#define NR_OPEN 20
-#define NR_INODE 64
+#define NR_INODE 128
#define NR_FILE 64
#define NR_SUPER 8
#define NR_HASH 307
@@ -52,13 +49,10 @@ void buffer_init(long buffer_end);
#define NULL ((void *) 0)
#endif
-#define INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct d_inode)))
-#define DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct dir_entry)))
-
#define PIPE_READ_WAIT(inode) ((inode).i_wait)
#define PIPE_WRITE_WAIT(inode) ((inode).i_wait2)
-#define PIPE_HEAD(inode) ((inode).i_zone[0])
-#define PIPE_TAIL(inode) ((inode).i_zone[1])
+#define PIPE_HEAD(inode) ((inode).i_data[0])
+#define PIPE_TAIL(inode) ((inode).i_data[1])
#define PIPE_SIZE(inode) ((PIPE_HEAD(inode)-PIPE_TAIL(inode))&(PAGE_SIZE-1))
#define PIPE_EMPTY(inode) (PIPE_HEAD(inode)==PIPE_TAIL(inode))
#define PIPE_FULL(inode) (PIPE_SIZE(inode)==(PAGE_SIZE-1))
@@ -85,31 +79,23 @@ struct buffer_head {
struct buffer_head * b_next_free;
};
-struct d_inode {
- unsigned short i_mode;
- unsigned short i_uid;
- unsigned long i_size;
- unsigned long i_time;
- unsigned char i_gid;
- unsigned char i_nlinks;
- unsigned short i_zone[9];
-};
-
-struct m_inode {
- unsigned short i_mode;
- unsigned short i_uid;
- unsigned long i_size;
- unsigned long i_mtime;
- unsigned char i_gid;
- unsigned char i_nlinks;
- unsigned short i_zone[9];
-/* these are in memory also */
+struct inode {
+ dev_t i_dev;
+ ino_t i_ino;
+ umode_t i_mode;
+ nlink_t i_nlink;
+ uid_t i_uid;
+ gid_t i_gid;
+ dev_t i_rdev;
+ off_t i_size;
+ time_t i_atime;
+ time_t i_mtime;
+ time_t i_ctime;
+ unsigned long i_data[16];
+ struct inode_operations * i_op;
+ struct super_block * i_sb;
struct task_struct * i_wait;
struct task_struct * i_wait2; /* for pipes */
- unsigned long i_atime;
- unsigned long i_ctime;
- unsigned short i_dev;
- unsigned short i_num;
unsigned short i_count;
unsigned char i_lock;
unsigned char i_dirt;
@@ -123,7 +109,8 @@ struct file {
unsigned short f_mode;
unsigned short f_flags;
unsigned short f_count;
- struct m_inode * f_inode;
+ struct inode * f_inode;
+ struct file_operations * f_op;
off_t f_pos;
};
@@ -140,8 +127,8 @@ struct super_block {
struct buffer_head * s_imap[8];
struct buffer_head * s_zmap[8];
unsigned short s_dev;
- struct m_inode * s_isup;
- struct m_inode * s_imount;
+ struct inode * s_covered;
+ struct inode * s_mounted;
unsigned long s_time;
struct task_struct * s_wait;
unsigned char s_lock;
@@ -149,23 +136,29 @@ struct super_block {
unsigned char s_dirt;
};
-struct d_super_block {
- unsigned short s_ninodes;
- unsigned short s_nzones;
- unsigned short s_imap_blocks;
- unsigned short s_zmap_blocks;
- unsigned short s_firstdatazone;
- unsigned short s_log_zone_size;
- unsigned long s_max_size;
- unsigned short s_magic;
+struct file_operations {
+ int (*lseek) (struct inode *, struct file *, off_t, int);
+ int (*read) (struct inode *, struct file *, char *, int);
+ int (*write) (struct inode *, struct file *, char *, int);
};
-struct dir_entry {
- unsigned short inode;
- char name[NAME_LEN];
+struct inode_operations {
+ int (*create) (struct inode *,const char *,int,int,struct inode **);
+ int (*lookup) (struct inode *,const char *,int,struct inode **);
+ int (*link) (struct inode *,struct inode *,const char *,int);
+ int (*unlink) (struct inode *,const char *,int);
+ int (*symlink) (struct inode *,const char *,int,const char *);
+ int (*mkdir) (struct inode *,const char *,int,int);
+ int (*rmdir) (struct inode *,const char *,int);
+ int (*mknod) (struct inode *,const char *,int,int,int);
+ int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int);
+ int (*readlink) (struct inode *,char *,int);
+ int (*open) (struct inode *, struct file *);
+ void (*release) (struct inode *, struct file *);
+ struct inode * (*follow_link) (struct inode *, struct inode *);
};
-extern struct m_inode inode_table[NR_INODE];
+extern struct inode inode_table[NR_INODE];
extern struct file file_table[NR_FILE];
extern struct super_block super_block[NR_SUPER];
extern struct buffer_head * start_buffer;
@@ -176,35 +169,41 @@ extern int floppy_change(unsigned int nr);
extern int ticks_to_floppy_on(unsigned int dev);
extern void floppy_on(unsigned int dev);
extern void floppy_off(unsigned int dev);
-extern void truncate(struct m_inode * inode);
+extern void truncate(struct inode * inode);
extern void sync_inodes(void);
-extern void wait_on(struct m_inode * inode);
-extern int bmap(struct m_inode * inode,int block);
-extern int create_block(struct m_inode * inode,int block);
-extern struct m_inode * namei(const char * pathname);
-extern struct m_inode * lnamei(const char * pathname);
+extern void wait_on(struct inode * inode);
+extern int bmap(struct inode * inode,int block);
+extern struct inode * namei(const char * pathname);
+extern struct inode * lnamei(const char * pathname);
extern int open_namei(const char * pathname, int flag, int mode,
- struct m_inode ** res_inode);
-extern void iput(struct m_inode * inode);
-extern struct m_inode * iget(int dev,int nr);
-extern struct m_inode * get_empty_inode(void);
-extern struct m_inode * get_pipe_inode(void);
+ struct inode ** res_inode);
+extern void iput(struct inode * inode);
+extern struct inode * iget(int dev,int nr);
+extern struct inode * get_empty_inode(void);
+extern struct inode * get_pipe_inode(void);
extern struct buffer_head * get_hash_table(int dev, int block);
extern struct buffer_head * getblk(int dev, int block);
extern void ll_rw_block(int rw, struct buffer_head * bh);
extern void ll_rw_page(int rw, int dev, int nr, char * buffer);
+extern void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buffer);
extern void brelse(struct buffer_head * buf);
extern struct buffer_head * bread(int dev,int block);
extern void bread_page(unsigned long addr,int dev,int b[4]);
extern struct buffer_head * breada(int dev,int block,...);
-extern int new_block(int dev);
-extern int free_block(int dev, int block);
-extern struct m_inode * new_inode(int dev);
-extern void free_inode(struct m_inode * inode);
extern int sync_dev(int dev);
extern struct super_block * get_super(int dev);
extern int ROOT_DEV;
extern void mount_root(void);
+extern int minix_file_read(struct inode *, struct file *, char *, int);
+extern int pipe_read(struct inode *, struct file *, char *, int);
+extern int char_read(struct inode *, struct file *, char *, int);
+extern int block_read(struct inode *, struct file *, char *, int);
+
+extern int minix_file_write(struct inode *, struct file *, char *, int);
+extern int pipe_write(struct inode *, struct file *, char *, int);
+extern int char_write(struct inode *, struct file *, char *, int);
+extern int block_write(struct inode *, struct file *, char *, int);
+
#endif
diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h
index e6c593f..883c7ae 100644
--- a/include/linux/hdreg.h
+++ b/include/linux/hdreg.h
@@ -49,15 +49,17 @@
#define ECC_ERR 0x40 /* ? */
#define BBD_ERR 0x80 /* ? */
+#define EXTENDED_PARTITION 5
+
struct partition {
- unsigned char boot_ind; /* 0x80 - active (unused) */
- unsigned char head; /* ? */
- unsigned char sector; /* ? */
- unsigned char cyl; /* ? */
- unsigned char sys_ind; /* ? */
- unsigned char end_head; /* ? */
- unsigned char end_sector; /* ? */
- unsigned char end_cyl; /* ? */
+ unsigned char boot_ind; /* 0x80 - active */
+ unsigned char head; /* starting head */
+ unsigned char sector; /* starting sector */
+ unsigned char cyl; /* starting cylinder */
+ unsigned char sys_ind; /* What partition type */
+ unsigned char end_head; /* end head */
+ unsigned char end_sector; /* end sector */
+ unsigned char end_cyl; /* end cylinder */
unsigned int start_sect; /* starting sector counting from 0 */
unsigned int nr_sects; /* nr of sectors in partition */
};
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index d294d85..eab299b 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -10,15 +10,6 @@ void console_print(const char * str);
int tty_write(unsigned ch,char * buf,int count);
void * malloc(unsigned int size);
void free_s(void * obj, int size);
-extern void hd_times_out(void);
-extern void sysbeepstop(void);
-extern void blank_screen(void);
-extern void unblank_screen(void);
-
-extern int beepcount;
-extern int hd_timeout;
-extern int blankinterval;
-extern int blankcount;
#define free(x) free_s((x), 0)
diff --git a/include/linux/math_emu.h b/include/linux/math_emu.h
index abe0cc2..c5501b6 100644
--- a/include/linux/math_emu.h
+++ b/include/linux/math_emu.h
@@ -9,20 +9,20 @@
#include <linux/sched.h>
struct info {
- long ___math_ret;
long ___orig_eip;
- long ___edi;
- long ___esi;
- long ___ebp;
- long ___sys_call_ret;
- long ___eax;
+ long ___ret_from_system_call;
long ___ebx;
long ___ecx;
long ___edx;
- long ___orig_eax;
- long ___fs;
- long ___es;
+ long ___esi;
+ long ___edi;
+ long ___ebp;
+ long ___eax;
long ___ds;
+ long ___es;
+ long ___fs;
+ long ___gs;
+ long ___orig_eax;
long ___eip;
long ___cs;
long ___eflags;
@@ -140,6 +140,7 @@ char * ea(struct info * __info, unsigned short __code);
/* convert.c */
+void frndint(const temp_real * __a, temp_real * __b);
void short_to_temp(const short_real * __a, temp_real * __b);
void long_to_temp(const long_real * __a, temp_real * __b);
void temp_to_short(const temp_real * __a, short_real * __b);
diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h
new file mode 100644
index 0000000..4ccb845
--- /dev/null
+++ b/include/linux/minix_fs.h
@@ -0,0 +1,78 @@
+/*
+ * The minix filesystem constants/structures
+ */
+
+#ifndef _MINIX_FS_H
+#define _MINIX_FS_H
+
+#include <sys/types.h>
+
+#define MINIX_NAME_LEN 14
+#define MINIX_ROOT_INO 1
+
+#define MINIX_I_MAP_SLOTS 8
+#define MINIX_Z_MAP_SLOTS 8
+#define MINIX_SUPER_MAGIC 0x137F
+
+#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
+#define MINIX_DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_dir_entry)))
+
+struct minix_inode {
+ unsigned short i_mode;
+ unsigned short i_uid;
+ unsigned long i_size;
+ unsigned long i_time;
+ unsigned char i_gid;
+ unsigned char i_nlinks;
+ unsigned short i_zone[9];
+};
+
+struct minix_super_block {
+ unsigned short s_ninodes;
+ unsigned short s_nzones;
+ unsigned short s_imap_blocks;
+ unsigned short s_zmap_blocks;
+ unsigned short s_firstdatazone;
+ unsigned short s_log_zone_size;
+ unsigned long s_max_size;
+ unsigned short s_magic;
+};
+
+struct minix_dir_entry {
+ unsigned short inode;
+ char name[MINIX_NAME_LEN];
+};
+
+extern int minix_open(struct inode * inode, struct file * filp);
+extern void minix_release(struct inode * inode, struct file * filp);
+extern struct inode * minix_follow_link(struct inode * dir, struct inode * inode);
+extern int minix_lookup(struct inode * dir,const char * name, int len,
+ struct inode ** result);
+extern int minix_create(struct inode * dir,const char * name, int len, int mode,
+ struct inode ** result);
+extern int minix_mkdir(struct inode * dir, const char * name, int len, int mode);
+extern int minix_rmdir(struct inode * dir, const char * name, int len);
+extern int minix_unlink(struct inode * dir, const char * name, int len);
+extern int minix_symlink(struct inode * inode, const char * name, int len,
+ const char * symname);
+extern int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len);
+extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
+extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
+ struct inode * new_dir, const char * new_name, int new_len);
+extern int minix_readlink(struct inode * inode, char * buffer, int buflen);
+extern struct inode * minix_new_inode(int dev);
+extern void minix_free_inode(struct inode * inode);
+extern int minix_new_block(int dev);
+extern int minix_free_block(int dev, int block);
+
+extern int minix_create_block(struct inode * inode, int block);
+extern int minix_bmap(struct inode * inode,int block);
+
+extern int minix_lseek(struct inode * inode, struct file * filp, off_t offset, int origin);
+extern int minix_read(struct inode * inode, struct file * filp, char * buf, int count);
+extern int minix_write(struct inode * inode, struct file * filp, char * buf, int count);
+
+extern struct inode_operations minix_inode_operations;
+extern struct file_operations minix_file_operations;
+
+#endif
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 94c3713..e1eacea 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3,13 +3,19 @@
#define PAGE_SIZE 4096
+#include <linux/fs.h>
#include <linux/kernel.h>
#include <signal.h>
-extern int SWAP_DEV;
+extern unsigned int swap_device;
+extern struct inode * swap_file;
-#define read_swap_page(nr,buffer) ll_rw_page(READ,SWAP_DEV,(nr),(buffer));
-#define write_swap_page(nr,buffer) ll_rw_page(WRITE,SWAP_DEV,(nr),(buffer));
+extern void rw_swap_page(int rw, unsigned int nr, char * buf);
+
+#define read_swap_page(nr,buf) \
+ rw_swap_page(READ,(nr),(buf))
+#define write_swap_page(nr,buf) \
+ rw_swap_page(WRITE,(nr),(buf))
extern unsigned long get_free_page(void);
extern unsigned long put_dirty_page(unsigned long page,unsigned long address);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 8f1ef9b..d903e2d 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -129,12 +129,13 @@ struct task_struct {
unsigned int flags; /* per process flags, defined below */
unsigned short used_math;
/* file system info */
+ int link_count;
int tty; /* -1 if no tty, so it must be signed */
unsigned short umask;
- struct m_inode * pwd;
- struct m_inode * root;
- struct m_inode * executable;
- struct m_inode * library;
+ struct inode * pwd;
+ struct inode * root;
+ struct inode * executable;
+ struct inode * library;
unsigned long close_on_exec;
struct file * filp[NR_OPEN];
/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
@@ -148,6 +149,10 @@ struct task_struct {
*/
#define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */
/* Not implemented yet, only for 486*/
+#define PF_PTRACED 0x00000010 /* set if ptrace (0) has been called. */
+#define PF_VM86 0x00000020 /* set if process can execute a vm86 */
+ /* task. */
+ /* not impelmented. */
/*
* INIT_TASK is used to set up the first task table, touch at
@@ -167,7 +172,7 @@ struct task_struct {
{0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}}, \
/* flags */ 0, \
/* math */ 0, \
-/* fs info */ -1,0022,NULL,NULL,NULL,NULL,0, \
+/* fs info */ 0,-1,0022,NULL,NULL,NULL,NULL,0, \
/* filp */ {NULL,}, \
{ \
{0,0}, \
@@ -212,7 +217,7 @@ __asm__("str %%ax\n\t" \
"subl %2,%%eax\n\t" \
"shrl $4,%%eax" \
:"=a" (n) \
- :"a" (0),"i" (FIRST_TSS_ENTRY<<3))
+ :"0" (0),"i" (FIRST_TSS_ENTRY<<3))
/*
* switch_to(n) should switch tasks to task nr n, first
* checking that n isn't the current task, in which case it does nothing.
@@ -231,7 +236,8 @@ __asm__("cmpl %%ecx,_current\n\t" \
"clts\n" \
"1:" \
::"m" (*&__tmp.a),"m" (*&__tmp.b), \
- "d" (_TSS(n)),"c" ((long) task[n])); \
+ "d" (_TSS(n)),"c" ((long) task[n]) \
+ :"cx"); \
}
#define PAGE_ALIGN(n) (((n)+0xfff)&0xfffff000)
@@ -262,23 +268,28 @@ __asm__("movw %%dx,%0\n\t" \
#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base )
#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 )
-#define _get_base(addr) ({\
-unsigned long __base; \
-__asm__("movb %3,%%dh\n\t" \
- "movb %2,%%dl\n\t" \
- "shll $16,%%edx\n\t" \
- "movw %1,%%dx" \
- :"=d" (__base) \
- :"m" (*((addr)+2)), \
- "m" (*((addr)+4)), \
- "m" (*((addr)+7))); \
-__base;})
+static unsigned long inline _get_base(char * addr)
+{
+ unsigned long __base;
+ __asm__("movb %3,%%dh\n\t"
+ "movb %2,%%dl\n\t"
+ "shll $16,%%edx\n\t"
+ "movw %1,%%dx"
+ :"=&d" (__base)
+ :"m" (*((addr)+2)),
+ "m" (*((addr)+4)),
+ "m" (*((addr)+7)));
+ return __base;
+}
#define get_base(ldt) _get_base( ((char *)&(ldt)) )
-#define get_limit(segment) ({ \
-unsigned long __limit; \
-__asm__("lsll %1,%0\n\tincl %0":"=r" (__limit):"r" (segment)); \
-__limit;})
+static unsigned long inline get_limit(unsigned long segment)
+{
+ unsigned long __limit;
+ __asm__("lsll %1,%0"
+ :"=r" (__limit):"r" (segment));
+ return __limit+1;
+}
#endif
diff --git a/include/linux/sys.h b/include/linux/sys.h
index 2a1c8be..1e6f2c3 100644
--- a/include/linux/sys.h
+++ b/include/linux/sys.h
@@ -89,6 +89,8 @@ extern int sys_symlink();
extern int sys_lstat();
extern int sys_readlink();
extern int sys_uselib();
+extern int sys_swapon();
+extern int sys_reboot();
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
@@ -105,7 +107,7 @@ sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending, sys_sethostname,
sys_setrlimit, sys_getrlimit, sys_getrusage, sys_gettimeofday,
sys_settimeofday, sys_getgroups, sys_setgroups, sys_select, sys_symlink,
-sys_lstat, sys_readlink, sys_uselib };
+sys_lstat, sys_readlink, sys_uselib, sys_swapon, sys_reboot };
/* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
diff --git a/include/linux/timer.h b/include/linux/timer.h
new file mode 100644
index 0000000..295738e
--- /dev/null
+++ b/include/linux/timer.h
@@ -0,0 +1,44 @@
+#ifndef _TIMER_H
+#define _TIMER_H
+
+/*
+ * DON'T CHANGE THESE!! Most of them are hardcoded into some assembly language
+ * as well as being defined here.
+ */
+
+/*
+ * The timers are:
+ *
+ * BLANK_TIMER console screen-saver timer
+ *
+ * BEEP_TIMER console beep timer
+ *
+ * SERx_TIMER serial incoming characters timer
+ *
+ * SERx_TIMEOUT timeout for serial writes
+ *
+ * HD_TIMER harddisk timer
+ *
+ * FLOPPY_TIMER floppy disk timer (not used right now)
+ */
+
+#define BLANK_TIMER 0
+#define BEEP_TIMER 1
+#define SER1_TIMER 2
+#define SER2_TIMER 3
+
+#define SER1_TIMEOUT 8
+#define SER2_TIMEOUT 9
+
+#define HD_TIMER 16
+#define FLOPPY_TIMER 17
+
+struct timer_struct {
+ unsigned long expires;
+ void (*fn)(void);
+};
+
+extern unsigned long timer_active;
+extern struct timer_struct timer_table[32];
+
+#endif
diff --git a/include/linux/tty.h b/include/linux/tty.h
index c3d7af6..4812f85 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -60,6 +60,7 @@ struct tty_struct {
int pgrp;
int session;
int stopped;
+ struct winsize winsize;
void (*write)(struct tty_struct * tty);
struct tty_queue *read_q;
struct tty_queue *write_q;
@@ -68,6 +69,9 @@ struct tty_struct {
extern struct tty_struct tty_table[];
extern int fg_console;
+extern unsigned long video_num_columns;
+extern unsigned long video_num_lines;
+
#define TTY_TABLE(nr) \
(tty_table + ((nr) ? (((nr) < 64)? (nr)-1:(nr)) : fg_console))
@@ -84,7 +88,7 @@ void rs_init(void);
void con_init(void);
void tty_init(void);
-int tty_read(unsigned c, char * buf, int n);
+int tty_read(unsigned c, char * buf, int n, unsigned short flags);
int tty_write(unsigned c, char * buf, int n);
void con_write(struct tty_struct * tty);
@@ -94,6 +98,6 @@ void spty_write(struct tty_struct * tty);
void copy_to_cooked(struct tty_struct * tty);
-void update_screen(void);
+void update_screen(int new_console);
#endif
diff --git a/include/signal.h b/include/signal.h
index 462556d..e4126d3 100644
--- a/include/signal.h
+++ b/include/signal.h
@@ -33,6 +33,26 @@ typedef unsigned int sigset_t; /* 32 bits */
#define SIGTTIN 21
#define SIGTTOU 22
+/*
+ * Most of these aren't used yet (and perhaps never will),
+ * so they are commented out.
+ */
+
+/*
+#define SIGIO 23
+#define SIGPOLL SIGIO
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+*/
+
+#define SIGWINCH 28
+
+/*
+#define SIGLOST 29
+*/
+
/* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */
#define SA_NOCLDSTOP 1
#define SA_INTERRUPT 0x20000000
diff --git a/include/string.h b/include/string.h
index 05a6d9c..7da1793 100644
--- a/include/string.h
+++ b/include/string.h
@@ -35,7 +35,7 @@ __asm__("cld\n"
return dest;
}
-extern inline char * strncpy(char * dest,const char *src,int count)
+extern inline char * strncpy(char * dest,const char *src,size_t count)
{
__asm__("cld\n"
"1:\tdecl %2\n\t"
@@ -65,7 +65,7 @@ __asm__("cld\n\t"
return dest;
}
-extern inline char * strncat(char * dest,const char * src,int count)
+extern inline char * strncat(char * dest,const char * src,size_t count)
{
__asm__("cld\n\t"
"repne\n\t"
@@ -104,7 +104,7 @@ __asm__("cld\n"
return __res;
}
-extern inline int strncmp(const char * cs,const char * ct,int count)
+extern inline int strncmp(const char * cs,const char * ct,size_t count)
{
register int __res __asm__("ax");
__asm__("cld\n"
@@ -158,7 +158,7 @@ __asm__("cld\n\t"
return __res;
}
-extern inline int strspn(const char * cs, const char * ct)
+extern inline size_t strspn(const char * cs, const char * ct)
{
register char * __res __asm__("si");
__asm__("cld\n\t"
@@ -182,7 +182,7 @@ __asm__("cld\n\t"
return __res-cs;
}
-extern inline int strcspn(const char * cs, const char * ct)
+extern inline size_t strcspn(const char * cs, const char * ct)
{
register char * __res __asm__("si");
__asm__("cld\n\t"
@@ -260,7 +260,7 @@ __asm__("cld\n\t" \
return __res;
}
-extern inline int strlen(const char * s)
+extern inline size_t strlen(const char * s)
{
register int __res __asm__("cx");
__asm__("cld\n\t"
@@ -327,13 +327,18 @@ __asm__("testl %1,%1\n\t"
"jne 8f\n\t"
"movl %0,%1\n"
"8:"
- :"=b" (__res),"=S" (___strtok)
+#if __GNUC__ == 2
+ :"=r" (__res)
+#else
+ :"=b" (__res)
+#endif
+ ,"=S" (___strtok)
:"0" (___strtok),"1" (s),"g" (ct)
:"ax","cx","dx","di");
return __res;
}
-extern inline void * memcpy(void * dest,const void * src, int n)
+extern inline void * memcpy(void * dest,const void * src, size_t n)
{
__asm__("cld\n\t"
"rep\n\t"
@@ -343,7 +348,7 @@ __asm__("cld\n\t"
return dest;
}
-extern inline void * memmove(void * dest,const void * src, int n)
+extern inline void * memmove(void * dest,const void * src, size_t n)
{
if (dest<src)
__asm__("cld\n\t"
@@ -354,13 +359,14 @@ __asm__("cld\n\t"
else
__asm__("std\n\t"
"rep\n\t"
- "movsb"
+ "movsb\n\t"
+ "cld"
::"c" (n),"S" (src+n-1),"D" (dest+n-1)
:"cx","si","di");
return dest;
}
-extern inline int memcmp(const void * cs,const void * ct,int count)
+extern inline int memcmp(const void * cs,const void * ct,size_t count)
{
register int __res __asm__("ax");
__asm__("cld\n\t"
@@ -376,7 +382,7 @@ __asm__("cld\n\t"
return __res;
}
-extern inline void * memchr(const void * cs,char c,int count)
+extern inline void * memchr(const void * cs,char c,size_t count)
{
register void * __res __asm__("di");
if (!count)
@@ -392,7 +398,7 @@ __asm__("cld\n\t"
return __res;
}
-extern inline void * memset(void * s,char c,int count)
+extern inline void * memset(void * s,char c,size_t count)
{
__asm__("cld\n\t"
"rep\n\t"
diff --git a/include/sys/ptrace.h b/include/sys/ptrace.h
new file mode 100644
index 0000000..14bf3c7
--- /dev/null
+++ b/include/sys/ptrace.h
@@ -0,0 +1,52 @@
+/* ptrace.h */
+/* structs and defines to help the user use the ptrace system call. */
+
+#ifndef _SYS_PTRACE_H
+#define _SYS_PTRACE_H
+/* has the defines to get at the registers. */
+/* use ptrace (3 or 6, pid, PT_EXCL, data); to read or write
+ the processes registers. */
+
+#define EBX 0
+#define ECX 1
+#define EDX 2
+#define ESI 3
+#define EDI 4
+#define EBP 5
+#define EAX 6
+#define DS 7
+#define ES 8
+#define FS 9
+#define GS 10
+#define ORIG_EAX 11
+#define EIP 12
+#define CS 13
+#define EFL 14
+#define UESP 15
+#define SS 16
+
+
+/* this struct defines the way the registers are stored on the
+ stack during a system call. */
+
+struct pt_regs {
+ long ebx;
+ long ecx;
+ long edx;
+ long esi;
+ long edi;
+ long ebp;
+ long eax;
+ long ds;
+ long es;
+ long fs;
+ long gs;
+ long orig_eax;
+ long eip;
+ long cs;
+ long eflags;
+ long esp;
+ long ss;
+};
+
+#endif /* _SYS_PTRACE_H */
diff --git a/include/sys/time.h b/include/sys/time.h
index 7d56038..1165c26 100644
--- a/include/sys/time.h
+++ b/include/sys/time.h
@@ -24,6 +24,7 @@ struct timezone {
#define DST_TUR 9 /* Turkey */
#define DST_AUSTALT 10 /* Australian style with shift in 1986 */
+#define FD_SETSIZE (8*sizeof(fd_set))
#define FD_SET(fd,fdsetp) (*(fdsetp) |= (1 << (fd)))
#define FD_CLR(fd,fdsetp) (*(fdsetp) &= ~(1 << (fd)))
#define FD_ISSET(fd,fdsetp) ((*(fdsetp) >> fd) & 1)
diff --git a/include/sys/types.h b/include/sys/types.h
index aa260c8..5e220fa 100644
--- a/include/sys/types.h
+++ b/include/sys/types.h
@@ -27,11 +27,12 @@ typedef unsigned short dev_t;
typedef unsigned short ino_t;
typedef unsigned short mode_t;
typedef unsigned short umode_t;
-typedef unsigned char nlink_t;
+typedef unsigned short nlink_t;
typedef int daddr_t;
typedef long off_t;
typedef unsigned char u_char;
typedef unsigned short ushort;
+typedef char *caddr_t;
typedef unsigned char cc_t;
typedef unsigned int speed_t;
diff --git a/include/termios.h b/include/termios.h
index 3c2937b..faa6e53 100644
--- a/include/termios.h
+++ b/include/termios.h
@@ -35,6 +35,7 @@
#define TIOCSSOFTCAR 0x541A
#define FIONREAD 0x541B
#define TIOCINQ FIONREAD
+#define TIOCLINUX 0x541C
struct winsize {
unsigned short ws_row;
diff --git a/include/time.h b/include/time.h
index fbb4e73..f7e7ba1 100644
--- a/include/time.h
+++ b/include/time.h
@@ -32,7 +32,7 @@ struct tm {
};
#define __isleap(year) \
- ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 1000 == 0))
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
clock_t clock(void);
time_t time(time_t * tp);
diff --git a/include/unistd.h b/include/unistd.h
index b72f6b0..622aa6f 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -4,11 +4,11 @@
/* ok, this may be a joke, but I'm working on it */
#define _POSIX_VERSION 198808L
-#define _POSIX_CHOWN_RESTRICTED /* only root can do a chown (I think..) */
-#define _POSIX_NO_TRUNC /* no pathname truncation (but see in kernel) */
-#define _POSIX_VDISABLE '\0' /* character to disable things like ^C */
-#define _POSIX_JOB_CONTROL
-#define _POSIX_SAVED_IDS /* Implemented, for whatever good it is */
+#define _POSIX_CHOWN_RESTRICTED 1 /* only root can do a chown (I think..) */
+#define _POSIX_NO_TRUNC 1 /* no pathname truncation (but see kernel) */
+#define _POSIX_VDISABLE '\0' /* character to disable things like ^C */
+#define _POSIX_JOB_CONTROL 1
+#define _POSIX_SAVED_IDS 1 /* Implemented, for whatever good it is */
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
@@ -146,6 +146,8 @@
#define __NR_lstat 84
#define __NR_readlink 85
#define __NR_uselib 86
+#define __NR_swapon 87
+#define __NR_reboot 88
#define _syscall0(type,name) \
type name(void) \
@@ -164,9 +166,10 @@ return -1; \
type name(atype a) \
{ \
long __res; \
-__asm__ volatile ("int $0x80" \
+__asm__ volatile ("movl %2,%%ebx\n\t" \
+ "int $0x80" \
: "=a" (__res) \
- : "0" (__NR_##name),"b" ((long)(a))); \
+ : "0" (__NR_##name),"g" ((long)(a)):"bx"); \
if (__res >= 0) \
return (type) __res; \
errno = -__res; \
@@ -177,9 +180,10 @@ return -1; \
type name(atype a,btype b) \
{ \
long __res; \
-__asm__ volatile ("int $0x80" \
+__asm__ volatile ("movl %2,%%ebx\n\t" \
+ "int $0x80" \
: "=a" (__res) \
- : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b))); \
+ : "0" (__NR_##name),"g" ((long)(a)),"c" ((long)(b)):"bx"); \
if (__res >= 0) \
return (type) __res; \
errno = -__res; \
@@ -190,9 +194,10 @@ return -1; \
type name(atype a,btype b,ctype c) \
{ \
long __res; \
-__asm__ volatile ("int $0x80" \
+__asm__ volatile ("movl %2,%%ebx\n\t" \
+ "int $0x80" \
: "=a" (__res) \
- : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \
+ : "0" (__NR_##name),"g" ((long)(a)),"c" ((long)(b)),"d" ((long)(c)):"bx"); \
if (__res>=0) \
return (type) __res; \
errno=-__res; \
@@ -276,5 +281,5 @@ int getgroups(int gidsetlen, gid_t *gidset);
int setgroups(int gidsetlen, gid_t *gidset);
int select(int width, fd_set * readfds, fd_set * writefds,
fd_set * exceptfds, struct timeval * timeout);
-
+int swapon(const char * specialfile);
#endif
diff --git a/init/main.c b/init/main.c
index 5fd2cdb..1739de5 100644
--- a/init/main.c
+++ b/init/main.c
@@ -73,7 +73,6 @@ static int sprintf(char * str, const char *fmt, ...)
#define CON_COLS (((*(unsigned short *)0x9000e) & 0xff00) >> 8)
#define DRIVE_INFO (*(struct drive_info *)0x90080)
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
-#define ORIG_SWAP_DEV (*(unsigned short *)0x901FA)
/*
* Yeah, yeah, it's ugly, but I cannot find how to do this correctly
@@ -116,6 +115,9 @@ static long buffer_memory_end = 0;
static long main_memory_start = 0;
static char term[32];
+static char * argv_init[] = { "/bin/init", NULL };
+static char * envp_init[] = { "HOME=/", NULL, NULL };
+
static char * argv_rc[] = { "/bin/sh", NULL };
static char * envp_rc[] = { "HOME=/", NULL ,NULL };
@@ -124,26 +126,28 @@ static char * envp[] = { "HOME=/usr/root", NULL, NULL };
struct drive_info { char dummy[32]; } drive_info;
-void main(void) /* This really IS void, no error here. */
-{ /* The startup routine assumes (well, ...) this */
+void start_kernel(void)
+{
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
ROOT_DEV = ORIG_ROOT_DEV;
- SWAP_DEV = ORIG_SWAP_DEV;
sprintf(term, "TERM=con%dx%d", CON_COLS, CON_ROWS);
envp[1] = term;
envp_rc[1] = term;
+ envp_init[1] = term;
drive_info = DRIVE_INFO;
memory_end = (1<<20) + (EXT_MEM_K<<10);
memory_end &= 0xfffff000;
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
- if (memory_end > 12*1024*1024)
+ if (memory_end >= 12*1024*1024)
buffer_memory_end = 4*1024*1024;
- else if (memory_end > 6*1024*1024)
+ else if (memory_end >= 6*1024*1024)
buffer_memory_end = 2*1024*1024;
+ else if (memory_end >= 4*1024*1024)
+ buffer_memory_end = 3*512*1024;
else
buffer_memory_end = 1*1024*1024;
main_memory_start = buffer_memory_end;
@@ -198,6 +202,10 @@ void init(void)
printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,
NR_BUFFERS*BLOCK_SIZE);
printf("Free mem: %d bytes\n\r",memory_end-main_memory_start);
+
+ execve("/bin/init",argv_init,envp_init);
+ /* if this fails, fall through to original stuff */
+
if (!(pid=fork())) {
close(0);
if (open("/etc/rc",O_RDONLY,0))
diff --git a/kernel/Makefile b/kernel/Makefile
index 5f5685f..5a5444f 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -1,18 +1,21 @@
#
-# Makefile for the FREAX-kernel.
+# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
-AR =gar
-AS =gas
-LD =gld
+# gcc2 doesn't have these:
+#GCC_OPT = -fcombine-regs
+
+AR =ar
+AS =as
+LD =ld
LDFLAGS =-s -x
CC =gcc
-CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \
- -finline-functions -mstring-insns -nostdinc -I../include
+CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer $(GCC_OPT) \
+ -finline-functions -nostdinc -I../include
CPP =gcc -E -nostdinc -I../include
.c.s:
@@ -26,7 +29,7 @@ CPP =gcc -E -nostdinc -I../include
OBJS = sched.o sys_call.o traps.o asm.o fork.o \
panic.o printk.o vsprintf.o sys.o exit.o \
- signal.o mktime.o
+ signal.o mktime.o ptrace.o
kernel.o: $(OBJS)
$(LD) -r -o kernel.o $(OBJS)
@@ -66,17 +69,24 @@ panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h \
../include/sys/time.h ../include/time.h ../include/sys/resource.h
printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \
../include/linux/kernel.h
+ptrace.s ptrace.o : ptrace.c ../include/linux/head.h ../include/linux/kernel.h \
+ ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \
+ ../include/linux/mm.h ../include/signal.h ../include/sys/param.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+ ../include/errno.h ../include/asm/segment.h ../include/asm/system.h \
+ ../include/sys/ptrace.h
sched.s sched.o : sched.c ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
../include/sys/time.h ../include/time.h ../include/sys/resource.h \
- ../include/linux/sys.h ../include/linux/fdreg.h ../include/asm/system.h \
- ../include/asm/io.h ../include/asm/segment.h
+ ../include/linux/timer.h ../include/linux/sys.h ../include/linux/fdreg.h \
+ ../include/asm/system.h ../include/asm/io.h ../include/asm/segment.h \
+ ../include/errno.h
signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
../include/sys/time.h ../include/time.h ../include/sys/resource.h \
- ../include/asm/segment.h ../include/errno.h
+ ../include/asm/segment.h ../include/sys/wait.h ../include/errno.h
sys.s sys.o : sys.c ../include/errno.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
@@ -89,5 +99,5 @@ traps.s traps.o : traps.c ../include/string.h ../include/linux/head.h \
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h ../include/asm/system.h ../include/asm/segment.h \
- ../include/asm/io.h
+ ../include/asm/io.h ../include/errno.h
vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h
diff --git a/kernel/asm.s b/kernel/asm.s
index b3bbf8b..299e4a9 100644
--- a/kernel/asm.s
+++ b/kernel/asm.s
@@ -16,72 +16,90 @@
.globl _invalid_TSS,_segment_not_present,_stack_segment
.globl _general_protection,_coprocessor_error,_irq13,_reserved
.globl _alignment_check
+.globl _page_fault
_divide_error:
+ pushl $0 # no error code
pushl $_do_divide_error
-no_error_code:
- xchgl %eax,(%esp)
- pushl %ebx
- pushl %ecx
- pushl %edx
+error_code:
+ push %fs
+ push %es
+ push %ds
+ pushl %eax
+ pushl %ebp
pushl %edi
pushl %esi
- pushl %ebp
- push %ds
- push %es
- push %fs
- pushl $0 # "error code"
- lea 44(%esp),%edx
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
+ cld
+ movl $-1, %eax
+ xchgl %eax, 0x2c(%esp) # orig_eax (get the error code. )
+ xorl %ebx,%ebx # zero ebx
+ mov %gs,%bx # get the lower order bits of gs
+ xchgl %ebx, 0x28(%esp) # get the address and save gs.
+ pushl %eax # push the error code
+ lea 52(%esp),%edx
pushl %edx
movl $0x10,%edx
mov %dx,%ds
mov %dx,%es
mov %dx,%fs
- call *%eax
+ call *%ebx
addl $8,%esp
- pop %fs
- pop %es
- pop %ds
- popl %ebp
+ popl %ebx
+ popl %ecx
+ popl %edx
popl %esi
popl %edi
- popl %edx
- popl %ecx
- popl %ebx
+ popl %ebp
popl %eax
+ pop %ds
+ pop %es
+ pop %fs
+ pop %gs
+ addl $4,%esp
iret
_debug:
+ pushl $0
pushl $_do_int3 # _do_debug
- jmp no_error_code
+ jmp error_code
_nmi:
+ pushl $0
pushl $_do_nmi
- jmp no_error_code
+ jmp error_code
_int3:
+ pushl $0
pushl $_do_int3
- jmp no_error_code
+ jmp error_code
_overflow:
+ pushl $0
pushl $_do_overflow
- jmp no_error_code
+ jmp error_code
_bounds:
+ pushl $0
pushl $_do_bounds
- jmp no_error_code
+ jmp error_code
_invalid_op:
+ pushl $0
pushl $_do_invalid_op
- jmp no_error_code
+ jmp error_code
_coprocessor_segment_overrun:
+ pushl $0
pushl $_do_coprocessor_segment_overrun
- jmp no_error_code
+ jmp error_code
_reserved:
+ pushl $0
pushl $_do_reserved
- jmp no_error_code
+ jmp error_code
_irq13:
pushl %eax
@@ -97,37 +115,7 @@ _irq13:
_double_fault:
pushl $_do_double_fault
-error_code:
- xchgl %eax,4(%esp) # error code <-> %eax
- xchgl %ebx,(%esp) # &function <-> %ebx
- pushl %ecx
- pushl %edx
- pushl %edi
- pushl %esi
- pushl %ebp
- push %ds
- push %es
- push %fs
- pushl %eax # error code
- lea 44(%esp),%eax # offset
- pushl %eax
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- mov %ax,%fs
- call *%ebx
- addl $8,%esp
- pop %fs
- pop %es
- pop %ds
- popl %ebp
- popl %esi
- popl %edi
- popl %edx
- popl %ecx
- popl %ebx
- popl %eax
- iret
+ jmp error_code
_invalid_TSS:
pushl $_do_invalid_TSS
@@ -149,3 +137,6 @@ _alignment_check:
pushl $_do_alignment_check
jmp error_code
+_page_fault:
+ pushl $_do_page_fault
+ jmp error_code
diff --git a/kernel/blk_drv/Makefile b/kernel/blk_drv/Makefile
index e1393ac..ee05aaa 100644
--- a/kernel/blk_drv/Makefile
+++ b/kernel/blk_drv/Makefile
@@ -1,18 +1,18 @@
#
-# Makefile for the FREAX-kernel block device drivers.
+# Makefile for the kernel block device drivers.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
-AR =gar
-AS =gas
-LD =gld
+AR =ar
+AS =as
+LD =ld
LDFLAGS =-s -x
CC =gcc
-CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \
- -finline-functions -mstring-insns -nostdinc -I../../include
+CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \
+ -finline-functions -nostdinc -I../../include
CPP =gcc -E -nostdinc -I../../include
.c.s:
@@ -53,9 +53,9 @@ hd.s hd.o : hd.c ../../include/linux/config.h ../../include/linux/sched.h \
../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h \
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
- ../../include/sys/resource.h ../../include/linux/hdreg.h \
- ../../include/asm/system.h ../../include/asm/io.h \
- ../../include/asm/segment.h blk.h
+ ../../include/sys/resource.h ../../include/linux/timer.h \
+ ../../include/linux/hdreg.h ../../include/asm/system.h \
+ ../../include/asm/io.h ../../include/asm/segment.h blk.h
ll_rw_blk.s ll_rw_blk.o : ll_rw_blk.c ../../include/errno.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/linux/mm.h \
@@ -67,5 +67,6 @@ ramdisk.s ramdisk.o : ramdisk.c ../../include/string.h ../../include/linux/confi
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h \
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
- ../../include/sys/resource.h ../../include/asm/system.h \
- ../../include/asm/segment.h ../../include/asm/memory.h blk.h
+ ../../include/sys/resource.h ../../include/linux/minix_fs.h \
+ ../../include/asm/system.h ../../include/asm/segment.h \
+ ../../include/asm/memory.h blk.h
diff --git a/kernel/blk_drv/blk.h b/kernel/blk_drv/blk.h
index 0c62c82..28e37d5 100644
--- a/kernel/blk_drv/blk.h
+++ b/kernel/blk_drv/blk.h
@@ -38,9 +38,9 @@ struct request {
* are much more time-critical than writes.
*/
#define IN_ORDER(s1,s2) \
-((s1)->cmd<(s2)->cmd || (s1)->cmd==(s2)->cmd && \
-((s1)->dev < (s2)->dev || ((s1)->dev == (s2)->dev && \
-(s1)->sector < (s2)->sector)))
+((s1)->cmd<(s2)->cmd || ((s1)->cmd==(s2)->cmd && \
+((s1)->dev < (s2)->dev || (((s1)->dev == (s2)->dev && \
+(s1)->sector < (s2)->sector)))))
struct blk_dev_struct {
void (*request_fn)(void);
@@ -81,9 +81,9 @@ extern int * blk_size[NR_BLK_DEV];
/* harddisk */
#define DEVICE_NAME "harddisk"
#define DEVICE_INTR do_hd
-#define DEVICE_TIMEOUT hd_timeout
+#define DEVICE_TIMEOUT HD_TIMER
#define DEVICE_REQUEST do_hd_request
-#define DEVICE_NR(device) (MINOR(device)/5)
+#define DEVICE_NR(device) (MINOR(device)>>6)
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
@@ -100,8 +100,9 @@ extern int * blk_size[NR_BLK_DEV];
void (*DEVICE_INTR)(void) = NULL;
#endif
#ifdef DEVICE_TIMEOUT
-int DEVICE_TIMEOUT = 0;
-#define SET_INTR(x) (DEVICE_INTR = (x),DEVICE_TIMEOUT = 200)
+#define SET_INTR(x) (DEVICE_INTR = (x), \
+ timer_table[DEVICE_TIMEOUT].expires = jiffies + 200, \
+ timer_active |= 1<<DEVICE_TIMEOUT)
#else
#define SET_INTR(x) (DEVICE_INTR = (x))
#endif
@@ -134,7 +135,7 @@ extern inline void end_request(int uptodate)
}
#ifdef DEVICE_TIMEOUT
-#define CLEAR_DEVICE_TIMEOUT DEVICE_TIMEOUT = 0;
+#define CLEAR_DEVICE_TIMEOUT timer_active &= ~(1<<DEVICE_TIMEOUT);
#else
#define CLEAR_DEVICE_TIMEOUT
#endif
diff --git a/kernel/blk_drv/floppy.c b/kernel/blk_drv/floppy.c
index 3bccac0..92881e5 100644
--- a/kernel/blk_drv/floppy.c
+++ b/kernel/blk_drv/floppy.c
@@ -25,9 +25,11 @@
* handler may not sleep, or a kernel panic will happen. Thus I cannot
* call "floppy-on" directly, but have to set a special timer interrupt
* etc.
- *
- * Also, I'm not certain this works on more than 1 floppy. Bugs may
- * abund.
+ */
+
+/*
+ * 28.02.92 - made track-buffering routines, based on the routines written
+ * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
*/
#include <linux/sched.h>
@@ -53,11 +55,11 @@ __asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port))
#define TYPE(x) ((x)>>2)
#define DRIVE(x) ((x)&0x03)
/*
- * Note that MAX_ERRORS=8 doesn't imply that we retry every bad read
- * max 8 times - some types of errors increase the errorcount by 2,
- * so we might actually retry only 5-6 times before giving up.
+ * Note that MAX_ERRORS=X doesn't imply that we retry every bad read
+ * max X times - some types of errors increase the errorcount by 2,
+ * so we might actually retry only X/2 times before giving up.
*/
-#define MAX_ERRORS 8
+#define MAX_ERRORS 12
/*
* globals used by 'result()'
@@ -79,10 +81,12 @@ static unsigned char reply_buffer[MAX_REPLIES];
* types (ie 360kB diskette in 1.2MB drive etc). Others should
* be self-explanatory.
*/
-static struct floppy_struct {
+struct floppy_struct {
unsigned int size, sect, head, track, stretch;
unsigned char gap,rate,spec1;
-} floppy_type[] = {
+};
+
+static struct floppy_struct floppy_type[] = {
{ 0, 0,0, 0,0,0x00,0x00,0x00 }, /* no testing */
{ 720, 9,2,40,0,0x2A,0x02,0xDF }, /* 360kB PC diskettes */
{ 2400,15,2,80,0,0x1B,0x00,0xDF }, /* 1.2 MB AT-diskettes */
@@ -104,12 +108,16 @@ static struct floppy_struct {
extern void floppy_interrupt(void);
extern char tmp_floppy_area[1024];
+extern char floppy_track_buffer[512*2*18];
/*
* These are global variables, as that's the easiest way to give
* information to interrupts. They are the data used for the current
* request.
*/
+static int read_track = 0; /* flag to indicate if we want to read all track */
+static int buffer_track = -1;
+static int buffer_drive = -1;
static int cur_spec1 = -1;
static int cur_rate = -1;
static struct floppy_struct * floppy = floppy_type;
@@ -147,6 +155,7 @@ repeat:
goto repeat;
if (inb(FD_DIR) & 0x80) {
floppy_off(nr);
+ buffer_track = -1;
return 1;
}
floppy_off(nr);
@@ -160,10 +169,16 @@ __asm__("cld ; rep ; movsl" \
static void setup_DMA(void)
{
- long addr = (long) CURRENT->buffer;
+ unsigned long addr = (long) CURRENT->buffer;
+ unsigned long count = 1024;
cli();
- if (addr >= 0x100000) {
+ if (read_track) {
+/* mark buffer-track bad, in case all this fails.. */
+ buffer_drive = buffer_track = -1;
+ count = floppy->sect*2*512;
+ addr = (long) floppy_track_buffer;
+ } else if (addr >= 0x100000) {
addr = (long) tmp_floppy_area;
if (command == FD_WRITE)
copy_buffer(CURRENT->buffer,tmp_floppy_area);
@@ -183,10 +198,12 @@ static void setup_DMA(void)
addr >>= 8;
/* bits 16-19 of addr */
immoutb_p(addr,0x81);
-/* low 8 bits of count-1 (1024-1=0x3ff) */
- immoutb_p(0xff,5);
+/* low 8 bits of count-1 */
+ count--;
+ immoutb_p(count,5);
+ count >>= 8;
/* high 8 bits of count-1 */
- immoutb_p(3,5);
+ immoutb_p(count,5);
/* activate DMA 2 */
immoutb_p(0|2,10);
sti();
@@ -233,6 +250,7 @@ static int result(void)
static void bad_flp_intr(void)
{
+ current_track = -1;
CURRENT->errors++;
if (CURRENT->errors > MAX_ERRORS) {
floppy_deselect(current_drive);
@@ -240,8 +258,6 @@ static void bad_flp_intr(void)
}
if (CURRENT->errors > MAX_ERRORS/2)
reset = 1;
- else
- recalibrate = 1;
}
/*
@@ -250,6 +266,8 @@ static void bad_flp_intr(void)
*/
static void rw_interrupt(void)
{
+ char * buffer_area;
+
if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || (ST2 & 0x73)) {
if (ST1 & 0x02) {
printk("Drive %d is write protected\n\r",current_drive);
@@ -260,22 +278,43 @@ static void rw_interrupt(void)
do_fd_request();
return;
}
- if (command == FD_READ && (unsigned long)(CURRENT->buffer) >= 0x100000)
+ if (read_track) {
+ buffer_track = seek_track;
+ buffer_drive = current_drive;
+ buffer_area = floppy_track_buffer +
+ ((sector-1 + head*floppy->sect)<<9);
+ copy_buffer(buffer_area,CURRENT->buffer);
+ } else if (command == FD_READ &&
+ (unsigned long)(CURRENT->buffer) >= 0x100000)
copy_buffer(tmp_floppy_area,CURRENT->buffer);
floppy_deselect(current_drive);
end_request(1);
do_fd_request();
}
+/*
+ * We try to read tracks, but if we get too many errors, we
+ * go back to reading just one sector at a time.
+ *
+ * This means we should be able to read a sector even if there
+ * are other bad sectors on this track.
+ */
inline void setup_rw_floppy(void)
{
setup_DMA();
do_floppy = rw_interrupt;
output_byte(command);
- output_byte(head<<2 | current_drive);
- output_byte(track);
- output_byte(head);
- output_byte(sector);
+ if (read_track) {
+ output_byte(current_drive);
+ output_byte(track);
+ output_byte(0);
+ output_byte(1);
+ } else {
+ output_byte(head<<2 | current_drive);
+ output_byte(track);
+ output_byte(head);
+ output_byte(sector);
+ }
output_byte(2); /* sector size = 512 */
output_byte(floppy->sect);
output_byte(floppy->gap);
@@ -294,6 +333,7 @@ static void seek_interrupt(void)
/* sense drive status */
output_byte(FD_SENSEI);
if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) {
+ recalibrate = 1;
bad_flp_intr();
do_fd_request();
return;
@@ -309,6 +349,7 @@ static void seek_interrupt(void)
*/
static void transfer(void)
{
+ read_track = (command == FD_READ) && (CURRENT->errors < 4);
if (cur_spec1 != floppy->spec1) {
cur_spec1 = floppy->spec1;
output_byte(FD_SPECIFY);
@@ -326,14 +367,12 @@ static void transfer(void)
return;
}
do_floppy = seek_interrupt;
- if (seek_track) {
- output_byte(FD_SEEK);
- output_byte(head<<2 | current_drive);
- output_byte(seek_track);
- } else {
- output_byte(FD_RECALIBRATE);
- output_byte(head<<2 | current_drive);
- }
+ output_byte(FD_SEEK);
+ if (read_track)
+ output_byte(current_drive);
+ else
+ output_byte((head<<2) | current_drive);
+ output_byte(seek_track);
if (reset)
do_fd_request();
}
@@ -418,6 +457,7 @@ static void floppy_on_interrupt(void)
void do_fd_request(void)
{
unsigned int block;
+ char * buffer_area;
seek = 0;
if (reset) {
@@ -443,15 +483,29 @@ void do_fd_request(void)
head = block % floppy->head;
track = block / floppy->head;
seek_track = track << floppy->stretch;
- if (seek_track != current_track)
- seek = 1;
- sector++;
if (CURRENT->cmd == READ)
command = FD_READ;
else if (CURRENT->cmd == WRITE)
command = FD_WRITE;
- else
- panic("do_fd_request: unknown command");
+ else {
+ printk("do_fd_request: unknown command\n");
+ end_request(0);
+ goto repeat;
+ }
+ if ((seek_track == buffer_track) &&
+ (current_drive == buffer_drive)) {
+ buffer_area = floppy_track_buffer +
+ ((sector + head*floppy->sect)<<9);
+ if (command == FD_READ) {
+ copy_buffer(buffer_area,CURRENT->buffer);
+ end_request(1);
+ goto repeat;
+ } else
+ copy_buffer(CURRENT->buffer,buffer_area);
+ }
+ if (seek_track != current_track)
+ seek = 1;
+ sector++;
add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt);
}
@@ -468,8 +522,9 @@ static int floppy_sizes[] ={
void floppy_init(void)
{
+ outb(current_DOR,FD_DOR);
blk_size[MAJOR_NR] = floppy_sizes;
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
- set_trap_gate(0x26,&floppy_interrupt);
+ set_intr_gate(0x26,&floppy_interrupt);
outb(inb_p(0x21)&~0x40,0x21);
}
diff --git a/kernel/blk_drv/hd.c b/kernel/blk_drv/hd.c
index 563be0a..b75b176 100644
--- a/kernel/blk_drv/hd.c
+++ b/kernel/blk_drv/hd.c
@@ -15,6 +15,7 @@
#include <linux/config.h>
#include <linux/sched.h>
+#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/hdreg.h>
@@ -44,7 +45,7 @@ static int reset = 0;
* This struct defines the HD's and their types.
*/
struct hd_i_struct {
- int head,sect,cyl,wpcom,lzone,ctl;
+ unsigned int head,sect,cyl,wpcom,lzone,ctl;
};
#ifdef HD_TYPE
struct hd_i_struct hd_info[] = { HD_TYPE };
@@ -57,9 +58,9 @@ static int NR_HD = 0;
static struct hd_struct {
long start_sect;
long nr_sects;
-} hd[5*MAX_HD]={{0,0},};
+} hd[MAX_HD<<6]={{0,0},};
-static int hd_sizes[5*MAX_HD] = {0, };
+static int hd_sizes[MAX_HD<<6] = {0, };
#define port_read(port,buf,nr) \
__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
@@ -70,14 +71,40 @@ __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
extern void hd_interrupt(void);
extern void rd_load(void);
+static unsigned int current_minor;
+
+static void check_partition(unsigned int dev)
+{
+ int minor, i;
+ struct buffer_head *bh;
+ struct partition *p;
+
+ if (!(bh = bread(dev,0))) {
+ printk("Unable to read partition table of device %04x\n",dev);
+ return;
+ }
+ minor = current_minor;
+ if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
+ p = 0x1BE + (void *)bh->b_data;
+ for (i=0 ; i<4 ; i++,p++) {
+ hd[i+minor].start_sect = p->start_sect;
+ hd[i+minor].nr_sects = p->nr_sects;
+ }
+ if (p->nr_sects && p->sys_ind == EXTENDED_PARTITION) {
+ current_minor += 4;
+ check_partition(i+minor);
+ }
+ } else
+ printk("Bad partition table on dev %04x\n",dev);
+ brelse(bh);
+}
+
/* This may be used only once, enforced by 'static int callable' */
int sys_setup(void * BIOS)
{
static int callable = 1;
int i,drive;
unsigned char cmos_disks;
- struct partition *p;
- struct buffer_head * bh;
if (!callable)
return -1;
@@ -98,8 +125,8 @@ int sys_setup(void * BIOS)
NR_HD=1;
#endif
for (i=0 ; i<NR_HD ; i++) {
- hd[i*5].start_sect = 0;
- hd[i*5].nr_sects = hd_info[i].head*
+ hd[i<<6].start_sect = 0;
+ hd[i<<6].nr_sects = hd_info[i].head*
hd_info[i].sect*hd_info[i].cyl;
}
@@ -133,34 +160,19 @@ int sys_setup(void * BIOS)
else
NR_HD = 0;
for (i = NR_HD ; i < 2 ; i++) {
- hd[i*5].start_sect = 0;
- hd[i*5].nr_sects = 0;
+ hd[i<<6].start_sect = 0;
+ hd[i<<6].nr_sects = 0;
}
for (drive=0 ; drive<NR_HD ; drive++) {
- if (!(bh = bread(0x300 + drive*5,0))) {
- printk("Unable to read partition table of drive %d\n\r",
- drive);
- panic("");
- }
- if (bh->b_data[510] != 0x55 || (unsigned char)
- bh->b_data[511] != 0xAA) {
- printk("Bad partition table on drive %d\n\r",drive);
- panic("");
- }
- p = 0x1BE + (void *)bh->b_data;
- for (i=1;i<5;i++,p++) {
- hd[i+5*drive].start_sect = p->start_sect;
- hd[i+5*drive].nr_sects = p->nr_sects;
- }
- brelse(bh);
+ current_minor = 1+(drive<<6);
+ check_partition(0x0300+(drive<<6));
}
- for (i=0 ; i<5*MAX_HD ; i++)
+ for (i=0 ; i<(MAX_HD<<6) ; i++)
hd_sizes[i] = hd[i].nr_sects>>1 ;
blk_size[MAJOR_NR] = hd_sizes;
if (NR_HD)
printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
rd_load();
- init_swapping();
mount_root();
return (0);
}
@@ -169,7 +181,11 @@ static int controller_ready(void)
{
int retries = 100000;
- while (--retries && (inb_p(HD_STATUS)&0xc0)!=0x40);
+ while (--retries && (inb_p(HD_STATUS)&0x80))
+ /* nothing */;
+ if (!retries)
+ printk("controller_ready: status = %02x\n\r",
+ (unsigned char) inb_p(HD_STATUS));
return (retries);
}
@@ -188,12 +204,14 @@ static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
unsigned int head,unsigned int cyl,unsigned int cmd,
void (*intr_addr)(void))
{
- register int port asm("dx");
+ unsigned short port;
if (drive>1 || head>15)
panic("Trying to write bad sector");
- if (!controller_ready())
- panic("HD controller not ready");
+ if (reset || !controller_ready()) {
+ reset = 1;
+ return;
+ }
SET_INTR(intr_addr);
outb_p(hd_info[drive].ctl,HD_CMD);
port=HD_DATA;
@@ -217,7 +235,7 @@ static int drive_busy(void)
if (c == (READY_STAT | SEEK_STAT))
return 0;
}
- printk("HD controller times out\n\r");
+ printk("HD controller times out, c=%02x\n\r",c);
return(1);
}
@@ -252,6 +270,8 @@ repeat:
if (i < NR_HD) {
hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
+ if (reset)
+ goto repeat;
} else
do_hd_request();
}
@@ -315,7 +335,7 @@ static void recal_intr(void)
do_hd_request();
}
-void hd_times_out(void)
+static void hd_times_out(void)
{
if (!CURRENT)
return;
@@ -337,16 +357,16 @@ void do_hd_request(void)
INIT_REQUEST;
dev = MINOR(CURRENT->dev);
block = CURRENT->sector;
- if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) {
+ if (dev >= (NR_HD<<6) || block+2 > hd[dev].nr_sects) {
end_request(0);
goto repeat;
}
block += hd[dev].start_sect;
- dev /= 5;
- __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0),
- "r" (hd_info[dev].sect));
- __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0),
- "r" (hd_info[dev].head));
+ dev >>= 6;
+ sec = block % hd_info[dev].sect;
+ block /= hd_info[dev].sect;
+ head = block % hd_info[dev].head;
+ cyl = block / hd_info[dev].head;
sec++;
nsect = CURRENT->nr_sectors;
if (reset) {
@@ -358,10 +378,14 @@ void do_hd_request(void)
recalibrate = 0;
hd_out(dev,hd_info[CURRENT_DEV].sect,0,0,0,
WIN_RESTORE,&recal_intr);
+ if (reset)
+ goto repeat;
return;
}
if (CURRENT->cmd == WRITE) {
hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
+ if (reset)
+ goto repeat;
for(i=0 ; i<10000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
/* nothing */ ;
if (!r) {
@@ -371,6 +395,8 @@ void do_hd_request(void)
port_write(HD_DATA,CURRENT->buffer,256);
} else if (CURRENT->cmd == READ) {
hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
+ if (reset)
+ goto repeat;
} else
panic("unknown hd-command");
}
@@ -378,7 +404,8 @@ void do_hd_request(void)
void hd_init(void)
{
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
- set_intr_gate(0x2E,&hd_interrupt);
+ set_trap_gate(0x2E,&hd_interrupt);
outb_p(inb_p(0x21)&0xfb,0x21);
outb(inb_p(0xA1)&0xbf,0xA1);
+ timer_table[HD_TIMER].fn = hd_times_out;
}
diff --git a/kernel/blk_drv/ll_rw_blk.c b/kernel/blk_drv/ll_rw_blk.c
index 9506a06..777dcc3 100644
--- a/kernel/blk_drv/ll_rw_blk.c
+++ b/kernel/blk_drv/ll_rw_blk.c
@@ -87,7 +87,7 @@ static void add_request(struct blk_dev_struct * dev, struct request * req)
(dev->request_fn)();
return;
}
- for ( ; tmp->next ; tmp=tmp->next) {
+ for ( ; tmp->next ; tmp = tmp->next) {
if (!req->bh)
if (tmp->next->bh)
break;
@@ -98,8 +98,8 @@ static void add_request(struct blk_dev_struct * dev, struct request * req)
IN_ORDER(req,tmp->next))
break;
}
- req->next=tmp->next;
- tmp->next=req;
+ req->next = tmp->next;
+ tmp->next = req;
sti();
}
@@ -118,8 +118,10 @@ static void make_request(int major,int rw, struct buffer_head * bh)
else
rw = WRITE;
}
- if (rw!=READ && rw!=WRITE)
- panic("Bad block dev command, must be R/W/RA/WA");
+ if (rw!=READ && rw!=WRITE) {
+ printk("Bad block dev command, must be R/W/RA/WA\n");
+ return;
+ }
lock_buffer(bh);
if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) {
unlock_buffer(bh);
@@ -135,18 +137,21 @@ repeat:
else
req = request+((NR_REQUEST*2)/3);
/* find an empty request */
+ cli();
while (--req >= request)
- if (req->dev<0)
- break;
+ if (req->dev < 0)
+ goto found;
/* if none found, sleep on new requests: check for rw_ahead */
- if (req < request) {
- if (rw_ahead) {
- unlock_buffer(bh);
- return;
- }
- sleep_on(&wait_for_request);
- goto repeat;
+ if (rw_ahead) {
+ sti();
+ unlock_buffer(bh);
+ return;
}
+ sleep_on(&wait_for_request);
+ sti();
+ goto repeat;
+
+found: sti();
/* fill up the request-info, and add it to the queue */
req->dev = bh->b_dev;
req->cmd = rw;
@@ -171,6 +176,7 @@ void ll_rw_page(int rw, int dev, int page, char * buffer)
}
if (rw!=READ && rw!=WRITE)
panic("Bad block dev command, must be R/W");
+ cli();
repeat:
req = request+NR_REQUEST;
while (--req >= request)
@@ -180,6 +186,7 @@ repeat:
sleep_on(&wait_for_request);
goto repeat;
}
+ sti();
/* fill up the request-info, and add it to the queue */
req->dev = dev;
req->cmd = rw;
@@ -193,7 +200,7 @@ repeat:
current->state = TASK_UNINTERRUPTIBLE;
add_request(major+blk_dev,req);
schedule();
-}
+}
void ll_rw_block(int rw, struct buffer_head * bh)
{
@@ -201,7 +208,7 @@ void ll_rw_block(int rw, struct buffer_head * bh)
if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV ||
!(blk_dev[major].request_fn)) {
- printk("Trying to read nonexistent block-device\n\r");
+ printk("ll_rw_block: Trying to read nonexistent block-device\n\r");
return;
}
make_request(major,rw,bh);
@@ -216,3 +223,46 @@ void blk_dev_init(void)
request[i].next = NULL;
}
}
+
+void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
+{
+ int i;
+ struct request * req;
+ unsigned int major = MAJOR(dev);
+
+ if (major >= NR_BLK_DEV || !(blk_dev[major].request_fn)) {
+ printk("ll_rw_swap_file: trying to swap nonexistent block-device\n\r");
+ return;
+ }
+
+ if (rw!=READ && rw!=WRITE) {
+ printk("ll_rw_swap: bad block dev command, must be R/W");
+ return;
+ }
+
+ for (i=0; i<nb; i++, buf += BLOCK_SIZE)
+ {
+repeat:
+ req = request+NR_REQUEST;
+ while (--req >= request)
+ if (req->dev<0)
+ break;
+ if (req < request) {
+ sleep_on(&wait_for_request);
+ goto repeat;
+ }
+
+ req->dev = dev;
+ req->cmd = rw;
+ req->errors = 0;
+ req->sector = b[i] << 1;
+ req->nr_sectors = 2;
+ req->buffer = buf;
+ req->waiting = current;
+ req->bh = NULL;
+ req->next = NULL;
+ current->state = TASK_UNINTERRUPTIBLE;
+ add_request(major+blk_dev,req);
+ schedule();
+ }
+}
diff --git a/kernel/blk_drv/ramdisk.c b/kernel/blk_drv/ramdisk.c
index dc99f7c..a7d86fb 100644
--- a/kernel/blk_drv/ramdisk.c
+++ b/kernel/blk_drv/ramdisk.c
@@ -8,6 +8,7 @@
#include <linux/config.h>
#include <linux/sched.h>
+#include <linux/minix_fs.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <asm/system.h>
@@ -88,9 +89,9 @@ void rd_load(void)
printk("Disk error while looking for ramdisk!\n");
return;
}
- *((struct d_super_block *) &s) = *((struct d_super_block *) bh->b_data);
+ *((struct minix_super_block *) &s) = *((struct minix_super_block *) bh->b_data);
brelse(bh);
- if (s.s_magic != SUPER_MAGIC)
+ if (s.s_magic != MINIX_SUPER_MAGIC)
/* No ram disk image present, assume normal floppy boot */
return;
nblocks = s.s_nzones << s.s_log_zone_size;
diff --git a/kernel/chr_drv/Makefile b/kernel/chr_drv/Makefile
index 66f4cec..4c28f9c 100644
--- a/kernel/chr_drv/Makefile
+++ b/kernel/chr_drv/Makefile
@@ -1,18 +1,21 @@
#
-# Makefile for the FREAX-kernel character device drivers.
+# Makefile for the kernel character device drivers.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
-AR =gar
-AS =gas
-LD =gld
+# gcc2 doesn't understand this option:
+#GCC_OPT = -fcombine-regs
+
+AR =ar
+AS =as
+LD =ld
LDFLAGS =-s -x
CC =gcc
-CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \
- -finline-functions -mstring-insns -nostdinc -I../../include
+CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer $(GCC_OPT) \
+ -finline-functions -nostdinc -I../../include
CPP =gcc -E -nostdinc -I../../include
.c.s:
@@ -50,8 +53,9 @@ console.s console.o : console.c ../../include/linux/sched.h \
../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h \
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
- ../../include/sys/resource.h ../../include/linux/tty.h \
- ../../include/termios.h ../../include/linux/config.h ../../include/asm/io.h \
+ ../../include/sys/resource.h ../../include/linux/timer.h \
+ ../../include/linux/tty.h ../../include/termios.h \
+ ../../include/linux/config.h ../../include/asm/io.h \
../../include/asm/system.h ../../include/asm/segment.h \
../../include/string.h ../../include/errno.h
pty.s pty.o : pty.c ../../include/linux/tty.h ../../include/termios.h \
@@ -67,13 +71,14 @@ serial.s serial.o : serial.c ../../include/linux/tty.h ../../include/termios.h \
../../include/linux/mm.h ../../include/linux/kernel.h \
../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
../../include/time.h ../../include/sys/resource.h \
- ../../include/asm/system.h ../../include/asm/io.h
+ ../../include/linux/timer.h ../../include/asm/system.h \
+ ../../include/asm/io.h
tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \
../../include/signal.h ../../include/sys/types.h ../../include/unistd.h \
../../include/sys/stat.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/times.h ../../include/sys/utsname.h \
../../include/sys/param.h ../../include/sys/resource.h \
- ../../include/utime.h ../../include/linux/sched.h \
+ ../../include/utime.h ../../include/fcntl.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/linux/mm.h ../../include/linux/kernel.h \
../../include/linux/tty.h ../../include/termios.h \
diff --git a/kernel/chr_drv/console.c b/kernel/chr_drv/console.c
index 781fdab..3de8648 100644
--- a/kernel/chr_drv/console.c
+++ b/kernel/chr_drv/console.c
@@ -31,6 +31,7 @@
*/
#include <linux/sched.h>
+#include <linux/timer.h>
#include <linux/tty.h>
#include <linux/config.h>
#include <linux/kernel.h>
@@ -52,6 +53,8 @@
INIT_C_CC \
}
+static void blank_screen(void);
+static void unblank_screen(void);
/*
* These are set up by the setup-routine at boot-time:
@@ -77,13 +80,18 @@
int NR_CONSOLES = 0;
extern void keyboard_interrupt(void);
+extern void set_leds(void);
+extern unsigned char kapplic;
+extern unsigned char kleds;
+extern unsigned char kmode;
+
+unsigned long video_num_columns; /* Number of text columns */
+unsigned long video_num_lines; /* Number of test lines */
static unsigned char video_type; /* Type of display being used */
-static unsigned long video_num_columns; /* Number of text columns */
static unsigned long video_mem_base; /* Base of video memory */
static unsigned long video_mem_term; /* End of video memory */
static unsigned long video_size_row; /* Bytes per row */
-static unsigned long video_num_lines; /* Number of test lines */
static unsigned char video_page; /* Initial video page */
static unsigned short video_port_reg; /* Video register select port */
static unsigned short video_port_val; /* Video register value port */
@@ -96,7 +104,7 @@ static struct {
int vc_bold_attr;
unsigned long vc_ques;
unsigned long vc_state;
- unsigned long vc_restate;
+ char * vc_restate;
unsigned long vc_checkin;
unsigned long vc_origin; /* Used for EGA/VGA fast scroll */
unsigned long vc_scr_end; /* Used for EGA/VGA fast scroll */
@@ -109,9 +117,18 @@ static struct {
unsigned int vc_saved_x;
unsigned int vc_saved_y;
unsigned int vc_iscolor;
+ unsigned char vc_kbdapplic;
+ unsigned char vc_kbdleds;
+ unsigned char vc_kbdmode;
char * vc_translate;
} vc_cons [MAX_CONSOLES];
+#define MEM_BUFFER_SIZE (2*80*50*8)
+
+unsigned short *vc_scrbuf[MAX_CONSOLES];
+unsigned short vc_scrmembuf[MEM_BUFFER_SIZE/2];
+static int console_blanked = 0;
+
#define origin (vc_cons[currcons].vc_origin)
#define scr_end (vc_cons[currcons].vc_scr_end)
#define pos (vc_cons[currcons].vc_pos)
@@ -134,9 +151,12 @@ static struct {
#define def_attr (vc_cons[currcons].vc_def_attr)
#define video_erase_char (vc_cons[currcons].vc_video_erase_char)
#define iscolor (vc_cons[currcons].vc_iscolor)
+#define kbdapplic (vc_cons[currcons].vc_kbdapplic)
+#define kbdmode (vc_cons[currcons].vc_kbdmode)
+#define kbdleds (vc_cons[currcons].vc_kbdleds)
-int blankinterval = 0;
-int blankcount = 0;
+int blankinterval = 5*60*HZ;
+static int screen_size = 0;
static void sysbeep(void);
@@ -152,10 +172,15 @@ static char * translations[] = {
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~ ",
/* vt100 graphics */
- " !\"#$%&'()*+,-./0123456789:;<=>?"
- "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ "
- "\004\261\007\007\007\007\370\361\007\007\275\267\326\323\327\304"
- "\304\304\304\304\307\266\320\322\272\363\362\343\\007\234\007 "
+ " !\"#$%&'()*+,-./\333123456789:;<=>?"
+ "@ABCDEFGH\017JKLMNOPQRSTUVWXYZ[\\]^ "
+ /* ' a b c d e f g h i j k l m n o */
+ "\004\261\007\007\007\007\370\361\040\007\331\277\332\300\305\007"
+ /* p q r s t u v w x y z { | } ~ */
+ "\007\304\007\007\303\264\301\302\263\007\007\007\007\007\234 "
+
+ /*"\004\261\007\007\007\007\370\361\007\007\275\267\326\323\327\304"
+ "\304\304\304\304\307\266\320\322\272\363\362\343\\007\234\007 " */
};
#define NORM_TRANS (translations[0])
@@ -187,8 +212,26 @@ static inline void set_origin(int currcons)
static void scrup(int currcons)
{
- if (bottom<=top)
+ unsigned int oldbottom, oldtop;
+
+ oldbottom = bottom;
+ oldtop = top;
+ if (y < top) {
+ top = 0;
+ bottom = y + 1;
+ } else if (y > bottom) {
+ bottom = video_num_lines;
+ top = y;
+ }
+ if (top > video_num_lines)
+ top = 0;
+ if (bottom > video_num_lines)
+ bottom = video_num_lines;
+ if (bottom <= top) {
+ bottom = oldbottom;
+ top = oldtop;
return;
+ }
if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM)
{
if (!top && bottom == video_num_lines) {
@@ -248,42 +291,47 @@ static void scrup(int currcons)
"S" (origin+video_size_row*(top+1))
:"cx","di","si");
}
+ bottom = oldbottom;
+ top = oldtop;
}
static void scrdown(int currcons)
{
- if (bottom <= top)
- return;
- if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM)
- {
- __asm__("std\n\t"
- "rep\n\t"
- "movsl\n\t"
- "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
- "movl _video_num_columns,%%ecx\n\t"
- "rep\n\t"
- "stosw"
- ::"a" (video_erase_char),
- "c" ((bottom-top-1)*video_num_columns>>1),
- "D" (origin+video_size_row*bottom-4),
- "S" (origin+video_size_row*(bottom-1)-4)
- :"ax","cx","di","si");
+ unsigned int oldbottom, oldtop;
+
+ oldbottom = bottom;
+ oldtop = top;
+ if (y < top) {
+ top = 0;
+ bottom = y + 1;
+ } else if (y > bottom) {
+ bottom = video_num_lines;
+ top = y;
}
- else /* Not EGA/VGA */
- {
- __asm__("std\n\t"
- "rep\n\t"
- "movsl\n\t"
- "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
- "movl _video_num_columns,%%ecx\n\t"
- "rep\n\t"
- "stosw"
- ::"a" (video_erase_char),
- "c" ((bottom-top-1)*video_num_columns>>1),
- "D" (origin+video_size_row*bottom-4),
- "S" (origin+video_size_row*(bottom-1)-4)
- :"ax","cx","di","si");
+ if (top > video_num_lines)
+ top = 0;
+ if (bottom > video_num_lines)
+ bottom = video_num_lines;
+ if (bottom<=top) {
+ bottom = oldbottom;
+ top = oldtop;
+ return;
}
+ __asm__("std\n\t"
+ "rep\n\t"
+ "movsl\n\t"
+ "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
+ "movl _video_num_columns,%%ecx\n\t"
+ "rep\n\t"
+ "stosw\n\t"
+ "cld"
+ ::"a" (video_erase_char),
+ "c" ((bottom-top-1)*video_num_columns>>1),
+ "D" (origin+video_size_row*bottom-4),
+ "S" (origin+video_size_row*(bottom-1)-4)
+ :"ax","cx","di","si");
+ bottom = oldbottom;
+ top = oldtop;
}
static void lf(int currcons)
@@ -292,8 +340,8 @@ static void lf(int currcons)
y++;
pos += video_size_row;
return;
- }
- scrup(currcons);
+ } else
+ scrup(currcons);
}
static void ri(int currcons)
@@ -302,8 +350,8 @@ static void ri(int currcons)
y--;
pos -= video_size_row;
return;
- }
- scrdown(currcons);
+ } else
+ scrdown(currcons);
}
static void cr(int currcons)
@@ -323,8 +371,8 @@ static void del(int currcons)
static void csi_J(int currcons, int vpar)
{
- long count __asm__("cx");
- long start __asm__("di");
+ long count;
+ long start;
switch (vpar) {
case 0: /* erase from cursor to end of display */
@@ -352,8 +400,8 @@ static void csi_J(int currcons, int vpar)
static void csi_K(int currcons, int vpar)
{
- long count __asm__("cx");
- long start __asm__("di");
+ long count;
+ long start;
switch (vpar) {
case 0: /* erase from cursor to end of line */
@@ -384,6 +432,7 @@ static void csi_K(int currcons, int vpar)
void csi_m(int currcons )
{
int i;
+ static int conv_table[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
for (i=0;i<=npar;i++)
switch (par[i]) {
@@ -417,11 +466,11 @@ void csi_m(int currcons )
if (!can_do_colour)
break;
iscolor = 1;
- if ((par[i]>=30) && (par[i]<=38))
- attr = (attr & 0xf0) | (par[i]-30);
+ if ((par[i]>=30) && (par[i]<=37))
+ attr = (attr & 0xf0) | conv_table[par[i]-30];
else /* Background color */
- if ((par[i]>=40) && (par[i]<=48))
- attr = (attr & 0x0f) | ((par[i]-40)<<4);
+ if ((par[i]>=40) && (par[i]<=47))
+ attr = (attr & 0x0f) | (conv_table[par[i]-40]<<4);
else
break;
}
@@ -429,7 +478,6 @@ void csi_m(int currcons )
static inline void set_cursor(int currcons)
{
- blankcount = blankinterval;
if (currcons != fg_console)
return;
cli();
@@ -569,19 +617,21 @@ static void restore_cur(int currcons)
enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
- ESsetterm, ESsetgraph };
+ ESsetterm, ESsetgraph, ESgraph, ESgresc, ESignore };
void con_write(struct tty_struct * tty)
{
int nr;
char c;
int currcons;
-
+
+ wake_up(&tty->write_q->proc_list);
currcons = tty - tty_table;
- if ((currcons>=MAX_CONSOLES) || (currcons<0))
- panic("con_write: illegal tty");
-
- nr = CHARS(tty->write_q);
+ if ((currcons>=MAX_CONSOLES) || (currcons<0)) {
+ printk("con_write: illegal tty\n\r");
+ return;
+ }
+ nr = CHARS(tty->write_q);
while (nr--) {
if (tty->stopped)
break;
@@ -596,21 +646,18 @@ void con_write(struct tty_struct * tty)
pos -= video_size_row;
lf(currcons);
}
- __asm__("movb %2,%%ah\n\t"
- "movw %%ax,%1\n\t"
- ::"a" (translate[c-32]),
- "m" (*(short *)pos),
- "m" (attr)
- :"ax");
- pos += 2;
+ *(char *) pos = translate[c-32];
+ pos++;
+ *(char *) pos = attr;
+ pos++;
x++;
} else if (c==27)
- state=ESesc;
+ state = ESesc;
else if (c==10 || c==11 || c==12)
lf(currcons);
else if (c==13)
cr(currcons);
- else if (c==ERASE_CHAR(tty))
+ else if (c==127)
del(currcons);
else if (c==8) {
if (x) {
@@ -618,7 +665,7 @@ void con_write(struct tty_struct * tty)
pos -= 2;
}
} else if (c==9) {
- c=8-(x&7);
+ c = 8-(x&7);
x += c;
pos += c<<1;
if (x>video_num_columns) {
@@ -629,17 +676,19 @@ void con_write(struct tty_struct * tty)
c=9;
} else if (c==7)
sysbeep();
- else if (c == 14)
- translate = GRAF_TRANS;
- else if (c == 15)
+ else if (c == 14) {
+ checkin = 1;
+ translate = restate;
+ } else if (c == 15) {
translate = NORM_TRANS;
+ checkin = 0;
+ }
break;
case ESesc:
state = ESnormal;
- switch (c)
- {
+ switch (c) {
case '[':
- state=ESsquare;
+ state = ESsquare;
break;
case 'E':
gotoxy(currcons,0,y+1);
@@ -659,7 +708,8 @@ void con_write(struct tty_struct * tty)
case '8':
restore_cur(currcons);
break;
- case '(': case ')':
+ case '(':
+ case ')':
state = ESsetgraph;
break;
case 'P':
@@ -670,23 +720,32 @@ void con_write(struct tty_struct * tty)
break;
case 'c':
tty->termios = DEF_TERMIOS;
- state = restate = ESnormal;
+ state = ESnormal;
+ restate = NORM_TRANS;
checkin = 0;
top = 0;
bottom = video_num_lines;
- break;
- /* case '>': Numeric keypad */
- /* case '=': Appl. keypad */
+ translate = NORM_TRANS;
+ case '>': /* Numeric keypad */
+ kbdapplic = 0;
+ if (currcons == fg_console)
+ kapplic = 0;
+ break;
+ case '=': /* Appl. keypad */
+ kbdapplic = 1;
+ if (currcons == fg_console)
+ kapplic = 1;
+ break;
}
break;
case ESsquare:
- for(npar=0;npar<NPAR;npar++)
+ for(npar = 0 ; npar < NPAR ; npar++)
par[npar]=0;
- npar=0;
- state=ESgetpars;
- if (c =='[') /* Function key */
- { state=ESfunckey;
- break;
+ npar = 0;
+ state = ESgetpars;
+ if (c == '[') { /* Function key */
+ state=ESfunckey;
+ break;
}
if (ques=(c=='?'))
break;
@@ -700,9 +759,9 @@ void con_write(struct tty_struct * tty)
} else state=ESgotpars;
case ESgotpars:
state = ESnormal;
- if (ques)
- { ques =0;
- break;
+ if (ques) {
+ ques = 0;
+ break;
}
switch(c) {
case 'G': case '`':
@@ -784,10 +843,8 @@ void con_write(struct tty_struct * tty)
((par[1]-13) == par[0]) &&
((par[2]-17) == par[0])))
break;
- if ((c=='l')&&(par[0]>=0)&&(par[0]<=60))
- {
+ if ((c=='l') && (par[0]<=60)) {
blankinterval = HZ*60*par[0];
- blankcount = blankinterval;
}
if (c=='b')
vc_cons[currcons].vc_bold_attr
@@ -803,22 +860,55 @@ void con_write(struct tty_struct * tty)
def_attr = attr;
video_erase_char = (video_erase_char&0x0ff) | (def_attr<<8);
} else if (c == 'L')
- ; /*linewrap on*/
+ /*linewrap on*/;
else if (c == 'l')
- ; /*linewrap off*/
+ /*linewrap off*/;
break;
case ESsetgraph:
+ if (c == '0') {
+ if (checkin)
+ translate = GRAF_TRANS;
+ restate = GRAF_TRANS;
+ } else if (c == 'B')
+ translate = restate = NORM_TRANS;
state = ESnormal;
- if (c == '0')
- translate = GRAF_TRANS;
- else if (c == 'B')
- translate = NORM_TRANS;
break;
default:
state = ESnormal;
}
}
set_cursor(currcons);
+ timer_active &= ~(1<<BLANK_TIMER);
+ if (console_blanked) {
+ timer_table[BLANK_TIMER].expires = 0;
+ timer_active |= 1<<BLANK_TIMER;
+ } else if (blankinterval) {
+ timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
+ timer_active |= 1<<BLANK_TIMER;
+ }
+}
+
+void do_keyboard_interrupt(void)
+{
+ copy_to_cooked(TTY_TABLE(0));
+ timer_active &= ~(1<<BLANK_TIMER);
+ if (console_blanked) {
+ timer_table[BLANK_TIMER].expires = 0;
+ timer_active |= 1<<BLANK_TIMER;
+ } else if (blankinterval) {
+ timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
+ timer_active |= 1<<BLANK_TIMER;
+ }
+}
+
+void * memsetw(void * s,unsigned short c,int count)
+{
+__asm__("cld\n\t"
+ "rep\n\t"
+ "stosw"
+ ::"a" (c),"D" (s),"c" (count)
+ :"cx","di");
+return s;
}
/*
@@ -839,13 +929,19 @@ void con_init(void)
int currcons = 0;
long base, term;
long video_memory;
+ long saveterm, savebase;
video_num_columns = ORIG_VIDEO_COLS;
video_size_row = video_num_columns * 2;
video_num_lines = ORIG_VIDEO_LINES;
video_page = ORIG_VIDEO_PAGE;
video_erase_char = 0x0720;
- blankcount = blankinterval;
+ timer_table[BLANK_TIMER].fn = blank_screen;
+ timer_table[BLANK_TIMER].expires = 0;
+ if (blankinterval) {
+ timer_table[BLANK_TIMER].expires = jiffies+blankinterval;
+ timer_active |= 1<<BLANK_TIMER;
+ }
if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
{
@@ -884,14 +980,7 @@ void con_init(void)
display_desc = "*CGA";
}
}
- video_memory = video_mem_term - video_mem_base;
- NR_CONSOLES = video_memory / (video_num_lines * video_size_row);
- if (NR_CONSOLES > MAX_CONSOLES)
- NR_CONSOLES = MAX_CONSOLES;
- if (!NR_CONSOLES)
- NR_CONSOLES = 1;
- video_memory /= NR_CONSOLES;
-
+
/* Let the user known what kind of display driver we are using */
display_ptr = ((char *)video_mem_base) + video_size_row - 8;
@@ -901,20 +990,38 @@ void con_init(void)
display_ptr++;
}
+ savebase = video_mem_base;
+ saveterm = video_mem_term;
+ memsetw(vc_scrmembuf,video_erase_char,MEM_BUFFER_SIZE/2);
+ video_mem_base = (long)vc_scrmembuf;
+ video_mem_term = (long)&(vc_scrmembuf[MEM_BUFFER_SIZE/2]);
+ video_memory = video_mem_term - video_mem_base;
+ screen_size = (video_num_lines * video_size_row);
+ NR_CONSOLES = video_memory / screen_size;
+ if (NR_CONSOLES > MAX_CONSOLES)
+ NR_CONSOLES = MAX_CONSOLES;
+ if (!NR_CONSOLES)
+ NR_CONSOLES = 1;
+ video_memory = screen_size;
+
/* Initialize the variables used for scrolling (mostly EGA/VGA) */
base = origin = video_mem_start = video_mem_base;
term = video_mem_end = base + video_memory;
- scr_end = video_mem_start + video_num_lines * video_size_row;
+ scr_end = video_mem_start + screen_size;
top = 0;
bottom = video_num_lines;
attr = 0x07;
def_attr = 0x07;
- restate = state = ESnormal;
+ restate = NORM_TRANS;
+ state = ESnormal;
checkin = 0;
ques = 0;
iscolor = 0;
translate = NORM_TRANS;
+ kbdleds = 2;
+ kbdmode = 0;
+ kbdapplic = 0;
vc_cons[0].vc_bold_attr = -1;
gotoxy(currcons,ORIG_X,ORIG_Y);
@@ -925,7 +1032,20 @@ void con_init(void)
video_mem_end = (term += video_memory);
gotoxy(currcons,0,0);
}
- update_screen();
+ for (currcons = 0; currcons<NR_CONSOLES; currcons++)
+ vc_scrbuf[currcons] = (unsigned short *)origin;
+ currcons = 0;
+ video_mem_base = savebase;
+ video_mem_term = saveterm;
+
+ video_mem_start = video_mem_base;
+ video_mem_end = video_mem_term;
+ origin = video_mem_start;
+ scr_end = video_mem_start + video_num_lines * video_size_row;
+ top = 0;
+ bottom = video_num_lines;
+ pos=origin + y*video_size_row + (x<<1);
+ update_screen(fg_console);
set_trap_gate(0x21,&keyboard_interrupt);
outb_p(inb_p(0x21)&0xfd,0x21);
a=inb_p(0x61);
@@ -933,22 +1053,88 @@ void con_init(void)
outb_p(a,0x61);
}
-void update_screen(void)
+void kbdsave(int new_console)
+{
+ int currcons = fg_console;
+ kbdmode = kmode;
+ kbdleds = kleds;
+ kbdapplic = kapplic;
+ currcons = new_console;
+ kmode = (kmode & 0x3F) | (kbdmode & 0xC0);
+ kleds = kbdleds;
+ kapplic = kbdapplic;
+ set_leds();
+}
+
+static void get_scrmem(int currcons)
+{
+ memcpy((void *)vc_scrbuf[fg_console],(void *)origin, screen_size);
+ video_mem_start = (unsigned long)vc_scrbuf[fg_console];
+ origin = video_mem_start;
+ scr_end = video_mem_end = video_mem_start+screen_size;
+ top = 0;
+ pos = origin + y*video_size_row + (x<<1);
+ bottom = video_num_lines;
+}
+
+static void set_scrmem(int currcons)
+{
+ video_mem_start = video_mem_base;
+ video_mem_end = video_mem_term;
+ origin = video_mem_start;
+ scr_end = video_mem_start + screen_size;
+ top = 0;
+ bottom = video_num_lines;
+ pos = origin + y*video_size_row + (x<<1);
+ memcpy((void *)video_mem_base, (void *)vc_scrbuf[fg_console], screen_size);
+}
+
+void blank_screen(void)
+{
+ timer_table[BLANK_TIMER].fn = unblank_screen;
+ get_scrmem(fg_console);
+ hide_cursor(fg_console);
+ console_blanked = 1;
+ memsetw((void *)video_mem_base, 0x0020, video_mem_term-video_mem_base );
+}
+
+void unblank_screen(void)
{
+ timer_table[BLANK_TIMER].fn = blank_screen;
+ if (blankinterval) {
+ timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
+ timer_active |= 1<<BLANK_TIMER;
+ }
+ console_blanked = 0;
+ set_scrmem(fg_console);
set_origin(fg_console);
set_cursor(fg_console);
}
+void update_screen(int new_console)
+{
+ static int lock = 0;
+
+ if (new_console == fg_console || lock)
+ return;
+ lock = 1;
+ kbdsave(new_console);
+ get_scrmem(fg_console);
+ fg_console = new_console;
+ set_scrmem(fg_console);
+ set_origin(fg_console);
+ set_cursor(new_console);
+ lock = 0;
+}
+
/* from bsd-net-2: */
-void sysbeepstop(void)
+static void sysbeepstop(void)
{
/* disable counter 2 */
outb(inb_p(0x61)&0xFC, 0x61);
}
-int beepcount = 0;
-
static void sysbeep(void)
{
/* enable counter 2 */
@@ -959,7 +1145,9 @@ static void sysbeep(void)
outb_p(0x37, 0x42);
outb(0x06, 0x42);
/* 1/8 second */
- beepcount = HZ/8;
+ timer_table[BEEP_TIMER].expires = jiffies + HZ/8;
+ timer_table[BEEP_TIMER].fn = sysbeepstop;
+ timer_active |= 1<<BEEP_TIMER;
}
int do_screendump(int arg)
@@ -967,36 +1155,26 @@ int do_screendump(int arg)
char *sptr, *buf = (char *)arg;
int currcons, l;
- verify_area(buf,video_num_columns*video_num_lines);
- currcons = get_fs_byte(buf);
- if ((currcons<1) || (currcons>NR_CONSOLES))
+ verify_area(buf,2+video_num_columns*video_num_lines);
+ currcons = get_fs_byte(buf+1);
+ if ((currcons<0) || (currcons>NR_CONSOLES))
return -EIO;
- currcons--;
+ put_fs_byte((char)(video_num_lines),buf++);
+ put_fs_byte((char)(video_num_columns),buf++);
+ currcons = (currcons ? currcons-1 : fg_console);
sptr = (char *) origin;
- for (l=video_num_lines*video_num_columns; l>0 ; l--)
+ for (l=video_num_lines*video_num_columns; l>0 ; l--, sptr++)
put_fs_byte(*sptr++,buf++);
return(0);
}
-void blank_screen()
-{
- if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
- return;
-/* blank here. I can't find out how to do it, though */
-}
-
-void unblank_screen()
-{
- if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
- return;
-/* unblank here */
-}
-
void console_print(const char * b)
{
int currcons = fg_console;
char c;
+ if (currcons<0 || currcons>=NR_CONSOLES)
+ currcons = 0;
while (c = *(b++)) {
if (c == 10) {
cr(currcons);
@@ -1012,13 +1190,10 @@ void console_print(const char * b)
pos -= video_size_row;
lf(currcons);
}
- __asm__("movb %2,%%ah\n\t"
- "movw %%ax,%1\n\t"
- ::"a" (c),
- "m" (*(short *)pos),
- "m" (attr)
- :"ax");
- pos += 2;
+ *(char *) pos = c;
+ pos++;
+ *(char *) pos = attr;
+ pos++;
x++;
}
set_cursor(currcons);
diff --git a/kernel/chr_drv/keyboard.S b/kernel/chr_drv/keyboard.S
index 5995738..0177e06 100644
--- a/kernel/chr_drv/keyboard.S
+++ b/kernel/chr_drv/keyboard.S
@@ -8,17 +8,26 @@
* Thanks to Alfred Leung for US keyboard patches
* Wolfgang Thiel for German keyboard patches
* Marc Corsini for the French keyboard
+ * LeBlanc@mcc.ac.uk for the UK keyboard
+ * Tommy Thorn (tthorn@daimi.aau.dk) for Danish keyboard
*/
/* KBD_FINNISH for Finnish keyboards
* KBD_US for US-type
* KBD_GR for German keyboards
* KBD_FR for Frech keyboard
+ * KBD_UK for British extended keyboard
+ * KBD_DK for Danish keyboard
*/
#define KBD_FINNISH
.text
+.globl _hard_reset_now
.globl _keyboard_interrupt
+.globl _kapplic
+.globl _kmode
+.globl _kleds
+.globl _set_leds
/*
* these are for the keyboard read functions
@@ -30,8 +39,9 @@ tail = 8
proc_list = 12
buf = 16
-mode: .byte 0 /* caps, alt, ctrl and shift mode */
-leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */
+_kapplic: .byte 0
+_kmode: .byte 0 /* caps, alt, ctrl and shift mode */
+_kleds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */
e0: .byte 0
/*
@@ -40,6 +50,7 @@ e0: .byte 0
* ascii character(s).
*/
_keyboard_interrupt:
+ cld
pushl %eax
pushl %ebx
pushl %ecx
@@ -49,17 +60,10 @@ _keyboard_interrupt:
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
- movl _blankinterval,%eax
- movl %eax,_blankcount
xorl %eax,%eax /* %eax is scan code */
inb $0x60,%al
- cmpb $0xe0,%al
- je set_e0
- cmpb $0xe1,%al
- je set_e1
- call key_table(,%eax,4)
- movb $0,e0
-e0_e1: inb $0x61,%al
+ pushl %eax
+ inb $0x61,%al
jmp 1f
1: jmp 1f
1: orb $0x80,%al
@@ -70,11 +74,23 @@ e0_e1: inb $0x61,%al
1: jmp 1f
1: andb $0x7F,%al
outb %al,$0x61
- movb $0x20,%al
+ jmp 1f
+1: jmp 1f
+1: movb $0x20,%al
outb %al,$0x20
- pushl $0
- call _do_tty_interrupt
- addl $4,%esp
+ popl %eax
+ movl $1,%ebx
+ cmpb $0xE0,%al
+ je end_intr
+ movl $2,%ebx
+ cmpb $0xE1,%al
+ je end_intr
+ sti
+ call key_table(,%eax,4)
+ call _do_keyboard_interrupt
+ movl $0,%ebx
+end_intr:
+ movb %bl,e0
pop %es
pop %ds
popl %edx
@@ -82,10 +98,6 @@ e0_e1: inb $0x61,%al
popl %ebx
popl %eax
iret
-set_e0: movb $1,e0
- jmp e0_e1
-set_e1: movb $2,e0
- jmp e0_e1
/*
* This routine fills the buffer with max 8 bytes, taken from
@@ -121,7 +133,7 @@ alt: movb $0x10,%al
1: cmpb $0,e0
je 2f
addb %al,%al
-2: orb %al,mode
+2: orb %al,_kmode
ret
unctrl: movb $0x04,%al
jmp 1f
@@ -130,50 +142,68 @@ unalt: movb $0x10,%al
je 2f
addb %al,%al
2: notb %al
- andb %al,mode
+ andb %al,_kmode
ret
lshift:
- orb $0x01,mode
+ orb $0x01,_kmode
ret
unlshift:
- andb $0xfe,mode
+ andb $0xfe,_kmode
ret
rshift:
- orb $0x02,mode
+ orb $0x02,_kmode
ret
unrshift:
- andb $0xfd,mode
+ andb $0xfd,_kmode
ret
-caps: testb $0x80,mode
+old_leds:
+ .byte 2
+
+caps: testb $0x80,_kmode
jne 1f
- xorb $4,leds
- xorb $0x40,mode
- orb $0x80,mode
-set_leds:
+ xorb $4,_kleds
+ xorb $0x40,_kmode
+ orb $0x80,_kmode
+_set_leds:
+ movb _kleds,%al
+ cmpb old_leds,%al
+ je 1f
+ movb %al,old_leds
call kb_wait
movb $0xed,%al /* set leds command */
outb %al,$0x60
call kb_wait
- movb leds,%al
+ movb _kleds,%al
outb %al,$0x60
- ret
-uncaps: andb $0x7f,mode
+1: ret
+uncaps: andb $0x7f,_kmode
ret
scroll:
- testb $0x03,mode
+ testb $0x03,_kmode
je 1f
call _show_mem
jmp 2f
1: call _show_state
-2: xorb $1,leds
- jmp set_leds
-num: xorb $2,leds
- jmp set_leds
+2: xorb $1,_kleds
+ jmp _set_leds
+
+num: cmpb $0x01,_kapplic
+ jne notappl
+ movw $0x0050,%ax
+applkey:
+ shll $16,%eax
+ movw $0x4f1b,%ax
+ xorl %ebx,%ebx
+ jmp put_queue
+
+notappl:
+ xorb $2,_kleds
+ jmp _set_leds
/*
- * curosr-key/numeric keypad cursor keys are handled here.
+ * cursor-key/numeric keypad cursor keys are handled here.
* checking for numeric keypad etc.
*/
cursor:
@@ -182,21 +212,29 @@ cursor:
cmpb $12,%al
ja 1f
jne cur2 /* check for ctrl-alt-del */
- testb $0x0c,mode
+ testb $0x0c,_kmode
je cur2
- testb $0x30,mode
- jne reboot
+ testb $0x30,_kmode
+ jne _ctrl_alt_del
cur2: cmpb $0x01,e0 /* e0 forces cursor movement */
je cur
- testb $0x02,leds /* not num-lock forces cursor */
- je cur
- testb $0x03,mode /* shift forces cursor */
+ testb $0x03,_kmode /* shift forces cursor */
jne cur
+ cmpb $0x01,_kapplic
+ jne notcappl
+ movb appl_table(%eax),%al
+ jmp applkey
+notcappl:
+ testb $0x02,_kleds /* not num-lock forces cursor */
+ je cur
xorl %ebx,%ebx
movb num_table(%eax),%al
jmp put_queue
1: ret
+/*
+ * cursor keys send ^[ [ x if normal, ^[ O x if application mode
+ */
cur: movb cur_table(%eax),%al
cmpb $'9,%al
ja ok_cur
@@ -204,17 +242,42 @@ cur: movb cur_table(%eax),%al
ok_cur: shll $16,%eax
movw $0x5b1b,%ax
xorl %ebx,%ebx
+ cmpb $0x01,_kapplic
+ jne put_queue
+ movb $0x4f,%ah
jmp put_queue
-#if defined(KBD_FR)
+#if defined(KBD_FR) /* || defined(KBD_DK) correct, but .. */
num_table:
- .ascii "789 456 1230."
+ .ascii "789-456+1230."
#else
num_table:
- .ascii "789 456 1230,"
+ .ascii "789-456+1230,"
#endif
cur_table:
- .ascii "HA5 DGC YB623"
+ .ascii "HA5-DGC+YB623"
+
+/*
+ Keypad / 35 B7 Q
+ Keypad * (PrtSc) 37 B7 R
+ Keypad NumLock 45 ?? P
+ Keypad 7 (Home) 47 C7 w
+ Keypad 8 (Up arrow) 48 C8 x
+ Keypad 9 (PgUp) 49 C9 y
+ Keypad - 4A CA S
+ Keypad 4 (Left arrow) 4B CB t
+ Keypad 5 4C CC u
+ Keypad 6 (Right arrow) 4D CD v
+ Keypad + 4E CE l
+ Keypad 1 (End) 4F CF q
+ Keypad 2 (Down arrow) 50 D0 r
+ Keypad 3 (PgDn) 51 D1 s
+ Keypad 0 (Ins) 52 D2 p
+ Keypad . (Del) 53 D3 n
+*/
+
+appl_table:
+ .ascii "wxyStuvlqrspn"
/*
* this routine handles function keys
@@ -230,7 +293,7 @@ func:
cmpb $11,%al
ja end_func
ok_func:
- testb $0x10,mode
+ testb $0x10,_kmode
jne alt_func
cmpl $4,%ecx /* check that there is enough room */
jl end_func
@@ -319,7 +382,6 @@ key_map:
.byte '<
.fill 10,1,0
-
shift_map:
.byte 0,27
.ascii "!@#$%^&*()_+"
@@ -352,6 +414,56 @@ alt_map:
.byte '|
.fill 10,1,0
+#elif defined(KBD_UK)
+
+key_map:
+ .byte 0,27
+ .ascii "1234567890-="
+ .byte 127,9
+ .ascii "qwertyuiop[]"
+ .byte 13,0
+ .ascii "asdfghjkl;'"
+ .byte '`,0
+ .ascii "#zxcvbnm,./"
+ .byte 0,'*,0,32 /* 36-39 */
+ .fill 16,1,0 /* 3A-49 */
+ .byte '-,0,0,0,'+ /* 4A-4E */
+ .byte 0,0,0,0,0,0,0 /* 4F-55 */
+ .ascii "\\"
+ .fill 10,1,0
+
+shift_map:
+ .byte 0,27
+ .ascii "!\"#$%%&*()_+"
+ .byte 127,9
+ .ascii "QWERTYUIOP{}"
+ .byte 13,0
+ .ascii "ASDFGHJKL:@"
+ .byte '~,0
+ .ascii "~ZXCVBNM<>?"
+ .byte 0,'*,0,32 /* 36-39 */
+ .fill 16,1,0 /* 3A-49 */
+ .byte '-,0,0,0,'+ /* 4A-4E */
+ .byte 0,0,0,0,0,0,0 /* 4F-55 */
+ .byte '|
+ .fill 10,1,0
+
+alt_map:
+ .byte 0,0
+ .ascii "\0@\0$\0\0{[]}\\\0"
+ .byte 0,0
+ .byte 0,0,0,0,0,0,0,0,0,0,0
+ .byte '~,13,0
+ .byte 0,0,0,0,0,0,0,0,0,0,0
+ .byte 0,0
+ .byte 0,0,0,0,0,0,0,0,0,0,0
+ .byte 0,0,0,0 /* 36-39 */
+ .fill 16,1,0 /* 3A-49 */
+ .byte 0,0,0,0,0 /* 4A-4E */
+ .byte 0,0,0,0,0,0,0 /* 4F-55 */
+ .byte '|
+ .fill 10,1,0
+
#elif defined(KBD_GR)
key_map:
@@ -370,7 +482,6 @@ key_map:
.byte '<
.fill 10,1,0
-
shift_map:
.byte 0,27
.ascii "!\"#$%&/()=?`"
@@ -403,7 +514,6 @@ alt_map:
.byte '|
.fill 10,1,0
-
#elif defined(KBD_FR)
key_map:
@@ -454,6 +564,56 @@ alt_map:
.byte '|
.fill 10,1,0
+#elif defined(KBD_DK)
+
+key_map:
+ .byte 0,27
+ .ascii "1234567890+'"
+ .byte 127,9
+ .ascii "qwertyuiop"
+ .byte 134,0,13,0 /* This is IBM-PC, change it to latin-1 */
+ .ascii "asdfghjkl"
+ .byte 145,155,0,0
+ .ascii "'zxcvbnm,.-"
+ .byte 0,'*,0,32 /* 36-39 */
+ .fill 16,1,0 /* 3A-49 */
+ .byte '-,0,0,0,'+ /* 4A-4E */
+ .byte 0,0,0,0,0,0,0 /* 4F-55 */
+ .byte '<
+ .fill 10,1,0
+
+shift_map:
+ .byte 0,27
+ .ascii "!\"#$%&/()=?`"
+ .byte 127,9
+ .ascii "QWERTYUIOP"
+ .byte 143,94,13,0
+ .ascii "ASDFGHJKL"
+ .byte 146,157,0,0
+ .ascii "*ZXCVBNM;:_"
+ .byte 0,'*,0,32 /* 36-39 */
+ .fill 16,1,0 /* 3A-49 */
+ .byte '-,0,0,0,'+ /* 4A-4E */
+ .byte 0,0,0,0,0,0,0 /* 4F-55 */
+ .byte '>
+ .fill 10,1,0
+
+alt_map:
+ .byte 0,0
+ .ascii "\0@\0$\0\0{[]}\0"
+ .byte '|,0,0
+ .byte 0,0,0,0,0,0,0,0,0,0,0
+ .byte '~,13,0
+ .byte 0,0,0,0,0,0,0,0,0,0,0
+ .byte 0,0
+ .byte 0,0,0,0,0,0,0,0,0,0,0
+ .byte 0,0,0,0 /* 36-39 */
+ .fill 16,1,0 /* 3A-49 */
+ .byte 0,0,0,0,0 /* 4A-4E */
+ .byte 0,0,0,0,0,0,0 /* 4F-55 */
+ .ascii "\\"
+ .fill 10,1,0
+
#else
#error "KBD-type not defined"
#endif
@@ -463,30 +623,30 @@ alt_map:
*/
do_self:
lea alt_map,%ebx
- testb $0x20,mode /* alt-gr */
+ testb $0x20,_kmode /* alt-gr */
jne 1f
lea shift_map,%ebx
- testb $0x03,mode
+ testb $0x03,_kmode
jne 1f
lea key_map,%ebx
1: movb (%ebx,%eax),%al
orb %al,%al
je none
- testb $0x4c,mode /* ctrl or caps */
+ testb $0x4c,_kmode /* ctrl or caps */
je 2f
cmpb $'a,%al
jb 2f
cmpb $'},%al
ja 2f
subb $32,%al
-2: testb $0x0c,mode /* ctrl */
+2: testb $0x0c,_kmode /* ctrl */
je 3f
cmpb $64,%al
jb 3f
cmpb $64+32,%al
jae 3f
subb $64,%al
-3: testb $0x10,mode /* left alt */
+3: testb $0x10,_kmode /* left alt */
je 4f
orb $0x80,%al
4: andl $0xff,%eax
@@ -495,16 +655,49 @@ do_self:
none: ret
/*
- * minus has a routine of it's own, as a 'E0h' before
- * the scan code for minus means that the numeric keypad
+ * slash and star have routines of their own, as a 'E0h' before
+ * the scan code for slash means that the numeric keypad
* slash was pushed.
*/
-minus: cmpb $1,e0
+slash: cmpb $1,e0
jne do_self
+ cmpb $1,_kapplic
+ jne notmapplic
+ movw $'Q,%ax
+ jmp applkey
+
+notmapplic:
movl $'/,%eax
xorl %ebx,%ebx
jmp put_queue
+star: cmpb $1,_kapplic
+ jne do_self
+ movw $'R,%ax
+ jmp applkey
+
+notsapplic:
+ movl $'*,%eax
+ xorl %ebx,%ebx
+ jmp put_queue
+
+enter: cmpb $1,e0
+ jne do_self
+ cmpb $1,_kapplic
+ jne do_self
+ movw $'M,%ax
+ jmp applkey
+
+minus: cmpb $1,_kapplic
+ jne do_self
+ movw $'S,%ax
+ jmp applkey
+
+plus: cmpb $1,_kapplic
+ jne do_self
+ movw $'l,%ax
+ jmp applkey
+
/*
* This table decides which routine to call when a scan-code has been
* gotten. Most routines just call do_self, or none, depending if
@@ -518,19 +711,19 @@ key_table:
.long do_self,do_self,do_self,do_self /* 10-13 q w e r */
.long do_self,do_self,do_self,do_self /* 14-17 t y u i */
.long do_self,do_self,do_self,do_self /* 18-1B o p } ^ */
- .long do_self,ctrl,do_self,do_self /* 1C-1F enter ctrl a s */
+ .long enter,ctrl,do_self,do_self /* 1C-1F enter ctrl a s */
.long do_self,do_self,do_self,do_self /* 20-23 d f g h */
.long do_self,do_self,do_self,do_self /* 24-27 j k l | */
.long do_self,do_self,lshift,do_self /* 28-2B { para lshift , */
.long do_self,do_self,do_self,do_self /* 2C-2F z x c v */
.long do_self,do_self,do_self,do_self /* 30-33 b n m , */
- .long do_self,minus,rshift,do_self /* 34-37 . - rshift * */
+ .long do_self,slash,rshift,star /* 34-37 . - rshift * */
.long alt,do_self,caps,func /* 38-3B alt sp caps f1 */
.long func,func,func,func /* 3C-3F f2 f3 f4 f5 */
.long func,func,func,func /* 40-43 f6 f7 f8 f9 */
.long func,num,scroll,cursor /* 44-47 f10 num scr home */
- .long cursor,cursor,do_self,cursor /* 48-4B up pgup - left */
- .long cursor,cursor,do_self,cursor /* 4C-4F n5 right + end */
+ .long cursor,cursor,minus,cursor /* 48-4B up pgup - left */
+ .long cursor,cursor,plus,cursor /* 4C-4F n5 right + end */
.long cursor,cursor,cursor,cursor /* 50-53 dn pgdn ins del */
.long none,none,do_self,func /* 54-57 sysreq ? < f11 */
.long func,none,none,none /* 58-5B f12 ? ? ? */
@@ -578,22 +771,35 @@ key_table:
/*
* kb_wait waits for the keyboard controller buffer to empty.
- * there is no timeout - if the buffer doesn't empty, we hang.
*/
kb_wait:
pushl %eax
+ pushl %ebx
+ movl $10000,%ebx
1: inb $0x64,%al
testb $0x02,%al
+ je 2f
+ decl %ebx
jne 1b
+2: popl %ebx
popl %eax
ret
+
+no_idt:
+ .long 0,0
/*
* This routine reboots the machine by asking the keyboard
- * controller to pulse the reset-line low.
+ * controller to pulse the reset-line low. We try that for a while,
+ * and if it doesn't work, we do some other stupid things.
*/
-reboot:
- call kb_wait
+_hard_reset_now:
+ sti
+ movl $100,%ebx
+1: call kb_wait
movw $0x1234,0x472 /* don't do memory check */
- movb $0xfc,%al /* pulse reset and A20 low */
+ movb $0xfe,%al /* pulse reset low */
outb %al,$0x64
-die: jmp die
+ decl %ebx
+ jne 1b
+ lidt no_idt /* zero-length idt: should triple-fault */
+ jmp _hard_reset_now
diff --git a/kernel/chr_drv/rs_io.s b/kernel/chr_drv/rs_io.s
index 67baadb..f147cec 100644
--- a/kernel/chr_drv/rs_io.s
+++ b/kernel/chr_drv/rs_io.s
@@ -38,6 +38,7 @@ _rs1_interrupt:
_rs2_interrupt:
pushl $_table_list+16
rs_int:
+ cld
pushl %edx
pushl %ecx
pushl %ebx
@@ -105,13 +106,15 @@ read_char:
cmpl tail(%ecx),%ebx
je 1f
movl %ebx,head(%ecx)
-1: addl $63,%edx
- pushl %edx
- call _do_tty_interrupt
- addl $4,%esp
+1: movl mask_table(,%edx,4),%edx
+ orl %edx,_timer_active
ret
.align 2
+mask_table:
+ .long 0,4,8
+
+.align 2
write_char:
movl 4(%ecx),%ecx # write-queue
movl head(%ecx),%ebx
diff --git a/kernel/chr_drv/serial.c b/kernel/chr_drv/serial.c
index a78b1e5..2334e50 100644
--- a/kernel/chr_drv/serial.c
+++ b/kernel/chr_drv/serial.c
@@ -15,6 +15,7 @@
#include <linux/tty.h>
#include <linux/sched.h>
+#include <linux/timer.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -23,6 +24,48 @@
extern void rs1_interrupt(void);
extern void rs2_interrupt(void);
+static void com1_timer(void)
+{
+ copy_to_cooked(tty_table+64);
+}
+
+static void com2_timer(void)
+{
+ copy_to_cooked(tty_table+65);
+}
+
+static inline void do_rs_write(unsigned int port)
+{
+ char c;
+
+#define TTY (tty_table[64+port].write_q)
+#define TIMER (SER1_TIMEOUT+port)
+ cli();
+ if (!EMPTY(TTY)) {
+ outb_p(inb_p(TTY->data+1)|0x02,TTY->data+1);
+ if (inb(TTY->data+5) & 0x20) {
+ GETCH(TTY,c);
+ outb(c,TTY->data);
+ }
+ timer_table[TIMER].expires = jiffies + 50;
+ timer_active |= 1 << TIMER;
+ } else
+ timer_active &= ~(1 << TIMER);
+ sti();
+#undef TIMER
+#undef TTY
+}
+
+static void com1_timeout(void)
+{
+ do_rs_write(0);
+}
+
+static void com2_timeout(void)
+{
+ do_rs_write(1);
+}
+
static void init(int port)
{
outb_p(0x80,port+3); /* set DLAB of line control reg */
@@ -36,6 +79,16 @@ static void init(int port)
void rs_init(void)
{
+/* SERx_TIMER timers are used for receiving: timeout is always 0 (immediate) */
+ timer_table[SER1_TIMER].fn = com1_timer;
+ timer_table[SER1_TIMER].expires = 0;
+ timer_table[SER2_TIMER].fn = com2_timer;
+ timer_table[SER2_TIMER].expires = 0;
+/* SERx_TIMEOUT timers are used for writing: prevent serial lockups */
+ timer_table[SER1_TIMEOUT].fn = com1_timeout;
+ timer_table[SER1_TIMEOUT].expires = 0;
+ timer_table[SER2_TIMEOUT].fn = com2_timeout;
+ timer_table[SER2_TIMEOUT].expires = 0;
set_intr_gate(0x24,rs1_interrupt);
set_intr_gate(0x23,rs2_interrupt);
init(tty_table[64].read_q->data);
@@ -54,6 +107,7 @@ void rs_write(struct tty_struct * tty)
{
cli();
if (!EMPTY(tty->write_q))
- outb(inb_p(tty->write_q->data+1)|0x02,tty->write_q->data+1);
+ outb_p(inb_p(tty->write_q->data+1)|0x02,tty->write_q->data+1);
+ timer_active |= 3 << SER1_TIMEOUT;
sti();
}
diff --git a/kernel/chr_drv/tty_io.c b/kernel/chr_drv/tty_io.c
index 6551da1..18ea261 100644
--- a/kernel/chr_drv/tty_io.c
+++ b/kernel/chr_drv/tty_io.c
@@ -15,6 +15,7 @@
#include <errno.h>
#include <signal.h>
#include <unistd.h>
+#include <fcntl.h>
#define ALRMMASK (1<<(SIGALRM-1))
@@ -35,6 +36,7 @@ int is_orphaned_pgrp(int pgrp);
#define L_ECHO(tty) _L_FLAG((tty),ECHO)
#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
+#define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
@@ -88,10 +90,9 @@ void change_console(unsigned int new_console)
{
if (new_console == fg_console || new_console >= NR_CONSOLES)
return;
- fg_console = new_console;
- table_list[0] = con_queues + 0 + fg_console*3;
- table_list[1] = con_queues + 1 + fg_console*3;
- update_screen();
+ table_list[0] = con_queues + 0 + new_console*3;
+ table_list[1] = con_queues + 1 + new_console*3;
+ update_screen(new_console);
}
static void sleep_if_empty(struct tty_queue * queue)
@@ -119,7 +120,7 @@ void wait_for_keypress(void)
void copy_to_cooked(struct tty_struct * tty)
{
- signed char c;
+ unsigned char c;
if (!(tty->read_q || tty->write_q || tty->secondary)) {
printk("copy_to_cooked: missing queues\n\r");
@@ -210,19 +211,17 @@ void copy_to_cooked(struct tty_struct * tty)
if (c==10 || (EOF_CHAR(tty) != _POSIX_VDISABLE &&
c==EOF_CHAR(tty)))
tty->secondary->data++;
- if (L_ECHO(tty)) {
- if (c==10) {
- PUTCH(10,tty->write_q);
- PUTCH(13,tty->write_q);
- } else if (c<32) {
- if (L_ECHOCTL(tty)) {
- PUTCH('^',tty->write_q);
- PUTCH(c+64,tty->write_q);
- }
+ if ((L_ECHO(tty) || L_ECHONL(tty)) && (c==10)) {
+ PUTCH(10,tty->write_q);
+ PUTCH(13,tty->write_q);
+ } else if (L_ECHO(tty)) {
+ if (c<32 && L_ECHOCTL(tty)) {
+ PUTCH('^',tty->write_q);
+ PUTCH(c+64,tty->write_q);
} else
PUTCH(c,tty->write_q);
- tty->write(tty);
}
+ tty->write(tty);
PUTCH(c,tty->secondary);
}
wake_up(&tty->secondary->proc_list);
@@ -258,17 +257,18 @@ int tty_signal(int sig, struct tty_struct *tty)
/* (but restart after we continue) */
}
-int tty_read(unsigned channel, char * buf, int nr)
+int tty_read(unsigned channel, char * buf, int nr, unsigned short flags)
{
struct tty_struct * tty;
struct tty_struct * other_tty = NULL;
- char c, * b=buf;
+ unsigned char c;
+ char * b=buf;
int minimum,time;
if (channel > 255)
return -EIO;
tty = TTY_TABLE(channel);
- if (!(tty->write_q || tty->read_q || tty->secondary))
+ if (!(tty->read_q && tty->secondary))
return -EIO;
if ((current->tty == channel) && (tty->pgrp != current->pgrp))
return(tty_signal(SIGTTIN, tty));
@@ -288,10 +288,13 @@ int tty_read(unsigned channel, char * buf, int nr)
current->timeout = time + jiffies;
time = 0;
}
+ if (flags & O_NONBLOCK)
+ time = current->timeout = 0;
if (minimum>nr)
minimum = nr;
+ copy_to_cooked(tty);
while (nr>0) {
- if (other_tty)
+ if (other_tty && other_tty->write)
other_tty->write(other_tty);
cli();
if (EMPTY(tty->secondary) || (L_CANON(tty) &&
@@ -305,6 +308,7 @@ int tty_read(unsigned channel, char * buf, int nr)
break;
interruptible_sleep_on(&tty->secondary->proc_list);
sti();
+ copy_to_cooked(tty);
continue;
}
sti();
@@ -331,9 +335,13 @@ int tty_read(unsigned channel, char * buf, int nr)
break;
}
current->timeout = 0;
- if ((current->signal & ~current->blocked) && !(b-buf))
+ if (b-buf)
+ return b-buf;
+ if (current->signal & ~current->blocked)
return -ERESTARTSYS;
- return (b-buf);
+ if (flags & O_NONBLOCK)
+ return -EAGAIN;
+ return 0;
}
int tty_write(unsigned channel, char * buf, int nr)
@@ -345,7 +353,7 @@ int tty_write(unsigned channel, char * buf, int nr)
if (channel > 255)
return -EIO;
tty = TTY_TABLE(channel);
- if (!(tty->write_q || tty->read_q || tty->secondary))
+ if (!(tty->write_q && tty->write))
return -EIO;
if (L_TOSTOP(tty) &&
(current->tty == channel) && (tty->pgrp != current->pgrp))
@@ -380,25 +388,6 @@ int tty_write(unsigned channel, char * buf, int nr)
return (b-buf);
}
-/*
- * Jeh, sometimes I really like the 386.
- * This routine is called from an interrupt,
- * and there should be absolutely no problem
- * with sleeping even in an interrupt (I hope).
- * Of course, if somebody proves me wrong, I'll
- * hate intel for all time :-). We'll have to
- * be careful and see to reinstating the interrupt
- * chips before calling this, though.
- *
- * I don't think we sleep here under normal circumstances
- * anyway, which is good, as the task sleeping might be
- * totally innocent.
- */
-void do_tty_interrupt(int tty)
-{
- copy_to_cooked(TTY_TABLE(tty));
-}
-
void chr_dev_init(void)
{
}
@@ -416,7 +405,8 @@ void tty_init(void)
for (i=0 ; i<256 ; i++) {
tty_table[i] = (struct tty_struct) {
{0, 0, 0, 0, 0, INIT_C_CC},
- 0, 0, 0, NULL, NULL, NULL, NULL
+ 0, 0, 0, {0,0,0,0},
+ NULL, NULL, NULL, NULL
};
}
con_init();
@@ -424,13 +414,14 @@ void tty_init(void)
con_table[i] = (struct tty_struct) {
{ICRNL, /* change incoming CR to NL */
OPOST|ONLCR, /* change outgoing NL to CRNL */
- 0,
+ B38400 | CS8,
IXON | ISIG | ICANON | ECHO | ECHOCTL | ECHOKE,
0, /* console termio */
INIT_C_CC},
0, /* initial pgrp */
0, /* initial session */
0, /* initial stopped */
+ {video_num_lines,video_num_columns,0,0},
con_write,
con_queues+0+i*3,con_queues+1+i*3,con_queues+2+i*3
};
@@ -446,6 +437,7 @@ void tty_init(void)
0,
0,
0,
+ {25,80,0,0},
rs_write,
rs_queues+0+i*3,rs_queues+1+i*3,rs_queues+2+i*3
};
@@ -461,6 +453,7 @@ void tty_init(void)
0,
0,
0,
+ {25,80,0,0},
mpty_write,
mpty_queues+0+i*3,mpty_queues+1+i*3,mpty_queues+2+i*3
};
@@ -474,6 +467,7 @@ void tty_init(void)
0,
0,
0,
+ {25,80,0,0},
spty_write,
spty_queues+0+i*3,spty_queues+1+i*3,spty_queues+2+i*3
};
diff --git a/kernel/chr_drv/tty_ioctl.c b/kernel/chr_drv/tty_ioctl.c
index c3ac9a1..a4250d3 100644
--- a/kernel/chr_drv/tty_ioctl.c
+++ b/kernel/chr_drv/tty_ioctl.c
@@ -16,6 +16,8 @@
#include <asm/system.h>
extern int session_of_pgrp(int pgrp);
+extern int do_screendump(int arg);
+extern int kill_pg(int pgrp, int sig, int priv);
extern int tty_signal(int sig, struct tty_struct *tty);
static unsigned short quotient[] = {
@@ -41,9 +43,12 @@ static void change_speed(struct tty_struct * tty)
static void flush(struct tty_queue * queue)
{
- cli();
- queue->head = queue->tail;
- sti();
+ if (queue) {
+ cli();
+ queue->head = queue->tail;
+ sti();
+ wake_up(&queue->proc_list);
+ }
}
static void wait_until_sent(struct tty_struct * tty)
@@ -56,6 +61,34 @@ static void send_break(struct tty_struct * tty)
/* do nothing - not implemented */
}
+static int do_get_ps_info(int arg)
+{
+ struct tstruct {
+ int flag;
+ int present[NR_TASKS];
+ struct task_struct tasks[NR_TASKS];
+ };
+ struct tstruct *ts = (struct tstruct *)arg;
+ struct task_struct **p;
+ char *c, *d;
+ int i, n = 0;
+
+ verify_area((void *)arg, sizeof(struct tstruct));
+
+ for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
+ if (*p)
+ {
+ c = (char *)(*p);
+ d = (char *)(ts->tasks+n);
+ for (i=0 ; i<sizeof(struct task_struct) ; i++)
+ put_fs_byte(*c++, d++);
+ put_fs_long(1, (unsigned long *)(ts->present+n));
+ }
+ else
+ put_fs_long(0, (unsigned long *)(ts->present+n));
+ return(0);
+}
+
static int get_termios(struct tty_struct * tty, struct termios * termios)
{
int i;
@@ -130,31 +163,84 @@ static int set_termio(struct tty_struct * tty, struct termio * termio,
return 0;
}
+static int set_window_size(struct tty_struct * tty, struct winsize * ws)
+{
+ int i,changed;
+ char c, * tmp;
+
+ if (!ws)
+ return -EINVAL;
+ tmp = (char *) &tty->winsize;
+ changed = 0;
+ for (i = 0; i < sizeof (*ws) ; i++,tmp++) {
+ c = get_fs_byte(i + (char *) ws);
+ if (c == *tmp)
+ continue;
+ changed = 1;
+ *tmp = c;
+ }
+ if (changed)
+ kill_pg(tty->pgrp, SIGWINCH, 1);
+ return 0;
+}
+
+static int get_window_size(struct tty_struct * tty, struct winsize * ws)
+{
+ int i;
+ char * tmp;
+
+ if (!ws)
+ return -EINVAL;
+ verify_area(ws, sizeof (*ws));
+ tmp = (char *) ws;
+ for (i = 0; i < sizeof (struct winsize) ; i++,tmp++)
+ put_fs_byte(((char *) &tty->winsize)[i], tmp);
+ return 0;
+}
+
int tty_ioctl(int dev, int cmd, int arg)
{
struct tty_struct * tty;
- int pgrp;
+ struct tty_struct * other_tty;
+ int pgrp;
if (MAJOR(dev) == 5) {
- dev=current->tty;
+ dev = current->tty;
if (dev<0)
- panic("tty_ioctl: dev<0");
+ return -EINVAL;
} else
dev=MINOR(dev);
tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console);
+
+ if (IS_A_PTY(dev))
+ other_tty = tty_table + PTY_OTHER(dev);
+ else
+ other_tty = NULL;
+
+ if (!(tty->write_q && tty->read_q && tty->secondary && tty->write))
+ return -EINVAL;
switch (cmd) {
case TCGETS:
return get_termios(tty,(struct termios *) arg);
case TCSETSF:
- flush(tty->read_q); /* fallthrough */
+ flush(tty->read_q);
+ flush(tty->secondary);
+ if (other_tty)
+ flush(other_tty->write_q);
+ /* fallthrough */
case TCSETSW:
- wait_until_sent(tty); /* fallthrough */
+ wait_until_sent(tty);
+ /* fallthrough */
case TCSETS:
return set_termios(tty,(struct termios *) arg, dev);
case TCGETA:
return get_termio(tty,(struct termio *) arg);
case TCSETAF:
- flush(tty->read_q); /* fallthrough */
+ flush(tty->read_q);
+ flush(tty->secondary);
+ if (other_tty)
+ flush(other_tty->write_q);
+ /* fallthrough */
case TCSETAW:
wait_until_sent(tty); /* fallthrough */
case TCSETA:
@@ -186,13 +272,19 @@ int tty_ioctl(int dev, int cmd, int arg)
}
return -EINVAL; /* not implemented */
case TCFLSH:
- if (arg==0)
+ if (arg==0) {
flush(tty->read_q);
- else if (arg==1)
+ flush(tty->secondary);
+ if (other_tty)
+ flush(other_tty->write_q);
+ } else if (arg==1)
flush(tty->write_q);
else if (arg==2) {
flush(tty->read_q);
+ flush(tty->secondary);
flush(tty->write_q);
+ if (other_tty)
+ flush(other_tty->write_q);
} else
return -EINVAL;
return 0;
@@ -230,9 +322,11 @@ int tty_ioctl(int dev, int cmd, int arg)
case TIOCSTI:
return -EINVAL; /* not implemented */
case TIOCGWINSZ:
- return -EINVAL; /* not implemented */
+ return get_window_size(tty,(struct winsize *) arg);
case TIOCSWINSZ:
- return -EINVAL; /* not implemented */
+ if (other_tty)
+ set_window_size(other_tty,(struct winsize *) arg);
+ return set_window_size(tty,(struct winsize *) arg);
case TIOCMGET:
return -EINVAL; /* not implemented */
case TIOCMBIS:
@@ -245,6 +339,16 @@ int tty_ioctl(int dev, int cmd, int arg)
return -EINVAL; /* not implemented */
case TIOCSSOFTCAR:
return -EINVAL; /* not implemented */
+ case TIOCLINUX:
+ switch (get_fs_byte((char *)arg))
+ {
+ case 0:
+ return do_screendump(arg);
+ case 1:
+ return do_get_ps_info(arg);
+ default:
+ return -EINVAL;
+ }
default:
return -EINVAL;
}
diff --git a/kernel/exit.c b/kernel/exit.c
index 381995b..e81319a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -15,9 +15,46 @@
#include <linux/tty.h>
#include <asm/segment.h>
-int sys_pause(void);
int sys_close(int fd);
+inline int send_sig(long sig,struct task_struct * p,int priv)
+{
+ if (!p || (sig < 0) || (sig > 32))
+ return -EINVAL;
+ if (!priv && (current->euid!=p->euid) && !suser())
+ return -EPERM;
+ if (!sig)
+ return 0;
+ if ((sig == SIGKILL) || (sig == SIGCONT)) {
+ if (p->state == TASK_STOPPED)
+ p->state = TASK_RUNNING;
+ p->exit_code = 0;
+ p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
+ (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );
+ }
+ /* Depends on order SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU */
+ if ((sig >= SIGSTOP) && (sig <= SIGTTOU))
+ p->signal &= ~(1<<(SIGCONT-1));
+ /* Actually deliver the signal */
+ p->signal |= (1<<(sig-1));
+ if (p->flags & PF_PTRACED) {
+ /* save the signal number for wait. */
+ p->exit_code = sig;
+
+ /* we have to make sure the parent is awake. */
+ if (p->p_pptr != NULL && p->p_pptr->state == TASK_INTERRUPTIBLE)
+ p->p_pptr->state = TASK_RUNNING;
+
+ /* we have to make sure that the process stops. */
+ if (p->state == TASK_INTERRUPTIBLE || p->state == TASK_RUNNING)
+ p->state = TASK_STOPPED;
+
+ if (p == current)
+ schedule();
+ }
+ return 0;
+}
+
void release(struct task_struct * p)
{
int i;
@@ -134,30 +171,6 @@ void audit_ptree()
}
#endif /* DEBUG_PROC_TREE */
-static inline int send_sig(long sig,struct task_struct * p,int priv)
-{
- if (!p)
- return -EINVAL;
- if (!priv && (current->euid!=p->euid) && !suser())
- return -EPERM;
- if ((sig == SIGKILL) || (sig == SIGCONT)) {
- if (p->state == TASK_STOPPED)
- p->state = TASK_RUNNING;
- p->exit_code = 0;
- p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
- (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );
- }
- /* If the signal will be ignored, don't even post it */
- if ((int) p->sigaction[sig-1].sa_handler == 1)
- return 0;
- /* Depends on order SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU */
- if ((sig >= SIGSTOP) && (sig <= SIGTTOU))
- p->signal &= ~(1<<(SIGCONT-1));
- /* Actually deliver the signal */
- p->signal |= (1<<(sig-1));
- return 0;
-}
-
int session_of_pgrp(int pgrp)
{
struct task_struct **p;
@@ -174,7 +187,7 @@ int kill_pg(int pgrp, int sig, int priv)
int err,retval = -ESRCH;
int found = 0;
- if (sig<1 || sig>32 || pgrp<=0)
+ if (sig<0 || sig>32 || pgrp<=0)
return -EINVAL;
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if ((*p)->pgrp == pgrp) {
@@ -190,7 +203,7 @@ int kill_proc(int pid, int sig, int priv)
{
struct task_struct **p;
- if (sig<1 || sig>32)
+ if (sig<0 || sig>32)
return -EINVAL;
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if ((*p)->pid == pid)
@@ -296,7 +309,7 @@ volatile void do_exit(long code)
kill_pg(current->pgrp,SIGCONT,1);
}
/* Let father know we died */
- current->p_pptr->signal |= (1<<(SIGCHLD-1));
+ send_sig (SIGCHLD, current->p_pptr, 1);
/*
* This loop does two things:
@@ -308,6 +321,7 @@ volatile void do_exit(long code)
*/
if (p = current->p_cptr) {
while (1) {
+ p->flags &= ~PF_PTRACED;
p->p_pptr = task[1];
if (p->state == TASK_ZOMBIE)
task[1]->signal |= (1<<(SIGCHLD-1));
@@ -373,7 +387,8 @@ int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
struct task_struct *p;
unsigned long oldblocked;
- verify_area(stat_addr,4);
+ if (stat_addr)
+ verify_area(stat_addr,4);
repeat:
flag=0;
for (p = current->p_cptr ; p ; p = p->p_osptr) {
@@ -392,15 +407,17 @@ repeat:
if (!(options & WUNTRACED) ||
!p->exit_code)
continue;
- put_fs_long((p->exit_code << 8) | 0x7f,
- stat_addr);
+ if (stat_addr)
+ put_fs_long((p->exit_code << 8) | 0x7f,
+ stat_addr);
p->exit_code = 0;
return p->pid;
case TASK_ZOMBIE:
current->cutime += p->utime;
current->cstime += p->stime;
flag = p->pid;
- put_fs_long(p->exit_code, stat_addr);
+ if (stat_addr)
+ put_fs_long(p->exit_code, stat_addr);
release(p);
#ifdef DEBUG_PROC_TREE
audit_ptree();
diff --git a/kernel/fork.c b/kernel/fork.c
index 4c076be..e3e1e67 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -45,8 +45,12 @@ int copy_mem(int nr,struct task_struct * p)
data_limit=get_limit(0x17);
old_code_base = get_base(current->ldt[1]);
old_data_base = get_base(current->ldt[2]);
- if (old_data_base != old_code_base)
+ if (old_data_base != old_code_base) {
+ printk("ldt[0]: %08x %08x\n",current->ldt[0].a,current->ldt[0].b);
+ printk("ldt[1]: %08x %08x\n",current->ldt[1].a,current->ldt[1].b);
+ printk("ldt[2]: %08x %08x\n",current->ldt[2].a,current->ldt[2].b);
panic("We don't support separate I&D");
+ }
if (data_limit < code_limit)
panic("Bad data_limit");
new_data_base = new_code_base = nr * TASK_SIZE;
@@ -60,23 +64,44 @@ int copy_mem(int nr,struct task_struct * p)
return 0;
}
+static int find_empty_process(void)
+{
+ int i;
+
+ repeat:
+ if ((++last_pid)<0) last_pid=1;
+ for(i=0 ; i<NR_TASKS ; i++)
+ if (task[i] && ((task[i]->pid == last_pid) ||
+ (task[i]->pgrp == last_pid)))
+ goto repeat;
+ for(i=1 ; i<NR_TASKS ; i++)
+ if (!task[i])
+ return i;
+ return -EAGAIN;
+}
+
/*
* Ok, this is the main fork-routine. It copies the system process
* information (task[nr]) and sets up the necessary registers. It
* also copies the data segment in it's entirety.
*/
-int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
- long ebx,long ecx,long edx, long orig_eax,
- long fs,long es,long ds,
+int sys_fork(long ebx,long ecx,long edx,
+ long esi, long edi, long ebp, long eax, long ds,
+ long es, long fs, long gs, long orig_eax,
long eip,long cs,long eflags,long esp,long ss)
{
struct task_struct *p;
- int i;
+ int i,nr;
struct file *f;
p = (struct task_struct *) get_free_page();
if (!p)
return -EAGAIN;
+ nr = find_empty_process();
+ if (nr < 0) {
+ free_page((unsigned long) p);
+ return nr;
+ }
task[nr] = p;
*p = *current; /* NOTE! this doesn't copy the supervisor stack */
p->state = TASK_UNINTERRUPTIBLE;
@@ -137,21 +162,5 @@ int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
p->p_osptr->p_ysptr = p;
current->p_cptr = p;
p->state = TASK_RUNNING; /* do this last, just in case */
- return last_pid;
-}
-
-int find_empty_process(void)
-{
- int i;
-
- repeat:
- if ((++last_pid)<0) last_pid=1;
- for(i=0 ; i<NR_TASKS ; i++)
- if (task[i] && ((task[i]->pid == last_pid) ||
- (task[i]->pgrp == last_pid)))
- goto repeat;
- for(i=1 ; i<NR_TASKS ; i++)
- if (!task[i])
- return i;
- return -EAGAIN;
+ return p->pid;
}
diff --git a/kernel/math/Makefile b/kernel/math/Makefile
index 834283d..d136ef5 100644
--- a/kernel/math/Makefile
+++ b/kernel/math/Makefile
@@ -1,18 +1,18 @@
#
-# Makefile for the FREAX-kernel character device drivers.
+# Makefile for the kernel math emulation routines
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
-AR =gar
-AS =gas
-LD =gld
+AR =ar
+AS =as
+LD =ld
LDFLAGS =-s -x
CC =gcc
-CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \
- -finline-functions -mstring-insns -nostdinc -I../../include
+CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \
+ -finline-functions -nostdinc -I../../include
CPP =gcc -E -nostdinc -I../../include
.c.s:
@@ -45,39 +45,48 @@ dep:
add.s add.o : add.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h
+ ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h
compare.s compare.o : compare.c ../../include/linux/math_emu.h \
../../include/linux/sched.h ../../include/linux/head.h \
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h
+ ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h
convert.s convert.o : convert.c ../../include/linux/math_emu.h \
../../include/linux/sched.h ../../include/linux/head.h \
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h
+ ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h
div.s div.o : div.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h
+ ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h
ea.s ea.o : ea.c ../../include/stddef.h ../../include/linux/math_emu.h \
../../include/linux/sched.h ../../include/linux/head.h \
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h \
- ../../include/asm/segment.h
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/asm/segment.h
error.s error.o : error.c ../../include/signal.h ../../include/sys/types.h \
../../include/linux/sched.h ../../include/linux/head.h \
../../include/linux/fs.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h
+ ../../include/linux/kernel.h ../../include/sys/param.h \
+ ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h
get_put.s get_put.o : get_put.c ../../include/signal.h ../../include/sys/types.h \
../../include/linux/math_emu.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/linux/mm.h ../../include/linux/kernel.h \
- ../../include/asm/segment.h
-math_emulate.s math_emulate.o : math_emulate.c ../../include/signal.h \
- ../../include/sys/types.h ../../include/linux/math_emu.h \
- ../../include/linux/sched.h ../../include/linux/head.h \
- ../../include/linux/fs.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/asm/segment.h
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/asm/segment.h
+math_emulate.s math_emulate.o : math_emulate.c ../../include/linux/config.h
mul.s mul.o : mul.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h
+ ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h
diff --git a/kernel/math/convert.c b/kernel/math/convert.c
index 5e3d1a5..e938324 100644
--- a/kernel/math/convert.c
+++ b/kernel/math/convert.c
@@ -113,6 +113,73 @@ void temp_to_long(const temp_real * a, long_real * b)
}
}
+void frndint(const temp_real * a, temp_real * b)
+{
+ int shift = 16383 + 63 - (a->exponent & 0x7fff);
+ unsigned long underflow;
+
+ if ((shift < 0) || (shift == 16383+63)) {
+ *b = *a;
+ return;
+ }
+ b->a = b->b = underflow = 0;
+ b->exponent = a->exponent;
+ if (shift < 32) {
+ b->b = a->b; b->a = a->a;
+ } else if (shift < 64) {
+ b->a = a->b; underflow = a->a;
+ shift -= 32;
+ b->exponent += 32;
+ } else if (shift < 96) {
+ underflow = a->b;
+ shift -= 64;
+ b->exponent += 64;
+ } else {
+ underflow = 1;
+ shift = 0;
+ }
+ b->exponent += shift;
+ __asm__("shrdl %2,%1,%0"
+ :"=r" (underflow),"=r" (b->a)
+ :"c" ((char) shift),"0" (underflow),"1" (b->a));
+ __asm__("shrdl %2,%1,%0"
+ :"=r" (b->a),"=r" (b->b)
+ :"c" ((char) shift),"0" (b->a),"1" (b->b));
+ __asm__("shrl %1,%0"
+ :"=r" (b->b)
+ :"c" ((char) shift),"0" (b->b));
+ switch (ROUNDING) {
+ case ROUND_NEAREST:
+ __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b)
+ ,"r" (0x7fffffff + (b->a & 1))
+ ,"m" (*&underflow));
+ break;
+ case ROUND_UP:
+ if ((b->exponent >= 0) && underflow)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ case ROUND_DOWN:
+ if ((b->exponent < 0) && underflow)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ }
+ if (b->a || b->b)
+ while (b->b >= 0) {
+ b->exponent--;
+ __asm__("addl %0,%0 ; adcl %1,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ }
+ else
+ b->exponent = 0;
+}
+
void real_to_int(const temp_real * a, temp_int * b)
{
int shift = 16383 + 63 - (a->exponent & 0x7fff);
@@ -132,8 +199,10 @@ void real_to_int(const temp_real * a, temp_int * b)
} else if (shift < 96) {
underflow = a->b;
shift -= 64;
- } else
- return;
+ } else {
+ underflow = 1;
+ shift = 0;
+ }
__asm__("shrdl %2,%1,%0"
:"=r" (underflow),"=r" (b->a)
:"c" ((char) shift),"0" (underflow),"1" (b->a));
diff --git a/kernel/math/error.c b/kernel/math/error.c
index 1de404a..5f1c1c2 100644
--- a/kernel/math/error.c
+++ b/kernel/math/error.c
@@ -10,7 +10,7 @@
void math_error(void)
{
- __asm__("fnclex");
if (last_task_used_math)
last_task_used_math->signal |= 1<<(SIGFPE-1);
+ __asm__("fnclex");
}
diff --git a/kernel/math/get_put.c b/kernel/math/get_put.c
index 5f8167b..39063fe 100644
--- a/kernel/math/get_put.c
+++ b/kernel/math/get_put.c
@@ -213,7 +213,7 @@ void put_longlong_int(const temp_real * tmp,
#define DIV10(low,high,rem) \
__asm__("divl %6 ; xchgl %1,%2 ; divl %6" \
- :"=d" (rem),"=a" (low),"=b" (high) \
+ :"=d" (rem),"=a" (low),"=r" (high) \
:"0" (0),"1" (high),"2" (low),"c" (10))
void put_BCD(const temp_real * tmp,struct info * info, unsigned short code)
diff --git a/kernel/math/math_emulate.c b/kernel/math/math_emulate.c
index f79fd73..6fb6e6f 100644
--- a/kernel/math/math_emulate.c
+++ b/kernel/math/math_emulate.c
@@ -30,6 +30,10 @@
* hide most of the 387-specific things here.
*/
+#include <linux/config.h>
+
+#ifdef KERNEL_MATH_EMULATION
+
#include <signal.h>
#define __ALIGNED_TEMP_REAL 1
@@ -127,9 +131,13 @@ static void do_emu(struct info * info)
case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3:
case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7:
case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb:
- case 0x1fc: case 0x1fd: case 0x1fe: case 0x1ff:
- printk("%04x fxxx not implemented\n\r",code + 0xc800);
+ case 0x1fd: case 0x1fe: case 0x1ff:
+ printk("%04x fxxx not implemented\n\r",code + 0xd800);
math_abort(info,1<<(SIGILL-1));
+ case 0x1fc:
+ frndint(PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
case 0x2e9:
fucom(PST(1),PST(0));
fpop(); fpop();
@@ -481,15 +489,14 @@ void math_emulate(long ___false)
I387.swd = 0x0000;
I387.twd = 0x0000;
}
-/* &___false points to info->___orig_eip, so subtract 1 to get info */
- do_emu((struct info *) ((&___false) - 1));
+ do_emu((struct info *) &___false);
}
void __math_abort(struct info * info, unsigned int signal)
{
EIP = ORIG_EIP;
current->signal |= signal;
- __asm__("movl %0,%%esp ; ret"::"g" ((long) info));
+ __asm__("movl %0,%%esp ; ret"::"g" (((long) info)-4));
}
static void fpop(void)
@@ -527,3 +534,16 @@ static temp_real_unaligned * __st(int i)
i &= 7;
return (temp_real_unaligned *) (i*10 + (char *)(I387.st_space));
}
+
+#else /* no math emulation */
+
+#include <signal.h>
+#include <linux/sched.h>
+
+void math_emulate(long ___false)
+{
+ current->signal |= 1<<(SIGFPE-1);
+ schedule();
+}
+
+#endif /* KERNEL_MATH_EMULATION */
diff --git a/kernel/math/mul.c b/kernel/math/mul.c
index 94f7c52..ae85e70 100644
--- a/kernel/math/mul.c
+++ b/kernel/math/mul.c
@@ -39,7 +39,7 @@ static void mul64(const temp_real * a, const temp_real * b, int * c)
"addl %%eax,4(%2)\n\t"
"adcl %%edx,8(%2)\n\t"
"adcl $0,12(%2)"
- ::"b" ((long) a),"c" ((long) b),"D" ((long) c)
+ ::"S" ((long) a),"c" ((long) b),"D" ((long) c)
:"ax","dx");
}
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
new file mode 100644
index 0000000..1dab261
--- /dev/null
+++ b/kernel/ptrace.c
@@ -0,0 +1,322 @@
+/* ptrace.c */
+/* By Ross Biro 1/23/92 */
+
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <errno.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <sys/ptrace.h>
+/* does not yet catch signals sent when the child dies. in
+ exit.c or in signal.c. */
+
+/* determines which flags the user has access to. */
+/* 1 = access 0 = no access */
+#define FLAG_MASK 0x00000dd9
+
+/* set's the trap flag. */
+#define TRAP_FLAG 0x100
+
+/* check's for granularity. */
+#define GRANULARITY 0x00800000
+
+/* this is the number to subtract from the top of the stack. To find
+ the local frame. */
+
+#define MAGICNUMBER 68
+
+void do_no_page (unsigned long, unsigned long, struct task_struct *);
+void write_verify (unsigned long);
+
+/* change a pid into a task struct. */
+static inline int get_task(int pid)
+{
+ int i;
+ for (i =0; i < NR_TASKS; i++)
+ {
+ if (task[i] != NULL && (task[i]->pid == pid)) return (i);
+ }
+ return (-1);
+}
+
+/* this routine will get a word off of the processes priviledged stack.
+ the offset is how far from the base addr as stored in the TSS.
+ this routine assumes that all the priviledged stacks are in our
+ data space. */
+
+static inline int
+get_stack_long(struct task_struct *task, int offset)
+{
+ unsigned char *stack;
+ stack = (unsigned char *)task->tss.esp0;
+ stack += offset;
+ return (*((int *)stack));
+
+}
+
+/* this routine will put a word on the processes priviledged stack.
+ the offset is how far from the base addr as stored in the TSS.
+ this routine assumes that all the priviledged stacks are in our
+ data space. */
+
+static inline int
+put_stack_long(struct task_struct *task, int offset, unsigned short data)
+{
+ unsigned char *stack;
+ stack = (unsigned char *)task->tss.esp0;
+ stack += offset;
+ *(int *)stack = data;
+ return (0);
+
+}
+
+/* this routine will get a word out of an arbitrary
+ tasks data space. It likes to have the task number
+ rather than the task pointer. Perhaps the number
+ should be included in the pointer. */
+/* seg = 0 if I space */
+static inline int get_long (int tsk, long addr, unsigned seg, int *data)
+{
+ int i;
+ int limit;
+ int cur;
+ unsigned long address;
+ unsigned long page;
+ unsigned oldfs;
+ /* find the task number of the current task. */
+ for (i = 0; i < NR_TASKS ; i ++)
+ {
+ if (task[i] == current) break;
+ }
+ if (i == NR_TASKS)
+ {
+ panic ("PTRACE: Can't find current task\n");
+ }
+ cur = i;
+
+ /* we will need to check the redaability of the segment
+ and then the byte in order to avoid segment violations. */
+ seg++;
+ limit=(task[tsk]->ldt[seg].a) & 0xffff;
+ /* this should be constant amound all of our segments, but we
+ had better check anyway. */
+ if (task[tsk]->ldt[seg].b & GRANULARITY) limit = limit << 12;
+
+ if (limit <= addr+4) return (-EIO);
+
+ /* Now compute the address, and make sure that it is present. */
+ address = ((task[tsk]->ldt[seg].a & 0xffff000) >> 8) |
+ ((task[tsk]->ldt[seg].b & 0xff) << 16 ) |
+ (task[tsk]->ldt[seg].b & 0xff000000);
+
+ page = *((unsigned long*) ((address >> 20) & 0xffc));
+ /* see if it is present. */
+ if (! (page & PAGE_PRESENT))
+ {
+ do_no_page (0, address, task[tsk]);
+ }
+
+ oldfs=get_fs();
+ /* now convert seg to the right format. */
+ seg = seg << 3 | 0x4;
+
+ cli(); /* we are about to change our ldt, we better do it
+ with interrupts off. Perhaps we should call schedule
+ first so that we won't be taking too much extra time. */
+ lldt(tsk);
+ set_fs(seg);
+ *data = get_fs_long((void *)addr); /* we are assuming kernel space
+ is in the gdt here. */
+ lldt(cur);
+ set_fs(oldfs);
+ sti();
+ return (0);
+}
+
+/* this routine will get a word out of an arbitrary
+ tasks data space. It likes to have the task number
+ rather than the task pointer. Perhaps the number
+ should be included in the pointer. */
+/* seg = 0 if I space */
+static inline int put_long (int tsk, long addr, int data, unsigned seg)
+{
+ int i;
+ int limit;
+ unsigned oldfs;
+ unsigned long address;
+ unsigned long page;
+ int cur;
+ /* find the task number of the current task. */
+ for (i = 0; i < NR_TASKS ; i ++)
+ {
+ if (task[i] == current) break;
+ }
+ if (i == NR_TASKS)
+ {
+ panic ("PTRACE: Can't find current task\n");
+ }
+ cur = i;
+
+ /* we will need to check the readability of the segment
+ and then the byte in order to avoid segment violations. */
+ seg++;
+ limit=(task[tsk]->ldt[seg].a) & 0xffff;
+ /* this should be constant amound all of our segments, but we
+ had better check anyway. */
+ if (task[tsk]->ldt[seg].b & GRANULARITY) limit = limit << 12;
+
+ if (limit <= addr+4) return (-EIO);
+
+ /* Now compute the address, and make sure that it is present. */
+ address = ((task[tsk]->ldt[seg].a & 0xffff000) >> 8) |
+ ((task[tsk]->ldt[seg].b & 0xff) << 16 ) |
+ (task[tsk]->ldt[seg].b & 0xff000000);
+
+ page = *((unsigned long*) ((address >> 20) & 0xffc));
+ /* see if it is present. */
+ if (! (page & PAGE_PRESENT))
+ {
+ do_no_page (0, address, task[tsk]);
+ }
+ write_verify (address);
+
+ oldfs=get_fs();
+ /* now convert seg to the right format. */
+ seg = seg << 3 | 0x4;
+
+ cli(); /* we are about to change our ldt, we better do it
+ with interrupts off. Perhaps we should call schedule
+ first so that we won't be taking too much extra time. */
+ lldt(tsk);
+ set_fs(seg);
+ put_fs_long(data,(void *)addr);
+ lldt(cur);
+ set_fs(oldfs);
+ sti();
+ return (0);
+}
+
+
+int
+sys_ptrace( unsigned long *buffer)
+/* Perform ptrace(request, pid, addr, data) syscall */
+{
+ long request, pid, data;
+ long addr;
+ struct task_struct *child;
+ int childno;
+
+ request = get_fs_long(buffer++);
+ pid = get_fs_long(buffer++);
+ addr = get_fs_long(buffer++); /* assume long = void * */
+ data = get_fs_long(buffer++);
+
+ if (request == 0)
+ {
+ /* set the ptrace bit in the proccess flags. */
+ current->flags |= PF_PTRACED;
+ return (0);
+ }
+
+ childno=get_task(pid);
+
+ if (childno < 0)
+ return (-ESRCH);
+ else
+ child = task[childno];
+
+ if (child->p_pptr != current ||
+ !(child->flags & PF_PTRACED) || child->state != TASK_STOPPED)
+ return (-ESRCH);
+
+ switch (request)
+ {
+ /* when I and D space are seperate, these will need to be fixed. */
+ case 1: /* read word at location addr. */
+ case 2: {
+ int tmp;
+ int res;
+ res = get_long(childno, addr, 1, &tmp);
+ if (res < 0)
+ return res;
+ verify_area(data, 4);
+ put_fs_long( tmp, (unsigned long *)data);
+ return 0;
+ }
+
+ case 3: /* read the word at location addr in the USER area. */
+ {
+ int tmp;
+ addr = addr >> 2; /* temporary hack. */
+ if (addr < 0 || addr >= 17)
+ return (-EIO);
+ verify_area(data, 4);
+ tmp = get_stack_long (child, 4*addr-MAGICNUMBER);
+ put_fs_long(tmp,(unsigned long *)data);
+ return (0);
+ }
+ case 4: /* write the word at location addr. */
+ case 5:
+ /* when I and D space are seperate, this will have to be fixed. */
+ if (put_long(childno, addr, data, 1)) return (-EIO);
+ return (0);
+
+ case 6: /* write the word at location addr in the USER area */
+ addr = addr >> 2; /* temproary hack. */
+ if (addr < 0 || addr >= 17) return (-EIO);
+ if (addr == ORIG_EAX) return (-EIO);
+ if (addr == EFL) /* flags. */
+ {
+ data &= FLAG_MASK;
+ data |= get_stack_long(child, EFL*4-MAGICNUMBER) & ~FLAG_MASK;
+ }
+
+ if (put_stack_long(child, 4*addr-MAGICNUMBER, data)) return (-EIO);
+ return (0);
+
+ case 7: /* restart after signal. */
+ {
+ long tmp;
+ child->signal=0;
+ if (data > 0 && data <= NSIG)
+ child->signal = 1<<(data-1);
+ child->state = 0;
+ /* make sure the single step bit is not set. */
+ tmp = get_stack_long (child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
+ put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
+ return (0);
+ }
+
+ case 8: /* make the child exit. Best I can do is send it a sigkill.
+ perhaps it should be put in the status that it want's to
+ exit. */
+ {
+ long tmp;
+ child->state = 0;
+ child->signal = 1 << (SIGKILL -1 );
+ /* make sure the single step bit is not set. */
+ tmp = get_stack_long (child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
+ put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
+ return (0);
+ }
+
+ case 9: /* set the trap flag. */
+ {
+ long tmp;
+ tmp = get_stack_long (child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
+ put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
+ child->state = 0;
+ child->signal=0;
+ if (data > 0 && data <NSIG)
+ child->signal= 1<<(data-1);
+ /* give it a chance to run. */
+ return (0);
+ }
+
+ default:
+ return (-EIO);
+ }
+
+}
diff --git a/kernel/sched.c b/kernel/sched.c
index 8de11a1..335551d 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -11,6 +11,7 @@
* current-task
*/
#include <linux/sched.h>
+#include <linux/timer.h>
#include <linux/kernel.h>
#include <linux/sys.h>
#include <linux/fdreg.h>
@@ -19,6 +20,7 @@
#include <asm/segment.h>
#include <signal.h>
+#include <errno.h>
#define _S(nr) (1<<((nr)-1))
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
@@ -107,9 +109,8 @@ void math_state_restore()
}
/*
- * 'schedule()' is the scheduler function. This is GOOD CODE! There
- * probably won't be any reason to change this, as it should work well
- * in all circumstances (ie gives IO-bound processes good response etc).
+ * 'schedule()' is the scheduler function. It's a very simple and nice
+ * scheduler: it's not perfect, but certainly works for most things.
* The one thing you might take a look at is the signal-handler code here.
*
* NOTE!! Task 0 is the 'idle' task, which gets called when no other
@@ -134,7 +135,7 @@ void schedule(void)
(*p)->signal |= (1<<(SIGALRM-1));
(*p)->alarm = 0;
}
- if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
+ if (((*p)->signal & ~(*p)->blocked) &&
(*p)->state==TASK_INTERRUPTIBLE)
(*p)->state=TASK_RUNNING;
}
@@ -163,32 +164,44 @@ void schedule(void)
int sys_pause(void)
{
+ unsigned long old_blocked;
+ unsigned long mask;
+ struct sigaction * sa = current->sigaction;
+
+ old_blocked = current->blocked;
+ for (mask=1 ; mask ; sa++,mask += mask)
+ if (sa->sa_handler == SIG_IGN)
+ current->blocked |= mask;
current->state = TASK_INTERRUPTIBLE;
schedule();
- return 0;
+ current->blocked = old_blocked;
+ return -EINTR;
}
static inline void __sleep_on(struct task_struct **p, int state)
{
struct task_struct *tmp;
+ unsigned int flags;
if (!p)
return;
if (current == &(init_task.task))
panic("task[0] trying to sleep");
+ __asm__("pushfl ; popl %0":"=r" (flags));
tmp = *p;
*p = current;
current->state = state;
+/* make sure interrupts are enabled: there should be no more races here */
+ sti();
repeat: schedule();
if (*p && *p != current) {
- (**p).state = 0;
current->state = TASK_UNINTERRUPTIBLE;
+ (**p).state = 0;
goto repeat;
}
- if (!*p)
- printk("Warning: *P = NULL\n\r");
if (*p = tmp)
tmp->state=0;
+ __asm__("pushl %0 ; popfl"::"r" (flags));
}
void interruptible_sleep_on(struct task_struct **p)
@@ -321,27 +334,24 @@ void add_timer(long jiffies, void (*fn)(void))
sti();
}
+unsigned long timer_active = 0;
+struct timer_struct timer_table[32];
+
void do_timer(long cpl)
{
- static int blanked = 0;
-
- if (blankcount || !blankinterval) {
- if (blanked)
- unblank_screen();
- if (blankcount)
- blankcount--;
- blanked = 0;
- } else if (!blanked) {
- blank_screen();
- blanked = 1;
- }
- if (hd_timeout)
- if (!--hd_timeout)
- hd_times_out();
+ unsigned long mask;
+ struct timer_struct *tp = timer_table+0;
- if (beepcount)
- if (!--beepcount)
- sysbeepstop();
+ for (mask = 1 ; mask ; tp++,mask += mask) {
+ if (mask > timer_active)
+ break;
+ if (!(mask & timer_active))
+ continue;
+ if (tp->expires > jiffies)
+ continue;
+ timer_active &= ~mask;
+ tp->fn();
+ }
if (cpl)
current->utime++;
@@ -409,8 +419,11 @@ int sys_getegid(void)
int sys_nice(long increment)
{
- if (current->priority-increment>0)
- current->priority -= increment;
+ if (increment < 0 && !suser())
+ return -EPERM;
+ if (increment > current->priority)
+ increment = current->priority-1;
+ current->priority -= increment;
return 0;
}
@@ -424,7 +437,7 @@ void sched_init(void)
set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
p = gdt+2+FIRST_TSS_ENTRY;
- for(i=1;i<NR_TASKS;i++) {
+ for(i=1 ; i<NR_TASKS ; i++) {
task[i] = NULL;
p->a=p->b=0;
p++;
diff --git a/kernel/signal.c b/kernel/signal.c
index b326435..cf0aa01 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -9,8 +9,11 @@
#include <asm/segment.h>
#include <signal.h>
+#include <sys/wait.h>
#include <errno.h>
+int send_sig (int, struct task_struct *, int);
+
int sys_sgetmask()
{
return current->blocked;
@@ -125,8 +128,12 @@ int core_dump(long signr)
return(0); /* We didn't do a dump */
}
-int do_signal(long signr,long eax,long ebx, long ecx, long edx, long orig_eax,
- long fs, long es, long ds,
+extern int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
+
+int do_signal(long signr,long ebx, long ecx, long edx,
+ long esi, long edi, long ebp, long eax,
+ long ds, long es, long fs, long gs,
+ long orig_eax,
long eip, long cs, long eflags,
unsigned long * esp, long ss)
{
@@ -153,12 +160,18 @@ int do_signal(long signr,long eax,long ebx, long ecx, long edx, long orig_eax,
}
}
sa_handler = (unsigned long) sa->sa_handler;
- if (sa_handler==1)
+ if (sa_handler==1) {
+/* check for SIGCHLD: it's special */
+ if (signr == SIGCHLD)
+ while (sys_waitpid(-1,NULL,WNOHANG) > 0)
+ /* nothing */;
return(1); /* Ignore, see if there are more signals... */
+ }
if (!sa_handler) {
switch (signr) {
case SIGCONT:
case SIGCHLD:
+ case SIGWINCH:
return(1); /* Ignore, ... */
case SIGSTOP:
@@ -169,7 +182,9 @@ int do_signal(long signr,long eax,long ebx, long ecx, long edx, long orig_eax,
current->exit_code = signr;
if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- current->p_pptr->signal |= (1<<(SIGCHLD-1));
+ send_sig(SIGCHLD, current->p_pptr, 1);
+/* current->p_pptr->signal |= (1<<(SIGCHLD-1));*/
+
return(1); /* Reschedule another event */
case SIGQUIT:
@@ -205,5 +220,7 @@ int do_signal(long signr,long eax,long ebx, long ecx, long edx, long orig_eax,
put_fs_long(eflags,tmp_esp++);
put_fs_long(old_eip,tmp_esp++);
current->blocked |= sa->sa_mask;
+/* force a supervisor-mode page-in of the signal handler to reduce races */
+ __asm__("testb $0,%%fs:%0"::"m" (*(char *) sa_handler));
return(0); /* Continue, execute handler */
}
diff --git a/kernel/sys.c b/kernel/sys.c
index fd85818..40b8b40 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -17,6 +17,11 @@
#include <sys/resource.h>
#include <string.h>
+/*
+ * this indicates wether you can reboot with ctrl-alt-del: the deault is yes
+ */
+static int C_A_D = 1;
+
/*
* The timezone where the local system is located. Used as a default by some
* programs who obtain this value by using gettimeofday.
@@ -35,30 +40,59 @@ int sys_break()
return -ENOSYS;
}
-int sys_ptrace()
+int sys_stty()
{
return -ENOSYS;
}
-int sys_stty()
+int sys_gtty()
{
return -ENOSYS;
}
-int sys_gtty()
+int sys_prof()
{
return -ENOSYS;
}
-int sys_rename()
+extern void hard_reset_now(void);
+
+/*
+ * Reboot system call: for obvious reasons only root may call it,
+ * and even root needs to set up some magic numbers in the registers
+ * so that some mistake won't make this reboot the whole machine.
+ * You can also set the meaning of the ctrl-alt-del-key here.
+ *
+ * reboot doesn't sync: do that yourself before calling this.
+ */
+int sys_reboot(int magic, int magic_too, int flag)
{
- return -ENOSYS;
+ if (!suser())
+ return -EPERM;
+ if (magic != 0xfee1dead || magic_too != 672274793)
+ return -EINVAL;
+ if (flag == 0x01234567)
+ hard_reset_now();
+ else if (flag == 0x89ABCDEF)
+ C_A_D = 1;
+ else if (!flag)
+ C_A_D = 0;
+ else
+ return -EINVAL;
+ return (0);
}
-int sys_prof()
+/*
+ * This function gets called by ctrl-alt-del - ie the keyboard interrupt.
+ * As it's called within an interrupt, it may NOT sync: the only choice
+ * is wether to reboot at once, or just ignore the ctrl-alt-del.
+ */
+void ctrl_alt_del(void)
{
- return -ENOSYS;
+ if (C_A_D)
+ hard_reset_now();
}
+
/*
* This is done BSD-style, with no consideration of the saved gid, except
diff --git a/kernel/sys_call.s b/kernel/sys_call.s
index f85ddf3..8d7a982 100644
--- a/kernel/sys_call.s
+++ b/kernel/sys_call.s
@@ -15,37 +15,49 @@
* unnecessarily.
*
* Stack layout in 'ret_from_system_call':
+ * ptrace needs to have all regs on the stack.
+ * if the order here is changed, it needs to be
+ * updated in fork.c:copy_process, signal.c:do_signal,
+ * ptrace.c ptrace.h
*
- * 0(%esp) - %eax
- * 4(%esp) - %ebx
- * 8(%esp) - %ecx
- * C(%esp) - %edx
- * 10(%esp) - original %eax (-1 if not system call)
- * 14(%esp) - %fs
- * 18(%esp) - %es
+ * 0(%esp) - %ebx
+ * 4(%esp) - %ecx
+ * 8(%esp) - %edx
+ * C(%esp) - %esi
+ * 10(%esp) - %edi
+ * 14(%esp) - %ebp
+ * 18(%esp) - %eax
* 1C(%esp) - %ds
- * 20(%esp) - %eip
- * 24(%esp) - %cs
- * 28(%esp) - %eflags
- * 2C(%esp) - %oldesp
- * 30(%esp) - %oldss
+ * 20(%esp) - %es
+ * 24(%esp) - %fs
+ * 28(%esp) - %gs
+ * 2C(%esp) - orig_eax
+ * 30(%esp) - %eip
+ * 34(%esp) - %cs
+ * 38(%esp) - %eflags
+ * 3C(%esp) - %oldesp
+ * 40(%esp) - %oldss
*/
SIG_CHLD = 17
-EAX = 0x00
-EBX = 0x04
-ECX = 0x08
-EDX = 0x0C
-ORIG_EAX = 0x10
-FS = 0x14
-ES = 0x18
+EBX = 0x00
+ECX = 0x04
+EDX = 0x08
+ESI = 0x0C
+EDI = 0x10
+EBP = 0x14
+EAX = 0x18
DS = 0x1C
-EIP = 0x20
-CS = 0x24
-EFLAGS = 0x28
-OLDESP = 0x2C
-OLDSS = 0x30
+ES = 0x20
+FS = 0x24
+GS = 0x28
+ORIG_EAX = 0x2C
+EIP = 0x30
+CS = 0x34
+EFLAGS = 0x38
+OLDESP = 0x3C
+OLDSS = 0x40
state = 0 # these are offsets into the task-struct.
counter = 4
@@ -68,7 +80,7 @@ ENOSYS = 38
* Ok, I get parallel printer interrupts while using the floppy for some
* strange reason. Urgel. Now I just ignore them.
*/
-.globl _system_call,_sys_fork,_timer_interrupt,_sys_execve
+.globl _system_call,_timer_interrupt,_sys_execve
.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt
.globl _device_not_available, _coprocessor_error
@@ -82,10 +94,16 @@ reschedule:
jmp _schedule
.align 2
_system_call:
- push %ds
- push %es
+ cld
+ pushl %eax # save orig_eax
+ push %gs
push %fs
- pushl %eax # save the orig_eax
+ push %es
+ push %ds
+ pushl %eax # save eax. The return value will be put here.
+ pushl %ebp
+ pushl %edi
+ pushl %esi
pushl %edx
pushl %ecx # push %ebx,%ecx,%edx as parameters
pushl %ebx # to the system call
@@ -97,9 +115,8 @@ _system_call:
cmpl _NR_syscalls,%eax
jae bad_sys_call
call _sys_call_table(,%eax,4)
- pushl %eax
-2:
- movl _current,%eax
+ movl %eax,EAX(%esp) # save the return value
+2: movl _current,%eax
cmpl $0,state(%eax) # state
jne reschedule
cmpl $0,counter(%eax) # counter
@@ -126,26 +143,36 @@ ret_from_sys_call:
popl %ecx
testl %eax, %eax
jne 2b # see if we need to switch tasks, or do more signals
-3: popl %eax
+3:
popl %ebx
popl %ecx
popl %edx
- addl $4, %esp # skip orig_eax
- pop %fs
- pop %es
+ popl %esi
+ popl %edi
+ popl %ebp
+ popl %eax
pop %ds
+ pop %es
+ pop %fs
+ pop %gs
+ addl $4,%esp # skip the orig_eax
iret
.align 2
_coprocessor_error:
- push %ds
- push %es
+ cld
+ pushl $-1 # mark this as an int.
+ push %gs
push %fs
- pushl $-1 # fill in -1 for orig_eax
+ push %es
+ push %ds
+ pushl %eax # save eax.
+ pushl %ebp
+ pushl %edi
+ pushl %esi
pushl %edx
pushl %ecx
pushl %ebx
- pushl %eax
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
@@ -156,14 +183,19 @@ _coprocessor_error:
.align 2
_device_not_available:
- push %ds
- push %es
+ cld
+ pushl $-1 # mark this as an int
+ push %gs
push %fs
- pushl $-1 # fill in -1 for orig_eax
+ push %es
+ push %ds
+ pushl %eax
+ pushl %ebp
+ pushl %edi
+ pushl %esi
pushl %edx
pushl %ecx
pushl %ebx
- pushl %eax
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
@@ -174,27 +206,26 @@ _device_not_available:
movl %cr0,%eax
testl $0x4,%eax # EM (math emulation bit)
je _math_state_restore
- pushl %ebp
- pushl %esi
- pushl %edi
pushl $0 # temporary storage for ORIG_EIP
call _math_emulate
addl $4,%esp
- popl %edi
- popl %esi
- popl %ebp
ret
.align 2
_timer_interrupt:
- push %ds # save ds,es and put kernel data space
- push %es # into them. %fs is used by _system_call
+ cld
+ pushl $-1 # mark this as an int
+ push %gs
push %fs
- pushl $-1 # fill in -1 for orig_eax
- pushl %edx # we save %eax,%ecx,%edx as gcc doesn't
- pushl %ecx # save those across function calls. %ebx
- pushl %ebx # is saved as we use that in ret_sys_call
+ push %es
+ push %ds
pushl %eax
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
@@ -212,27 +243,14 @@ _timer_interrupt:
.align 2
_sys_execve:
- lea EIP(%esp),%eax
+ lea (EIP+4)(%esp),%eax # don't forget about the return address.
pushl %eax
call _do_execve
addl $4,%esp
ret
-.align 2
-_sys_fork:
- call _find_empty_process
- testl %eax,%eax
- js 1f
- push %gs
- pushl %esi
- pushl %edi
- pushl %ebp
- pushl %eax
- call _copy_process
- addl $20,%esp
-1: ret
-
_hd_interrupt:
+ cld
pushl %eax
pushl %ecx
pushl %edx
@@ -248,14 +266,14 @@ _hd_interrupt:
outb %al,$0xA0 # EOI to interrupt controller #1
jmp 1f # give port chance to breathe
1: jmp 1f
-1: xorl %edx,%edx
- movl %edx,_hd_timeout
+1: outb %al,$0x20
+ andl $0xfffeffff,_timer_active
+ xorl %edx,%edx
xchgl _do_hd,%edx
testl %edx,%edx
jne 1f
movl $_unexpected_hd_interrupt,%edx
-1: outb %al,$0x20
- call *%edx # "interesting" way of handling intr.
+1: call *%edx # "interesting" way of handling intr.
pop %fs
pop %es
pop %ds
@@ -265,6 +283,7 @@ _hd_interrupt:
iret
_floppy_interrupt:
+ cld
pushl %eax
pushl %ecx
pushl %edx
@@ -293,6 +312,7 @@ _floppy_interrupt:
iret
_parallel_interrupt:
+ cld
pushl %eax
movb $0x20,%al
outb %al,$0x20
diff --git a/kernel/traps.c b/kernel/traps.c
index ae9f8cb..797bb79 100644
--- a/kernel/traps.c
+++ b/kernel/traps.c
@@ -18,6 +18,8 @@
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
+#include <errno.h>
+
#define get_seg_byte(seg,addr) ({ \
register char __res; \
@@ -58,6 +60,7 @@ void reserved(void);
void parallel_interrupt(void);
void irq13(void);
void alignment_check(void);
+int send_sig(long, struct task_struct *, int);
static void die(char * str,long esp_ptr,long nr)
{
@@ -65,11 +68,12 @@ static void die(char * str,long esp_ptr,long nr)
int i;
printk("%s: %04x\n\r",str,nr&0xffff);
- printk("EIP:\t%04x:%p\nEFLAGS:\t%p\nESP:\t%04x:%p\n",
- esp[1],esp[0],esp[2],esp[4],esp[3]);
+ printk("EIP: %04x:%p\nEFLAGS: %p\n", 0xffff & esp[1],esp[0],esp[2]);
+ if ((0xffff & esp[1]) == 0xf)
+ printk("ESP: %04x:%p\n",0xffff & esp[4],esp[3]);
printk("fs: %04x\n",_fs());
printk("base: %p, limit: %p\n",get_base(current->ldt[1]),get_limit(0x17));
- if (esp[4] == 0x17) {
+ if ((0xffff & esp[1]) == 0xf) {
printk("Stack: ");
for (i=0;i<4;i++)
printk("%p ",get_seg_long(0x17,i+(long *)esp[3]));
@@ -103,21 +107,9 @@ void do_divide_error(long esp, long error_code)
die("divide error",esp,error_code);
}
-void do_int3(long * esp, long error_code,
- long fs,long es,long ds,
- long ebp,long esi,long edi,
- long edx,long ecx,long ebx,long eax)
+void do_int3(long esp, long error_code)
{
- int tr;
-
- __asm__("str %%ax":"=a" (tr):"0" (0));
- printk("eax\t\tebx\t\tecx\t\tedx\n\r%8x\t%8x\t%8x\t%8x\n\r",
- eax,ebx,ecx,edx);
- printk("esi\t\tedi\t\tebp\t\tesp\n\r%8x\t%8x\t%8x\t%8x\n\r",
- esi,edi,ebp,(long) esp);
- printk("\n\rds\tes\tfs\ttr\n\r%4x\t%4x\t%4x\t%4x\n\r",
- ds,es,fs,tr);
- printk("EIP: %8x CS: %4x EFLAGS: %8x\n\r",esp[0],esp[1],esp[2]);
+ send_sig(SIGTRAP, current, 0);
}
void do_nmi(long esp, long error_code)
@@ -127,7 +119,7 @@ void do_nmi(long esp, long error_code)
void do_debug(long esp, long error_code)
{
- die("debug",esp,error_code);
+ send_sig(SIGTRAP, current, 0);
}
void do_overflow(long esp, long error_code)
diff --git a/lib/Makefile b/lib/Makefile
index a4a33b5..9f678c8 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -6,13 +6,16 @@
# unless it's something special (ie not a .c file).
#
-AR =gar
-AS =gas
-LD =gld
+# gcc2 doesn't understand some options..
+# GCC_OPT = -fcombine-regs
+
+AR =ar
+AS =as
+LD =ld
LDFLAGS =-s -x
CC =gcc
-CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \
- -finline-functions -mstring-insns -nostdinc -I../include
+CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer $(GCC_OPT) \
+ -finline-functions -nostdinc -I../include
CPP =gcc -E -nostdinc -I../include
.c.s:
diff --git a/lib/_exit.c b/lib/_exit.c
index c0c9d69..ac48d1a 100644
--- a/lib/_exit.c
+++ b/lib/_exit.c
@@ -9,5 +9,6 @@
volatile void _exit(int exit_code)
{
- __asm__("int $0x80"::"a" (__NR_exit),"b" (exit_code));
+ __asm__("movl %1,%%ebx\n\t"
+ "int $0x80"::"a" (__NR_exit),"g" (exit_code));
}
diff --git a/lib/open.c b/lib/open.c
index 8c3fc58..5972807 100644
--- a/lib/open.c
+++ b/lib/open.c
@@ -14,9 +14,10 @@ int open(const char * filename, int flag, ...)
va_list arg;
va_start(arg,flag);
- __asm__("int $0x80"
+ __asm__("movl %2,%%ebx\n\t"
+ "int $0x80"
:"=a" (res)
- :"0" (__NR_open),"b" (filename),"c" (flag),
+ :"0" (__NR_open),"g" ((long)(filename)),"c" (flag),
"d" (va_arg(arg,int)));
if (res>=0)
return res;
diff --git a/mm/Makefile b/mm/Makefile
index bab2e4c..44c38ab 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -1,9 +1,9 @@
CC =gcc
-CFLAGS =-O -Wall -fstrength-reduce -fcombine-regs -fomit-frame-pointer \
+CFLAGS =-O -Wall -fstrength-reduce -fomit-frame-pointer \
-finline-functions -nostdinc -I../include
-AS =gas
-AR =gar
-LD =gld
+AS =as
+AR =ar
+LD =ld
CPP =gcc -E -nostdinc -I../include
.c.o:
@@ -15,7 +15,7 @@ CPP =gcc -E -nostdinc -I../include
$(CC) $(CFLAGS) \
-S -o $*.s $<
-OBJS = memory.o swap.o page.o
+OBJS = memory.o swap.o
all: mm.o
@@ -37,8 +37,8 @@ memory.o : memory.c ../include/signal.h ../include/sys/types.h \
../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h
-swap.o : swap.c ../include/string.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
- ../include/sys/param.h ../include/sys/time.h ../include/time.h \
- ../include/sys/resource.h
+swap.o : swap.c ../include/string.h ../include/errno.h \
+ ../include/linux/mm.h ../include/linux/fs.h ../include/sys/types.h \
+ ../include/linux/kernel.h ../include/signal.h ../include/sys/stat.h \
+ ../include/linux/sched.h ../include/linux/head.h ../include/sys/param.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/resource.h
diff --git a/mm/memory.c b/mm/memory.c
index b7815bb..a77f26f 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -44,6 +44,10 @@ unsigned long HIGH_MEMORY = 0;
#define copy_page(from,to) \
__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
+#define CHECK_LAST_NR 16
+
+static unsigned long last_pages[CHECK_LAST_NR] = { 0, };
+
unsigned char mem_map [ PAGING_PAGES ] = {0,};
/*
@@ -53,13 +57,14 @@ unsigned char mem_map [ PAGING_PAGES ] = {0,};
void free_page(unsigned long addr)
{
if (addr < LOW_MEM) return;
- if (addr >= HIGH_MEMORY)
- panic("trying to free nonexistent page");
- addr -= LOW_MEM;
- addr >>= 12;
- if (mem_map[addr]--) return;
- mem_map[addr]=0;
- panic("trying to free free page");
+ if (addr < HIGH_MEMORY) {
+ addr -= LOW_MEM;
+ addr >>= 12;
+ if (mem_map[addr]--)
+ return;
+ mem_map[addr]=0;
+ }
+ printk("trying to free free page: memory probably corrupted");
}
/*
@@ -68,6 +73,8 @@ void free_page(unsigned long addr)
*/
int free_page_tables(unsigned long from,unsigned long size)
{
+ unsigned long page;
+ unsigned long page_dir;
unsigned long *pg_table;
unsigned long * dir, nr;
@@ -78,23 +85,28 @@ int free_page_tables(unsigned long from,unsigned long size)
size = (size + 0x3fffff) >> 22;
dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
for ( ; size-->0 ; dir++) {
- if (!(1 & *dir))
+ if (!(page_dir = *dir))
continue;
- pg_table = (unsigned long *) (0xfffff000 & *dir);
- for (nr=0 ; nr<1024 ; nr++) {
- if (*pg_table) {
- if (1 & *pg_table)
- free_page(0xfffff000 & *pg_table);
- else
- swap_free(*pg_table >> 1);
- *pg_table = 0;
- }
- pg_table++;
- }
- free_page(0xfffff000 & *dir);
*dir = 0;
+ if (!(page_dir & 1)) {
+ printk("free_page_tables: bad page directory.");
+ continue;
+ }
+ pg_table = (unsigned long *) (0xfffff000 & page_dir);
+ for (nr=0 ; nr<1024 ; nr++,pg_table++) {
+ if (!(page = *pg_table))
+ continue;
+ *pg_table = 0;
+ if (1 & page)
+ free_page(0xfffff000 & page);
+ else
+ swap_free(page >> 1);
+ }
+ free_page(0xfffff000 & page_dir);
}
invalidate();
+ for (page = 0; page < CHECK_LAST_NR ; page++)
+ last_pages[page] = 0;
return 0;
}
@@ -130,10 +142,17 @@ int copy_page_tables(unsigned long from,unsigned long to,long size)
to_dir = (unsigned long *) ((to>>20) & 0xffc);
size = ((unsigned) (size+0x3fffff)) >> 22;
for( ; size-->0 ; from_dir++,to_dir++) {
- if (1 & *to_dir)
- panic("copy_page_tables: already exist");
- if (!(1 & *from_dir))
+ if (*to_dir)
+ printk("copy_page_tables: already exist, "
+ "probable memory corruption\n");
+ if (!*from_dir)
continue;
+ if (!(1 & *from_dir)) {
+ printk("copy_page_tables: page table swapped out, "
+ "probable memory corruption");
+ *from_dir = 0;
+ continue;
+ }
from_page_table = (unsigned long *) (0xfffff000 & *from_dir);
if (!(to_page_table = (unsigned long *) get_free_page()))
return -1; /* Out of memory, see freeing */
@@ -177,10 +196,14 @@ static unsigned long put_page(unsigned long page,unsigned long address)
/* NOTE !!! This uses the fact that _pg_dir=0 */
- if (page < LOW_MEM || page >= HIGH_MEMORY)
- printk("Trying to put page %p at %p\n",page,address);
- if (mem_map[(page-LOW_MEM)>>12] != 1)
+ if (page < LOW_MEM || page >= HIGH_MEMORY) {
+ printk("put_page: trying to put page %p at %p\n",page,address);
+ return 0;
+ }
+ if (mem_map[(page-LOW_MEM)>>12] != 1) {
printk("mem_map disagrees with %p at %p\n",page,address);
+ return 0;
+ }
page_table = (unsigned long *) ((address>>20) & 0xffc);
if ((*page_table)&1)
page_table = (unsigned long *) (0xfffff000 & *page_table);
@@ -208,7 +231,7 @@ unsigned long put_dirty_page(unsigned long page, unsigned long address)
/* NOTE !!! This uses the fact that _pg_dir=0 */
if (page < LOW_MEM || page >= HIGH_MEMORY)
- printk("Trying to put page %p at %p\n",page,address);
+ printk("put_dirty_page: trying to put page %p at %p\n",page,address);
if (mem_map[(page-LOW_MEM)>>12] != 1)
printk("mem_map disagrees with %p at %p\n",page,address);
page_table = (unsigned long *) ((address>>20) & 0xffc);
@@ -227,20 +250,40 @@ unsigned long put_dirty_page(unsigned long page, unsigned long address)
void un_wp_page(unsigned long * table_entry)
{
- unsigned long old_page,new_page;
-
- old_page = 0xfffff000 & *table_entry;
+ unsigned long old_page;
+ unsigned long new_page = 0;
+ unsigned long dirty;
+
+repeat:
+ old_page = *table_entry;
+ dirty = old_page & PAGE_DIRTY;
+ if (!(old_page & 1)) {
+ if (new_page)
+ free_page(new_page);
+ return;
+ }
+ old_page &= 0xfffff000;
+ if (old_page >= HIGH_MEMORY) {
+ if (new_page)
+ free_page(new_page);
+ printk("bad page address\n\r");
+ do_exit(SIGSEGV);
+ }
if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) {
*table_entry |= 2;
invalidate();
+ if (new_page)
+ free_page(new_page);
return;
}
- if (!(new_page=get_free_page()))
- oom();
- if (old_page >= LOW_MEM)
- mem_map[MAP_NR(old_page)]--;
+ if (!new_page) {
+ if (!(new_page=get_free_page()))
+ oom();
+ goto repeat;
+ }
copy_page(old_page,new_page);
- *table_entry = new_page | 7;
+ *table_entry = new_page | dirty | 7;
+ free_page(old_page);
invalidate();
}
@@ -255,16 +298,10 @@ void do_wp_page(unsigned long error_code,unsigned long address)
{
if (address < TASK_SIZE)
printk("\n\rBAD! KERNEL MEMORY WP-ERR!\n\r");
- if (address - current->start_code > TASK_SIZE) {
+ if (address - current->start_code >= TASK_SIZE) {
printk("Bad things happen: page error in do_wp_page\n\r");
do_exit(SIGSEGV);
}
-#if 0
-/* we cannot do this yet: the estdio library writes to code space */
-/* stupid, stupid. I really want the libc.a from GNU */
- if (CODE_SPACE(address))
- do_exit(SIGSEGV);
-#endif
un_wp_page((unsigned long *)
(((address>>10) & 0xffc) + (0xfffff000 &
*((unsigned long *) ((address>>20) &0xffc)))));
@@ -327,11 +364,12 @@ static int try_to_share(unsigned long address, struct task_struct * p)
if (phys_addr >= HIGH_MEMORY || phys_addr < LOW_MEM)
return 0;
to = *(unsigned long *) to_page;
- if (!(to & 1))
+ if (!(to & 1)) {
if (to = get_free_page())
*(unsigned long *) to_page = to | 7;
else
oom();
+ }
to &= 0xfffff000;
to_page = to + ((address>>10) & 0xffc);
if (1 & *(unsigned long *) to_page)
@@ -354,7 +392,7 @@ static int try_to_share(unsigned long address, struct task_struct * p)
* We first check if it is at all feasible by checking executable->i_count.
* It should be >1 if there are other tasks sharing this inode.
*/
-static int share_page(struct m_inode * inode, unsigned long address)
+static int share_page(struct inode * inode, unsigned long address)
{
struct task_struct ** p;
@@ -378,21 +416,34 @@ static int share_page(struct m_inode * inode, unsigned long address)
return 0;
}
-void do_no_page(unsigned long error_code,unsigned long address)
+void do_no_page(unsigned long error_code,
+ unsigned long address, struct task_struct *tsk)
{
+ static unsigned int last_checked = 0;
int nr[4];
unsigned long tmp;
unsigned long page;
int block,i;
- struct m_inode * inode;
+ struct inode * inode;
+ /* Trashing ? Make it interruptible, but don't penalize otherwise */
+ for (i = 0; i < CHECK_LAST_NR; i++)
+ if ((address & 0xfffff000) == last_pages[i]) {
+ current->counter = 0;
+ schedule();
+ }
+ last_checked++;
+ if (last_checked >= CHECK_LAST_NR)
+ last_checked = 0;
+ last_pages[last_checked] = address & 0xfffff000;
if (address < TASK_SIZE)
printk("\n\rBAD!! KERNEL PAGE MISSING\n\r");
- if (address - current->start_code > TASK_SIZE) {
+ if (address - tsk->start_code >= TASK_SIZE) {
printk("Bad things happen: nonexistent page error in do_no_page\n\r");
do_exit(SIGSEGV);
}
page = *(unsigned long *) ((address >> 20) & 0xffc);
+/* check the page directory: make a page dir entry if no such exists */
if (page & 1) {
page &= 0xfffff000;
page += (address >> 10) & 0xffc;
@@ -401,14 +452,21 @@ void do_no_page(unsigned long error_code,unsigned long address)
swap_in((unsigned long *) page);
return;
}
+ } else {
+ if (page)
+ printk("do_no_page: bad page directory\n");
+ if (!(page = get_free_page()))
+ oom();
+ page |= 7;
+ *(unsigned long *) ((address >> 20) & 0xffc) = page;
}
address &= 0xfffff000;
- tmp = address - current->start_code;
+ tmp = address - tsk->start_code;
if (tmp >= LIBRARY_OFFSET ) {
- inode = current->library;
+ inode = tsk->library;
block = 1 + (tmp-LIBRARY_OFFSET) / BLOCK_SIZE;
- } else if (tmp < current->end_data) {
- inode = current->executable;
+ } else if (tmp < tsk->end_data) {
+ inode = tsk->executable;
block = 1 + tmp / BLOCK_SIZE;
} else {
inode = NULL;
@@ -418,6 +476,7 @@ void do_no_page(unsigned long error_code,unsigned long address)
get_empty_page(address);
return;
}
+ if (tsk == current)
if (share_page(inode,tmp))
return;
if (!(page = get_free_page()))
@@ -426,7 +485,7 @@ void do_no_page(unsigned long error_code,unsigned long address)
for (i=0 ; i<4 ; block++,i++)
nr[i] = bmap(inode,block);
bread_page(page,inode->i_dev,nr);
- i = tmp + 4096 - current->end_data;
+ i = tmp + 4096 - tsk->end_data;
if (i>4095)
i = 0;
tmp = page + 4096;
@@ -444,6 +503,8 @@ void mem_init(long start_mem, long end_mem)
{
int i;
+ swap_device = 0;
+ swap_file = NULL;
HIGH_MEMORY = end_mem;
for (i=0 ; i<PAGING_PAGES ; i++)
mem_map[i] = USED;
@@ -478,6 +539,7 @@ void show_mem(void)
if (pg_dir[i]>HIGH_MEMORY) {
printk("page directory[%d]: %08X\n\r",
i,pg_dir[i]);
+ i++;
continue;
}
if (pg_dir[i]>LOW_MEM)
@@ -500,3 +562,22 @@ void show_mem(void)
}
printk("Memory found: %d (%d)\n\r",free-shared,total);
}
+
+
+/* This routine handles page faults. It determines the address,
+ and the problem then passes it off to one of the appropriate
+ routines. */
+void do_page_fault (unsigned long *esp, unsigned long error_code)
+{
+ unsigned long address;
+ /* get the address */
+
+ __asm__ ("movl %%cr2,%0":"=r" (address));
+ if (!(error_code & 1)) {
+ do_no_page(error_code, address, current);
+ return;
+ } else {
+ do_wp_page(error_code, address);
+ return;
+ }
+}
diff --git a/mm/swap.c b/mm/swap.c
index 327259b..4c621d0 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -10,8 +10,10 @@
*/
#include <string.h>
+#include <errno.h>
#include <linux/mm.h>
+#include <sys/stat.h>
#include <linux/sched.h>
#include <linux/head.h>
#include <linux/kernel.h>
@@ -33,7 +35,30 @@ bitop(setbit,"s")
bitop(clrbit,"r")
static char * swap_bitmap = NULL;
-int SWAP_DEV = 0;
+unsigned int swap_device = 0;
+struct inode * swap_file = NULL;
+
+void rw_swap_page(int rw, unsigned int nr, char * buf)
+{
+ unsigned int zones[4];
+ int i;
+
+ if (swap_device) {
+ ll_rw_page(rw,swap_device,nr,buf);
+ return;
+ }
+ if (swap_file) {
+ nr <<= 2;
+ for (i = 0; i < 4; i++)
+ if (!(zones[i] = bmap(swap_file,nr++))) {
+ printk("rw_swap_page: bad swap file\n");
+ return;
+ }
+ ll_rw_swap_file(rw,swap_file->i_dev, zones,4,buf);
+ return;
+ }
+ printk("ll_swap_page: no swap file or device\n");
+}
/*
* We never page the pages in task[0] - kernel memory.
@@ -49,7 +74,7 @@ static int get_swap_page(void)
if (!swap_bitmap)
return 0;
- for (nr = 1; nr < 32768 ; nr++)
+ for (nr = 1; nr < SWAP_BITS ; nr++)
if (clrbit(swap_bitmap,nr))
return nr;
return 0;
@@ -62,7 +87,7 @@ void swap_free(int swap_nr)
if (swap_bitmap && swap_nr < SWAP_BITS)
if (!setbit(swap_bitmap,swap_nr))
return;
- printk("Swap-space bad (swap_free())\n\r");
+ printk("swap_free: swap-space bitmap bad\n");
return;
}
@@ -114,6 +139,7 @@ int try_to_swap_out(unsigned long * table_ptr)
free_page(page);
return 1;
}
+ page &= 0xfffff000;
*table_ptr = 0;
invalidate();
free_page(page);
@@ -121,42 +147,41 @@ int try_to_swap_out(unsigned long * table_ptr)
}
/*
- * Ok, this has a rather intricate logic - the idea is to make good
- * and fast machine code. If we didn't worry about that, things would
- * be easier.
+ * Go through the page tables, searching for a user page that
+ * we can swap out.
*/
int swap_out(void)
{
- static int dir_entry = FIRST_VM_PAGE>>10;
+ static int dir_entry = 1024;
static int page_entry = -1;
int counter = VM_PAGES;
- int pg_table;
+ int pg_table = 0;
- while (counter>0) {
- pg_table = pg_dir[dir_entry];
- if (pg_table & 1)
- break;
+repeat:
+ while (counter > 0) {
counter -= 1024;
dir_entry++;
if (dir_entry >= 1024)
dir_entry = FIRST_VM_PAGE>>10;
+ if (pg_table = pg_dir[dir_entry])
+ break;
+ }
+ if (counter <= 0) {
+ printk("Out of swap-memory\n");
+ return 0;
+ }
+ if (!(pg_table & 1)) {
+ printk("bad page-table at pg_dir[%d]: %08x\n\r",dir_entry,
+ pg_table);
+ return 0;
}
pg_table &= 0xfffff000;
- while (counter-- > 0) {
+ while (counter > 0) {
+ counter--;
page_entry++;
if (page_entry >= 1024) {
- page_entry = 0;
- repeat:
- dir_entry++;
- if (dir_entry >= 1024)
- dir_entry = FIRST_VM_PAGE>>10;
- pg_table = pg_dir[dir_entry];
- if (!(pg_table&1))
- if ((counter -= 1024) > 0)
- goto repeat;
- else
- break;
- pg_table &= 0xfffff000;
+ page_entry = -1;
+ goto repeat;
}
if (try_to_swap_out(page_entry + (unsigned long *) pg_table))
return 1;
@@ -171,7 +196,7 @@ int swap_out(void)
*/
unsigned long get_free_page(void)
{
-register unsigned long __res asm("ax");
+ unsigned long result;
repeat:
__asm__("std ; repne ; scasb\n\t"
@@ -184,70 +209,82 @@ repeat:
"leal 4092(%%edx),%%edi\n\t"
"rep ; stosl\n\t"
"movl %%edx,%%eax\n"
- "1:"
- :"=a" (__res)
+ "1:\tcld"
+ :"=a" (result)
:"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
"D" (mem_map+PAGING_PAGES-1)
:"di","cx","dx");
- if (__res >= HIGH_MEMORY)
+ if (result >= HIGH_MEMORY)
goto repeat;
- if (!__res && swap_out())
+ if ((result && result < LOW_MEM) || (result & 0xfff)) {
+ printk("weird result: %08x\n",result);
+ result = 0;
+ }
+ if (!result && swap_out())
goto repeat;
- return __res;
+ return result;
}
-void init_swapping(void)
+/*
+ * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
+ *
+ * The swapon system call
+ */
+
+int sys_swapon(const char * specialfile)
{
- extern int *blk_size[];
- int swap_size,i,j;
+ struct inode * swap_inode;
+ int i,j;
- if (!SWAP_DEV)
- return;
- if (!blk_size[MAJOR(SWAP_DEV)]) {
- printk("Unable to get size of swap device\n\r");
- return;
+ if (!suser())
+ return -EPERM;
+ if (!(swap_inode = namei(specialfile)))
+ return -ENOENT;
+ if (swap_file || swap_device || swap_bitmap) {
+ iput(swap_inode);
+ return -EBUSY;
}
- swap_size = blk_size[MAJOR(SWAP_DEV)][MINOR(SWAP_DEV)];
- if (!swap_size)
- return;
- if (swap_size < 100) {
- printk("Swap device too small (%d blocks)\n\r",swap_size);
- return;
+ if (S_ISBLK(swap_inode->i_mode)) {
+ swap_device = swap_inode->i_rdev;
+ iput(swap_inode);
+ } else if (S_ISREG(swap_inode->i_mode))
+ swap_file = swap_inode;
+ else {
+ iput(swap_inode);
+ return -EINVAL;
}
- swap_size >>= 2;
- if (swap_size > SWAP_BITS)
- swap_size = SWAP_BITS;
swap_bitmap = (char *) get_free_page();
if (!swap_bitmap) {
- printk("Unable to start swapping: out of memory :-)\n\r");
- return;
+ iput(swap_file);
+ swap_device = 0;
+ swap_file = NULL;
+ printk("Unable to start swapping: out of memory :-)\n");
+ return -ENOMEM;
}
read_swap_page(0,swap_bitmap);
if (strncmp("SWAP-SPACE",swap_bitmap+4086,10)) {
printk("Unable to find swap-space signature\n\r");
free_page((long) swap_bitmap);
+ iput(swap_file);
+ swap_device = 0;
+ swap_file = NULL;
swap_bitmap = NULL;
- return;
+ return -EINVAL;
}
memset(swap_bitmap+4086,0,10);
- for (i = 0 ; i < SWAP_BITS ; i++) {
- if (i == 1)
- i = swap_size;
- if (bit(swap_bitmap,i)) {
- printk("Bad swap-space bit-map\n\r");
- free_page((long) swap_bitmap);
- swap_bitmap = NULL;
- return;
- }
- }
j = 0;
- for (i = 1 ; i < swap_size ; i++)
+ for (i = 1 ; i < SWAP_BITS ; i++)
if (bit(swap_bitmap,i))
j++;
if (!j) {
+ printk("Empty swap-file\n");
free_page((long) swap_bitmap);
+ iput(swap_file);
+ swap_device = 0;
+ swap_file = NULL;
swap_bitmap = NULL;
- return;
+ return -EINVAL;
}
- printk("Swap device ok: %d pages (%d bytes) swap-space\n\r",j,j*4096);
+ printk("Adding Swap: %d pages (%d bytes) swap-space\n\r",j,j*4096);
+ return 0;
}
diff --git a/tools/build.c b/tools/build.c
index 32d2efb..1fa477b 100644
--- a/tools/build.c
+++ b/tools/build.c
@@ -18,8 +18,6 @@
/*
* Changes by tytso to allow root device specification
- *
- * Added swap-device specification: Linux 20.12.91
*/
#include <stdio.h> /* fprintf */
@@ -34,13 +32,10 @@
#define MINIX_HEADER 32
#define GCC_HEADER 1024
-#define SYS_SIZE 0x3000
-
-#define DEFAULT_MAJOR_ROOT 3
-#define DEFAULT_MINOR_ROOT 6
+#define SYS_SIZE 0x4000
-#define DEFAULT_MAJOR_SWAP 0
-#define DEFAULT_MINOR_SWAP 0
+#define DEFAULT_MAJOR_ROOT 0
+#define DEFAULT_MINOR_ROOT 0
/* max nr of sectors of setup: don't change unless you also change
* bootsect etc */
@@ -64,10 +59,9 @@ int main(int argc, char ** argv)
int i,c,id;
char buf[1024];
char major_root, minor_root;
- char major_swap, minor_swap;
struct stat sb;
- if ((argc < 4) || (argc > 6))
+ if ((argc < 4) || (argc > 5))
usage();
if (argc > 4) {
if (strcmp(argv[4], "FLOPPY")) {
@@ -85,35 +79,13 @@ int main(int argc, char ** argv)
major_root = DEFAULT_MAJOR_ROOT;
minor_root = DEFAULT_MINOR_ROOT;
}
- if (argc == 6) {
- if (strcmp(argv[5], "NONE")) {
- if (stat(argv[5], &sb)) {
- perror(argv[5]);
- die("Couldn't stat root device.");
- }
- major_swap = MAJOR(sb.st_rdev);
- minor_swap = MINOR(sb.st_rdev);
- } else {
- major_swap = 0;
- minor_swap = 0;
- }
- } else {
- major_swap = DEFAULT_MAJOR_SWAP;
- minor_swap = DEFAULT_MINOR_SWAP;
- }
fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
- fprintf(stderr, "Swap device is (%d, %d)\n", major_swap, minor_swap);
if ((major_root != 2) && (major_root != 3) &&
(major_root != 0)) {
fprintf(stderr, "Illegal root device (major = %d)\n",
major_root);
die("Bad root device --- major #");
}
- if (major_swap && major_swap != 3) {
- fprintf(stderr, "Illegal swap device (major = %d)\n",
- major_swap);
- die("Bad root device --- major #");
- }
for (i=0;i<sizeof buf; i++) buf[i]=0;
if ((id=open(argv[1],O_RDONLY,0))<0)
die("Unable to open 'boot'");
@@ -137,8 +109,6 @@ int main(int argc, char ** argv)
die("Boot block must be exactly 512 bytes");
if ((*(unsigned short *)(buf+510)) != 0xAA55)
die("Boot block hasn't got boot flag (0xAA55)");
- buf[506] = (char) minor_swap;
- buf[507] = (char) major_swap;
buf[508] = (char) minor_root;
buf[509] = (char) major_root;
i=write(1,buf,512);