Commit fa1ec100 authored by Linus Torvalds's avatar Linus Torvalds

Linux 0.10 (November 11, 1991 ???)

Likely correct 0.10: these were re-created from the RCS tree that Ted
Ts'o had, no known pristine 0.10 tree (or, sadly, 0.02 and 0.03 trees)
exist any more.

Linux-0.10 was actually a major step.  It was _almost_ able to host
itself, and if I remember correctly, a small patch I posted to the
newsgroup a few days later got the buffer cache handling stable enough
that Linux could now compile itself under itself without running out of
memory due to a memory leak.

Apart from bugfixes, the major update here is the support for
mount/umount.  But you can also tell that others are starting to test
out this thing, since the harddisk geometry is now auto-sensed, and we
support the US keyboard layout in addition to the Finnish one.

(This is also the first actual thing from the outside: the US keyboard
layout tables came from Alfred Leung, although with major editing by me.)

 - add copyright messages ("(C) 1991  Linus Torvalds")

   Nobody else is really doing coding (yet..) but clearly I'm starting
   to be a lot more aware of other people here.

 - split up boot/boot.s into boot/bootsect.s and boot/setup.s
 - autodetect floppy type for booting
 - make root device and boot device configurable

 - support up to 16MB of physical memory (instead of just 8MB ;)

   Whee. We're clearly moving into the "big iron" phase of Linux.

 - move drivers around.  We now have separate subdirectories for
   character device drivers (tty and memory) and block device drivers.

 - initial floppy driver support!

   You can see how the "block layer" interfaces evolved directly from
   moving parts of the original hd.c driver into ll_rw_block.c and
   making them "generic".

 - make file reading do simple read-ahead
 - make file writing avoid reading in blocks that are totally overwritten
 - add support for /dev/port and /dev/null (!!)
 - improve pipe throughput

 - add support for sigaction(), not just old-style signal()

   This also rewrites most of the signal code in C rather than assembly.

 - add "mknod()" and "mount()"/"umount()" system calls, and support
   for traversing over mount-points.

 - add "sessions" and setsid(), so that we get proper SIGHUP's
