From e6c7a63f3cc9898b82d65ac3bda90d543a471c17 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:09:00 -0500 Subject: [PATCH] [PATCH] Linux-0.95 (March 8, 1992) This was the first kernel that got released under the GPL (0.12 had a time-lapse to make sure the people involved accepted the license change: nobody ever complained). Because 0.12 had been so successful, this was supposed to be closer to 1.0. Yeah, right. 1.0 was eventually released almost exactly two years later.. The big change here is the first signs of a real VFS layer: while the only available filesystem is still the Minix-compatible one, the code is factored out, and the Minix-specific stuff is put in its own directory. You can clearly see how the thing is moving towards having multiple different filesystems. The VFS changes also cause cleanups in various drivers, since we end up having more clear inode operation structure pointer handling. Superblock handling is still minix-specific.. NOTE! We also have /bin/init finally. It still falls through to the old "run shells forever" case if no init can be found, but it's starting to look a whole more like real UNIX user-land now.. New developers: Ross Biro shows up, and does ptrace. He will later end up doing the first-generation networking code. Other changes: - UK and Danish keyboard maps (and the keyboard driver supported "Application mode" keys from vt100+) - Make sure interrupts clear the 'D'irection flag - Floppy driver gets track buffer, which speeds it up immensely. This was done based on patches by Lawrence Foard (entropy@wintermute.wpi.edu) - Lots of buffer cache cleanups. - support nonblocking pipe file descriptors - recursive symlink support - sys_swapon() means that we don't have to select the swap device at build (or boot) time ("Written 01/25/92 by Simmule Turner, heavily changed by Linus") - start some generic timer work (ugh, but these first timers were _horrible_ hardcoded things) - ptrace for debugging - console size query support with TIOC[G|S]WINSZ - /dev/kmem ("by Damiano") - rebooting (with ctrl-alt-del or sys_reboot()). From the release notes: 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 even better to vt200 control codes than 0.11. Special graphic characters etc: you can well use them as terminals to VMS (although that's a shameful waste of resources), 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) --- Makefile | 34 +- boot/bootsect.S | 2 +- boot/head.s | 53 ++- boot/setup.S | 13 +- fs/Makefile | 55 +-- fs/block_dev.c | 28 +- fs/buffer.c | 105 +++-- fs/char_dev.c | 56 ++- fs/exec.c | 24 +- fs/fcntl.c | 6 +- fs/inode.c | 226 +++-------- fs/ioctl.c | 4 +- fs/minix/Makefile | 69 ++++ fs/{ => minix}/bitmap.c | 115 +++--- fs/{ => minix}/file_dev.c | 51 ++- fs/minix/inode.c | 145 +++++++ fs/minix/minix_op.c | 38 ++ fs/minix/namei.c | 795 +++++++++++++++++++++++++++++++++++++ fs/minix/truncate.c | 154 +++++++ fs/namei.c | 758 ++++++++--------------------------- fs/open.c | 71 +--- fs/pipe.c | 25 +- fs/read_write.c | 74 ++-- fs/select.c | 22 +- fs/stat.c | 40 +- fs/super.c | 68 ++-- fs/truncate.c | 99 ----- include/asm/io.h | 45 ++- include/asm/segment.h | 12 +- include/asm/system.h | 10 +- include/errno.h | 1 + include/fcntl.h | 2 +- include/linux/config.h | 11 +- include/linux/fs.h | 133 +++---- include/linux/hdreg.h | 18 +- include/linux/kernel.h | 9 - include/linux/math_emu.h | 19 +- include/linux/minix_fs.h | 78 ++++ include/linux/mm.h | 12 +- include/linux/sched.h | 55 ++- include/linux/sys.h | 4 +- include/linux/timer.h | 44 ++ include/linux/tty.h | 8 +- include/signal.h | 20 + include/string.h | 32 +- include/sys/ptrace.h | 52 +++ include/sys/time.h | 1 + include/sys/types.h | 3 +- include/termios.h | 1 + include/time.h | 2 +- include/unistd.h | 29 +- init/main.c | 20 +- init/main.s | 551 ------------------------- kernel/Makefile | 32 +- kernel/asm.s | 107 +++-- kernel/blk_drv/Makefile | 23 +- kernel/blk_drv/blk.h | 17 +- kernel/blk_drv/floppy.c | 125 ++++-- kernel/blk_drv/hd.c | 140 ++++--- kernel/blk_drv/ll_rw_blk.c | 82 +++- kernel/blk_drv/ramdisk.c | 5 +- kernel/chr_drv/Makefile | 25 +- kernel/chr_drv/console.c | 457 ++++++++++++++------- kernel/chr_drv/keyboard.S | 348 ++++++++++++---- kernel/chr_drv/rs_io.s | 11 +- kernel/chr_drv/serial.c | 56 ++- kernel/chr_drv/tty_io.c | 80 ++-- kernel/chr_drv/tty_ioctl.c | 130 +++++- kernel/exit.c | 81 ++-- kernel/fork.c | 53 ++- kernel/math/Makefile | 47 ++- kernel/math/convert.c | 73 +++- kernel/math/error.c | 2 +- kernel/math/get_put.c | 2 +- kernel/math/math_emulate.c | 30 +- kernel/math/mul.c | 2 +- kernel/ptrace.c | 322 +++++++++++++++ kernel/sched.c | 71 ++-- kernel/signal.c | 25 +- kernel/sys.c | 48 ++- kernel/sys_call.s | 168 ++++---- kernel/traps.c | 28 +- lib/Makefile | 13 +- lib/_exit.c | 3 +- lib/open.c | 5 +- mm/Makefile | 20 +- mm/memory.c | 185 ++++++--- mm/page.s | 40 -- mm/swap.c | 165 +++++--- tools/build.c | 38 +- 90 files changed, 4503 insertions(+), 2858 deletions(-) create mode 100644 fs/minix/Makefile rename fs/{ => minix}/bitmap.c (54%) rename fs/{ => minix}/file_dev.c (59%) create mode 100644 fs/minix/inode.c create mode 100644 fs/minix/minix_op.c create mode 100644 fs/minix/namei.c create mode 100644 fs/minix/truncate.c delete mode 100644 fs/truncate.c create mode 100644 include/linux/minix_fs.h create mode 100644 include/linux/timer.h create mode 100644 include/sys/ptrace.h delete mode 100644 init/main.s create mode 100644 kernel/ptrace.c delete mode 100644 mm/page.s diff --git a/Makefile b/Makefile index 1cb2861d8488..8bedb81b8ebf 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 1df6c2317d7b..8a8ecb89b09a 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 de56a74aa24f..037713941a85 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 093f96c86807..1befd14f1311 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 96d8de1fa49f..55bcd62b6dd7 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 af7cbdaf0497..e4a4e9ed6f2d 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 f0f3fb30bbc1..2ece7792b240 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 ; ib_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 ; ib_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 ; ib_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)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 #include -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 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 d5136f2e81c8..2195ff99f7fd 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 c201aa840fbc..ab7fe1f21c68 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 5c56663d889c..dd68b1d29d90 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -8,18 +8,17 @@ #include #include +#include #include #include #include -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= 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 ; ii_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) { 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 c7b41eb90309..d293a929fd47 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -11,7 +11,7 @@ #include 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 000000000000..967bda58f589 --- /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/bitmap.c b/fs/minix/bitmap.c similarity index 54% rename from fs/bitmap.c rename to fs/minix/bitmap.c index ec733d049d88..645db74b0c9e 100644 --- a/fs/bitmap.c +++ b/fs/minix/bitmap.c @@ -8,6 +8,7 @@ #include #include +#include #include #define clear_block(addr) \ @@ -17,15 +18,15 @@ __asm__("cld\n\t" \ ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di") #define set_bit(nr,addr) ({\ -register int res __asm__("ax"); \ -__asm__ __volatile__("btsl %2,%3\n\tsetb %%al": \ -"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \ +char res; \ +__asm__ __volatile__("btsl %1,%2\n\tsetb %0": \ +"=q" (res):"r" (nr),"m" (*(addr))); \ res;}) #define clear_bit(nr,addr) ({\ -register int res __asm__("ax"); \ -__asm__ __volatile__("btrl %2,%3\n\tsetnb %%al": \ -"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \ +char res; \ +__asm__ __volatile__("btrl %1,%2\n\tsetnb %0": \ +"=q" (res):"r" (nr),"m" (*(addr))); \ res;}) #define find_first_zero(addr) ({ \ @@ -34,20 +35,20 @@ __asm__("cld\n" \ "1:\tlodsl\n\t" \ "notl %%eax\n\t" \ "bsfl %%eax,%%edx\n\t" \ - "je 2f\n\t" \ - "addl %%edx,%%ecx\n\t" \ - "jmp 3f\n" \ - "2:\taddl $32,%%ecx\n\t" \ + "jne 2f\n\t" \ + "addl $32,%%ecx\n\t" \ "cmpl $8192,%%ecx\n\t" \ - "jl 1b\n" \ - "3:" \ - :"=c" (__res):"c" (0),"S" (addr):"ax","dx","si"); \ + "jl 1b\n\t" \ + "xorl %%edx,%%edx\n" \ + "2:\taddl %%edx,%%ecx" \ + :"=c" (__res):"0" (0),"S" (addr):"ax","dx","si"); \ __res;}) -int free_block(int dev, int block) +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"); @@ -64,16 +65,17 @@ int free_block(int dev, int block) if (bh->b_count) brelse(bh); } - block -= sb->s_firstdatazone - 1 ; - if (clear_bit(block&8191,sb->s_zmap[block/8192]->b_data)) { - printk("block (%04x:%d) ",dev,block+sb->s_firstdatazone-1); - printk("free_block: bit already cleared\n"); - } - sb->s_zmap[block/8192]->b_dirt = 1; + 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 new_block(int dev) +int minix_new_block(int dev) { struct buffer_head * bh; struct super_block * sb; @@ -105,9 +107,8 @@ int new_block(int dev) return j; } -void free_inode(struct m_inode * inode) +void minix_free_inode(struct inode * inode) { - struct super_block * sb; struct buffer_head * bh; if (!inode) @@ -117,53 +118,67 @@ void free_inode(struct m_inode * inode) return; } if (inode->i_count>1) { - printk("trying to free inode with count=%d\n",inode->i_count); - panic("free_inode"); + 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_nlinks) - panic("trying to free inode with links"); - if (!(sb = get_super(inode->i_dev))) - panic("trying to free inode on nonexistent device"); - if (inode->i_num < 1 || inode->i_num > sb->s_ninodes) - panic("trying to free inode 0 or nonexistant inode"); - if (!(bh=sb->s_imap[inode->i_num>>13])) - panic("nonexistent imap in superblock"); - if (clear_bit(inode->i_num&8191,bh->b_data)) + 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 m_inode * new_inode(int dev) +struct inode * minix_new_inode(int dev) { - struct m_inode * inode; - struct super_block * sb; + struct inode * inode; struct buffer_head * bh; int i,j; if (!(inode=get_empty_inode())) return NULL; - if (!(sb = get_super(dev))) - panic("new_inode with unknown device"); + 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=sb->s_imap[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 > sb->s_ninodes) { + 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; } - if (set_bit(j,bh->b_data)) - panic("new_inode: bit already set"); bh->b_dirt = 1; - inode->i_count=1; - inode->i_nlinks=1; - inode->i_dev=dev; - inode->i_uid=current->euid; - inode->i_gid=current->egid; - inode->i_dirt=1; - inode->i_num = j + i*8192; + 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/file_dev.c b/fs/minix/file_dev.c similarity index 59% rename from fs/file_dev.c rename to fs/minix/file_dev.c index 0c50eaa86ba6..646ba0e24d0a 100644 --- a/fs/file_dev.c +++ b/fs/minix/file_dev.c @@ -8,29 +8,36 @@ #include #include +#include #include #include #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) -int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) +int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count) { - int left,chars,nr; + int read,left,chars,nr; struct buffer_head * bh; - if ((left=count)<=0) - return 0; - while (left) { - if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) { + 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))) - break; + return read?read:-EIO; } else bh = NULL; - nr = filp->f_pos % BLOCK_SIZE; + 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) @@ -42,16 +49,15 @@ int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) } } inode->i_atime = CURRENT_TIME; - return (count-left)?(count-left):-ERROR; + return read; } -int file_write(struct m_inode * inode, struct file * filp, char * buf, int count) +int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count) { off_t pos; - int block,c; + int written,block,c; struct buffer_head * bh; char * p; - int i=0; /* * ok, append may not work when many processes are writing at the same time @@ -61,22 +67,30 @@ int file_write(struct m_inode * inode, struct file * filp, char * buf, int count pos = inode->i_size; else pos = filp->f_pos; - while (ii_dev,block))) + } + 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-i) c = count-i; + if (c > count-written) + c = count-written; pos += c; if (pos > inode->i_size) { inode->i_size = pos; inode->i_dirt = 1; } - i += c; + written += c; while (c-->0) *(p++) = get_fs_byte(buf++); brelse(bh); @@ -85,6 +99,7 @@ int file_write(struct m_inode * inode, struct file * filp, char * buf, int count if (!(filp->f_flags & O_APPEND)) { filp->f_pos = pos; inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; } - return (i?i:-1); + return written; } diff --git a/fs/minix/inode.c b/fs/minix/inode.c new file mode 100644 index 000000000000..a4dab0533df2 --- /dev/null +++ b/fs/minix/inode.c @@ -0,0 +1,145 @@ +/* + * linux/fs/minix/inode.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include + +#include +#include +#include +#include +#include + +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 000000000000..a85e3a89104d --- /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 +#include + +/* + * 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 000000000000..d3c0224ca5ce --- /dev/null +++ b/fs/minix/namei.c @@ -0,0 +1,795 @@ +/* + * linux/fs/minix/namei.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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]=(ib_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= (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 (ib_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 000000000000..4f163bd170d9 --- /dev/null +++ b/fs/minix/truncate.c @@ -0,0 +1,154 @@ +/* + * linux/fs/truncate.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include +#include + +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 8b99d707e831..f1a0e8f6a0fb 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -9,6 +9,7 @@ */ #include +#include #include #include @@ -18,21 +19,17 @@ #include #include -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]=(ib_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= (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 92c897369f7a..9653b8345919 100644 --- a/fs/open.c +++ b/fs/open.c @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -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 ; fdfilp[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 38ea99d4cff4..d1b6e7c7819d 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -7,25 +7,26 @@ #include #include #include +#include #include -#include /* for get_free_page */ #include #include -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 341274acde8e..da81a6fb2533 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -12,26 +12,20 @@ #include #include -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 24c84efcc8d2..053b1ab3f3c1 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 b4f36fe1705e..029ec2ff7bf9 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -12,19 +12,19 @@ #include #include -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 (ib_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 20c1c9bf0637..eedff32e1368 100644 --- a/fs/super.c +++ b/fs/super.c @@ -9,6 +9,7 @@ */ #include #include +#include #include #include @@ -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;is_imap[i]); - for(i=0;is_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;is_imap[i] = NULL; - for (i=0;is_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;is_imap[i]); - for(i=0;is_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 ; inodei_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;ii_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/fs/truncate.c b/fs/truncate.c deleted file mode 100644 index 32bc19d43b61..000000000000 --- a/fs/truncate.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * linux/fs/truncate.c - * - * (C) 1991 Linus Torvalds - */ - -#include - -#include - -static int 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 (free_block(dev,*p)) { - *p = 0; - bh->b_dirt = 1; - } else - block_busy = 1; - brelse(bh); - } - if (block_busy) - return 0; - else - return free_block(dev,block); -} - -static int 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 (free_ind(dev,*p)) { - *p = 0; - bh->b_dirt = 1; - } else - block_busy = 1; - brelse(bh); - } - if (block_busy) - return 0; - else - return free_block(dev,block); -} - -void truncate(struct m_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_zone[i]) { - if (free_block(inode->i_dev,inode->i_zone[i])) - inode->i_zone[i]=0; - else - block_busy = 1; - } - if (free_ind(inode->i_dev,inode->i_zone[7])) - inode->i_zone[7] = 0; - else - block_busy = 1; - if (free_dind(inode->i_dev,inode->i_zone[8])) - inode->i_zone[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; -} - diff --git a/include/asm/io.h b/include/asm/io.h index d5cc42a6d015..118249acbf23 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 c03657f2acde..5efc9e7b3e87 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 c112e104c41d..6f5f670bad04 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 6f35d037da4c..a38b78fd239c 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 a5bf9af52978..4bc0c10cf2b0 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 a30130e73a1f..ca364b629122 100644 --- a/include/linux/config.h +++ b/include/linux/config.h @@ -1,6 +1,15 @@ #ifndef _CONFIG_H #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 */ @@ -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 5e6768fb6e60..0c7b2e9b10bd 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 e6c593f0bd19..883c7ae70ee7 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 d294d85edff5..eab299bc3b17 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 abe0cc2118f5..c5501b6eae0d 100644 --- a/include/linux/math_emu.h +++ b/include/linux/math_emu.h @@ -9,20 +9,20 @@ #include 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 000000000000..4ccb8458361e --- /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 + +#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 94c37132d331..e1eacea98b03 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -3,13 +3,19 @@ #define PAGE_SIZE 4096 +#include #include #include -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 8f1ef9b125f3..d903e2daf671 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 2a1c8be2c263..1e6f2c3daf5b 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 000000000000..295738e64f2b --- /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 c3d7af69ab65..4812f85aff08 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 462556d5be45..e4126d339125 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 05a6d9cfa1a7..7da1793d138e 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> fd) & 1) diff --git a/include/sys/types.h b/include/sys/types.h index aa260c84b9b4..5e220faa3794 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 3c2937b6b8fa..faa6e53ef01d 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 fbb4e7357f82..f7e7ba1982ee 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 b72f6b05c96a..622aa6f19aa5 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 5fd2cdbd8a87..1739de5de754 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/init/main.s b/init/main.s deleted file mode 100644 index ad0c2403acbd..000000000000 --- a/init/main.s +++ /dev/null @@ -1,551 +0,0 @@ - .file "init/main.c" -gcc_compiled.: -.text -LC0: - .ascii "out of memory\12\15\0" - .align 2 -_sprintf: - movl 4(%esp),%edx - leal 12(%esp),%eax - pushl %eax - pushl 12(%esp) - pushl %edx - call _vsprintf - addl $12,%esp - ret - .align 2 -_time_init: - pushl %ebp - movl %esp,%ebp - subl $44,%esp -L65: - movl $128,%eax - movl $112,%edx -/APP - outb %al,%dx - jmp 1f -1: jmp 1f -1: -/NO_APP - movl $113,%edx -/APP - inb %dx,%al - jmp 1f -1: jmp 1f -1: -/NO_APP - movb %al,-40(%ebp) - movzbl -40(%ebp),%eax - movl %eax,-36(%ebp) - movl $130,%eax - movl $112,%edx -/APP - outb %al,%dx - jmp 1f -1: jmp 1f -1: -/NO_APP - movl $113,%edx -/APP - inb %dx,%al - jmp 1f -1: jmp 1f -1: -/NO_APP - movb %al,-40(%ebp) - movzbl -40(%ebp),%eax - movl %eax,-32(%ebp) - movl $132,%eax - movl $112,%edx -/APP - outb %al,%dx - jmp 1f -1: jmp 1f -1: -/NO_APP - movl $113,%edx -/APP - inb %dx,%al - jmp 1f -1: jmp 1f -1: -/NO_APP - movb %al,-40(%ebp) - movzbl -40(%ebp),%eax - movl %eax,-28(%ebp) - movl $135,%eax - movl $112,%edx -/APP - outb %al,%dx - jmp 1f -1: jmp 1f -1: -/NO_APP - movl $113,%edx -/APP - inb %dx,%al - jmp 1f -1: jmp 1f -1: -/NO_APP - movb %al,-40(%ebp) - movzbl -40(%ebp),%eax - movl %eax,-24(%ebp) - movl $136,%eax - movl $112,%edx -/APP - outb %al,%dx - jmp 1f -1: jmp 1f -1: -/NO_APP - movl $113,%edx -/APP - inb %dx,%al - jmp 1f -1: jmp 1f -1: -/NO_APP - movb %al,-40(%ebp) - movzbl -40(%ebp),%eax - movl %eax,-20(%ebp) - movl $137,%eax - movl $112,%edx -/APP - outb %al,%dx - jmp 1f -1: jmp 1f -1: -/NO_APP - movl $113,%edx -/APP - inb %dx,%al - jmp 1f -1: jmp 1f -1: -/NO_APP - movb %al,-40(%ebp) - movzbl -40(%ebp),%eax - movl %eax,-16(%ebp) - movl $128,%eax - movl $112,%edx -/APP - outb %al,%dx - jmp 1f -1: jmp 1f -1: -/NO_APP - movl $113,%edx -/APP - inb %dx,%al - jmp 1f -1: jmp 1f -1: -/NO_APP - movb %al,-40(%ebp) - movzbl -40(%ebp),%eax - cmpl -36(%ebp),%eax - jne L65 - movl -36(%ebp),%eax - andl $15,%eax - movl -36(%ebp),%edx - sarl $4,%edx - leal (%edx,%edx,4),%edx - leal (%eax,%edx,2),%eax - movl %eax,-36(%ebp) - movl -32(%ebp),%eax - andl $15,%eax - movl -32(%ebp),%edx - sarl $4,%edx - leal (%edx,%edx,4),%edx - leal (%eax,%edx,2),%eax - movl %eax,-32(%ebp) - movl -28(%ebp),%eax - andl $15,%eax - movl -28(%ebp),%edx - sarl $4,%edx - leal (%edx,%edx,4),%edx - leal (%eax,%edx,2),%eax - movl %eax,-28(%ebp) - movl -24(%ebp),%eax - andl $15,%eax - movl -24(%ebp),%edx - sarl $4,%edx - leal (%edx,%edx,4),%edx - leal (%eax,%edx,2),%eax - movl %eax,-24(%ebp) - movl -20(%ebp),%eax - andl $15,%eax - movl -20(%ebp),%edx - sarl $4,%edx - leal (%edx,%edx,4),%edx - leal (%eax,%edx,2),%eax - movl %eax,-20(%ebp) - movl -16(%ebp),%eax - andl $15,%eax - movl -16(%ebp),%edx - sarl $4,%edx - leal (%edx,%edx,4),%edx - leal (%eax,%edx,2),%eax - movl %eax,-16(%ebp) - decl -20(%ebp) - leal -36(%ebp),%eax - pushl %eax - call _kernel_mktime - movl %eax,_startup_time - leave - ret -.data - .align 2 -_memory_end: - .long 0 - .align 2 -_buffer_memory_end: - .long 0 - .align 2 -_main_memory_start: - .long 0 -.text -LC1: - .ascii "/bin/sh\0" -.data - .align 2 -_argv_rc: - .long LC1 - .long 0 -.text -LC2: - .ascii "HOME=/\0" -.data - .align 2 -_envp_rc: - .long LC2 - .long 0 - .long 0 -.text -LC3: - .ascii "-/bin/sh\0" -.data - .align 2 -_argv: - .long LC3 - .long 0 -.text -LC4: - .ascii "HOME=/usr/root\0" -.data - .align 2 -_envp: - .long LC4 - .long 0 - .long 0 -.text -LC5: - .ascii "TERM=con%dx%d\0" - .align 2 -.globl _main -_main: - pushl %ebp - movl %esp,%ebp - subl $8,%esp - pushl %edi - pushl %esi - movzwl 590332,%eax - movl %eax,_ROOT_DEV - movzwl 590330,%eax - movl %eax,_SWAP_DEV - movw 589838,%dx - andl $255,%edx - pushl %edx - movw 589838,%ax - andw $65280,%ax - shrw $8,%ax - movw %ax,-4(%ebp) - movzwl -4(%ebp),%eax - pushl %eax - pushl $LC5 - pushl $_term - call _sprintf - movl $_term,_envp+4 - movl $_term,_envp_rc+4 - movl $_drive_info,%edi - movl $589952,%esi - movl $8,%ecx - cld - rep - movsl - movzwl 589826,%eax - sall $10,%eax - addl $1048576,%eax - movl %eax,_memory_end - andl $-4096,_memory_end - addl $16,%esp - cmpl $16777216,_memory_end - jle L69 - movl $16777216,_memory_end -L69: - cmpl $12582912,_memory_end - jle L70 - movl $4194304,_buffer_memory_end - jmp L71 - .align 2 -L70: - cmpl $6291456,_memory_end - jle L72 - movl $2097152,_buffer_memory_end - jmp L71 - .align 2 -L72: - movl $1048576,_buffer_memory_end -L71: - movl _buffer_memory_end,%eax - movl %eax,_main_memory_start - pushl _memory_end - pushl _buffer_memory_end - call _mem_init - call _trap_init - call _blk_dev_init - call _chr_dev_init - call _tty_init - call _time_init - call _sched_init - pushl _buffer_memory_end - call _buffer_init - call _hd_init - call _floppy_init -/APP - sti - movl %esp,%eax - pushl $0x17 - pushl %eax - pushfl - pushl $0x0f - pushl $1f - iret -1: movl $0x17,%eax - movw %ax,%ds - movw %ax,%es - movw %ax,%fs - movw %ax,%gs -/NO_APP - addl $12,%esp - movl $2,%eax -/APP - int $0x80 -/NO_APP - movl %eax,%edx - testl %edx,%edx - jge L75 - negl %edx - movl %edx,_errno - movl $-1,%edx -L75: - testl %edx,%edx - jne L74 - call _init -L74: -L77: - movl $29,%eax -/APP - int $0x80 -/NO_APP - jmp L77 - .align 2 - leal -16(%ebp),%esp - popl %esi - popl %edi - leave - ret - .align 2 -_printf: - pushl %ebx - leal 12(%esp),%eax - pushl %eax - pushl 12(%esp) - pushl $_printbuf - call _vsprintf - movl %eax,%ebx - pushl %ebx - pushl $_printbuf - pushl $1 - call _write - movl %ebx,%eax - addl $24,%esp - popl %ebx - ret -LC6: - .ascii "/dev/tty1\0" -LC7: - .ascii "%d buffers = %d bytes buffer space\12\15\0" -LC8: - .ascii "Free mem: %d bytes\12\15\0" -LC9: - .ascii "/etc/rc\0" -LC10: - .ascii "Fork failed in init\15\12\0" -LC11: - .ascii "\12\15child %d died with code %04x\12\15\0" - .align 2 -.globl _init -_init: - pushl %ebp - movl %esp,%ebp - subl $4,%esp - pushl %edi - pushl %esi - pushl %ebx - xorl %eax,%eax - movl $_drive_info,%ebx -/APP - int $0x80 -/NO_APP - testl %eax,%eax - jge L82 - negl %eax - movl %eax,_errno -L82: - pushl $0 - pushl $2 - pushl $LC6 - call _open - pushl $0 - call _dup - pushl $0 - call _dup - movl _nr_buffers,%eax - sall $10,%eax - pushl %eax - pushl _nr_buffers - pushl $LC7 - call _printf - addl $32,%esp - movl _memory_end,%eax - subl _main_memory_start,%eax - pushl %eax - pushl $LC8 - call _printf - addl $8,%esp - movl $2,%eax -/APP - int $0x80 -/NO_APP - testl %eax,%eax - jl L86 - movl %eax,%edi - jmp L85 - .align 2 -L86: - negl %eax - movl %eax,_errno - movl $-1,%edi -L85: - testl %edi,%edi - jne L84 - pushl $0 - call _close - pushl $0 - pushl $0 - pushl $LC9 - call _open - addl $16,%esp - testl %eax,%eax - je L87 - pushl $1 - call __exit - .align 2 -L87: - pushl $_envp_rc - pushl $_argv_rc - pushl $LC1 - call _execve - pushl $2 - call __exit - .align 2 -L84: - testl %edi,%edi - jle L88 - leal -4(%ebp),%esi -L89: - pushl %esi - call _wait - addl $4,%esp - cmpl %edi,%eax - jne L89 -L88: - leal -4(%ebp),%esi -L91: - movl $2,%eax -/APP - int $0x80 -/NO_APP - testl %eax,%eax - jge L94 - negl %eax - movl %eax,_errno - movl $-1,%eax -L94: - movl %eax,%edi - testl %edi,%edi - jge L93 - pushl $LC10 - call _printf - addl $4,%esp - jmp L91 - .align 2 -L93: - testl %edi,%edi - jne L96 - pushl $0 - call _close - pushl $1 - call _close - pushl $2 - call _close - call _setsid - pushl $0 - pushl $2 - pushl $LC6 - call _open - pushl $0 - call _dup - pushl $0 - call _dup - addl $32,%esp - pushl $_envp - pushl $_argv - pushl $LC1 - call _execve - pushl %eax - call __exit - .align 2 -L96: -L97: - pushl %esi - call _wait - addl $4,%esp - cmpl %edi,%eax - jne L97 - pushl -4(%ebp) - pushl %edi - pushl $LC11 - call _printf - addl $12,%esp - movl $36,%eax -/APP - int $0x80 -/NO_APP - testl %eax,%eax - jge L91 - negl %eax - movl %eax,_errno - jmp L91 - .align 2 - leal -16(%ebp),%esp - popl %ebx - popl %esi - popl %edi - leave - ret -.comm _drive_info,32 -.lcomm _term,32 -.lcomm _printbuf,1024 diff --git a/kernel/Makefile b/kernel/Makefile index 5f5685f735b0..5a5444f060ba 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 b3bbf8bbea1d..299e4a95983d 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 e1393ac93151..ee05aaab1e19 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 0c62c826d496..28e37d573fbf 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< @@ -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 e6c71695df93..b75b17655cfd 100644 --- a/kernel/blk_drv/hd.c +++ b/kernel/blk_drv/hd.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,7 @@ inb_p(0x71); \ #define MAX_HD 2 static void recal_intr(void); +static void bad_rw_intr(void); static int recalibrate = 0; static int reset = 0; @@ -43,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 }; @@ -56,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") @@ -69,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; @@ -97,8 +125,8 @@ int sys_setup(void * BIOS) NR_HD=1; #endif for (i=0 ; ib_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); } @@ -168,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); } @@ -187,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; @@ -216,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); } @@ -233,16 +252,35 @@ static void reset_controller(void) printk("HD-controller reset failed: %02x\n\r",i); } -static void reset_hd(int nr) +static void reset_hd(void) { - reset_controller(); - hd_out(nr,hd_info[nr].sect,hd_info[nr].sect,hd_info[nr].head-1, - hd_info[nr].cyl,WIN_SPECIFY,&recal_intr); + static int i; + +repeat: + if (reset) { + reset = 0; + i = -1; + reset_controller(); + } else if (win_result()) { + bad_rw_intr(); + if (reset) + goto repeat; + } + i++; + 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(); } void unexpected_hd_interrupt(void) { printk("Unexpected HD interrupt\n\r"); + reset = 1; + do_hd_request(); } static void bad_rw_intr(void) @@ -297,9 +335,13 @@ static void recal_intr(void) do_hd_request(); } -void hd_times_out(void) +static void hd_times_out(void) { + if (!CURRENT) + return; printk("HD timeout"); + if (++CURRENT->errors >= MAX_ERRORS) + end_request(0); SET_INTR(NULL); reset = 1; do_hd_request(); @@ -315,32 +357,35 @@ 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) { - reset = 0; recalibrate = 1; - reset_hd(CURRENT_DEV); + reset_hd(); return; } if (recalibrate) { 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) { @@ -350,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"); } @@ -357,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 9506a067ef89..777dcc3f5a83 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= 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 dc99f7cd1f11..a7d86fbbd625 100644 --- a/kernel/blk_drv/ramdisk.c +++ b/kernel/blk_drv/ramdisk.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -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 66f4cec49cb3..4c28f9c1b036 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 781fdab7e5ae..3de86488e64f 100644 --- a/kernel/chr_drv/console.c +++ b/kernel/chr_drv/console.c @@ -31,6 +31,7 @@ */ #include +#include #include #include #include @@ -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=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< 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; currconsNR_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 59957385a810..0177e0680b78 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 67baadb1afc6..f147cecb082b 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,12 +106,14 @@ 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 diff --git a/kernel/chr_drv/serial.c b/kernel/chr_drv/serial.c index a78b1e559dcb..2334e50a3322 100644 --- a/kernel/chr_drv/serial.c +++ b/kernel/chr_drv/serial.c @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -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 6551da15712b..18ea261528ae 100644 --- a/kernel/chr_drv/tty_io.c +++ b/kernel/chr_drv/tty_io.c @@ -15,6 +15,7 @@ #include #include #include +#include #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 c3ac9a1f908d..a4250d3ca73b 100644 --- a/kernel/chr_drv/tty_ioctl.c +++ b/kernel/chr_drv/tty_ioctl.c @@ -16,6 +16,8 @@ #include 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 ; ipresent+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 381995bde3d9..e81319a920d3 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -15,9 +15,46 @@ #include #include -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 4c076bee33e3..e3e1e67dcdd6 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 ; ipid == last_pid) || + (task[i]->pgrp == last_pid))) + goto repeat; + for(i=1 ; istate = 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 ; ipid == last_pid) || - (task[i]->pgrp == last_pid))) - goto repeat; - for(i=1 ; ipid; } diff --git a/kernel/math/Makefile b/kernel/math/Makefile index 834283d226c7..d136ef5dd5e1 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 5e3d1a59618b..e9383242bf31 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 1de404abb2d0..5f1c1c2ca4c2 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 5f8167be5d28..39063fee899a 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 f79fd7359024..6fb6e6f0067f 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 + +#ifdef KERNEL_MATH_EMULATION + #include #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 +#include + +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 94f7c52ed7c3..ae85e70581d0 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 000000000000..1dab26141c31 --- /dev/null +++ b/kernel/ptrace.c @@ -0,0 +1,322 @@ +/* ptrace.c */ +/* By Ross Biro 1/23/92 */ + +#include +#include +#include +#include +#include +#include +#include +#include +/* 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 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 8de11a1455e2..335551d6e3ef 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -11,6 +11,7 @@ * current-task */ #include +#include #include #include #include @@ -19,6 +20,7 @@ #include #include +#include #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;ia=p->b=0; p++; diff --git a/kernel/signal.c b/kernel/signal.c index b326435a0b0d..cf0aa01baa96 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -9,8 +9,11 @@ #include #include +#include #include +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 fd858181c091..40b8b4016345 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -17,6 +17,11 @@ #include #include +/* + * 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 f85ddf36c571..8d7a982a2716 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 ae9f8cb91f4e..797bb79d60dc 100644 --- a/kernel/traps.c +++ b/kernel/traps.c @@ -18,6 +18,8 @@ #include #include #include +#include + #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 a4a33b57cfd1..9f678c8fab0a 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 c0c9d6995696..ac48d1aaf7b9 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 8c3fc5898115..59728071612b 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 bab2e4c3c02d..44c38abbde9c 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 b7815bbc8576..a77f26f675f3 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 ; iHIGH_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/page.s b/mm/page.s deleted file mode 100644 index bd1c586bd8af..000000000000 --- a/mm/page.s +++ /dev/null @@ -1,40 +0,0 @@ -/* - * linux/mm/page.s - * - * (C) 1991 Linus Torvalds - */ - -/* - * page.s contains the low-level page-exception code. - * the real work is done in mm.c - */ - -.globl _page_fault - -_page_fault: - xchgl %eax,(%esp) - pushl %ecx - pushl %edx - push %ds - push %es - push %fs - movl $0x10,%edx - mov %dx,%ds - mov %dx,%es - mov %dx,%fs - movl %cr2,%edx - pushl %edx - pushl %eax - testl $1,%eax - jne 1f - call _do_no_page - jmp 2f -1: call _do_wp_page -2: addl $8,%esp - pop %fs - pop %es - pop %ds - popl %edx - popl %ecx - popl %eax - iret diff --git a/mm/swap.c b/mm/swap.c index 327259b1dd3e..4c621d0123bb 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -10,8 +10,10 @@ */ #include +#include #include +#include #include #include #include @@ -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 32d2efb0994e..1fa477bad97a 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 /* 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