aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Benedict Torvalds <torvalds@cc.helsinki.fi>1991-12-08 17:51:24 +0200
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:01 -0400
commit7aadf253807264ad5561479e2a8b9de9602f966d (patch)
treed4303c76a830525f6aa6152569b3e3ee83b8c47d
parentbe068f1a017608faa9b4a0652686426df2e87689 (diff)
downloadarchive-7aadf253807264ad5561479e2a8b9de9602f966d.tar.gz
linux-0.11 availablev0.11
The subject says it all: I have uploaded linux version 0.11 to nic.funet.fi and tupac-amaru. They won't show up for a while on nic, but are already visible in pub/msdos/replace/incoming at amaru. rtx-11 is so slow to use from here that I didn't upload them there: I guess they'll show up within a couple of days (tytso?). The files uploaded were: bootimage.Z - US keyboard compressed bootimage rootimage.Z - 1200kB compressed root image linux-0.11.tar.Z - sources as86.tar.Z - linux binaries for bruce evans' 16-bit assembler and loader. INSTALL-0.11 - updated install-info This version has a lot of corrections, and is stable at least on my machine. I /hope/ every known bug is fixed, but no promises (and all unknown bugs are still there, probably with reinforcements ;-). Those who like to use caps lock as a ctrl-key, you'll have to re-patch the kernel. It's not implemented in the standard version. Linus PS. I'll be a bit busy with the #"$/% physics-course I'm taking, so I might not be as active on the net this coming week as I would like to. PPS. corsini: the problem you have with the recompiled uemacs sounds like it isn't resetting the ISIG bit in c_lflags when moving to raw mode. Search for c_lflags in the source: it should effectively be set to zero (I think) - no signals, no canonical mode etc. <INSTALL-0.11> Using Linux v0.11 Linus Torvalds 08.12.91 NOTE: Users of 0.10, please check the "changed" list before using 0.11. Booting linux Linux-0.11 can easily be booted by getting the 2 files bootimage-0.11.Z and rootimage-0.11.Z from the linux archive, uncompressing them and writing them out to disks of the same size (ie 2 1.44M floppies or 2 1.2M floppies). Writing the disks is done with the "rawrite.exe" program from dos, or with "dd" from unix. Linux is then booted simply by inserting the bootdiskette in drive A, and rebooting the machine. If everything goes well, linux will ask you to insert the root-disk after loading the system. Hopefully linux will then correctly load the shell executable, and leave you as root on the new system (prompt '# '). Using it. You can get a complete list of available commands by pressing <tab> twice: the root-disk contains mostly setup-programs needed to install the system on a harddisk. You can test them a bit, reading directories etc. In order to install linux on the harddisk, first check out your harddisk by executing the command "fdisk" - it should show you all the partitions available. If you have only 1 AT-harddisk, you should get a errormessage, just ignore it. At my system fdisk reports the following: /dev/hd1: 20476 blocks minix /dev/hd2: 19975 blocks minix /dev/hd3: 1020 blocks minix /dev/hd4: 170 blocks active 16-bit DOS (>=32M) /dev/hd6: 41641 blocks active minix The partition type given (12-bit DOS, minix etc) doesn{t really mean anything, unless it's a "extended partition", in which case you shouldn't use that partition for anything: linux doesn't yet understand them. When later using "mkfs" to make a linux file system, it won't change the output of fdisk, so fdisk may well report "DOS", while in fact you have made it a linux partition. If fdisk doesn't print out anything but errors, linux is unable to read your harddisk, and you are f**ked. Play around with the floppy version, but you won't be able to do anything real. Making a filesystem In order to really use linux, you will have to make a filesystem on your harddisk. This starts by deciding which partition you can use. Look again at what fdisk reports, and try to figure out which of the partitions you are using for DOS, OS/2 etc. /dev/hdX where X={1,2,3,4} always refers to the first harddisk, X={6,7,8,9} always refers to the second disk. /dev/hd0 and /dev/hd5 are special: they are all of the drive, and mkfs will refuse to use them for a filesystem. When you are certain you know which device points to which partition, you make a filesystem on the partition of your choice by writing: mkfs -c /dev/hdX blocks where "-c" means that you want mkfs to check for errors, "dev/hdX" is the free partition you intend to use for linux, and "blocks" is the number of blocks fdisk reports for that particular partition. NOTE! mkfs will overwrite the partition you selected, so be doubly (or triply) sure that you don't mind that. Note that when using the "-c" flag, mkfs will read through the entire partition: this can take some time. If there are read errors, mkfs will mark the particular block as bad, and continue: linux will also print a little message "harddisk I/O error". After running mkfs these messages should never occur again: if they do, your data may be corrupted. Mounting the filesystem After mkfs has exited, it's time to mount the file-system, and do the necessary things to make it a root file system. Mount the new filesystem on /user by writing: cd / mount /dev/hdX /user If you get errors for this, mkfs failed, and there is probably something seriously wrong. After mounting the device, you want to move all the files on the current floppy-root to the new fs. This can most easily be done by writing: cd /user for i in bin dev etc usr tmp floppy do cp +recursive +verbose /$i $i done sync which will also tell you what it is doing (/bin/sh -> bin/sh etc). After that, you should have a new filesystem that contains the bare necessities to start hacking linux. Play around some more, and exit linux by writing "logout or exit". This should result in child 4 died with error code 0000 # Do a couple of syncs (3 is a magic number), and reboot the machine. ALWAYS remember to sync before rebooting: terrible things happen if you don't. Using the harddisk as root Once you have happily made a new root, you will want to boot up with it. This is done by changing a word at offset 508 in the boot-image. The word (in 386-order, ie low byte first) tells the system which device to use as root: it is initially 0, which means that we want to use a floppy of the same type as the boot-disk (and this is the reason that you may not use a 360kB boot-disk even though the system fits on one: it has to be the same type as the root-diskette). In order to use the harddisk as root, this value has to be changed to point to the correct device. Harddisks have a major number of 3 under linux, and the minor nr is the same as the number X in /dev/hdX. The complete device number is then calculated with DEV_NO = (major<<8)+minor or alternatively major*256+minor. Thus /dev/hd1 is (3<<8)+1 = 0x301, /dev/hd6 = 0x0306 etc. Assuming the partition you made into the new root was /dev/hd2, you will have to write 0x0302 into the boot-image. That is, you should change the 508th byte in the image to 0x02, and the 509th byte to 0x03. There is a sample program for this in some of the older INSTALL-notes, if you don't understand what it's all about. Ok, I got the root on hd, what now? As you have probably noticed, you cannot get very far with the binaries found on the original root-diskette. So the first thing you want to do is to import some new binaries. To do this you need to tell linux what kind of floppies you have, as that's the easiest way to import things. As with harddisk, floppies have device numbers, but this time major = 2 instead of 3. The minor number is not as easy: it's a composite that tells which drive (A, B, C or D) and what type of drive (360kB, 1.2M, 1.44M etc). The formula is 'minor = type*4+nr', where nr is 0-3 for A-D, and type is 2 for 1.2M disks, and 7 for 1.44M disks. There are other types, but these should suffice for now. Thus if you have a 1.2M A-drive, and want to call it "floppy0", you have to tell linux so. This is done with the "mknod" command. mknod takes 4 paramters: the unix name of the device, a "b" or a "c" depending on whether it's a Block of Character device, and the major and minor numbers. Thus to make "floppy0" a 1.2M A-drive, you write: mknod /dev/floppy0 b 2 8 b is for Block-device, the 2 is for floppy, and the 8 is 4*2+0, where the 2 is 1.2M-drive and the 0 is drive A. Likewise to make a "floppy1" device that is a 1.44M drive in B, you write: mknod /dev/floppy1 b 2 29 where 29 = 4*7 + 1. There are a couple of standard names, for users that are used to minix (major, minor in parentheses): /dev/PS0 is a 1.44M in A (2,28), /dev/PS1 a 1.44M in B (2,29), /dev/at0 is a 1.2M in A (2,8), /dev/at1 is a 1.2M in B (2,9). Use mknod to make those that fit your computer. After you have made these special block devices, you can now read a floppy under linux. The easiest way to import things into linux is by writing a tar-file to a floppy with rawrite.exe, and then using: tar xvf /dev/floppy0 to untar it under linux. This way you can get the gcc binaries etc available from the linux-carrying sites. Changes from 0.10: - /bin/update is no longer automatically executed upon bootup: instead the file /etc/rc is evaluated by the shell. This file can then start the update process, mount andy needed filesystems, possibly fsck'ing them first. A minimal /etc/rc looks like this: /bin/update & > /etc/mtab echo " Ok." - init() restarts the shell every time it is exited: logout from the login shell results in a "child xxx died with error code yyy", a sync and then a new shell as root. - floppies work a lot better than in 0.10. Even using two floppies at the same time seems to work out ok. Reading big chunks at a time is also faster then in 0.10 (I think). - harddisk errors are handled better. Use the "-c" option in mkfs to map out all errors. - linux accepts most video-cards: harcules, MDA, CGA etc seem to work. - ^G beeps on the console, so command completion under bash etc will notify of errors. - sticky directories, corrected handling of uid/gid bits, and better handling of protections when not root. Most of these won't be noticeable until we get a init/login.
-rw-r--r--Makefile47
-rw-r--r--boot/bootsect.s140
-rw-r--r--boot/head.s24
-rw-r--r--boot/setup.s202
-rw-r--r--fs/Makefile16
-rw-r--r--fs/bitmap.c10
-rw-r--r--fs/buffer.c70
-rw-r--r--fs/char_dev.c8
-rw-r--r--fs/exec.c119
-rw-r--r--fs/inode.c69
-rw-r--r--fs/ioctl.c2
-rw-r--r--fs/namei.c43
-rw-r--r--fs/read_write.c4
-rw-r--r--fs/super.c5
-rw-r--r--include/asm/segment.h2
-rw-r--r--include/ctype.h4
-rw-r--r--include/linux/config.h16
-rw-r--r--include/linux/fs.h4
-rw-r--r--include/linux/kernel.h7
-rw-r--r--include/linux/sched.h9
-rw-r--r--include/linux/sys.h5
-rw-r--r--include/termios.h6
-rw-r--r--include/unistd.h33
-rw-r--r--init/main.c62
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/asm.s29
-rw-r--r--kernel/blk_drv/Makefile2
-rw-r--r--kernel/blk_drv/blk.h40
-rw-r--r--kernel/blk_drv/floppy.c248
-rw-r--r--kernel/blk_drv/hd.c120
-rw-r--r--kernel/blk_drv/ll_rw_blk.c54
-rw-r--r--kernel/blk_drv/ramdisk.c109
-rw-r--r--kernel/chr_drv/Makefile9
-rw-r--r--kernel/chr_drv/console.c357
-rw-r--r--kernel/chr_drv/keyboard.S133
-rw-r--r--kernel/chr_drv/tty_io.c42
-rw-r--r--kernel/chr_drv/tty_ioctl.c (renamed from fs/tty_ioctl.c)31
-rw-r--r--kernel/exit.c17
-rw-r--r--kernel/fork.c11
-rw-r--r--kernel/math/Makefile43
-rw-r--r--kernel/math/math_emulate.c42
-rw-r--r--kernel/sched.c66
-rw-r--r--kernel/signal.c4
-rw-r--r--kernel/system_call.s66
-rw-r--r--lib/Makefile4
-rw-r--r--lib/malloc.c (renamed from kernel/malloc.c)0
-rw-r--r--mm/Makefile3
-rw-r--r--mm/memory.c171
-rw-r--r--tools/build.c10
49 files changed, 1731 insertions, 788 deletions
diff --git a/Makefile b/Makefile
index 816b7bc..9de9f4f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,18 +1,30 @@
-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:
@@ -27,24 +39,30 @@ LIBS =lib/lib.a
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)
@@ -67,9 +85,8 @@ 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
+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
@@ -78,15 +95,15 @@ tmp.s: boot/bootsect.s tools/system
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:
diff --git a/boot/bootsect.s b/boot/bootsect.s
index 77fbb04..711f103 100644
--- a/boot/bootsect.s
+++ b/boot/bootsect.s
@@ -1,20 +1,26 @@
-|
-| 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
@@ -25,16 +31,16 @@ begdata:
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:
@@ -51,31 +57,31 @@ 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
@@ -83,30 +89,30 @@ ok_load_setup:
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
@@ -114,10 +120,10 @@ ok_load_setup:
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:
@@ -126,30 +132,30 @@ root_defined:
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:
diff --git a/boot/head.s b/boot/head.s
index 2c4970a..de56a74 100644
--- a/boot/head.s
+++ b/boot/head.s
@@ -41,16 +41,30 @@ startup_32:
* 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
*
* sets up a idt with 256 entries pointing to
diff --git a/boot/setup.s b/boot/setup.s
index 5034a65..2329d00 100644
--- a/boot/setup.s
+++ b/boot/setup.s
@@ -1,22 +1,22 @@
-|
-| 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
@@ -30,23 +30,39 @@ begbss:
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
@@ -58,7 +74,7 @@ start:
rep
movsb
-| Get hd1 data
+! Get hd1 data
mov ax,#0x0000
mov ds,ax
@@ -70,7 +86,7 @@ start:
rep
movsb
-| Check that there IS a hd1 :-)
+! Check that there IS a hd1 :-)
mov ax,#0x01500
mov dl,#0x81
@@ -88,20 +104,20 @@ no_disk1:
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
@@ -109,103 +125,103 @@ do_move:
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:
diff --git a/fs/Makefile b/fs/Makefile
index 989319f..97a388e 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -17,7 +17,7 @@ CPP =gcc -E -nostdinc -I../include
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)
@@ -47,10 +47,11 @@ 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/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 \
@@ -97,8 +98,3 @@ super.o : super.c ../include/linux/config.h ../include/linux/sched.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
diff --git a/fs/bitmap.c b/fs/bitmap.c
index 843c9ee..a3fc362 100644
--- a/fs/bitmap.c
+++ b/fs/bitmap.c
@@ -18,12 +18,14 @@ __asm__("cld\n\t" \
#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) ({ \
@@ -126,7 +128,7 @@ void free_inode(struct m_inode * inode)
if (!(bh=sb->s_imap[inode->i_num>>13]))
panic("nonexistent imap in superblock");
if (clear_bit(inode->i_num&8191,bh->b_data))
- panic("free_inode: bit already cleared");
+ printk("free_inode: bit already cleared.\n\r");
bh->b_dirt = 1;
memset(inode,0,sizeof(*inode));
}
@@ -157,6 +159,8 @@ struct m_inode * new_inode(int dev)
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;
diff --git a/fs/buffer.c b/fs/buffer.c
index c827631..f0f3fb3 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -81,6 +81,21 @@ int sync_dev(int dev)
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
@@ -98,25 +113,16 @@ int sync_dev(int dev)
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)
@@ -194,8 +200,7 @@ struct buffer_head * get_hash_table(int dev, int block)
* 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)
@@ -214,6 +219,7 @@ repeat:
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);
@@ -274,6 +280,40 @@ struct buffer_head * bread(int dev,int block)
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
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 8052a3e..7b07cc9 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -97,10 +97,8 @@ int rw_char(int rw,int dev, char * buf, int count, off_t * pos)
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);
}
diff --git a/fs/exec.c b/fs/exec.c
index 5fd0049..419f248 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -4,6 +4,19 @@
* (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>
@@ -25,96 +38,6 @@ extern int sys_close(int fd);
*/
#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
@@ -267,7 +190,6 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
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)
@@ -307,11 +229,9 @@ restart_interp:
* 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);
@@ -396,8 +316,9 @@ restart_interp:
}
}
/* 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++)
@@ -417,10 +338,6 @@ restart_interp:
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++));
@@ -430,8 +347,6 @@ restart_interp:
exec_error2:
iput(inode);
exec_error1:
- if (buf)
- free(buf);
for (i=0 ; i<MAX_ARG_PAGES ; i++)
free_page(page[i]);
return(retval);
diff --git a/fs/inode.c b/fs/inode.c
index 803347f..85c4107 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -40,6 +40,22 @@ static inline void unlock_inode(struct m_inode * inode)
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;
@@ -148,15 +164,19 @@ void iput(struct m_inode * inode)
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);
@@ -171,40 +191,35 @@ repeat:
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;
@@ -283,7 +298,8 @@ static void read_inode(struct m_inode * 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)))
@@ -302,7 +318,12 @@ static void write_inode(struct m_inode * inode)
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)))
diff --git a/fs/ioctl.c b/fs/ioctl.c
index cb514a9..36fc976 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -39,7 +39,7 @@ int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
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);
diff --git a/fs/namei.c b/fs/namei.c
index cad3203..fe2425c 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4,6 +4,10 @@
* (C) 1991 Linus Torvalds
*/
+/*
+ * Some corrections by tytso.
+ */
+
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
@@ -76,7 +80,7 @@ static int match(int len,const char * name,struct dir_entry * de)
/*
* 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.
@@ -596,18 +600,30 @@ int sys_rmdir(const char * name)
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;
}
@@ -667,32 +683,25 @@ int sys_unlink(const char * name)
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);
diff --git a/fs/read_write.c b/fs/read_write.c
index f8f4e3e..341274a 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -64,7 +64,7 @@ int sys_read(unsigned int fd,char * buf,int count)
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))
@@ -91,7 +91,7 @@ int sys_write(unsigned int fd,char * buf,int count)
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))
diff --git a/fs/super.c b/fs/super.c
index 25ba5b6..b73fdca 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -74,6 +74,7 @@ struct super_block * get_super(int dev)
void put_super(int dev)
{
struct super_block * sb;
+ struct m_inode * inode;
int i;
if (dev == ROOT_DEV) {
@@ -183,9 +184,9 @@ int sys_umount(char * dev_name)
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;
diff --git a/include/asm/segment.h b/include/asm/segment.h
index 936ed72..c03657f 100644
--- a/include/asm/segment.h
+++ b/include/asm/segment.h
@@ -41,6 +41,7 @@ __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()
@@ -62,4 +63,3 @@ extern inline void set_fs(unsigned long val)
__asm__("mov %0,%%fs"::"a" ((unsigned short) val));
}
-
diff --git a/include/ctype.h b/include/ctype.h
index ad7cb77..7acf55d 100644
--- a/include/ctype.h
+++ b/include/ctype.h
@@ -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 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
diff --git a/include/linux/config.h b/include/linux/config.h
index e515cf1..b706122 100644
--- a/include/linux/config.h
+++ b/include/linux/config.h
@@ -6,9 +6,17 @@
* 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
@@ -34,7 +42,7 @@
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
diff --git a/include/linux/fs.h b/include/linux/fs.h
index da58aec..7a90b10 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -26,6 +26,7 @@
#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);
@@ -66,8 +67,8 @@ typedef char buffer_block[BLOCK_SIZE];
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 */
@@ -186,6 +187,7 @@ extern struct buffer_head * getblk(int dev, int 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);
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 2f2fb75..cb40dd5 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -6,10 +6,10 @@ 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);
-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
@@ -19,3 +19,4 @@ void free_s(void *obj, int size);
* permissions checks first, and check suser() last.
*/
#define suser() (current->euid == 0)
+
diff --git a/include/linux/sched.h b/include/linux/sched.h
index f41827f..3407bb9 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -27,7 +27,7 @@
#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);
@@ -85,7 +85,7 @@ struct task_struct {
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;
@@ -97,6 +97,7 @@ struct task_struct {
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 */
@@ -112,12 +113,12 @@ struct task_struct {
#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}, \
diff --git a/include/linux/sys.h b/include/linux/sys.h
index 33f172c..c538fc1 100644
--- a/include/linux/sys.h
+++ b/include/linux/sys.h
@@ -68,6 +68,8 @@ extern int sys_setsid();
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,
@@ -80,4 +82,5 @@ sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
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 };
diff --git a/include/termios.h b/include/termios.h
index f707674..2b7b913 100644
--- a/include/termios.h
+++ b/include/termios.h
@@ -31,6 +31,7 @@
#define TIOCMSET 0x5418
#define TIOCGSOFTCAR 0x5419
#define TIOCSSOFTCAR 0x541A
+#define TIOCINQ 0x541B
struct winsize {
unsigned short ws_row;
@@ -145,6 +146,8 @@ struct termios {
#define B9600 0000015
#define B19200 0000016
#define B38400 0000017
+#define EXTA B19200
+#define EXTB B38400
#define CSIZE 0000060
#define CS5 0000000
#define CS6 0000020
@@ -159,6 +162,9 @@ struct termios {
#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
diff --git a/include/unistd.h b/include/unistd.h
index 4418363..bf71dcb 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -5,7 +5,7 @@
#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 */
@@ -125,16 +125,20 @@
#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; \
}
@@ -142,12 +146,12 @@ 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; \
}
@@ -155,12 +159,12 @@ 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; \
}
@@ -168,13 +172,14 @@ 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__ */
diff --git a/init/main.c b/init/main.c
index ce55e24..25de9e0 100644
--- a/init/main.c
+++ b/init/main.c
@@ -48,6 +48,7 @@ extern void chr_dev_init(void);
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;
@@ -96,6 +97,7 @@ static void time_init(void)
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;
@@ -111,11 +113,17 @@ void main(void) /* This really IS void, no error here. */
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();
@@ -151,35 +159,51 @@ static int printf(const char *fmt, ...)
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() */
}
diff --git a/kernel/Makefile b/kernel/Makefile
index d75e141..07d7f61 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -37,6 +37,7 @@ clean:
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
diff --git a/kernel/asm.s b/kernel/asm.s
index c19900f..e72a9ab 100644
--- a/kernel/asm.s
+++ b/kernel/asm.s
@@ -12,7 +12,7 @@
*/
.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
@@ -74,28 +74,6 @@ _invalid_op:
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
@@ -114,10 +92,7 @@ _irq13:
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
diff --git a/kernel/blk_drv/Makefile b/kernel/blk_drv/Makefile
index a830c3f..0fd7cb0 100644
--- a/kernel/blk_drv/Makefile
+++ b/kernel/blk_drv/Makefile
@@ -24,7 +24,7 @@ CPP =gcc -E -nostdinc -I../../include
$(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)
diff --git a/kernel/blk_drv/blk.h b/kernel/blk_drv/blk.h
index 1682465..c4a7cde 100644
--- a/kernel/blk_drv/blk.h
+++ b/kernel/blk_drv/blk.h
@@ -2,7 +2,17 @@
#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
@@ -22,9 +32,15 @@ struct request {
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);
@@ -41,7 +57,16 @@ extern struct task_struct * wait_for_request;
* 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
@@ -68,7 +93,9 @@ extern struct task_struct * wait_for_request;
#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)
@@ -103,13 +130,10 @@ repeat: \
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
diff --git a/kernel/blk_drv/floppy.c b/kernel/blk_drv/floppy.c
index 47ee961..2500a88 100644
--- a/kernel/blk_drv/floppy.c
+++ b/kernel/blk_drv/floppy.c
@@ -5,6 +5,21 @@
*/
/*
+ * 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
* handler may not sleep, or a kernel panic will happen. Thus I cannot
@@ -26,12 +41,11 @@
#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))
@@ -39,11 +53,11 @@ __asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port))
#define TYPE(x) ((x)>>2)
#define DRIVE(x) ((x)&0x03)
/*
- * Note that MAX_ERRORS=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()'
@@ -58,14 +72,15 @@ static unsigned char reply_buffer[MAX_REPLIES];
/*
* 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 */
@@ -102,16 +117,33 @@ static unsigned char sector = 0;
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;
@@ -129,6 +161,7 @@ static void setup_DMA(void)
{
long addr = (long) CURRENT->buffer;
+ cli();
if (addr >= 0x100000) {
addr = (long) tmp_floppy_area;
if (command == FD_WRITE)
@@ -155,6 +188,7 @@ static void setup_DMA(void)
immoutb_p(3,5);
/* activate DMA 2 */
immoutb_p(0|2,10);
+ sti();
}
static void output_byte(char byte)
@@ -162,13 +196,16 @@ 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");
}
@@ -176,56 +213,61 @@ static int result(void)
{
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);
@@ -237,36 +279,26 @@ static void seek_interrupt(void)
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();
}
/*
@@ -284,6 +316,14 @@ static void transfer(void)
}
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);
@@ -293,6 +333,8 @@ static void transfer(void)
output_byte(FD_RECALIBRATE);
output_byte(head<<2 | current_drive);
}
+ if (reset)
+ do_fd_request();
}
/*
@@ -300,59 +342,95 @@ static void transfer(void)
*/
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) {
@@ -364,6 +442,8 @@ void do_fd_request(void)
head = block % floppy->head;
track = block / floppy->head;
seek_track = track << floppy->stretch;
+ if (seek_track != current_track)
+ seek = 1;
sector++;
if (CURRENT->cmd == READ)
command = FD_READ;
@@ -377,6 +457,6 @@ void do_fd_request(void)
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);
}
diff --git a/kernel/blk_drv/hd.c b/kernel/blk_drv/hd.c
index bfb8701..23c58d4 100644
--- a/kernel/blk_drv/hd.c
+++ b/kernel/blk_drv/hd.c
@@ -9,6 +9,8 @@
* 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>
@@ -23,10 +25,20 @@
#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.
*/
@@ -53,12 +65,14 @@ __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
__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;
@@ -85,6 +99,40 @@ int sys_setup(void * BIOS)
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",
@@ -103,22 +151,24 @@ int sys_setup(void * BIOS)
}
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))
@@ -138,7 +188,7 @@ static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
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);
@@ -153,8 +203,8 @@ static int drive_busy(void)
{
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;
@@ -169,26 +219,19 @@ static void reset_controller(void)
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)
@@ -198,25 +241,27 @@ 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();
}
@@ -225,11 +270,13 @@ static void write_intr(void)
{
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;
}
@@ -237,6 +284,13 @@ static void write_intr(void)
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;
@@ -259,13 +313,25 @@ void do_hd_request(void)
"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) {
@@ -277,7 +343,7 @@ void do_hd_request(void)
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);
}
diff --git a/kernel/blk_drv/ll_rw_blk.c b/kernel/blk_drv/ll_rw_blk.c
index ae8741b..f57d998 100644
--- a/kernel/blk_drv/ll_rw_blk.c
+++ b/kernel/blk_drv/ll_rw_blk.c
@@ -67,49 +67,69 @@ static void add_request(struct blk_dev_struct * dev, struct request * req)
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;
@@ -127,8 +147,10 @@ void ll_rw_block(int rw, struct buffer_head * bh)
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);
}
diff --git a/kernel/blk_drv/ramdisk.c b/kernel/blk_drv/ramdisk.c
index 0131376..dc99f7c 100644
--- a/kernel/blk_drv/ramdisk.c
+++ b/kernel/blk_drv/ramdisk.c
@@ -1,13 +1,15 @@
/*
* 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>
@@ -15,26 +17,109 @@
#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;
}
diff --git a/kernel/chr_drv/Makefile b/kernel/chr_drv/Makefile
index 1405638..9e2b848 100644
--- a/kernel/chr_drv/Makefile
+++ b/kernel/chr_drv/Makefile
@@ -24,7 +24,8 @@ CPP =gcc -E -nostdinc -I../../include
$(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)
@@ -59,3 +60,9 @@ tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \
../../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
diff --git a/kernel/chr_drv/console.c b/kernel/chr_drv/console.c
index 3ca4169..ae6bbde 100644
--- a/kernel/chr_drv/console.c
+++ b/kernel/chr_drv/console.c
@@ -12,6 +12,7 @@
* 'void con_write(struct tty_queue * queue)'
* Hopefully this will be a rather complete VT102 implementation.
*
+ * Beeping thanks to John T Kohl.
*/
/*
@@ -21,6 +22,11 @@
* 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>
@@ -29,27 +35,48 @@
/*
* 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
@@ -57,93 +84,128 @@ static unsigned char attr=0x07;
*/
#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();
@@ -153,7 +215,7 @@ static void ri(void)
{
if (y>top) {
y--;
- pos -= columns<<1;
+ pos -= video_size_row;
return;
}
scrdown();
@@ -170,7 +232,7 @@ static void del(void)
if (x) {
pos -= 2;
x--;
- *(unsigned short *)pos = 0x0720;
+ *(unsigned short *)pos = video_erase_char;
}
}
@@ -189,7 +251,7 @@ static void csi_J(int par)
start = origin;
break;
case 2: /* erase whole display */
- count = columns*lines;
+ count = video_num_columns * video_num_lines;
start = origin;
break;
default:
@@ -199,7 +261,7 @@ static void csi_J(int par)
"rep\n\t"
"stosw\n\t"
::"c" (count),
- "D" (start),"a" (0x0720)
+ "D" (start),"a" (video_erase_char)
:"cx","di");
}
@@ -210,18 +272,18 @@ static void csi_K(int par)
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;
@@ -230,7 +292,7 @@ static void csi_K(int par)
"rep\n\t"
"stosw\n\t"
::"c" (count),
- "D" (start),"a" (0x0720)
+ "D" (start),"a" (video_erase_char)
:"cx","di");
}
@@ -251,10 +313,10 @@ void csi_m(void)
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();
}
@@ -274,10 +336,10 @@ static void respond(struct tty_struct * tty)
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;
@@ -292,7 +354,7 @@ static void insert_line(void)
oldtop=top;
oldbottom=bottom;
top=y;
- bottom=lines;
+ bottom = video_num_lines;
scrdown();
top=oldtop;
bottom=oldbottom;
@@ -303,14 +365,14 @@ static void delete_char(void)
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)
@@ -320,7 +382,7 @@ static void delete_line(void)
oldtop=top;
oldbottom=bottom;
top=y;
- bottom=lines;
+ bottom = video_num_lines;
scrup();
top=oldtop;
bottom=oldbottom;
@@ -328,38 +390,38 @@ static void delete_line(void)
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--)
@@ -391,9 +453,9 @@ void con_write(struct tty_struct * tty)
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"
@@ -419,13 +481,14 @@ void con_write(struct tty_struct * tty)
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;
@@ -522,9 +585,9 @@ void con_write(struct tty_struct * tty)
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];
}
@@ -547,10 +610,74 @@ void con_write(struct tty_struct * tty)
* 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);
@@ -559,3 +686,25 @@ void con_init(void)
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;
+}
diff --git a/kernel/chr_drv/keyboard.S b/kernel/chr_drv/keyboard.S
index 120ca12..709ef9a 100644
--- a/kernel/chr_drv/keyboard.S
+++ b/kernel/chr_drv/keyboard.S
@@ -6,6 +6,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>
@@ -26,7 +28,6 @@ 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
-flags: .byte 0 /* 0x1 - map caps lock to ctrl */
/*
* con_int is the real interrupt routine that reads the
@@ -138,9 +139,7 @@ unrshift:
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
@@ -153,9 +152,7 @@ set_leds:
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
@@ -197,8 +194,13 @@ ok_cur: shll $16,%eax
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"
@@ -339,6 +341,108 @@ alt_map:
.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
@@ -389,19 +493,6 @@ minus: cmpb $1,e0
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
@@ -423,7 +514,7 @@ key_table:
.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 */
diff --git a/kernel/chr_drv/tty_io.c b/kernel/chr_drv/tty_io.c
index ec92914..b8da643 100644
--- a/kernel/chr_drv/tty_io.c
+++ b/kernel/chr_drv/tty_io.c
@@ -6,8 +6,9 @@
/*
* '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>
@@ -49,10 +50,10 @@
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 */
@@ -62,8 +63,8 @@ struct tty_struct tty_table[] = {
{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,
@@ -75,8 +76,8 @@ struct tty_struct tty_table[] = {
{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,
@@ -158,6 +159,21 @@ void copy_to_cooked(struct tty_struct * tty)
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 ||
@@ -181,13 +197,13 @@ void copy_to_cooked(struct tty_struct * tty)
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;
}
}
@@ -221,8 +237,8 @@ int tty_read(unsigned channel, char * buf, int nr)
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))
diff --git a/fs/tty_ioctl.c b/kernel/chr_drv/tty_ioctl.c
index fd936dc..e4e3745 100644
--- a/fs/tty_ioctl.c
+++ b/kernel/chr_drv/tty_ioctl.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/tty_ioctl.c
+ * linux/kernel/chr_drv/tty_ioctl.c
*
* (C) 1991 Linus Torvalds
*/
@@ -11,9 +11,31 @@
#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();
@@ -47,6 +69,7 @@ static int set_termios(struct tty_struct * tty, struct termios * termios)
for (i=0 ; i< (sizeof (*termios)) ; i++)
((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
+ change_speed(tty);
return 0;
}
@@ -85,6 +108,7 @@ static int set_termio(struct tty_struct * tty, struct termio * termio)
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;
}
@@ -151,6 +175,11 @@ int tty_ioctl(int dev, int cmd, int arg)
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:
diff --git a/kernel/exit.c b/kernel/exit.c
index 1b0aa03..2406ebe 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -94,6 +94,8 @@ static void tell_father(int pid)
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);
}
@@ -104,8 +106,12 @@ int do_exit(long code)
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);
@@ -113,6 +119,8 @@ int do_exit(long code)
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)
@@ -133,7 +141,7 @@ int sys_exit(int error_code)
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);
@@ -164,8 +172,9 @@ repeat:
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;
diff --git a/kernel/fork.c b/kernel/fork.c
index f776896..38a997a 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -50,6 +50,7 @@ int copy_mem(int nr,struct task_struct * p)
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)) {
@@ -76,8 +77,9 @@ int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
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;
@@ -109,8 +111,9 @@ int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
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;
}
@@ -121,9 +124,11 @@ int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
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;
}
diff --git a/kernel/math/Makefile b/kernel/math/Makefile
new file mode 100644
index 0000000..7e0b4c4
--- /dev/null
+++ b/kernel/math/Makefile
@@ -0,0 +1,43 @@
+#
+# 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:
diff --git a/kernel/math/math_emulate.c b/kernel/math/math_emulate.c
new file mode 100644
index 0000000..825e528
--- /dev/null
+++ b/kernel/math/math_emulate.c
@@ -0,0 +1,42 @@
+/*
+ * 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);
+}
diff --git a/kernel/sched.c b/kernel/sched.c
index 6788312..15d839b 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -25,8 +25,13 @@
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)
@@ -73,16 +78,17 @@ void math_state_restore()
{
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;
}
/*
@@ -196,46 +202,28 @@ 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);
+ 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];
@@ -316,10 +304,18 @@ void add_timer(long jiffies, void (*fn)(void))
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) {
@@ -403,6 +399,8 @@ void sched_init(void)
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 */
diff --git a/kernel/signal.c b/kernel/signal.c
index 79fb6ca..055fc20 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -84,13 +84,13 @@ void do_signal(long signr,long eax, long ebx, long ecx, long edx,
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) {
diff --git a/kernel/system_call.s b/kernel/system_call.s
index 5f7cafc..c96826c 100644
--- a/kernel/system_call.s
+++ b/kernel/system_call.s
@@ -58,7 +58,7 @@ sa_mask = 4
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
@@ -66,6 +66,7 @@ nr_system_calls = 70
*/
.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:
@@ -127,6 +128,51 @@ ret_from_sys_call:
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
push %es # into them. %fs is used by _system_call
@@ -182,17 +228,19 @@ _hd_interrupt:
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
@@ -211,10 +259,12 @@ _floppy_interrupt:
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
diff --git a/lib/Makefile b/lib/Makefile
index bc1ecf3..a4a33b5 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -25,7 +25,7 @@ CPP =gcc -E -nostdinc -I../include
-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)
@@ -56,6 +56,8 @@ errno.s errno.o : errno.c
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
diff --git a/kernel/malloc.c b/lib/malloc.c
index 42723a7..42723a7 100644
--- a/kernel/malloc.c
+++ b/lib/malloc.c
diff --git a/mm/Makefile b/mm/Makefile
index 3f20add..d431718 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -33,4 +33,5 @@ dep:
### 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
diff --git a/mm/memory.c b/mm/memory.c
index 66bfa6c..a27cd78 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4,13 +4,37 @@
* (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))
@@ -22,6 +46,9 @@ __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) \
@@ -62,7 +89,7 @@ return __res;
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;
@@ -173,7 +200,7 @@ unsigned long put_page(unsigned long page,unsigned long address)
/* NOTE !!! This uses the fact that _pg_dir=0 */
- if (page < LOW_MEM || page > HIGH_MEMORY)
+ 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);
@@ -187,6 +214,7 @@ unsigned long put_page(unsigned long page,unsigned long address)
page_table = (unsigned long *) tmp;
}
page_table[(address>>12) & 0x3ff] = page | 7;
+/* no need for invalidate */
return page;
}
@@ -197,13 +225,15 @@ void un_wp_page(unsigned long * table_entry)
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);
}
@@ -211,9 +241,17 @@ void un_wp_page(unsigned long * table_entry)
* 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)))));
@@ -233,14 +271,129 @@ void write_verify(unsigned long address)
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)
diff --git a/tools/build.c b/tools/build.c
index 2118b27..69e25d0 100644
--- a/tools/build.c
+++ b/tools/build.c
@@ -16,6 +16,10 @@
* 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 */
@@ -28,6 +32,8 @@
#define MINIX_HEADER 32
#define GCC_HEADER 1024
+#define SYS_SIZE 0x2000
+
#define DEFAULT_MAJOR_ROOT 3
#define DEFAULT_MINOR_ROOT 6
@@ -45,7 +51,7 @@ void die(char * str)
void usage(void)
{
- die("Usage: build bootsect setup system [> image]");
+ die("Usage: build bootsect setup system [rootdev] [> image]");
}
int main(int argc, char ** argv)
@@ -156,5 +162,7 @@ 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);
}