parent bb441db1
#
# Makefile for linux.
# If you don't have '-mstring-insns' in your gcc (and nobody but me has :-)
# remove them from the CFLAGS defines.
#
ROOTDEV= /dev/hd3
AS86 =as -0 -a
CC86 =cc -0
......@@ -13,9 +9,10 @@ LD =gld
LDFLAGS =-s -x -M
CC =gcc
CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs
CPP =gcc -E -nostdinc -Iinclude
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:
......@@ -29,8 +26,8 @@ LIBS =lib/lib.a
all: Image
Image: boot/boot tools/system tools/build
tools/build boot/boot tools/system > 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
......@@ -41,12 +38,19 @@ tools/build: tools/build.c
boot/head.o: boot/head.s
tools/system: boot/head.o init/main.o \
$(ARCHIVES) $(LIBS)
$(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)
......@@ -59,16 +63,22 @@ fs/fs.o:
lib/lib.a:
(cd lib; make)
boot/boot: boot/boot.s tools/system
(echo -n "SYSSIZE = (";ls -l tools/system | grep system \
| cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s
cat boot/boot.s >> tmp.s
$(AS86) -o boot/boot.o tmp.s
rm -f tmp.s
$(LD86) -s -o boot/boot boot/boot.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
#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 boot/boot core
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)
......@@ -92,5 +102,5 @@ 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/asm/system.h include/asm/io.h include/stddef.h \
include/stdarg.h include/fcntl.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
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.
.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 ax,#BOOTSEG
mov ds,ax
mov ax,#INITSEG
mov es,ax
mov cx,#256
sub si,si
sub di,di
rep
movw
jmpi go,INITSEG
go: mov ax,cs
mov ds,ax
mov es,ax
| put stack at 0x9ff00.
mov ss,ax
mov sp,#0xFF00 | arbitrary value >>512
| 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
mov ax,#0x0000 | reset the diskette
int 0x13
j load_setup
ok_load_setup:
| Get disk drive parameters, specifically nr of sectors/track
mov dl,#0x00
mov ax,#0x0800 | AH=8 is get drive parameters
int 0x13
mov ch,#0x00
seg cs
mov sectors,cx
mov ax,#INITSEG
mov es,ax
| Print some inane message
mov ah,#0x03 | read cursor pos
xor bh,bh
int 0x10
mov cx,#24
mov bx,#0x0007 | page 0, attribute 7 (normal)
mov bp,#msg1
mov ax,#0x1301 | write string, move cursor
int 0x10
| ok, we've written the message, now
| we want to load the system (at 0x10000)
mov ax,#SYSSEG
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.
seg cs
mov ax,root_dev
cmp ax,#0
jne root_defined
seg cs
mov bx,sectors
mov ax,#0x0208 | /dev/ps0 - 1.2Mb
cmp bx,#15
je root_defined
mov ax,#0x021c | /dev/PS0 - 1.44Mb
cmp bx,#18
je root_defined
undef_root:
jmp undef_root
root_defined:
seg cs
mov root_dev,ax
| 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 ax,es
test ax,#0x0fff
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?
jb ok1_read
ret
ok1_read:
seg cs
mov ax,sectors
sub ax,sread
mov cx,ax
shl cx,#9
add cx,bx
jnc ok2_read
je ok2_read
xor ax,ax
sub ax,bx
shr ax,#9
ok2_read:
call read_track
mov cx,ax
add ax,sread
seg cs
cmp ax,sectors
jne ok3_read
mov ax,#1
sub ax,head
jne ok4_read
inc track
ok4_read:
mov head,ax
xor ax,ax
ok3_read:
mov sread,ax
shl cx,#9
add bx,cx
jnc rp_read
mov ax,es
add ax,#0x1000
mov es,ax
xor bx,bx
jmp rp_read
read_track:
push ax
push bx
push cx
push dx
mov dx,track
mov cx,sread
inc cx
mov ch,dl
mov dx,head
mov dh,dl
mov dl,#0
and dx,#0x0100
mov ah,#2
int 0x13
jc bad_rt
pop dx
pop cx
pop bx
pop ax
ret
bad_rt: mov ax,#0
mov dx,#0
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 dx,#0x3f2
mov al,#0
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:
/*
*
* 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:
#!/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;
}
/*
* linux/boot/head.s
*
* (C) 1991 Linus Torvalds
*/
/*
* head.s contains the 32-bit startup code.
*
......@@ -6,7 +12,7 @@
* the page directory.
*/
.text
.globl _idt,_gdt,_pg_dir
.globl _idt,_gdt,_pg_dir,_tmp_floppy_area
_pg_dir:
startup_32:
movl $0x10,%eax
......@@ -25,14 +31,22 @@ startup_32:
lss _stack_start,%esp
xorl %eax,%eax
1: incl %eax # check that A20 really IS enabled
movl %eax,0x000000
movl %eax,0x000000 # loop forever if it isn't
cmpl %eax,0x100000
je 1b
/*
* NOTE! 486 should set bit 16, to check for write-protect in supervisor
* mode. Then it would be unnecessary with the "verify_area()"-calls.
* 486 users probably want to set the NE (#5) bit also, so as to use
* int 16 for math errors.
*/
movl %cr0,%eax # check math chip
andl $0x80000011,%eax # Save PG,ET,PE
/* "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
orl $4,%eax # else set emulate bit
xorl $6,%eax # else reset MP and set EM
1: movl %eax,%cr0
jmp after_page_tables
......@@ -78,6 +92,11 @@ setup_gdt:
lgdt gdt_descr
ret
/*
* I put the kernel page tables right after the page directory,
* using 4 of them to span 16 Mb of physical memory. People with
* more than 16MB will have to expand this.
*/
.org 0x1000
pg0:
......@@ -85,11 +104,20 @@ pg0:
pg1:
.org 0x3000
pg2: # This is not used yet, but if you
# want to expand past 8 Mb, you'll have
# to use it.
pg2:
.org 0x4000
pg3:
.org 0x5000
/*
* tmp_floppy_area is used by the floppy-driver when DMA cannot
* reach to a buffer-block. It needs to be aligned, so that it isn't
* on a 64kB border.
*/
_tmp_floppy_area:
.fill 1024,1,0
after_page_tables:
pushl $0 # These are the parameters to main :-)
pushl $0
......@@ -102,11 +130,30 @@ L6:
# just in case, we know what happens.
/* This is the default interrupt "handler" :-) */
int_msg:
.asciz "Unknown interrupt\n\r"
.align 2
ignore_int:
incb 0xb8000+160 # put something on the screen
movb $2,0xb8000+161 # so that we know something
iret # happened
pushl %eax
pushl %ecx
pushl %edx
push %ds
push %es
push %fs
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
mov %ax,%fs
pushl $int_msg
call _printk
popl %eax
pop %fs
pop %es
pop %ds
popl %edx
popl %ecx
popl %eax
iret
/*
......@@ -114,7 +161,7 @@ ignore_int:
*
* This routine sets up paging by setting the page bit
* in cr0. The page tables are set up, identity-mapping
* the first 8MB. The pager assumes that no illegal
* the first 16MB. The pager assumes that no illegal
* addresses are produced (ie >4Mb on a 4Mb machine).
*
* NOTE! Although all physical memory should be identity
......@@ -124,25 +171,27 @@ ignore_int:
* will be mapped to some other place - mm keeps track of
* that.
*
* For those with more memory than 8 Mb - tough luck. I've
* For those with more memory than 16 Mb - tough luck. I've
* not got it, why should you :-) The source is here. Change
* it. (Seriously - it shouldn't be too difficult. Mostly
* change some constants etc. I left it at 8Mb, as my machine
* change some constants etc. I left it at 16Mb, as my machine
* even cannot be extended past that (ok, but it was cheap :-)
* I've tried to show which constants to change by having
* some kind of marker at them (search for "8Mb"), but I
* some kind of marker at them (search for "16Mb"), but I
* won't guarantee that's all :-( )
*/
.align 2
setup_paging:
movl $1024*3,%ecx
movl $1024*5,%ecx /* 5 pages - pg_dir+4 page tables */
xorl %eax,%eax
xorl %edi,%edi /* pg_dir is at 0x000 */
cld;rep;stosl
movl $pg0+7,_pg_dir /* set present bit/user r/w */
movl $pg1+7,_pg_dir+4 /* --------- " " --------- */
movl $pg1+4092,%edi
movl $0x7ff007,%eax /* 8Mb - 4096 + 7 (r/w user,p) */
movl $pg2+7,_pg_dir+8 /* --------- " " --------- */
movl $pg3+7,_pg_dir+12 /* --------- " " --------- */
movl $pg3+4092,%edi
movl $0xfff007,%eax /* 16Mb - 4096 + 7 (r/w user,p) */
std
1: stosl /* fill pages backwards - more efficient :-) */
subl $0x1000,%eax
......@@ -169,7 +218,7 @@ gdt_descr:
_idt: .fill 256,8,0 # idt is uninitialized
_gdt: .quad 0x0000000000000000 /* NULL descriptor */
.quad 0x00c09a00000007ff /* 8Mb */
.quad 0x00c09200000007ff /* 8Mb */
.quad 0x00c09a0000000fff /* 16Mb */
.quad 0x00c0920000000fff /* 16Mb */
.quad 0x0000000000000000 /* TEMPORARY - don't use */
.fill 252,8,0 /* space for LDT's and TSS's etc */
|
| boot.s
| setup.s (C) 1991 Linus Torvalds
|
| boot.s is loaded at 0x7c00 by the bios-startup routines, and moves itself
| out of the way to address 0x90000, and jumps there.
| 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.
|
| It then loads the system at 0x10000, using BIOS interrupts. Thereafter
| it disables all interrupts, moves the system down to 0x0000, changes
| to protected mode, and calls the start of system. System then must
| RE-initialize the protected mode in it's own tables, and enable
| interrupts as needed.
| 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! 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 - in fact more would mean we'd have to move
| not just these start-up routines, but also do something about the cache-
| memory (block IO devices). The area left over in the lower 640 kB is meant
| for these. No other memory is assumed to be "physical", ie all memory
| over 1Mb is demand-paging. All addresses under 1Mb are guaranteed to match
| their physical addresses.
|
| NOTE1 abouve is no longer valid in it's entirety. cache-memory is allocated
| above the 1Mb mark as well as below. Otherwise it is mainly correct.
|
| NOTE 2! The boot disk type must be set at compile-time, by setting
| the following equ. Having the boot-up procedure hunt for the right
| disk type is severe brain-damage.
| The loader has been made as simple as possible (had to, to get it
| in 512 bytes with the code to move to protected mode), 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.
| 1.44Mb disks:
sectors = 18
| 1.2Mb disks:
| sectors = 15
| 720kB disks:
| sectors = 9
| 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
......@@ -46,55 +27,67 @@ begdata:
begbss:
.text
BOOTSEG = 0x07c0
INITSEG = 0x9000
SYSSEG = 0x1000 | system loaded at 0x10000 (65536).
ENDSEG = SYSSEG + SYSSIZE
entry start
start:
mov ax,#BOOTSEG
| 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 ds,ax
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.
| Get memory size (extended mem, kB)
mov ah,#0x88
int 0x15
mov [2],ax
| Get hd0 data
mov ax,#0x0000
mov ds,ax
lds si,[4*0x41]
mov ax,#INITSEG
mov es,ax
mov cx,#256
sub si,si
sub di,di
mov di,#0x0080
mov cx,#0x10
rep
movw
jmpi go,INITSEG
go: mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov sp,#0x400 | arbitrary value >>512
movsb
mov ah,#0x03 | read cursor pos
xor bh,bh
int 0x10
mov cx,#24
mov bx,#0x0007 | page 0, attribute 7 (normal)
mov bp,#msg1
mov ax,#0x1301 | write string, move cursor
int 0x10
| Get hd1 data
| ok, we've written the message, now
| we want to load the system (at 0x10000)
mov ax,#0x0000
mov ds,ax
lds si,[4*0x46]
mov ax,#INITSEG
mov es,ax
mov di,#0x0090
mov cx,#0x10
rep
movsb
mov ax,#SYSSEG
mov es,ax | segment of 0x010000
call read_it
call kill_motor
| Check that there IS a hd1 :-)
| if the read went well we get current cursor position ans save it for
| posterity.
mov ax,#0x01500
mov dl,#0x81
int 0x13
jc no_disk1
cmp ah,#3
je is_disk1
no_disk1:
mov ax,#INITSEG
mov es,ax
mov di,#0x0090
mov cx,#0x10
mov ax,#0x00
rep
stosb
is_disk1:
mov ah,#0x03 | read cursor pos
xor bh,bh
int 0x10 | save it in known place, con_init fetches
mov [510],dx | it from 0x90510.
| now we want to move to protected mode ...
cli | no interrupts allowed !
......@@ -114,13 +107,12 @@ do_move:
mov cx,#0x8000
rep
movsw
j do_move
jmp do_move
| then we load the segment descriptors
end_move:
mov ax,cs | 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
......@@ -194,107 +186,6 @@ empty_8042:
jnz empty_8042 | yes - loop
ret
| 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)
|
| This routine has to be recompiled to fit another drive type,
| just change the "sectors" variable at the start of the file
| (originally 18, for a 1.44Mb drive)
|
sread: .word 1 | 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
rp_read:
mov ax,es
cmp ax,#ENDSEG | have we loaded all yet?
jb ok1_read
ret
ok1_read:
mov ax,#sectors
sub ax,sread
mov cx,ax
shl cx,#9
add cx,bx
jnc ok2_read
je ok2_read
xor ax,ax
sub ax,bx
shr ax,#9
ok2_read:
call read_track
mov cx,ax
add ax,sread
cmp ax,#sectors
jne ok3_read
mov ax,#1
sub ax,head
jne ok4_read
inc track
ok4_read:
mov head,ax
xor ax,ax
ok3_read:
mov sread,ax
shl cx,#9
add bx,cx
jnc rp_read
mov ax,es
add ax,#0x1000
mov es,ax
xor bx,bx
jmp rp_read
read_track:
push ax
push bx
push cx
push dx
mov dx,track
mov cx,sread
inc cx
mov ch,dl
mov dx,head
mov dh,dl
mov dl,#0
and dx,#0x0100
mov ah,#2
int 0x13
jc bad_rt
pop dx
pop cx
pop bx
pop ax
ret
bad_rt: mov ax,#0
mov dx,#0
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 dx,#0x3f2
mov al,#0
outb
pop dx
ret
gdt:
.word 0,0,0,0 | dummy
......@@ -314,13 +205,8 @@ idt_48:
gdt_48:
.word 0x800 | gdt limit=2048, 256 GDT entries
.word gdt,0x9 | gdt base = 0X9xxxx
.word 512+gdt,0x9 | gdt base = 0X9xxxx
msg1:
.byte 13,10
.ascii "Loading system ..."
.byte 13,10,13,10
.text
endtext:
.data
......
/*
*
* 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:
......@@ -34,62 +34,71 @@ dep:
### Dependencies:
bitmap.o : bitmap.c ../include/string.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/linux/kernel.h
block_dev.o : block_dev.c ../include/errno.h ../include/linux/fs.h \
../include/sys/types.h ../include/linux/kernel.h ../include/asm/segment.h
buffer.o : buffer.c ../include/linux/config.h ../include/linux/sched.h \
../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h
block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/linux/kernel.h ../include/asm/system.h
char_dev.o : char_dev.c ../include/errno.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/linux/kernel.h
../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
../include/asm/segment.h ../include/asm/system.h
buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
../include/sys/types.h ../include/linux/mm.h ../include/signal.h \
../include/linux/kernel.h ../include/asm/system.h ../include/asm/io.h
char_dev.o : char_dev.c ../include/errno.h ../include/sys/types.h \
../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/linux/kernel.h ../include/asm/segment.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/linux/kernel.h \
../include/asm/segment.h ../include/fcntl.h ../include/sys/stat.h
../include/sys/types.h ../include/linux/mm.h ../include/signal.h \
../include/linux/kernel.h ../include/asm/segment.h ../include/fcntl.h \
../include/sys/stat.h
file_dev.o : file_dev.c ../include/errno.h ../include/fcntl.h \
../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \
../include/asm/segment.h
../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \
../include/linux/kernel.h ../include/asm/segment.h
file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h
inode.o : inode.c ../include/string.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/linux/kernel.h ../include/asm/system.h
inode.o : inode.c ../include/string.h ../include/sys/stat.h \
../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \
../include/linux/kernel.h ../include/asm/system.h
ioctl.o : ioctl.c ../include/string.h ../include/errno.h \
../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
../include/signal.h
namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
../include/linux/kernel.h ../include/asm/segment.h ../include/string.h \
../include/fcntl.h ../include/errno.h ../include/const.h \
../include/sys/stat.h
../include/signal.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
open.o : open.c ../include/string.h ../include/errno.h ../include/fcntl.h \
../include/sys/types.h ../include/utime.h ../include/sys/stat.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
../include/linux/mm.h ../include/linux/tty.h ../include/termios.h \
../include/linux/kernel.h ../include/asm/segment.h
../include/linux/mm.h ../include/signal.h ../include/linux/tty.h \
../include/termios.h ../include/linux/kernel.h ../include/asm/segment.h
pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
../include/linux/mm.h ../include/asm/segment.h
read_write.o : read_write.c ../include/sys/stat.h ../include/sys/types.h \
../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
../include/asm/segment.h
../include/signal.h ../include/asm/segment.h
stat.o : stat.c ../include/errno.h ../include/sys/stat.h \
../include/sys/types.h ../include/linux/fs.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/mm.h ../include/linux/kernel.h \
../include/asm/segment.h
../include/linux/head.h ../include/linux/mm.h ../include/signal.h \
../include/linux/kernel.h ../include/asm/segment.h
super.o : super.c ../include/linux/config.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/linux/kernel.h
../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
../include/asm/system.h ../include/errno.h ../include/sys/stat.h
truncate.o : truncate.c ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
../include/sys/stat.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/linux/kernel.h \
../include/linux/tty.h ../include/asm/segment.h ../include/asm/system.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
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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 *) &times->actime);
modtime = get_fs_long((unsigned long *) &times->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) {
@
/*
* linux/fs/bitmap.c
*
* (C) 1991 Linus Torvalds
*/
/* bitmap.c contains the code that handles the inode and block bitmaps */
#include <string.h>
......
/*
* linux/fs/block_dev.c
*
* (C) 1991 Linus Torvalds
*/
#include <errno.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#define NR_BLK_DEV ((sizeof (rd_blk))/(sizeof (rd_blk[0])))
#include <asm/system.h>
int block_write(int dev, long * pos, char * buf, int count)
{
int block = *pos / BLOCK_SIZE;
int offset = *pos % BLOCK_SIZE;
int block = *pos >> BLOCK_SIZE_BITS;
int offset = *pos & (BLOCK_SIZE-1);
int chars;
int written = 0;
struct buffer_head * bh;
register char * p;
while (count>0) {
bh = bread(dev,block);
chars = BLOCK_SIZE - offset;
if (chars > count)
chars=count;
if (chars == BLOCK_SIZE)
bh = getblk(dev,block);
else
bh = breada(dev,block,block+1,block+2,-1);
block++;
if (!bh)
return written?written:-EIO;
chars = (count<BLOCK_SIZE) ? count : BLOCK_SIZE;
p = offset + bh->b_data;
offset = 0;
block++;
*pos += chars;
written += chars;
count -= chars;
......@@ -36,51 +46,28 @@ int block_write(int dev, long * pos, char * buf, int count)
int block_read(int dev, unsigned long * pos, char * buf, int count)
{
int block = *pos / BLOCK_SIZE;
int offset = *pos % BLOCK_SIZE;
int block = *pos >> BLOCK_SIZE_BITS;
int offset = *pos & (BLOCK_SIZE-1);
int chars;
int read = 0;
struct buffer_head * bh;
register char * p;
while (count>0) {
bh = bread(dev,block);
if (!bh)
chars = BLOCK_SIZE-offset;
if (chars > count)
chars = count;
if (!(bh = breada(dev,block,block+1,block+2,-1)))
return read?read:-EIO;
chars = (count<BLOCK_SIZE) ? count : BLOCK_SIZE;
block++;
p = offset + bh->b_data;
offset = 0;
block++;
*pos += chars;
read += chars;
count -= chars;
while (chars-->0)
put_fs_byte(*(p++),buf++);
bh->b_dirt = 1;
brelse(bh);
}
return read;
}
extern void rw_hd(int rw, struct buffer_head * bh);
typedef void (*blk_fn)(int rw, struct buffer_head * bh);
static blk_fn rd_blk[]={
NULL, /* nodev */
NULL, /* dev mem */
NULL, /* dev fd */
rw_hd, /* dev hd */
NULL, /* dev ttyx */
NULL, /* dev tty */
NULL}; /* dev lp */
void ll_rw_block(int rw, struct buffer_head * bh)
{
blk_fn blk_addr;
unsigned int major;
if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || !(blk_addr=rd_blk[major]))
panic("Trying to read nonexistent block-device");
blk_addr(rw, bh);
}
/*
* 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
......@@ -6,18 +12,19 @@
* 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>
#if (BUFFER_END & 0xfff)
#error "Bad BUFFER_END value"
#endif
#if (BUFFER_END > 0xA0000 && BUFFER_END <= 0x100000)
#error "Bad BUFFER_END value"
#endif
#include <asm/io.h>
extern int end;
struct buffer_head * start_buffer = (struct buffer_head *) &end;
......@@ -49,7 +56,7 @@ int sys_sync(void)
return 0;
}
static int sync_dev(int dev)
int sync_dev(int dev)
{
int i;
struct buffer_head * bh;
......@@ -59,12 +66,59 @@ static int sync_dev(int dev)
if (bh->b_dev != dev)
continue;
wait_on_buffer(bh);
if (bh->b_dirt)
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)]
......@@ -124,73 +178,70 @@ struct buffer_head * get_hash_table(int dev, int block)
{
struct buffer_head * bh;
repeat:
if (!(bh=find_buffer(dev,block)))
return NULL;
bh->b_count++;
wait_on_buffer(bh);
if (bh->b_dev != dev || bh->b_blocknr != block) {
brelse(bh);
goto repeat;
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--;
}
return bh;
}
/*
* 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;
struct buffer_head * tmp, * bh;
repeat:
if (tmp=get_hash_table(dev,block))
return tmp;
if (bh = get_hash_table(dev,block))
return bh;
tmp = free_list;
do {
if (!tmp->b_count) {
wait_on_buffer(tmp); /* we still have to wait */
if (!tmp->b_count) /* on it, it might be dirty */
if (tmp->b_count)
continue;
if (!bh || BADNESS(tmp)<BADNESS(bh)) {
bh = tmp;
if (!BADNESS(tmp))
break;
}
tmp = tmp->b_next_free;
} while (tmp != free_list || (tmp=NULL));
/* Kids, don't try THIS at home ^^^^^. Magic */
if (!tmp) {
printk("Sleeping on free buffer ..");
} while ((tmp = tmp->b_next_free) != free_list);
if (!bh) {
sleep_on(&buffer_wait);
printk("ok\n");
goto repeat;
}
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.
*/
if (tmp->b_dirt)
sync_dev(tmp->b_dev);
/* 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);
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;
}
/* and then insert into correct position */
insert_into_queues(tmp);
return tmp;
/* 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)
......@@ -216,18 +267,54 @@ struct buffer_head * bread(int dev,int block)
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(void)
void buffer_init(long buffer_end)
{
struct buffer_head * h = start_buffer;
void * b = (void *) BUFFER_END;
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;
......
/*
* linux/fs/char_dev.c
*
* (C) 1991 Linus Torvalds
*/
#include <errno.h>
#include <sys/types.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <asm/io.h>
extern int tty_read(unsigned minor,char * buf,int count);
extern int tty_write(unsigned minor,char * buf,int count);
static int rw_ttyx(int rw,unsigned minor,char * buf,int count);
static int rw_tty(int rw,unsigned minor,char * buf,int count);
typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count,off_t * pos);
static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos)
{
return ((rw==READ)?tty_read(minor,buf,count):
tty_write(minor,buf,count));
}
static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos)
{
if (current->tty<0)
return -EPERM;
return rw_ttyx(rw,current->tty,buf,count,pos);
}
static int rw_ram(int rw,char * buf, int count, off_t *pos)
{
return -EIO;
}
static int rw_mem(int rw,char * buf, int count, off_t * pos)
{
return -EIO;
}
typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count);
static int rw_kmem(int rw,char * buf, int count, off_t * pos)
{
return -EIO;
}
static int rw_port(int rw,char * buf, int count, off_t * pos)
{
int i=*pos;
while (count-->0 && i<65536) {
if (rw==READ)
put_fs_byte(inb(i),buf++);
else
outb(get_fs_byte(buf++),i);
i++;
}
i -= *pos;
*pos += i;
return i;
}
static int rw_memory(int rw, unsigned minor, char * buf, int count, off_t * pos)
{
switch(minor) {
case 0:
return rw_ram(rw,buf,count,pos);
case 1:
return rw_mem(rw,buf,count,pos);
case 2:
return rw_kmem(rw,buf,count,pos);
case 3:
return (rw==READ)?0:count; /* rw_null */
case 4:
return rw_port(rw,buf,count,pos);
default:
return -EIO;
}
}
#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr)))
static crw_ptr crw_table[]={
NULL, /* nodev */
NULL, /* /dev/mem */
rw_memory, /* /dev/mem etc */
NULL, /* /dev/fd */
NULL, /* /dev/hd */
rw_ttyx, /* /dev/ttyx */
......@@ -23,20 +92,7 @@ static crw_ptr crw_table[]={
NULL, /* /dev/lp */
NULL}; /* unnamed pipes */
static int rw_ttyx(int rw,unsigned minor,char * buf,int count)
{
return ((rw==READ)?tty_read(minor,buf,count):
tty_write(minor,buf,count));
}
static int rw_tty(int rw,unsigned minor,char * buf,int count)
{
if (current->tty<0)
return -EPERM;
return rw_ttyx(rw,current->tty,buf,count);
}
int rw_char(int rw,int dev, char * buf, int count)
int rw_char(int rw,int dev, char * buf, int count, off_t * pos)
{
crw_ptr call_addr;
......@@ -46,5 +102,5 @@ int rw_char(int rw,int dev, char * buf, int count)
printk("dev: %04x\n",dev);
panic("Trying to r/w from/to nonexistent character device");
}
return call_addr(rw,MINOR(dev),buf,count);
return call_addr(rw,MINOR(dev),buf,count,pos);
}
/*
* linux/fs/exec.c
*
* (C) 1991 Linus Torvalds
*/
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <a.out.h>
......@@ -158,36 +165,66 @@ static int count(char ** argv)
* '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)
unsigned long p, int from_kmem)
{
int len,i;
char *tmp;
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 (!(tmp = (char *)get_fs_long(((unsigned long *) argv)+argc)))
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 */
if (p-len < 0) { /* this shouldn't happen - 128kB */
set_fs(old_fs);
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);
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;
}
......@@ -227,7 +264,11 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
struct exec ex;
unsigned long page[MAX_ARG_PAGES];
int i,argc,envc;
unsigned long p;
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)
panic("execve called from supervisor mode");
......@@ -235,49 +276,130 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
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 */
iput(inode);
return -EACCES;
retval = -EACCES;
goto exec_error2;
}
i = inode->i_mode;
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;
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]))) {
iput(inode);
return -EACCES;
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 *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);
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)) {
iput(inode);
return -ENOEXEC;
retval = -ENOEXEC;
goto exec_error2;
}
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;
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 */
if (buf)
free_s(buf, 1024);
for (i=0 ; i<32 ; i++)
current->sig_fn[i] = NULL;
current->sigaction[i].sa_handler = NULL;
for (i=0 ; i<NR_OPEN ; i++)
if ((current->close_on_exec>>i)&1)
sys_close(i);
......@@ -293,6 +415,8 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
(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)
......@@ -303,4 +427,12 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
eip[0] = ex.a_entry; /* eip, magic happens :-) */
eip[3] = p; /* stack pointer */
return 0;
exec_error2:
iput(inode);
exec_error1:
if (buf)
free(buf);
for (i=0 ; i<MAX_ARG_PAGES ; i++)
free_page(page[i]);
return(retval);
}
This diff is collapsed.
This diff is collapsed.
/*
* linux/fs/fcntl.c
*
* (C) 1991 Linus Torvalds
*/
#include <string.h>
#include <errno.h>
#include <linux/sched.h>
......
/*
* linux/fs/file_dev.c
*
* (C) 1991 Linus Torvalds
*/
#include <errno.h>
#include <fcntl.h>
......
/*
* linux/fs/file_table.c
*
* (C) 1991 Linus Torvalds
*/
#include <linux/fs.h>
struct file file_table[NR_FILE];
This diff is collapsed.
/*
* linux/fs/ioctl.c
*
* (C) 1991 Linus Torvalds
*/
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* linux/fs/truncate.c
*
* (C) 1991 Linus Torvalds
*/
#include <linux/sched.h>
#include <sys/stat.h>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -28,7 +28,7 @@ extern char _ctmp;
#define isascii(c) (((unsigned) c)<=0x7f)
#define toascii(c) (((unsigned) c)&0x7f)
#define tolower(c) (_ctmp=c,isupper(_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
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment