This was created from a re-packaged 0.11 tree.
Linux-0.11 has a few rather major improvements, but perhaps most
notably, is the first kernel where some other people start making
real contributions.
- I fixed the buffer cache code, making it a lot more stable
- demand-loading from disk. My comment proudly states:
Once more I can proudly say that linux stood up to being changed: it
was less than 2 hours work to get demand-loading completely implemented.
This is a major milestone, since it makes the kernel much more
powerful than Minix was at the time. I also share clean pages.
- we still don't have an /sbin/init, but we now load /etc/rc at bootup,
and the kernel will loop, spawning shells forever. That makes it easier
to test things.
- scaffolding for math emulation introduced.
- Ted Ts'o shows up as a coder. Ted implements:
o "#!" escape handling for executables
o fixes for some file permission handling
o "sticky" directory bit
o first "malloc()/free()" implementation.
(this one is horrible: the free needs the size for good
performance, which will result in years of "free_s()" pains)
o adds BSD-style setreuid/gid() handling
o allows us to specify root device at image build time
o cleanups of some of the uglier direct %fs-register accesses
- Galen Hunt shows up as a coder: he's added code to handle different
video card detection (whereas my original one just handled VGA, we
now handle CGA, MGA, EGA and VGA)
- The console can beep now: John T Kohl (who also does the tty KILL
char handling)
- we also now have German (Wolfgang Thiel) and French (Marc Corsini)
keyboard maps. World Domination!
Btw, if you wonder what the "Urgel" comments are - I was still fairly
Swedish-speaking, and "Urgel" is what I would these days write as "Ugh".
It's a sign of trouble or ugly code. The floppy driver in particular is
clearly not something I'm very proud of ;).
-ROOTDEV= /dev/hd3
+#
+# if you want the ram-disk device, define this to be the
+# size in blocks.
+#
+RAMDISK = #-DRAMDISK=512
-AS86 =as -0 -a
-CC86 =cc -0
-LD86 =ld -0
+AS86 =as86 -0 -a
+LD86 =ld86 -0
AS =gas
LD =gld
LDFLAGS =-s -x -M
-CC =gcc
-CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs
+CC =gcc $(RAMDISK)
+CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \
+-fcombine-regs -mstring-insns
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'.
+#
+ROOT_DEV=/dev/hd6
+
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
.c.s:
all: Image
Image: boot/bootsect boot/setup tools/system tools/build
- tools/build boot/bootsect boot/setup tools/system $(ROOTDEV) > Image
+ tools/build boot/bootsect boot/setup tools/system $(ROOT_DEV) > Image
sync
+disk: Image
+ dd bs=8192 if=Image of=/dev/PS0
+
tools/build: tools/build.c
$(CC) $(CFLAGS) \
-o tools/build tools/build.c
- chmem +65000 tools/build
boot/head.o: boot/head.s
tools/system: boot/head.o init/main.o \
- $(ARCHIVES) $(DRIVERS) $(LIBS)
+ $(ARCHIVES) $(DRIVERS) $(MATH) $(LIBS)
$(LD) $(LDFLAGS) boot/head.o init/main.o \
$(ARCHIVES) \
$(DRIVERS) \
+ $(MATH) \
$(LIBS) \
-o tools/system > System.map
+kernel/math/math.a:
+ (cd kernel/math; make)
+
kernel/blk_drv/blk_drv.a:
(cd kernel/blk_drv; make)
lib/lib.a:
(cd lib; make)
-#boot/setup: boot/setup.s
-# $(AS86) -o boot/setup.o boot/setup.s
-# $(LD86) -s -o boot/setup boot/setup.o
+boot/setup: boot/setup.s
+ $(AS86) -o boot/setup.o boot/setup.s
+ $(LD86) -s -o boot/setup boot/setup.o
-#boot/bootsect: tmp.s
-# $(AS86) -o boot/bootsect.o tmp.s
-# rm -f tmp.s
-# $(LD86) -s -o boot/bootsect boot/bootsect.o
+boot/bootsect: boot/bootsect.s
+ $(AS86) -o boot/bootsect.o boot/bootsect.s
+ $(LD86) -s -o boot/bootsect boot/bootsect.o
-#tmp.s: boot/bootsect.s tools/system
-# (echo -n "SYSSIZE = (";ls -l tools/system | grep system \
-# | cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s
-# cat boot/bootsect.s >> tmp.s
+tmp.s: boot/bootsect.s tools/system
+ (echo -n "SYSSIZE = (";ls -l tools/system | grep system \
+ | cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s
+ cat boot/bootsect.s >> tmp.s
clean:
- rm -f Image System.map tmp_make core
- rm -f init/*.o boot/*.o tools/system tools/build
+ rm -f Image System.map tmp_make core boot/bootsect boot/setup
+ rm -f init/*.o tools/system tools/build boot/*.o
(cd mm;make clean)
(cd fs;make clean)
(cd kernel;make clean)
(cd lib;make clean)
backup: clean
- (cd .. ; tar cf - linux | compress16 - > backup.Z)
+ (cd .. ; tar cf - linux | compress - > backup.Z)
sync
dep:
+++ /dev/null
-head 1.2;
-branch ;
-access ;
-symbols ;
-locks ; strict;
-comment @# @;
-
-
-1.2
-date 91.11.11.15.02.48; author tytso; state Exp;
-branches ;
-next 1.1;
-
-1.1
-date 91.11.11.14.43.04; author tytso; state Exp;
-branches ;
-next ;
-
-
-desc
-@Top level makefile for the Linux kernel
-@
-
-
-1.2
-log
-@Comment out code to build and clean out 16 bit binaries.
-
-Modify rule to specify the appropriate root device to the build program
-@
-text
-@ROOTDEV= /dev/hd3
-
-AS86 =as -0 -a
-CC86 =cc -0
-LD86 =ld -0
-
-AS =gas
-LD =gld
-LDFLAGS =-s -x -M
-CC =gcc
-CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs
-CPP =cpp -nostdinc -Iinclude
-
-ARCHIVES=kernel/kernel.o mm/mm.o fs/fs.o
-DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a
-LIBS =lib/lib.a
-
-.c.s:
- $(CC) $(CFLAGS) \
- -nostdinc -Iinclude -S -o $*.s $<
-.s.o:
- $(AS) -c -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) \
- -nostdinc -Iinclude -c -o $*.o $<
-
-all: Image
-
-Image: boot/bootsect boot/setup tools/system tools/build
- tools/build boot/bootsect boot/setup tools/system $(ROOTDEV) > Image
- sync
-
-tools/build: tools/build.c
- $(CC) $(CFLAGS) \
- -o tools/build tools/build.c
- chmem +65000 tools/build
-
-boot/head.o: boot/head.s
-
-tools/system: boot/head.o init/main.o \
- $(ARCHIVES) $(DRIVERS) $(LIBS)
- $(LD) $(LDFLAGS) boot/head.o init/main.o \
- $(ARCHIVES) \
- $(DRIVERS) \
- $(LIBS) \
- -o tools/system > System.map
-
-kernel/blk_drv/blk_drv.a:
- (cd kernel/blk_drv; make)
-
-kernel/chr_drv/chr_drv.a:
- (cd kernel/chr_drv; make)
-
-kernel/kernel.o:
- (cd kernel; make)
-
-mm/mm.o:
- (cd mm; make)
-
-fs/fs.o:
- (cd fs; make)
-
-lib/lib.a:
- (cd lib; make)
-
-#boot/setup: boot/setup.s
-# $(AS86) -o boot/setup.o boot/setup.s
-# $(LD86) -s -o boot/setup boot/setup.o
-
-#boot/bootsect: tmp.s
-# $(AS86) -o boot/bootsect.o tmp.s
-# rm -f tmp.s
-# $(LD86) -s -o boot/bootsect boot/bootsect.o
-
-#tmp.s: boot/bootsect.s tools/system
-# (echo -n "SYSSIZE = (";ls -l tools/system | grep system \
-# | cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s
-# cat boot/bootsect.s >> tmp.s
-
-clean:
- rm -f Image System.map tmp_make core
- rm -f init/*.o boot/*.o tools/system tools/build
- (cd mm;make clean)
- (cd fs;make clean)
- (cd kernel;make clean)
- (cd lib;make clean)
-
-backup: clean
- (cd .. ; tar cf - linux | compress16 - > backup.Z)
- sync
-
-dep:
- sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
- (for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done) >> tmp_make
- cp tmp_make Makefile
- (cd fs; make dep)
- (cd kernel; make dep)
- (cd mm; make dep)
-
-### Dependencies:
-init/main.o : init/main.c include/unistd.h include/sys/stat.h \
- include/sys/types.h include/sys/times.h include/sys/utsname.h \
- include/utime.h include/time.h include/linux/tty.h include/termios.h \
- include/linux/sched.h include/linux/head.h include/linux/fs.h \
- include/linux/mm.h include/signal.h include/asm/system.h include/asm/io.h \
- include/stddef.h include/stdarg.h include/fcntl.h
-@
-
-
-1.1
-log
-@Initial revision
-@
-text
-@d1 2
-d30 1
-a30 1
- tools/build boot/bootsect boot/setup tools/system > Image
-d66 3
-a68 3
-boot/setup: boot/setup.s
- $(AS86) -o boot/setup.o boot/setup.s
- $(LD86) -s -o boot/setup boot/setup.o
-d70 4
-a73 4
-boot/bootsect: tmp.s
- $(AS86) -o boot/bootsect.o tmp.s
- rm -f tmp.s
- $(LD86) -s -o boot/bootsect boot/bootsect.o
-d75 4
-a78 4
-tmp.s: boot/bootsect.s tools/system
- (echo -n "SYSSIZE = (";ls -l tools/system | grep system \
- | cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s
- cat boot/bootsect.s >> tmp.s
-d81 2
-a82 2
- rm -f Image System.map tmp_make boot/bootsect core
- rm -f boot/setup init/*.o boot/*.o tools/system tools/build
-@
-|
-| bootsect.s (C) 1991 Linus Torvalds
-|
-| bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
-| iself out of the way to address 0x90000, and jumps there.
-|
-| It then loads 'setup' directly after itself (0x90200), and the system
-| at 0x10000, using BIOS interrupts.
-|
-| NOTE! currently system is at most 8*65536 bytes long. This should be no
-| problem, even in the future. I want to keep it simple. This 512 kB
-| kernel size should be enough, especially as this doesn't contain the
-| buffer cache as in minix
-|
-| The loader has been made as simple as possible, and continuos
-| read errors will result in a unbreakable loop. Reboot by hand. It
-| loads pretty fast by getting whole sectors at a time whenever possible.
+!
+! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
+! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
+! versions of linux
+!
+SYSSIZE = 0x3000
+!
+! bootsect.s (C) 1991 Linus Torvalds
+!
+! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
+! iself out of the way to address 0x90000, and jumps there.
+!
+! It then loads 'setup' directly after itself (0x90200), and the system
+! at 0x10000, using BIOS interrupts.
+!
+! NOTE! currently system is at most 8*65536 bytes long. This should be no
+! problem, even in the future. I want to keep it simple. This 512 kB
+! kernel size should be enough, especially as this doesn't contain the
+! buffer cache as in minix
+!
+! The loader has been made as simple as possible, and continuos
+! read errors will result in a unbreakable loop. Reboot by hand. It
+! loads pretty fast by getting whole sectors at a time whenever possible.
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begbss:
.text
-SETUPLEN = 4 | nr of setup-sectors
-BOOTSEG = 0x07c0 | original address of boot-sector
-INITSEG = 0x9000 | we move boot here - out of the way
-SETUPSEG = 0x9020 | setup starts here
-SYSSEG = 0x1000 | system loaded at 0x10000 (65536).
-ENDSEG = SYSSEG + SYSSIZE | where to stop loading
+SETUPLEN = 4 ! nr of setup-sectors
+BOOTSEG = 0x07c0 ! original address of boot-sector
+INITSEG = 0x9000 ! we move boot here - out of the way
+SETUPSEG = 0x9020 ! setup starts here
+SYSSEG = 0x1000 ! system loaded at 0x10000 (65536).
+ENDSEG = SYSSEG + SYSSIZE ! where to stop loading
-| ROOT_DEV: 0x000 - same type of floppy as boot.
-| 0x301 - first partition on first drive etc
-ROOT_DEV = 0 | 0x306
+! ROOT_DEV: 0x000 - same type of floppy as boot.
+! 0x301 - first partition on first drive etc
+ROOT_DEV = 0x306
entry start
start:
go: mov ax,cs
mov ds,ax
mov es,ax
-| put stack at 0x9ff00.
+! put stack at 0x9ff00.
mov ss,ax
- mov sp,#0xFF00 | arbitrary value >>512
+ mov sp,#0xFF00 ! arbitrary value >>512
-| load the setup-sectors directly after the bootblock.
-| Note that 'es' is already set up.
+! load the setup-sectors directly after the bootblock.
+! Note that 'es' is already set up.
load_setup:
- mov dx,#0x0000 | drive 0, head 0
- mov cx,#0x0002 | sector 2, track 0
- mov bx,#0x0200 | address = 512, in INITSEG
- mov ax,#0x0200+SETUPLEN | service 2, nr of sectors
- int 0x13 | read it
- jnc ok_load_setup | ok - continue
+ mov dx,#0x0000 ! drive 0, head 0
+ mov cx,#0x0002 ! sector 2, track 0
+ mov bx,#0x0200 ! address = 512, in INITSEG
+ mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors
+ int 0x13 ! read it
+ jnc ok_load_setup ! ok - continue
mov dx,#0x0000
- mov ax,#0x0000 | reset the diskette
+ mov ax,#0x0000 ! reset the diskette
int 0x13
j load_setup
ok_load_setup:
-| Get disk drive parameters, specifically nr of sectors/track
+! Get disk drive parameters, specifically nr of sectors/track
mov dl,#0x00
- mov ax,#0x0800 | AH=8 is get drive parameters
+ mov ax,#0x0800 ! AH=8 is get drive parameters
int 0x13
mov ch,#0x00
seg cs
mov ax,#INITSEG
mov es,ax
-| Print some inane message
+! Print some inane message
- mov ah,#0x03 | read cursor pos
+ mov ah,#0x03 ! read cursor pos
xor bh,bh
int 0x10
mov cx,#24
- mov bx,#0x0007 | page 0, attribute 7 (normal)
+ mov bx,#0x0007 ! page 0, attribute 7 (normal)
mov bp,#msg1
- mov ax,#0x1301 | write string, move cursor
+ mov ax,#0x1301 ! write string, move cursor
int 0x10
-| ok, we've written the message, now
-| we want to load the system (at 0x10000)
+! ok, we've written the message, now
+! we want to load the system (at 0x10000)
mov ax,#SYSSEG
- mov es,ax | segment of 0x010000
+ mov es,ax ! segment of 0x010000
call read_it
call kill_motor
-| After that we check which root-device to use. If the device is
-| defined (!= 0), nothing is done and the given device is used.
-| Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
-| on the number of sectors that the BIOS reports currently.
+! After that we check which root-device to use. If the device is
+! defined (!= 0), nothing is done and the given device is used.
+! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
+! on the number of sectors that the BIOS reports currently.
seg cs
mov ax,root_dev
jne root_defined
seg cs
mov bx,sectors
- mov ax,#0x0208 | /dev/ps0 - 1.2Mb
+ mov ax,#0x0208 ! /dev/ps0 - 1.2Mb
cmp bx,#15
je root_defined
- mov ax,#0x021c | /dev/PS0 - 1.44Mb
+ mov ax,#0x021c ! /dev/PS0 - 1.44Mb
cmp bx,#18
je root_defined
undef_root:
seg cs
mov root_dev,ax
-| after that (everyting loaded), we jump to
-| the setup-routine loaded directly after
-| the bootblock:
+! after that (everyting loaded), we jump to
+! the setup-routine loaded directly after
+! the bootblock:
jmpi 0,SETUPSEG
-| This routine loads the system at address 0x10000, making sure
-| no 64kB boundaries are crossed. We try to load it as fast as
-| possible, loading whole tracks whenever we can.
-|
-| in: es - starting address segment (normally 0x1000)
-|
-sread: .word 1+SETUPLEN | sectors read of current track
-head: .word 0 | current head
-track: .word 0 | current track
+! This routine loads the system at address 0x10000, making sure
+! no 64kB boundaries are crossed. We try to load it as fast as
+! possible, loading whole tracks whenever we can.
+!
+! in: es - starting address segment (normally 0x1000)
+!
+sread: .word 1+SETUPLEN ! sectors read of current track
+head: .word 0 ! current head
+track: .word 0 ! current track
read_it:
mov ax,es
test ax,#0x0fff
-die: jne die | es must be at 64kB boundary
- xor bx,bx | bx is starting address within segment
+die: jne die ! es must be at 64kB boundary
+ xor bx,bx ! bx is starting address within segment
rp_read:
mov ax,es
- cmp ax,#ENDSEG | have we loaded all yet?
+ cmp ax,#ENDSEG ! have we loaded all yet?
jb ok1_read
ret
ok1_read:
+++ /dev/null
-/*
- *
- * bootsect.s (C) 1991 Linus Torvalds
- *
- * bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
- * iself out of the way to address 0x90000, and jumps there.
- *
- * It then loads 'setup' directly after itself (0x90200), and the system
- * at 0x10000, using BIOS interrupts.
- *
- * NOTE! currently system is at most 8*65536 bytes long. This should be no
- * problem, even in the future. I want to keep it simple. This 512 kB
- * kernel size should be enough, especially as this doesn't contain the
- * buffer cache as in minix
- *
- * The loader has been made as simple as possible, and continuos
- * read errors will result in a unbreakable loop. Reboot by hand. It
- * loads pretty fast by getting whole sectors at a time whenever possible.
- */
-
-.globl begtext, begdata, begbss, endtext, enddata, endbss
-.text
-begtext:
-.data
-begdata:
-.bss
-begbss:
-.text
-
-SETUPLEN = 4 # nr of setup-sectors
-BOOTSEG = 0x07c0 # original address of boot-sector
-INITSEG = 0x9000 # we move boot here - out of the way
-SETUPSEG = 0x9020 # setup starts here
-SYSSEG = 0x1000 # system loaded at 0x10000 (65536).
-ENDSEG = SYSSEG + SYSSIZE # where to stop loading
-
-/*
- * ROOT_DEV: 0x000 - same type of floppy as boot.
- * 0x301 - first partition on first drive etc
- */
-ROOT_DEV = 0 # 0x306
-
-entry start
-start:
- mov $BOOTSEG,%ax
- mov %ax,%ds
- mov $INITSEG,%ax
- mov %ax,%es
- mov $256,%cx
- sub %si,%si
- sub %di,%di
- rep
- movw
- jmpi go,INITSEG
-go: mov %cs,%ax
- mov %ax,%ds
- mov %ax,%es
-/*
- * put stack at 0x9ff00.
- */
- mov %ax,%ss
- mov $0xFF00,%sp # arbitrary value >>512
-
-/*
- * load the setup-sectors directly after the bootblock.
- * Note that 'es' is already set up.
- */
-
-load_setup:
- mov $0x0000,%dx # drive 0, head 0
- mov $0x0002,%cx # sector 2, track 0
- mov $0x0200,%bx # address = 512, in INITSEG
- mov $0x0200,%ax+SETUPLEN # service 2, nr of sectors
- int 0x13 # read it
- jnc ok_load_setup # ok - continue
- mov $0x0000,%dx
- mov $0x0000,%ax # reset the diskette
- int 0x13
- j load_setup
-
-ok_load_setup:
-
-/*
- * Get disk drive parameters, specifically nr of sectors/track
- */
-
- mov $0x00,%dl
- mov $0x0800,%ax # AH=8 is get drive parameters
- int 0x13
- mov $0x00,%ch
- seg %cs
- mov %cx,sectors
- mov $INITSEG,%ax
- mov %ax,%es
-
-/*
- * Print some inane message
- */
-
- mov $0x03,%ah # read cursor pos
- xor %bh,%bh
- int 0x10
-
- mov $24,%cx
- mov $0x0007,%bx # page 0, attribute 7 (normal)
- mov $msg1,%bp
- mov $0x1301,%ax # write string, move cursor
- int 0x10
-
-/*
- * ok, we've written the message, now
- * we want to load the system (at 0x10000)
- */
-
- mov $SYSSEG,%ax
- mov %ax,%es # segment of 0x010000
- call read_it
- call kill_motor
-
-/*
- * After that we check which root-device to use. If the device is
- * defined (!= 0), nothing is done and the given device is used.
- * Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
- * on the number of sectors that the BIOS reports currently.
- */
-
- seg %cs
- mov root,%ax_dev
- cmp %ax,$0
- jne root_defined
- seg %cs
- mov sectors,%bx
- mov $0x0208,%ax # /dev/ps0 - 1.2Mb
- cmp %bx,$15
- je root_defined
- mov $0x021c,%ax # /dev/PS0 - 1.44Mb
- cmp %bx,$18
- je root_defined
-undef_root:
- jmp undef_root
-root_defined:
- seg %cs
- mov root_%ax,dev
-
-/*
- * after that (everyting loaded), we jump to
- * the setup-routine loaded directly after
- * the bootblock:
- */
-
- jmpi 0,SETUPSEG
-
-/*
- * This routine loads the system at address 0x10000, making sure
- * no 64kB boundaries are crossed. We try to load it as fast as
- * possible, loading whole tracks whenever we can.
- *
- * in: es - starting address segment (normally 0x1000)
- *
- */
-sread: .word 1+SETUPLEN # sectors read of current track
-head: .word 0 # current head
-track: .word 0 # current track
-
-read_it:
- mov %es,%ax
- test %ax,$0x0fff
-die: jne die # %es must be at 64kB boundary
- xor %bx,%bx # %bx is starting address within segment
-rp_read:
- mov %es,%ax
- cmp %ax,$ENDSEG # have we loaded all yet?
- jb ok1_read
- ret
-ok1_read:
- seg %cs
- mov sectors,%ax
- sub sread,%ax
- mov %ax,%cx
- shl $9,%cx
- add %bx,%cx
- jnc ok2_read
- je ok2_read
- xor %ax,%ax
- sub %bx,%ax
- shr $9,%ax
-ok2_read:
- call read_track
- mov %ax,%cx
- add sread,%ax
- seg %cs
- cmp %ax,sectors
- jne ok3_read
- mov $1,%ax
- sub head,%ax
- jne ok4_read
- inc track
-ok4_read:
- mov %ax,head
- xor %ax,%ax
-ok3_read:
- mov %ax,sread
- shl $9,%cx
- add %cx,%bx
- jnc rp_read
- mov %es,%ax
- add $0x1000,%ax
- mov %ax,%es
- xor %bx,%bx
- jmp rp_read
-
-read_track:
- push %ax
- push %bx
- push %cx
- push %dx
- mov track,%dx
- mov sread,%cx
- inc %cx
- mov %dl,%ch
- mov head,%dx
- mov %dl,%dh
- mov $0,%dl
- and $0x0100,%dx
- mov $2,%ah
- int 0x13
- jc bad_rt
- pop %dx
- pop %cx
- pop %bx
- pop %ax
- ret
-bad_rt: mov %ax,$0
- mov $0,%dx
- int 0x13
- pop %dx
- pop %cx
- pop %bx
- pop %ax
- jmp read_track
-
-/*
- * This procedure turns off the floppy drive motor, so
- * that we enter the kernel in a known state, and
- * don't have to worry about it later.
- */
-kill_motor:
- push %dx
- mov $0x3f2,%dx
- mov $0,%al
- outb
- pop %dx
- ret
-
-sectors:
- .word 0
-
-msg1:
- .byte 13,10
- .ascii "Loading system ..."
- .byte 13,10,13,10
-
-.org 508
-root_dev:
- .word ROOT_DEV
-boot_flag:
- .word 0xAA55
-
-.text
-endtext:
-.data
-enddata:
-.bss
-endbss:
+++ /dev/null
-#!/afs/net/tools/@sys/perl
-#
-#
-
-$in_block_comment = 0;
-
-while (<>) {
- if (/^\|/) {
- if (! $in_block_comment) {
- print "/* \n";
- $in_block_comment = 1;
- }
- s/\|/ */;
- print;
- next;
- } else {
- if ($in_block_comment) {
- print " */\n";
- $in_block_comment = 0;
- }
- }
-
- s/#/$/; # Convert immediate references
- s/\|/#/; # Convert in-line comments
-
- s/(\b|,)([abcd][xhl])(\b|,|$)/\1%\2\3/g;
- s/(\b|,)([cdsefg]s)(\b|,|$)/\1%\2\3/g;
- s/(\b|,)([sd]i)(\b|,|$)/\1%\2\3/g;
- s/(\b|,)([sb]p)(\b|,|$)/\1%\2\3/g;
- s/(\b|,)(e[abcd]x)(\b|,|$)/\1%\2\3/g;
-
- if (/^(([a-zA-Z]+:[ \t]+)|[ \t]+)([a-zA-Z]+)/) {
- $op = $3;
- if (($op eq "mov") || ($op eq "add") || ($op eq "sub") ||
- ($op eq "xor") || ($op eq "and") || ($op eq "shr") ||
- ($op eq "shl") || ($op eq "in") || ($op eq "out")) {
- #
- # We need to swap arguments...
- #
- s/([0-9a-zA-Z%\$]+)(,)([0-9a-zA-Z%\$]+)/\3\2\1/;
- }
- }
-
- print;
-}
-
-
* int 16 for math errors.
*/
movl %cr0,%eax # check math chip
- andl $0x80000011,%eax # Save PG,ET,PE
+ andl $0x80000011,%eax # Save PG,PE,ET
/* "orl $0x10020,%eax" here for 486 might be good */
orl $2,%eax # set MP
- testl $0x10,%eax
- jne 1f # ET is set - 387 is present
- xorl $6,%eax # else reset MP and set EM
-1: movl %eax,%cr0
+ movl %eax,%cr0
+ call check_x87
jmp after_page_tables
+/*
+ * We depend on ET to be correct. This checks for 287/387.
+ */
+check_x87:
+ fninit
+ fstsw %ax
+ cmpb $0,%al
+ je 1f /* no coprocessor: have to set bits */
+ movl %cr0,%eax
+ xorl $6,%eax /* reset MP, set EM */
+ movl %eax,%cr0
+ ret
+.align 2
+1: .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
+ ret
+
/*
* setup_idt
*
-|
-| setup.s (C) 1991 Linus Torvalds
-|
-| setup.s is responsible for getting the system data from the BIOS,
-| and putting them into the appropriate places in system memory.
-| both setup.s and system has been loaded by the bootblock.
-|
-| This code asks the bios for memory/disk/other parameters, and
-| puts them in a "safe" place: 0x90000-0x901FF, ie where the
-| boot-block used to be. It is then up to the protected mode
-| system to read them from there before the area is overwritten
-| for buffer-blocks.
-|
-
-| NOTE! These had better be the same as in bootsect.s!
-
-INITSEG = 0x9000 | we move boot here - out of the way
-SYSSEG = 0x1000 | system loaded at 0x10000 (65536).
-SETUPSEG = 0x9020 | this is the current segment
+!
+! setup.s (C) 1991 Linus Torvalds
+!
+! setup.s is responsible for getting the system data from the BIOS,
+! and putting them into the appropriate places in system memory.
+! both setup.s and system has been loaded by the bootblock.
+!
+! This code asks the bios for memory/disk/other parameters, and
+! puts them in a "safe" place: 0x90000-0x901FF, ie where the
+! boot-block used to be. It is then up to the protected mode
+! system to read them from there before the area is overwritten
+! for buffer-blocks.
+!
+
+! NOTE! These had better be the same as in bootsect.s!
+
+INITSEG = 0x9000 ! we move boot here - out of the way
+SYSSEG = 0x1000 ! system loaded at 0x10000 (65536).
+SETUPSEG = 0x9020 ! this is the current segment
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
entry start
start:
-| ok, the read went well so we get current cursor position and save it for
-| posterity.
+! ok, the read went well so we get current cursor position and save it for
+! posterity.
- mov ax,#INITSEG | this is done in bootsect already, but...
+ mov ax,#INITSEG ! this is done in bootsect already, but...
mov ds,ax
- mov ah,#0x03 | read cursor pos
+ mov ah,#0x03 ! read cursor pos
xor bh,bh
- int 0x10 | save it in known place, con_init fetches
- mov [0],dx | it from 0x90000.
+ int 0x10 ! save it in known place, con_init fetches
+ mov [0],dx ! it from 0x90000.
-| Get memory size (extended mem, kB)
+! Get memory size (extended mem, kB)
mov ah,#0x88
int 0x15
mov [2],ax
-| Get hd0 data
+! Get video-card data:
+
+ mov ah,#0x0f
+ int 0x10
+ mov [4],bx ! bh = display page
+ mov [6],ax ! al = video mode, ah = window width
+
+! check for EGA/VGA and some config parameters
+
+ mov ah,#0x12
+ mov bl,#0x10
+ int 0x10
+ mov [8],ax
+ mov [10],bx
+ mov [12],cx
+
+! Get hd0 data
mov ax,#0x0000
mov ds,ax
rep
movsb
-| Get hd1 data
+! Get hd1 data
mov ax,#0x0000
mov ds,ax
rep
movsb
-| Check that there IS a hd1 :-)
+! Check that there IS a hd1 :-)
mov ax,#0x01500
mov dl,#0x81
stosb
is_disk1:
-| now we want to move to protected mode ...
+! now we want to move to protected mode ...
- cli | no interrupts allowed !
+ cli ! no interrupts allowed !
-| first we move the system to it's rightful place
+! first we move the system to it's rightful place
mov ax,#0x0000
- cld | 'direction'=0, movs moves forward
+ cld ! 'direction'=0, movs moves forward
do_move:
- mov es,ax | destination segment
+ mov es,ax ! destination segment
add ax,#0x1000
cmp ax,#0x9000
jz end_move
- mov ds,ax | source segment
+ mov ds,ax ! source segment
sub di,di
sub si,si
mov cx,#0x8000
movsw
jmp do_move
-| then we load the segment descriptors
+! then we load the segment descriptors
end_move:
- mov ax,#SETUPSEG | right, forgot this at first. didn't work :-)
+ mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-)
mov ds,ax
- lidt idt_48 | load idt with 0,0
- lgdt gdt_48 | load gdt with whatever appropriate
+ lidt idt_48 ! load idt with 0,0
+ lgdt gdt_48 ! load gdt with whatever appropriate
-| that was painless, now we enable A20
+! that was painless, now we enable A20
call empty_8042
- mov al,#0xD1 | command write
+ mov al,#0xD1 ! command write
out #0x64,al
call empty_8042
- mov al,#0xDF | A20 on
+ mov al,#0xDF ! A20 on
out #0x60,al
call empty_8042
-| well, that went ok, I hope. Now we have to reprogram the interrupts :-(
-| we put them right after the intel-reserved hardware interrupts, at
-| int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
-| messed this up with the original PC, and they haven't been able to
-| rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
-| which is used for the internal hardware interrupts as well. We just
-| have to reprogram the 8259's, and it isn't fun.
-
- mov al,#0x11 | initialization sequence
- out #0x20,al | send it to 8259A-1
- .word 0x00eb,0x00eb | jmp $+2, jmp $+2
- out #0xA0,al | and to 8259A-2
+! well, that went ok, I hope. Now we have to reprogram the interrupts :-(
+! we put them right after the intel-reserved hardware interrupts, at
+! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
+! messed this up with the original PC, and they haven't been able to
+! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
+! which is used for the internal hardware interrupts as well. We just
+! have to reprogram the 8259's, and it isn't fun.
+
+ mov al,#0x11 ! initialization sequence
+ out #0x20,al ! send it to 8259A-1
+ .word 0x00eb,0x00eb ! jmp $+2, jmp $+2
+ out #0xA0,al ! and to 8259A-2
.word 0x00eb,0x00eb
- mov al,#0x20 | start of hardware int's (0x20)
+ mov al,#0x20 ! start of hardware int's (0x20)
out #0x21,al
.word 0x00eb,0x00eb
- mov al,#0x28 | start of hardware int's 2 (0x28)
+ mov al,#0x28 ! start of hardware int's 2 (0x28)
out #0xA1,al
.word 0x00eb,0x00eb
- mov al,#0x04 | 8259-1 is master
+ mov al,#0x04 ! 8259-1 is master
out #0x21,al
.word 0x00eb,0x00eb
- mov al,#0x02 | 8259-2 is slave
+ mov al,#0x02 ! 8259-2 is slave
out #0xA1,al
.word 0x00eb,0x00eb
- mov al,#0x01 | 8086 mode for both
+ mov al,#0x01 ! 8086 mode for both
out #0x21,al
.word 0x00eb,0x00eb
out #0xA1,al
.word 0x00eb,0x00eb
- mov al,#0xFF | mask off all interrupts for now
+ mov al,#0xFF ! mask off all interrupts for now
out #0x21,al
.word 0x00eb,0x00eb
out #0xA1,al
-| well, that certainly wasn't fun :-(. Hopefully it works, and we don't
-| need no steenking BIOS anyway (except for the initial loading :-).
-| The BIOS-routine wants lots of unnecessary data, and it's less
-| "interesting" anyway. This is how REAL programmers do it.
-|
-| Well, now's the time to actually move into protected mode. To make
-| things as simple as possible, we do no register set-up or anything,
-| we let the gnu-compiled 32-bit programs do that. We just jump to
-| absolute address 0x00000, in 32-bit protected mode.
-
- mov ax,#0x0001 | protected mode (PE) bit
- lmsw ax | This is it!
- jmpi 0,8 | jmp offset 0 of segment 8 (cs)
-
-| This routine checks that the keyboard command queue is empty
-| No timeout is used - if this hangs there is something wrong with
-| the machine, and we probably couldn't proceed anyway.
+! well, that certainly wasn't fun :-(. Hopefully it works, and we don't
+! need no steenking BIOS anyway (except for the initial loading :-).
+! The BIOS-routine wants lots of unnecessary data, and it's less
+! "interesting" anyway. This is how REAL programmers do it.
+!
+! Well, now's the time to actually move into protected mode. To make
+! things as simple as possible, we do no register set-up or anything,
+! we let the gnu-compiled 32-bit programs do that. We just jump to
+! absolute address 0x00000, in 32-bit protected mode.
+
+ mov ax,#0x0001 ! protected mode (PE) bit
+ lmsw ax ! This is it!
+ jmpi 0,8 ! jmp offset 0 of segment 8 (cs)
+
+! This routine checks that the keyboard command queue is empty
+! No timeout is used - if this hangs there is something wrong with
+! the machine, and we probably couldn't proceed anyway.
empty_8042:
.word 0x00eb,0x00eb
- in al,#0x64 | 8042 status port
- test al,#2 | is input buffer full?
- jnz empty_8042 | yes - loop
+ in al,#0x64 ! 8042 status port
+ test al,#2 ! is input buffer full?
+ jnz empty_8042 ! yes - loop
ret
gdt:
- .word 0,0,0,0 | dummy
+ .word 0,0,0,0 ! dummy
- .word 0x07FF | 8Mb - limit=2047 (2048*4096=8Mb)
- .word 0x0000 | base address=0
- .word 0x9A00 | code read/exec
- .word 0x00C0 | granularity=4096, 386
+ .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
+ .word 0x0000 ! base address=0
+ .word 0x9A00 ! code read/exec
+ .word 0x00C0 ! granularity=4096, 386
- .word 0x07FF | 8Mb - limit=2047 (2048*4096=8Mb)
- .word 0x0000 | base address=0
- .word 0x9200 | data read/write
- .word 0x00C0 | granularity=4096, 386
+ .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
+ .word 0x0000 ! base address=0
+ .word 0x9200 ! data read/write
+ .word 0x00C0 ! granularity=4096, 386
idt_48:
- .word 0 | idt limit=0
- .word 0,0 | idt base=0L
+ .word 0 ! idt limit=0
+ .word 0,0 ! idt base=0L
gdt_48:
- .word 0x800 | gdt limit=2048, 256 GDT entries
- .word 512+gdt,0x9 | gdt base = 0X9xxxx
+ .word 0x800 ! gdt limit=2048, 256 GDT entries
+ .word 512+gdt,0x9 ! gdt base = 0X9xxxx
.text
endtext:
+++ /dev/null
-/*
- *
- * setup.s (C) 1991 Linus Torvalds
- *
- * setup.s is responsible for getting the system data from the BIOS,
- * and putting them into the appropriate places in system memory.
- * both setup.s and system has been loaded by the bootblock.
- *
- * This code asks the bios for memory/disk/other parameters, and
- * puts them in a "safe" place: 0x90000-0x901FF, ie where the
- * boot-block used to be. It is then up to the protected mode
- * system to read them from there before the area is overwritten
- * for buffer-blocks.
- *
- */
-
-/*
- * NOTE! These had better be the same as in bootsect.s!
- */
-
-INITSEG = 0x9000 # we move boot here - out of the way
-SYSSEG = 0x1000 # system loaded at 0x10000 (65536).
-SETUPSEG = 0x9020 # this is the current segment
-
-.globl begtext, begdata, begbss, endtext, enddata, endbss
-.text
-begtext:
-.data
-begdata:
-.bss
-begbss:
-.text
-
-entry start
-start:
-
-/*
- * ok, the read went well so we get current cursor position and save it for
- * posterity.
- */
-
- mov $INITSEG,%ax # this is done in bootsect already, but...
- mov %ax,%ds
- mov $0x03,%ah # read cursor pos
- xor %bh,%bh
- int 0x10 # save it in known place, con_init fetches
- mov [0],%dx # it from 0x90000.
-
-/*
- * Get memory size (extended mem, kB)
- */
-
- mov $0x88,%ah
- int 0x15
- mov [2],%ax
-
-/*
- * Get hd0 data
- */
-
- mov $0x0000,%ax
- mov %ax,%ds
- lds %si,[4*0x41]
- mov $INITSEG,%ax
- mov %ax,%es
- mov $0x0080,%di
- mov $0x10,%cx
- rep
- movsb
-
-/*
- * Get hd1 data
- */
-
- mov $0x0000,%ax
- mov %ax,%ds
- lds %si,[4*0x46]
- mov $INITSEG,%ax
- mov %ax,%es
- mov $0x0090,%di
- mov $0x10,%cx
- rep
- movsb
-
-/*
- * Check that there IS a hd1 :-)
- */
-
- mov $0x01500,%ax
- mov $0x81,%dl
- int 0x13
- jc no_disk1
- cmp %ah,$3
- je is_disk1
-no_disk1:
- mov $INITSEG,%ax
- mov %ax,%es
- mov $0x0090,%di
- mov $0x10,%cx
- mov $0x00,%ax
- rep
- stosb
-is_disk1:
-
-/*
- * now we want to move to protected mode ...
- */
-
- cli # no interrupts allowed !
-
-/*
- * first we move the system to it's rightful place
- */
-
- mov $0x0000,%ax
- cld # 'direction'=0, movs moves forward
-do_move:
- mov %ax,%es # destination segment
- add $0x1000,%ax
- cmp %ax,$0x9000
- jz end_move
- mov %ax,%ds # source segment
- sub %di,%di
- sub %si,%si
- mov $0x8000,%cx
- rep
- movsw
- jmp do_move
-
-/*
- * then we load the segment descriptors
- */
-
-end_move:
- mov $SETUPSEG,%ax # right, forgot this at first. didn't work :-)
- mov %ax,%ds
- lidt idt_48 # load idt with 0,0
- lgdt gdt_48 # load gdt with whatever appropriate
-
-/*
- * that was painless, now we enable A20
- */
-
- call empty_8042
- mov $0xD1,%al # command write
- out %al,$0x64
- call empty_8042
- mov $0xDF,%al # A20 on
- out %al,$0x60
- call empty_8042
-
-/*
- * well, that went ok, I hope. Now we have to reprogram the interrupts :-(
- * we put them right after the intel-reserved hardware interrupts, at
- * int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
- * messed this up with the original PC, and they haven't been able to
- * rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
- * which is used for the internal hardware interrupts as well. We just
- * have to reprogram the 8259's, and it isn't fun.
- */
-
- mov $0x11,%al # initialization sequence
- out %al,$0x20 # send it to 8259A-1
- .word 0x00eb,0x00eb # jmp $+2, jmp $+2
- out %al,$0xA0 # and to 8259A-2
- .word 0x00eb,0x00eb
- mov $0x20,%al # start of hardware int's (0x20)
- out %al,$0x21
- .word 0x00eb,0x00eb
- mov $0x28,%al # start of hardware int's 2 (0x28)
- out %al,$0xA1
- .word 0x00eb,0x00eb
- mov $0x04,%al # 8259-1 is master
- out %al,$0x21
- .word 0x00eb,0x00eb
- mov $0x02,%al # 8259-2 is slave
- out %al,$0xA1
- .word 0x00eb,0x00eb
- mov $0x01,%al # 8086 mode for both
- out %al,$0x21
- .word 0x00eb,0x00eb
- out %al,$0xA1
- .word 0x00eb,0x00eb
- mov $0xFF,%al # mask off all interrupts for now
- out %al,$0x21
- .word 0x00eb,0x00eb
- out %al,$0xA1
-
-/*
- * well, that certainly wasn't fun :-(. Hopefully it works, and we don't
- * need no steenking BIOS anyway (except for the initial loading :-).
- * The BIOS-routine wants lots of unnecessary data, and it's less
- * "interesting" anyway. This is how REAL programmers do it.
- *
- * Well, now's the time to actually move into protected mode. To make
- * things as simple as possible, we do no register set-up or anything,
- * we let the gnu-compiled 32-bit programs do that. We just jump to
- * absolute address 0x00000, in 32-bit protected mode.
- */
-
- mov $0x0001,%ax # protected mode (PE) bit
- lmsw %ax # This is it!
- jmpi 0,8 # jmp offset 0 of segment 8 (%cs)
-
-/*
- * This routine checks that the keyboard command queue is empty
- * No timeout is used - if this hangs there is something wrong with
- * the machine, and we probably couldn't proceed anyway.
- */
-empty_8042:
- .word 0x00eb,0x00eb
- in $0x64,%al # 8042 status port
- test %al,$2 # is input buffer full?
- jnz empty_8042 # yes - loop
- ret
-
-gdt:
- .word 0,0,0,0 # dummy
-
- .word 0x07FF # 8Mb - limit=2047 (2048*4096=8Mb)
- .word 0x0000 # base address=0
- .word 0x9A00 # code read/exec
- .word 0x00C0 # granularity=4096, 386
-
- .word 0x07FF # 8Mb - limit=2047 (2048*4096=8Mb)
- .word 0x0000 # base address=0
- .word 0x9200 # data read/write
- .word 0x00C0 # granularity=4096, 386
-
-idt_48:
- .word 0 # idt limit=0
- .word 0,0 # idt base=0L
-
-gdt_48:
- .word 0x800 # gdt limit=2048, 256 GDT entries
- .word 512+gdt,0x9 # gdt base = 0X9xxxx
-
-.text
-endtext:
-.data
-enddata:
-.bss
-endbss:
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 tty_ioctl.o truncate.o
+ bitmap.o fcntl.o ioctl.o truncate.o
fs.o: $(OBJS)
$(LD) -r -o fs.o $(OBJS)
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
../include/asm/segment.h ../include/asm/io.h
-exec.o : exec.c ../include/errno.h ../include/sys/stat.h \
- ../include/sys/types.h ../include/a.out.h ../include/linux/fs.h \
- ../include/linux/sched.h ../include/linux/head.h ../include/linux/mm.h \
- ../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h
+exec.o : exec.c ../include/errno.h ../include/string.h \
+ ../include/sys/stat.h ../include/sys/types.h ../include/a.out.h \
+ ../include/linux/fs.h ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
+ ../include/asm/segment.h
fcntl.o : fcntl.c ../include/string.h ../include/errno.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
../include/sys/types.h ../include/linux/mm.h ../include/signal.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/signal.h ../include/sys/stat.h
-tty_ioctl.o : tty_ioctl.c ../include/errno.h ../include/termios.h \
- ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
- ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \
- ../include/linux/kernel.h ../include/linux/tty.h ../include/asm/segment.h \
- ../include/asm/system.h
+++ /dev/null
-head 1.2;
-branch ;
-access ;
-symbols ;
-locks ; strict;
-comment @ * @;
-
-
-1.2
-date 91.11.20.00.10.40; author tytso; state Exp;
-branches ;
-next 1.1;
-
-1.1
-date 91.11.12.15.49.42; author tytso; state Exp;
-branches ;
-next ;
-
-
-desc
-@@
-
-
-1.2
-log
-@Used new version of buffer.c supplied from Linus.
-@
-text
-@/*
- * linux/fs/buffer.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-/*
- * 'buffer.c' implements the buffer-cache functions. Race-conditions have
- * been avoided by NEVER letting a interrupt change a buffer (except for the
- * data, of course), but instead letting the caller do it. NOTE! As interrupts
- * can wake up a caller, some cli-sti sequences are needed to check for
- * sleep-on-calls. These should be extremely quick, though (I hope).
- */
-
-/*
- * NOTE! There is one discordant note here: checking floppies for
- * disk change. This is where it fits best, I think, as it should
- * invalidate changed floppy-disk-caches.
- */
-
-#include <stdarg.h>
-
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <asm/system.h>
-#include <asm/io.h>
-
-extern int end;
-struct buffer_head * start_buffer = (struct buffer_head *) &end;
-struct buffer_head * hash_table[NR_HASH];
-static struct buffer_head * free_list;
-static struct task_struct * buffer_wait = NULL;
-int NR_BUFFERS = 0;
-
-static inline void wait_on_buffer(struct buffer_head * bh)
-{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
-}
-
-int sys_sync(void)
-{
- int i;
- struct buffer_head * bh;
-
- sync_inodes(); /* write out inodes into buffers */
- bh = start_buffer;
- for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
- wait_on_buffer(bh);
- if (bh->b_dirt)
- ll_rw_block(WRITE,bh);
- }
- return 0;
-}
-
-int sync_dev(int dev)
-{
- int i;
- struct buffer_head * bh;
-
- bh = start_buffer;
- for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
- if (bh->b_dev != dev)
- continue;
- wait_on_buffer(bh);
- if (bh->b_dev == dev && bh->b_dirt)
- ll_rw_block(WRITE,bh);
- }
- sync_inodes();
- bh = start_buffer;
- for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
- if (bh->b_dev != dev)
- continue;
- wait_on_buffer(bh);
- if (bh->b_dev == dev && bh->b_dirt)
- ll_rw_block(WRITE,bh);
- }
- return 0;
-}
-
-/*
- * This routine checks whether a floppy has been changed, and
- * invalidates all buffer-cache-entries in that case. This
- * is a relatively slow routine, so we have to try to minimize using
- * it. Thus it is called only upon a 'mount' or 'open'. This
- * is the best way of combining speed and utility, I think.
- * People changing diskettes in the middle of an operation deserve
- * to loose :-)
- *
- * NOTE! Although currently this is only for floppies, the idea is
- * that any additional removable block-device will use this routine,
- * and that mount/open needn't know that floppies/whatever are
- * special.
- */
-void check_disk_change(int dev)
-{
- int i;
- struct buffer_head * bh;
-
- if (MAJOR(dev) != 2)
- return;
- dev=MINOR(dev) & 0x03; /* which floppy is it? */
- if (!floppy_change(dev))
- return;
- dev |= 0x200;
- for (i=0 ; i<NR_SUPER ; i++)
- if ((super_block[i].s_dev & 0xff03)==dev)
- put_super(super_block[i].s_dev);
- bh = start_buffer;
- for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
- if ((bh->b_dev & 0xff03) != dev)
- continue;
- wait_on_buffer(bh);
- if ((bh->b_dev & 0xff03) == dev)
- bh->b_uptodate = bh->b_dirt = 0;
- }
-}
-
-#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)
-{
-/* 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 */
- 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;
-}
-
-static inline void insert_into_queues(struct buffer_head * bh)
-{
-/* put at end 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;
-/* put the buffer in new hash-queue if it has a device */
- bh->b_prev = NULL;
- bh->b_next = NULL;
- if (!bh->b_dev)
- return;
- bh->b_next = hash(bh->b_dev,bh->b_blocknr);
- hash(bh->b_dev,bh->b_blocknr) = bh;
- bh->b_next->b_prev = bh;
-}
-
-static struct buffer_head * find_buffer(int dev, int block)
-{
- struct buffer_head * tmp;
-
- for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
- if (tmp->b_dev==dev && tmp->b_blocknr==block)
- return tmp;
- return NULL;
-}
-
-/*
- * Why like this, I hear you say... The reason is race-conditions.
- * As we don't lock buffers (unless we are readint them, that is),
- * something might happen to it while we sleep (ie a read-error
- * will force it bad). This shouldn't really happen currently, but
- * the code is ready.
- */
-struct buffer_head * get_hash_table(int dev, int block)
-{
- struct buffer_head * bh;
-
- for (;;) {
- if (!(bh=find_buffer(dev,block)))
- return NULL;
- bh->b_count++;
- wait_on_buffer(bh);
- if (bh->b_dev == dev && bh->b_blocknr == block)
- return bh;
- bh->b_count--;
- }
-}
-
-/*
- * Ok, this is getblk, and it isn't very clear, again to hinder
- * race-conditions. Most of the code is seldom used, (ie repeating),
- * so it should be much more efficient than it looks.
- *
- * The algoritm is changed: better, and an elusive bug removed.
- * LBT 11.11.91
- */
-#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
-struct buffer_head * getblk(int dev,int block)
-{
- struct buffer_head * tmp, * bh;
-
-repeat:
- if (bh = get_hash_table(dev,block))
- return bh;
- tmp = free_list;
- do {
- if (tmp->b_count)
- continue;
- if (!bh || BADNESS(tmp)<BADNESS(bh)) {
- bh = tmp;
- if (!BADNESS(tmp))
- break;
- }
- } while ((tmp = tmp->b_next_free) != free_list);
- if (!bh) {
- sleep_on(&buffer_wait);
- goto repeat;
- }
- wait_on_buffer(bh);
- if (bh->b_count)
- goto repeat;
- while (bh->b_dirt) {
- sync_dev(bh->b_dev);
- wait_on_buffer(bh);
- if (bh->b_count)
- goto repeat;
- }
-/* NOTE!! While we slept waiting for this block, somebody else might */
-/* already have added "this" block to the cache. check it */
- if (find_buffer(dev,block))
- goto repeat;
-/* OK, FINALLY we know that this buffer is the only one of it's kind, */
-/* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */
- bh->b_count=1;
- bh->b_dirt=0;
- bh->b_uptodate=0;
- remove_from_queues(bh);
- bh->b_dev=dev;
- bh->b_blocknr=block;
- insert_into_queues(bh);
- return bh;
-}
-
-void brelse(struct buffer_head * buf)
-{
- if (!buf)
- return;
- wait_on_buffer(buf);
- if (!(buf->b_count--))
- panic("Trying to free free buffer");
- wake_up(&buffer_wait);
-}
-
-/*
- * bread() reads a specified block and returns the buffer that contains
- * it. It returns NULL if the block was unreadable.
- */
-struct buffer_head * bread(int dev,int block)
-{
- struct buffer_head * bh;
-
- if (!(bh=getblk(dev,block)))
- panic("bread: getblk returned NULL\n");
- if (bh->b_uptodate)
- return bh;
- ll_rw_block(READ,bh);
- wait_on_buffer(bh);
- if (bh->b_uptodate)
- return bh;
- brelse(bh);
- return NULL;
-}
-
-/*
- * Ok, breada can be used as bread, but additionally to mark other
- * blocks for reading as well. End the argument list with a negative
- * number.
- */
-struct buffer_head * breada(int dev,int first, ...)
-{
- va_list args;
- struct buffer_head * bh, *tmp;
-
- va_start(args,first);
- if (!(bh=getblk(dev,first)))
- panic("bread: getblk returned NULL\n");
- if (!bh->b_uptodate)
- ll_rw_block(READ,bh);
- while ((first=va_arg(args,int))>=0) {
- tmp=getblk(dev,first);
- if (tmp) {
- if (!tmp->b_uptodate)
- ll_rw_block(READA,bh);
- tmp->b_count--;
- }
- }
- va_end(args);
- wait_on_buffer(bh);
- if (bh->b_uptodate)
- return bh;
- brelse(bh);
- return (NULL);
-}
-
-void buffer_init(long buffer_end)
-{
- struct buffer_head * h = start_buffer;
- void * b;
- int i;
-
- if (buffer_end == 1<<20)
- b = (void *) (640*1024);
- else
- b = (void *) buffer_end;
- while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
- h->b_dev = 0;
- h->b_dirt = 0;
- h->b_count = 0;
- h->b_lock = 0;
- h->b_uptodate = 0;
- h->b_wait = NULL;
- h->b_next = NULL;
- h->b_prev = NULL;
- h->b_data = (char *) b;
- h->b_prev_free = h-1;
- h->b_next_free = h+1;
- h++;
- NR_BUFFERS++;
- if (b == (void *) 0x100000)
- b = (void *) 0xA0000;
- }
- h--;
- free_list = start_buffer;
- free_list->b_prev_free = h;
- h->b_next_free = free_list;
- for (i=0;i<NR_HASH;i++)
- hash_table[i]=NULL;
-}
-@
-
-
-1.1
-log
-@Initial revision
-@
-text
-@d72 9
-d196 3
-d200 1
-d203 1
-a203 1
- struct buffer_head * tmp;
-d206 2
-a207 2
- if (tmp=get_hash_table(dev,block))
- return tmp;
-d209 6
-a214 4
- for (;;) {
- if (!tmp->b_count) {
- wait_on_buffer(tmp); /* we still have to wait */
- if (!tmp->b_count) /* on it, it might be dirty */
-d217 12
-a228 3
- tmp = tmp->b_next_free;
- if (tmp == free_list) {
- sleep_on(&buffer_wait);
-a229 1
- }
-d231 3
-a233 23
- tmp->b_count++;
- remove_from_queues(tmp);
-/*
- * Now, when we know nobody can get to this node (as it's removed from the
- * free list), we write it out. We can sleep here without fear of race-
- * conditions.
- */
- while (tmp->b_dirt) {
- sync_dev(tmp->b_dev);
- wait_on_buffer(tmp);
- }
-/* update buffer contents */
- tmp->b_dev=dev;
- tmp->b_blocknr=block;
- tmp->b_dirt=0;
- tmp->b_uptodate=0;
-/* NOTE!! While we possibly slept in sync_dev(), somebody else might have */
-/* added "this" block already, so check for that. Thank God for goto's. */
- if (find_buffer(dev,block)) {
- tmp->b_dev=0; /* ok, someone else has beaten us */
- tmp->b_blocknr=0; /* to it - free this block and */
- tmp->b_count=0; /* try again */
- insert_into_queues(tmp);
-d235 10
-a244 4
- }
-/* and then insert into correct position */
- insert_into_queues(tmp);
- return tmp;
-@
+++ /dev/null
-head 1.2;
-branch ;
-access ;
-symbols ;
-locks tytso:1.2; strict;
-comment @ * @;
-
-
-1.2
-date 91.12.01.09.22.01; author tytso; state Exp;
-branches ;
-next 1.1;
-
-1.1
-date 91.11.21.23.19.36; author tytso; state Exp;
-branches ;
-next ;
-
-
-desc
-@@
-
-
-1.2
-log
-@Patches sent to Linus
-@
-text
-@/*
- * linux/fs/exec.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-#include <errno.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <a.out.h>
-
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <asm/segment.h>
-
-extern int sys_exit(int exit_code);
-extern int sys_close(int fd);
-
-/*
- * MAX_ARG_PAGES defines the number of pages allocated for arguments
- * and envelope for the new program. 32 should suffice, this gives
- * a maximum env+arg of 128kB !
- */
-#define MAX_ARG_PAGES 32
-
-#define cp_block(from,to) \
-__asm__("pushl $0x10\n\t" \
- "pushl $0x17\n\t" \
- "pop %%es\n\t" \
- "cld\n\t" \
- "rep\n\t" \
- "movsl\n\t" \
- "pop %%es" \
- ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
- :"cx","di","si")
-
-/*
- * read_head() reads blocks 1-6 (not 0). Block 0 has already been
- * read for header information.
- */
-int read_head(struct m_inode * inode,int blocks)
-{
- struct buffer_head * bh;
- int count;
-
- if (blocks>6)
- blocks=6;
- for(count = 0 ; count<blocks ; count++) {
- if (!inode->i_zone[count+1])
- continue;
- if (!(bh=bread(inode->i_dev,inode->i_zone[count+1])))
- return -1;
- cp_block(bh->b_data,count*BLOCK_SIZE);
- brelse(bh);
- }
- return 0;
-}
-
-int read_ind(int dev,int ind,long size,unsigned long offset)
-{
- struct buffer_head * ih, * bh;
- unsigned short * table,block;
-
- if (size<=0)
- panic("size<=0 in read_ind");
- if (size>512*BLOCK_SIZE)
- size=512*BLOCK_SIZE;
- if (!ind)
- return 0;
- if (!(ih=bread(dev,ind)))
- return -1;
- table = (unsigned short *) ih->b_data;
- while (size>0) {
- if (block=*(table++))
- if (!(bh=bread(dev,block))) {
- brelse(ih);
- return -1;
- } else {
- cp_block(bh->b_data,offset);
- brelse(bh);
- }
- size -= BLOCK_SIZE;
- offset += BLOCK_SIZE;
- }
- brelse(ih);
- return 0;
-}
-
-/*
- * read_area() reads an area into %fs:mem.
- */
-int read_area(struct m_inode * inode,long size)
-{
- struct buffer_head * dind;
- unsigned short * table;
- int i,count;
-
- if ((i=read_head(inode,(size+BLOCK_SIZE-1)/BLOCK_SIZE)) ||
- (size -= BLOCK_SIZE*6)<=0)
- return i;
- if ((i=read_ind(inode->i_dev,inode->i_zone[7],size,BLOCK_SIZE*6)) ||
- (size -= BLOCK_SIZE*512)<=0)
- return i;
- if (!(i=inode->i_zone[8]))
- return 0;
- if (!(dind = bread(inode->i_dev,i)))
- return -1;
- table = (unsigned short *) dind->b_data;
- for(count=0 ; count<512 ; count++)
- if ((i=read_ind(inode->i_dev,*(table++),size,
- BLOCK_SIZE*(518+count))) || (size -= BLOCK_SIZE*512)<=0)
- return i;
- panic("Impossibly long executable");
-}
-
-/*
- * create_tables() parses the env- and arg-strings in new user
- * memory and creates the pointer tables from them, and puts their
- * addresses on the "stack", returning the new stack pointer value.
- */
-static unsigned long * create_tables(char * p,int argc,int envc)
-{
- unsigned long *argv,*envp;
- unsigned long * sp;
-
- sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
- sp -= envc+1;
- envp = sp;
- sp -= argc+1;
- argv = sp;
- put_fs_long((unsigned long)envp,--sp);
- put_fs_long((unsigned long)argv,--sp);
- put_fs_long((unsigned long)argc,--sp);
- while (argc-->0) {
- put_fs_long((unsigned long) p,argv++);
- while (get_fs_byte(p++)) /* nothing */ ;
- }
- put_fs_long(0,argv);
- while (envc-->0) {
- put_fs_long((unsigned long) p,envp++);
- while (get_fs_byte(p++)) /* nothing */ ;
- }
- put_fs_long(0,envp);
- return sp;
-}
-
-/*
- * count() counts the number of arguments/envelopes
- */
-static int count(char ** argv)
-{
- int i=0;
- char ** tmp;
-
- if (tmp = argv)
- while (get_fs_long((unsigned long *) (tmp++)))
- i++;
-
- return i;
-}
-
-/*
- * 'copy_string()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- *
- * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies
- * whether the string and the string array are from user or kernel segments:
- *
- * from_kmem argv * argv **
- * 0 user space user space
- * 1 kernel space user space
- * 2 kernel space kernel space
- *
- * We do this by playing games with the fs segment register. Since it
- * it is expensive to load a segment register, we try to avoid calling
- * set_fs() unless we absolutely have to.
- */
-static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
- unsigned long p, int from_kmem)
-{
- char *tmp, *pag;
- int len, offset = 0;
- unsigned long old_fs, new_fs;
-
- if (!p)
- return 0; /* bullet-proofing */
- new_fs = get_ds();
- old_fs = get_fs();
- if (from_kmem==2)
- set_fs(new_fs);
- while (argc-- > 0) {
- if (from_kmem == 1)
- set_fs(new_fs);
- if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))
- panic("argc is wrong");
- if (from_kmem == 1)
- set_fs(old_fs);
- len=0; /* remember zero-padding */
- do {
- len++;
- } while (get_fs_byte(tmp++));
- if (p-len < 0) { /* this shouldn't happen - 128kB */
- set_fs(old_fs);
- return 0;
- }
- while (len) {
- --p; --tmp; --len;
- if (--offset < 0) {
- offset = p % PAGE_SIZE;
- if (from_kmem==2)
- set_fs(old_fs);
- if (!(pag = (char *) page[p/PAGE_SIZE]) &&
- !(pag = (char *) page[p/PAGE_SIZE] =
- (unsigned long *) get_free_page()))
- return 0;
- if (from_kmem==2)
- set_fs(new_fs);
-
- }
- *(pag + offset) = get_fs_byte(tmp);
- }
- }
- if (from_kmem==2)
- set_fs(old_fs);
- return p;
-}
-
-static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
-{
- unsigned long code_limit,data_limit,code_base,data_base;
- int i;
-
- code_limit = text_size+PAGE_SIZE -1;
- code_limit &= 0xFFFFF000;
- data_limit = 0x4000000;
- code_base = get_base(current->ldt[1]);
- data_base = code_base;
- set_base(current->ldt[1],code_base);
- set_limit(current->ldt[1],code_limit);
- set_base(current->ldt[2],data_base);
- set_limit(current->ldt[2],data_limit);
-/* make sure fs points to the NEW data segment */
- __asm__("pushl $0x17\n\tpop %%fs"::);
- data_base += data_limit;
- for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
- data_base -= PAGE_SIZE;
- if (page[i])
- put_page(page[i],data_base);
- }
- return data_limit;
-}
-
-/*
- * 'do_execve()' executes a new program.
- */
-int do_execve(unsigned long * eip,long tmp,char * filename,
- char ** argv, char ** envp)
-{
- struct m_inode * inode;
- struct buffer_head * bh;
- struct exec ex;
- unsigned long page[MAX_ARG_PAGES];
- int i,argc,envc;
- int e_uid, e_gid;
- int retval;
- int sh_bang = 0;
- unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
-
- if ((0xffff & eip[1]) != 0x000f)
- panic("execve called from supervisor mode");
- for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
- page[i]=0;
- if (!(inode=namei(filename))) /* get executables inode */
- return -ENOENT;
- argc = count(argv);
- envc = count(envp);
-
-restart_interp:
- if (!S_ISREG(inode->i_mode)) { /* must be regular file */
- retval = -EACCES;
- 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;
- if (current->euid == inode->i_uid)
- i >>= 6;
- else if (current->egid == inode->i_gid)
- i >>= 3;
- if (!(i & 1) &&
- !((inode->i_mode & 0111) && suser())) {
- retval = -ENOEXEC;
- goto exec_error2;
- }
- if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
- retval = -EACCES;
- goto exec_error2;
- }
- ex = *((struct exec *) bh->b_data); /* read exec-header */
- if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
- /*
- * This section does the #! interpretation.
- * Sorta complicated, but hopefully it will work. -TYT
- */
-
- char buf[1023], *cp, *interp, *i_name, *i_arg;
- unsigned long old_fs;
-
- strncpy(buf, bh->b_data+2, 1022);
- brelse(bh);
- iput(inode);
- buf[1022] = '\0';
- if (cp = strchr(buf, '\n')) {
- *cp = '\0';
- for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
- }
- if (!cp || *cp == '\0') {
- retval = -ENOEXEC; /* No interpreter name found */
- goto exec_error1;
- }
- interp = i_name = cp;
- i_arg = 0;
- for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
- if (*cp == '/')
- i_name = cp+1;
- }
- if (*cp) {
- *cp++ = '\0';
- i_arg = cp;
- }
- /*
- * OK, we've parsed out the interpreter name and
- * (optional) argument.
- */
- if (sh_bang++ == 0) {
- p = copy_strings(envc, envp, page, p, 0);
- p = copy_strings(--argc, argv+1, page, p, 0);
- }
- /*
- * Splice in (1) the interpreter's name for argv[0]
- * (2) (optional) argument to interpreter
- * (3) filename of shell script
- *
- * This is done in reverse order, because of how the
- * user environment and arguments are stored.
- */
- p = copy_strings(1, &filename, page, p, 1);
- argc++;
- if (i_arg) {
- p = copy_strings(1, &i_arg, page, p, 2);
- argc++;
- }
- p = copy_strings(1, &i_name, page, p, 2);
- argc++;
- if (!p) {
- retval = -ENOMEM;
- goto exec_error1;
- }
- /*
- * OK, now restart the process with the interpreter's inode.
- */
- old_fs = get_fs();
- set_fs(get_ds());
- if (!(inode=namei(interp))) { /* get executables inode */
- set_fs(old_fs);
- retval = -ENOENT;
- goto exec_error1;
- }
- set_fs(old_fs);
- goto restart_interp;
- }
- brelse(bh);
- if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
- ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
- inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
- retval = -ENOEXEC;
- goto exec_error2;
- }
- if (N_TXTOFF(ex) != BLOCK_SIZE) {
- printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
- retval = -ENOEXEC;
- goto exec_error2;
- }
- if (!sh_bang) {
- p = copy_strings(envc,envp,page,p,0);
- p = copy_strings(argc,argv,page,p,0);
- if (!p) {
- retval = -ENOMEM;
- goto exec_error2;
- }
- }
-/* OK, This is the point of no return */
- for (i=0 ; i<32 ; i++)
- current->sigaction[i].sa_handler = NULL;
- for (i=0 ; i<NR_OPEN ; i++)
- if ((current->close_on_exec>>i)&1)
- sys_close(i);
- current->close_on_exec = 0;
- free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
- free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
- if (last_task_used_math == current)
- last_task_used_math = NULL;
- current->used_math = 0;
- p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
- p = (unsigned long) create_tables((char *)p,argc,envc);
- current->brk = ex.a_bss +
- (current->end_data = ex.a_data +
- (current->end_code = ex.a_text));
- current->start_stack = p & 0xfffff000;
- current->euid = e_uid;
- current->egid = e_gid;
- i = read_area(inode,ex.a_text+ex.a_data);
- iput(inode);
- if (i<0)
- sys_exit(-1);
- i = ex.a_text+ex.a_data;
- while (i&0xfff)
- put_fs_byte(0,(char *) (i++));
- eip[0] = ex.a_entry; /* eip, magic happens :-) */
- eip[3] = p; /* stack pointer */
- return 0;
-exec_error2:
- iput(inode);
-exec_error1:
- for (i=0 ; i<MAX_ARG_PAGES ; i++)
- free_page(page[i]);
- return(retval);
-}
-@
-
-
-1.1
-log
-@Initial revision
-@
-text
-@d8 1
-d168 12
-d182 1
-a182 1
- unsigned long p)
-d184 3
-a186 2
- int len,i;
- char *tmp;
-d188 6
-d195 3
-a197 1
- if (!(tmp = (char *)get_fs_long(((unsigned long *) argv)+argc)))
-d199 2
-d205 2
-a206 1
- if (p-len < 0) /* this shouldn't happen - 128kB */
-a207 5
- i = ((unsigned) (p-len)) >> 12;
- while (i<MAX_ARG_PAGES && !page[i]) {
- if (!(page[i]=get_free_page()))
- return 0;
- i++;
-d209 16
-a224 7
- do {
- --p;
- if (!page[p/PAGE_SIZE])
- panic("nonexistent page in exec.c");
- ((char *) page[p/PAGE_SIZE])[p%PAGE_SIZE] =
- get_fs_byte(--tmp);
- } while (--len);
-d226 2
-d267 4
-a270 1
- unsigned long p;
-d278 4
-d283 2
-a284 2
- iput(inode);
- return -EACCES;
-d287 10
-a296 10
- if (current->uid && current->euid) {
- if (current->euid == inode->i_uid)
- i >>= 6;
- else if (current->egid == inode->i_gid)
- i >>= 3;
- } else if (i & 0111)
- i=1;
- if (!(i & 1)) {
- iput(inode);
- return -ENOEXEC;
-d299 15
-d315 59
-a373 1
- return -EACCES;
-a374 1
- ex = *((struct exec *) bh->b_data); /* read exec-header */
-d379 2
-a380 2
- iput(inode);
- return -ENOEXEC;
-d382 4
-a385 11
- if (N_TXTOFF(ex) != BLOCK_SIZE)
- panic("N_TXTOFF != BLOCK_SIZE. See a.out.h.");
- argc = count(argv);
- envc = count(envp);
- p = copy_strings(envc,envp,page,PAGE_SIZE*MAX_ARG_PAGES-4);
- p = copy_strings(argc,argv,page,p);
- if (!p) {
- for (i=0 ; i<MAX_ARG_PAGES ; i++)
- free_page(page[i]);
- iput(inode);
- return -1;
-d387 8
-d413 2
-d425 6
-@
+++ /dev/null
-head 1.2;
-branch ;
-access ;
-symbols ;
-locks ; strict;
-comment @ * @;
-
-
-1.2
-date 91.12.01.09.22.07; author tytso; state Exp;
-branches ;
-next 1.1;
-
-1.1
-date 91.11.21.09.55.14; author tytso; state Exp;
-branches ;
-next ;
-
-
-desc
-@@
-
-
-1.2
-log
-@Patches sent to Linus
-@
-text
-@/*
- * linux/fs/namei.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <asm/segment.h>
-
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <const.h>
-#include <sys/stat.h>
-
-#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])
-
-/*
- * comment out this line if you want names > 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()
- *
- * is used to check for read/write/execute permissions on a file.
- * 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 mode = inode->i_mode;
-
-/* special case: not even root can read/write a deleted file */
- if (inode->i_dev && !inode->i_nlinks)
- return 0;
- else if (current->euid==inode->i_uid)
- mode >>= 6;
- else if (current->egid==inode->i_gid)
- mode >>= 3;
- if (((mode & mask & 0007) == mask) || suser())
- return 1;
- return 0;
-}
-
-/*
- * 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;
- 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 and 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.
- */
-static struct buffer_head * find_entry(struct m_inode ** dir,
- const char * name, int namelen, struct dir_entry ** res_dir)
-{
- 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;
- if (!namelen)
- return 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++;
- }
- }
- }
- 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++;
- }
- brelse(bh);
- return NULL;
-}
-
-/*
- * add_entry()
- *
- * adds a file entry to the specified directory, using the same
- * semantics as find_entry(). It returns NULL if it failed.
- *
- * NOTE!! The inode part of 'de' is left at 0 - which means you
- * may not sleep between calling this and putting something into
- * the entry, as someone else might have used it while you slept.
- */
-static struct buffer_head * add_entry(struct m_inode * dir,
- const char * name, int namelen, struct dir_entry ** res_dir)
-{
- int block,i;
- struct buffer_head * bh;
- struct dir_entry * de;
-
- *res_dir = NULL;
-#ifdef NO_TRUNCATE
- if (namelen > NAME_LEN)
- return NULL;
-#else
- if (namelen > NAME_LEN)
- namelen = NAME_LEN;
-#endif
- if (!namelen)
- return NULL;
- if (!(block = dir->i_zone[0]))
- return NULL;
- if (!(bh = bread(dir->i_dev,block)))
- return NULL;
- i = 0;
- de = (struct dir_entry *) bh->b_data;
- while (1) {
- if ((char *)de >= BLOCK_SIZE+bh->b_data) {
- brelse(bh);
- bh = NULL;
- block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK);
- if (!block)
- return NULL;
- if (!(bh = bread(dir->i_dev,block))) {
- i += DIR_ENTRIES_PER_BLOCK;
- continue;
- }
- de = (struct dir_entry *) bh->b_data;
- }
- if (i*sizeof(struct dir_entry) >= dir->i_size) {
- de->inode=0;
- dir->i_size = (i+1)*sizeof(struct dir_entry);
- dir->i_dirt = 1;
- dir->i_ctime = CURRENT_TIME;
- }
- if (!de->inode) {
- dir->i_mtime = CURRENT_TIME;
- for (i=0; i < NAME_LEN ; i++)
- de->name[i]=(i<namelen)?get_fs_byte(name+i):0;
- bh->b_dirt = 1;
- *res_dir = de;
- return bh;
- }
- de++;
- i++;
- }
- brelse(bh);
- return NULL;
-}
-
-/*
- * get_dir()
- *
- * Getdir traverses the pathname until it hits the topmost directory.
- * It returns NULL on failure.
- */
-static struct m_inode * get_dir(const char * pathname)
-{
- char c;
- const char * thisname;
- struct m_inode * inode;
- struct buffer_head * bh;
- int namelen,inr,idev;
- struct dir_entry * de;
-
- if (!current->root || !current->root->i_count)
- panic("No root inode");
- if (!current->pwd || !current->pwd->i_count)
- panic("No cwd inode");
- if ((c=get_fs_byte(pathname))=='/') {
- inode = current->root;
- pathname++;
- } else if (c)
- inode = current->pwd;
- else
- return NULL; /* empty name is bad */
- inode->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++)
- /* nothing */ ;
- if (!c)
- return inode;
- if (!(bh = find_entry(&inode,thisname,namelen,&de))) {
- iput(inode);
- return NULL;
- }
- inr = de->inode;
- idev = inode->i_dev;
- brelse(bh);
- iput(inode);
- if (!(inode = iget(idev,inr)))
- return NULL;
- }
-}
-
-/*
- * 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)
-{
- char c;
- const char * basename;
- struct m_inode * dir;
-
- if (!(dir = get_dir(pathname)))
- return NULL;
- basename = pathname;
- while (c=get_fs_byte(pathname++))
- if (c=='/')
- basename=pathname;
- *namelen = pathname-basename-1;
- *name = basename;
- return dir;
-}
-
-/*
- * namei()
- *
- * is used by most simple commands to get the inode of a specified name.
- * Open, link etc use their own routines, but this is enough for things
- * like 'chmod' etc.
- */
-struct m_inode * namei(const char * pathname)
-{
- const char * basename;
- int inr,dev,namelen;
- struct m_inode * dir;
- struct buffer_head * bh;
- struct dir_entry * de;
-
- if (!(dir = dir_namei(pathname,&namelen,&basename)))
- return NULL;
- if (!namelen) /* special case: '/usr/' etc */
- return dir;
- bh = find_entry(&dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- return NULL;
- }
- inr = de->inode;
- dev = dir->i_dev;
- brelse(bh);
- iput(dir);
- dir=iget(dev,inr);
- if (dir) {
- dir->i_atime=CURRENT_TIME;
- dir->i_dirt=1;
- }
- return dir;
-}
-
-/*
- * open_namei()
- *
- * 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)
-{
- const char * basename;
- int inr,dev,namelen;
- struct m_inode * dir, *inode;
- struct buffer_head * bh;
- struct dir_entry * de;
-
- if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
- flag |= O_WRONLY;
- mode &= 0777 & ~current->umask;
- mode |= I_REGULAR;
- if (!(dir = dir_namei(pathname,&namelen,&basename)))
- return -ENOENT;
- if (!namelen) { /* special case: '/usr/' etc */
- if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
- *res_inode=dir;
- return 0;
- }
- iput(dir);
- return -EISDIR;
- }
- bh = find_entry(&dir,basename,namelen,&de);
- if (!bh) {
- if (!(flag & O_CREAT)) {
- iput(dir);
- return -ENOENT;
- }
- 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);
- iput(dir);
- return -ENOSPC;
- }
- de->inode = inode->i_num;
- bh->b_dirt = 1;
- brelse(bh);
- iput(dir);
- *res_inode = inode;
- return 0;
- }
- inr = de->inode;
- dev = dir->i_dev;
- brelse(bh);
- iput(dir);
- if (flag & O_EXCL)
- return -EEXIST;
- if (!(inode=iget(dev,inr)))
- return -EACCES;
- if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
- !permission(inode,ACC_MODE(flag))) {
- iput(inode);
- return -EPERM;
- }
- inode->i_atime = CURRENT_TIME;
- if (flag & O_TRUNC)
- truncate(inode);
- *res_inode = inode;
- return 0;
-}
-
-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;
-
- if (!suser())
- return -EPERM;
- if (!(dir = dir_namei(filename,&namelen,&basename)))
- return -ENOENT;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
- }
- if (!permission(dir,MAY_WRITE)) {
- 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_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;
- }
- de->inode = inode->i_num;
- bh->b_dirt = 1;
- iput(dir);
- iput(inode);
- brelse(bh);
- return 0;
-}
-
-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;
-
- if (!suser())
- return -EPERM;
- if (!(dir = dir_namei(pathname,&namelen,&basename)))
- return -ENOENT;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
- }
- if (!permission(dir,MAY_WRITE)) {
- 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))) {
- 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);
- free_block(inode->i_dev,inode->i_zone[0]);
- 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);
- free_block(inode->i_dev,inode->i_zone[0]);
- inode->i_nlinks=0;
- iput(inode);
- return -ENOSPC;
- }
- de->inode = inode->i_num;
- bh->b_dirt = 1;
- dir->i_nlinks++;
- dir->i_dirt = 1;
- iput(dir);
- iput(inode);
- brelse(bh);
- return 0;
-}
-
-/*
- * routine to check that the specified directory is empty (for rmdir)
- */
-static int empty_dir(struct m_inode * inode)
-{
- int nr,block;
- int len;
- struct buffer_head * bh;
- struct dir_entry * de;
-
- len = inode->i_size / sizeof (struct dir_entry);
- if (len<2 || !inode->i_zone[0] ||
- !(bh=bread(inode->i_dev,inode->i_zone[0]))) {
- printk("warning - bad directory on dev %04x\n",inode->i_dev);
- return 0;
- }
- de = (struct dir_entry *) bh->b_data;
- if (de[0].inode != inode->i_num || !de[1].inode ||
- strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
- printk("warning - bad directory on dev %04x\n",inode->i_dev);
- return 0;
- }
- nr = 2;
- de += 2;
- while (nr<len) {
- if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
- brelse(bh);
- block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK);
- if (!block) {
- nr += DIR_ENTRIES_PER_BLOCK;
- continue;
- }
- if (!(bh=bread(inode->i_dev,block)))
- return 0;
- de = (struct dir_entry *) bh->b_data;
- }
- if (de->inode) {
- brelse(bh);
- return 0;
- }
- de++;
- nr++;
- }
- brelse(bh);
- return 1;
-}
-
-int sys_rmdir(const char * name)
-{
- const char * basename;
- int namelen;
- struct m_inode * dir, * inode;
- struct buffer_head * bh;
- struct dir_entry * de;
-
- if (!suser())
- return -EPERM;
- if (!(dir = dir_namei(name,&namelen,&basename)))
- return -ENOENT;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
- }
- bh = find_entry(&dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- return -ENOENT;
- }
- if (!permission(dir,MAY_WRITE)) {
- iput(dir);
- brelse(bh);
- return -EPERM;
- }
- if (!(inode = iget(dir->i_dev, de->inode))) {
- iput(dir);
- 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;
-}
-
-int sys_unlink(const char * name)
-{
- const char * basename;
- int namelen;
- struct m_inode * dir, * inode;
- struct buffer_head * bh;
- struct dir_entry * de;
-
- if (!(dir = dir_namei(name,&namelen,&basename)))
- return -ENOENT;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
- }
- if (!permission(dir,MAY_WRITE)) {
- iput(dir);
- return -EPERM;
- }
- bh = find_entry(&dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- return -ENOENT;
- }
- inode = iget(dir->i_dev, de->inode);
- if (!inode) {
- printk("iget failed in delete (%04x:%d)",dir->i_dev,de->inode);
- iput(dir);
- brelse(bh);
- return -ENOENT;
- }
- if (S_ISDIR(inode->i_mode)) {
- iput(inode);
- iput(dir);
- brelse(bh);
- return -EPERM;
- }
- /*
- * If the directory has the sticky bit, the user must either
- * own the file or own the directory or be the superuser to
- * delete a file in that directory. This is typically used
- * for /tmp and /usr/tmp.
- */
- if ((dir->i_mode & S_ISVTX) && (current->euid != inode->i_uid) &&
- (current->euid != dir->i_uid) && !suser()) {
- iput(inode);
- 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;
-}
-
-int sys_link(const char * oldname, const char * newname)
-{
- struct dir_entry * de;
- struct m_inode * oldinode, * dir;
- struct buffer_head * bh;
- const char * basename;
- int namelen;
-
- oldinode=namei(oldname);
- if (!oldinode)
- return -ENOENT;
- if (S_ISDIR(oldinode->i_mode)) {
- iput(oldinode);
- return -EPERM;
- }
- dir = dir_namei(newname,&namelen,&basename);
- if (!dir) {
- iput(oldinode);
- return -EACCES;
- }
- if (!namelen) {
- iput(oldinode);
- iput(dir);
- return -EPERM;
- }
- if (dir->i_dev != oldinode->i_dev) {
- iput(dir);
- iput(oldinode);
- return -EXDEV;
- }
- if (!permission(dir,MAY_WRITE)) {
- iput(dir);
- iput(oldinode);
- return -EACCES;
- }
- bh = find_entry(&dir,basename,namelen,&de);
- if (bh) {
- brelse(bh);
- iput(dir);
- iput(oldinode);
- return -EEXIST;
- }
- 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;
-}
-@
-
-
-1.1
-log
-@Initial revision
-@
-text
-@d43 1
-a43 3
- if (!(current->uid && current->euid))
- mode=0777;
- else if (current->uid==inode->i_uid || current->euid==inode->i_uid)
-d45 1
-a45 1
- else if (current->gid==inode->i_gid || current->egid==inode->i_gid)
-d47 3
-a49 1
- return mode & mask & 0007;
-d371 1
-d397 1
-a397 1
- permission(inode,ACC_MODE(flag))!=ACC_MODE(flag)) {
-d416 1
-a416 1
- if (current->euid && current->uid)
-d467 1
-a467 1
- if (current->euid && current->uid)
-d591 1
-a591 1
- if (current->euid && current->uid)
-d683 13
-@
+++ /dev/null
-head 1.2;
-branch ;
-access ;
-symbols ;
-locks ; strict;
-comment @ * @;
-
-
-1.2
-date 91.12.01.09.22.10; author tytso; state Exp;
-branches ;
-next 1.1;
-
-1.1
-date 91.11.21.09.38.53; author tytso; state Exp;
-branches ;
-next ;
-
-
-desc
-@@
-
-
-1.2
-log
-@Patches sent to Linus
-@
-text
-@/*
- * linux/fs/open.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-#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/tty.h>
-#include <linux/kernel.h>
-#include <asm/segment.h>
-
-int sys_ustat(int dev, struct ustat * ubuf)
-{
- return -ENOSYS;
-}
-
-int sys_utime(char * filename, struct utimbuf * times)
-{
- struct m_inode * inode;
- long actime,modtime;
-
- if (!(inode=namei(filename)))
- return -ENOENT;
- if (times) {
- actime = get_fs_long((unsigned long *) ×->actime);
- modtime = get_fs_long((unsigned long *) ×->modtime);
- } else
- actime = modtime = CURRENT_TIME;
- inode->i_atime = actime;
- inode->i_mtime = modtime;
- inode->i_dirt = 1;
- iput(inode);
- return 0;
-}
-
-/*
- * XXX should we use the real or effective uid? BSD uses the real uid,
- * so as to make this call useful to setuid programs.
- */
-int sys_access(const char * filename,int mode)
-{
- struct m_inode * inode;
- int res, i_mode;
-
- mode &= 0007;
- if (!(inode=namei(filename)))
- return -EACCES;
- i_mode = res = inode->i_mode & 0777;
- iput(inode);
- if (current->uid == inode->i_uid)
- res >>= 6;
- else if (current->gid == inode->i_gid)
- res >>= 6;
- if ((res & 0007 & mode) == mode)
- return 0;
- /*
- * XXX we are doing this test last because we really should be
- * swapping the effective with the real user id (temporarily),
- * and then calling suser() routine. If we do call the
- * suser() routine, it needs to be called last.
- */
- if ((!current->uid) &&
- (!(mode & 1) || (i_mode & 0111)))
- return 0;
- return -EACCES;
-}
-
-int sys_chdir(const char * filename)
-{
- struct m_inode * inode;
-
- if (!(inode = namei(filename)))
- return -ENOENT;
- if (!S_ISDIR(inode->i_mode)) {
- iput(inode);
- return -ENOTDIR;
- }
- iput(current->pwd);
- current->pwd = inode;
- return (0);
-}
-
-int sys_chroot(const char * filename)
-{
- struct m_inode * inode;
-
- if (!(inode=namei(filename)))
- return -ENOENT;
- if (!S_ISDIR(inode->i_mode)) {
- iput(inode);
- return -ENOTDIR;
- }
- iput(current->root);
- current->root = inode;
- return (0);
-}
-
-int sys_chmod(const char * filename,int mode)
-{
- struct m_inode * inode;
-
- if (!(inode=namei(filename)))
- return -ENOENT;
- if ((current->euid != inode->i_uid) && !suser()) {
- iput(inode);
- return -EACCES;
- }
- inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
- inode->i_dirt = 1;
- iput(inode);
- return 0;
-}
-
-int sys_chown(const char * filename,int uid,int gid)
-{
- struct m_inode * inode;
-
- if (!(inode=namei(filename)))
- return -ENOENT;
- if (!suser()) {
- iput(inode);
- return -EACCES;
- }
- inode->i_uid=uid;
- inode->i_gid=gid;
- inode->i_dirt=1;
- iput(inode);
- return 0;
-}
-
-int sys_open(const char * filename,int flag,int mode)
-{
- struct m_inode * inode;
- struct file * f;
- int i,fd;
-
- mode &= 0777 & ~current->umask;
- for(fd=0 ; fd<NR_OPEN ; fd++)
- if (!current->filp[fd])
- break;
- if (fd>=NR_OPEN)
- return -EINVAL;
- current->close_on_exec &= ~(1<<fd);
- f=0+file_table;
- for (i=0 ; i<NR_FILE ; i++,f++)
- if (!f->f_count) break;
- if (i>=NR_FILE)
- return -EINVAL;
- (current->filp[fd]=f)->f_count++;
- if ((i=open_namei(filename,flag,mode,&inode))<0) {
- current->filp[fd]=NULL;
- f->f_count=0;
- return i;
- }
-/* ttys are somewhat special (ttyxx major==4, tty major==5) */
- if (S_ISCHR(inode->i_mode))
- if (MAJOR(inode->i_zone[0])==4) {
- if (current->leader && current->tty<0) {
- current->tty = MINOR(inode->i_zone[0]);
- tty_table[current->tty].pgrp = current->pgrp;
- }
- } else if (MAJOR(inode->i_zone[0])==5)
- if (current->tty<0) {
- iput(inode);
- current->filp[fd]=NULL;
- f->f_count=0;
- return -EPERM;
- }
-/* 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_flags = flag;
- f->f_count = 1;
- f->f_inode = inode;
- f->f_pos = 0;
- return (fd);
-}
-
-int sys_creat(const char * pathname, int mode)
-{
- return sys_open(pathname, O_CREAT | O_TRUNC, mode);
-}
-
-int sys_close(unsigned int fd)
-{
- struct file * filp;
-
- if (fd >= NR_OPEN)
- return -EINVAL;
- current->close_on_exec &= ~(1<<fd);
- if (!(filp = current->filp[fd]))
- return -EINVAL;
- current->filp[fd] = NULL;
- if (filp->f_count == 0)
- panic("Close: file count is 0");
- if (--filp->f_count)
- return (0);
- iput(filp->f_inode);
- return (0);
-}
-@
-
-
-1.1
-log
-@Initial revision
-@
-text
-@d43 4
-d50 1
-a50 1
- int res;
-d55 1
-a55 1
- res = inode->i_mode & 0777;
-d57 1
-a57 6
- if (!(current->euid && current->uid))
- if (res & 0111)
- res = 0777;
- else
- res = 0666;
- if (current->euid == inode->i_uid)
-d59 1
-a59 1
- else if (current->egid == inode->i_gid)
-d63 9
-d111 4
-a114 6
- if (current->uid && current->euid)
- if (current->uid!=inode->i_uid && current->euid!=inode->i_uid) {
- iput(inode);
- return -EACCES;
- } else
- mode = (mode & 0777) | (inode->i_mode & 07000);
-d127 1
-a127 1
- if (current->uid && current->euid) {
-@
#define set_bit(nr,addr) ({\
register int res __asm__("ax"); \
-__asm__("btsl %2,%3\n\tsetb %%al":"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
+__asm__ __volatile__("btsl %2,%3\n\tsetb %%al": \
+"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
res;})
#define clear_bit(nr,addr) ({\
register int res __asm__("ax"); \
-__asm__("btrl %2,%3\n\tsetnb %%al":"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
+__asm__ __volatile__("btrl %2,%3\n\tsetnb %%al": \
+"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
res;})
#define find_first_zero(addr) ({ \
if (!(bh=sb->s_imap[inode->i_num>>13]))
panic("nonexistent imap in superblock");
if (clear_bit(inode->i_num&8191,bh->b_data))
- panic("free_inode: bit already cleared");
+ printk("free_inode: bit already cleared.\n\r");
bh->b_dirt = 1;
memset(inode,0,sizeof(*inode));
}
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_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
return 0;
}
+void inline invalidate_buffers(int dev)
+{
+ int i;
+ struct buffer_head * bh;
+
+ bh = start_buffer;
+ for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
+ if (bh->b_dev != dev)
+ continue;
+ wait_on_buffer(bh);
+ if (bh->b_dev == dev)
+ bh->b_uptodate = bh->b_dirt = 0;
+ }
+}
+
/*
* This routine checks whether a floppy has been changed, and
* invalidates all buffer-cache-entries in that case. This
void check_disk_change(int dev)
{
int i;
- struct buffer_head * bh;
if (MAJOR(dev) != 2)
return;
- dev=MINOR(dev) & 0x03; /* which floppy is it? */
- if (!floppy_change(dev))
+ if (!floppy_change(dev & 0x03))
return;
- dev |= 0x200;
for (i=0 ; i<NR_SUPER ; i++)
- if ((super_block[i].s_dev & 0xff03)==dev)
+ if (super_block[i].s_dev == dev)
put_super(super_block[i].s_dev);
- bh = start_buffer;
- for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
- if ((bh->b_dev & 0xff03) != dev)
- continue;
- wait_on_buffer(bh);
- if ((bh->b_dev & 0xff03) == dev)
- bh->b_uptodate = bh->b_dirt = 0;
- }
+ invalidate_inodes(dev);
+ invalidate_buffers(dev);
}
#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
* race-conditions. Most of the code is seldom used, (ie repeating),
* so it should be much more efficient than it looks.
*
- * The algoritm is changed: better, and an elusive bug removed.
- * LBT 11.11.91
+ * The algoritm is changed: hopefully better, and an elusive bug removed.
*/
#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
struct buffer_head * getblk(int dev,int block)
if (!BADNESS(tmp))
break;
}
+/* and repeat until we find something good */
} while ((tmp = tmp->b_next_free) != free_list);
if (!bh) {
sleep_on(&buffer_wait);
return NULL;
}
+#define COPYBLK(from,to) \
+__asm__("cld\n\t" \
+ "rep\n\t" \
+ "movsl\n\t" \
+ ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
+ :"cx","di","si")
+
+/*
+ * bread_page reads four buffers into memory at the desired address. It's
+ * a function of its own, as there is some speed to be got by reading them
+ * all at the same time, not waiting for one to be read, and then another
+ * etc.
+ */
+void bread_page(unsigned long address,int dev,int b[4])
+{
+ struct buffer_head * bh[4];
+ int i;
+
+ for (i=0 ; i<4 ; i++)
+ if (b[i]) {
+ if (bh[i] = getblk(dev,b[i]))
+ if (!bh[i]->b_uptodate)
+ ll_rw_block(READ,bh[i]);
+ } else
+ bh[i] = NULL;
+ for (i=0 ; i<4 ; i++,address += BLOCK_SIZE)
+ if (bh[i]) {
+ wait_on_buffer(bh[i]);
+ if (bh[i]->b_uptodate)
+ COPYBLK((unsigned long) bh[i]->b_data,address);
+ brelse(bh[i]);
+ }
+}
+
/*
* Ok, breada can be used as bread, but additionally to mark other
* blocks for reading as well. End the argument list with a negative
crw_ptr call_addr;
if (MAJOR(dev)>=NRDEVS)
- panic("rw_char: dev>NRDEV");
- if (!(call_addr=crw_table[MAJOR(dev)])) {
- printk("dev: %04x\n",dev);
- panic("Trying to r/w from/to nonexistent character device");
- }
+ return -ENODEV;
+ if (!(call_addr=crw_table[MAJOR(dev)]))
+ return -ENODEV;
return call_addr(rw,MINOR(dev),buf,count,pos);
}
* (C) 1991 Linus Torvalds
*/
+/*
+ * #!-checking implemented by tytso.
+ */
+
+/*
+ * Demand-loading implemented 01.12.91 - no need to read anything but
+ * the header into memory. The inode of the executable is put into
+ * "current->executable", and page faults do the actual loading. Clean.
+ *
+ * Once more I can proudly say that linux stood up to being changed: it
+ * was less than 2 hours work to get demand-loading completely implemented.
+ */
+
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
*/
#define MAX_ARG_PAGES 32
-#define cp_block(from,to) \
-__asm__("pushl $0x10\n\t" \
- "pushl $0x17\n\t" \
- "pop %%es\n\t" \
- "cld\n\t" \
- "rep\n\t" \
- "movsl\n\t" \
- "pop %%es" \
- ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
- :"cx","di","si")
-
-/*
- * read_head() reads blocks 1-6 (not 0). Block 0 has already been
- * read for header information.
- */
-int read_head(struct m_inode * inode,int blocks)
-{
- struct buffer_head * bh;
- int count;
-
- if (blocks>6)
- blocks=6;
- for(count = 0 ; count<blocks ; count++) {
- if (!inode->i_zone[count+1])
- continue;
- if (!(bh=bread(inode->i_dev,inode->i_zone[count+1])))
- return -1;
- cp_block(bh->b_data,count*BLOCK_SIZE);
- brelse(bh);
- }
- return 0;
-}
-
-int read_ind(int dev,int ind,long size,unsigned long offset)
-{
- struct buffer_head * ih, * bh;
- unsigned short * table,block;
-
- if (size<=0)
- panic("size<=0 in read_ind");
- if (size>512*BLOCK_SIZE)
- size=512*BLOCK_SIZE;
- if (!ind)
- return 0;
- if (!(ih=bread(dev,ind)))
- return -1;
- table = (unsigned short *) ih->b_data;
- while (size>0) {
- if (block=*(table++))
- if (!(bh=bread(dev,block))) {
- brelse(ih);
- return -1;
- } else {
- cp_block(bh->b_data,offset);
- brelse(bh);
- }
- size -= BLOCK_SIZE;
- offset += BLOCK_SIZE;
- }
- brelse(ih);
- return 0;
-}
-
-/*
- * read_area() reads an area into %fs:mem.
- */
-int read_area(struct m_inode * inode,long size)
-{
- struct buffer_head * dind;
- unsigned short * table;
- int i,count;
-
- if ((i=read_head(inode,(size+BLOCK_SIZE-1)/BLOCK_SIZE)) ||
- (size -= BLOCK_SIZE*6)<=0)
- return i;
- if ((i=read_ind(inode->i_dev,inode->i_zone[7],size,BLOCK_SIZE*6)) ||
- (size -= BLOCK_SIZE*512)<=0)
- return i;
- if (!(i=inode->i_zone[8]))
- return 0;
- if (!(dind = bread(inode->i_dev,i)))
- return -1;
- table = (unsigned short *) dind->b_data;
- for(count=0 ; count<512 ; count++)
- if ((i=read_ind(inode->i_dev,*(table++),size,
- BLOCK_SIZE*(518+count))) || (size -= BLOCK_SIZE*512)<=0)
- return i;
- panic("Impossibly long executable");
-}
-
/*
* create_tables() parses the env- and arg-strings in new user
* memory and creates the pointer tables from them, and puts their
int e_uid, e_gid;
int retval;
int sh_bang = 0;
- char *buf = 0;
unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
if ((0xffff & eip[1]) != 0x000f)
* Sorta complicated, but hopefully it will work. -TYT
*/
- char *cp, *interp, *i_name, *i_arg;
+ char buf[1023], *cp, *interp, *i_name, *i_arg;
unsigned long old_fs;
- if (!buf)
- buf = malloc(1024);
strncpy(buf, bh->b_data+2, 1022);
brelse(bh);
iput(inode);
}
}
/* OK, This is the point of no return */
- if (buf)
- free_s(buf, 1024);
+ if (current->executable)
+ iput(current->executable);
+ current->executable = inode;
for (i=0 ; i<32 ; i++)
current->sigaction[i].sa_handler = NULL;
for (i=0 ; i<NR_OPEN ; i++)
current->start_stack = p & 0xfffff000;
current->euid = e_uid;
current->egid = e_gid;
- i = read_area(inode,ex.a_text+ex.a_data);
- iput(inode);
- if (i<0)
- sys_exit(-1);
i = ex.a_text+ex.a_data;
while (i&0xfff)
put_fs_byte(0,(char *) (i++));
exec_error2:
iput(inode);
exec_error1:
- if (buf)
- free(buf);
for (i=0 ; i<MAX_ARG_PAGES ; i++)
free_page(page[i]);
return(retval);
+++ /dev/null
-/*
- * linux/fs/exec.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-#include <errno.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <a.out.h>
-
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <asm/segment.h>
-
-extern int sys_exit(int exit_code);
-extern int sys_close(int fd);
-
-/*
- * MAX_ARG_PAGES defines the number of pages allocated for arguments
- * and envelope for the new program. 32 should suffice, this gives
- * a maximum env+arg of 128kB !
- */
-#define MAX_ARG_PAGES 32
-
-#define cp_block(from,to) \
-__asm__("pushl $0x10\n\t" \
- "pushl $0x17\n\t" \
- "pop %%es\n\t" \
- "cld\n\t" \
- "rep\n\t" \
- "movsl\n\t" \
- "pop %%es" \
- ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
- :"cx","di","si")
-
-/*
- * read_head() reads blocks 1-6 (not 0). Block 0 has already been
- * read for header information.
- */
-int read_head(struct m_inode * inode,int blocks)
-{
- struct buffer_head * bh;
- int count;
-
- if (blocks>6)
- blocks=6;
- for(count = 0 ; count<blocks ; count++) {
- if (!inode->i_zone[count+1])
- continue;
- if (!(bh=bread(inode->i_dev,inode->i_zone[count+1])))
- return -1;
- cp_block(bh->b_data,count*BLOCK_SIZE);
- brelse(bh);
- }
- return 0;
-}
-
-int read_ind(int dev,int ind,long size,unsigned long offset)
-{
- struct buffer_head * ih, * bh;
- unsigned short * table,block;
-
- if (size<=0)
- panic("size<=0 in read_ind");
- if (size>512*BLOCK_SIZE)
- size=512*BLOCK_SIZE;
- if (!ind)
- return 0;
- if (!(ih=bread(dev,ind)))
- return -1;
- table = (unsigned short *) ih->b_data;
- while (size>0) {
- if (block=*(table++))
- if (!(bh=bread(dev,block))) {
- brelse(ih);
- return -1;
- } else {
- cp_block(bh->b_data,offset);
- brelse(bh);
- }
- size -= BLOCK_SIZE;
- offset += BLOCK_SIZE;
- }
- brelse(ih);
- return 0;
-}
-
-/*
- * read_area() reads an area into %fs:mem.
- */
-int read_area(struct m_inode * inode,long size)
-{
- struct buffer_head * dind;
- unsigned short * table;
- int i,count;
-
- if ((i=read_head(inode,(size+BLOCK_SIZE-1)/BLOCK_SIZE)) ||
- (size -= BLOCK_SIZE*6)<=0)
- return i;
- if ((i=read_ind(inode->i_dev,inode->i_zone[7],size,BLOCK_SIZE*6)) ||
- (size -= BLOCK_SIZE*512)<=0)
- return i;
- if (!(i=inode->i_zone[8]))
- return 0;
- if (!(dind = bread(inode->i_dev,i)))
- return -1;
- table = (unsigned short *) dind->b_data;
- for(count=0 ; count<512 ; count++)
- if ((i=read_ind(inode->i_dev,*(table++),size,
- BLOCK_SIZE*(518+count))) || (size -= BLOCK_SIZE*512)<=0)
- return i;
- panic("Impossibly long executable");
-}
-
-/*
- * create_tables() parses the env- and arg-strings in new user
- * memory and creates the pointer tables from them, and puts their
- * addresses on the "stack", returning the new stack pointer value.
- */
-static unsigned long * create_tables(char * p,int argc,int envc)
-{
- unsigned long *argv,*envp;
- unsigned long * sp;
-
- sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
- sp -= envc+1;
- envp = sp;
- sp -= argc+1;
- argv = sp;
- put_fs_long((unsigned long)envp,--sp);
- put_fs_long((unsigned long)argv,--sp);
- put_fs_long((unsigned long)argc,--sp);
- while (argc-->0) {
- put_fs_long((unsigned long) p,argv++);
- while (get_fs_byte(p++)) /* nothing */ ;
- }
- put_fs_long(0,argv);
- while (envc-->0) {
- put_fs_long((unsigned long) p,envp++);
- while (get_fs_byte(p++)) /* nothing */ ;
- }
- put_fs_long(0,envp);
- return sp;
-}
-
-/*
- * count() counts the number of arguments/envelopes
- */
-static int count(char ** argv)
-{
- int i=0;
- char ** tmp;
-
- if (tmp = argv)
- while (get_fs_long((unsigned long *) (tmp++)))
- i++;
-
- return i;
-}
-
-/*
- * 'copy_string()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- *
- * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies
- * whether the string and the string array are from user or kernel segments:
- *
- * from_kmem argv * argv **
- * 0 user space user space
- * 1 kernel space user space
- * 2 kernel space kernel space
- *
- * We do this by playing games with the fs segment register. Since it
- * it is expensive to load a segment register, we try to avoid calling
- * set_fs() unless we absolutely have to.
- */
-static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
- unsigned long p, int from_kmem)
-{
- char *tmp, *pag;
- int len, offset = 0;
- unsigned long old_fs, new_fs;
-
- if (!p)
- return 0; /* bullet-proofing */
- new_fs = get_ds();
- old_fs = get_fs();
- if (from_kmem==2)
- set_fs(new_fs);
- while (argc-- > 0) {
- if (from_kmem == 1)
- set_fs(new_fs);
- if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))
- panic("argc is wrong");
- if (from_kmem == 1)
- set_fs(old_fs);
- len=0; /* remember zero-padding */
- do {
- len++;
- } while (get_fs_byte(tmp++));
- if (p-len < 0) { /* this shouldn't happen - 128kB */
- set_fs(old_fs);
- return 0;
- }
- while (len) {
- --p; --tmp; --len;
- if (--offset < 0) {
- offset = p % PAGE_SIZE;
- if (from_kmem==2)
- set_fs(old_fs);
- if (!(pag = (char *) page[p/PAGE_SIZE]) &&
- !(pag = (char *) page[p/PAGE_SIZE] =
- (unsigned long *) get_free_page()))
- return 0;
- if (from_kmem==2)
- set_fs(new_fs);
-
- }
- *(pag + offset) = get_fs_byte(tmp);
- }
- }
- if (from_kmem==2)
- set_fs(old_fs);
- return p;
-}
-
-static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
-{
- unsigned long code_limit,data_limit,code_base,data_base;
- int i;
-
- code_limit = text_size+PAGE_SIZE -1;
- code_limit &= 0xFFFFF000;
- data_limit = 0x4000000;
- code_base = get_base(current->ldt[1]);
- data_base = code_base;
- set_base(current->ldt[1],code_base);
- set_limit(current->ldt[1],code_limit);
- set_base(current->ldt[2],data_base);
- set_limit(current->ldt[2],data_limit);
-/* make sure fs points to the NEW data segment */
- __asm__("pushl $0x17\n\tpop %%fs"::);
- data_base += data_limit;
- for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
- data_base -= PAGE_SIZE;
- if (page[i])
- put_page(page[i],data_base);
- }
- return data_limit;
-}
-
-/*
- * 'do_execve()' executes a new program.
- */
-int do_execve(unsigned long * eip,long tmp,char * filename,
- char ** argv, char ** envp)
-{
- struct m_inode * inode;
- struct buffer_head * bh;
- struct exec ex;
- unsigned long page[MAX_ARG_PAGES];
- int i,argc,envc;
- int e_uid, e_gid;
- int retval;
- int sh_bang = 0;
- unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
-
- if ((0xffff & eip[1]) != 0x000f)
- panic("execve called from supervisor mode");
- for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
- page[i]=0;
- if (!(inode=namei(filename))) /* get executables inode */
- return -ENOENT;
- argc = count(argv);
- envc = count(envp);
-
-restart_interp:
- if (!S_ISREG(inode->i_mode)) { /* must be regular file */
- retval = -EACCES;
- 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;
- if (current->euid == inode->i_uid)
- i >>= 6;
- else if (current->egid == inode->i_gid)
- i >>= 3;
- if (!(i & 1) &&
- !((inode->i_mode & 0111) && suser())) {
- retval = -ENOEXEC;
- goto exec_error2;
- }
- if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
- retval = -EACCES;
- goto exec_error2;
- }
- ex = *((struct exec *) bh->b_data); /* read exec-header */
- if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
- /*
- * This section does the #! interpretation.
- * Sorta complicated, but hopefully it will work. -TYT
- */
-
- char buf[1023], *cp, *interp, *i_name, *i_arg;
- unsigned long old_fs;
-
- strncpy(buf, bh->b_data+2, 1022);
- brelse(bh);
- iput(inode);
- buf[1022] = '\0';
- if (cp = strchr(buf, '\n')) {
- *cp = '\0';
- for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
- }
- if (!cp || *cp == '\0') {
- retval = -ENOEXEC; /* No interpreter name found */
- goto exec_error1;
- }
- interp = i_name = cp;
- i_arg = 0;
- for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
- if (*cp == '/')
- i_name = cp+1;
- }
- if (*cp) {
- *cp++ = '\0';
- i_arg = cp;
- }
- /*
- * OK, we've parsed out the interpreter name and
- * (optional) argument.
- */
- if (sh_bang++ == 0) {
- p = copy_strings(envc, envp, page, p, 0);
- p = copy_strings(--argc, argv+1, page, p, 0);
- }
- /*
- * Splice in (1) the interpreter's name for argv[0]
- * (2) (optional) argument to interpreter
- * (3) filename of shell script
- *
- * This is done in reverse order, because of how the
- * user environment and arguments are stored.
- */
- p = copy_strings(1, &filename, page, p, 1);
- argc++;
- if (i_arg) {
- p = copy_strings(1, &i_arg, page, p, 2);
- argc++;
- }
- p = copy_strings(1, &i_name, page, p, 2);
- argc++;
- if (!p) {
- retval = -ENOMEM;
- goto exec_error1;
- }
- /*
- * OK, now restart the process with the interpreter's inode.
- */
- old_fs = get_fs();
- set_fs(get_ds());
- if (!(inode=namei(interp))) { /* get executables inode */
- set_fs(old_fs);
- retval = -ENOENT;
- goto exec_error1;
- }
- set_fs(old_fs);
- goto restart_interp;
- }
- brelse(bh);
- if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
- ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
- inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
- retval = -ENOEXEC;
- goto exec_error2;
- }
- if (N_TXTOFF(ex) != BLOCK_SIZE) {
- printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
- retval = -ENOEXEC;
- goto exec_error2;
- }
- if (!sh_bang) {
- p = copy_strings(envc,envp,page,p,0);
- p = copy_strings(argc,argv,page,p,0);
- if (!p) {
- retval = -ENOMEM;
- goto exec_error2;
- }
- }
-/* OK, This is the point of no return */
- for (i=0 ; i<32 ; i++)
- current->sigaction[i].sa_handler = NULL;
- for (i=0 ; i<NR_OPEN ; i++)
- if ((current->close_on_exec>>i)&1)
- sys_close(i);
- current->close_on_exec = 0;
- free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
- free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
- if (last_task_used_math == current)
- last_task_used_math = NULL;
- current->used_math = 0;
- p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
- p = (unsigned long) create_tables((char *)p,argc,envc);
- current->brk = ex.a_bss +
- (current->end_data = ex.a_data +
- (current->end_code = ex.a_text));
- current->start_stack = p & 0xfffff000;
- current->euid = e_uid;
- current->egid = e_gid;
- i = read_area(inode,ex.a_text+ex.a_data);
- iput(inode);
- if (i<0)
- sys_exit(-1);
- i = ex.a_text+ex.a_data;
- while (i&0xfff)
- put_fs_byte(0,(char *) (i++));
- eip[0] = ex.a_entry; /* eip, magic happens :-) */
- eip[3] = p; /* stack pointer */
- return 0;
-exec_error2:
- iput(inode);
-exec_error1:
- for (i=0 ; i<MAX_ARG_PAGES ; i++)
- free_page(page[i]);
- return(retval);
-}
+++ /dev/null
-/*
- * linux/fs/exec.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-#include <errno.h>
-#include <sys/stat.h>
-#include <a.out.h>
-
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <asm/segment.h>
-
-extern int sys_exit(int exit_code);
-extern int sys_close(int fd);
-
-/*
- * MAX_ARG_PAGES defines the number of pages allocated for arguments
- * and envelope for the new program. 32 should suffice, this gives
- * a maximum env+arg of 128kB !
- */
-#define MAX_ARG_PAGES 32
-
-#define cp_block(from,to) \
-__asm__("pushl $0x10\n\t" \
- "pushl $0x17\n\t" \
- "pop %%es\n\t" \
- "cld\n\t" \
- "rep\n\t" \
- "movsl\n\t" \
- "pop %%es" \
- ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
- :"cx","di","si")
-
-/*
- * read_head() reads blocks 1-6 (not 0). Block 0 has already been
- * read for header information.
- */
-int read_head(struct m_inode * inode,int blocks)
-{
- struct buffer_head * bh;
- int count;
-
- if (blocks>6)
- blocks=6;
- for(count = 0 ; count<blocks ; count++) {
- if (!inode->i_zone[count+1])
- continue;
- if (!(bh=bread(inode->i_dev,inode->i_zone[count+1])))
- return -1;
- cp_block(bh->b_data,count*BLOCK_SIZE);
- brelse(bh);
- }
- return 0;
-}
-
-int read_ind(int dev,int ind,long size,unsigned long offset)
-{
- struct buffer_head * ih, * bh;
- unsigned short * table,block;
-
- if (size<=0)
- panic("size<=0 in read_ind");
- if (size>512*BLOCK_SIZE)
- size=512*BLOCK_SIZE;
- if (!ind)
- return 0;
- if (!(ih=bread(dev,ind)))
- return -1;
- table = (unsigned short *) ih->b_data;
- while (size>0) {
- if (block=*(table++))
- if (!(bh=bread(dev,block))) {
- brelse(ih);
- return -1;
- } else {
- cp_block(bh->b_data,offset);
- brelse(bh);
- }
- size -= BLOCK_SIZE;
- offset += BLOCK_SIZE;
- }
- brelse(ih);
- return 0;
-}
-
-/*
- * read_area() reads an area into %fs:mem.
- */
-int read_area(struct m_inode * inode,long size)
-{
- struct buffer_head * dind;
- unsigned short * table;
- int i,count;
-
- if ((i=read_head(inode,(size+BLOCK_SIZE-1)/BLOCK_SIZE)) ||
- (size -= BLOCK_SIZE*6)<=0)
- return i;
- if ((i=read_ind(inode->i_dev,inode->i_zone[7],size,BLOCK_SIZE*6)) ||
- (size -= BLOCK_SIZE*512)<=0)
- return i;
- if (!(i=inode->i_zone[8]))
- return 0;
- if (!(dind = bread(inode->i_dev,i)))
- return -1;
- table = (unsigned short *) dind->b_data;
- for(count=0 ; count<512 ; count++)
- if ((i=read_ind(inode->i_dev,*(table++),size,
- BLOCK_SIZE*(518+count))) || (size -= BLOCK_SIZE*512)<=0)
- return i;
- panic("Impossibly long executable");
-}
-
-/*
- * create_tables() parses the env- and arg-strings in new user
- * memory and creates the pointer tables from them, and puts their
- * addresses on the "stack", returning the new stack pointer value.
- */
-static unsigned long * create_tables(char * p,int argc,int envc)
-{
- unsigned long *argv,*envp;
- unsigned long * sp;
-
- sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
- sp -= envc+1;
- envp = sp;
- sp -= argc+1;
- argv = sp;
- put_fs_long((unsigned long)envp,--sp);
- put_fs_long((unsigned long)argv,--sp);
- put_fs_long((unsigned long)argc,--sp);
- while (argc-->0) {
- put_fs_long((unsigned long) p,argv++);
- while (get_fs_byte(p++)) /* nothing */ ;
- }
- put_fs_long(0,argv);
- while (envc-->0) {
- put_fs_long((unsigned long) p,envp++);
- while (get_fs_byte(p++)) /* nothing */ ;
- }
- put_fs_long(0,envp);
- return sp;
-}
-
-/*
- * count() counts the number of arguments/envelopes
- */
-static int count(char ** argv)
-{
- int i=0;
- char ** tmp;
-
- if (tmp = argv)
- while (get_fs_long((unsigned long *) (tmp++)))
- i++;
-
- return i;
-}
-
-/*
- * 'copy_string()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- */
-static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
- unsigned long p)
-{
- int len,i;
- char *tmp;
-
- while (argc-- > 0) {
- if (!(tmp = (char *)get_fs_long(((unsigned long *) argv)+argc)))
- panic("argc is wrong");
- len=0; /* remember zero-padding */
- do {
- len++;
- } while (get_fs_byte(tmp++));
- if (p-len < 0) /* this shouldn't happen - 128kB */
- return 0;
- i = ((unsigned) (p-len)) >> 12;
- while (i<MAX_ARG_PAGES && !page[i]) {
- if (!(page[i]=get_free_page()))
- return 0;
- i++;
- }
- do {
- --p;
- if (!page[p/PAGE_SIZE])
- panic("nonexistent page in exec.c");
- ((char *) page[p/PAGE_SIZE])[p%PAGE_SIZE] =
- get_fs_byte(--tmp);
- } while (--len);
- }
- return p;
-}
-
-static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
-{
- unsigned long code_limit,data_limit,code_base,data_base;
- int i;
-
- code_limit = text_size+PAGE_SIZE -1;
- code_limit &= 0xFFFFF000;
- data_limit = 0x4000000;
- code_base = get_base(current->ldt[1]);
- data_base = code_base;
- set_base(current->ldt[1],code_base);
- set_limit(current->ldt[1],code_limit);
- set_base(current->ldt[2],data_base);
- set_limit(current->ldt[2],data_limit);
-/* make sure fs points to the NEW data segment */
- __asm__("pushl $0x17\n\tpop %%fs"::);
- data_base += data_limit;
- for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
- data_base -= PAGE_SIZE;
- if (page[i])
- put_page(page[i],data_base);
- }
- return data_limit;
-}
-
-/*
- * 'do_execve()' executes a new program.
- */
-int do_execve(unsigned long * eip,long tmp,char * filename,
- char ** argv, char ** envp)
-{
- struct m_inode * inode;
- struct buffer_head * bh;
- struct exec ex;
- unsigned long page[MAX_ARG_PAGES];
- int i,argc,envc;
- int e_uid, e_gid;
- unsigned long p;
- int retval;
- int interp = 0;
-
- if ((0xffff & eip[1]) != 0x000f)
- panic("execve called from supervisor mode");
- for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
- page[i]=0;
- if (!(inode=namei(filename))) { /* get executables inode */
- retval = -ENOENT;
- goto exec_error1;
- }
- argc = count(argv);
- envc = count(envp);
-
-restart_interp:
- e_uid = current->euid; /* Note this means no setuid */
- e_gid = current->egid; /* shell scripts! */
- if (!S_ISREG(inode->i_mode)) { /* must be regular file */
- retval = -EACCES;
- goto exec_error2;
- }
- i = inode->i_mode;
- if (i & S_ISUID)
- e_uid = inode->i_uid;
- if (i & S_ISGID)
- e_gid = inode->i_gid;
- if (current->euid == inode->i_uid)
- i >>= 6;
- else if (current->egid == inode->i_gid)
- i >>= 3;
- if (!(i & 1) &&
- !((inode->i_mode & 111) && suser())) {
- retval = -ENOEXEC;
- goto exec_error2;
- }
- if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
- retval = -EACCES;
- goto exec_error2;
- }
- ex = *((struct exec *) bh->b_data); /* read exec-header */
- if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (interp > 3)) {
- /*
- * This section does the #! interpretation.
- * Gee, I hope the C compiler is intelligent about this,
- * and only activates this sub-frame when necessary.
- */
- char buf[1023], *cp, *interp, *i_name, *i_arg;
- int len;
-
- strncpy(buf, bh->b_data+2, 1022);
- brelse(bh);
- iput(inode);
- buf[1022] = '\0';
- if (!(cp = strchr(buf, '\n'))) {
- retval = -ENOEXEC;
- goto exec_error1;
- }
- *cp = '\0';
- for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++) ;
- if (*cp == '\0') {
- retval = -ENOEXEC; /* No interpreter name found */
- goto exec_error1;
- }
- interp = i_name = cp;
- for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
- if (*cp == '/')
- i_name = cp;
- }
- if (*cp) {
- *cp++ = '\0';
- i_arg = cp;
- } else
- i_arg = 0;
- /*
- * OK, we've parsed out the interpreter name and
- * (optional) argument.
- */
- if (interp++ == 0) {
- p = copy_strings(envc,envp,page,
- PAGE_SIZE*MAX_ARG_PAGES-4);
- p = copy_strings(--argc,argv+1,page,p);
- }
- /*
- * Copy in interpreter name
- */
- len = strlen(i_name) + 1;
- i = ((unsigned) (p-len)) >> 12;
- while (i<MAX_ARG_PAGES && !page[i]) {
- if (!(page[i]=get_free_page())) {
- retval = -ENOMEM;
- goto exec_error1;
- }
- i++;
- }
- do {
- --p;
- if (!page[p/PAGE_SIZE])
- panic("nonexistent page in exec.c");
- ((char *) page[p/PAGE_SIZE])[p%PAGE_SIZE] =
- i_name[--len];
- } while (len);
- /*
- * OK, now restart the process with the interpreter's inode.
- */
- if (!(inode=namei(interpreter))) { /* get executables inode */
- retval = -ENOENT;
- goto exec_error1;
- }
- goto restart_interp;
- } else
- brelse(bh);
- if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
- ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
- inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
- retval = -ENOEXEC;
- goto exec_error2;
- }
- if (N_TXTOFF(ex) != BLOCK_SIZE) {
- printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
- retval = -ENOEXEC;
- goto exec_error2;
- }
- if (!interp) {
- p = copy_strings(envc,envp,page,PAGE_SIZE*MAX_ARG_PAGES-4);
- p = copy_strings(argc,argv,page,p);
- }
- if (!p) {
- for (i=0 ; i<MAX_ARG_PAGES ; i++)
- free_page(page[i]);
- retval = -ENOMEM;
- goto exec_error2;
- }
-/* OK, This is the point of no return */
- for (i=0 ; i<32 ; i++)
- current->sigaction[i].sa_handler = NULL;
- for (i=0 ; i<NR_OPEN ; i++)
- if ((current->close_on_exec>>i)&1)
- sys_close(i);
- current->close_on_exec = 0;
- free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
- free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
- if (last_task_used_math == current)
- last_task_used_math = NULL;
- current->used_math = 0;
- p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
- p = (unsigned long) create_tables((char *)p,argc,envc);
- current->brk = ex.a_bss +
- (current->end_data = ex.a_data +
- (current->end_code = ex.a_text));
- current->start_stack = p & 0xfffff000;
- current->euid = e_uid;
- current->egid = e_gid;
- i = read_area(inode,ex.a_text+ex.a_data);
- iput(inode);
- if (i<0)
- sys_exit(-1);
- i = ex.a_text+ex.a_data;
- while (i&0xfff)
- put_fs_byte(0,(char *) (i++));
- eip[0] = ex.a_entry; /* eip, magic happens :-) */
- eip[3] = p; /* stack pointer */
- return 0;
-exec_error2:
- iput(inode);
-exec_error1:
- for (i=0 ; i<MAX_ARG_PAGES ; i++)
- free_page(page[i]);
- return(retval);
-}
wake_up(&inode->i_wait);
}
+void invalidate_inodes(int dev)
+{
+ int i;
+ struct m_inode * inode;
+
+ inode = 0+inode_table;
+ for(i=0 ; i<NR_INODE ; i++,inode++) {
+ wait_on_inode(inode);
+ if (inode->i_dev == dev) {
+ if (inode->i_count)
+ printk("inode in use on removed disk\n\r");
+ inode->i_dev = inode->i_dirt = 0;
+ }
+ }
+}
+
void sync_inodes(void)
{
int i;
inode->i_pipe=0;
return;
}
- if (!inode->i_dev || inode->i_count>1) {
+ if (!inode->i_dev) {
inode->i_count--;
return;
}
-repeat:
if (S_ISBLK(inode->i_mode)) {
sync_dev(inode->i_zone[0]);
wait_on_inode(inode);
}
+repeat:
+ if (inode->i_count>1) {
+ inode->i_count--;
+ return;
+ }
if (!inode->i_nlinks) {
truncate(inode);
free_inode(inode);
return;
}
-static volatile int last_allocated_inode = 0;
-
struct m_inode * get_empty_inode(void)
{
struct m_inode * inode;
- int inr;
+ static struct m_inode * last_inode = inode_table;
+ int i;
- while (1) {
+ do {
inode = NULL;
- inr = last_allocated_inode;
- do {
- if (!inode_table[inr].i_count) {
- inode = inr + inode_table;
- break;
+ for (i = NR_INODE; i ; i--) {
+ if (++last_inode >= inode_table + NR_INODE)
+ last_inode = inode_table;
+ if (!last_inode->i_count) {
+ inode = last_inode;
+ if (!inode->i_dirt && !inode->i_lock)
+ break;
}
- inr++;
- if (inr>=NR_INODE)
- inr=0;
- } while (inr != last_allocated_inode);
+ }
if (!inode) {
- for (inr=0 ; inr<NR_INODE ; inr++)
- printk("%04x: %6d\t",inode_table[inr].i_dev,
- inode_table[inr].i_num);
+ for (i=0 ; i<NR_INODE ; i++)
+ printk("%04x: %6d\t",inode_table[i].i_dev,
+ inode_table[i].i_num);
panic("No free inodes in mem");
}
- last_allocated_inode = inr;
wait_on_inode(inode);
while (inode->i_dirt) {
write_inode(inode);
wait_on_inode(inode);
}
- if (!inode->i_count)
- break;
- }
+ } while (inode->i_count);
memset(inode,0,sizeof(*inode));
inode->i_count = 1;
return inode;
int block;
lock_inode(inode);
- sb=get_super(inode->i_dev);
+ 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)))
int block;
lock_inode(inode);
- sb=get_super(inode->i_dev);
+ 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)))
return -EINVAL;
dev = filp->f_inode->i_zone[0];
if (MAJOR(dev) >= NRDEVS)
- panic("unknown device for ioctl");
+ return -ENODEV;
if (!ioctl_table[MAJOR(dev)])
return -ENOTTY;
return ioctl_table[MAJOR(dev)](dev,cmd,arg);
* (C) 1991 Linus Torvalds
*/
+/*
+ * Some corrections by tytso.
+ */
+
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
/*
* find_entry()
*
- * finds and entry in the specified directory with the wanted name. It
+ * 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.
iput(dir);
return -ENOENT;
}
+ if (!permission(dir,MAY_WRITE)) {
+ iput(dir);
+ return -EPERM;
+ }
bh = find_entry(&dir,basename,namelen,&de);
if (!bh) {
iput(dir);
return -ENOENT;
}
- if (!permission(dir,MAY_WRITE)) {
+ if (!(inode = iget(dir->i_dev, de->inode))) {
iput(dir);
brelse(bh);
return -EPERM;
}
- if (!(inode = iget(dir->i_dev, de->inode))) {
+ 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;
}
iput(dir);
return -ENOENT;
}
- inode = iget(dir->i_dev, de->inode);
- if (!inode) {
- printk("iget failed in delete (%04x:%d)",dir->i_dev,de->inode);
+ if (!(inode = iget(dir->i_dev, de->inode))) {
iput(dir);
brelse(bh);
return -ENOENT;
}
- if (S_ISDIR(inode->i_mode)) {
- iput(inode);
+ 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 the directory has the sticky bit, the user must either
- * own the file or own the directory or be the superuser to
- * delete a file in that directory. This is typically used
- * for /tmp and /usr/tmp.
- */
- if ((dir->i_mode & S_ISVTX) && (current->euid != inode->i_uid) &&
- (current->euid != dir->i_uid) && !suser()) {
+ if (S_ISDIR(inode->i_mode)) {
iput(inode);
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);
+++ /dev/null
-/*
- * linux/fs/namei.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <asm/segment.h>
-
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <const.h>
-#include <sys/stat.h>
-
-#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])
-
-/*
- * comment out this line if you want names > 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()
- *
- * is used to check for read/write/execute permissions on a file.
- * 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 mode = inode->i_mode;
-
-/* special case: not even root can read/write a deleted file */
- if (inode->i_dev && !inode->i_nlinks)
- return 0;
- else if (current->euid==inode->i_uid)
- mode >>= 6;
- else if (current->egid==inode->i_gid)
- mode >>= 3;
- return mode & mask & 0007;
-}
-
-/*
- * 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;
- 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 and 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.
- */
-static struct buffer_head * find_entry(struct m_inode ** dir,
- const char * name, int namelen, struct dir_entry ** res_dir)
-{
- 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;
- if (!namelen)
- return 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++;
- }
- }
- }
- 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++;
- }
- brelse(bh);
- return NULL;
-}
-
-/*
- * add_entry()
- *
- * adds a file entry to the specified directory, using the same
- * semantics as find_entry(). It returns NULL if it failed.
- *
- * NOTE!! The inode part of 'de' is left at 0 - which means you
- * may not sleep between calling this and putting something into
- * the entry, as someone else might have used it while you slept.
- */
-static struct buffer_head * add_entry(struct m_inode * dir,
- const char * name, int namelen, struct dir_entry ** res_dir)
-{
- int block,i;
- struct buffer_head * bh;
- struct dir_entry * de;
-
- *res_dir = NULL;
-#ifdef NO_TRUNCATE
- if (namelen > NAME_LEN)
- return NULL;
-#else
- if (namelen > NAME_LEN)
- namelen = NAME_LEN;
-#endif
- if (!namelen)
- return NULL;
- if (!(block = dir->i_zone[0]))
- return NULL;
- if (!(bh = bread(dir->i_dev,block)))
- return NULL;
- i = 0;
- de = (struct dir_entry *) bh->b_data;
- while (1) {
- if ((char *)de >= BLOCK_SIZE+bh->b_data) {
- brelse(bh);
- bh = NULL;
- block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK);
- if (!block)
- return NULL;
- if (!(bh = bread(dir->i_dev,block))) {
- i += DIR_ENTRIES_PER_BLOCK;
- continue;
- }
- de = (struct dir_entry *) bh->b_data;
- }
- if (i*sizeof(struct dir_entry) >= dir->i_size) {
- de->inode=0;
- dir->i_size = (i+1)*sizeof(struct dir_entry);
- dir->i_dirt = 1;
- dir->i_ctime = CURRENT_TIME;
- }
- if (!de->inode) {
- dir->i_mtime = CURRENT_TIME;
- for (i=0; i < NAME_LEN ; i++)
- de->name[i]=(i<namelen)?get_fs_byte(name+i):0;
- bh->b_dirt = 1;
- *res_dir = de;
- return bh;
- }
- de++;
- i++;
- }
- brelse(bh);
- return NULL;
-}
-
-/*
- * get_dir()
- *
- * Getdir traverses the pathname until it hits the topmost directory.
- * It returns NULL on failure.
- */
-static struct m_inode * get_dir(const char * pathname)
-{
- char c;
- const char * thisname;
- struct m_inode * inode;
- struct buffer_head * bh;
- int namelen,inr,idev;
- struct dir_entry * de;
-
- if (!current->root || !current->root->i_count)
- panic("No root inode");
- if (!current->pwd || !current->pwd->i_count)
- panic("No cwd inode");
- if ((c=get_fs_byte(pathname))=='/') {
- inode = current->root;
- pathname++;
- } else if (c)
- inode = current->pwd;
- else
- return NULL; /* empty name is bad */
- inode->i_count++;
- while (1) {
- thisname = pathname;
- if (!S_ISDIR(inode->i_mode) ||
- !(permission(inode,MAY_EXEC) || suser())) {
- iput(inode);
- return NULL;
- }
- for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++)
- /* nothing */ ;
- if (!c)
- return inode;
- if (!(bh = find_entry(&inode,thisname,namelen,&de))) {
- iput(inode);
- return NULL;
- }
- inr = de->inode;
- idev = inode->i_dev;
- brelse(bh);
- iput(inode);
- if (!(inode = iget(idev,inr)))
- return NULL;
- }
-}
-
-/*
- * 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)
-{
- char c;
- const char * basename;
- struct m_inode * dir;
-
- if (!(dir = get_dir(pathname)))
- return NULL;
- basename = pathname;
- while (c=get_fs_byte(pathname++))
- if (c=='/')
- basename=pathname;
- *namelen = pathname-basename-1;
- *name = basename;
- return dir;
-}
-
-/*
- * namei()
- *
- * is used by most simple commands to get the inode of a specified name.
- * Open, link etc use their own routines, but this is enough for things
- * like 'chmod' etc.
- */
-struct m_inode * namei(const char * pathname)
-{
- const char * basename;
- int inr,dev,namelen;
- struct m_inode * dir;
- struct buffer_head * bh;
- struct dir_entry * de;
-
- if (!(dir = dir_namei(pathname,&namelen,&basename)))
- return NULL;
- if (!namelen) /* special case: '/usr/' etc */
- return dir;
- bh = find_entry(&dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- return NULL;
- }
- inr = de->inode;
- dev = dir->i_dev;
- brelse(bh);
- iput(dir);
- dir=iget(dev,inr);
- if (dir) {
- dir->i_atime=CURRENT_TIME;
- dir->i_dirt=1;
- }
- return dir;
-}
-
-/*
- * open_namei()
- *
- * 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)
-{
- const char * basename;
- int inr,dev,namelen;
- struct m_inode * dir, *inode;
- struct buffer_head * bh;
- struct dir_entry * de;
-
- if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
- flag |= O_WRONLY;
- mode &= 0777 & ~current->umask;
- mode |= I_REGULAR;
- if (!(dir = dir_namei(pathname,&namelen,&basename)))
- return -ENOENT;
- if (!namelen) { /* special case: '/usr/' etc */
- if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
- *res_inode=dir;
- return 0;
- }
- iput(dir);
- return -EISDIR;
- }
- bh = find_entry(&dir,basename,namelen,&de);
- if (!bh) {
- if (!(flag & O_CREAT)) {
- iput(dir);
- return -ENOENT;
- }
- if (!(permission(dir,MAY_WRITE) || suser())) {
- iput(dir);
- return -EACCES;
- }
- inode = new_inode(dir->i_dev);
- if (!inode) {
- iput(dir);
- return -ENOSPC;
- }
- inode->i_mode = mode;
- inode->i_dirt = 1;
- bh = add_entry(dir,basename,namelen,&de);
- if (!bh) {
- inode->i_nlinks--;
- iput(inode);
- iput(dir);
- return -ENOSPC;
- }
- de->inode = inode->i_num;
- bh->b_dirt = 1;
- brelse(bh);
- iput(dir);
- *res_inode = inode;
- return 0;
- }
- inr = de->inode;
- dev = dir->i_dev;
- brelse(bh);
- iput(dir);
- if (flag & O_EXCL)
- return -EEXIST;
- if (!(inode=iget(dev,inr)))
- return -EACCES;
- if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
- (!(permission(inode,ACC_MODE(flag))==ACC_MODE(flag)) ||
- suser())) {
- iput(inode);
- return -EPERM;
- }
- inode->i_atime = CURRENT_TIME;
- if (flag & O_TRUNC)
- truncate(inode);
- *res_inode = inode;
- return 0;
-}
-
-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;
-
- if (!suser())
- return -EPERM;
- if (!(dir = dir_namei(filename,&namelen,&basename)))
- return -ENOENT;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
- }
- if (!(permission(dir,MAY_WRITE) || suser())) {
- 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_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;
- }
- de->inode = inode->i_num;
- bh->b_dirt = 1;
- iput(dir);
- iput(inode);
- brelse(bh);
- return 0;
-}
-
-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;
-
- if (!suser())
- return -EPERM;
- if (!(dir = dir_namei(pathname,&namelen,&basename)))
- return -ENOENT;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
- }
- if (!(permission(dir,MAY_WRITE) || suser())) {
- 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))) {
- 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);
- free_block(inode->i_dev,inode->i_zone[0]);
- 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);
- free_block(inode->i_dev,inode->i_zone[0]);
- inode->i_nlinks=0;
- iput(inode);
- return -ENOSPC;
- }
- de->inode = inode->i_num;
- bh->b_dirt = 1;
- dir->i_nlinks++;
- dir->i_dirt = 1;
- iput(dir);
- iput(inode);
- brelse(bh);
- return 0;
-}
-
-/*
- * routine to check that the specified directory is empty (for rmdir)
- */
-static int empty_dir(struct m_inode * inode)
-{
- int nr,block;
- int len;
- struct buffer_head * bh;
- struct dir_entry * de;
-
- len = inode->i_size / sizeof (struct dir_entry);
- if (len<2 || !inode->i_zone[0] ||
- !(bh=bread(inode->i_dev,inode->i_zone[0]))) {
- printk("warning - bad directory on dev %04x\n",inode->i_dev);
- return 0;
- }
- de = (struct dir_entry *) bh->b_data;
- if (de[0].inode != inode->i_num || !de[1].inode ||
- strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
- printk("warning - bad directory on dev %04x\n",inode->i_dev);
- return 0;
- }
- nr = 2;
- de += 2;
- while (nr<len) {
- if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
- brelse(bh);
- block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK);
- if (!block) {
- nr += DIR_ENTRIES_PER_BLOCK;
- continue;
- }
- if (!(bh=bread(inode->i_dev,block)))
- return 0;
- de = (struct dir_entry *) bh->b_data;
- }
- if (de->inode) {
- brelse(bh);
- return 0;
- }
- de++;
- nr++;
- }
- brelse(bh);
- return 1;
-}
-
-int sys_rmdir(const char * name)
-{
- const char * basename;
- int namelen;
- struct m_inode * dir, * inode;
- struct buffer_head * bh;
- struct dir_entry * de;
-
- if (!suser())
- return -EPERM;
- if (!(dir = dir_namei(name,&namelen,&basename)))
- return -ENOENT;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
- }
- bh = find_entry(&dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- return -ENOENT;
- }
- if (!(permission(dir,MAY_WRITE) || suser())) {
- iput(dir);
- brelse(bh);
- return -EPERM;
- }
- if (!(inode = iget(dir->i_dev, de->inode))) {
- iput(dir);
- 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;
-}
-
-int sys_unlink(const char * name)
-{
- const char * basename;
- int namelen;
- struct m_inode * dir, * inode;
- struct buffer_head * bh;
- struct dir_entry * de;
-
- if (!(dir = dir_namei(name,&namelen,&basename)))
- return -ENOENT;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
- }
- if (!(permission(dir,MAY_WRITE) || suser())) {
- iput(dir);
- return -EPERM;
- }
- bh = find_entry(&dir,basename,namelen,&de);
- if (!bh) {
- iput(dir);
- return -ENOENT;
- }
- inode = iget(dir->i_dev, de->inode);
- if (!inode) {
- printk("iget failed in delete (%04x:%d)",dir->i_dev,de->inode);
- iput(dir);
- brelse(bh);
- return -ENOENT;
- }
- if (S_ISDIR(inode->i_mode)) {
- iput(inode);
- 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;
-}
-
-int sys_link(const char * oldname, const char * newname)
-{
- struct dir_entry * de;
- struct m_inode * oldinode, * dir;
- struct buffer_head * bh;
- const char * basename;
- int namelen;
-
- oldinode=namei(oldname);
- if (!oldinode)
- return -ENOENT;
- if (S_ISDIR(oldinode->i_mode)) {
- iput(oldinode);
- return -EPERM;
- }
- dir = dir_namei(newname,&namelen,&basename);
- if (!dir) {
- iput(oldinode);
- return -EACCES;
- }
- if (!namelen) {
- iput(oldinode);
- iput(dir);
- return -EPERM;
- }
- if (dir->i_dev != oldinode->i_dev) {
- iput(dir);
- iput(oldinode);
- return -EXDEV;
- }
- if (!(permission(dir,MAY_WRITE) || suser())) {
- iput(dir);
- iput(oldinode);
- return -EACCES;
- }
- bh = find_entry(&dir,basename,namelen,&de);
- if (bh) {
- brelse(bh);
- iput(dir);
- iput(oldinode);
- return -EEXIST;
- }
- 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;
-}
+++ /dev/null
-/*
- * linux/fs/open.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-#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/tty.h>
-#include <linux/kernel.h>
-#include <asm/segment.h>
-
-int sys_ustat(int dev, struct ustat * ubuf)
-{
- return -ENOSYS;
-}
-
-int sys_utime(char * filename, struct utimbuf * times)
-{
- struct m_inode * inode;
- long actime,modtime;
-
- if (!(inode=namei(filename)))
- return -ENOENT;
- if (times) {
- actime = get_fs_long((unsigned long *) ×->actime);
- modtime = get_fs_long((unsigned long *) ×->modtime);
- } else
- actime = modtime = CURRENT_TIME;
- inode->i_atime = actime;
- inode->i_mtime = modtime;
- inode->i_dirt = 1;
- iput(inode);
- return 0;
-}
-
-int sys_access(const char * filename,int mode)
-{
- struct m_inode * inode;
- int res;
-
- mode &= 0007;
- if (!(inode=namei(filename)))
- return -EACCES;
- res = inode->i_mode & 0777;
- iput(inode);
- if (!(current->euid && current->uid))
- if (res & 0111)
- res = 0777;
- else
- res = 0666;
- if (current->euid == inode->i_uid)
- res >>= 6;
- else if (current->egid == inode->i_gid)
- res >>= 6;
- if ((res & 0007 & mode) == mode)
- return 0;
- return -EACCES;
-}
-
-int sys_chdir(const char * filename)
-{
- struct m_inode * inode;
-
- if (!(inode = namei(filename)))
- return -ENOENT;
- if (!S_ISDIR(inode->i_mode)) {
- iput(inode);
- return -ENOTDIR;
- }
- iput(current->pwd);
- current->pwd = inode;
- return (0);
-}
-
-int sys_chroot(const char * filename)
-{
- struct m_inode * inode;
-
- if (!(inode=namei(filename)))
- return -ENOENT;
- if (!S_ISDIR(inode->i_mode)) {
- iput(inode);
- return -ENOTDIR;
- }
- iput(current->root);
- current->root = inode;
- return (0);
-}
-
-int sys_chmod(const char * filename,int mode)
-{
- struct m_inode * inode;
-
- if (!(inode=namei(filename)))
- return -ENOENT;
- if (current->uid && current->euid)
- if (current->uid!=inode->i_uid && current->euid!=inode->i_uid) {
- iput(inode);
- return -EACCES;
- } else
- mode = (mode & 0777) | (inode->i_mode & 07000);
- inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
- inode->i_dirt = 1;
- iput(inode);
- return 0;
-}
-
-int sys_chown(const char * filename,int uid,int gid)
-{
- struct m_inode * inode;
-
- if (!(inode=namei(filename)))
- return -ENOENT;
- if (current->uid && current->euid) {
- iput(inode);
- return -EACCES;
- }
- inode->i_uid=uid;
- inode->i_gid=gid;
- inode->i_dirt=1;
- iput(inode);
- return 0;
-}
-
-int sys_open(const char * filename,int flag,int mode)
-{
- struct m_inode * inode;
- struct file * f;
- int i,fd;
-
- mode &= 0777 & ~current->umask;
- for(fd=0 ; fd<NR_OPEN ; fd++)
- if (!current->filp[fd])
- break;
- if (fd>=NR_OPEN)
- return -EINVAL;
- current->close_on_exec &= ~(1<<fd);
- f=0+file_table;
- for (i=0 ; i<NR_FILE ; i++,f++)
- if (!f->f_count) break;
- if (i>=NR_FILE)
- return -EINVAL;
- (current->filp[fd]=f)->f_count++;
- if ((i=open_namei(filename,flag,mode,&inode))<0) {
- current->filp[fd]=NULL;
- f->f_count=0;
- return i;
- }
-/* ttys are somewhat special (ttyxx major==4, tty major==5) */
- if (S_ISCHR(inode->i_mode))
- if (MAJOR(inode->i_zone[0])==4) {
- if (current->leader && current->tty<0) {
- current->tty = MINOR(inode->i_zone[0]);
- tty_table[current->tty].pgrp = current->pgrp;
- }
- } else if (MAJOR(inode->i_zone[0])==5)
- if (current->tty<0) {
- iput(inode);
- current->filp[fd]=NULL;
- f->f_count=0;
- return -EPERM;
- }
-/* 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_flags = flag;
- f->f_count = 1;
- f->f_inode = inode;
- f->f_pos = 0;
- return (fd);
-}
-
-int sys_creat(const char * pathname, int mode)
-{
- return sys_open(pathname, O_CREAT | O_TRUNC, mode);
-}
-
-int sys_close(unsigned int fd)
-{
- struct file * filp;
-
- if (fd >= NR_OPEN)
- return -EINVAL;
- current->close_on_exec &= ~(1<<fd);
- if (!(filp = current->filp[fd]))
- return -EINVAL;
- current->filp[fd] = NULL;
- if (filp->f_count == 0)
- panic("Close: file count is 0");
- if (--filp->f_count)
- return (0);
- iput(filp->f_inode);
- return (0);
-}
verify_area(buf,count);
inode = file->f_inode;
if (inode->i_pipe)
- return (file->f_mode&1)?read_pipe(inode,buf,count):-1;
+ return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO;
if (S_ISCHR(inode->i_mode))
return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos);
if (S_ISBLK(inode->i_mode))
return 0;
inode=file->f_inode;
if (inode->i_pipe)
- return (file->f_mode&2)?write_pipe(inode,buf,count):-1;
+ return (file->f_mode&2)?write_pipe(inode,buf,count):-EIO;
if (S_ISCHR(inode->i_mode))
return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos);
if (S_ISBLK(inode->i_mode))
void put_super(int dev)
{
struct super_block * sb;
+ struct m_inode * inode;
int i;
if (dev == ROOT_DEV) {
return -ENOENT;
if (!sb->s_imount->i_mount)
printk("Mounted inode has i_mount=0\n");
- for(inode=inode_table+0 ; inode<inode_table+NR_INODE ; inode++)
+ for (inode=inode_table+0 ; inode<inode_table+NR_INODE ; inode++)
if (inode->i_dev==dev && inode->i_count)
- return -EBUSY;
+ return -EBUSY;
sb->s_imount->i_mount=0;
iput(sb->s_imount);
sb->s_imount = NULL;
+++ /dev/null
-/*
- * linux/fs/tty_ioctl.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-#include <errno.h>
-#include <termios.h>
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/tty.h>
-
-#include <asm/segment.h>
-#include <asm/system.h>
-
-static void flush(struct tty_queue * queue)
-{
- cli();
- queue->head = queue->tail;
- sti();
-}
-
-static void wait_until_sent(struct tty_struct * tty)
-{
- /* do nothing - not implemented */
-}
-
-static void send_break(struct tty_struct * tty)
-{
- /* do nothing - not implemented */
-}
-
-static int get_termios(struct tty_struct * tty, struct termios * termios)
-{
- int i;
-
- verify_area(termios, sizeof (*termios));
- for (i=0 ; i< (sizeof (*termios)) ; i++)
- put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios );
- return 0;
-}
-
-static int set_termios(struct tty_struct * tty, struct termios * termios)
-{
- int i;
-
- for (i=0 ; i< (sizeof (*termios)) ; i++)
- ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
- return 0;
-}
-
-static int get_termio(struct tty_struct * tty, struct termio * termio)
-{
- int i;
- struct termio tmp_termio;
-
- verify_area(termio, sizeof (*termio));
- tmp_termio.c_iflag = tty->termios.c_iflag;
- tmp_termio.c_oflag = tty->termios.c_oflag;
- tmp_termio.c_cflag = tty->termios.c_cflag;
- tmp_termio.c_lflag = tty->termios.c_lflag;
- tmp_termio.c_line = tty->termios.c_line;
- for(i=0 ; i < NCC ; i++)
- tmp_termio.c_cc[i] = tty->termios.c_cc[i];
- for (i=0 ; i< (sizeof (*termio)) ; i++)
- put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
- return 0;
-}
-
-/*
- * This only works as the 386 is low-byt-first
- */
-static int set_termio(struct tty_struct * tty, struct termio * termio)
-{
- int i;
- struct termio tmp_termio;
-
- for (i=0 ; i< (sizeof (*termio)) ; i++)
- ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
- *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag;
- *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag;
- *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag;
- *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag;
- tty->termios.c_line = tmp_termio.c_line;
- for(i=0 ; i < NCC ; i++)
- tty->termios.c_cc[i] = tmp_termio.c_cc[i];
- return 0;
-}
-
-int tty_ioctl(int dev, int cmd, int arg)
-{
- struct tty_struct * tty;
- if (MAJOR(dev) == 5) {
- dev=current->tty;
- if (dev<0)
- panic("tty_ioctl: dev<0");
- } else
- dev=MINOR(dev);
- tty = dev + tty_table;
- switch (cmd) {
- case TCGETS:
- return get_termios(tty,(struct termios *) arg);
- case TCSETSF:
- flush(&tty->read_q); /* fallthrough */
- case TCSETSW:
- wait_until_sent(tty); /* fallthrough */
- case TCSETS:
- return set_termios(tty,(struct termios *) arg);
- case TCGETA:
- return get_termio(tty,(struct termio *) arg);
- case TCSETAF:
- flush(&tty->read_q); /* fallthrough */
- case TCSETAW:
- wait_until_sent(tty); /* fallthrough */
- case TCSETA:
- return set_termio(tty,(struct termio *) arg);
- case TCSBRK:
- if (!arg) {
- wait_until_sent(tty);
- send_break(tty);
- }
- return 0;
- case TCXONC:
- return -EINVAL; /* not implemented */
- case TCFLSH:
- if (arg==0)
- flush(&tty->read_q);
- else if (arg==1)
- flush(&tty->write_q);
- else if (arg==2) {
- flush(&tty->read_q);
- flush(&tty->write_q);
- } else
- return -EINVAL;
- return 0;
- case TIOCEXCL:
- return -EINVAL; /* not implemented */
- case TIOCNXCL:
- return -EINVAL; /* not implemented */
- case TIOCSCTTY:
- return -EINVAL; /* set controlling term NI */
- case TIOCGPGRP:
- verify_area((void *) arg,4);
- put_fs_long(tty->pgrp,(unsigned long *) arg);
- return 0;
- case TIOCSPGRP:
- tty->pgrp=get_fs_long((unsigned long *) arg);
- return 0;
- case TIOCOUTQ:
- verify_area((void *) arg,4);
- put_fs_long(CHARS(tty->write_q),(unsigned long *) arg);
- return 0;
- case TIOCSTI:
- return -EINVAL; /* not implemented */
- case TIOCGWINSZ:
- return -EINVAL; /* not implemented */
- case TIOCSWINSZ:
- return -EINVAL; /* not implemented */
- case TIOCMGET:
- return -EINVAL; /* not implemented */
- case TIOCMBIS:
- return -EINVAL; /* not implemented */
- case TIOCMBIC:
- return -EINVAL; /* not implemented */
- case TIOCMSET:
- return -EINVAL; /* not implemented */
- case TIOCGSOFTCAR:
- return -EINVAL; /* not implemented */
- case TIOCSSOFTCAR:
- return -EINVAL; /* not implemented */
- default:
- return -EINVAL;
- }
-}
+++ /dev/null
-head 1.2;
-branch ;
-access ;
-symbols ;
-locks ; strict;
-comment @ * @;
-
-
-1.2
-date 91.11.15.19.30.40; author tytso; state Exp;
-branches ;
-next 1.1;
-
-1.1
-date 91.11.15.16.16.12; author tytso; state Exp;
-branches ;
-next ;
-
-
-desc
-@@
-
-
-1.2
-log
-@Fixed bug in tolower(). Plus sign should have been a minus sign.
-@
-text
-@#ifndef _CTYPE_H
-#define _CTYPE_H
-
-#define _U 0x01 /* upper */
-#define _L 0x02 /* lower */
-#define _D 0x04 /* digit */
-#define _C 0x08 /* cntrl */
-#define _P 0x10 /* punct */
-#define _S 0x20 /* white space (space/lf/tab) */
-#define _X 0x40 /* hex digit */
-#define _SP 0x80 /* hard space (0x20) */
-
-extern unsigned char _ctype[];
-extern char _ctmp;
-
-#define isalnum(c) ((_ctype+1)[c]&(_U|_L|_D))
-#define isalpha(c) ((_ctype+1)[c]&(_U|_L))
-#define iscntrl(c) ((_ctype+1)[c]&(_C))
-#define isdigit(c) ((_ctype+1)[c]&(_D))
-#define isgraph(c) ((_ctype+1)[c]&(_P|_U|_L|_D))
-#define islower(c) ((_ctype+1)[c]&(_L))
-#define isprint(c) ((_ctype+1)[c]&(_P|_U|_L|_D|_SP))
-#define ispunct(c) ((_ctype+1)[c]&(_P))
-#define isspace(c) ((_ctype+1)[c]&(_S))
-#define isupper(c) ((_ctype+1)[c]&(_U))
-#define isxdigit(c) ((_ctype+1)[c]&(_D|_X))
-
-#define isascii(c) (((unsigned) c)<=0x7f)
-#define toascii(c) (((unsigned) c)&0x7f)
-
-#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp+('a'-'A'):_ctmp)
-#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp+('A'-'a'):_ctmp)
-
-#endif
-@
-
-
-1.1
-log
-@Initial revision
-@
-text
-@d31 1
-a31 1
-#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp+('a'+'A'):_ctmp)
-@
+++ /dev/null
-head 1.1;
-branch ;
-access ;
-symbols ;
-locks tytso:1.1; strict;
-comment @ * @;
-
-
-1.1
-date 91.11.25.10.43.03; author tytso; state Exp;
-branches ;
-next ;
-
-
-desc
-@@
-
-
-
-1.1
-log
-@Initial revision
-@
-text
-@extern inline unsigned char get_fs_byte(const char * addr)
-{
- unsigned register char _v;
-
- __asm__ ("movb %%fs:%1,%0":"=r" (_v):"m" (*addr));
- return _v;
-}
-
-extern inline unsigned short get_fs_word(const unsigned short *addr)
-{
- unsigned short _v;
-
- __asm__ ("movw %%fs:%1,%0":"=r" (_v):"m" (*addr));
- return _v;
-}
-
-extern inline unsigned long get_fs_long(const unsigned long *addr)
-{
- unsigned long _v;
-
- __asm__ ("movl %%fs:%1,%0":"=r" (_v):"m" (*addr)); \
- return _v;
-}
-
-extern inline void put_fs_byte(char val,char *addr)
-{
-__asm__ ("movb %0,%%fs:%1"::"r" (val),"m" (*addr));
-}
-
-extern inline void put_fs_word(short val,short * addr)
-{
-__asm__ ("movw %0,%%fs:%1"::"r" (val),"m" (*addr));
-}
-
-extern inline void put_fs_long(unsigned long val,unsigned long * addr)
-{
-__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 ]
*/
extern inline unsigned long get_fs()
__asm__("mov %0,%%fs"::"a" ((unsigned short) val));
}
-
#define isascii(c) (((unsigned) c)<=0x7f)
#define toascii(c) (((unsigned) c)&0x7f)
-#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp+('a'-'A'):_ctmp)
-#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp+('A'-'a'):_ctmp)
+#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp-('A'-'a'):_ctmp)
+#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp-('a'-'A'):_ctmp)
#endif
+++ /dev/null
-#ifndef _CTYPE_H
-#define _CTYPE_H
-
-#define _U 0x01 /* upper */
-#define _L 0x02 /* lower */
-#define _D 0x04 /* digit */
-#define _C 0x08 /* cntrl */
-#define _P 0x10 /* punct */
-#define _S 0x20 /* white space (space/lf/tab) */
-#define _X 0x40 /* hex digit */
-#define _SP 0x80 /* hard space (0x20) */
-
-extern unsigned char _ctype[];
-extern char _ctmp;
-
-#define isalnum(c) ((_ctype+1)[c]&(_U|_L|_D))
-#define isalpha(c) ((_ctype+1)[c]&(_U|_L))
-#define iscntrl(c) ((_ctype+1)[c]&(_C))
-#define isdigit(c) ((_ctype+1)[c]&(_D))
-#define isgraph(c) ((_ctype+1)[c]&(_P|_U|_L|_D))
-#define islower(c) ((_ctype+1)[c]&(_L))
-#define isprint(c) ((_ctype+1)[c]&(_P|_U|_L|_D|_SP))
-#define ispunct(c) ((_ctype+1)[c]&(_P))
-#define isspace(c) ((_ctype+1)[c]&(_S))
-#define isupper(c) ((_ctype+1)[c]&(_U))
-#define isxdigit(c) ((_ctype+1)[c]&(_D|_X))
-
-#define isascii(c) (((unsigned) c)<=0x7f)
-#define toascii(c) (((unsigned) c)&0x7f)
-
-#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp+('a'+'A'):_ctmp)
-#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp+('A'-'a'):_ctmp)
-
-#endif
+++ /dev/null
-head 1.2;
-branch ;
-access ;
-symbols ;
-locks tytso:1.2; strict;
-comment @ * @;
-
-
-1.2
-date 91.12.01.09.22.22; author tytso; state Exp;
-branches ;
-next 1.1;
-
-1.1
-date 91.11.21.08.56.53; author tytso; state Exp;
-branches ;
-next ;
-
-
-desc
-@@
-
-
-1.2
-log
-@Patches sent to Linus
-@
-text
-@/*
- * 'kernel.h' contains some often-used function prototypes etc
- */
-void verify_area(void * addr,int count);
-volatile void panic(const char * str);
-int printf(const char * fmt, ...);
-int printk(const char * fmt, ...);
-int tty_write(unsigned ch,char * buf,int count);
-
-/*
- * This is defined as a macro, but at some point this might become a
- * real subroutine that sets a flag if it returns true (to do
- * BSD-style accounting where the process is flagged if it uses root
- * privs). The implication of this is that you should do normal
- * permissions checks first, and check suser() last.
- */
-#define suser() (current->euid == 0)
-@
-
-
-1.1
-log
-@Initial revision
-@
-text
-@d9 9
-@
* root-device by changing the line ROOT_DEV = XXX in boot/bootsect.s
*/
-/* define your keyboard here - US (KBD_US) or Finnish (KBD_FINNISH) */
-#define KBD_US
-/* #define KBD_FINNISH */
+/*
+ * define your keyboard here -
+ * KBD_FINNISH for Finnish keyboards
+ * KBD_US for US-type
+ * KBD_GR for German keyboards
+ * KBD_FR for Frech keyboard
+ */
+/*#define KBD_US */
+/*#define KBD_GR */
+/*#define KBD_FR */
+#define KBD_FINNISH
/*
* Normally, Linux can get the drive parameters from the BIOS at
with more than 8 heads.
If you want the BIOS to tell what kind of drive you have, just
- leave HD_TYPE undefined.
+ leave HD_TYPE undefined. This is the normal thing to do.
*/
#endif
#define READ 0
#define WRITE 1
#define READA 2 /* read-ahead - don't pause */
+#define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */
void buffer_init(long buffer_end);
struct buffer_head {
char * b_data; /* pointer to data block (1024 bytes) */
+ unsigned long b_blocknr; /* block number */
unsigned short b_dev; /* device (0 = free) */
- unsigned short b_blocknr; /* block number */
unsigned char b_uptodate;
unsigned char b_dirt; /* 0-clean,1-dirty */
unsigned char b_count; /* users using this block */
extern void ll_rw_block(int rw, struct buffer_head * bh);
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 void free_block(int dev, int block);
int printf(const char * fmt, ...);
int printk(const char * fmt, ...);
int tty_write(unsigned ch,char * buf,int count);
-void *malloc(unsigned int len);
-void free_s(void *obj, int size);
+void * malloc(unsigned int size);
+void free_s(void * obj, int size);
-#define free(x) free_s((x), 0)
+#define free(x) free_s((x), 0)
/*
* This is defined as a macro, but at some point this might become a
* permissions checks first, and check suser() last.
*/
#define suser() (current->euid == 0)
+
+++ /dev/null
-/*
- * 'kernel.h' contains some often-used function prototypes etc
- */
-void verify_area(void * addr,int count);
-volatile void panic(const char * str);
-int printf(const char * fmt, ...);
-int printk(const char * fmt, ...);
-int tty_write(unsigned ch,char * buf,int count);
-
-/*
- * This is defined as a macro, but at some point this might become a
- * real subroutine that sets a flag if it returns true (to do
- * BSD-style accounting where the process is flagged if it uses root
- * privs). The implication of this is that you should do normal
- * permissions checks first, and check suser() last.
- */
-#define suser() (current->euid == 0)
+++ /dev/null
-/*
- * 'kernel.h' contains some often-used function prototypes etc
- */
-void verify_area(void * addr,int count);
-volatile void panic(const char * str);
-int printf(const char * fmt, ...);
-int printk(const char * fmt, ...);
-int tty_write(unsigned ch,char * buf,int count);
#endif
extern int copy_page_tables(unsigned long from, unsigned long to, long size);
-extern int free_page_tables(unsigned long from, long size);
+extern int free_page_tables(unsigned long from, unsigned long size);
extern void sched_init(void);
extern void schedule(void);
long blocked; /* bitmap of masked signals */
/* various fields */
int exit_code;
- unsigned long end_code,end_data,brk,start_stack;
+ unsigned long start_code,end_code,end_data,brk,start_stack;
long pid,father,pgrp,session,leader;
unsigned short uid,euid,suid;
unsigned short gid,egid,sgid;
unsigned short umask;
struct m_inode * pwd;
struct m_inode * root;
+ struct m_inode * executable;
unsigned long close_on_exec;
struct file * filp[NR_OPEN];
/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
#define INIT_TASK \
/* state etc */ { 0,15,15, \
/* signals */ 0,{{},},0, \
-/* ec,brk... */ 0,0,0,0,0, \
+/* ec,brk... */ 0,0,0,0,0,0, \
/* pid etc.. */ 0,-1,0,0,0, \
/* uid etc */ 0,0,0,0,0,0, \
/* alarm */ 0,0,0,0,0,0, \
/* math */ 0, \
-/* fs info */ -1,0022,NULL,NULL,0, \
+/* fs info */ -1,0022,NULL,NULL,NULL,0, \
/* filp */ {NULL,}, \
{ \
{0,0}, \
extern int sys_sigaction();
extern int sys_sgetmask();
extern int sys_ssetmask();
+extern int sys_setreuid();
+extern int sys_setregid();
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,
sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
-sys_getpgrp,sys_setsid,sys_sigaction,sys_sgetmask,sys_ssetmask };
+sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
+sys_setreuid,sys_setregid };
#define TIOCMSET 0x5418
#define TIOCGSOFTCAR 0x5419
#define TIOCSSOFTCAR 0x541A
+#define TIOCINQ 0x541B
struct winsize {
unsigned short ws_row;
#define B9600 0000015
#define B19200 0000016
#define B38400 0000017
+#define EXTA B19200
+#define EXTB B38400
#define CSIZE 0000060
#define CS5 0000000
#define CS6 0000020
#define CIBAUD 03600000 /* input baud rate (not used) */
#define CRTSCTS 020000000000 /* flow control */
+#define PARENB CPARENB
+#define PARODD CPARODD
+
/* c_lflag bits */
#define ISIG 0000001
#define ICANON 0000002
#define _POSIX_VERSION 198808L
#define _POSIX_CHOWN_RESTRICTED /* only root can do a chown (I think..) */
-/* #define _POSIX_NO_TRUNC*/ /* pathname truncation (but see in kernel) */
+#define _POSIX_NO_TRUNC /* no pathname truncation (but see in kernel) */
#define _POSIX_VDISABLE '\0' /* character to disable things like ^C */
/*#define _POSIX_SAVED_IDS */ /* we'll get to this yet */
/*#define _POSIX_JOB_CONTROL */ /* we aren't there quite yet. Soon hopefully */
#define __NR_getpgrp 65
#define __NR_setsid 66
#define __NR_sigaction 67
+#define __NR_sgetmask 68
+#define __NR_ssetmask 69
+#define __NR_setreuid 70
+#define __NR_setregid 71
#define _syscall0(type,name) \
type name(void) \
{ \
-type __res; \
+long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name)); \
if (__res >= 0) \
- return __res; \
+ return (type) __res; \
errno = -__res; \
return -1; \
}
#define _syscall1(type,name,atype,a) \
type name(atype a) \
{ \
-type __res; \
+long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
- : "0" (__NR_##name),"b" (a)); \
+ : "0" (__NR_##name),"b" ((long)(a))); \
if (__res >= 0) \
- return __res; \
+ return (type) __res; \
errno = -__res; \
return -1; \
}
#define _syscall2(type,name,atype,a,btype,b) \
type name(atype a,btype b) \
{ \
-type __res; \
+long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
- : "0" (__NR_##name),"b" (a),"c" (b)); \
+ : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b))); \
if (__res >= 0) \
- return __res; \
+ return (type) __res; \
errno = -__res; \
return -1; \
}
#define _syscall3(type,name,atype,a,btype,b,ctype,c) \
type name(atype a,btype b,ctype c) \
{ \
-type __res; \
+long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
- : "0" (__NR_##name),"b" (a),"c" (b),"d" (c)); \
-if (__res<0) \
- errno=-__res , __res = -1; \
-return __res;\
+ : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \
+if (__res>=0) \
+ return (type) __res; \
+errno=-__res; \
+return -1; \
}
#endif /* __LIBRARY__ */
extern void hd_init(void);
extern void floppy_init(void);
extern void mem_init(long start, long end);
+extern long rd_init(long mem_start, int length);
extern long kernel_mktime(struct tm * tm);
extern long startup_time;
static long memory_end = 0;
static long buffer_memory_end = 0;
+static long main_memory_start = 0;
struct drive_info { char dummy[32]; } drive_info;
memory_end &= 0xfffff000;
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
- if (memory_end > 6*1024*1024)
+ if (memory_end > 12*1024*1024)
+ buffer_memory_end = 4*1024*1024;
+ else if (memory_end > 6*1024*1024)
buffer_memory_end = 2*1024*1024;
else
buffer_memory_end = 1*1024*1024;
- mem_init(buffer_memory_end,memory_end);
+ main_memory_start = buffer_memory_end;
+#ifdef RAMDISK
+ main_memory_start += rd_init(main_memory_start, RAMDISK*1024);
+#endif
+ mem_init(main_memory_start,memory_end);
trap_init();
blk_dev_init();
chr_dev_init();
return i;
}
+static char * argv_rc[] = { "/bin/sh", NULL };
+static char * envp_rc[] = { "HOME=/", NULL };
+
static char * argv[] = { "-/bin/sh",NULL };
static char * envp[] = { "HOME=/usr/root", NULL };
void init(void)
{
- int i,j;
+ int pid,i;
setup((void *) &drive_info);
- if (!fork())
- _exit(execve("/bin/update",NULL,NULL));
(void) open("/dev/tty0",O_RDWR,0);
(void) dup(0);
(void) dup(0);
printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,
NR_BUFFERS*BLOCK_SIZE);
- printf("Free mem: %d bytes\n\r",memory_end-buffer_memory_end);
- printf(" Ok.\n\r");
- if ((i=fork())<0)
- printf("Fork failed in init\r\n");
- else if (!i) {
- close(0);close(1);close(2);
- setsid();
- (void) open("/dev/tty0",O_RDWR,0);
- (void) dup(0);
- (void) dup(0);
- _exit(execve("/bin/sh",argv,envp));
+ printf("Free mem: %d bytes\n\r",memory_end-main_memory_start);
+ if (!(pid=fork())) {
+ close(0);
+ if (open("/etc/rc",O_RDONLY,0))
+ _exit(1);
+ execve("/bin/sh",argv_rc,envp_rc);
+ _exit(2);
+ }
+ if (pid>0)
+ while (pid != wait(&i))
+ /* nothing */;
+ while (1) {
+ if ((pid=fork())<0) {
+ printf("Fork failed in init\r\n");
+ continue;
+ }
+ if (!pid) {
+ close(0);close(1);close(2);
+ setsid();
+ (void) open("/dev/tty0",O_RDWR,0);
+ (void) dup(0);
+ (void) dup(0);
+ _exit(execve("/bin/sh",argv,envp));
+ }
+ while (1)
+ if (pid == wait(&i))
+ break;
+ printf("\n\rchild %d died with code %04x\n\r",pid,i);
+ sync();
}
- j=wait(&i);
- printf("child %d died with code %04x\n",j,i);
- sync();
_exit(0); /* NOTE! _exit, not exit() */
}
for i in *.c;do rm -f `basename $$i .c`.s;done
(cd chr_drv; make clean)
(cd blk_drv; make clean)
+ (cd math; make clean)
dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
+++ /dev/null
-head 1.3;
-branch ;
-access ;
-symbols ;
-locks ; strict;
-comment @ * @;
-
-
-1.3
-date 91.12.01.09.21.46; author tytso; state Exp;
-branches ;
-next 1.2;
-
-1.2
-date 91.11.20.00.10.00; author tytso; state Exp;
-branches ;
-next 1.1;
-
-1.1
-date 91.11.16.21.02.17; author tytso; state Exp;
-branches ;
-next ;
-
-
-desc
-@@
-
-
-1.3
-log
-@Patches sent to Linus
-@
-text
-@/*
- * linux/kernel/exit.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-#include <errno.h>
-#include <signal.h>
-#include <sys/wait.h>
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/tty.h>
-#include <asm/segment.h>
-
-int sys_pause(void);
-int sys_close(int fd);
-
-void release(struct task_struct * p)
-{
- int i;
-
- if (!p)
- return;
- for (i=1 ; i<NR_TASKS ; i++)
- if (task[i]==p) {
- task[i]=NULL;
- free_page((long)p);
- schedule();
- return;
- }
- panic("trying to release non-existent task");
-}
-
-static inline int send_sig(long sig,struct task_struct * p,int priv)
-{
- if (!p || sig<1 || sig>32)
- return -EINVAL;
- if (priv || (current->euid==p->euid) || suser())
- p->signal |= (1<<(sig-1));
- else
- return -EPERM;
- return 0;
-}
-
-static void kill_session(void)
-{
- struct task_struct **p = NR_TASKS + task;
-
- while (--p > &FIRST_TASK) {
- if (*p && (*p)->session == current->session)
- (*p)->signal |= 1<<(SIGHUP-1);
- }
-}
-
-/*
- * XXX need to check permissions needed to send signals to process
- * groups, etc. etc. kill() permissions semantics are tricky!
- */
-int sys_kill(int pid,int sig)
-{
- struct task_struct **p = NR_TASKS + task;
- int err, retval = 0;
-
- if (!pid) while (--p > &FIRST_TASK) {
- if (*p && (*p)->pgrp == current->pid)
- if (err=send_sig(sig,*p,1))
- retval = err;
- } else if (pid>0) while (--p > &FIRST_TASK) {
- if (*p && (*p)->pid == pid)
- if (err=send_sig(sig,*p,0))
- retval = err;
- } else if (pid == -1) while (--p > &FIRST_TASK)
- if (err = send_sig(sig,*p,0))
- retval = err;
- else while (--p > &FIRST_TASK)
- if (*p && (*p)->pgrp == -pid)
- if (err = send_sig(sig,*p,0))
- retval = err;
- return retval;
-}
-
-static void tell_father(int pid)
-{
- int i;
-
- if (pid)
- for (i=0;i<NR_TASKS;i++) {
- if (!task[i])
- continue;
- if (task[i]->pid != pid)
- continue;
- task[i]->signal |= (1<<(SIGCHLD-1));
- return;
- }
-/* if we don't find any fathers, we just release ourselves */
- release(current);
-}
-
-int do_exit(long code)
-{
- int i;
-
- free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
- free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
- for (i=0 ; i<NR_TASKS ; i++)
- if (task[i] && task[i]->father == current->pid)
- task[i]->father = 0;
- for (i=0 ; i<NR_OPEN ; i++)
- if (current->filp[i])
- sys_close(i);
- iput(current->pwd);
- current->pwd=NULL;
- iput(current->root);
- current->root=NULL;
- if (current->leader && current->tty >= 0)
- tty_table[current->tty].pgrp = 0;
- if (last_task_used_math == current)
- last_task_used_math = NULL;
- if (current->leader)
- kill_session();
- current->state = TASK_ZOMBIE;
- current->exit_code = code;
- tell_father(current->father);
- schedule();
- return (-1); /* just to suppress warnings */
-}
-
-int sys_exit(int error_code)
-{
- return do_exit((error_code&0xff)<<8);
-}
-
-int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
-{
- int flag;
- struct task_struct ** p;
-
- verify_area(stat_addr,4);
-repeat:
- flag=0;
- for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
- if (!*p || *p == current)
- continue;
- if ((*p)->father != current->pid)
- continue;
- if (pid>0) {
- if ((*p)->pid != pid)
- continue;
- } else if (!pid) {
- if ((*p)->pgrp != current->pgrp)
- continue;
- } else if (pid != -1) {
- if ((*p)->pgrp != -pid)
- continue;
- }
- switch ((*p)->state) {
- case TASK_STOPPED:
- if (!(options & WUNTRACED))
- continue;
- put_fs_long(0x7f,stat_addr);
- 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);
- release(*p);
- return flag;
- default:
- flag=1;
- continue;
- }
- }
- if (flag) {
- if (options & WNOHANG)
- return 0;
- current->state=TASK_INTERRUPTIBLE;
- schedule();
- if (!(current->signal &= ~(1<<(SIGCHLD-1))))
- goto repeat;
- else
- return -EINTR;
- }
- return -ECHILD;
-}
-
-
-@
-
-
-1.2
-log
-@Fixed bug in waitpid() so that the proper exit code would be returned.
-@
-text
-@d35 1
-a35 1
-static inline void send_sig(long sig,struct task_struct * p,int priv)
-d38 2
-a39 6
- return;
- if (priv ||
- current->uid==p->uid ||
- current->euid==p->uid ||
- current->uid==p->euid ||
- current->euid==p->euid)
-d41 3
-d49 1
-a49 1
-
-d56 5
-a60 1
-void do_kill(long pid,long sig,int priv)
-d63 1
-d66 3
-a68 2
- if (*p && (*p)->pgrp == current->pid)
- send_sig(sig,*p,priv);
-d70 3
-a72 2
- if (*p && (*p)->pid == pid)
- send_sig(sig,*p,priv);
-d74 2
-a75 1
- send_sig(sig,*p,priv);
-d78 3
-a80 7
- send_sig(sig,*p,priv);
-}
-
-int sys_kill(int pid,int sig)
-{
- do_kill(pid,sig,!(current->uid || current->euid));
- return 0;
-@
-
-
-1.1
-log
-@Initial revision
-@
-text
-@d164 1
-a165 1
- put_fs_long((*p)->exit_code,stat_addr);
-@
+++ /dev/null
-head 1.2;
-branch ;
-access ;
-symbols ;
-locks ; strict;
-comment @ * @;
-
-
-1.2
-date 91.12.01.09.21.22; author tytso; state Exp;
-branches ;
-next 1.1;
-
-1.1
-date 91.11.21.08.47.30; author tytso; state Exp;
-branches ;
-next ;
-
-
-desc
-@@
-
-
-1.2
-log
-@Patches sent to linus
-@
-text
-@/*
- * linux/kernel/sched.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-/*
- * 'sched.c' is the main kernel file. It contains scheduling primitives
- * (sleep_on, wakeup, schedule etc) as well as a number of simple system
- * call functions (type getpid(), which just extracts a field from
- * current-task
- */
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/sys.h>
-#include <linux/fdreg.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/segment.h>
-
-#include <signal.h>
-
-#define _S(nr) (1<<((nr)-1))
-#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
-
-void show_task(int nr,struct task_struct * p)
-{
- printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state);
- printk("eip=%04x:%08x\n\r",p->tss.cs&0xffff,p->tss.eip);
-}
-
-void show_stat(void)
-{
- int i;
-
- for (i=0;i<NR_TASKS;i++)
- if (task[i])
- show_task(i,task[i]);
-}
-
-#define LATCH (1193180/HZ)
-
-extern void mem_use(void);
-
-extern int timer_interrupt(void);
-extern int system_call(void);
-
-union task_union {
- struct task_struct task;
- char stack[PAGE_SIZE];
-};
-
-static union task_union init_task = {INIT_TASK,};
-
-long volatile jiffies=0;
-long startup_time=0;
-struct task_struct *current = &(init_task.task);
-struct task_struct *last_task_used_math = NULL;
-
-struct task_struct * task[NR_TASKS] = {&(init_task.task), };
-
-long user_stack [ PAGE_SIZE>>2 ] ;
-
-struct {
- long * a;
- short b;
- } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };
-/*
- * 'math_state_restore()' saves the current math information in the
- * old math state array, and gets the new ones from the current task
- */
-void math_state_restore()
-{
- if (last_task_used_math == current)
- return;
- if (last_task_used_math) {
- __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
- }
- if (current->used_math) {
- __asm__("frstor %0"::"m" (current->tss.i387));
- } else {
- __asm__("fninit"::);
- current->used_math=1;
- }
- last_task_used_math=current;
-}
-
-/*
- * '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).
- * 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
- * tasks can run. It can not be killed, and it cannot sleep. The 'state'
- * information in task[0] is never used.
- */
-void schedule(void)
-{
- int i,next,c;
- struct task_struct ** p;
-
-/* check alarm, wake up any interruptible tasks that have got a signal */
-
- for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
- if (*p) {
- if ((*p)->alarm && (*p)->alarm < jiffies) {
- (*p)->signal |= (1<<(SIGALRM-1));
- (*p)->alarm = 0;
- }
- if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
- (*p)->state==TASK_INTERRUPTIBLE)
- (*p)->state=TASK_RUNNING;
- }
-
-/* this is the scheduler proper: */
-
- while (1) {
- c = -1;
- next = 0;
- i = NR_TASKS;
- p = &task[NR_TASKS];
- while (--i) {
- if (!*--p)
- continue;
- if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
- c = (*p)->counter, next = i;
- }
- if (c) break;
- for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
- if (*p)
- (*p)->counter = ((*p)->counter >> 1) +
- (*p)->priority;
- }
- switch_to(next);
-}
-
-int sys_pause(void)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- return 0;
-}
-
-void sleep_on(struct task_struct **p)
-{
- struct task_struct *tmp;
-
- if (!p)
- return;
- if (current == &(init_task.task))
- panic("task[0] trying to sleep");
- tmp = *p;
- *p = current;
- current->state = TASK_UNINTERRUPTIBLE;
- schedule();
- if (tmp)
- tmp->state=0;
-}
-
-void interruptible_sleep_on(struct task_struct **p)
-{
- struct task_struct *tmp;
-
- if (!p)
- return;
- if (current == &(init_task.task))
- panic("task[0] trying to sleep");
- tmp=*p;
- *p=current;
-repeat: current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (*p && *p != current) {
- (**p).state=0;
- goto repeat;
- }
- *p=NULL;
- if (tmp)
- tmp->state=0;
-}
-
-void wake_up(struct task_struct **p)
-{
- if (p && *p) {
- (**p).state=0;
- *p=NULL;
- }
-}
-
-/*
- * OK, here are some floppy things that shouldn't be in the kernel
- * proper. They are here because the floppy needs a timer, and this
- * was the easiest way of doing it.
- */
-static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL};
-static int mon_timer[4]={0,0,0,0};
-static int moff_timer[4]={0,0,0,0};
-unsigned char current_DOR = 0x0C;
-unsigned char selected = 0;
-struct task_struct * wait_on_floppy_select = NULL;
-
-void floppy_select(unsigned int nr)
-{
- if (nr>3)
- printk("floppy_select: nr>3\n\r");
- cli();
- while (selected)
- sleep_on(&wait_on_floppy_select);
- current_DOR &= 0xFC;
- current_DOR |= nr;
- outb(current_DOR,FD_DOR);
- sti();
-}
-
-void floppy_deselect(unsigned int nr)
-{
- if (nr != (current_DOR & 3))
- printk("floppy_deselect: drive not selected\n\r");
- selected = 0;
- wake_up(&wait_on_floppy_select);
-}
-
-int ticks_to_floppy_on(unsigned int nr)
-{
- unsigned char mask = 1<<(nr+4);
-
- if (nr>3)
- panic("floppy_on: nr>3");
- moff_timer[nr]=10000; /* 100 s = very big :-) */
- cli(); /* use floppy_off to turn it off */
- if (!(mask & current_DOR)) {
- current_DOR |= mask;
- if (!selected) {
- current_DOR &= 0xFC;
- current_DOR |= nr;
- }
- outb(current_DOR,FD_DOR);
- mon_timer[nr] = HZ;
- }
- sti();
- return mon_timer[nr];
-}
-
-void floppy_on(unsigned int nr)
-{
- cli();
- while (ticks_to_floppy_on(nr))
- sleep_on(nr+wait_motor);
- sti();
-}
-
-void floppy_off(unsigned int nr)
-{
- moff_timer[nr]=3*HZ;
-}
-
-void do_floppy_timer(void)
-{
- int i;
- unsigned char mask = 0x10;
-
- for (i=0 ; i<4 ; i++,mask <<= 1) {
- if (!(mask & current_DOR))
- continue;
- if (mon_timer[i]) {
- if (!--mon_timer[i])
- wake_up(i+wait_motor);
- } else if (!moff_timer[i]) {
- current_DOR &= ~mask;
- outb(current_DOR,FD_DOR);
- } else
- moff_timer[i]--;
- }
-}
-
-#define TIME_REQUESTS 64
-
-static struct timer_list {
- long jiffies;
- void (*fn)();
- struct timer_list * next;
-} timer_list[TIME_REQUESTS], * next_timer = NULL;
-
-void add_timer(long jiffies, void (*fn)(void))
-{
- struct timer_list * p;
-
- if (!fn)
- return;
- cli();
- if (jiffies <= 0)
- (fn)();
- else {
- for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++)
- if (!p->fn)
- break;
- if (p >= timer_list + TIME_REQUESTS)
- panic("No more time requests free");
- p->fn = fn;
- p->jiffies = jiffies;
- p->next = next_timer;
- next_timer = p;
- while (p->next && p->next->jiffies < p->jiffies) {
- p->jiffies -= p->next->jiffies;
- fn = p->fn;
- p->fn = p->next->fn;
- p->next->fn = fn;
- jiffies = p->jiffies;
- p->jiffies = p->next->jiffies;
- p->next->jiffies = jiffies;
- p = p->next;
- }
- }
- sti();
-}
-
-void do_timer(long cpl)
-{
- if (cpl)
- current->utime++;
- else
- current->stime++;
- if (next_timer) {
- next_timer->jiffies--;
- while (next_timer && next_timer->jiffies <= 0) {
- void (*fn)(void);
-
- fn = next_timer->fn;
- next_timer->fn = NULL;
- next_timer = next_timer->next;
- (fn)();
- }
- }
- if (current_DOR & 0xf0)
- do_floppy_timer();
- if ((--current->counter)>0) return;
- current->counter=0;
- if (!cpl) return;
- schedule();
-}
-
-int sys_alarm(long seconds)
-{
- int old = current->alarm;
-
- if (old)
- old = (old - jiffies) / HZ;
- current->alarm = (seconds>0)?(jiffies+HZ*seconds):0;
- return (old);
-}
-
-int sys_getpid(void)
-{
- return current->pid;
-}
-
-int sys_getppid(void)
-{
- return current->father;
-}
-
-int sys_getuid(void)
-{
- return current->uid;
-}
-
-int sys_geteuid(void)
-{
- return current->euid;
-}
-
-int sys_getgid(void)
-{
- return current->gid;
-}
-
-int sys_getegid(void)
-{
- return current->egid;
-}
-
-int sys_nice(long increment)
-{
- if (current->priority-increment>0)
- current->priority -= increment;
- return 0;
-}
-
-void sched_init(void)
-{
- int i;
- struct desc_struct * p;
-
- if (sizeof(struct sigaction) != 16)
- panic("Struct sigaction MUST be 16 bytes");
- set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
- set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
- p = gdt+2+FIRST_TSS_ENTRY;
- for(i=1;i<NR_TASKS;i++) {
- task[i] = NULL;
- p->a=p->b=0;
- p++;
- p->a=p->b=0;
- p++;
- }
- ltr(0);
- lldt(0);
- outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
- outb_p(LATCH & 0xff , 0x40); /* LSB */
- outb(LATCH >> 8 , 0x40); /* MSB */
- set_intr_gate(0x20,&timer_interrupt);
- outb(inb_p(0x21)&~0x01,0x21);
- set_system_gate(0x80,&system_call);
-}
-@
-
-
-1.1
-log
-@Initial revision
-@
-text
-@d344 4
-d349 1
-a349 1
- return seconds;
-@
+++ /dev/null
-head 1.2;
-branch ;
-access ;
-symbols ;
-locks ; strict;
-comment @ * @;
-
-
-1.2
-date 91.12.01.09.21.30; author tytso; state Exp;
-branches ;
-next 1.1;
-
-1.1
-date 91.11.21.09.18.36; author tytso; state Exp;
-branches ;
-next ;
-
-
-desc
-@@
-
-
-1.2
-log
-@Patches sent to linus
-@
-text
-@/*
- * linux/kernel/sys.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-#include <errno.h>
-
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/kernel.h>
-#include <asm/segment.h>
-#include <sys/times.h>
-#include <sys/utsname.h>
-
-int sys_ftime()
-{
- return -ENOSYS;
-}
-
-int sys_break()
-{
- return -ENOSYS;
-}
-
-int sys_ptrace()
-{
- return -ENOSYS;
-}
-
-int sys_stty()
-{
- return -ENOSYS;
-}
-
-int sys_gtty()
-{
- return -ENOSYS;
-}
-
-int sys_rename()
-{
- return -ENOSYS;
-}
-
-int sys_prof()
-{
- return -ENOSYS;
-}
-
-int sys_setregid(int rgid, int egid)
-{
- if (rgid>0) {
- if ((current->gid == rgid) ||
- suser())
- current->gid = rgid;
- else
- return(-EPERM);
- }
- if (egid>0) {
- if ((current->gid == egid) ||
- (current->egid == egid) ||
- (current->sgid == egid) ||
- suser())
- current->egid = egid;
- else
- return(-EPERM);
- }
- return 0;
-}
-
-int sys_setgid(int gid)
-{
- return(sys_setregid(gid, gid));
-}
-
-int sys_acct()
-{
- return -ENOSYS;
-}
-
-int sys_phys()
-{
- return -ENOSYS;
-}
-
-int sys_lock()
-{
- return -ENOSYS;
-}
-
-int sys_mpx()
-{
- return -ENOSYS;
-}
-
-int sys_ulimit()
-{
- return -ENOSYS;
-}
-
-int sys_time(long * tloc)
-{
- int i;
-
- i = CURRENT_TIME;
- if (tloc) {
- verify_area(tloc,4);
- put_fs_long(i,(unsigned long *)tloc);
- }
- return i;
-}
-
-/*
- * Unprivileged users may change the real user id to the effective uid
- * or vice versa.
- */
-int sys_setreuid(int ruid, int euid)
-{
- int old_ruid = current->uid;
-
- if (ruid>0) {
- if ((current->euid==ruid) ||
- (old_ruid == ruid) ||
- suser())
- current->uid = ruid;
- else
- return(-EPERM);
- }
- if (euid>0) {
- if ((old_ruid == euid) ||
- (current->euid == euid) ||
- suser())
- current->euid = euid;
- else {
- current->uid = old_ruid;
- return(-EPERM);
- }
- }
- return 0;
-}
-
-int sys_setuid(int uid)
-{
- return(sys_setreuid(uid, uid));
-}
-
-int sys_stime(long * tptr)
-{
- if (!suser())
- return -EPERM;
- startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ;
- return 0;
-}
-
-int sys_times(struct tms * tbuf)
-{
- if (tbuf) {
- verify_area(tbuf,sizeof *tbuf);
- put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime);
- put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime);
- put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime);
- put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime);
- }
- return jiffies;
-}
-
-int sys_brk(unsigned long end_data_seg)
-{
- if (end_data_seg >= current->end_code &&
- end_data_seg < current->start_stack - 16384)
- current->brk = end_data_seg;
- return current->brk;
-}
-
-/*
- * This needs some heave checking ...
- * I just haven't get the stomach for it. I also don't fully
- * understand sessions/pgrp etc. Let somebody who does explain it.
- */
-int sys_setpgid(int pid, int pgid)
-{
- int i;
-
- if (!pid)
- pid = current->pid;
- if (!pgid)
- pgid = current->pid;
- for (i=0 ; i<NR_TASKS ; i++)
- if (task[i] && task[i]->pid==pid) {
- if (task[i]->leader)
- return -EPERM;
- if (task[i]->session != current->session)
- return -EPERM;
- task[i]->pgrp = pgid;
- return 0;
- }
- return -ESRCH;
-}
-
-int sys_getpgrp(void)
-{
- return current->pgrp;
-}
-
-int sys_setsid(void)
-{
- if (current->leader && !suser())
- return -EPERM;
- current->leader = 1;
- current->session = current->pgrp = current->pid;
- current->tty = -1;
- return current->pgrp;
-}
-
-int sys_uname(struct utsname * name)
-{
- static struct utsname thisname = {
- "linux .0","nodename","release ","version ","machine "
- };
- int i;
-
- if (!name) return -ERROR;
- verify_area(name,sizeof *name);
- for(i=0;i<sizeof *name;i++)
- put_fs_byte(((char *) &thisname)[i],i+(char *) name);
- return 0;
-}
-
-int sys_umask(int mask)
-{
- int old = current->umask;
-
- current->umask = mask & 0777;
- return (old);
-}
-@
-
-
-1.1
-log
-@Initial revision
-@
-text
-@d51 1
-a51 1
-int sys_setgid(int gid)
-d53 4
-a56 3
- if (current->euid && current->uid)
- if (current->gid==gid || current->sgid==gid)
- current->egid = gid;
-d58 11
-a68 3
- return -EPERM;
- else
- current->gid = current->egid = gid;
-d72 5
-d114 5
-a118 1
-int sys_setuid(int uid)
-d120 7
-a126 3
- if (current->euid && current->uid)
- if (uid==current->uid || current->suid==current->uid)
- current->euid=uid;
-d128 12
-a139 3
- return -EPERM;
- else
- current->euid=current->uid=uid;
-d143 5
-d150 1
-a150 1
- if (current->euid && current->uid)
-d208 1
-a208 3
- if (current->uid && current->euid)
- return -EPERM;
- if (current->leader)
-@
*/
.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
-.globl _device_not_available,_double_fault,_coprocessor_segment_overrun
+.globl _double_fault,_coprocessor_segment_overrun
.globl _invalid_TSS,_segment_not_present,_stack_segment
.globl _general_protection,_coprocessor_error,_irq13,_reserved
pushl $_do_invalid_op
jmp no_error_code
-math_emulate:
- popl %eax
- pushl $_do_device_not_available
- jmp no_error_code
-_device_not_available:
- pushl %eax
- movl %cr0,%eax
- testl $0x4,%eax # EM (math emulation bit)
- jne math_emulate
- clts # clear TS so that we can use math
- pushl %ecx
- pushl %edx
- push %ds
- movl $0x10,%eax
- mov %ax,%ds
- call _math_state_restore
- pop %ds
- popl %edx
- popl %ecx
- popl %eax
- iret
-
_coprocessor_segment_overrun:
pushl $_do_coprocessor_segment_overrun
jmp no_error_code
1: jmp 1f
1: outb %al,$0xA0
popl %eax
-_coprocessor_error:
- fnclex
- pushl $_do_coprocessor_error
- jmp no_error_code
+ jmp _coprocessor_error
_double_fault:
pushl $_do_double_fault
$(CC) $(CFLAGS) \
-c -o $*.o $<
-OBJS = ll_rw_blk.o floppy.o hd.o
+OBJS = ll_rw_blk.o floppy.o hd.o ramdisk.o
blk_drv.a: $(OBJS)
$(AR) rcs blk_drv.a $(OBJS)
#define _BLK_H
#define NR_BLK_DEV 7
-#define NR_REQUEST 64
+/*
+ * NR_REQUEST is the number of entries in the request-queue.
+ * NOTE that writes may use only the low 2/3 of these: reads
+ * take precedence.
+ *
+ * 32 seems to be a reasonable number: enough to get some benefit
+ * from the elevator-mechanism, but not so much as to lock a lot of
+ * buffers when they are in the queue. 64 seems to be too many (easily
+ * long pauses in reading when heavy writing/syncing is going on)
+ */
+#define NR_REQUEST 32
/*
* Ok, this is an expanded form so that we can use the same
struct request * next;
};
+/*
+ * This is used in the elevator algorithm: Note that
+ * reads always go before writes. This is natural: reads
+ * 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)->sector < (s2)->sector)))
struct blk_dev_struct {
void (*request_fn)(void);
* Add entries as needed. Currently the only block devices
* supported are hard-disks and floppies.
*/
-#if (MAJOR_NR == 2)
+
+#if (MAJOR_NR == 1)
+/* ram disk */
+#define DEVICE_NAME "ramdisk"
+#define DEVICE_REQUEST do_rd_request
+#define DEVICE_NR(device) ((device) & 7)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == 2)
/* floppy */
#define DEVICE_NAME "floppy"
#define DEVICE_INTR do_floppy
#define CURRENT (blk_dev[MAJOR_NR].current_request)
#define CURRENT_DEV DEVICE_NR(CURRENT->dev)
+#ifdef DEVICE_INTR
void (*DEVICE_INTR)(void) = NULL;
+#endif
static void (DEVICE_REQUEST)(void);
extern inline void unlock_buffer(struct buffer_head * bh)
return; \
if (MAJOR(CURRENT->dev) != MAJOR_NR) \
panic(DEVICE_NAME ": request list destroyed"); \
- if (CURRENT->bh) \
+ if (CURRENT->bh) { \
if (!CURRENT->bh->b_lock) \
panic(DEVICE_NAME ": block not locked"); \
- else { \
- CURRENT->bh->b_dirt = 0; \
- CURRENT->bh->b_uptodate = 0; \
- }
+ }
#endif
* (C) 1991 Linus Torvalds
*/
+/*
+ * 02.12.91 - Changed to static variables to indicate need for reset
+ * and recalibrate. This makes some things easier (output_byte reset
+ * checking etc), and means less interrupt jumping in case of errors,
+ * so the code is hopefully easier to understand.
+ */
+
+/*
+ * This file is certainly a mess. I've tried my best to get it working,
+ * but I don't like programming floppies, and I have only one anyway.
+ * Urgel. I should check for more errors, and do more graceful error
+ * recovery. Seems there are problems with several drives. I've tried to
+ * correct them. No promises.
+ */
+
/*
* As with hd.c, all routines within this file can (and will) be called
* by interrupts, so extreme caution is needed. A hardware interrupt
#define MAJOR_NR 2
#include "blk.h"
-static void reset_floppy(void);
-static void seek_interrupt(void);
-static void rw_interrupt(void);
+static int recalibrate = 0;
+static int reset = 0;
+static int seek = 0;
extern unsigned char current_DOR;
-extern unsigned char selected;
#define immoutb_p(val,port) \
__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=10 doesn't imply that we retry every bad read
- * max 10 times - some types of errors increase the errorcount by 2,
- * so we might actually retry only 6-7 times before giving up.
+ * 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.
*/
-#define MAX_ERRORS 10
+#define MAX_ERRORS 8
/*
* globals used by 'result()'
/*
* This struct defines the different floppy types. Unlike minix
* linux doesn't have a "search for right type"-type, as the code
- * for that is convoluted and weird.
+ * for that is convoluted and weird. I've got enough problems with
+ * this driver as it is.
*
* The 'stretch' tells if the tracks need to be boubled for some
* types (ie 360kB diskette in 1.2MB drive etc). Others should
* be self-explanatory.
*/
static struct floppy_struct {
- int size, sect, head, track, stretch;
+ unsigned int size, sect, head, track, stretch;
unsigned char gap,rate,spec1;
} floppy_type[] = {
{ 0, 0,0, 0,0,0x00,0x00,0x00 }, /* no testing */
static unsigned char head = 0;
static unsigned char track = 0;
static unsigned char seek_track = 0;
+static unsigned char current_track = 255;
static unsigned char command = 0;
+unsigned char selected = 0;
+struct task_struct * wait_on_floppy_select = NULL;
+
+void floppy_deselect(unsigned int nr)
+{
+ if (nr != (current_DOR & 3))
+ printk("floppy_deselect: drive not selected\n\r");
+ selected = 0;
+ wake_up(&wait_on_floppy_select);
+}
/*
* floppy-change is never called from an interrupt, so we can relax a bit
- * here.
+ * here, sleep etc. Note that floppy-on tries to set current_DOR to point
+ * to the desired drive, but it will probably not survive the sleep if
+ * several floppies are used at the same time: thus the loop.
*/
int floppy_change(unsigned int nr)
{
+repeat:
floppy_on(nr);
- floppy_select(nr);
+ while ((current_DOR & 3) != nr && selected)
+ interruptible_sleep_on(&wait_on_floppy_select);
+ if ((current_DOR & 3) != nr)
+ goto repeat;
if (inb(FD_DIR) & 0x80) {
floppy_off(nr);
return 1;
{
long addr = (long) CURRENT->buffer;
+ cli();
if (addr >= 0x100000) {
addr = (long) tmp_floppy_area;
if (command == FD_WRITE)
immoutb_p(3,5);
/* activate DMA 2 */
immoutb_p(0|2,10);
+ sti();
}
static void output_byte(char byte)
int counter;
unsigned char status;
+ if (reset)
+ return;
for(counter = 0 ; counter < 10000 ; counter++) {
- status = inb(FD_STATUS) & (STATUS_READY | STATUS_DIR);
+ status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR);
if (status == STATUS_READY) {
outb(byte,FD_DATA);
return;
}
}
+ reset = 1;
printk("Unable to send byte to FDC\n\r");
}
{
int i = 0, counter, status;
+ if (reset)
+ return -1;
for (counter = 0 ; counter < 10000 ; counter++) {
- status = inb(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY);
+ status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY);
if (status == STATUS_READY)
return i;
if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
if (i >= MAX_REPLIES)
break;
- reply_buffer[i++] = inb(FD_DATA);
+ reply_buffer[i++] = inb_p(FD_DATA);
}
}
+ reset = 1;
printk("Getstatus times out\n\r");
return -1;
}
+static void bad_flp_intr(void)
+{
+ CURRENT->errors++;
+ if (CURRENT->errors > MAX_ERRORS) {
+ floppy_deselect(current_drive);
+ end_request(0);
+ }
+ if (CURRENT->errors > MAX_ERRORS/2)
+ reset = 1;
+ else
+ recalibrate = 1;
+}
+
/*
- * This is the routine called after every seek (or recalibrate) interrupt
- * from the floppy controller. Note that the "unexpected interrupt" routine
- * also does a recalibrate, but doesn't come here.
+ * Ok, this interrupt is called after a DMA read/write has succeeded,
+ * so we check the results, and copy any buffers.
*/
-static void seek_interrupt(void)
+static void rw_interrupt(void)
{
-/* sense drive status */
- output_byte(FD_SENSEI);
- if (result() != 2 || (ST0 & 0xF8) != 0x20) {
- CURRENT->errors++;
- if (CURRENT->errors > MAX_ERRORS) {
+ if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || (ST2 & 0x73)) {
+ if (ST1 & 0x02) {
+ printk("Drive %d is write protected\n\r",current_drive);
floppy_deselect(current_drive);
end_request(0);
- reset_floppy();
- return;
- }
- output_byte(FD_RECALIBRATE);
- output_byte(head<<2 | current_drive);
+ } else
+ bad_flp_intr();
+ do_fd_request();
return;
}
-/* are we on the right track? */
- if (ST1 != seek_track) {
- CURRENT->errors++;
- if (CURRENT->errors > MAX_ERRORS) {
- floppy_deselect(current_drive);
- end_request(0);
- reset_floppy();
- return;
- }
- output_byte(FD_SEEK);
- output_byte(head<<2 | current_drive);
- output_byte(seek_track);
- return;
- }
-/* yes - set up DMA and read/write command */
+ 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();
+}
+
+inline void setup_rw_floppy(void)
+{
setup_DMA();
do_floppy = rw_interrupt;
output_byte(command);
output_byte(floppy->sect);
output_byte(floppy->gap);
output_byte(0xFF); /* sector size (0xff when n!=0 ?) */
+ if (reset)
+ do_fd_request();
}
/*
- * Ok, this interrupt is called after a DMA read/write has succeeded,
- * so we check the results, and copy any buffers.
+ * This is the routine called after every seek (or recalibrate) interrupt
+ * from the floppy controller. Note that the "unexpected interrupt" routine
+ * also does a recalibrate, but doesn't come here.
*/
-static void rw_interrupt(void)
+static void seek_interrupt(void)
{
- if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) ||
- (ST2 & 0x73)) {
- CURRENT->errors++;
- if (CURRENT->errors > MAX_ERRORS || (ST1 & 0x02)) {
- if (ST1 & 0x02)
- printk("Drive %d is write protected\n\r",
- current_drive);
- floppy_deselect(current_drive);
- end_request(0);
- do_fd_request();
- return;
- }
- do_floppy = seek_interrupt;
- output_byte(FD_RECALIBRATE);
- output_byte(head<<2 | current_drive);
+/* sense drive status */
+ output_byte(FD_SENSEI);
+ if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) {
+ bad_flp_intr();
+ do_fd_request();
return;
}
- if (command == FD_READ && (long)(CURRENT->buffer) >= 0x100000)
- copy_buffer(tmp_floppy_area,CURRENT->buffer);
- floppy_deselect(current_drive);
- end_request(1);
- do_fd_request();
+ current_track = ST1;
+ setup_rw_floppy();
}
/*
}
if (cur_rate != floppy->rate)
outb_p(cur_rate = floppy->rate,FD_DCR);
+ if (reset) {
+ do_fd_request();
+ return;
+ }
+ if (!seek) {
+ setup_rw_floppy();
+ return;
+ }
do_floppy = seek_interrupt;
if (seek_track) {
output_byte(FD_SEEK);
output_byte(FD_RECALIBRATE);
output_byte(head<<2 | current_drive);
}
+ if (reset)
+ do_fd_request();
}
/*
*/
static void recal_interrupt(void)
{
- do_floppy = NULL;
output_byte(FD_SENSEI);
- if (result()!=2 || (ST0 & 0xE0) == 0x60) {
- reset_floppy();
- return;
- }
+ if (result()!=2 || (ST0 & 0xE0) == 0x60)
+ reset = 1;
+ else
+ recalibrate = 0;
do_fd_request();
}
void unexpected_floppy_interrupt(void)
{
output_byte(FD_SENSEI);
- if (result()!=2 || (ST0 & 0xE0) == 0x60) {
- reset_floppy();
- return;
- }
+ if (result()!=2 || (ST0 & 0xE0) == 0x60)
+ reset = 1;
+ else
+ recalibrate = 1;
+}
+
+static void recalibrate_floppy(void)
+{
+ recalibrate = 0;
+ current_track = 0;
do_floppy = recal_interrupt;
output_byte(FD_RECALIBRATE);
output_byte(head<<2 | current_drive);
+ if (reset)
+ do_fd_request();
}
static void reset_interrupt(void)
{
output_byte(FD_SENSEI);
(void) result();
- do_floppy = recal_interrupt;
- output_byte(FD_RECALIBRATE);
- output_byte(head<<2 | current_drive);
+ output_byte(FD_SPECIFY);
+ output_byte(cur_spec1); /* hut etc */
+ output_byte(6); /* Head load time =6ms, DMA */
+ do_fd_request();
}
+/*
+ * reset is done by pulling bit 2 of DOR low for a while.
+ */
static void reset_floppy(void)
{
+ int i;
+
+ reset = 0;
+ cur_spec1 = -1;
+ cur_rate = -1;
+ recalibrate = 1;
printk("Reset-floppy called\n\r");
+ cli();
do_floppy = reset_interrupt;
- outb_p(0,FD_DOR);
+ outb_p(current_DOR & ~0x04,FD_DOR);
+ for (i=0 ; i<100 ; i++)
+ __asm__("nop");
outb(current_DOR,FD_DOR);
+ sti();
}
static void floppy_on_interrupt(void)
{
/* We cannot do a floppy-select, as that might sleep. We just force it */
selected = 1;
- current_DOR &= 0xFC;
- current_DOR |= current_drive;
- transfer();
+ if (current_drive != (current_DOR & 3)) {
+ current_DOR &= 0xFC;
+ current_DOR |= current_drive;
+ outb(current_DOR,FD_DOR);
+ add_timer(2,&transfer);
+ } else
+ transfer();
}
void do_fd_request(void)
{
unsigned int block;
+ seek = 0;
+ if (reset) {
+ reset_floppy();
+ return;
+ }
+ if (recalibrate) {
+ recalibrate_floppy();
+ return;
+ }
INIT_REQUEST;
floppy = (MINOR(CURRENT->dev)>>2) + floppy_type;
+ if (current_drive != CURRENT_DEV)
+ seek = 1;
current_drive = CURRENT_DEV;
block = CURRENT->sector;
if (block+2 > floppy->size) {
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;
void floppy_init(void)
{
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
- set_intr_gate(0x26,&floppy_interrupt);
+ set_trap_gate(0x26,&floppy_interrupt);
outb(inb_p(0x21)&~0x40,0x21);
}
* request-list, using interrupts to jump between functions. As
* all the functions are called within interrupts, we may not
* sleep. Special care is recommended.
+ *
+ * modified by Drew Eckhardt to check nr of hd's from the CMOS.
*/
#include <linux/config.h>
#define MAJOR_NR 3
#include "blk.h"
+#define CMOS_READ(addr) ({ \
+outb_p(0x80|addr,0x70); \
+inb_p(0x71); \
+})
+
/* Max read/write errors/sector */
-#define MAX_ERRORS 5
+#define MAX_ERRORS 7
#define MAX_HD 2
+static void recal_intr(void);
+
+static int recalibrate = 1;
+static int reset = 1;
+
/*
* This struct defines the HD's and their types.
*/
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
extern void hd_interrupt(void);
+extern void rd_load(void);
/* 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;
hd[i*5].nr_sects = hd_info[i].head*
hd_info[i].sect*hd_info[i].cyl;
}
+
+ /*
+ We querry CMOS about hard disks : it could be that
+ we have a SCSI/ESDI/etc controller that is BIOS
+ compatable with ST-506, and thus showing up in our
+ BIOS table, but not register compatable, and therefore
+ not present in CMOS.
+
+ Furthurmore, we will assume that our ST-506 drives
+ <if any> are the primary drives in the system, and
+ the ones reflected as drive 1 or 2.
+
+ The first drive is stored in the high nibble of CMOS
+ byte 0x12, the second in the low nibble. This will be
+ either a 4 bit drive type or 0xf indicating use byte 0x19
+ for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
+
+ Needless to say, a non-zero value means we have
+ an AT controller hard disk for that drive.
+
+
+ */
+
+ if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
+ if (cmos_disks & 0x0f)
+ NR_HD = 2;
+ else
+ NR_HD = 1;
+ else
+ NR_HD = 0;
+ for (i = NR_HD ; i < 2 ; i++) {
+ hd[i*5].start_sect = 0;
+ hd[i*5].nr_sects = 0;
+ }
for (drive=0 ; drive<NR_HD ; drive++) {
if (!(bh = bread(0x300 + drive*5,0))) {
printk("Unable to read partition table of drive %d\n\r",
}
brelse(bh);
}
- printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
+ if (NR_HD)
+ printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
+ rd_load();
mount_root();
return (0);
}
static int controller_ready(void)
{
- int retries=1000;
+ int retries=10000;
- while (--retries && (inb(HD_STATUS)&0xc0)!=0x40);
+ while (--retries && (inb_p(HD_STATUS)&0xc0)!=0x40);
return (retries);
}
static int win_result(void)
{
- int i=inb(HD_STATUS);
+ int i=inb_p(HD_STATUS);
if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
== (READY_STAT | SEEK_STAT))
if (!controller_ready())
panic("HD controller not ready");
do_hd = intr_addr;
- outb(hd_info[drive].ctl,HD_CMD);
+ outb_p(hd_info[drive].ctl,HD_CMD);
port=HD_DATA;
outb_p(hd_info[drive].wpcom>>2,++port);
outb_p(nsect,++port);
{
unsigned int i;
- for (i = 0; i < 100000; i++)
- if (READY_STAT == (inb(HD_STATUS) & (BUSY_STAT | READY_STAT)))
+ for (i = 0; i < 10000; i++)
+ if (READY_STAT == (inb_p(HD_STATUS) & (BUSY_STAT|READY_STAT)))
break;
i = inb(HD_STATUS);
i &= BUSY_STAT | READY_STAT | SEEK_STAT;
int i;
outb(4,HD_CMD);
- for(i = 0; i < 1000; i++) nop();
- outb(0,HD_CMD);
- for(i = 0; i < 10000 && drive_busy(); i++) /* nothing */;
+ for(i = 0; i < 100; i++) nop();
+ outb(hd_info[0].ctl & 0x0f ,HD_CMD);
if (drive_busy())
printk("HD-controller still busy\n\r");
- if((i = inb(ERR_STAT)) != 1)
+ if ((i = inb(HD_ERROR)) != 1)
printk("HD-controller reset failed: %02x\n\r",i);
}
-static void redo_hd_request(void)
-{
- do_hd = NULL;
- do_hd_request();
-}
-
static void reset_hd(int nr)
{
reset_controller();
hd_out(nr,hd_info[nr].sect,hd_info[nr].sect,hd_info[nr].head-1,
- hd_info[nr].cyl,WIN_SPECIFY,&redo_hd_request);
+ hd_info[nr].cyl,WIN_SPECIFY,&recal_intr);
}
void unexpected_hd_interrupt(void)
static void bad_rw_intr(void)
{
- int i = CURRENT_DEV;
-
- if (CURRENT->errors++ >= MAX_ERRORS)
+ if (++CURRENT->errors >= MAX_ERRORS)
end_request(0);
- reset_hd(i);
+ if (CURRENT->errors > MAX_ERRORS/2)
+ reset = 1;
}
static void read_intr(void)
{
if (win_result()) {
bad_rw_intr();
+ do_hd_request();
return;
}
port_read(HD_DATA,CURRENT->buffer,256);
CURRENT->errors = 0;
CURRENT->buffer += 512;
CURRENT->sector++;
- if (--CURRENT->nr_sectors)
+ if (--CURRENT->nr_sectors) {
+ do_hd = &read_intr;
return;
+ }
end_request(1);
do_hd_request();
}
{
if (win_result()) {
bad_rw_intr();
+ do_hd_request();
return;
}
if (--CURRENT->nr_sectors) {
CURRENT->sector++;
CURRENT->buffer += 512;
+ do_hd = &write_intr;
port_write(HD_DATA,CURRENT->buffer,256);
return;
}
do_hd_request();
}
+static void recal_intr(void)
+{
+ if (win_result())
+ bad_rw_intr();
+ do_hd_request();
+}
+
void do_hd_request(void)
{
int i,r;
"r" (hd_info[dev].head));
sec++;
nsect = CURRENT->nr_sectors;
+ if (reset) {
+ reset = 0;
+ recalibrate = 1;
+ reset_hd(CURRENT_DEV);
+ return;
+ }
+ if (recalibrate) {
+ recalibrate = 0;
+ hd_out(dev,hd_info[CURRENT_DEV].sect,0,0,0,
+ WIN_RESTORE,&recal_intr);
+ return;
+ }
if (CURRENT->cmd == WRITE) {
hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
/* nothing */ ;
if (!r) {
- reset_hd(CURRENT_DEV);
- return;
+ bad_rw_intr();
+ goto repeat;
}
port_write(HD_DATA,CURRENT->buffer,256);
} else if (CURRENT->cmd == READ) {
void hd_init(void)
{
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
- set_trap_gate(0x2E,&hd_interrupt);
+ set_intr_gate(0x2E,&hd_interrupt);
outb_p(inb_p(0x21)&0xfb,0x21);
outb(inb_p(0xA1)&0xbf,0xA1);
}
req->next = NULL;
cli();
+ if (req->bh)
+ req->bh->b_dirt = 0;
if (!(tmp = dev->current_request)) {
dev->current_request = req;
sti();
(dev->request_fn)();
- } else {
- for ( ; tmp->next ; tmp=tmp->next)
- if ((IN_ORDER(tmp,req) ||
- !IN_ORDER(tmp,tmp->next)) &&
- IN_ORDER(req,tmp->next))
- break;
- req->next=tmp->next;
- tmp->next=req;
+ return;
}
+ for ( ; tmp->next ; tmp=tmp->next)
+ if ((IN_ORDER(tmp,req) ||
+ !IN_ORDER(tmp,tmp->next)) &&
+ IN_ORDER(req,tmp->next))
+ break;
+ req->next=tmp->next;
+ tmp->next=req;
sti();
}
static void make_request(int major,int rw, struct buffer_head * bh)
{
struct request * req;
+ int rw_ahead;
-/* READA is special case - the read is not really needed, so if the */
+/* WRITEA/READA is special case - it is not really needed, so if the */
/* buffer is locked, we just forget about it, else it's a normal read */
- if (rw == READA) {
+ if (rw_ahead = (rw == READA || rw == WRITEA)) {
if (bh->b_lock)
return;
+ if (rw == READA)
+ rw = READ;
else
- rw=READ;
+ rw = WRITE;
}
if (rw!=READ && rw!=WRITE)
- panic("Bad block dev command, must be R/W/RA");
+ panic("Bad block dev command, must be R/W/RA/WA");
lock_buffer(bh);
if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) {
unlock_buffer(bh);
return;
}
repeat:
- for (req=0+request ; req<NR_REQUEST+request ; req++)
+/* we don't allow the write-requests to fill up the queue completely:
+ * we want some room for reads: they take precedence. The last third
+ * of the requests are only for reads.
+ */
+ if (rw == READ)
+ req = request+NR_REQUEST;
+ else
+ req = request+((NR_REQUEST*2)/3);
+/* find an empty request */
+ while (--req >= request)
if (req->dev<0)
break;
- if (req==NR_REQUEST+request) {
+/* 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;
}
+/* fill up the request-info, and add it to the queue */
req->dev = bh->b_dev;
req->cmd = rw;
req->errors=0;
unsigned int major;
if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV ||
- !(blk_dev[major].request_fn))
- panic("Trying to read nonexistent block-device");
+ !(blk_dev[major].request_fn)) {
+ printk("Trying to read nonexistent block-device\n\r");
+ return;
+ }
make_request(major,rw,bh);
}
/*
* linux/kernel/blk_drv/ramdisk.c
*
- * Written by Theodore Ts'o
+ * Written by Theodore Ts'o, 12/2/91
*/
+#include <string.h>
+
#include <linux/config.h>
+#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
-#include <linux/hdreg.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/memory.h>
#define MAJOR_NR 1
#include "blk.h"
-char *ram_disk; /* Start of ram disk */
-int ram_disk_size; /* Size of ram disk */
+char *rd_start;
+int rd_length = 0;
-void do_ram_request(void)
+void do_rd_request(void)
{
- int i,r;
- unsigned int block,dev;
- unsigned int sec,head,cyl;
- unsigned int nsect;
+ int len;
+ char *addr;
INIT_REQUEST;
- if (MINOR(CURRENT->dev) != 0) {
+ addr = rd_start + (CURRENT->sector << 9);
+ len = CURRENT->nr_sectors << 9;
+ if ((MINOR(CURRENT->dev) != 1) || (addr+len > rd_start+rd_length)) {
end_request(0);
goto repeat;
}
- block = CURRENT->sector;
+ if (CURRENT-> cmd == WRITE) {
+ (void ) memcpy(addr,
+ CURRENT->buffer,
+ len);
+ } else if (CURRENT->cmd == READ) {
+ (void) memcpy(CURRENT->buffer,
+ addr,
+ len);
+ } else
+ panic("unknown ramdisk-command");
end_request(1);
+ goto repeat;
}
-void ram_init(void)
+/*
+ * Returns amount of memory which needs to be reserved.
+ */
+long rd_init(long mem_start, int length)
{
+ int i;
+ char *cp;
+ blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+ rd_start = (char *) mem_start;
+ rd_length = length;
+ cp = rd_start;
+ for (i=0; i < length; i++)
+ *cp++ = '\0';
+ return(length);
+}
+
+/*
+ * If the root device is the ram disk, try to load it.
+ * In order to do this, the root device is originally set to the
+ * floppy, and we later change it to be ram disk.
+ */
+void rd_load(void)
+{
+ struct buffer_head *bh;
+ struct super_block s;
+ int block = 256; /* Start at block 256 */
+ int i = 1;
+ int nblocks;
+ char *cp; /* Move pointer */
+
+ if (!rd_length)
+ return;
+ printk("Ram disk: %d bytes, starting at 0x%x\n", rd_length,
+ (int) rd_start);
+ if (MAJOR(ROOT_DEV) != 2)
+ return;
+ bh = breada(ROOT_DEV,block+1,block,block+2,-1);
+ if (!bh) {
+ printk("Disk error while looking for ramdisk!\n");
+ return;
+ }
+ *((struct d_super_block *) &s) = *((struct d_super_block *) bh->b_data);
+ brelse(bh);
+ if (s.s_magic != SUPER_MAGIC)
+ /* No ram disk image present, assume normal floppy boot */
+ return;
+ nblocks = s.s_nzones << s.s_log_zone_size;
+ if (nblocks > (rd_length >> BLOCK_SIZE_BITS)) {
+ printk("Ram disk image too big! (%d blocks, %d avail)\n",
+ nblocks, rd_length >> BLOCK_SIZE_BITS);
+ return;
+ }
+ printk("Loading %d bytes into ram disk... 0000k",
+ nblocks << BLOCK_SIZE_BITS);
+ cp = rd_start;
+ while (nblocks) {
+ if (nblocks > 2)
+ bh = breada(ROOT_DEV, block, block+1, block+2, -1);
+ else
+ bh = bread(ROOT_DEV, block);
+ if (!bh) {
+ printk("I/O error on block %d, aborting load\n",
+ block);
+ return;
+ }
+ (void) memcpy(cp, bh->b_data, BLOCK_SIZE);
+ brelse(bh);
+ printk("\010\010\010\010\010%4dk",i);
+ cp += BLOCK_SIZE;
+ block++;
+ nblocks--;
+ i++;
+ }
+ printk("\010\010\010\010\010done \n");
+ ROOT_DEV=0x0101;
}
+++ /dev/null
-/*
- * linux/kernel/blk_drv/ramdisk.c
- *
- * Written by Theodore Ts'o
- */
-
-#include <linux/config.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/hdreg.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/segment.h>
-
-#define MAJOR_NR 2
-#include "blk.h"
-
-void do_ram_request(void)
-{
- int i,r;
- unsigned int block,dev;
- unsigned int sec,head,cyl;
- unsigned int nsect;
-
- INIT_REQUEST;
- dev = MINOR(CURRENT->dev);
- block = CURRENT->sector;
- if (dev >= 5*NR_HD || 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));
- sec++;
- nsect = CURRENT->nr_sectors;
- if (CURRENT->cmd == WRITE) {
- hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
- for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
- /* nothing */ ;
- if (!r) {
- reset_hd(CURRENT_DEV);
- return;
- }
- port_write(HD_DATA,CURRENT->buffer,256);
- } else if (CURRENT->cmd == READ) {
- hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
- } else
- panic("unknown hd-command");
-}
-
-void ram_init(void)
-{
-
-}
$(CC) $(CFLAGS) \
-c -o $*.o $<
-OBJS = tty_io.o console.o keyboard.o serial.o rs_io.o
+OBJS = tty_io.o console.o keyboard.o serial.o rs_io.o \
+ tty_ioctl.o
chr_drv.a: $(OBJS)
$(AR) rcs chr_drv.a $(OBJS)
../../include/linux/fs.h ../../include/linux/mm.h ../../include/linux/tty.h \
../../include/termios.h ../../include/asm/segment.h \
../../include/asm/system.h
+tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.h \
+ ../../include/linux/sched.h ../../include/linux/head.h \
+ ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
+ ../../include/signal.h ../../include/linux/kernel.h \
+ ../../include/linux/tty.h ../../include/asm/io.h \
+ ../../include/asm/segment.h ../../include/asm/system.h
+++ /dev/null
-head 1.1;
-branch ;
-access ;
-symbols ;
-locks tytso:1.1; strict;
-comment @@;
-
-
-1.1
-date 91.11.21.14.50.43; author tytso; state Exp;
-branches ;
-next ;
-
-
-desc
-@@
-
-
-
-1.1
-log
-@Initial revision
-@
-text
-@/*
- * linux/kernel/keyboard.S
- *
- * (C) 1991 Linus Torvalds
- */
-
-/*
- * Thanks to Alfred Leung for US keyboard patches
- */
-
-#include <linux/config.h>
-
-.text
-.globl _keyboard_interrupt
-
-/*
- * these are for the keyboard read functions
- */
-size = 1024 /* must be a power of two ! And MUST be the same
- as in tty_io.c !!!! */
-head = 4
-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) */
-e0: .byte 0
-
-/*
- * con_int is the real interrupt routine that reads the
- * keyboard scan-code and converts it into the appropriate
- * ascii character(s).
- */
-_keyboard_interrupt:
- pushl %eax
- pushl %ebx
- pushl %ecx
- pushl %edx
- push %ds
- push %es
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- xorl %al,%al /* %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
- jmp 1f
-1: jmp 1f
-1: orb $0x80,%al
- jmp 1f
-1: jmp 1f
-1: outb %al,$0x61
- jmp 1f
-1: jmp 1f
-1: andb $0x7F,%al
- outb %al,$0x61
- movb $0x20,%al
- outb %al,$0x20
- pushl $0
- call _do_tty_interrupt
- addl $4,%esp
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- 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
- * %ebx:%eax. (%edx is high). The bytes are written in the
- * order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero.
- */
-put_queue:
- pushl %ecx
- pushl %edx
- movl _table_list,%edx # read-queue for console
- movl head(%edx),%ecx
-1: movb %al,buf(%edx,%ecx)
- incl %ecx
- andl $size-1,%ecx
- cmpl tail(%edx),%ecx # buffer full - discard everything
- je 3f
- shrdl $8,%ebx,%eax
- je 2f
- shrl $8,%ebx
- jmp 1b
-2: movl %ecx,head(%edx)
- movl proc_list(%edx),%ecx
- testl %ecx,%ecx
- je 3f
- movl $0,(%ecx)
-3: popl %edx
- popl %ecx
- ret
-
-ctrl: movb $0x04,%al
- jmp 1f
-alt: movb $0x10,%al
-1: cmpb $0,e0
- je 2f
- addb %al,%al
-2: orb %al,mode
- ret
-unctrl: movb $0x04,%al
- jmp 1f
-unalt: movb $0x10,%al
-1: cmpb $0,e0
- je 2f
- addb %al,%al
-2: notb %al
- andb %al,mode
- ret
-
-lshift:
- orb $0x01,mode
- ret
-unlshift:
- andb $0xfe,mode
- ret
-rshift:
- orb $0x02,mode
- ret
-unrshift:
- andb $0xfd,mode
- ret
-
-caps: testb $0x80,mode
- jne 1f
- xorb $4,leds
- xorb $0x40,mode
- orb $0x80,mode
-set_leds:
- call kb_wait
- movb $0xed,%al /* set leds command */
- outb %al,$0x60
- call kb_wait
- movb leds,%al
- outb %al,$0x60
- ret
-uncaps: andb $0x7f,mode
- ret
-scroll:
- xorb $1,leds
- jmp set_leds
-num: xorb $2,leds
- jmp set_leds
-
-/*
- * curosr-key/numeric keypad cursor keys are handled here.
- * checking for numeric keypad etc.
- */
-cursor:
- subb $0x47,%al
- jb 1f
- cmpb $12,%al
- ja 1f
- jne cur2 /* check for ctrl-alt-del */
- testb $0x0c,mode
- je cur2
- testb $0x30,mode
- jne reboot
-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 */
- jne cur
- xorl %ebx,%ebx
- movb num_table(%eax),%al
- jmp put_queue
-1: ret
-
-cur: movb cur_table(%eax),%al
- cmpb $'9,%al
- ja ok_cur
- movb $'~,%ah
-ok_cur: shll $16,%eax
- movw $0x5b1b,%ax
- xorl %ebx,%ebx
- jmp put_queue
-
-num_table:
- .ascii "789 456 1230,"
-cur_table:
- .ascii "HA5 DGC YB623"
-
-/*
- * this routine handles function keys
- */
-func:
- pushl %eax
- pushl %ecx
- pushl %edx
- call _show_stat
- popl %edx
- popl %ecx
- popl %eax
- subb $0x3B,%al
- jb end_func
- cmpb $9,%al
- jbe ok_func
- subb $18,%al
- cmpb $10,%al
- jb end_func
- cmpb $11,%al
- ja end_func
-ok_func:
- cmpl $4,%ecx /* check that there is enough room */
- jl end_func
- movl func_table(,%eax,4),%eax
- xorl %ebx,%ebx
- jmp put_queue
-end_func:
- ret
-
-/*
- * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc.
- */
-func_table:
- .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b
- .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b
- .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b
-
-#if defined(KBD_FINNISH)
-key_map:
- .byte 0,27
- .ascii "1234567890+'"
- .byte 127,9
- .ascii "qwertyuiop}"
- .byte 0,13,0
- .ascii "asdfghjkl|{"
- .byte 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 13,0
- .ascii "ASDFGHJKL\\["
- .byte 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 */
- .byte '|
- .fill 10,1,0
-
-#elif defined(KBD_US)
-
-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 */
- .byte '<
- .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
-
-#else
-#error "KBD-type not defined"
-#endif
-/*
- * do_self handles "normal" keys, ie keys that don't change meaning
- * and which have just one character returns.
- */
-do_self:
- lea alt_map,%ebx
- testb $0x20,mode /* alt-gr */
- jne 1f
- lea shift_map,%ebx
- testb $0x03,mode
- jne 1f
- lea key_map,%ebx
-1: movb (%ebx,%eax),%al
- orb %al,%al
- je none
- testb $0x4c,mode /* ctrl or caps */
- je 2f
- cmpb $'a,%al
- jb 2f
- cmpb $'},%al
- ja 2f
- subb $32,%al
-2: testb $0x0c,mode /* ctrl */
- je 3f
- cmpb $64,%al
- jb 3f
- cmpb $64+32,%al
- jae 3f
- subb $64,%al
-3: testb $0x10,mode /* left alt */
- je 4f
- orb $0x80,%al
-4: andl $0xff,%eax
- xorl %ebx,%ebx
- call put_queue
-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 was pushed.
- */
-minus: cmpb $1,e0
- jne do_self
- movl $'/,%eax
- xorl %ebx,%ebx
- jmp put_queue
-
-/*
- * This table decides which routine to call when a scan-code has been
- * gotten. Most routines just call do_self, or none, depending if
- * they are make or break.
- */
-key_table:
- .long none,do_self,do_self,do_self /* 00-03 s0 esc 1 2 */
- .long do_self,do_self,do_self,do_self /* 04-07 3 4 5 6 */
- .long do_self,do_self,do_self,do_self /* 08-0B 7 8 9 0 */
- .long do_self,do_self,do_self,do_self /* 0C-0F + ' bs tab */
- .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 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 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,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 ? ? ? */
- .long none,none,none,none /* 5C-5F ? ? ? ? */
- .long none,none,none,none /* 60-63 ? ? ? ? */
- .long none,none,none,none /* 64-67 ? ? ? ? */
- .long none,none,none,none /* 68-6B ? ? ? ? */
- .long none,none,none,none /* 6C-6F ? ? ? ? */
- .long none,none,none,none /* 70-73 ? ? ? ? */
- .long none,none,none,none /* 74-77 ? ? ? ? */
- .long none,none,none,none /* 78-7B ? ? ? ? */
- .long none,none,none,none /* 7C-7F ? ? ? ? */
- .long none,none,none,none /* 80-83 ? br br br */
- .long none,none,none,none /* 84-87 br br br br */
- .long none,none,none,none /* 88-8B br br br br */
- .long none,none,none,none /* 8C-8F br br br br */
- .long none,none,none,none /* 90-93 br br br br */
- .long none,none,none,none /* 94-97 br br br br */
- .long none,none,none,none /* 98-9B br br br br */
- .long none,unctrl,none,none /* 9C-9F br unctrl br br */
- .long none,none,none,none /* A0-A3 br br br br */
- .long none,none,none,none /* A4-A7 br br br br */
- .long none,none,unlshift,none /* A8-AB br br unlshift br */
- .long none,none,none,none /* AC-AF br br br br */
- .long none,none,none,none /* B0-B3 br br br br */
- .long none,none,unrshift,none /* B4-B7 br br unrshift br */
- .long unalt,none,uncaps,none /* B8-BB unalt br uncaps br */
- .long none,none,none,none /* BC-BF br br br br */
- .long none,none,none,none /* C0-C3 br br br br */
- .long none,none,none,none /* C4-C7 br br br br */
- .long none,none,none,none /* C8-CB br br br br */
- .long none,none,none,none /* CC-CF br br br br */
- .long none,none,none,none /* D0-D3 br br br br */
- .long none,none,none,none /* D4-D7 br br br br */
- .long none,none,none,none /* D8-DB br ? ? ? */
- .long none,none,none,none /* DC-DF ? ? ? ? */
- .long none,none,none,none /* E0-E3 e0 e1 ? ? */
- .long none,none,none,none /* E4-E7 ? ? ? ? */
- .long none,none,none,none /* E8-EB ? ? ? ? */
- .long none,none,none,none /* EC-EF ? ? ? ? */
- .long none,none,none,none /* F0-F3 ? ? ? ? */
- .long none,none,none,none /* F4-F7 ? ? ? ? */
- .long none,none,none,none /* F8-FB ? ? ? ? */
- .long none,none,none,none /* FC-FF ? ? ? ? */
-
-/*
- * 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
-1: inb $0x64,%al
- testb $0x02,%al
- jne 1b
- popl %eax
- ret
-/*
- * This routine reboots the machine by asking the keyboard
- * controller to pulse the reset-line low.
- */
-reboot:
- call kb_wait
- movw $0x1234,0x472 /* don't do memory check */
- movb $0xfc,%al /* pulse reset and A20 low */
- outb %al,$0x64
-die: jmp die
-@
* 'void con_write(struct tty_queue * queue)'
* Hopefully this will be a rather complete VT102 implementation.
*
+ * Beeping thanks to John T Kohl.
*/
/*
* interrupt, as we use trap-gates. Hopefully all is well.
*/
+/*
+ * Code to check for different video-cards mostly by Galen Hunt,
+ * <g-hunt@ee.utah.edu>
+ */
+
#include <linux/sched.h>
#include <linux/tty.h>
#include <asm/io.h>
/*
* These are set up by the setup-routine at boot-time:
*/
-#define ORIG_X (*(unsigned char *)0x90000)
-#define ORIG_Y (*(unsigned char *)0x90001)
-#define SCREEN_START 0xb8000
-#define SCREEN_END 0xc0000
-#define LINES 25
-#define COLUMNS 80
+#define ORIG_X (*(unsigned char *)0x90000)
+#define ORIG_Y (*(unsigned char *)0x90001)
+#define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004)
+#define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff)
+#define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8)
+#define ORIG_VIDEO_LINES (25)
+#define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008)
+#define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a)
+#define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c)
+
+#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */
+#define VIDEO_TYPE_CGA 0x11 /* CGA Display */
+#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */
+#define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */
+
#define NPAR 16
extern void keyboard_interrupt(void);
-static unsigned long origin=SCREEN_START;
-static unsigned long scr_end=SCREEN_START+LINES*COLUMNS*2;
-static unsigned long pos;
-static unsigned long x,y;
-static unsigned long top=0,bottom=LINES;
-static unsigned long lines=LINES,columns=COLUMNS;
-static unsigned long state=0;
-static unsigned long npar,par[NPAR];
-static unsigned long ques=0;
-static unsigned char attr=0x07;
+static unsigned char video_type; /* Type of display being used */
+static unsigned long video_num_columns; /* Number of text columns */
+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 long video_mem_start; /* Start of video RAM */
+static unsigned long video_mem_end; /* End of video RAM (sort of) */
+static unsigned short video_port_reg; /* Video register select port */
+static unsigned short video_port_val; /* Video register value port */
+static unsigned short video_erase_char; /* Char+Attrib to erase with */
+
+static unsigned long origin; /* Used for EGA/VGA fast scroll */
+static unsigned long scr_end; /* Used for EGA/VGA fast scroll */
+static unsigned long pos;
+static unsigned long x,y;
+static unsigned long top,bottom;
+static unsigned long state=0;
+static unsigned long npar,par[NPAR];
+static unsigned long ques=0;
+static unsigned char attr=0x07;
+
+static void sysbeep(void);
/*
* this is what the terminal answers to a ESC-Z or csi0c
*/
#define RESPONSE "\033[?1;2c"
-/* NOTE! gotoxy thinks x==columns is ok */
+/* NOTE! gotoxy thinks x==video_num_columns is ok */
static inline void gotoxy(unsigned int new_x,unsigned int new_y)
{
- if (new_x > columns || new_y >= lines)
+ if (new_x > video_num_columns || new_y >= video_num_lines)
return;
x=new_x;
y=new_y;
- pos=origin+((y*columns+x)<<1);
+ pos=origin + y*video_size_row + (x<<1);
}
static inline void set_origin(void)
{
cli();
- outb_p(12,0x3d4);
- outb_p(0xff&((origin-SCREEN_START)>>9),0x3d5);
- outb_p(13,0x3d4);
- outb_p(0xff&((origin-SCREEN_START)>>1),0x3d5);
+ outb_p(12, video_port_reg);
+ outb_p(0xff&((origin-video_mem_start)>>9), video_port_val);
+ outb_p(13, video_port_reg);
+ outb_p(0xff&((origin-video_mem_start)>>1), video_port_val);
sti();
}
static void scrup(void)
{
- if (!top && bottom==lines) {
- origin += columns<<1;
- pos += columns<<1;
- scr_end += columns<<1;
- if (scr_end>SCREEN_END) {
+ if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM)
+ {
+ if (!top && bottom == video_num_lines) {
+ origin += video_size_row;
+ pos += video_size_row;
+ scr_end += video_size_row;
+ if (scr_end > video_mem_end) {
+ __asm__("cld\n\t"
+ "rep\n\t"
+ "movsl\n\t"
+ "movl _video_num_columns,%1\n\t"
+ "rep\n\t"
+ "stosw"
+ ::"a" (video_erase_char),
+ "c" ((video_num_lines-1)*video_num_columns>>1),
+ "D" (video_mem_start),
+ "S" (origin)
+ :"cx","di","si");
+ scr_end -= origin-video_mem_start;
+ pos -= origin-video_mem_start;
+ origin = video_mem_start;
+ } else {
+ __asm__("cld\n\t"
+ "rep\n\t"
+ "stosw"
+ ::"a" (video_erase_char),
+ "c" (video_num_columns),
+ "D" (scr_end-video_size_row)
+ :"cx","di");
+ }
+ set_origin();
+ } else {
__asm__("cld\n\t"
"rep\n\t"
"movsl\n\t"
- "movl _columns,%1\n\t"
+ "movl _video_num_columns,%%ecx\n\t"
"rep\n\t"
"stosw"
- ::"a" (0x0720),
- "c" ((lines-1)*columns>>1),
- "D" (SCREEN_START),
- "S" (origin)
+ ::"a" (video_erase_char),
+ "c" ((bottom-top-1)*video_num_columns>>1),
+ "D" (origin+video_size_row*top),
+ "S" (origin+video_size_row*(top+1))
:"cx","di","si");
- scr_end -= origin-SCREEN_START;
- pos -= origin-SCREEN_START;
- origin = SCREEN_START;
- } else {
- __asm__("cld\n\t"
- "rep\n\t"
- "stosl"
- ::"a" (0x07200720),
- "c" (columns>>1),
- "D" (scr_end-(columns<<1))
- :"cx","di");
}
- set_origin();
- } else {
+ }
+ else /* Not EGA/VGA */
+ {
__asm__("cld\n\t"
"rep\n\t"
"movsl\n\t"
- "movl _columns,%%ecx\n\t"
+ "movl _video_num_columns,%%ecx\n\t"
"rep\n\t"
"stosw"
- ::"a" (0x0720),
- "c" ((bottom-top-1)*columns>>1),
- "D" (origin+(columns<<1)*top),
- "S" (origin+(columns<<1)*(top+1))
+ ::"a" (video_erase_char),
+ "c" ((bottom-top-1)*video_num_columns>>1),
+ "D" (origin+video_size_row*top),
+ "S" (origin+video_size_row*(top+1))
:"cx","di","si");
}
}
static void scrdown(void)
{
- __asm__("std\n\t"
- "rep\n\t"
- "movsl\n\t"
- "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
- "movl _columns,%%ecx\n\t"
- "rep\n\t"
- "stosw"
- ::"a" (0x0720),
- "c" ((bottom-top-1)*columns>>1),
- "D" (origin+(columns<<1)*bottom-4),
- "S" (origin+(columns<<1)*(bottom-1)-4)
- :"ax","cx","di","si");
+ 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");
+ }
+ 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");
+ }
}
static void lf(void)
{
if (y+1<bottom) {
y++;
- pos += columns<<1;
+ pos += video_size_row;
return;
}
scrup();
{
if (y>top) {
y--;
- pos -= columns<<1;
+ pos -= video_size_row;
return;
}
scrdown();
if (x) {
pos -= 2;
x--;
- *(unsigned short *)pos = 0x0720;
+ *(unsigned short *)pos = video_erase_char;
}
}
start = origin;
break;
case 2: /* erase whole display */
- count = columns*lines;
+ count = video_num_columns * video_num_lines;
start = origin;
break;
default:
"rep\n\t"
"stosw\n\t"
::"c" (count),
- "D" (start),"a" (0x0720)
+ "D" (start),"a" (video_erase_char)
:"cx","di");
}
switch (par) {
case 0: /* erase from cursor to end of line */
- if (x>=columns)
+ if (x>=video_num_columns)
return;
- count = columns-x;
+ count = video_num_columns-x;
start = pos;
break;
case 1: /* erase from start of line to cursor */
start = pos - (x<<1);
- count = (x<columns)?x:columns;
+ count = (x<video_num_columns)?x:video_num_columns;
break;
case 2: /* erase whole line */
start = pos - (x<<1);
- count = columns;
+ count = video_num_columns;
break;
default:
return;
"rep\n\t"
"stosw\n\t"
::"c" (count),
- "D" (start),"a" (0x0720)
+ "D" (start),"a" (video_erase_char)
:"cx","di");
}
static inline void set_cursor(void)
{
cli();
- outb_p(14,0x3d4);
- outb_p(0xff&((pos-SCREEN_START)>>9),0x3d5);
- outb_p(15,0x3d4);
- outb_p(0xff&((pos-SCREEN_START)>>1),0x3d5);
+ outb_p(14, video_port_reg);
+ outb_p(0xff&((pos-video_mem_start)>>9), video_port_val);
+ outb_p(15, video_port_reg);
+ outb_p(0xff&((pos-video_mem_start)>>1), video_port_val);
sti();
}
static void insert_char(void)
{
int i=x;
- unsigned short tmp,old=0x0720;
+ unsigned short tmp, old = video_erase_char;
unsigned short * p = (unsigned short *) pos;
- while (i++<columns) {
+ while (i++<video_num_columns) {
tmp=*p;
*p=old;
old=tmp;
oldtop=top;
oldbottom=bottom;
top=y;
- bottom=lines;
+ bottom = video_num_lines;
scrdown();
top=oldtop;
bottom=oldbottom;
int i;
unsigned short * p = (unsigned short *) pos;
- if (x>=columns)
+ if (x>=video_num_columns)
return;
i = x;
- while (++i < columns) {
+ while (++i < video_num_columns) {
*p = *(p+1);
p++;
}
- *p=0x0720;
+ *p = video_erase_char;
}
static void delete_line(void)
oldtop=top;
oldbottom=bottom;
top=y;
- bottom=lines;
+ bottom = video_num_lines;
scrup();
top=oldtop;
bottom=oldbottom;
static void csi_at(unsigned int nr)
{
- if (nr>columns)
- nr=columns;
+ if (nr > video_num_columns)
+ nr = video_num_columns;
else if (!nr)
- nr=1;
+ nr = 1;
while (nr--)
insert_char();
}
static void csi_L(unsigned int nr)
{
- if (nr>lines)
- nr=lines;
+ if (nr > video_num_lines)
+ nr = video_num_lines;
else if (!nr)
- nr=1;
+ nr = 1;
while (nr--)
insert_line();
}
static void csi_P(unsigned int nr)
{
- if (nr>columns)
- nr=columns;
+ if (nr > video_num_columns)
+ nr = video_num_columns;
else if (!nr)
- nr=1;
+ nr = 1;
while (nr--)
delete_char();
}
static void csi_M(unsigned int nr)
{
- if (nr>lines)
- nr=lines;
+ if (nr > video_num_lines)
+ nr = video_num_lines;
else if (!nr)
nr=1;
while (nr--)
switch(state) {
case 0:
if (c>31 && c<127) {
- if (x>=columns) {
- x -= columns;
- pos -= columns<<1;
+ if (x>=video_num_columns) {
+ x -= video_num_columns;
+ pos -= video_size_row;
lf();
}
__asm__("movb _attr,%%ah\n\t"
c=8-(x&7);
x += c;
pos += c<<1;
- if (x>columns) {
- x -= columns;
- pos -= columns<<1;
+ if (x>video_num_columns) {
+ x -= video_num_columns;
+ pos -= video_size_row;
lf();
}
c=9;
- }
+ } else if (c==7)
+ sysbeep();
break;
case 1:
state=0;
break;
case 'r':
if (par[0]) par[0]--;
- if (!par[1]) par[1]=lines;
+ if (!par[1]) par[1] = video_num_lines;
if (par[0] < par[1] &&
- par[1] <= lines) {
+ par[1] <= video_num_lines) {
top=par[0];
bottom=par[1];
}
* This routine initalizes console interrupts, and does nothing
* else. If you want the screen to clear, call tty_write with
* the appropriate escape-sequece.
+ *
+ * Reads the information preserved by setup.s to determine the current display
+ * type and sets everything accordingly.
*/
void con_init(void)
{
register unsigned char a;
+ char *display_desc = "????";
+ char *display_ptr;
+
+ video_num_columns = ORIG_VIDEO_COLS;
+ video_size_row = video_num_columns * 2;
+ video_num_lines = ORIG_VIDEO_LINES;
+ video_page = ORIG_VIDEO_PAGE;
+ video_erase_char = 0x0720;
+
+ if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
+ {
+ video_mem_start = 0xb0000;
+ video_port_reg = 0x3b4;
+ video_port_val = 0x3b5;
+ if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
+ {
+ video_type = VIDEO_TYPE_EGAM;
+ video_mem_end = 0xb8000;
+ display_desc = "EGAm";
+ }
+ else
+ {
+ video_type = VIDEO_TYPE_MDA;
+ video_mem_end = 0xb2000;
+ display_desc = "*MDA";
+ }
+ }
+ else /* If not, it is color. */
+ {
+ video_mem_start = 0xb8000;
+ video_port_reg = 0x3d4;
+ video_port_val = 0x3d5;
+ if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
+ {
+ video_type = VIDEO_TYPE_EGAC;
+ video_mem_end = 0xbc000;
+ display_desc = "EGAc";
+ }
+ else
+ {
+ video_type = VIDEO_TYPE_CGA;
+ video_mem_end = 0xba000;
+ display_desc = "*CGA";
+ }
+ }
+
+ /* Let the user known what kind of display driver we are using */
+
+ display_ptr = ((char *)video_mem_start) + video_size_row - 8;
+ while (*display_desc)
+ {
+ *display_ptr++ = *display_desc++;
+ display_ptr++;
+ }
+
+ /* Initialize the variables used for scrolling (mostly EGA/VGA) */
+
+ origin = video_mem_start;
+ scr_end = video_mem_start + video_num_lines * video_size_row;
+ top = 0;
+ bottom = video_num_lines;
gotoxy(ORIG_X,ORIG_Y);
set_trap_gate(0x21,&keyboard_interrupt);
outb_p(a|0x80,0x61);
outb(a,0x61);
}
+/* from bsd-net-2: */
+
+void sysbeepstop(void)
+{
+ /* disable counter 2 */
+ outb(inb_p(0x61)&0xFC, 0x61);
+}
+
+int beepcount = 0;
+
+static void sysbeep(void)
+{
+ /* enable counter 2 */
+ outb_p(inb_p(0x61)|3, 0x61);
+ /* set command for counter 2, 2 byte write */
+ outb_p(0xB6, 0x43);
+ /* send 0x637 for 750 HZ */
+ outb_p(0x37, 0x42);
+ outb(0x06, 0x42);
+ /* 1/8 second */
+ beepcount = HZ/8;
+}
/*
* Thanks to Alfred Leung for US keyboard patches
+ * Wolfgang Thiel for German keyboard patches
+ * Marc Corsini for the French keyboard
*/
#include <linux/config.h>
mode: .byte 0 /* caps, alt, ctrl and shift mode */
leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */
e0: .byte 0
-flags: .byte 0 /* 0x1 - map caps lock to ctrl */
/*
* con_int is the real interrupt routine that reads the
andb $0xfd,mode
ret
-caps: testb $0x1,flags
- je ctrl
- testb $0x80,mode
+caps: testb $0x80,mode
jne 1f
xorb $4,leds
xorb $0x40,mode
movb leds,%al
outb %al,$0x60
ret
-uncaps: testb $0x1,flags
- je unctrl
- andb $0x7f,mode
+uncaps: andb $0x7f,mode
ret
scroll:
xorb $1,leds
xorl %ebx,%ebx
jmp put_queue
+#if defined(KBD_FR)
+num_table:
+ .ascii "789 456 1230."
+#else
num_table:
.ascii "789 456 1230,"
+#endif
cur_table:
.ascii "HA5 DGC YB623"
.byte '|
.fill 10,1,0
+#elif defined(KBD_GR)
+
+key_map:
+ .byte 0,27
+ .ascii "1234567890\\'"
+ .byte 127,9
+ .ascii "qwertzuiop@+"
+ .byte 13,0
+ .ascii "asdfghjkl[]^"
+ .byte 0,'#
+ .ascii "yxcvbnm,.-"
+ .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 "QWERTZUIOP\\*"
+ .byte 13,0
+ .ascii "ASDFGHJKL{}~"
+ .byte 0,''
+ .ascii "YXCVBNM;:_"
+ .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
+ .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_FR)
+
+key_map:
+ .byte 0,27
+ .ascii "&{\"'(-}_/@)="
+ .byte 127,9
+ .ascii "azertyuiop^$"
+ .byte 13,0
+ .ascii "qsdfghjklm|"
+ .byte '`,0,42 /* coin sup gauche, don't know, [*|mu] */
+ .ascii "wxcvbn,;:!"
+ .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 "1234567890]+"
+ .byte 127,9
+ .ascii "AZERTYUIOP<>"
+ .byte 13,0
+ .ascii "QSDFGHJKLM%"
+ .byte '~,0,'#
+ .ascii "WXCVBN?./\\"
+ .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~#{[|`\\^@]}"
+ .byte 0,0
+ .byte '@,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
+
#else
#error "KBD-type not defined"
#endif
movl $'/,%eax
xorl %ebx,%ebx
jmp put_queue
-/*
- * do_space handles ctrl-space as an ASCII NUL. Old habits die hard.
- */
-do_space:
- testb $0x04,mode /* ctrl */
- je do_self
- testb $0x03,mode /* shift */
- jne 1f
- xorb $0x01, flags /* toggle caps lock flag */
- ret
-1f: movl $0,%al /* ASCII NUL */
- xorl %ebx,%ebx
- jmp put_queue
/*
* This table decides which routine to call when a scan-code has been
.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 alt,do_space,caps,func /* 38-3B alt sp caps f1 */
+ .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 */
+++ /dev/null
-/*
- * linux/kernel/keyboard.S
- *
- * (C) 1991 Linus Torvalds
- */
-
-/*
- * Thanks to Alfred Leung for US keyboard patches
- */
-
-#include <linux/config.h>
-
-.text
-.globl _keyboard_interrupt
-
-/*
- * these are for the keyboard read functions
- */
-size = 1024 /* must be a power of two ! And MUST be the same
- as in tty_io.c !!!! */
-head = 4
-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) */
-e0: .byte 0
-
-/*
- * con_int is the real interrupt routine that reads the
- * keyboard scan-code and converts it into the appropriate
- * ascii character(s).
- */
-_keyboard_interrupt:
- pushl %eax
- pushl %ebx
- pushl %ecx
- pushl %edx
- push %ds
- push %es
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- xorl %al,%al /* %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
- jmp 1f
-1: jmp 1f
-1: orb $0x80,%al
- jmp 1f
-1: jmp 1f
-1: outb %al,$0x61
- jmp 1f
-1: jmp 1f
-1: andb $0x7F,%al
- outb %al,$0x61
- movb $0x20,%al
- outb %al,$0x20
- pushl $0
- call _do_tty_interrupt
- addl $4,%esp
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- 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
- * %ebx:%eax. (%edx is high). The bytes are written in the
- * order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero.
- */
-put_queue:
- pushl %ecx
- pushl %edx
- movl _table_list,%edx # read-queue for console
- movl head(%edx),%ecx
-1: movb %al,buf(%edx,%ecx)
- incl %ecx
- andl $size-1,%ecx
- cmpl tail(%edx),%ecx # buffer full - discard everything
- je 3f
- shrdl $8,%ebx,%eax
- je 2f
- shrl $8,%ebx
- jmp 1b
-2: movl %ecx,head(%edx)
- movl proc_list(%edx),%ecx
- testl %ecx,%ecx
- je 3f
- movl $0,(%ecx)
-3: popl %edx
- popl %ecx
- ret
-
-ctrl: movb $0x04,%al
- jmp 1f
-alt: movb $0x10,%al
-1: cmpb $0,e0
- je 2f
- addb %al,%al
-2: orb %al,mode
- ret
-unctrl: movb $0x04,%al
- jmp 1f
-unalt: movb $0x10,%al
-1: cmpb $0,e0
- je 2f
- addb %al,%al
-2: notb %al
- andb %al,mode
- ret
-
-lshift:
- orb $0x01,mode
- ret
-unlshift:
- andb $0xfe,mode
- ret
-rshift:
- orb $0x02,mode
- ret
-unrshift:
- andb $0xfd,mode
- ret
-
-caps: testb $0x80,mode
- jne 1f
- xorb $4,leds
- xorb $0x40,mode
- orb $0x80,mode
-set_leds:
- call kb_wait
- movb $0xed,%al /* set leds command */
- outb %al,$0x60
- call kb_wait
- movb leds,%al
- outb %al,$0x60
- ret
-uncaps: andb $0x7f,mode
- ret
-scroll:
- xorb $1,leds
- jmp set_leds
-num: xorb $2,leds
- jmp set_leds
-
-/*
- * curosr-key/numeric keypad cursor keys are handled here.
- * checking for numeric keypad etc.
- */
-cursor:
- subb $0x47,%al
- jb 1f
- cmpb $12,%al
- ja 1f
- jne cur2 /* check for ctrl-alt-del */
- testb $0x0c,mode
- je cur2
- testb $0x30,mode
- jne reboot
-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 */
- jne cur
- xorl %ebx,%ebx
- movb num_table(%eax),%al
- jmp put_queue
-1: ret
-
-cur: movb cur_table(%eax),%al
- cmpb $'9,%al
- ja ok_cur
- movb $'~,%ah
-ok_cur: shll $16,%eax
- movw $0x5b1b,%ax
- xorl %ebx,%ebx
- jmp put_queue
-
-num_table:
- .ascii "789 456 1230,"
-cur_table:
- .ascii "HA5 DGC YB623"
-
-/*
- * this routine handles function keys
- */
-func:
- pushl %eax
- pushl %ecx
- pushl %edx
- call _show_stat
- popl %edx
- popl %ecx
- popl %eax
- subb $0x3B,%al
- jb end_func
- cmpb $9,%al
- jbe ok_func
- subb $18,%al
- cmpb $10,%al
- jb end_func
- cmpb $11,%al
- ja end_func
-ok_func:
- cmpl $4,%ecx /* check that there is enough room */
- jl end_func
- movl func_table(,%eax,4),%eax
- xorl %ebx,%ebx
- jmp put_queue
-end_func:
- ret
-
-/*
- * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc.
- */
-func_table:
- .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b
- .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b
- .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b
-
-#if defined(KBD_FINNISH)
-key_map:
- .byte 0,27
- .ascii "1234567890+'"
- .byte 127,9
- .ascii "qwertyuiop}"
- .byte 0,13,0
- .ascii "asdfghjkl|{"
- .byte 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 13,0
- .ascii "ASDFGHJKL\\["
- .byte 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 */
- .byte '|
- .fill 10,1,0
-
-#elif defined(KBD_US)
-
-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 */
- .byte '<
- .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
-
-#else
-#error "KBD-type not defined"
-#endif
-/*
- * do_self handles "normal" keys, ie keys that don't change meaning
- * and which have just one character returns.
- */
-do_self:
- lea alt_map,%ebx
- testb $0x20,mode /* alt-gr */
- jne 1f
- lea shift_map,%ebx
- testb $0x03,mode
- jne 1f
- lea key_map,%ebx
-1: movb (%ebx,%eax),%al
- orb %al,%al
- je none
- testb $0x4c,mode /* ctrl or caps */
- je 2f
- cmpb $'a,%al
- jb 2f
- cmpb $'},%al
- ja 2f
- subb $32,%al
-2: testb $0x0c,mode /* ctrl */
- je 3f
- cmpb $64,%al
- jb 3f
- cmpb $64+32,%al
- jae 3f
- subb $64,%al
-3: testb $0x10,mode /* left alt */
- je 4f
- orb $0x80,%al
-4: andl $0xff,%eax
- xorl %ebx,%ebx
- call put_queue
-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 was pushed.
- */
-minus: cmpb $1,e0
- jne do_self
- movl $'/,%eax
- xorl %ebx,%ebx
- jmp put_queue
-/*
- * do_space handles ctrl-space as an ASCII NUL. Old habits die hard.
- */
-do_space:
- testb $0x04,mode /* ctrl */
- je do_self
- movl $0,%al /* ASCII NUL */
- xorl %ebx,%ebx
- jmp put_queue
-
-/*
- * This table decides which routine to call when a scan-code has been
- * gotten. Most routines just call do_self, or none, depending if
- * they are make or break.
- */
-key_table:
- .long none,do_self,do_self,do_self /* 00-03 s0 esc 1 2 */
- .long do_self,do_self,do_self,do_self /* 04-07 3 4 5 6 */
- .long do_self,do_self,do_self,do_self /* 08-0B 7 8 9 0 */
- .long do_self,do_self,do_self,do_self /* 0C-0F + ' bs tab */
- .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 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 alt,do_space,ctrl,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,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 ? ? ? */
- .long none,none,none,none /* 5C-5F ? ? ? ? */
- .long none,none,none,none /* 60-63 ? ? ? ? */
- .long none,none,none,none /* 64-67 ? ? ? ? */
- .long none,none,none,none /* 68-6B ? ? ? ? */
- .long none,none,none,none /* 6C-6F ? ? ? ? */
- .long none,none,none,none /* 70-73 ? ? ? ? */
- .long none,none,none,none /* 74-77 ? ? ? ? */
- .long none,none,none,none /* 78-7B ? ? ? ? */
- .long none,none,none,none /* 7C-7F ? ? ? ? */
- .long none,none,none,none /* 80-83 ? br br br */
- .long none,none,none,none /* 84-87 br br br br */
- .long none,none,none,none /* 88-8B br br br br */
- .long none,none,none,none /* 8C-8F br br br br */
- .long none,none,none,none /* 90-93 br br br br */
- .long none,none,none,none /* 94-97 br br br br */
- .long none,none,none,none /* 98-9B br br br br */
- .long none,unctrl,none,none /* 9C-9F br unctrl br br */
- .long none,none,none,none /* A0-A3 br br br br */
- .long none,none,none,none /* A4-A7 br br br br */
- .long none,none,unlshift,none /* A8-AB br br unlshift br */
- .long none,none,none,none /* AC-AF br br br br */
- .long none,none,none,none /* B0-B3 br br br br */
- .long none,none,unrshift,none /* B4-B7 br br unrshift br */
- .long unalt,none,unctrl,none /* B8-BB unalt br uncaps br */
- .long none,none,none,none /* BC-BF br br br br */
- .long none,none,none,none /* C0-C3 br br br br */
- .long none,none,none,none /* C4-C7 br br br br */
- .long none,none,none,none /* C8-CB br br br br */
- .long none,none,none,none /* CC-CF br br br br */
- .long none,none,none,none /* D0-D3 br br br br */
- .long none,none,none,none /* D4-D7 br br br br */
- .long none,none,none,none /* D8-DB br ? ? ? */
- .long none,none,none,none /* DC-DF ? ? ? ? */
- .long none,none,none,none /* E0-E3 e0 e1 ? ? */
- .long none,none,none,none /* E4-E7 ? ? ? ? */
- .long none,none,none,none /* E8-EB ? ? ? ? */
- .long none,none,none,none /* EC-EF ? ? ? ? */
- .long none,none,none,none /* F0-F3 ? ? ? ? */
- .long none,none,none,none /* F4-F7 ? ? ? ? */
- .long none,none,none,none /* F8-FB ? ? ? ? */
- .long none,none,none,none /* FC-FF ? ? ? ? */
-
-/*
- * 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
-1: inb $0x64,%al
- testb $0x02,%al
- jne 1b
- popl %eax
- ret
-/*
- * This routine reboots the machine by asking the keyboard
- * controller to pulse the reset-line low.
- */
-reboot:
- call kb_wait
- movw $0x1234,0x472 /* don't do memory check */
- movb $0xfc,%al /* pulse reset and A20 low */
- outb %al,$0x64
-die: jmp die
+++ /dev/null
-/*
- * linux/kernel/keyboard.S
- *
- * (C) 1991 Linus Torvalds
- */
-
-/*
- * Thanks to Alfred Leung for US keyboard patches
- */
-
-#include <linux/config.h>
-
-.text
-.globl _keyboard_interrupt
-
-/*
- * these are for the keyboard read functions
- */
-size = 1024 /* must be a power of two ! And MUST be the same
- as in tty_io.c !!!! */
-head = 4
-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) */
-e0: .byte 0
-
-/*
- * con_int is the real interrupt routine that reads the
- * keyboard scan-code and converts it into the appropriate
- * ascii character(s).
- */
-_keyboard_interrupt:
- pushl %eax
- pushl %ebx
- pushl %ecx
- pushl %edx
- push %ds
- push %es
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- xorl %al,%al /* %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
- jmp 1f
-1: jmp 1f
-1: orb $0x80,%al
- jmp 1f
-1: jmp 1f
-1: outb %al,$0x61
- jmp 1f
-1: jmp 1f
-1: andb $0x7F,%al
- outb %al,$0x61
- movb $0x20,%al
- outb %al,$0x20
- pushl $0
- call _do_tty_interrupt
- addl $4,%esp
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- 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
- * %ebx:%eax. (%edx is high). The bytes are written in the
- * order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero.
- */
-put_queue:
- pushl %ecx
- pushl %edx
- movl _table_list,%edx # read-queue for console
- movl head(%edx),%ecx
-1: movb %al,buf(%edx,%ecx)
- incl %ecx
- andl $size-1,%ecx
- cmpl tail(%edx),%ecx # buffer full - discard everything
- je 3f
- shrdl $8,%ebx,%eax
- je 2f
- shrl $8,%ebx
- jmp 1b
-2: movl %ecx,head(%edx)
- movl proc_list(%edx),%ecx
- testl %ecx,%ecx
- je 3f
- movl $0,(%ecx)
-3: popl %edx
- popl %ecx
- ret
-
-ctrl: movb $0x04,%al
- jmp 1f
-alt: movb $0x10,%al
-1: cmpb $0,e0
- je 2f
- addb %al,%al
-2: orb %al,mode
- ret
-unctrl: movb $0x04,%al
- jmp 1f
-unalt: movb $0x10,%al
-1: cmpb $0,e0
- je 2f
- addb %al,%al
-2: notb %al
- andb %al,mode
- ret
-
-lshift:
- orb $0x01,mode
- ret
-unlshift:
- andb $0xfe,mode
- ret
-rshift:
- orb $0x02,mode
- ret
-unrshift:
- andb $0xfd,mode
- ret
-
-caps: testb $0x80,mode
- jne 1f
- xorb $4,leds
- xorb $0x40,mode
- orb $0x80,mode
-set_leds:
- call kb_wait
- movb $0xed,%al /* set leds command */
- outb %al,$0x60
- call kb_wait
- movb leds,%al
- outb %al,$0x60
- ret
-uncaps: andb $0x7f,mode
- ret
-scroll:
- xorb $1,leds
- jmp set_leds
-num: xorb $2,leds
- jmp set_leds
-
-/*
- * curosr-key/numeric keypad cursor keys are handled here.
- * checking for numeric keypad etc.
- */
-cursor:
- subb $0x47,%al
- jb 1f
- cmpb $12,%al
- ja 1f
- jne cur2 /* check for ctrl-alt-del */
- testb $0x0c,mode
- je cur2
- testb $0x30,mode
- jne reboot
-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 */
- jne cur
- xorl %ebx,%ebx
- movb num_table(%eax),%al
- jmp put_queue
-1: ret
-
-cur: movb cur_table(%eax),%al
- cmpb $'9,%al
- ja ok_cur
- movb $'~,%ah
-ok_cur: shll $16,%eax
- movw $0x5b1b,%ax
- xorl %ebx,%ebx
- jmp put_queue
-
-num_table:
- .ascii "789 456 1230,"
-cur_table:
- .ascii "HA5 DGC YB623"
-
-/*
- * this routine handles function keys
- */
-func:
- pushl %eax
- pushl %ecx
- pushl %edx
- call _show_stat
- popl %edx
- popl %ecx
- popl %eax
- subb $0x3B,%al
- jb end_func
- cmpb $9,%al
- jbe ok_func
- subb $18,%al
- cmpb $10,%al
- jb end_func
- cmpb $11,%al
- ja end_func
-ok_func:
- cmpl $4,%ecx /* check that there is enough room */
- jl end_func
- movl func_table(,%eax,4),%eax
- xorl %ebx,%ebx
- jmp put_queue
-end_func:
- ret
-
-/*
- * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc.
- */
-func_table:
- .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b
- .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b
- .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b
-
-#if defined(KBD_FINNISH)
-key_map:
- .byte 0,27
- .ascii "1234567890+'"
- .byte 127,9
- .ascii "qwertyuiop}"
- .byte 0,13,0
- .ascii "asdfghjkl|{"
- .byte 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 13,0
- .ascii "ASDFGHJKL\\["
- .byte 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 */
- .byte '|
- .fill 10,1,0
-
-#elif defined(KBD_US)
-
-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 */
- .byte '<
- .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
-
-#else
-#error "KBD-type not defined"
-#endif
-/*
- * do_self handles "normal" keys, ie keys that don't change meaning
- * and which have just one character returns.
- */
-do_self:
- lea alt_map,%ebx
- testb $0x20,mode /* alt-gr */
- jne 1f
- lea shift_map,%ebx
- testb $0x03,mode
- jne 1f
- lea key_map,%ebx
-1: movb (%ebx,%eax),%al
- orb %al,%al
- je none
- testb $0x4c,mode /* ctrl or caps */
- je 2f
- cmpb $'a,%al
- jb 2f
- cmpb $'},%al
- ja 2f
- subb $32,%al
-2: testb $0x0c,mode /* ctrl */
- je 3f
- cmpb $64,%al
- jb 3f
- cmpb $64+32,%al
- jae 3f
- subb $64,%al
-3: testb $0x10,mode /* left alt */
- je 4f
- orb $0x80,%al
-4: andl $0xff,%eax
- xorl %ebx,%ebx
- call put_queue
-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 was pushed.
- */
-minus: cmpb $1,e0
- jne do_self
- movl $'/,%eax
- xorl %ebx,%ebx
- jmp put_queue
-
-/*
- * This table decides which routine to call when a scan-code has been
- * gotten. Most routines just call do_self, or none, depending if
- * they are make or break.
- */
-key_table:
- .long none,do_self,do_self,do_self /* 00-03 s0 esc 1 2 */
- .long do_self,do_self,do_self,do_self /* 04-07 3 4 5 6 */
- .long do_self,do_self,do_self,do_self /* 08-0B 7 8 9 0 */
- .long do_self,do_self,do_self,do_self /* 0C-0F + ' bs tab */
- .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 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 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,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 ? ? ? */
- .long none,none,none,none /* 5C-5F ? ? ? ? */
- .long none,none,none,none /* 60-63 ? ? ? ? */
- .long none,none,none,none /* 64-67 ? ? ? ? */
- .long none,none,none,none /* 68-6B ? ? ? ? */
- .long none,none,none,none /* 6C-6F ? ? ? ? */
- .long none,none,none,none /* 70-73 ? ? ? ? */
- .long none,none,none,none /* 74-77 ? ? ? ? */
- .long none,none,none,none /* 78-7B ? ? ? ? */
- .long none,none,none,none /* 7C-7F ? ? ? ? */
- .long none,none,none,none /* 80-83 ? br br br */
- .long none,none,none,none /* 84-87 br br br br */
- .long none,none,none,none /* 88-8B br br br br */
- .long none,none,none,none /* 8C-8F br br br br */
- .long none,none,none,none /* 90-93 br br br br */
- .long none,none,none,none /* 94-97 br br br br */
- .long none,none,none,none /* 98-9B br br br br */
- .long none,unctrl,none,none /* 9C-9F br unctrl br br */
- .long none,none,none,none /* A0-A3 br br br br */
- .long none,none,none,none /* A4-A7 br br br br */
- .long none,none,unlshift,none /* A8-AB br br unlshift br */
- .long none,none,none,none /* AC-AF br br br br */
- .long none,none,none,none /* B0-B3 br br br br */
- .long none,none,unrshift,none /* B4-B7 br br unrshift br */
- .long unalt,none,uncaps,none /* B8-BB unalt br uncaps br */
- .long none,none,none,none /* BC-BF br br br br */
- .long none,none,none,none /* C0-C3 br br br br */
- .long none,none,none,none /* C4-C7 br br br br */
- .long none,none,none,none /* C8-CB br br br br */
- .long none,none,none,none /* CC-CF br br br br */
- .long none,none,none,none /* D0-D3 br br br br */
- .long none,none,none,none /* D4-D7 br br br br */
- .long none,none,none,none /* D8-DB br ? ? ? */
- .long none,none,none,none /* DC-DF ? ? ? ? */
- .long none,none,none,none /* E0-E3 e0 e1 ? ? */
- .long none,none,none,none /* E4-E7 ? ? ? ? */
- .long none,none,none,none /* E8-EB ? ? ? ? */
- .long none,none,none,none /* EC-EF ? ? ? ? */
- .long none,none,none,none /* F0-F3 ? ? ? ? */
- .long none,none,none,none /* F4-F7 ? ? ? ? */
- .long none,none,none,none /* F8-FB ? ? ? ? */
- .long none,none,none,none /* FC-FF ? ? ? ? */
-
-/*
- * 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
-1: inb $0x64,%al
- testb $0x02,%al
- jne 1b
- popl %eax
- ret
-/*
- * This routine reboots the machine by asking the keyboard
- * controller to pulse the reset-line low.
- */
-reboot:
- call kb_wait
- movw $0x1234,0x472 /* don't do memory check */
- movb $0xfc,%al /* pulse reset and A20 low */
- outb %al,$0x64
-die: jmp die
+++ /dev/null
-/*
- * linux/kernel/keyboard.S
- *
- * (C) 1991 Linus Torvalds
- */
-
-/*
- * Thanks to Alfred Leung for US keyboard patches
- */
-
-#include <linux/config.h>
-
-.text
-.globl _keyboard_interrupt
-
-/*
- * these are for the keyboard read functions
- */
-size = 1024 /* must be a power of two ! And MUST be the same
- as in tty_io.c !!!! */
-head = 4
-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) */
-e0: .byte 0
-
-/*
- * con_int is the real interrupt routine that reads the
- * keyboard scan-code and converts it into the appropriate
- * ascii character(s).
- */
-_keyboard_interrupt:
- pushl %eax
- pushl %ebx
- pushl %ecx
- pushl %edx
- push %ds
- push %es
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- xorl %al,%al /* %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
- jmp 1f
-1: jmp 1f
-1: orb $0x80,%al
- jmp 1f
-1: jmp 1f
-1: outb %al,$0x61
- jmp 1f
-1: jmp 1f
-1: andb $0x7F,%al
- outb %al,$0x61
- movb $0x20,%al
- outb %al,$0x20
- pushl $0
- call _do_tty_interrupt
- addl $4,%esp
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- 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
- * %ebx:%eax. (%edx is high). The bytes are written in the
- * order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero.
- */
-put_queue:
- pushl %ecx
- pushl %edx
- movl _table_list,%edx # read-queue for console
- movl head(%edx),%ecx
-1: movb %al,buf(%edx,%ecx)
- incl %ecx
- andl $size-1,%ecx
- cmpl tail(%edx),%ecx # buffer full - discard everything
- je 3f
- shrdl $8,%ebx,%eax
- je 2f
- shrl $8,%ebx
- jmp 1b
-2: movl %ecx,head(%edx)
- movl proc_list(%edx),%ecx
- testl %ecx,%ecx
- je 3f
- movl $0,(%ecx)
-3: popl %edx
- popl %ecx
- ret
-
-ctrl: movb $0x04,%al
- jmp 1f
-alt: movb $0x10,%al
-1: cmpb $0,e0
- je 2f
- addb %al,%al
-2: orb %al,mode
- ret
-unctrl: movb $0x04,%al
- jmp 1f
-unalt: movb $0x10,%al
-1: cmpb $0,e0
- je 2f
- addb %al,%al
-2: notb %al
- andb %al,mode
- ret
-
-lshift:
- orb $0x01,mode
- ret
-unlshift:
- andb $0xfe,mode
- ret
-rshift:
- orb $0x02,mode
- ret
-unrshift:
- andb $0xfd,mode
- ret
-
-caps: testb $0x80,mode
- jne 1f
- xorb $4,leds
- xorb $0x40,mode
- orb $0x80,mode
-set_leds:
- call kb_wait
- movb $0xed,%al /* set leds command */
- outb %al,$0x60
- call kb_wait
- movb leds,%al
- outb %al,$0x60
- ret
-uncaps: andb $0x7f,mode
- ret
-scroll:
- xorb $1,leds
- jmp set_leds
-num: xorb $2,leds
- jmp set_leds
-
-/*
- * curosr-key/numeric keypad cursor keys are handled here.
- * checking for numeric keypad etc.
- */
-cursor:
- subb $0x47,%al
- jb 1f
- cmpb $12,%al
- ja 1f
- jne cur2 /* check for ctrl-alt-del */
- testb $0x0c,mode
- je cur2
- testb $0x30,mode
- jne reboot
-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 */
- jne cur
- xorl %ebx,%ebx
- movb num_table(%eax),%al
- jmp put_queue
-1: ret
-
-cur: movb cur_table(%eax),%al
- cmpb $'9,%al
- ja ok_cur
- movb $'~,%ah
-ok_cur: shll $16,%eax
- movw $0x5b1b,%ax
- xorl %ebx,%ebx
- jmp put_queue
-
-num_table:
- .ascii "789 456 1230,"
-cur_table:
- .ascii "HA5 DGC YB623"
-
-/*
- * this routine handles function keys
- */
-func:
- pushl %eax
- pushl %ecx
- pushl %edx
- call _show_stat
- popl %edx
- popl %ecx
- popl %eax
- subb $0x3B,%al
- jb end_func
- cmpb $9,%al
- jbe ok_func
- subb $18,%al
- cmpb $10,%al
- jb end_func
- cmpb $11,%al
- ja end_func
-ok_func:
- cmpl $4,%ecx /* check that there is enough room */
- jl end_func
- movl func_table(,%eax,4),%eax
- xorl %ebx,%ebx
- jmp put_queue
-end_func:
- ret
-
-/*
- * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc.
- */
-func_table:
- .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b
- .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b
- .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b
-
-#if defined(KBD_FINNISH)
-key_map:
- .byte 0,27
- .ascii "1234567890+'"
- .byte 127,9
- .ascii "qwertyuiop}"
- .byte 0,13,0
- .ascii "asdfghjkl|{"
- .byte 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 13,0
- .ascii "ASDFGHJKL\\["
- .byte 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 */
- .byte '|
- .fill 10,1,0
-
-#elif defined(KBD_US)
-
-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 */
- .byte '<
- .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
-
-#else
-#error "KBD-type not defined"
-#endif
-/*
- * do_self handles "normal" keys, ie keys that don't change meaning
- * and which have just one character returns.
- */
-do_self:
- lea alt_map,%ebx
- testb $0x20,mode /* alt-gr */
- jne 1f
- lea shift_map,%ebx
- testb $0x03,mode
- jne 1f
- lea key_map,%ebx
-1: movb (%ebx,%eax),%al
- orb %al,%al
- je none
- testb $0x4c,mode /* ctrl or caps */
- je 2f
- cmpb $'a,%al
- jb 2f
- cmpb $'},%al
- ja 2f
- subb $32,%al
-2: testb $0x0c,mode /* ctrl */
- je 3f
- cmpb $64,%al
- jb 3f
- cmpb $64+32,%al
- jae 3f
- subb $64,%al
-3: testb $0x10,mode /* left alt */
- je 4f
- orb $0x80,%al
-4: andl $0xff,%eax
- xorl %ebx,%ebx
- call put_queue
-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 was pushed.
- */
-minus: cmpb $1,e0
- jne do_self
- movl $'/,%eax
- xorl %ebx,%ebx
- jmp put_queue
-/*
- * do_space handles ctrl-space as an ASCII NUL. Old habits die hard.
- */
-do_space:
- testb $0x04,mode /* ctrl */
- je do_self
- movl $0,%al /* ASCII NUL */
- xorl %ebx,%ebx
- jmp put_queue
-
-/*
- * This table decides which routine to call when a scan-code has been
- * gotten. Most routines just call do_self, or none, depending if
- * they are make or break.
- */
-key_table:
- .long none,do_self,do_self,do_self /* 00-03 s0 esc 1 2 */
- .long do_self,do_self,do_self,do_self /* 04-07 3 4 5 6 */
- .long do_self,do_self,do_self,do_self /* 08-0B 7 8 9 0 */
- .long do_self,do_self,do_self,do_self /* 0C-0F + ' bs tab */
- .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 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 alt,do_space,ctrl,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,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 ? ? ? */
- .long none,none,none,none /* 5C-5F ? ? ? ? */
- .long none,none,none,none /* 60-63 ? ? ? ? */
- .long none,none,none,none /* 64-67 ? ? ? ? */
- .long none,none,none,none /* 68-6B ? ? ? ? */
- .long none,none,none,none /* 6C-6F ? ? ? ? */
- .long none,none,none,none /* 70-73 ? ? ? ? */
- .long none,none,none,none /* 74-77 ? ? ? ? */
- .long none,none,none,none /* 78-7B ? ? ? ? */
- .long none,none,none,none /* 7C-7F ? ? ? ? */
- .long none,none,none,none /* 80-83 ? br br br */
- .long none,none,none,none /* 84-87 br br br br */
- .long none,none,none,none /* 88-8B br br br br */
- .long none,none,none,none /* 8C-8F br br br br */
- .long none,none,none,none /* 90-93 br br br br */
- .long none,none,none,none /* 94-97 br br br br */
- .long none,none,none,none /* 98-9B br br br br */
- .long none,unctrl,none,none /* 9C-9F br unctrl br br */
- .long none,none,none,none /* A0-A3 br br br br */
- .long none,none,none,none /* A4-A7 br br br br */
- .long none,none,unlshift,none /* A8-AB br br unlshift br */
- .long none,none,none,none /* AC-AF br br br br */
- .long none,none,none,none /* B0-B3 br br br br */
- .long none,none,unrshift,none /* B4-B7 br br unrshift br */
- .long unalt,none,unctrl,none /* B8-BB unalt br uncaps br */
- .long none,none,none,none /* BC-BF br br br br */
- .long none,none,none,none /* C0-C3 br br br br */
- .long none,none,none,none /* C4-C7 br br br br */
- .long none,none,none,none /* C8-CB br br br br */
- .long none,none,none,none /* CC-CF br br br br */
- .long none,none,none,none /* D0-D3 br br br br */
- .long none,none,none,none /* D4-D7 br br br br */
- .long none,none,none,none /* D8-DB br ? ? ? */
- .long none,none,none,none /* DC-DF ? ? ? ? */
- .long none,none,none,none /* E0-E3 e0 e1 ? ? */
- .long none,none,none,none /* E4-E7 ? ? ? ? */
- .long none,none,none,none /* E8-EB ? ? ? ? */
- .long none,none,none,none /* EC-EF ? ? ? ? */
- .long none,none,none,none /* F0-F3 ? ? ? ? */
- .long none,none,none,none /* F4-F7 ? ? ? ? */
- .long none,none,none,none /* F8-FB ? ? ? ? */
- .long none,none,none,none /* FC-FF ? ? ? ? */
-
-/*
- * 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
-1: inb $0x64,%al
- testb $0x02,%al
- jne 1b
- popl %eax
- ret
-/*
- * This routine reboots the machine by asking the keyboard
- * controller to pulse the reset-line low.
- */
-reboot:
- call kb_wait
- movw $0x1234,0x472 /* don't do memory check */
- movb $0xfc,%al /* pulse reset and A20 low */
- outb %al,$0x64
-die: jmp die
/*
* 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
- * or rs-channels. It also implements echoing, cooked mode etc (well,
- * not currently, but ...)
+ * or rs-channels. It also implements echoing, cooked mode etc.
+ *
+ * Kill-line thanks to John T Kohl.
*/
#include <ctype.h>
#include <errno.h>
struct tty_struct tty_table[] = {
{
- {ICRNL,
+ {ICRNL, /* change incoming CR to NL */
OPOST|ONLCR, /* change outgoing NL to CRNL */
0,
- ICANON | ECHO | ECHOCTL | ECHOKE,
+ ISIG | ICANON | ECHO | ECHOCTL | ECHOKE,
0, /* console termio */
INIT_C_CC},
0, /* initial pgrp */
{0,0,0,0,""}, /* console write-queue */
{0,0,0,0,""} /* console secondary queue */
},{
- {0, /*IGNCR*/
- OPOST | ONLRET, /* change outgoing NL to CR */
+ {0, /* no translation */
+ 0, /* no translation */
B2400 | CS8,
0,
0,
{0x3f8,0,0,0,""},
{0,0,0,0,""}
},{
- {0, /*IGNCR*/
- OPOST | ONLRET, /* change outgoing NL to CR */
+ {0, /* no translation */
+ 0, /* no translation */
B2400 | CS8,
0,
0,
if (I_UCLC(tty))
c=tolower(c);
if (L_CANON(tty)) {
+ if (c==KILL_CHAR(tty)) {
+ /* deal with killing the input line */
+ while(!(EMPTY(tty->secondary) ||
+ (c=LAST(tty->secondary))==10 ||
+ c==EOF_CHAR(tty))) {
+ if (L_ECHO(tty)) {
+ if (c<32)
+ PUTCH(127,tty->write_q);
+ PUTCH(127,tty->write_q);
+ tty->write(tty);
+ }
+ DEC(tty->secondary.head);
+ }
+ continue;
+ }
if (c==ERASE_CHAR(tty)) {
if (EMPTY(tty->secondary) ||
(c=LAST(tty->secondary))==10 ||
continue;
}
}
- if (!L_ISIG(tty)) {
+ if (L_ISIG(tty)) {
if (c==INTR_CHAR(tty)) {
tty_intr(tty,INTMASK);
continue;
}
- if (c==KILL_CHAR(tty)) {
- tty_intr(tty,KILLMASK);
+ if (c==QUIT_CHAR(tty)) {
+ tty_intr(tty,QUITMASK);
continue;
}
}
if (channel>2 || nr<0) return -1;
tty = &tty_table[channel];
oldalarm = current->alarm;
- time = (unsigned) 10*tty->termios.c_cc[VTIME];
- minimum = (unsigned) tty->termios.c_cc[VMIN];
+ time = 10L*tty->termios.c_cc[VTIME];
+ minimum = tty->termios.c_cc[VMIN];
if (time && !minimum) {
minimum=1;
if (flag=(!oldalarm || time+jiffies<oldalarm))
--- /dev/null
+/*
+ * linux/kernel/chr_drv/tty_ioctl.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+#include <errno.h>
+#include <termios.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+static unsigned short quotient[] = {
+ 0, 2304, 1536, 1047, 857,
+ 768, 576, 384, 192, 96,
+ 64, 48, 24, 12, 6, 3
+};
+
+static void change_speed(struct tty_struct * tty)
+{
+ unsigned short port,quot;
+
+ if (!(port = tty->read_q.data))
+ return;
+ quot = quotient[tty->termios.c_cflag & CBAUD];
+ cli();
+ outb_p(0x80,port+3); /* set DLAB */
+ outb_p(quot & 0xff,port); /* LS of divisor */
+ outb_p(quot >> 8,port+1); /* MS of divisor */
+ outb(0x03,port+3); /* reset DLAB */
+ sti();
+}
+
+static void flush(struct tty_queue * queue)
+{
+ cli();
+ queue->head = queue->tail;
+ sti();
+}
+
+static void wait_until_sent(struct tty_struct * tty)
+{
+ /* do nothing - not implemented */
+}
+
+static void send_break(struct tty_struct * tty)
+{
+ /* do nothing - not implemented */
+}
+
+static int get_termios(struct tty_struct * tty, struct termios * termios)
+{
+ int i;
+
+ verify_area(termios, sizeof (*termios));
+ for (i=0 ; i< (sizeof (*termios)) ; i++)
+ put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios );
+ return 0;
+}
+
+static int set_termios(struct tty_struct * tty, struct termios * termios)
+{
+ int i;
+
+ for (i=0 ; i< (sizeof (*termios)) ; i++)
+ ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
+ change_speed(tty);
+ return 0;
+}
+
+static int get_termio(struct tty_struct * tty, struct termio * termio)
+{
+ int i;
+ struct termio tmp_termio;
+
+ verify_area(termio, sizeof (*termio));
+ tmp_termio.c_iflag = tty->termios.c_iflag;
+ tmp_termio.c_oflag = tty->termios.c_oflag;
+ tmp_termio.c_cflag = tty->termios.c_cflag;
+ tmp_termio.c_lflag = tty->termios.c_lflag;
+ tmp_termio.c_line = tty->termios.c_line;
+ for(i=0 ; i < NCC ; i++)
+ tmp_termio.c_cc[i] = tty->termios.c_cc[i];
+ for (i=0 ; i< (sizeof (*termio)) ; i++)
+ put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
+ return 0;
+}
+
+/*
+ * This only works as the 386 is low-byt-first
+ */
+static int set_termio(struct tty_struct * tty, struct termio * termio)
+{
+ int i;
+ struct termio tmp_termio;
+
+ for (i=0 ; i< (sizeof (*termio)) ; i++)
+ ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
+ *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag;
+ *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag;
+ *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag;
+ *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag;
+ tty->termios.c_line = tmp_termio.c_line;
+ for(i=0 ; i < NCC ; i++)
+ tty->termios.c_cc[i] = tmp_termio.c_cc[i];
+ change_speed(tty);
+ return 0;
+}
+
+int tty_ioctl(int dev, int cmd, int arg)
+{
+ struct tty_struct * tty;
+ if (MAJOR(dev) == 5) {
+ dev=current->tty;
+ if (dev<0)
+ panic("tty_ioctl: dev<0");
+ } else
+ dev=MINOR(dev);
+ tty = dev + tty_table;
+ switch (cmd) {
+ case TCGETS:
+ return get_termios(tty,(struct termios *) arg);
+ case TCSETSF:
+ flush(&tty->read_q); /* fallthrough */
+ case TCSETSW:
+ wait_until_sent(tty); /* fallthrough */
+ case TCSETS:
+ return set_termios(tty,(struct termios *) arg);
+ case TCGETA:
+ return get_termio(tty,(struct termio *) arg);
+ case TCSETAF:
+ flush(&tty->read_q); /* fallthrough */
+ case TCSETAW:
+ wait_until_sent(tty); /* fallthrough */
+ case TCSETA:
+ return set_termio(tty,(struct termio *) arg);
+ case TCSBRK:
+ if (!arg) {
+ wait_until_sent(tty);
+ send_break(tty);
+ }
+ return 0;
+ case TCXONC:
+ return -EINVAL; /* not implemented */
+ case TCFLSH:
+ if (arg==0)
+ flush(&tty->read_q);
+ else if (arg==1)
+ flush(&tty->write_q);
+ else if (arg==2) {
+ flush(&tty->read_q);
+ flush(&tty->write_q);
+ } else
+ return -EINVAL;
+ return 0;
+ case TIOCEXCL:
+ return -EINVAL; /* not implemented */
+ case TIOCNXCL:
+ return -EINVAL; /* not implemented */
+ case TIOCSCTTY:
+ return -EINVAL; /* set controlling term NI */
+ case TIOCGPGRP:
+ verify_area((void *) arg,4);
+ put_fs_long(tty->pgrp,(unsigned long *) arg);
+ return 0;
+ case TIOCSPGRP:
+ tty->pgrp=get_fs_long((unsigned long *) arg);
+ return 0;
+ case TIOCOUTQ:
+ verify_area((void *) arg,4);
+ put_fs_long(CHARS(tty->write_q),(unsigned long *) arg);
+ return 0;
+ case TIOCINQ:
+ verify_area((void *) arg,4);
+ put_fs_long(CHARS(tty->secondary),
+ (unsigned long *) arg);
+ return 0;
+ case TIOCSTI:
+ return -EINVAL; /* not implemented */
+ case TIOCGWINSZ:
+ return -EINVAL; /* not implemented */
+ case TIOCSWINSZ:
+ return -EINVAL; /* not implemented */
+ case TIOCMGET:
+ return -EINVAL; /* not implemented */
+ case TIOCMBIS:
+ return -EINVAL; /* not implemented */
+ case TIOCMBIC:
+ return -EINVAL; /* not implemented */
+ case TIOCMSET:
+ return -EINVAL; /* not implemented */
+ case TIOCGSOFTCAR:
+ return -EINVAL; /* not implemented */
+ case TIOCSSOFTCAR:
+ return -EINVAL; /* not implemented */
+ default:
+ return -EINVAL;
+ }
+}
return;
}
/* if we don't find any fathers, we just release ourselves */
+/* This is not really OK. Must change it to make father 1 */
+ printk("BAD BAD - no father found\n\r");
release(current);
}
free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
for (i=0 ; i<NR_TASKS ; i++)
- if (task[i] && task[i]->father == current->pid)
- task[i]->father = 0;
+ if (task[i] && task[i]->father == current->pid) {
+ task[i]->father = 1;
+ if (task[i]->state == TASK_ZOMBIE)
+ /* assumption task[1] is always init */
+ (void) send_sig(SIGCHLD, task[1], 1);
+ }
for (i=0 ; i<NR_OPEN ; i++)
if (current->filp[i])
sys_close(i);
current->pwd=NULL;
iput(current->root);
current->root=NULL;
+ iput(current->executable);
+ current->executable=NULL;
if (current->leader && current->tty >= 0)
tty_table[current->tty].pgrp = 0;
if (last_task_used_math == current)
int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
{
- int flag;
+ int flag, code;
struct task_struct ** p;
verify_area(stat_addr,4);
current->cutime += (*p)->utime;
current->cstime += (*p)->stime;
flag = (*p)->pid;
- put_fs_long((*p)->exit_code,stat_addr);
+ code = (*p)->exit_code;
release(*p);
+ put_fs_long(code,stat_addr);
return flag;
default:
flag=1;
+++ /dev/null
-/*
- * linux/kernel/exit.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-#include <errno.h>
-#include <signal.h>
-#include <sys/wait.h>
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/tty.h>
-#include <asm/segment.h>
-
-int sys_pause(void);
-int sys_close(int fd);
-
-void release(struct task_struct * p)
-{
- int i;
-
- if (!p)
- return;
- for (i=1 ; i<NR_TASKS ; i++)
- if (task[i]==p) {
- task[i]=NULL;
- free_page((long)p);
- schedule();
- return;
- }
- panic("trying to release non-existent task");
-}
-
-static inline void send_sig(long sig,struct task_struct * p,int priv)
-{
- if (!p || sig<1 || sig>32)
- return;
- if (priv ||
- current->uid==p->uid ||
- current->euid==p->uid ||
- current->uid==p->euid ||
- current->euid==p->euid)
- p->signal |= (1<<(sig-1));
-}
-
-static void kill_session(void)
-{
- struct task_struct **p = NR_TASKS + task;
-
- while (--p > &FIRST_TASK) {
- if (*p && (*p)->session == current->session)
- (*p)->signal |= 1<<(SIGHUP-1);
- }
-}
-
-void do_kill(long pid,long sig,int priv)
-{
- struct task_struct **p = NR_TASKS + task;
-
- if (!pid) while (--p > &FIRST_TASK) {
- if (*p && (*p)->pgrp == current->pid)
- send_sig(sig,*p,priv);
- } else if (pid>0) while (--p > &FIRST_TASK) {
- if (*p && (*p)->pid == pid)
- send_sig(sig,*p,priv);
- } else if (pid == -1) while (--p > &FIRST_TASK)
- send_sig(sig,*p,priv);
- else while (--p > &FIRST_TASK)
- if (*p && (*p)->pgrp == -pid)
- send_sig(sig,*p,priv);
-}
-
-int sys_kill(int pid,int sig)
-{
- do_kill(pid,sig,!(current->uid || current->euid));
- return 0;
-}
-
-static void tell_father(int pid)
-{
- int i;
-
- if (pid)
- for (i=0;i<NR_TASKS;i++) {
- if (!task[i])
- continue;
- if (task[i]->pid != pid)
- continue;
- task[i]->signal |= (1<<(SIGCHLD-1));
- return;
- }
-/* if we don't find any fathers, we just release ourselves */
- release(current);
-}
-
-int do_exit(long code)
-{
- int i;
-
- free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
- free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
- for (i=0 ; i<NR_TASKS ; i++)
- if (task[i] && task[i]->father == current->pid)
- task[i]->father = 0;
- for (i=0 ; i<NR_OPEN ; i++)
- if (current->filp[i])
- sys_close(i);
- iput(current->pwd);
- current->pwd=NULL;
- iput(current->root);
- current->root=NULL;
- if (current->leader && current->tty >= 0)
- tty_table[current->tty].pgrp = 0;
- if (last_task_used_math == current)
- last_task_used_math = NULL;
- if (current->leader)
- kill_session();
- current->state = TASK_ZOMBIE;
- current->exit_code = code;
- tell_father(current->father);
- schedule();
- return (-1); /* just to suppress warnings */
-}
-
-int sys_exit(int error_code)
-{
- return do_exit((error_code&0xff)<<8);
-}
-
-int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
-{
- int flag;
- struct task_struct ** p;
-
- verify_area(stat_addr,4);
-repeat:
- flag=0;
- for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
- if (!*p || *p == current)
- continue;
- if ((*p)->father != current->pid)
- continue;
- if (pid>0) {
- if ((*p)->pid != pid)
- continue;
- } else if (!pid) {
- if ((*p)->pgrp != current->pgrp)
- continue;
- } else if (pid != -1) {
- if ((*p)->pgrp != -pid)
- continue;
- }
- switch ((*p)->state) {
- case TASK_STOPPED:
- if (!(options & WUNTRACED))
- continue;
- put_fs_long(0x7f,stat_addr);
- 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);
- release(*p);
- return flag;
- default:
- flag=1;
- continue;
- }
- }
- if (flag) {
- if (options & WNOHANG)
- return 0;
- current->state=TASK_INTERRUPTIBLE;
- schedule();
- if (!(current->signal &= ~(1<<(SIGCHLD-1))))
- goto repeat;
- else
- return -EINTR;
- }
- return -ECHILD;
-}
-
-
if (data_limit < code_limit)
panic("Bad data_limit");
new_data_base = new_code_base = nr * 0x4000000;
+ p->start_code = new_code_base;
set_base(p->ldt[1],new_code_base);
set_base(p->ldt[2],new_data_base);
if (copy_page_tables(old_data_base,new_data_base,data_limit)) {
p = (struct task_struct *) get_free_page();
if (!p)
return -EAGAIN;
+ task[nr] = p;
*p = *current; /* NOTE! this doesn't copy the supervisor stack */
- p->state = TASK_RUNNING;
+ p->state = TASK_UNINTERRUPTIBLE;
p->pid = last_pid;
p->father = current->pid;
p->counter = p->priority;
p->tss.ldt = _LDT(nr);
p->tss.trace_bitmap = 0x80000000;
if (last_task_used_math == current)
- __asm__("fnsave %0"::"m" (p->tss.i387));
+ __asm__("clts ; fnsave %0"::"m" (p->tss.i387));
if (copy_mem(nr,p)) {
+ task[nr] = NULL;
free_page((long) p);
return -EAGAIN;
}
current->pwd->i_count++;
if (current->root)
current->root->i_count++;
+ if (current->executable)
+ current->executable->i_count++;
set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
- task[nr] = p; /* do this last, just in case */
+ p->state = TASK_RUNNING; /* do this last, just in case */
return last_pid;
}
+++ /dev/null
-/*
- * malloc.c --- a general purpose kernel memory allocator for Linux.
- *
- * Written by Theodore Ts'o (tytso@mit.edu), 11/29/91
- *
- * This routine is written to be as fast as possible, so that it
- * can be called from the interrupt level.
- *
- * Limitations: maximum size of memory we can allocate using this routine
- * is 4k, the size of a page in Linux.
- *
- * The general game plan is that each page (called a bucket) will only hold
- * objects of a given size. When all of the object on a page are released,
- * the page can be returned to the general free pool. When malloc() is
- * called, it looks for the smallest bucket size which will fulfill its
- * request, and allocate a piece of memory from that bucket pool.
- *
- * Each bucket has as its control block a bucket descriptor which keeps
- * track of how many objects are in use on that page, and the free list
- * for that page. Like the buckets themselves, bucket descriptors are
- * stored on pages requested from get_free_page(). However, unlike buckets,
- * pages devoted to bucket descriptor pages are never released back to the
- * system. Fortunately, a system should probably only need 1 or 2 bucket
- * descriptor pages, since a page can hold 256 bucket descriptors (which
- * corresponds to 1 megabyte worth of bucket pages.) If the kernel is using
- * that much allocated memory, it's probably doing something wrong. :-)
- *
- * Note: malloc() and free() both call get_free_page() and free_page()
- * in sections of code where interrupts are turned off, to allow
- * malloc() and free() to be safely called from an interrupt routine.
- * (We will probably need this functionality when networking code,
- * particularily things like NFS, is added to Linux.) However, this
- * presumes that get_free_page() and free_page() are interrupt-level
- * safe, which they may not be once paging is added. If this is the
- * case, we will need to modify malloc() to keep a few unused pages
- * "pre-allocated" so that it can safely draw upon those pages if
- * it is called from an interrupt routine.
- *
- * Another concern is that get_free_page() should not sleep; if it
- * does, the code is carefully ordered so as to avoid any race
- * conditions. The catch is that if malloc() is called re-entrantly,
- * there is a chance that unecessary pages will be grabbed from the
- * system. Except for the pages for the bucket descriptor page, the
- * extra pages will eventually get released back to the system, though,
- * so it isn't all that bad.
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <asm/system.h>
-
-struct bucket_desc { /* 16 bytes */
- void *page;
- struct bucket_desc *next;
- void *freeptr;
- unsigned short refcnt;
- unsigned short bucket_size;
-};
-
-struct _bucket_dir { /* 8 bytes */
- int size;
- struct bucket_desc *chain;
-};
-
-/*
- * The following is the where we store a pointer to the first bucket
- * descriptor for a given size.
- *
- * If it turns out that the Linux kernel allocates a lot of objects of a
- * specific size, then we may want to add that specific size to this list,
- * since that will allow the memory to be allocated more efficiently.
- * However, since an entire page must be dedicated to each specific size
- * on this list, some amount of temperance must be exercised here.
- *
- * Note that this list *must* be kept in order.
- */
-struct _bucket_dir bucket_dir[] = {
- { 16, (struct bucket_desc *) 0},
- { 32, (struct bucket_desc *) 0},
- { 64, (struct bucket_desc *) 0},
- { 128, (struct bucket_desc *) 0},
- { 256, (struct bucket_desc *) 0},
- { 512, (struct bucket_desc *) 0},
- { 1024, (struct bucket_desc *) 0},
- { 2048, (struct bucket_desc *) 0},
- { 4096, (struct bucket_desc *) 0},
- { 0, (struct bucket_desc *) 0}}; /* End of list marker */
-
-/*
- * This contains a linked list of free bucket descriptor blocks
- */
-struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0;
-
-/*
- * This routine initializes a bucket description page.
- */
-static inline void init_bucket_desc()
-{
- struct bucket_desc *bdesc, *first;
- int i;
-
- first = bdesc = (struct bucket_desc *) get_free_page();
- if (!bdesc)
- panic("Out of memory in init_bucket_desc()");
- for (i = PAGE_SIZE/sizeof(struct bucket_desc); i > 1; i--) {
- bdesc->next = bdesc+1;
- bdesc++;
- }
- /*
- * This is done last, to avoid race conditions in case
- * get_free_page() sleeps and this routine gets called again....
- */
- bdesc->next = free_bucket_desc;
- free_bucket_desc = first;
-}
-
-void *malloc(unsigned int len)
-{
- struct _bucket_dir *bdir;
- struct bucket_desc *bdesc;
- void *retval;
-
- /*
- * First we search the bucket_dir to find the right bucket change
- * for this request.
- */
- for (bdir = bucket_dir; bdir->size; bdir++)
- if (bdir->size >= len)
- break;
- if (!bdir->size) {
- printk("malloc called with impossibly large argument (%d)\n",
- len);
- panic("malloc: bad arg");
- }
- /*
- * Now we search for a bucket descriptor which has free space
- */
- cli(); /* Avoid race conditions */
- for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next)
- if (bdesc->freeptr)
- break;
- /*
- * If we didn't find a bucket with free space, then we'll
- * allocate a new one.
- */
- if (!bdesc) {
- char *cp;
- int i;
-
- if (!free_bucket_desc)
- init_bucket_desc();
- bdesc = free_bucket_desc;
- free_bucket_desc = bdesc->next;
- bdesc->refcnt = 0;
- bdesc->bucket_size = bdir->size;
- bdesc->page = bdesc->freeptr = (void *) cp = get_free_page();
- if (!cp)
- panic("Out of memory in kernel malloc()");
- /* Set up the chain of free objects */
- for (i=PAGE_SIZE/bdir->size; i > 1; i--) {
- *((char **) cp) = cp + bdir->size;
- cp += bdir->size;
- }
- *((char **) cp) = 0;
- bdesc->next = bdir->chain; /* OK, link it in! */
- bdir->chain = bdesc;
- }
- retval = (void *) bdesc->freeptr;
- bdesc->freeptr = *((void **) retval);
- bdesc->refcnt++;
- sti(); /* OK, we're safe again */
- return(retval);
-}
-
-/*
- * Here is the free routine. If you know the size of the object that you
- * are freeing, then free_s() will use that information to speed up the
- * search for the bucket descriptor.
- *
- * We will #define a macro so that "free(x)" is becomes "free_s(x, 0)"
- */
-void free_s(void *obj, int size)
-{
- void *page;
- struct _bucket_dir *bdir;
- struct bucket_desc *bdesc, *prev;
-
- /* Calculate what page this object lives in */
- page = (void *) ((unsigned long) obj & 0xfffff000);
- /* Now search the buckets looking for that page */
- for (bdir = bucket_dir; bdir->size; bdir++) {
- prev = 0;
- /* If size is zero then this conditional is always false */
- if (bdir->size < size)
- continue;
- for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) {
- if (bdesc->page == page)
- goto found;
- prev = bdesc;
- }
- }
- panic("Bad address passed to kernel free_s()");
-found:
- cli(); /* To avoid race conditions */
- *((void **)obj) = bdesc->freeptr;
- bdesc->freeptr = obj;
- bdesc->refcnt--;
- if (bdesc->refcnt == 0) {
- /*
- * We need to make sure that prev is still accurate. It
- * may not be, if someone rudely interrupted us....
- */
- if ((prev && (prev->next != bdesc)) ||
- (!prev && (bdir->chain != bdesc)))
- for (prev = bdir->chain; prev; prev = prev->next)
- if (prev->next == bdesc)
- break;
- if (prev)
- prev->next = bdesc->next;
- else {
- if (bdir->chain != bdesc)
- panic("malloc bucket chains corrupted");
- bdir->chain = bdesc->next;
- }
- free_page((unsigned long) bdesc->page);
- bdesc->next = free_bucket_desc;
- free_bucket_desc = bdesc;
- }
- sti();
- return;
-}
-
--- /dev/null
+#
+# Makefile for the FREAX-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
+LDFLAGS =-s -x
+CC =gcc
+CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \
+ -finline-functions -mstring-insns -nostdinc -I../../include
+CPP =gcc -E -nostdinc -I../../include
+
+.c.s:
+ $(CC) $(CFLAGS) \
+ -S -o $*.s $<
+.s.o:
+ $(AS) -c -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) \
+ -c -o $*.o $<
+
+OBJS = math_emulate.o
+
+math.a: $(OBJS)
+ $(AR) rcs math.a $(OBJS)
+ sync
+
+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 echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \
+ $(CPP) -M $$i;done) >> tmp_make
+ cp tmp_make Makefile
+
+### Dependencies:
--- /dev/null
+/*
+ * linux/kernel/math/math_emulate.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * This directory should contain the math-emulation code.
+ * Currently only results in a signal.
+ */
+
+#include <signal.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+
+void math_emulate(long edi, long esi, long ebp, long sys_call_ret,
+ long eax,long ebx,long ecx,long edx,
+ unsigned short fs,unsigned short es,unsigned short ds,
+ unsigned long eip,unsigned short cs,unsigned long eflags,
+ unsigned short ss, unsigned long esp)
+{
+ unsigned char first, second;
+
+/* 0x0007 means user code space */
+ if (cs != 0x000F) {
+ printk("math_emulate: %04x:%08x\n\r",cs,eip);
+ panic("Math emulation needed in kernel");
+ }
+ first = get_fs_byte((char *)((*&eip)++));
+ second = get_fs_byte((char *)((*&eip)++));
+ printk("%04x:%08x %02x %02x\n\r",cs,eip-2,first,second);
+ current->signal |= 1<<(SIGFPE-1);
+}
+
+void math_error(void)
+{
+ __asm__("fnclex");
+ if (last_task_used_math)
+ last_task_used_math->signal |= 1<<(SIGFPE-1);
+}
void show_task(int nr,struct task_struct * p)
{
+ int i,j = 4096-sizeof(struct task_struct);
+
printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state);
- printk("eip=%04x:%08x\n\r",p->tss.cs&0xffff,p->tss.eip);
+ i=0;
+ while (i<j && !((char *)(p+1))[i])
+ i++;
+ printk("%d (of %d) chars free in kernel stack\n\r",i,j);
}
void show_stat(void)
{
if (last_task_used_math == current)
return;
+ __asm__("fwait");
if (last_task_used_math) {
__asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
}
+ last_task_used_math=current;
if (current->used_math) {
__asm__("frstor %0"::"m" (current->tss.i387));
} else {
__asm__("fninit"::);
current->used_math=1;
}
- last_task_used_math=current;
}
/*
static int mon_timer[4]={0,0,0,0};
static int moff_timer[4]={0,0,0,0};
unsigned char current_DOR = 0x0C;
-unsigned char selected = 0;
-struct task_struct * wait_on_floppy_select = NULL;
-
-void floppy_select(unsigned int nr)
-{
- if (nr>3)
- printk("floppy_select: nr>3\n\r");
- cli();
- while (selected)
- sleep_on(&wait_on_floppy_select);
- current_DOR &= 0xFC;
- current_DOR |= nr;
- outb(current_DOR,FD_DOR);
- sti();
-}
-
-void floppy_deselect(unsigned int nr)
-{
- if (nr != (current_DOR & 3))
- printk("floppy_deselect: drive not selected\n\r");
- selected = 0;
- wake_up(&wait_on_floppy_select);
-}
int ticks_to_floppy_on(unsigned int nr)
{
- unsigned char mask = 1<<(nr+4);
+ extern unsigned char selected;
+ unsigned char mask = 0x10 << nr;
if (nr>3)
panic("floppy_on: nr>3");
moff_timer[nr]=10000; /* 100 s = very big :-) */
cli(); /* use floppy_off to turn it off */
- if (!(mask & current_DOR)) {
- current_DOR |= mask;
- if (!selected) {
- current_DOR &= 0xFC;
- current_DOR |= nr;
- }
- outb(current_DOR,FD_DOR);
- mon_timer[nr] = HZ;
+ mask |= current_DOR;
+ if (!selected) {
+ mask &= 0xFC;
+ mask |= nr;
+ }
+ if (mask != current_DOR) {
+ outb(mask,FD_DOR);
+ if ((mask ^ current_DOR) & 0xf0)
+ mon_timer[nr] = HZ/2;
+ else if (mon_timer[nr] < 2)
+ mon_timer[nr] = 2;
+ current_DOR = mask;
}
sti();
return mon_timer[nr];
void do_timer(long cpl)
{
+ extern int beepcount;
+ extern void sysbeepstop(void);
+
+ if (beepcount)
+ if (!--beepcount)
+ sysbeepstop();
+
if (cpl)
current->utime++;
else
current->stime++;
+
if (next_timer) {
next_timer->jiffies--;
while (next_timer && next_timer->jiffies <= 0) {
p->a=p->b=0;
p++;
}
+/* Clear NT, so that we won't have troubles with that later on */
+ __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
ltr(0);
lldt(0);
outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
+++ /dev/null
-/*
- * linux/kernel/sched.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-/*
- * 'sched.c' is the main kernel file. It contains scheduling primitives
- * (sleep_on, wakeup, schedule etc) as well as a number of simple system
- * call functions (type getpid(), which just extracts a field from
- * current-task
- */
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/sys.h>
-#include <linux/fdreg.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/segment.h>
-
-#include <signal.h>
-
-#define _S(nr) (1<<((nr)-1))
-#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
-
-void show_task(int nr,struct task_struct * p)
-{
- printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state);
- printk("eip=%04x:%08x\n\r",p->tss.cs&0xffff,p->tss.eip);
-}
-
-void show_stat(void)
-{
- int i;
-
- for (i=0;i<NR_TASKS;i++)
- if (task[i])
- show_task(i,task[i]);
-}
-
-#define LATCH (1193180/HZ)
-
-extern void mem_use(void);
-
-extern int timer_interrupt(void);
-extern int system_call(void);
-
-union task_union {
- struct task_struct task;
- char stack[PAGE_SIZE];
-};
-
-static union task_union init_task = {INIT_TASK,};
-
-long volatile jiffies=0;
-long startup_time=0;
-struct task_struct *current = &(init_task.task);
-struct task_struct *last_task_used_math = NULL;
-
-struct task_struct * task[NR_TASKS] = {&(init_task.task), };
-
-long user_stack [ PAGE_SIZE>>2 ] ;
-
-struct {
- long * a;
- short b;
- } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };
-/*
- * 'math_state_restore()' saves the current math information in the
- * old math state array, and gets the new ones from the current task
- */
-void math_state_restore()
-{
- if (last_task_used_math == current)
- return;
- if (last_task_used_math) {
- __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
- }
- if (current->used_math) {
- __asm__("frstor %0"::"m" (current->tss.i387));
- } else {
- __asm__("fninit"::);
- current->used_math=1;
- }
- last_task_used_math=current;
-}
-
-/*
- * '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).
- * 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
- * tasks can run. It can not be killed, and it cannot sleep. The 'state'
- * information in task[0] is never used.
- */
-void schedule(void)
-{
- int i,next,c;
- struct task_struct ** p;
-
-/* check alarm, wake up any interruptible tasks that have got a signal */
-
- for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
- if (*p) {
- if ((*p)->alarm && (*p)->alarm < jiffies) {
- (*p)->signal |= (1<<(SIGALRM-1));
- (*p)->alarm = 0;
- }
- if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
- (*p)->state==TASK_INTERRUPTIBLE)
- (*p)->state=TASK_RUNNING;
- }
-
-/* this is the scheduler proper: */
-
- while (1) {
- c = -1;
- next = 0;
- i = NR_TASKS;
- p = &task[NR_TASKS];
- while (--i) {
- if (!*--p)
- continue;
- if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
- c = (*p)->counter, next = i;
- }
- if (c) break;
- for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
- if (*p)
- (*p)->counter = ((*p)->counter >> 1) +
- (*p)->priority;
- }
- switch_to(next);
-}
-
-int sys_pause(void)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- return 0;
-}
-
-void sleep_on(struct task_struct **p)
-{
- struct task_struct *tmp;
-
- if (!p)
- return;
- if (current == &(init_task.task))
- panic("task[0] trying to sleep");
- tmp = *p;
- *p = current;
- current->state = TASK_UNINTERRUPTIBLE;
- schedule();
- if (tmp)
- tmp->state=0;
-}
-
-void interruptible_sleep_on(struct task_struct **p)
-{
- struct task_struct *tmp;
-
- if (!p)
- return;
- if (current == &(init_task.task))
- panic("task[0] trying to sleep");
- tmp=*p;
- *p=current;
-repeat: current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (*p && *p != current) {
- (**p).state=0;
- goto repeat;
- }
- *p=NULL;
- if (tmp)
- tmp->state=0;
-}
-
-void wake_up(struct task_struct **p)
-{
- if (p && *p) {
- (**p).state=0;
- *p=NULL;
- }
-}
-
-/*
- * OK, here are some floppy things that shouldn't be in the kernel
- * proper. They are here because the floppy needs a timer, and this
- * was the easiest way of doing it.
- */
-static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL};
-static int mon_timer[4]={0,0,0,0};
-static int moff_timer[4]={0,0,0,0};
-unsigned char current_DOR = 0x0C;
-unsigned char selected = 0;
-struct task_struct * wait_on_floppy_select = NULL;
-
-void floppy_select(unsigned int nr)
-{
- if (nr>3)
- printk("floppy_select: nr>3\n\r");
- cli();
- while (selected)
- sleep_on(&wait_on_floppy_select);
- current_DOR &= 0xFC;
- current_DOR |= nr;
- outb(current_DOR,FD_DOR);
- sti();
-}
-
-void floppy_deselect(unsigned int nr)
-{
- if (nr != (current_DOR & 3))
- printk("floppy_deselect: drive not selected\n\r");
- selected = 0;
- wake_up(&wait_on_floppy_select);
-}
-
-int ticks_to_floppy_on(unsigned int nr)
-{
- unsigned char mask = 1<<(nr+4);
-
- if (nr>3)
- panic("floppy_on: nr>3");
- moff_timer[nr]=10000; /* 100 s = very big :-) */
- cli(); /* use floppy_off to turn it off */
- if (!(mask & current_DOR)) {
- current_DOR |= mask;
- if (!selected) {
- current_DOR &= 0xFC;
- current_DOR |= nr;
- }
- outb(current_DOR,FD_DOR);
- mon_timer[nr] = HZ;
- }
- sti();
- return mon_timer[nr];
-}
-
-void floppy_on(unsigned int nr)
-{
- cli();
- while (ticks_to_floppy_on(nr))
- sleep_on(nr+wait_motor);
- sti();
-}
-
-void floppy_off(unsigned int nr)
-{
- moff_timer[nr]=3*HZ;
-}
-
-void do_floppy_timer(void)
-{
- int i;
- unsigned char mask = 0x10;
-
- for (i=0 ; i<4 ; i++,mask <<= 1) {
- if (!(mask & current_DOR))
- continue;
- if (mon_timer[i]) {
- if (!--mon_timer[i])
- wake_up(i+wait_motor);
- } else if (!moff_timer[i]) {
- current_DOR &= ~mask;
- outb(current_DOR,FD_DOR);
- } else
- moff_timer[i]--;
- }
-}
-
-#define TIME_REQUESTS 64
-
-static struct timer_list {
- long jiffies;
- void (*fn)();
- struct timer_list * next;
-} timer_list[TIME_REQUESTS], * next_timer = NULL;
-
-void add_timer(long jiffies, void (*fn)(void))
-{
- struct timer_list * p;
-
- if (!fn)
- return;
- cli();
- if (jiffies <= 0)
- (fn)();
- else {
- for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++)
- if (!p->fn)
- break;
- if (p >= timer_list + TIME_REQUESTS)
- panic("No more time requests free");
- p->fn = fn;
- p->jiffies = jiffies;
- p->next = next_timer;
- next_timer = p;
- while (p->next && p->next->jiffies < p->jiffies) {
- p->jiffies -= p->next->jiffies;
- fn = p->fn;
- p->fn = p->next->fn;
- p->next->fn = fn;
- jiffies = p->jiffies;
- p->jiffies = p->next->jiffies;
- p->next->jiffies = jiffies;
- p = p->next;
- }
- }
- sti();
-}
-
-void do_timer(long cpl)
-{
- if (cpl)
- current->utime++;
- else
- current->stime++;
- if (next_timer) {
- next_timer->jiffies--;
- while (next_timer && next_timer->jiffies <= 0) {
- void (*fn)(void);
-
- fn = next_timer->fn;
- next_timer->fn = NULL;
- next_timer = next_timer->next;
- (fn)();
- }
- }
- if (current_DOR & 0xf0)
- do_floppy_timer();
- if ((--current->counter)>0) return;
- current->counter=0;
- if (!cpl) return;
- schedule();
-}
-
-int sys_alarm(long seconds)
-{
- current->alarm = (seconds>0)?(jiffies+HZ*seconds):0;
- return seconds;
-}
-
-int sys_getpid(void)
-{
- return current->pid;
-}
-
-int sys_getppid(void)
-{
- return current->father;
-}
-
-int sys_getuid(void)
-{
- return current->uid;
-}
-
-int sys_geteuid(void)
-{
- return current->euid;
-}
-
-int sys_getgid(void)
-{
- return current->gid;
-}
-
-int sys_getegid(void)
-{
- return current->egid;
-}
-
-int sys_nice(long increment)
-{
- if (current->priority-increment>0)
- current->priority -= increment;
- return 0;
-}
-
-void sched_init(void)
-{
- int i;
- struct desc_struct * p;
-
- if (sizeof(struct sigaction) != 16)
- panic("Struct sigaction MUST be 16 bytes");
- set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
- set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
- p = gdt+2+FIRST_TSS_ENTRY;
- for(i=1;i<NR_TASKS;i++) {
- task[i] = NULL;
- p->a=p->b=0;
- p++;
- p->a=p->b=0;
- p++;
- }
- ltr(0);
- lldt(0);
- outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
- outb_p(LATCH & 0xff , 0x40); /* LSB */
- outb(LATCH >> 8 , 0x40); /* MSB */
- set_intr_gate(0x20,&timer_interrupt);
- outb(inb_p(0x21)&~0x01,0x21);
- set_system_gate(0x80,&system_call);
-}
long eip, long cs, long eflags,
unsigned long * esp, long ss)
{
- long sa_handler;
+ unsigned long sa_handler;
long old_eip=eip;
struct sigaction * sa = current->sigaction + signr - 1;
int longs;
unsigned long * tmp_esp;
- sa_handler = (long) sa->sa_handler;
+ sa_handler = (unsigned long) sa->sa_handler;
if (sa_handler==1)
return;
if (!sa_handler) {
+++ /dev/null
-/*
- * linux/kernel/sys.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-#include <errno.h>
-
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/kernel.h>
-#include <asm/segment.h>
-#include <sys/times.h>
-#include <sys/utsname.h>
-
-int sys_ftime()
-{
- return -ENOSYS;
-}
-
-int sys_break()
-{
- return -ENOSYS;
-}
-
-int sys_ptrace()
-{
- return -ENOSYS;
-}
-
-int sys_stty()
-{
- return -ENOSYS;
-}
-
-int sys_gtty()
-{
- return -ENOSYS;
-}
-
-int sys_rename()
-{
- return -ENOSYS;
-}
-
-int sys_prof()
-{
- return -ENOSYS;
-}
-
-int sys_setgid(int gid)
-{
- if (current->euid && current->uid)
- if (current->gid==gid || current->sgid==gid)
- current->egid = gid;
- else
- return -EPERM;
- else
- current->gid = current->egid = gid;
- return 0;
-}
-
-int sys_acct()
-{
- return -ENOSYS;
-}
-
-int sys_phys()
-{
- return -ENOSYS;
-}
-
-int sys_lock()
-{
- return -ENOSYS;
-}
-
-int sys_mpx()
-{
- return -ENOSYS;
-}
-
-int sys_ulimit()
-{
- return -ENOSYS;
-}
-
-int sys_time(long * tloc)
-{
- int i;
-
- i = CURRENT_TIME;
- if (tloc) {
- verify_area(tloc,4);
- put_fs_long(i,(unsigned long *)tloc);
- }
- return i;
-}
-
-int sys_setuid(int uid)
-{
- if (current->euid && current->uid)
- if (uid==current->uid || current->suid==current->uid)
- current->euid=uid;
- else
- return -EPERM;
- else
- current->euid=current->uid=uid;
- return 0;
-}
-
-int sys_stime(long * tptr)
-{
- if (current->euid && current->uid)
- return -EPERM;
- startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ;
- return 0;
-}
-
-int sys_times(struct tms * tbuf)
-{
- if (tbuf) {
- verify_area(tbuf,sizeof *tbuf);
- put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime);
- put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime);
- put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime);
- put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime);
- }
- return jiffies;
-}
-
-int sys_brk(unsigned long end_data_seg)
-{
- if (end_data_seg >= current->end_code &&
- end_data_seg < current->start_stack - 16384)
- current->brk = end_data_seg;
- return current->brk;
-}
-
-/*
- * This needs some heave checking ...
- * I just haven't get the stomach for it. I also don't fully
- * understand sessions/pgrp etc. Let somebody who does explain it.
- */
-int sys_setpgid(int pid, int pgid)
-{
- int i;
-
- if (!pid)
- pid = current->pid;
- if (!pgid)
- pgid = current->pid;
- for (i=0 ; i<NR_TASKS ; i++)
- if (task[i] && task[i]->pid==pid) {
- if (task[i]->leader)
- return -EPERM;
- if (task[i]->session != current->session)
- return -EPERM;
- task[i]->pgrp = pgid;
- return 0;
- }
- return -ESRCH;
-}
-
-int sys_getpgrp(void)
-{
- return current->pgrp;
-}
-
-int sys_setsid(void)
-{
- if (current->uid && current->euid)
- return -EPERM;
- if (current->leader)
- return -EPERM;
- current->leader = 1;
- current->session = current->pgrp = current->pid;
- current->tty = -1;
- return current->pgrp;
-}
-
-int sys_uname(struct utsname * name)
-{
- static struct utsname thisname = {
- "linux .0","nodename","release ","version ","machine "
- };
- int i;
-
- if (!name) return -ERROR;
- verify_area(name,sizeof *name);
- for(i=0;i<sizeof *name;i++)
- put_fs_byte(((char *) &thisname)[i],i+(char *) name);
- return 0;
-}
-
-int sys_umask(int mask)
-{
- int old = current->umask;
-
- current->umask = mask & 0777;
- return (old);
-}
sa_flags = 8
sa_restorer = 12
-nr_system_calls = 70
+nr_system_calls = 72
/*
* Ok, I get parallel printer interrupts while using the floppy for some
*/
.globl _system_call,_sys_fork,_timer_interrupt,_sys_execve
.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt
+.globl _device_not_available, _coprocessor_error
.align 2
bad_sys_call:
pop %ds
iret
+.align 2
+_coprocessor_error:
+ push %ds
+ push %es
+ push %fs
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
+ pushl %eax
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ movl $0x17,%eax
+ mov %ax,%fs
+ pushl $ret_from_sys_call
+ jmp _math_error
+
+.align 2
+_device_not_available:
+ push %ds
+ push %es
+ push %fs
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
+ pushl %eax
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ movl $0x17,%eax
+ mov %ax,%fs
+ pushl $ret_from_sys_call
+ clts # clear TS so that we can use math
+ movl %cr0,%eax
+ testl $0x4,%eax # EM (math emulation bit)
+ je _math_state_restore
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ call _math_emulate
+ popl %edi
+ popl %esi
+ popl %ebp
+ ret
+
.align 2
_timer_interrupt:
push %ds # save ds,es and put kernel data space
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
+ movl $0x17,%eax
mov %ax,%fs
movb $0x20,%al
- outb %al,$0x20 # EOI to interrupt controller #1
+ outb %al,$0xA0 # EOI to interrupt controller #1
jmp 1f # give port chance to breathe
1: jmp 1f
-1: outb %al,$0xA0 # same to controller #2
- movl _do_hd,%eax
- testl %eax,%eax
+1: xorl %edx,%edx
+ xchgl _do_hd,%edx
+ testl %edx,%edx
jne 1f
- movl $_unexpected_hd_interrupt,%eax
-1: call *%eax # "interesting" way of handling intr.
+ movl $_unexpected_hd_interrupt,%edx
+1: outb %al,$0x20
+ call *%edx # "interesting" way of handling intr.
pop %fs
pop %es
pop %ds
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
+ movl $0x17,%eax
mov %ax,%fs
movb $0x20,%al
outb %al,$0x20 # EOI to interrupt controller #1
- movl _do_floppy,%eax
+ xorl %eax,%eax
+ xchgl _do_floppy,%eax
testl %eax,%eax
jne 1f
movl $_unexpected_floppy_interrupt,%eax
-c -o $*.o $<
OBJS = ctype.o _exit.o open.o close.o errno.o write.o dup.o setsid.o \
- execve.o wait.o string.o
+ execve.o wait.o string.o malloc.o
lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
execve.s execve.o : execve.c ../include/unistd.h ../include/sys/stat.h \
../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
../include/utime.h
+malloc.s malloc.o : malloc.c ../include/linux/kernel.h ../include/linux/mm.h \
+ ../include/asm/system.h
open.s open.o : open.c ../include/unistd.h ../include/sys/stat.h \
../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
../include/utime.h ../include/stdarg.h
--- /dev/null
+/*
+ * malloc.c --- a general purpose kernel memory allocator for Linux.
+ *
+ * Written by Theodore Ts'o (tytso@mit.edu), 11/29/91
+ *
+ * This routine is written to be as fast as possible, so that it
+ * can be called from the interrupt level.
+ *
+ * Limitations: maximum size of memory we can allocate using this routine
+ * is 4k, the size of a page in Linux.
+ *
+ * The general game plan is that each page (called a bucket) will only hold
+ * objects of a given size. When all of the object on a page are released,
+ * the page can be returned to the general free pool. When malloc() is
+ * called, it looks for the smallest bucket size which will fulfill its
+ * request, and allocate a piece of memory from that bucket pool.
+ *
+ * Each bucket has as its control block a bucket descriptor which keeps
+ * track of how many objects are in use on that page, and the free list
+ * for that page. Like the buckets themselves, bucket descriptors are
+ * stored on pages requested from get_free_page(). However, unlike buckets,
+ * pages devoted to bucket descriptor pages are never released back to the
+ * system. Fortunately, a system should probably only need 1 or 2 bucket
+ * descriptor pages, since a page can hold 256 bucket descriptors (which
+ * corresponds to 1 megabyte worth of bucket pages.) If the kernel is using
+ * that much allocated memory, it's probably doing something wrong. :-)
+ *
+ * Note: malloc() and free() both call get_free_page() and free_page()
+ * in sections of code where interrupts are turned off, to allow
+ * malloc() and free() to be safely called from an interrupt routine.
+ * (We will probably need this functionality when networking code,
+ * particularily things like NFS, is added to Linux.) However, this
+ * presumes that get_free_page() and free_page() are interrupt-level
+ * safe, which they may not be once paging is added. If this is the
+ * case, we will need to modify malloc() to keep a few unused pages
+ * "pre-allocated" so that it can safely draw upon those pages if
+ * it is called from an interrupt routine.
+ *
+ * Another concern is that get_free_page() should not sleep; if it
+ * does, the code is carefully ordered so as to avoid any race
+ * conditions. The catch is that if malloc() is called re-entrantly,
+ * there is a chance that unecessary pages will be grabbed from the
+ * system. Except for the pages for the bucket descriptor page, the
+ * extra pages will eventually get released back to the system, though,
+ * so it isn't all that bad.
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/system.h>
+
+struct bucket_desc { /* 16 bytes */
+ void *page;
+ struct bucket_desc *next;
+ void *freeptr;
+ unsigned short refcnt;
+ unsigned short bucket_size;
+};
+
+struct _bucket_dir { /* 8 bytes */
+ int size;
+ struct bucket_desc *chain;
+};
+
+/*
+ * The following is the where we store a pointer to the first bucket
+ * descriptor for a given size.
+ *
+ * If it turns out that the Linux kernel allocates a lot of objects of a
+ * specific size, then we may want to add that specific size to this list,
+ * since that will allow the memory to be allocated more efficiently.
+ * However, since an entire page must be dedicated to each specific size
+ * on this list, some amount of temperance must be exercised here.
+ *
+ * Note that this list *must* be kept in order.
+ */
+struct _bucket_dir bucket_dir[] = {
+ { 16, (struct bucket_desc *) 0},
+ { 32, (struct bucket_desc *) 0},
+ { 64, (struct bucket_desc *) 0},
+ { 128, (struct bucket_desc *) 0},
+ { 256, (struct bucket_desc *) 0},
+ { 512, (struct bucket_desc *) 0},
+ { 1024, (struct bucket_desc *) 0},
+ { 2048, (struct bucket_desc *) 0},
+ { 4096, (struct bucket_desc *) 0},
+ { 0, (struct bucket_desc *) 0}}; /* End of list marker */
+
+/*
+ * This contains a linked list of free bucket descriptor blocks
+ */
+struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0;
+
+/*
+ * This routine initializes a bucket description page.
+ */
+static inline void init_bucket_desc()
+{
+ struct bucket_desc *bdesc, *first;
+ int i;
+
+ first = bdesc = (struct bucket_desc *) get_free_page();
+ if (!bdesc)
+ panic("Out of memory in init_bucket_desc()");
+ for (i = PAGE_SIZE/sizeof(struct bucket_desc); i > 1; i--) {
+ bdesc->next = bdesc+1;
+ bdesc++;
+ }
+ /*
+ * This is done last, to avoid race conditions in case
+ * get_free_page() sleeps and this routine gets called again....
+ */
+ bdesc->next = free_bucket_desc;
+ free_bucket_desc = first;
+}
+
+void *malloc(unsigned int len)
+{
+ struct _bucket_dir *bdir;
+ struct bucket_desc *bdesc;
+ void *retval;
+
+ /*
+ * First we search the bucket_dir to find the right bucket change
+ * for this request.
+ */
+ for (bdir = bucket_dir; bdir->size; bdir++)
+ if (bdir->size >= len)
+ break;
+ if (!bdir->size) {
+ printk("malloc called with impossibly large argument (%d)\n",
+ len);
+ panic("malloc: bad arg");
+ }
+ /*
+ * Now we search for a bucket descriptor which has free space
+ */
+ cli(); /* Avoid race conditions */
+ for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next)
+ if (bdesc->freeptr)
+ break;
+ /*
+ * If we didn't find a bucket with free space, then we'll
+ * allocate a new one.
+ */
+ if (!bdesc) {
+ char *cp;
+ int i;
+
+ if (!free_bucket_desc)
+ init_bucket_desc();
+ bdesc = free_bucket_desc;
+ free_bucket_desc = bdesc->next;
+ bdesc->refcnt = 0;
+ bdesc->bucket_size = bdir->size;
+ bdesc->page = bdesc->freeptr = (void *) cp = get_free_page();
+ if (!cp)
+ panic("Out of memory in kernel malloc()");
+ /* Set up the chain of free objects */
+ for (i=PAGE_SIZE/bdir->size; i > 1; i--) {
+ *((char **) cp) = cp + bdir->size;
+ cp += bdir->size;
+ }
+ *((char **) cp) = 0;
+ bdesc->next = bdir->chain; /* OK, link it in! */
+ bdir->chain = bdesc;
+ }
+ retval = (void *) bdesc->freeptr;
+ bdesc->freeptr = *((void **) retval);
+ bdesc->refcnt++;
+ sti(); /* OK, we're safe again */
+ return(retval);
+}
+
+/*
+ * Here is the free routine. If you know the size of the object that you
+ * are freeing, then free_s() will use that information to speed up the
+ * search for the bucket descriptor.
+ *
+ * We will #define a macro so that "free(x)" is becomes "free_s(x, 0)"
+ */
+void free_s(void *obj, int size)
+{
+ void *page;
+ struct _bucket_dir *bdir;
+ struct bucket_desc *bdesc, *prev;
+
+ /* Calculate what page this object lives in */
+ page = (void *) ((unsigned long) obj & 0xfffff000);
+ /* Now search the buckets looking for that page */
+ for (bdir = bucket_dir; bdir->size; bdir++) {
+ prev = 0;
+ /* If size is zero then this conditional is always false */
+ if (bdir->size < size)
+ continue;
+ for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) {
+ if (bdesc->page == page)
+ goto found;
+ prev = bdesc;
+ }
+ }
+ panic("Bad address passed to kernel free_s()");
+found:
+ cli(); /* To avoid race conditions */
+ *((void **)obj) = bdesc->freeptr;
+ bdesc->freeptr = obj;
+ bdesc->refcnt--;
+ if (bdesc->refcnt == 0) {
+ /*
+ * We need to make sure that prev is still accurate. It
+ * may not be, if someone rudely interrupted us....
+ */
+ if ((prev && (prev->next != bdesc)) ||
+ (!prev && (bdir->chain != bdesc)))
+ for (prev = bdir->chain; prev; prev = prev->next)
+ if (prev->next == bdesc)
+ break;
+ if (prev)
+ prev->next = bdesc->next;
+ else {
+ if (bdir->chain != bdesc)
+ panic("malloc bucket chains corrupted");
+ bdir->chain = bdesc->next;
+ }
+ free_page((unsigned long) bdesc->page);
+ bdesc->next = free_bucket_desc;
+ free_bucket_desc = bdesc;
+ }
+ sti();
+ return;
+}
+
### Dependencies:
memory.o : memory.c ../include/signal.h ../include/sys/types.h \
- ../include/linux/head.h ../include/linux/kernel.h ../include/asm/system.h
+ ../include/asm/system.h ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h
* (C) 1991 Linus Torvalds
*/
+/*
+ * demand-loading started 01.12.91 - seems it is high on the list of
+ * things wanted, and it should be easy to implement. - Linus
+ */
+
+/*
+ * Ok, demand-loading was easy, shared pages a little bit tricker. Shared
+ * pages started 02.12.91, seems to work. - Linus.
+ *
+ * Tested sharing by executing about 30 /bin/sh: under the old kernel it
+ * would have taken more than the 6M I have free, but it worked well as
+ * far as I could see.
+ *
+ * Also corrected some "invalidate()"s - I wasn't doing enough of them.
+ */
+
#include <signal.h>
+#include <asm/system.h>
+
+#include <linux/sched.h>
#include <linux/head.h>
#include <linux/kernel.h>
-#include <asm/system.h>
-int do_exit(long code);
+volatile void do_exit(long code);
+
+static inline volatile void oom(void)
+{
+ printk("out of memory\n\r");
+ do_exit(SIGSEGV);
+}
#define invalidate() \
__asm__("movl %%eax,%%cr3"::"a" (0))
#define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
#define USED 100
+#define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \
+current->start_code + current->end_code)
+
static long HIGH_MEMORY = 0;
#define copy_page(from,to) \
void free_page(unsigned long addr)
{
if (addr < LOW_MEM) return;
- if (addr > HIGH_MEMORY)
+ if (addr >= HIGH_MEMORY)
panic("trying to free nonexistent page");
addr -= LOW_MEM;
addr >>= 12;
/* NOTE !!! This uses the fact that _pg_dir=0 */
- if (page < LOW_MEM || page > HIGH_MEMORY)
+ 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)
printk("mem_map disagrees with %p at %p\n",page,address);
page_table = (unsigned long *) tmp;
}
page_table[(address>>12) & 0x3ff] = page | 7;
+/* no need for invalidate */
return page;
}
old_page = 0xfffff000 & *table_entry;
if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) {
*table_entry |= 2;
+ invalidate();
return;
}
if (!(new_page=get_free_page()))
- do_exit(SIGSEGV);
+ oom();
if (old_page >= LOW_MEM)
mem_map[MAP_NR(old_page)]--;
*table_entry = new_page | 7;
+ invalidate();
copy_page(old_page,new_page);
}
* This routine handles present pages, when users try to write
* to a shared page. It is done by copying the page to a new address
* and decrementing the shared-page counter for the old page.
+ *
+ * If it's in code space we exit with a segment error.
*/
void do_wp_page(unsigned long error_code,unsigned long address)
{
+#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)))));
return;
}
+void get_empty_page(unsigned long address)
+{
+ unsigned long tmp;
+
+ if (!(tmp=get_free_page()) || !put_page(tmp,address)) {
+ free_page(tmp); /* 0 is ok - ignored */
+ oom();
+ }
+}
+
+/*
+ * try_to_share() checks the page at address "address" in the task "p",
+ * to see if it exists, and if it is clean. If so, share it with the current
+ * task.
+ *
+ * NOTE! This assumes we have checked that p != current, and that they
+ * share the same executable.
+ */
+static int try_to_share(unsigned long address, struct task_struct * p)
+{
+ unsigned long from;
+ unsigned long to;
+ unsigned long from_page;
+ unsigned long to_page;
+ unsigned long phys_addr;
+
+ from_page = to_page = ((address>>20) & 0xffc);
+ from_page += ((p->start_code>>20) & 0xffc);
+ to_page += ((current->start_code>>20) & 0xffc);
+/* is there a page-directory at from? */
+ from = *(unsigned long *) from_page;
+ if (!(from & 1))
+ return 0;
+ from &= 0xfffff000;
+ from_page = from + ((address>>10) & 0xffc);
+ phys_addr = *(unsigned long *) from_page;
+/* is the page clean and present? */
+ if ((phys_addr & 0x41) != 0x01)
+ return 0;
+ phys_addr &= 0xfffff000;
+ if (phys_addr >= HIGH_MEMORY || phys_addr < LOW_MEM)
+ return 0;
+ to = *(unsigned long *) to_page;
+ 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)
+ panic("try_to_share: to_page already exists");
+/* share them: write-protect */
+ *(unsigned long *) from_page &= ~2;
+ *(unsigned long *) to_page = *(unsigned long *) from_page;
+ invalidate();
+ phys_addr -= LOW_MEM;
+ phys_addr >>= 12;
+ mem_map[phys_addr]++;
+ return 1;
+}
+
+/*
+ * share_page() tries to find a process that could share a page with
+ * the current one. Address is the address of the wanted page relative
+ * to the current data space.
+ *
+ * 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(unsigned long address)
+{
+ struct task_struct ** p;
+
+ if (!current->executable)
+ return 0;
+ if (current->executable->i_count < 2)
+ return 0;
+ for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
+ if (!*p)
+ continue;
+ if (current == *p)
+ continue;
+ if ((*p)->executable != current->executable)
+ continue;
+ if (try_to_share(address,*p))
+ return 1;
+ }
+ return 0;
+}
+
void do_no_page(unsigned long error_code,unsigned long address)
{
+ int nr[4];
unsigned long tmp;
+ unsigned long page;
+ int block,i;
- if (tmp=get_free_page())
- if (put_page(tmp,address))
- return;
- do_exit(SIGSEGV);
+ address &= 0xfffff000;
+ tmp = address - current->start_code;
+ if (!current->executable || tmp >= current->end_data) {
+ get_empty_page(address);
+ return;
+ }
+ if (share_page(tmp))
+ return;
+ if (!(page = get_free_page()))
+ oom();
+/* remember that 1 block is used for header */
+ block = 1 + tmp/BLOCK_SIZE;
+ for (i=0 ; i<4 ; block++,i++)
+ nr[i] = bmap(current->executable,block);
+ bread_page(page,current->executable->i_dev,nr);
+ i = tmp + 4096 - current->end_data;
+ tmp = page + 4096;
+ while (i-- > 0) {
+ tmp--;
+ *(char *)tmp = 0;
+ }
+ if (put_page(page,address))
+ return;
+ free_page(page);
+ oom();
}
void mem_init(long start_mem, long end_mem)
+++ /dev/null
-head 1.2;
-branch ;
-access ;
-symbols ;
-locks ; strict;
-comment @ * @;
-
-
-1.2
-date 91.11.20.00.07.29; author tytso; state Exp;
-branches ;
-next 1.1;
-
-1.1
-date 91.11.11.14.45.51; author tytso; state Exp;
-branches ;
-next ;
-
-
-desc
-@@
-
-
-1.2
-log
-@Add code to support changing the root device at boot time.
-@
-text
-@/*
- * linux/tools/build.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-/*
- * This file builds a disk-image from three different files:
- *
- * - bootsect: max 510 bytes of 8086 machine code, loads the rest
- * - setup: max 4 sectors of 8086 machine code, sets up system parm
- * - system: 80386 code for actual system
- *
- * It does some checking that all files are of the correct type, and
- * just writes the result to stdout, removing headers and padding to
- * the right amount. It also writes some system data to stderr.
- */
-
-#include <stdio.h> /* fprintf */
-#include <string.h>
-#include <stdlib.h> /* contains exit */
-#include <sys/types.h> /* unistd.h needs this */
-#include <sys/stat.h>
-#include <linux/fs.h>
-#include <unistd.h> /* contains read/write */
-#include <fcntl.h>
-
-#define MINIX_HEADER 32
-#define GCC_HEADER 1024
-
-#define DEFAULT_MAJOR_ROOT 3
-#define DEFAULT_MINOR_ROOT 6
-
-/* max nr of sectors of setup: don't change unless you also change
- * bootsect etc */
-#define SETUP_SECTS 4
-
-#define STRINGIFY(x) #x
-
-void die(char * str)
-{
- fprintf(stderr,"%s\n",str);
- exit(1);
-}
-
-void usage(void)
-{
- die("Usage: build bootsect setup system [> image]");
-}
-
-int main(int argc, char ** argv)
-{
- int i,c,id;
- char buf[1024];
- char major_root, minor_root;
- struct stat sb;
-
- if ((argc != 4) && (argc != 5))
- usage();
- if (argc == 5) {
- if (strcmp(argv[4], "FLOPPY")) {
- if (stat(argv[4], &sb)) {
- perror(argv[4]);
- die("Couldn't stat root device.");
- }
- major_root = MAJOR(sb.st_rdev);
- minor_root = MINOR(sb.st_rdev);
- } else {
- major_root = 0;
- minor_root = 0;
- }
- } else {
- major_root = DEFAULT_MAJOR_ROOT;
- minor_root = DEFAULT_MINOR_ROOT;
- }
- fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
- 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 #");
- }
- for (i=0;i<sizeof buf; i++) buf[i]=0;
- if ((id=open(argv[1],O_RDONLY,0))<0)
- die("Unable to open 'boot'");
- if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
- die("Unable to read header of 'boot'");
- if (((long *) buf)[0]!=0x04100301)
- die("Non-Minix header of 'boot'");
- if (((long *) buf)[1]!=MINIX_HEADER)
- die("Non-Minix header of 'boot'");
- if (((long *) buf)[3]!=0)
- die("Illegal data segment in 'boot'");
- if (((long *) buf)[4]!=0)
- die("Illegal bss in 'boot'");
- if (((long *) buf)[5] != 0)
- die("Non-Minix header of 'boot'");
- if (((long *) buf)[7] != 0)
- die("Illegal symbol table in 'boot'");
- i=read(id,buf,sizeof buf);
- fprintf(stderr,"Boot sector %d bytes.\n",i);
- if (i != 512)
- die("Boot block must be exactly 512 bytes");
- if ((*(unsigned short *)(buf+510)) != 0xAA55)
- die("Boot block hasn't got boot flag (0xAA55)");
- buf[508] = (char) minor_root;
- buf[509] = (char) major_root;
- i=write(1,buf,512);
- if (i!=512)
- die("Write call failed");
- close (id);
-
- if ((id=open(argv[2],O_RDONLY,0))<0)
- die("Unable to open 'setup'");
- if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
- die("Unable to read header of 'setup'");
- if (((long *) buf)[0]!=0x04100301)
- die("Non-Minix header of 'setup'");
- if (((long *) buf)[1]!=MINIX_HEADER)
- die("Non-Minix header of 'setup'");
- if (((long *) buf)[3]!=0)
- die("Illegal data segment in 'setup'");
- if (((long *) buf)[4]!=0)
- die("Illegal bss in 'setup'");
- if (((long *) buf)[5] != 0)
- die("Non-Minix header of 'setup'");
- if (((long *) buf)[7] != 0)
- die("Illegal symbol table in 'setup'");
- for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
- if (write(1,buf,c)!=c)
- die("Write call failed");
- close (id);
- if (i > SETUP_SECTS*512)
- die("Setup exceeds " STRINGIFY(SETUP_SECTS)
- " sectors - rewrite build/boot/setup");
- fprintf(stderr,"Setup is %d bytes.\n",i);
- for (c=0 ; c<sizeof(buf) ; c++)
- buf[c] = '\0';
- while (i<SETUP_SECTS*512) {
- c = SETUP_SECTS*512-i;
- if (c > sizeof(buf))
- c = sizeof(buf);
- if (write(1,buf,c) != c)
- die("Write call failed");
- i += c;
- }
-
- if ((id=open(argv[3],O_RDONLY,0))<0)
- die("Unable to open 'system'");
- if (read(id,buf,GCC_HEADER) != GCC_HEADER)
- die("Unable to read header of 'system'");
- if (((long *) buf)[5] != 0)
- die("Non-GCC header of 'system'");
- for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
- if (write(1,buf,c)!=c)
- die("Write call failed");
- close(id);
- fprintf(stderr,"System is %d bytes.\n",i);
- return(0);
-}
-@
-
-
-1.1
-log
-@Initial revision
-@
-text
-@d20 1
-d23 2
-d31 3
-d55 2
-d58 1
-a58 1
- if (argc != 4)
-d60 23
-d106 2
-@
* the right amount. It also writes some system data to stderr.
*/
+/*
+ * Changes by tytso to allow root device specification
+ */
+
#include <stdio.h> /* fprintf */
#include <string.h>
#include <stdlib.h> /* contains exit */
#define MINIX_HEADER 32
#define GCC_HEADER 1024
+#define SYS_SIZE 0x2000
+
#define DEFAULT_MAJOR_ROOT 3
#define DEFAULT_MINOR_ROOT 6
void usage(void)
{
- die("Usage: build bootsect setup system [> image]");
+ die("Usage: build bootsect setup system [rootdev] [> image]");
}
int main(int argc, char ** argv)
die("Write call failed");
close(id);
fprintf(stderr,"System is %d bytes.\n",i);
+ if (i > SYS_SIZE*16)
+ die("System is too big");
return(0);
}
+++ /dev/null
-/*
- * linux/tools/build.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-/*
- * This file builds a disk-image from three different files:
- *
- * - bootsect: max 510 bytes of 8086 machine code, loads the rest
- * - setup: max 4 sectors of 8086 machine code, sets up system parm
- * - system: 80386 code for actual system
- *
- * It does some checking that all files are of the correct type, and
- * just writes the result to stdout, removing headers and padding to
- * the right amount. It also writes some system data to stderr.
- */
-
-#include <stdio.h> /* fprintf */
-#include <stdlib.h> /* contains exit */
-#include <sys/types.h> /* unistd.h needs this */
-#include <unistd.h> /* contains read/write */
-#include <fcntl.h>
-
-#define MINIX_HEADER 32
-#define GCC_HEADER 1024
-
-/* max nr of sectors of setup: don't change unless you also change
- * bootsect etc */
-#define SETUP_SECTS 4
-
-#define STRINGIFY(x) #x
-
-void die(char * str)
-{
- fprintf(stderr,"%s\n",str);
- exit(1);
-}
-
-void usage(void)
-{
- die("Usage: build bootsect setup system [> image]");
-}
-
-int main(int argc, char ** argv)
-{
- int i,c,id;
- char buf[1024];
-
- if (argc != 4)
- usage();
- for (i=0;i<sizeof buf; i++) buf[i]=0;
- if ((id=open(argv[1],O_RDONLY,0))<0)
- die("Unable to open 'boot'");
- if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
- die("Unable to read header of 'boot'");
- if (((long *) buf)[0]!=0x04100301)
- die("Non-Minix header of 'boot'");
- if (((long *) buf)[1]!=MINIX_HEADER)
- die("Non-Minix header of 'boot'");
- if (((long *) buf)[3]!=0)
- die("Illegal data segment in 'boot'");
- if (((long *) buf)[4]!=0)
- die("Illegal bss in 'boot'");
- if (((long *) buf)[5] != 0)
- die("Non-Minix header of 'boot'");
- if (((long *) buf)[7] != 0)
- die("Illegal symbol table in 'boot'");
- i=read(id,buf,sizeof buf);
- fprintf(stderr,"Boot sector %d bytes.\n",i);
- if (i != 512)
- die("Boot block must be exactly 512 bytes");
- if ((*(unsigned short *)(buf+510)) != 0xAA55)
- die("Boot block hasn't got boot flag (0xAA55)");
- i=write(1,buf,512);
- if (i!=512)
- die("Write call failed");
- close (id);
-
- if ((id=open(argv[2],O_RDONLY,0))<0)
- die("Unable to open 'setup'");
- if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
- die("Unable to read header of 'setup'");
- if (((long *) buf)[0]!=0x04100301)
- die("Non-Minix header of 'setup'");
- if (((long *) buf)[1]!=MINIX_HEADER)
- die("Non-Minix header of 'setup'");
- if (((long *) buf)[3]!=0)
- die("Illegal data segment in 'setup'");
- if (((long *) buf)[4]!=0)
- die("Illegal bss in 'setup'");
- if (((long *) buf)[5] != 0)
- die("Non-Minix header of 'setup'");
- if (((long *) buf)[7] != 0)
- die("Illegal symbol table in 'setup'");
- for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
- if (write(1,buf,c)!=c)
- die("Write call failed");
- close (id);
- if (i > SETUP_SECTS*512)
- die("Setup exceeds " STRINGIFY(SETUP_SECTS)
- " sectors - rewrite build/boot/setup");
- fprintf(stderr,"Setup is %d bytes.\n",i);
- for (c=0 ; c<sizeof(buf) ; c++)
- buf[c] = '\0';
- while (i<SETUP_SECTS*512) {
- c = SETUP_SECTS*512-i;
- if (c > sizeof(buf))
- c = sizeof(buf);
- if (write(1,buf,c) != c)
- die("Write call failed");
- i += c;
- }
-
- if ((id=open(argv[3],O_RDONLY,0))<0)
- die("Unable to open 'system'");
- if (read(id,buf,GCC_HEADER) != GCC_HEADER)
- die("Unable to read header of 'system'");
- if (((long *) buf)[5] != 0)
- die("Non-GCC header of 'system'");
- for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
- if (write(1,buf,c)!=c)
- die("Write call failed");
- close(id);
- fprintf(stderr,"System is %d bytes.\n",i);
- return(0);
-}