aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Benedict Torvalds <torvalds@klaava.Helsinki.FI>1991-11-04 00:00:00 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:01 -0400
commitbe068f1a017608faa9b4a0652686426df2e87689 (patch)
treefff959a22d75c4a82192c99f1b4caa26a236eafc
parent8331b82c1ac6ebe96db75d5853b4329b1502d5d3 (diff)
downloadarchive-be068f1a017608faa9b4a0652686426df2e87689.tar.gz
Linux-0.10v0.10
[ Committer's note: official announcement and exact release date unknown. Some posts are included below to narrow the possible release date. There is a possibility that this version might not be pristine. Also this commit folds the 0.02 version which is apparently lost. ] <INSTALL-0.10> Warning: I have personally not done this the hard way, so I don't know what problems could surface. In general, this version is still meant for people with minix: they are more used to the system, and can do some things that DOS-based persons cannot. If you have only DOS, expect some troubles. As the version number suggests, this is still not the final product. This is a "fast hack", meant as a minimal guide to what you must do. I'll expand this as soon as people tell me what they have problems with etc etc. If somebody who has successfully installed the system wants to write something better, I'd be delighted. This guide stinks to high heaven. Installing Linux-0.10 on your system There are 5 major steps in installing linux on your system: 1 - BACK UP ANY IMPORTANT DATA. Linux accesses your hardware directly, and if your hardware differs from mine, you could be in for a nasty surprise. Doublecheck that your hardware is compatible: AT style harddisk, VGA controller. (If somebody has EGA, please tell me if the screen driver should happen to work) 2 - Make a file-system on your harddisk. This is easy if you have minix, but if you haven't got minix, you'll have to get the minix demo-disk from somewhere (plains.nodak.edu is one place), and use that. There should be a manual accompanying the demo-disk, and you had better read that carefully. Although this version of linux will boot up without minix, a knowledge of minix would help. Especially if you have never done any unix work, you'll be very confused. Making a filesystem means getting a empty partition (with DOS fdisk or similar), and using the 'mkfs /dev/hdX nnn' command to write out a empty file-system. 3 - copy the diskimages to two floppies. Again, under minix (or any unix), this is easy, as you can just do a simple 'dd' to a floppy, but from within MS-DOS this might be a bit trickier. 'debug' should be able to write diskettes directly, or you could get the sources to "raw-write" from the same place as you got the minix demo disk, and modify them to write out any disk image (or do they do that already?). NOTE! The floppies MUST be of the same type: even though the boot-image will fit nicely on a 360kB floppy, you have to write it to the same type of floppy as the root-image. That means a 1.2M or 1.44M floppy. The reason is that the floppy-type is determined at boot-time from the boot-floppy. Thus the same binary works on both 3.5" and 5.25" drives. 4 - boot up from floppy. This should be obvious. Having a floppy as root-device isn't very fast (especially on a machine with less than 6MB total ram -> small buffer cache), but it works (I hope). Test the programs on the root-floppy (cat mkdir etc). 5 - Mount the harddisk partition (I do it on /user: ie 'mount /dev/hdX /user'), and copy the file system over to the new partition. The following is a example of how to do this: $ cd /user $ mkdir usr $ for i in bin etc usr/bin usr/root mtools > do > mkdir $i > cp `ls -A /$i` $i > done $ mkdir dev $ cd dev $ for i in 0 1 2 3 4 5 6 7 8 9 > do > mknod 'hd'$i b 3 $i > done $ mknod tty c 5 0 $ mknod tty0 c 4 0 $ mknod tty1 c 4 1 $ mknod tty2 c 4 2 You should now have a filesystem you could boot from. Play around a bit, try to get aquainted with the new system. Log out when you've had enough. 6 - Changing the boot-diskette use your new harddisk partition as root. The root device to be used for linux is encoded in a word at offset 508 in the boot image. Normally this is 0, meaning that the root is to be the same type of floppy as was used in the boot process. This can be changed to whatever you like. Use a short program like the one at the end to change the word (I assume everybody has access to some kind of C compiler, be it under dos or unix). You can then write out the new bootdisk, and boot from it, now using the harddisk as root (much faster). Once you have successfully done that you might want to install additional programs (gcc etc) by reading them from a dos-floppy with 'mcopy'. Linus (torvalds@kruuna.helsinki.fi) ------ example program: use 'a.out < oldboot > newboot' ---- #include <unistd.h> char tmp[512]; void main(void) { int i; if (512 != read(0,tmp,512)) exit(1); if (0xAA55 != *((unsigned short *)(tmp+510))) exit(2); *((unsigned short *)(tmp+508)) = NEW_DEV; if (512 != write(1,tmp,512)) exit(3); while ((i=read(0,tmp,512)) > 0) if (i != write(1,tmp,i)) exit(4); exit(0); } ------- Devices: Harddisks: 0x301 - /dev/hd1 - first partition on first drive ... 0x304 - /dev/hd2 - fourth partition on first drive 0x306 - /dev/hd1 - first partition on second drive ... 0x309 - /dev/hd2 - fourth partition on second drive 0x300 - /dev/hd0 - the whole first drive. BE CAREFUL 0x305 - /dev/hd5 - the whole second drive. BE CAREFUL Floppies: 0x208 - 1.2M in A 0x209 - 1.2M in B 0x21C - 1.44M in A 0x21D - 1.44M in B ----- From: torvalds@klaava.Helsinki.FI (Linus Benedict Torvalds) Newsgroups: comp.os.minix Subject: Free minix-like kernel sources for 386-AT Keywords: 386, preliminary version Message-ID: <1991Oct5.054106.4647@klaava.Helsinki.FI> Date: 5 Oct 91 05:41:06 GMT Organization: University of Helsinki Do you pine for the nice days of minix-1.1, when men were men and wrote their own device drivers? Are you without a nice project and just dying to cut your teeth on a OS you can try to modify for your needs? Are you finding it frustrating when everything works on minix? No more all- nighters to get a nifty program working? Then this post might be just for you :-) As I mentioned a month(?) ago, I'm working on a free version of a minix-lookalike for AT-386 computers. It has finally reached the stage where it's even usable (though may not be depending on what you want), and I am willing to put out the sources for wider distribution. It is just version 0.02 (+1 (very small) patch already), but I've successfully run bash/gcc/gnu-make/gnu-sed/compress etc under it. Sources for this pet project of mine can be found at nic.funet.fi (128.214.6.100) in the directory /pub/OS/Linux. The directory also contains some README-file and a couple of binaries to work under linux (bash, update and gcc, what more can you ask for :-). Full kernel source is provided, as no minix code has been used. Library sources are only partially free, so that cannot be distributed currently. The system is able to compile "as-is" and has been known to work. Heh. Sources to the binaries (bash and gcc) can be found at the same place in /pub/gnu. ALERT! WARNING! NOTE! These sources still need minix-386 to be compiled (and gcc-1.40, possibly 1.37.1, haven't tested), and you need minix to set it up if you want to run it, so it is not yet a standalone system for those of you without minix. I'm working on it. You also need to be something of a hacker to set it up (?), so for those hoping for an alternative to minix-386, please ignore me. It is currently meant for hackers interested in operating systems and 386's with access to minix. The system needs an AT-compatible harddisk (IDE is fine) and EGA/VGA. If you are still interested, please ftp the README/RELNOTES, and/or mail me for additional info. I can (well, almost) hear you asking yourselves "why?". Hurd will be out in a year (or two, or next month, who knows), and I've already got minix. This is a program for hackers by a hacker. I've enjouyed doing it, and somebody might enjoy looking at it and even modifying it for their own needs. It is still small enough to understand, use and modify, and I'm looking forward to any comments you might have. I'm also interested in hearing from anybody who has written any of the utilities/library functions for minix. If your efforts are freely distributable (under copyright or even public domain), I'd like to hear from you, so I can add them to the system. I'm using Earl Chews estdio right now (thanks for a nice and working system Earl), and similar works will be very wellcome. Your (C)'s will of course be left intact. Drop me a line if you are willing to let me use your code. Linus ----- From: torvalds@klaava.Helsinki.FI (Linus Benedict Torvalds) Newsgroups: comp.os.minix Subject: Re: [comp.os.minix] Free minix-like kernel sources for 386-AT Summary: Still only ftp Message-ID: <1991Oct31.101252.13981@klaava.Helsinki.FI> Date: 31 Oct 91 10:12:52 GMT References: <3255@cluster.cs.su.oz.au> <AA7ig3fuR5@inzer.demos.su> Organization: University of Helsinki In article <AA7ig3fuR5@inzer.demos.su> moroz@inzer.demos.su writes: >chrisa@extro.ucc.su.OZ.AU (C. G. Albone) writes: >>Hello all.. >> I missed the original posting, so could someone please tell me >>how I may obtain the sources. > And me too !!!!!!!!!!!!!! > Also, are them available via e-mail (mail server or smth), as I'm >in the former Soviet Union and can't do any FTP. Ok, as I've gotten quite a few questions, I guess I'd better follow up again. Linux is currently ONLY available via ftp from nic.funet.fi, directory /pub/OS/Linux. As the sources change rather rapidly (next release due out this weekend after I have tested some more), it is also currently impractical to make them available from other places. There is a mail-server possibility fron nic, but I think it's still in testing (you could try mailing "mailserver@nic.funet.fi" with "help" in the body, but I don't know if it will work). Linux is a full kernel that has so far worked on a number (5-10?) of at-386 (and one 486 as far as I know). It supports GNU cc (gcc), bash and some other free stuff. It is currently more of a hackers kernel (and minix-386 is needed, but that will change with this weeks release), and the current version number is 0.03 (next is 0.10 I think). Good things about linux: - it's free, full source, and I try to correct bugs you find. - it's a bit faster than minix, I think. - uses paging for memory management (not to disk yet) - multithreaded fs (but then you can get patches to minix that do similar stuff) - mostly full termios and vt100-console. - most things easy to port (easier than to minix). Bad points: - ONLY 386/486 - early versions: there might be lots of bugs, and you might need to port/hack things to work. - minix is recommended even for the upcoming version that doesn't absolutely need it. - currently only VGA (EGA?) support, limited keyboard drivers (US and Finnish) etc You can mail me for more info. "finger torvalds@kruuna.helsinki.fi" might tell you something too. Linus (torvalds@kruuna.helsinki.fi) ----- Date: Thu, 7 Nov 91 14:19:23 -0500 To: linux-activists-mtg@tsx-11.MIT.EDU From: Robert Lund <rml@bighorn.uswest.com> Reply-To: tytso@Athena.MIT.EDU Hello, I have installed Linux 0.10 using the minix demo to build the root file system on a hd partition. I couldn't figure out how to use the mtools commands to get gccbin, utils, etc. from DOS to linux but I did discover an alternate approach that might prove useful to others. I happen to have a 1.44 drive as my A drive so ubder linux I did mknod /dev/PS0 B 2 28 Next, I formated a 1.44 floppy under DOS. Then, I uncompressed the tar files that I wanted to get from DOS to linux (I actually uncompressed under UNIX but I assume that a 16 bit uncompress utility under DOS would work). Then, I used the rawrite command available with the minix demo to dump a tar file, e.g. gccbin.tar, to the 1.44 floppy in the A drive (back under DOS again) Next, I booted Linux and did tar -xvf /dev/PS0 and lo and behold, it worked; tar read the raw device and successfully extracted the files. Hope this helps someone. Bob Lund
-rw-r--r--Makefile44
-rw-r--r--boot/boot.s329
-rw-r--r--boot/bootsect.s254
-rw-r--r--boot/head.s85
-rw-r--r--boot/setup.s215
-rw-r--r--fs/Makefile67
-rw-r--r--fs/bitmap.c6
-rw-r--r--fs/block_dev.c63
-rw-r--r--fs/buffer.c203
-rw-r--r--fs/char_dev.c94
-rw-r--r--fs/exec.c224
-rw-r--r--fs/fcntl.c6
-rw-r--r--fs/file_dev.c6
-rw-r--r--fs/file_table.c6
-rw-r--r--fs/inode.c29
-rw-r--r--fs/ioctl.c6
-rw-r--r--fs/namei.c137
-rw-r--r--fs/open.c52
-rw-r--r--fs/pipe.c71
-rw-r--r--fs/read_write.c14
-rw-r--r--fs/stat.c19
-rw-r--r--fs/super.c244
-rw-r--r--fs/truncate.c6
-rw-r--r--fs/tty_ioctl.c9
-rw-r--r--include/asm/segment.h27
-rw-r--r--include/ctype.h2
-rw-r--r--include/linux/config.h69
-rw-r--r--include/linux/fdreg.h71
-rw-r--r--include/linux/fs.h55
-rw-r--r--include/linux/hdreg.h34
-rw-r--r--include/linux/kernel.h13
-rw-r--r--include/linux/sched.h16
-rw-r--r--include/linux/sys.h5
-rw-r--r--include/linux/tty.h13
-rw-r--r--include/signal.h3
-rw-r--r--include/unistd.h1
-rw-r--r--init/main.c52
-rw-r--r--kernel/Makefile54
-rw-r--r--kernel/asm.s28
-rw-r--r--kernel/blk_drv/Makefile58
-rw-r--r--kernel/blk_drv/blk.h116
-rw-r--r--kernel/blk_drv/floppy.c382
-rw-r--r--kernel/blk_drv/hd.c283
-rw-r--r--kernel/blk_drv/ll_rw_blk.c143
-rw-r--r--kernel/blk_drv/ramdisk.c40
-rw-r--r--kernel/chr_drv/Makefile61
-rw-r--r--kernel/chr_drv/console.c (renamed from kernel/console.c)29
-rw-r--r--kernel/chr_drv/keyboard.S (renamed from kernel/keyboard.s)104
-rw-r--r--kernel/chr_drv/rs_io.s (renamed from kernel/rs_io.s)10
-rw-r--r--kernel/chr_drv/serial.c (renamed from kernel/serial.c)6
-rw-r--r--kernel/chr_drv/tty_io.c (renamed from kernel/tty_io.c)35
-rw-r--r--kernel/exit.c137
-rw-r--r--kernel/fork.c6
-rw-r--r--kernel/hd.c413
-rw-r--r--kernel/malloc.c232
-rw-r--r--kernel/mktime.c6
-rw-r--r--kernel/panic.c13
-rw-r--r--kernel/printk.c8
-rw-r--r--kernel/sched.c208
-rw-r--r--kernel/signal.c119
-rw-r--r--kernel/sys.c120
-rw-r--r--kernel/system_call.s112
-rw-r--r--kernel/traps.c25
-rw-r--r--kernel/vsprintf.c6
-rw-r--r--lib/Makefile27
-rw-r--r--lib/_exit.c6
-rw-r--r--lib/close.c6
-rw-r--r--lib/ctype.c6
-rw-r--r--lib/dup.c6
-rw-r--r--lib/errno.c6
-rw-r--r--lib/execve.c6
-rw-r--r--lib/open.c6
-rw-r--r--lib/setsid.c6
-rw-r--r--lib/string.c6
-rw-r--r--lib/wait.c6
-rw-r--r--lib/write.c6
-rw-r--r--mm/Makefile3
-rw-r--r--mm/memory.c49
-rw-r--r--mm/page.s6
-rw-r--r--tools/build.c106
80 files changed, 4109 insertions, 1452 deletions
diff --git a/Makefile b/Makefile
index d9d9fab..816b7bc 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,4 @@
-#
-# Makefile for linux.
-# If you don't have '-mstring-insns' in your gcc (and nobody but me has :-)
-# remove them from the CFLAGS defines.
-#
+ROOTDEV= /dev/hd3
AS86 =as -0 -a
CC86 =cc -0
@@ -13,9 +9,10 @@ LD =gld
LDFLAGS =-s -x -M
CC =gcc
CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs
-CPP =gcc -E -nostdinc -Iinclude
+CPP =cpp -nostdinc -Iinclude
ARCHIVES=kernel/kernel.o mm/mm.o fs/fs.o
+DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a
LIBS =lib/lib.a
.c.s:
@@ -29,8 +26,8 @@ LIBS =lib/lib.a
all: Image
-Image: boot/boot tools/system tools/build
- tools/build boot/boot tools/system > Image
+Image: boot/bootsect boot/setup tools/system tools/build
+ tools/build boot/bootsect boot/setup tools/system $(ROOTDEV) > Image
sync
tools/build: tools/build.c
@@ -41,12 +38,19 @@ tools/build: tools/build.c
boot/head.o: boot/head.s
tools/system: boot/head.o init/main.o \
- $(ARCHIVES) $(LIBS)
+ $(ARCHIVES) $(DRIVERS) $(LIBS)
$(LD) $(LDFLAGS) boot/head.o init/main.o \
$(ARCHIVES) \
+ $(DRIVERS) \
$(LIBS) \
-o tools/system > System.map
+kernel/blk_drv/blk_drv.a:
+ (cd kernel/blk_drv; make)
+
+kernel/chr_drv/chr_drv.a:
+ (cd kernel/chr_drv; make)
+
kernel/kernel.o:
(cd kernel; make)
@@ -59,16 +63,22 @@ fs/fs.o:
lib/lib.a:
(cd lib; make)
-boot/boot: boot/boot.s tools/system
+boot/setup: boot/setup.s
+ $(AS86) -o boot/setup.o boot/setup.s
+ $(LD86) -s -o boot/setup boot/setup.o
+
+boot/bootsect: tmp.s
+ $(AS86) -o boot/bootsect.o tmp.s
+ rm -f tmp.s
+ $(LD86) -s -o boot/bootsect boot/bootsect.o
+
+tmp.s: boot/bootsect.s tools/system
(echo -n "SYSSIZE = (";ls -l tools/system | grep system \
| cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s
- cat boot/boot.s >> tmp.s
- $(AS86) -o boot/boot.o tmp.s
- rm -f tmp.s
- $(LD86) -s -o boot/boot boot/boot.o
+ cat boot/bootsect.s >> tmp.s
clean:
- rm -f Image System.map tmp_make boot/boot core
+ rm -f Image System.map tmp_make core
rm -f init/*.o boot/*.o tools/system tools/build
(cd mm;make clean)
(cd fs;make clean)
@@ -92,5 +102,5 @@ init/main.o : init/main.c include/unistd.h include/sys/stat.h \
include/sys/types.h include/sys/times.h include/sys/utsname.h \
include/utime.h include/time.h include/linux/tty.h include/termios.h \
include/linux/sched.h include/linux/head.h include/linux/fs.h \
- include/linux/mm.h include/asm/system.h include/asm/io.h include/stddef.h \
- include/stdarg.h include/fcntl.h
+ include/linux/mm.h include/signal.h include/asm/system.h include/asm/io.h \
+ include/stddef.h include/stdarg.h include/fcntl.h
diff --git a/boot/boot.s b/boot/boot.s
deleted file mode 100644
index e19bbd2..0000000
--- a/boot/boot.s
+++ /dev/null
@@ -1,329 +0,0 @@
-|
-| boot.s
-|
-| boot.s is loaded at 0x7c00 by the bios-startup routines, and moves itself
-| out of the way to address 0x90000, and jumps there.
-|
-| It then loads the system at 0x10000, using BIOS interrupts. Thereafter
-| it disables all interrupts, moves the system down to 0x0000, changes
-| to protected mode, and calls the start of system. System then must
-| RE-initialize the protected mode in it's own tables, and enable
-| interrupts as needed.
-|
-| NOTE! currently system is at most 8*65536 bytes long. This should be no
-| problem, even in the future. I want to keep it simple. This 512 kB
-| kernel size should be enough - in fact more would mean we'd have to move
-| not just these start-up routines, but also do something about the cache-
-| memory (block IO devices). The area left over in the lower 640 kB is meant
-| for these. No other memory is assumed to be "physical", ie all memory
-| over 1Mb is demand-paging. All addresses under 1Mb are guaranteed to match
-| their physical addresses.
-|
-| NOTE1 abouve is no longer valid in it's entirety. cache-memory is allocated
-| above the 1Mb mark as well as below. Otherwise it is mainly correct.
-|
-| NOTE 2! The boot disk type must be set at compile-time, by setting
-| the following equ. Having the boot-up procedure hunt for the right
-| disk type is severe brain-damage.
-| The loader has been made as simple as possible (had to, to get it
-| in 512 bytes with the code to move to protected mode), and continuos
-| read errors will result in a unbreakable loop. Reboot by hand. It
-| loads pretty fast by getting whole sectors at a time whenever possible.
-
-| 1.44Mb disks:
-sectors = 18
-| 1.2Mb disks:
-| sectors = 15
-| 720kB disks:
-| sectors = 9
-
-.globl begtext, begdata, begbss, endtext, enddata, endbss
-.text
-begtext:
-.data
-begdata:
-.bss
-begbss:
-.text
-
-BOOTSEG = 0x07c0
-INITSEG = 0x9000
-SYSSEG = 0x1000 | system loaded at 0x10000 (65536).
-ENDSEG = SYSSEG + SYSSIZE
-
-entry start
-start:
- mov ax,#BOOTSEG
- mov ds,ax
- mov ax,#INITSEG
- mov es,ax
- mov cx,#256
- sub si,si
- sub di,di
- rep
- movw
- jmpi go,INITSEG
-go: mov ax,cs
- mov ds,ax
- mov es,ax
- mov ss,ax
- mov sp,#0x400 | arbitrary value >>512
-
- mov ah,#0x03 | read cursor pos
- xor bh,bh
- int 0x10
-
- mov cx,#24
- mov bx,#0x0007 | page 0, attribute 7 (normal)
- mov bp,#msg1
- mov ax,#0x1301 | write string, move cursor
- int 0x10
-
-| ok, we've written the message, now
-| we want to load the system (at 0x10000)
-
- mov ax,#SYSSEG
- mov es,ax | segment of 0x010000
- call read_it
- call kill_motor
-
-| if the read went well we get current cursor position ans save it for
-| posterity.
-
- mov ah,#0x03 | read cursor pos
- xor bh,bh
- int 0x10 | save it in known place, con_init fetches
- mov [510],dx | it from 0x90510.
-
-| now we want to move to protected mode ...
-
- cli | no interrupts allowed !
-
-| first we move the system to it's rightful place
-
- mov ax,#0x0000
- cld | 'direction'=0, movs moves forward
-do_move:
- mov es,ax | destination segment
- add ax,#0x1000
- cmp ax,#0x9000
- jz end_move
- mov ds,ax | source segment
- sub di,di
- sub si,si
- mov cx,#0x8000
- rep
- movsw
- j do_move
-
-| then we load the segment descriptors
-
-end_move:
-
- mov ax,cs | 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
-
-| that was painless, now we enable A20
-
- call empty_8042
- mov al,#0xD1 | command write
- out #0x64,al
- call empty_8042
- 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
- .word 0x00eb,0x00eb
- 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)
- out #0xA1,al
- .word 0x00eb,0x00eb
- mov al,#0x04 | 8259-1 is master
- out #0x21,al
- .word 0x00eb,0x00eb
- mov al,#0x02 | 8259-2 is slave
- out #0xA1,al
- .word 0x00eb,0x00eb
- 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
- 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.
-empty_8042:
- .word 0x00eb,0x00eb
- in al,#0x64 | 8042 status port
- test al,#2 | is input buffer full?
- jnz empty_8042 | yes - loop
- ret
-
-| This routine loads the system at address 0x10000, making sure
-| no 64kB boundaries are crossed. We try to load it as fast as
-| possible, loading whole tracks whenever we can.
-|
-| in: es - starting address segment (normally 0x1000)
-|
-| This routine has to be recompiled to fit another drive type,
-| just change the "sectors" variable at the start of the file
-| (originally 18, for a 1.44Mb drive)
-|
-sread: .word 1 | sectors read of current track
-head: .word 0 | current head
-track: .word 0 | current track
-read_it:
- mov ax,es
- test ax,#0x0fff
-die: jne die | es must be at 64kB boundary
- xor bx,bx | bx is starting address within segment
-rp_read:
- mov ax,es
- cmp ax,#ENDSEG | have we loaded all yet?
- jb ok1_read
- ret
-ok1_read:
- mov ax,#sectors
- sub ax,sread
- mov cx,ax
- shl cx,#9
- add cx,bx
- jnc ok2_read
- je ok2_read
- xor ax,ax
- sub ax,bx
- shr ax,#9
-ok2_read:
- call read_track
- mov cx,ax
- add ax,sread
- cmp ax,#sectors
- jne ok3_read
- mov ax,#1
- sub ax,head
- jne ok4_read
- inc track
-ok4_read:
- mov head,ax
- xor ax,ax
-ok3_read:
- mov sread,ax
- shl cx,#9
- add bx,cx
- jnc rp_read
- mov ax,es
- add ax,#0x1000
- mov es,ax
- xor bx,bx
- jmp rp_read
-
-read_track:
- push ax
- push bx
- push cx
- push dx
- mov dx,track
- mov cx,sread
- inc cx
- mov ch,dl
- mov dx,head
- mov dh,dl
- mov dl,#0
- and dx,#0x0100
- mov ah,#2
- int 0x13
- jc bad_rt
- pop dx
- pop cx
- pop bx
- pop ax
- ret
-bad_rt: mov ax,#0
- mov dx,#0
- int 0x13
- pop dx
- pop cx
- pop bx
- pop ax
- jmp read_track
-
-/*
- * This procedure turns off the floppy drive motor, so
- * that we enter the kernel in a known state, and
- * don't have to worry about it later.
- */
-kill_motor:
- push dx
- mov dx,#0x3f2
- mov al,#0
- outb
- pop dx
- ret
-
-gdt:
- .word 0,0,0,0 | dummy
-
- .word 0x07FF | 8Mb - limit=2047 (2048*4096=8Mb)
- .word 0x0000 | base address=0
- .word 0x9A00 | code read/exec
- .word 0x00C0 | granularity=4096, 386
-
- .word 0x07FF | 8Mb - limit=2047 (2048*4096=8Mb)
- .word 0x0000 | base address=0
- .word 0x9200 | data read/write
- .word 0x00C0 | granularity=4096, 386
-
-idt_48:
- .word 0 | idt limit=0
- .word 0,0 | idt base=0L
-
-gdt_48:
- .word 0x800 | gdt limit=2048, 256 GDT entries
- .word gdt,0x9 | gdt base = 0X9xxxx
-
-msg1:
- .byte 13,10
- .ascii "Loading system ..."
- .byte 13,10,13,10
-
-.text
-endtext:
-.data
-enddata:
-.bss
-endbss:
diff --git a/boot/bootsect.s b/boot/bootsect.s
new file mode 100644
index 0000000..77fbb04
--- /dev/null
+++ b/boot/bootsect.s
@@ -0,0 +1,254 @@
+|
+| bootsect.s (C) 1991 Linus Torvalds
+|
+| bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
+| iself out of the way to address 0x90000, and jumps there.
+|
+| It then loads 'setup' directly after itself (0x90200), and the system
+| at 0x10000, using BIOS interrupts.
+|
+| NOTE! currently system is at most 8*65536 bytes long. This should be no
+| problem, even in the future. I want to keep it simple. This 512 kB
+| kernel size should be enough, especially as this doesn't contain the
+| buffer cache as in minix
+|
+| The loader has been made as simple as possible, and continuos
+| read errors will result in a unbreakable loop. Reboot by hand. It
+| loads pretty fast by getting whole sectors at a time whenever possible.
+
+.globl begtext, begdata, begbss, endtext, enddata, endbss
+.text
+begtext:
+.data
+begdata:
+.bss
+begbss:
+.text
+
+SETUPLEN = 4 | nr of setup-sectors
+BOOTSEG = 0x07c0 | original address of boot-sector
+INITSEG = 0x9000 | we move boot here - out of the way
+SETUPSEG = 0x9020 | setup starts here
+SYSSEG = 0x1000 | system loaded at 0x10000 (65536).
+ENDSEG = SYSSEG + SYSSIZE | where to stop loading
+
+| ROOT_DEV: 0x000 - same type of floppy as boot.
+| 0x301 - first partition on first drive etc
+ROOT_DEV = 0 | 0x306
+
+entry start
+start:
+ mov ax,#BOOTSEG
+ mov ds,ax
+ mov ax,#INITSEG
+ mov es,ax
+ mov cx,#256
+ sub si,si
+ sub di,di
+ rep
+ movw
+ jmpi go,INITSEG
+go: mov ax,cs
+ mov ds,ax
+ mov es,ax
+| put stack at 0x9ff00.
+ mov ss,ax
+ mov sp,#0xFF00 | arbitrary value >>512
+
+| load the setup-sectors directly after the bootblock.
+| Note that 'es' is already set up.
+
+load_setup:
+ mov dx,#0x0000 | drive 0, head 0
+ mov cx,#0x0002 | sector 2, track 0
+ mov bx,#0x0200 | address = 512, in INITSEG
+ mov ax,#0x0200+SETUPLEN | service 2, nr of sectors
+ int 0x13 | read it
+ jnc ok_load_setup | ok - continue
+ mov dx,#0x0000
+ mov ax,#0x0000 | reset the diskette
+ int 0x13
+ j load_setup
+
+ok_load_setup:
+
+| Get disk drive parameters, specifically nr of sectors/track
+
+ mov dl,#0x00
+ mov ax,#0x0800 | AH=8 is get drive parameters
+ int 0x13
+ mov ch,#0x00
+ seg cs
+ mov sectors,cx
+ mov ax,#INITSEG
+ mov es,ax
+
+| Print some inane message
+
+ mov ah,#0x03 | read cursor pos
+ xor bh,bh
+ int 0x10
+
+ mov cx,#24
+ mov bx,#0x0007 | page 0, attribute 7 (normal)
+ mov bp,#msg1
+ mov ax,#0x1301 | write string, move cursor
+ int 0x10
+
+| ok, we've written the message, now
+| we want to load the system (at 0x10000)
+
+ mov ax,#SYSSEG
+ mov es,ax | segment of 0x010000
+ call read_it
+ call kill_motor
+
+| After that we check which root-device to use. If the device is
+| defined (!= 0), nothing is done and the given device is used.
+| Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
+| on the number of sectors that the BIOS reports currently.
+
+ seg cs
+ mov ax,root_dev
+ cmp ax,#0
+ jne root_defined
+ seg cs
+ mov bx,sectors
+ mov ax,#0x0208 | /dev/ps0 - 1.2Mb
+ cmp bx,#15
+ je root_defined
+ mov ax,#0x021c | /dev/PS0 - 1.44Mb
+ cmp bx,#18
+ je root_defined
+undef_root:
+ jmp undef_root
+root_defined:
+ seg cs
+ mov root_dev,ax
+
+| after that (everyting loaded), we jump to
+| the setup-routine loaded directly after
+| the bootblock:
+
+ jmpi 0,SETUPSEG
+
+| This routine loads the system at address 0x10000, making sure
+| no 64kB boundaries are crossed. We try to load it as fast as
+| possible, loading whole tracks whenever we can.
+|
+| in: es - starting address segment (normally 0x1000)
+|
+sread: .word 1+SETUPLEN | sectors read of current track
+head: .word 0 | current head
+track: .word 0 | current track
+
+read_it:
+ mov ax,es
+ test ax,#0x0fff
+die: jne die | es must be at 64kB boundary
+ xor bx,bx | bx is starting address within segment
+rp_read:
+ mov ax,es
+ cmp ax,#ENDSEG | have we loaded all yet?
+ jb ok1_read
+ ret
+ok1_read:
+ seg cs
+ mov ax,sectors
+ sub ax,sread
+ mov cx,ax
+ shl cx,#9
+ add cx,bx
+ jnc ok2_read
+ je ok2_read
+ xor ax,ax
+ sub ax,bx
+ shr ax,#9
+ok2_read:
+ call read_track
+ mov cx,ax
+ add ax,sread
+ seg cs
+ cmp ax,sectors
+ jne ok3_read
+ mov ax,#1
+ sub ax,head
+ jne ok4_read
+ inc track
+ok4_read:
+ mov head,ax
+ xor ax,ax
+ok3_read:
+ mov sread,ax
+ shl cx,#9
+ add bx,cx
+ jnc rp_read
+ mov ax,es
+ add ax,#0x1000
+ mov es,ax
+ xor bx,bx
+ jmp rp_read
+
+read_track:
+ push ax
+ push bx
+ push cx
+ push dx
+ mov dx,track
+ mov cx,sread
+ inc cx
+ mov ch,dl
+ mov dx,head
+ mov dh,dl
+ mov dl,#0
+ and dx,#0x0100
+ mov ah,#2
+ int 0x13
+ jc bad_rt
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+bad_rt: mov ax,#0
+ mov dx,#0
+ int 0x13
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ jmp read_track
+
+/*
+ * This procedure turns off the floppy drive motor, so
+ * that we enter the kernel in a known state, and
+ * don't have to worry about it later.
+ */
+kill_motor:
+ push dx
+ mov dx,#0x3f2
+ mov al,#0
+ outb
+ pop dx
+ ret
+
+sectors:
+ .word 0
+
+msg1:
+ .byte 13,10
+ .ascii "Loading system ..."
+ .byte 13,10,13,10
+
+.org 508
+root_dev:
+ .word ROOT_DEV
+boot_flag:
+ .word 0xAA55
+
+.text
+endtext:
+.data
+enddata:
+.bss
+endbss:
diff --git a/boot/head.s b/boot/head.s
index c008ba8..2c4970a 100644
--- a/boot/head.s
+++ b/boot/head.s
@@ -1,4 +1,10 @@
/*
+ * linux/boot/head.s
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* head.s contains the 32-bit startup code.
*
* NOTE!!! Startup happens at absolute address 0x00000000, which is also where
@@ -6,7 +12,7 @@
* the page directory.
*/
.text
-.globl _idt,_gdt,_pg_dir
+.globl _idt,_gdt,_pg_dir,_tmp_floppy_area
_pg_dir:
startup_32:
movl $0x10,%eax
@@ -25,14 +31,22 @@ startup_32:
lss _stack_start,%esp
xorl %eax,%eax
1: incl %eax # check that A20 really IS enabled
- movl %eax,0x000000
+ movl %eax,0x000000 # loop forever if it isn't
cmpl %eax,0x100000
je 1b
+/*
+ * NOTE! 486 should set bit 16, to check for write-protect in supervisor
+ * mode. Then it would be unnecessary with the "verify_area()"-calls.
+ * 486 users probably want to set the NE (#5) bit also, so as to use
+ * int 16 for math errors.
+ */
movl %cr0,%eax # check math chip
andl $0x80000011,%eax # Save PG,ET,PE
+/* "orl $0x10020,%eax" here for 486 might be good */
+ orl $2,%eax # set MP
testl $0x10,%eax
jne 1f # ET is set - 387 is present
- orl $4,%eax # else set emulate bit
+ xorl $6,%eax # else reset MP and set EM
1: movl %eax,%cr0
jmp after_page_tables
@@ -78,6 +92,11 @@ setup_gdt:
lgdt gdt_descr
ret
+/*
+ * I put the kernel page tables right after the page directory,
+ * using 4 of them to span 16 Mb of physical memory. People with
+ * more than 16MB will have to expand this.
+ */
.org 0x1000
pg0:
@@ -85,11 +104,20 @@ pg0:
pg1:
.org 0x3000
-pg2: # This is not used yet, but if you
- # want to expand past 8 Mb, you'll have
- # to use it.
+pg2:
.org 0x4000
+pg3:
+
+.org 0x5000
+/*
+ * tmp_floppy_area is used by the floppy-driver when DMA cannot
+ * reach to a buffer-block. It needs to be aligned, so that it isn't
+ * on a 64kB border.
+ */
+_tmp_floppy_area:
+ .fill 1024,1,0
+
after_page_tables:
pushl $0 # These are the parameters to main :-)
pushl $0
@@ -102,11 +130,30 @@ L6:
# just in case, we know what happens.
/* This is the default interrupt "handler" :-) */
+int_msg:
+ .asciz "Unknown interrupt\n\r"
.align 2
ignore_int:
- incb 0xb8000+160 # put something on the screen
- movb $2,0xb8000+161 # so that we know something
- iret # happened
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ push %ds
+ push %es
+ push %fs
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ mov %ax,%fs
+ pushl $int_msg
+ call _printk
+ popl %eax
+ pop %fs
+ pop %es
+ pop %ds
+ popl %edx
+ popl %ecx
+ popl %eax
+ iret
/*
@@ -114,7 +161,7 @@ ignore_int:
*
* This routine sets up paging by setting the page bit
* in cr0. The page tables are set up, identity-mapping
- * the first 8MB. The pager assumes that no illegal
+ * the first 16MB. The pager assumes that no illegal
* addresses are produced (ie >4Mb on a 4Mb machine).
*
* NOTE! Although all physical memory should be identity
@@ -124,25 +171,27 @@ ignore_int:
* will be mapped to some other place - mm keeps track of
* that.
*
- * For those with more memory than 8 Mb - tough luck. I've
+ * For those with more memory than 16 Mb - tough luck. I've
* not got it, why should you :-) The source is here. Change
* it. (Seriously - it shouldn't be too difficult. Mostly
- * change some constants etc. I left it at 8Mb, as my machine
+ * change some constants etc. I left it at 16Mb, as my machine
* even cannot be extended past that (ok, but it was cheap :-)
* I've tried to show which constants to change by having
- * some kind of marker at them (search for "8Mb"), but I
+ * some kind of marker at them (search for "16Mb"), but I
* won't guarantee that's all :-( )
*/
.align 2
setup_paging:
- movl $1024*3,%ecx
+ movl $1024*5,%ecx /* 5 pages - pg_dir+4 page tables */
xorl %eax,%eax
xorl %edi,%edi /* pg_dir is at 0x000 */
cld;rep;stosl
movl $pg0+7,_pg_dir /* set present bit/user r/w */
movl $pg1+7,_pg_dir+4 /* --------- " " --------- */
- movl $pg1+4092,%edi
- movl $0x7ff007,%eax /* 8Mb - 4096 + 7 (r/w user,p) */
+ movl $pg2+7,_pg_dir+8 /* --------- " " --------- */
+ movl $pg3+7,_pg_dir+12 /* --------- " " --------- */
+ movl $pg3+4092,%edi
+ movl $0xfff007,%eax /* 16Mb - 4096 + 7 (r/w user,p) */
std
1: stosl /* fill pages backwards - more efficient :-) */
subl $0x1000,%eax
@@ -169,7 +218,7 @@ gdt_descr:
_idt: .fill 256,8,0 # idt is uninitialized
_gdt: .quad 0x0000000000000000 /* NULL descriptor */
- .quad 0x00c09a00000007ff /* 8Mb */
- .quad 0x00c09200000007ff /* 8Mb */
+ .quad 0x00c09a0000000fff /* 16Mb */
+ .quad 0x00c0920000000fff /* 16Mb */
.quad 0x0000000000000000 /* TEMPORARY - don't use */
.fill 252,8,0 /* space for LDT's and TSS's etc */
diff --git a/boot/setup.s b/boot/setup.s
new file mode 100644
index 0000000..5034a65
--- /dev/null
+++ b/boot/setup.s
@@ -0,0 +1,215 @@
+|
+| setup.s (C) 1991 Linus Torvalds
+|
+| setup.s is responsible for getting the system data from the BIOS,
+| and putting them into the appropriate places in system memory.
+| both setup.s and system has been loaded by the bootblock.
+|
+| This code asks the bios for memory/disk/other parameters, and
+| puts them in a "safe" place: 0x90000-0x901FF, ie where the
+| boot-block used to be. It is then up to the protected mode
+| system to read them from there before the area is overwritten
+| for buffer-blocks.
+|
+
+| NOTE! These had better be the same as in bootsect.s!
+
+INITSEG = 0x9000 | we move boot here - out of the way
+SYSSEG = 0x1000 | system loaded at 0x10000 (65536).
+SETUPSEG = 0x9020 | this is the current segment
+
+.globl begtext, begdata, begbss, endtext, enddata, endbss
+.text
+begtext:
+.data
+begdata:
+.bss
+begbss:
+.text
+
+entry start
+start:
+
+| ok, the read went well so we get current cursor position and save it for
+| posterity.
+
+ mov ax,#INITSEG | this is done in bootsect already, but...
+ mov ds,ax
+ mov ah,#0x03 | read cursor pos
+ xor bh,bh
+ int 0x10 | save it in known place, con_init fetches
+ mov [0],dx | it from 0x90000.
+
+| Get memory size (extended mem, kB)
+
+ mov ah,#0x88
+ int 0x15
+ mov [2],ax
+
+| Get hd0 data
+
+ mov ax,#0x0000
+ mov ds,ax
+ lds si,[4*0x41]
+ mov ax,#INITSEG
+ mov es,ax
+ mov di,#0x0080
+ mov cx,#0x10
+ rep
+ movsb
+
+| Get hd1 data
+
+ mov ax,#0x0000
+ mov ds,ax
+ lds si,[4*0x46]
+ mov ax,#INITSEG
+ mov es,ax
+ mov di,#0x0090
+ mov cx,#0x10
+ rep
+ movsb
+
+| Check that there IS a hd1 :-)
+
+ mov ax,#0x01500
+ mov dl,#0x81
+ int 0x13
+ jc no_disk1
+ cmp ah,#3
+ je is_disk1
+no_disk1:
+ mov ax,#INITSEG
+ mov es,ax
+ mov di,#0x0090
+ mov cx,#0x10
+ mov ax,#0x00
+ rep
+ stosb
+is_disk1:
+
+| now we want to move to protected mode ...
+
+ cli | no interrupts allowed !
+
+| first we move the system to it's rightful place
+
+ mov ax,#0x0000
+ cld | 'direction'=0, movs moves forward
+do_move:
+ mov es,ax | destination segment
+ add ax,#0x1000
+ cmp ax,#0x9000
+ jz end_move
+ mov ds,ax | source segment
+ sub di,di
+ sub si,si
+ mov cx,#0x8000
+ rep
+ movsw
+ jmp do_move
+
+| then we load the segment descriptors
+
+end_move:
+ 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
+
+| that was painless, now we enable A20
+
+ call empty_8042
+ mov al,#0xD1 | command write
+ out #0x64,al
+ call empty_8042
+ 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
+ .word 0x00eb,0x00eb
+ 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)
+ out #0xA1,al
+ .word 0x00eb,0x00eb
+ mov al,#0x04 | 8259-1 is master
+ out #0x21,al
+ .word 0x00eb,0x00eb
+ mov al,#0x02 | 8259-2 is slave
+ out #0xA1,al
+ .word 0x00eb,0x00eb
+ 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
+ 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.
+empty_8042:
+ .word 0x00eb,0x00eb
+ 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 0x07FF | 8Mb - limit=2047 (2048*4096=8Mb)
+ .word 0x0000 | base address=0
+ .word 0x9A00 | code read/exec
+ .word 0x00C0 | granularity=4096, 386
+
+ .word 0x07FF | 8Mb - limit=2047 (2048*4096=8Mb)
+ .word 0x0000 | base address=0
+ .word 0x9200 | data read/write
+ .word 0x00C0 | granularity=4096, 386
+
+idt_48:
+ .word 0 | idt limit=0
+ .word 0,0 | idt base=0L
+
+gdt_48:
+ .word 0x800 | gdt limit=2048, 256 GDT entries
+ .word 512+gdt,0x9 | gdt base = 0X9xxxx
+
+.text
+endtext:
+.data
+enddata:
+.bss
+endbss:
diff --git a/fs/Makefile b/fs/Makefile
index 24e7e4c..989319f 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -34,62 +34,71 @@ dep:
### Dependencies:
bitmap.o : bitmap.c ../include/string.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/linux/mm.h ../include/linux/kernel.h
-block_dev.o : block_dev.c ../include/errno.h ../include/linux/fs.h \
- ../include/sys/types.h ../include/linux/kernel.h ../include/asm/segment.h
-buffer.o : buffer.c ../include/linux/config.h ../include/linux/sched.h \
+ ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h
+block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/linux/mm.h ../include/linux/kernel.h ../include/asm/system.h
-char_dev.o : char_dev.c ../include/errno.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/linux/mm.h ../include/linux/kernel.h
+ ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
+ ../include/asm/segment.h ../include/asm/system.h
+buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h \
+ ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \
+ ../include/linux/kernel.h ../include/asm/system.h ../include/asm/io.h
+char_dev.o : char_dev.c ../include/errno.h ../include/sys/types.h \
+ ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
+ ../include/asm/segment.h ../include/asm/io.h
exec.o : exec.c ../include/errno.h ../include/sys/stat.h \
../include/sys/types.h ../include/a.out.h ../include/linux/fs.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/mm.h \
- ../include/linux/kernel.h ../include/asm/segment.h
+ ../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h
fcntl.o : fcntl.c ../include/string.h ../include/errno.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
- ../include/sys/types.h ../include/linux/mm.h ../include/linux/kernel.h \
- ../include/asm/segment.h ../include/fcntl.h ../include/sys/stat.h
+ ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \
+ ../include/linux/kernel.h ../include/asm/segment.h ../include/fcntl.h \
+ ../include/sys/stat.h
file_dev.o : file_dev.c ../include/errno.h ../include/fcntl.h \
../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \
- ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \
- ../include/asm/segment.h
+ ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \
+ ../include/linux/kernel.h ../include/asm/segment.h
file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h
-inode.o : inode.c ../include/string.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/linux/mm.h ../include/linux/kernel.h ../include/asm/system.h
+inode.o : inode.c ../include/string.h ../include/sys/stat.h \
+ ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \
+ ../include/linux/kernel.h ../include/asm/system.h
ioctl.o : ioctl.c ../include/string.h ../include/errno.h \
../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h
+ ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
+ ../include/signal.h
namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
- ../include/linux/kernel.h ../include/asm/segment.h ../include/string.h \
- ../include/fcntl.h ../include/errno.h ../include/const.h \
- ../include/sys/stat.h
+ ../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h \
+ ../include/string.h ../include/fcntl.h ../include/errno.h \
+ ../include/const.h ../include/sys/stat.h
open.o : open.c ../include/string.h ../include/errno.h ../include/fcntl.h \
../include/sys/types.h ../include/utime.h ../include/sys/stat.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
- ../include/linux/mm.h ../include/linux/tty.h ../include/termios.h \
- ../include/linux/kernel.h ../include/asm/segment.h
+ ../include/linux/mm.h ../include/signal.h ../include/linux/tty.h \
+ ../include/termios.h ../include/linux/kernel.h ../include/asm/segment.h
pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
../include/linux/mm.h ../include/asm/segment.h
read_write.o : read_write.c ../include/sys/stat.h ../include/sys/types.h \
../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
- ../include/asm/segment.h
+ ../include/signal.h ../include/asm/segment.h
stat.o : stat.c ../include/errno.h ../include/sys/stat.h \
../include/sys/types.h ../include/linux/fs.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/mm.h ../include/linux/kernel.h \
- ../include/asm/segment.h
+ ../include/linux/head.h ../include/linux/mm.h ../include/signal.h \
+ ../include/linux/kernel.h ../include/asm/segment.h
super.o : super.c ../include/linux/config.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/linux/mm.h ../include/linux/kernel.h
+ ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
+ ../include/asm/system.h ../include/errno.h ../include/sys/stat.h
truncate.o : truncate.c ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
- ../include/sys/stat.h
+ ../include/signal.h ../include/sys/stat.h
tty_ioctl.o : tty_ioctl.c ../include/errno.h ../include/termios.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
- ../include/sys/types.h ../include/linux/mm.h ../include/linux/kernel.h \
- ../include/linux/tty.h ../include/asm/segment.h ../include/asm/system.h
+ ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \
+ ../include/linux/kernel.h ../include/linux/tty.h ../include/asm/segment.h \
+ ../include/asm/system.h
diff --git a/fs/bitmap.c b/fs/bitmap.c
index 49bb81b..843c9ee 100644
--- a/fs/bitmap.c
+++ b/fs/bitmap.c
@@ -1,3 +1,9 @@
+/*
+ * linux/fs/bitmap.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
/* bitmap.c contains the code that handles the inode and block bitmaps */
#include <string.h>
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 7bbae6a..a50ae3f 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1,28 +1,38 @@
+/*
+ * linux/fs/block_dev.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <errno.h>
-#include <linux/fs.h>
+#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
-
-#define NR_BLK_DEV ((sizeof (rd_blk))/(sizeof (rd_blk[0])))
+#include <asm/system.h>
int block_write(int dev, long * pos, char * buf, int count)
{
- int block = *pos / BLOCK_SIZE;
- int offset = *pos % BLOCK_SIZE;
+ int block = *pos >> BLOCK_SIZE_BITS;
+ int offset = *pos & (BLOCK_SIZE-1);
int chars;
int written = 0;
struct buffer_head * bh;
register char * p;
while (count>0) {
- bh = bread(dev,block);
+ chars = BLOCK_SIZE - offset;
+ if (chars > count)
+ chars=count;
+ if (chars == BLOCK_SIZE)
+ bh = getblk(dev,block);
+ else
+ bh = breada(dev,block,block+1,block+2,-1);
+ block++;
if (!bh)
return written?written:-EIO;
- chars = (count<BLOCK_SIZE) ? count : BLOCK_SIZE;
p = offset + bh->b_data;
offset = 0;
- block++;
*pos += chars;
written += chars;
count -= chars;
@@ -36,51 +46,28 @@ int block_write(int dev, long * pos, char * buf, int count)
int block_read(int dev, unsigned long * pos, char * buf, int count)
{
- int block = *pos / BLOCK_SIZE;
- int offset = *pos % BLOCK_SIZE;
+ int block = *pos >> BLOCK_SIZE_BITS;
+ int offset = *pos & (BLOCK_SIZE-1);
int chars;
int read = 0;
struct buffer_head * bh;
register char * p;
while (count>0) {
- bh = bread(dev,block);
- if (!bh)
+ chars = BLOCK_SIZE-offset;
+ if (chars > count)
+ chars = count;
+ if (!(bh = breada(dev,block,block+1,block+2,-1)))
return read?read:-EIO;
- chars = (count<BLOCK_SIZE) ? count : BLOCK_SIZE;
+ block++;
p = offset + bh->b_data;
offset = 0;
- block++;
*pos += chars;
read += chars;
count -= chars;
while (chars-->0)
put_fs_byte(*(p++),buf++);
- bh->b_dirt = 1;
brelse(bh);
}
return read;
}
-
-extern void rw_hd(int rw, struct buffer_head * bh);
-
-typedef void (*blk_fn)(int rw, struct buffer_head * bh);
-
-static blk_fn rd_blk[]={
- NULL, /* nodev */
- NULL, /* dev mem */
- NULL, /* dev fd */
- rw_hd, /* dev hd */
- NULL, /* dev ttyx */
- NULL, /* dev tty */
- NULL}; /* dev lp */
-
-void ll_rw_block(int rw, struct buffer_head * bh)
-{
- blk_fn blk_addr;
- unsigned int major;
-
- if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || !(blk_addr=rd_blk[major]))
- panic("Trying to read nonexistent block-device");
- blk_addr(rw, bh);
-}
diff --git a/fs/buffer.c b/fs/buffer.c
index 312ab17..c827631 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1,4 +1,10 @@
/*
+ * linux/fs/buffer.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* 'buffer.c' implements the buffer-cache functions. Race-conditions have
* been avoided by NEVER letting a interrupt change a buffer (except for the
* data, of course), but instead letting the caller do it. NOTE! As interrupts
@@ -6,18 +12,19 @@
* sleep-on-calls. These should be extremely quick, though (I hope).
*/
+/*
+ * NOTE! There is one discordant note here: checking floppies for
+ * disk change. This is where it fits best, I think, as it should
+ * invalidate changed floppy-disk-caches.
+ */
+
+#include <stdarg.h>
+
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/system.h>
-
-#if (BUFFER_END & 0xfff)
-#error "Bad BUFFER_END value"
-#endif
-
-#if (BUFFER_END > 0xA0000 && BUFFER_END <= 0x100000)
-#error "Bad BUFFER_END value"
-#endif
+#include <asm/io.h>
extern int end;
struct buffer_head * start_buffer = (struct buffer_head *) &end;
@@ -49,7 +56,7 @@ int sys_sync(void)
return 0;
}
-static int sync_dev(int dev)
+int sync_dev(int dev)
{
int i;
struct buffer_head * bh;
@@ -59,12 +66,59 @@ static int sync_dev(int dev)
if (bh->b_dev != dev)
continue;
wait_on_buffer(bh);
- if (bh->b_dirt)
+ if (bh->b_dev == dev && bh->b_dirt)
+ ll_rw_block(WRITE,bh);
+ }
+ sync_inodes();
+ bh = start_buffer;
+ for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
+ if (bh->b_dev != dev)
+ continue;
+ wait_on_buffer(bh);
+ if (bh->b_dev == dev && bh->b_dirt)
ll_rw_block(WRITE,bh);
}
return 0;
}
+/*
+ * This routine checks whether a floppy has been changed, and
+ * invalidates all buffer-cache-entries in that case. This
+ * is a relatively slow routine, so we have to try to minimize using
+ * it. Thus it is called only upon a 'mount' or 'open'. This
+ * is the best way of combining speed and utility, I think.
+ * People changing diskettes in the middle of an operation deserve
+ * to loose :-)
+ *
+ * NOTE! Although currently this is only for floppies, the idea is
+ * that any additional removable block-device will use this routine,
+ * and that mount/open needn't know that floppies/whatever are
+ * special.
+ */
+void check_disk_change(int dev)
+{
+ int i;
+ struct buffer_head * bh;
+
+ if (MAJOR(dev) != 2)
+ return;
+ dev=MINOR(dev) & 0x03; /* which floppy is it? */
+ if (!floppy_change(dev))
+ return;
+ dev |= 0x200;
+ for (i=0 ; i<NR_SUPER ; i++)
+ if ((super_block[i].s_dev & 0xff03)==dev)
+ put_super(super_block[i].s_dev);
+ bh = start_buffer;
+ for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
+ if ((bh->b_dev & 0xff03) != dev)
+ continue;
+ wait_on_buffer(bh);
+ if ((bh->b_dev & 0xff03) == dev)
+ bh->b_uptodate = bh->b_dirt = 0;
+ }
+}
+
#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
#define hash(dev,block) hash_table[_hashfn(dev,block)]
@@ -124,73 +178,70 @@ struct buffer_head * get_hash_table(int dev, int block)
{
struct buffer_head * bh;
-repeat:
- if (!(bh=find_buffer(dev,block)))
- return NULL;
- bh->b_count++;
- wait_on_buffer(bh);
- if (bh->b_dev != dev || bh->b_blocknr != block) {
- brelse(bh);
- goto repeat;
+ for (;;) {
+ if (!(bh=find_buffer(dev,block)))
+ return NULL;
+ bh->b_count++;
+ wait_on_buffer(bh);
+ if (bh->b_dev == dev && bh->b_blocknr == block)
+ return bh;
+ bh->b_count--;
}
- return bh;
}
/*
* Ok, this is getblk, and it isn't very clear, again to hinder
* race-conditions. Most of the code is seldom used, (ie repeating),
* so it should be much more efficient than it looks.
+ *
+ * The algoritm is changed: better, and an elusive bug removed.
+ * LBT 11.11.91
*/
+#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
struct buffer_head * getblk(int dev,int block)
{
- struct buffer_head * tmp;
+ struct buffer_head * tmp, * bh;
repeat:
- if (tmp=get_hash_table(dev,block))
- return tmp;
+ if (bh = get_hash_table(dev,block))
+ return bh;
tmp = free_list;
do {
- if (!tmp->b_count) {
- wait_on_buffer(tmp); /* we still have to wait */
- if (!tmp->b_count) /* on it, it might be dirty */
+ if (tmp->b_count)
+ continue;
+ if (!bh || BADNESS(tmp)<BADNESS(bh)) {
+ bh = tmp;
+ if (!BADNESS(tmp))
break;
}
- tmp = tmp->b_next_free;
- } while (tmp != free_list || (tmp=NULL));
- /* Kids, don't try THIS at home ^^^^^. Magic */
- if (!tmp) {
- printk("Sleeping on free buffer ..");
+ } while ((tmp = tmp->b_next_free) != free_list);
+ if (!bh) {
sleep_on(&buffer_wait);
- printk("ok\n");
goto repeat;
}
- tmp->b_count++;
- remove_from_queues(tmp);
-/*
- * Now, when we know nobody can get to this node (as it's removed from the
- * free list), we write it out. We can sleep here without fear of race-
- * conditions.
- */
- if (tmp->b_dirt)
- sync_dev(tmp->b_dev);
-/* update buffer contents */
- tmp->b_dev=dev;
- tmp->b_blocknr=block;
- tmp->b_dirt=0;
- tmp->b_uptodate=0;
-/* NOTE!! While we possibly slept in sync_dev(), somebody else might have
- * added "this" block already, so check for that. Thank God for goto's.
- */
- if (find_buffer(dev,block)) {
- tmp->b_dev=0; /* ok, someone else has beaten us */
- tmp->b_blocknr=0; /* to it - free this block and */
- tmp->b_count=0; /* try again */
- insert_into_queues(tmp);
+ wait_on_buffer(bh);
+ if (bh->b_count)
goto repeat;
+ while (bh->b_dirt) {
+ sync_dev(bh->b_dev);
+ wait_on_buffer(bh);
+ if (bh->b_count)
+ goto repeat;
}
-/* and then insert into correct position */
- insert_into_queues(tmp);
- return tmp;
+/* NOTE!! While we slept waiting for this block, somebody else might */
+/* already have added "this" block to the cache. check it */
+ if (find_buffer(dev,block))
+ goto repeat;
+/* OK, FINALLY we know that this buffer is the only one of it's kind, */
+/* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */
+ bh->b_count=1;
+ bh->b_dirt=0;
+ bh->b_uptodate=0;
+ remove_from_queues(bh);
+ bh->b_dev=dev;
+ bh->b_blocknr=block;
+ insert_into_queues(bh);
+ return bh;
}
void brelse(struct buffer_head * buf)
@@ -216,18 +267,54 @@ struct buffer_head * bread(int dev,int block)
if (bh->b_uptodate)
return bh;
ll_rw_block(READ,bh);
+ wait_on_buffer(bh);
+ if (bh->b_uptodate)
+ return bh;
+ brelse(bh);
+ return NULL;
+}
+
+/*
+ * Ok, breada can be used as bread, but additionally to mark other
+ * blocks for reading as well. End the argument list with a negative
+ * number.
+ */
+struct buffer_head * breada(int dev,int first, ...)
+{
+ va_list args;
+ struct buffer_head * bh, *tmp;
+
+ va_start(args,first);
+ if (!(bh=getblk(dev,first)))
+ panic("bread: getblk returned NULL\n");
+ if (!bh->b_uptodate)
+ ll_rw_block(READ,bh);
+ while ((first=va_arg(args,int))>=0) {
+ tmp=getblk(dev,first);
+ if (tmp) {
+ if (!tmp->b_uptodate)
+ ll_rw_block(READA,bh);
+ tmp->b_count--;
+ }
+ }
+ va_end(args);
+ wait_on_buffer(bh);
if (bh->b_uptodate)
return bh;
brelse(bh);
return (NULL);
}
-void buffer_init(void)
+void buffer_init(long buffer_end)
{
struct buffer_head * h = start_buffer;
- void * b = (void *) BUFFER_END;
+ void * b;
int i;
+ if (buffer_end == 1<<20)
+ b = (void *) (640*1024);
+ else
+ b = (void *) buffer_end;
while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
h->b_dev = 0;
h->b_dirt = 0;
diff --git a/fs/char_dev.c b/fs/char_dev.c
index e974242..8052a3e 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -1,21 +1,90 @@
+/*
+ * linux/fs/char_dev.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <errno.h>
+#include <sys/types.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+
extern int tty_read(unsigned minor,char * buf,int count);
extern int tty_write(unsigned minor,char * buf,int count);
-static int rw_ttyx(int rw,unsigned minor,char * buf,int count);
-static int rw_tty(int rw,unsigned minor,char * buf,int count);
+typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count,off_t * pos);
+
+static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos)
+{
+ return ((rw==READ)?tty_read(minor,buf,count):
+ tty_write(minor,buf,count));
+}
+
+static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos)
+{
+ if (current->tty<0)
+ return -EPERM;
+ return rw_ttyx(rw,current->tty,buf,count,pos);
+}
+
+static int rw_ram(int rw,char * buf, int count, off_t *pos)
+{
+ return -EIO;
+}
+
+static int rw_mem(int rw,char * buf, int count, off_t * pos)
+{
+ return -EIO;
+}
-typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count);
+static int rw_kmem(int rw,char * buf, int count, off_t * pos)
+{
+ return -EIO;
+}
+
+static int rw_port(int rw,char * buf, int count, off_t * pos)
+{
+ int i=*pos;
+
+ while (count-->0 && i<65536) {
+ if (rw==READ)
+ put_fs_byte(inb(i),buf++);
+ else
+ outb(get_fs_byte(buf++),i);
+ i++;
+ }
+ i -= *pos;
+ *pos += i;
+ return i;
+}
+
+static int rw_memory(int rw, unsigned minor, char * buf, int count, off_t * pos)
+{
+ switch(minor) {
+ case 0:
+ return rw_ram(rw,buf,count,pos);
+ case 1:
+ return rw_mem(rw,buf,count,pos);
+ case 2:
+ return rw_kmem(rw,buf,count,pos);
+ case 3:
+ return (rw==READ)?0:count; /* rw_null */
+ case 4:
+ return rw_port(rw,buf,count,pos);
+ default:
+ return -EIO;
+ }
+}
#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr)))
static crw_ptr crw_table[]={
NULL, /* nodev */
- NULL, /* /dev/mem */
+ rw_memory, /* /dev/mem etc */
NULL, /* /dev/fd */
NULL, /* /dev/hd */
rw_ttyx, /* /dev/ttyx */
@@ -23,20 +92,7 @@ static crw_ptr crw_table[]={
NULL, /* /dev/lp */
NULL}; /* unnamed pipes */
-static int rw_ttyx(int rw,unsigned minor,char * buf,int count)
-{
- return ((rw==READ)?tty_read(minor,buf,count):
- tty_write(minor,buf,count));
-}
-
-static int rw_tty(int rw,unsigned minor,char * buf,int count)
-{
- if (current->tty<0)
- return -EPERM;
- return rw_ttyx(rw,current->tty,buf,count);
-}
-
-int rw_char(int rw,int dev, char * buf, int count)
+int rw_char(int rw,int dev, char * buf, int count, off_t * pos)
{
crw_ptr call_addr;
@@ -46,5 +102,5 @@ int rw_char(int rw,int dev, char * buf, int count)
printk("dev: %04x\n",dev);
panic("Trying to r/w from/to nonexistent character device");
}
- return call_addr(rw,MINOR(dev),buf,count);
+ return call_addr(rw,MINOR(dev),buf,count,pos);
}
diff --git a/fs/exec.c b/fs/exec.c
index e9d5058..5fd0049 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1,4 +1,11 @@
+/*
+ * linux/fs/exec.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <errno.h>
+#include <string.h>
#include <sys/stat.h>
#include <a.out.h>
@@ -158,36 +165,66 @@ static int count(char ** argv)
* 'copy_string()' copies argument/envelope strings from user
* memory to free pages in kernel mem. These are in a format ready
* to be put directly into the top of new user memory.
+ *
+ * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies
+ * whether the string and the string array are from user or kernel segments:
+ *
+ * from_kmem argv * argv **
+ * 0 user space user space
+ * 1 kernel space user space
+ * 2 kernel space kernel space
+ *
+ * We do this by playing games with the fs segment register. Since it
+ * it is expensive to load a segment register, we try to avoid calling
+ * set_fs() unless we absolutely have to.
*/
static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
- unsigned long p)
+ unsigned long p, int from_kmem)
{
- int len,i;
- char *tmp;
+ char *tmp, *pag;
+ int len, offset = 0;
+ unsigned long old_fs, new_fs;
+ if (!p)
+ return 0; /* bullet-proofing */
+ new_fs = get_ds();
+ old_fs = get_fs();
+ if (from_kmem==2)
+ set_fs(new_fs);
while (argc-- > 0) {
- if (!(tmp = (char *)get_fs_long(((unsigned long *) argv)+argc)))
+ if (from_kmem == 1)
+ set_fs(new_fs);
+ if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))
panic("argc is wrong");
+ if (from_kmem == 1)
+ set_fs(old_fs);
len=0; /* remember zero-padding */
do {
len++;
} while (get_fs_byte(tmp++));
- if (p-len < 0) /* this shouldn't happen - 128kB */
+ if (p-len < 0) { /* this shouldn't happen - 128kB */
+ set_fs(old_fs);
return 0;
- i = ((unsigned) (p-len)) >> 12;
- while (i<MAX_ARG_PAGES && !page[i]) {
- if (!(page[i]=get_free_page()))
- return 0;
- i++;
}
- do {
- --p;
- if (!page[p/PAGE_SIZE])
- panic("nonexistent page in exec.c");
- ((char *) page[p/PAGE_SIZE])[p%PAGE_SIZE] =
- get_fs_byte(--tmp);
- } while (--len);
+ while (len) {
+ --p; --tmp; --len;
+ if (--offset < 0) {
+ offset = p % PAGE_SIZE;
+ if (from_kmem==2)
+ set_fs(old_fs);
+ if (!(pag = (char *) page[p/PAGE_SIZE]) &&
+ !(pag = (char *) page[p/PAGE_SIZE] =
+ (unsigned long *) get_free_page()))
+ return 0;
+ if (from_kmem==2)
+ set_fs(new_fs);
+
+ }
+ *(pag + offset) = get_fs_byte(tmp);
+ }
}
+ if (from_kmem==2)
+ set_fs(old_fs);
return p;
}
@@ -227,7 +264,11 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
struct exec ex;
unsigned long page[MAX_ARG_PAGES];
int i,argc,envc;
- unsigned long p;
+ int e_uid, e_gid;
+ int retval;
+ int sh_bang = 0;
+ char *buf = 0;
+ unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
if ((0xffff & eip[1]) != 0x000f)
panic("execve called from supervisor mode");
@@ -235,49 +276,130 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
page[i]=0;
if (!(inode=namei(filename))) /* get executables inode */
return -ENOENT;
+ argc = count(argv);
+ envc = count(envp);
+
+restart_interp:
if (!S_ISREG(inode->i_mode)) { /* must be regular file */
- iput(inode);
- return -EACCES;
+ retval = -EACCES;
+ goto exec_error2;
}
i = inode->i_mode;
- if (current->uid && current->euid) {
- if (current->euid == inode->i_uid)
- i >>= 6;
- else if (current->egid == inode->i_gid)
- i >>= 3;
- } else if (i & 0111)
- i=1;
- if (!(i & 1)) {
- iput(inode);
- return -ENOEXEC;
+ e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
+ e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
+ if (current->euid == inode->i_uid)
+ i >>= 6;
+ else if (current->egid == inode->i_gid)
+ i >>= 3;
+ if (!(i & 1) &&
+ !((inode->i_mode & 0111) && suser())) {
+ retval = -ENOEXEC;
+ goto exec_error2;
}
if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
- iput(inode);
- return -EACCES;
+ retval = -EACCES;
+ goto exec_error2;
}
ex = *((struct exec *) bh->b_data); /* read exec-header */
+ if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
+ /*
+ * This section does the #! interpretation.
+ * Sorta complicated, but hopefully it will work. -TYT
+ */
+
+ char *cp, *interp, *i_name, *i_arg;
+ unsigned long old_fs;
+
+ if (!buf)
+ buf = malloc(1024);
+ strncpy(buf, bh->b_data+2, 1022);
+ brelse(bh);
+ iput(inode);
+ buf[1022] = '\0';
+ if (cp = strchr(buf, '\n')) {
+ *cp = '\0';
+ for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
+ }
+ if (!cp || *cp == '\0') {
+ retval = -ENOEXEC; /* No interpreter name found */
+ goto exec_error1;
+ }
+ interp = i_name = cp;
+ i_arg = 0;
+ for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
+ if (*cp == '/')
+ i_name = cp+1;
+ }
+ if (*cp) {
+ *cp++ = '\0';
+ i_arg = cp;
+ }
+ /*
+ * OK, we've parsed out the interpreter name and
+ * (optional) argument.
+ */
+ if (sh_bang++ == 0) {
+ p = copy_strings(envc, envp, page, p, 0);
+ p = copy_strings(--argc, argv+1, page, p, 0);
+ }
+ /*
+ * Splice in (1) the interpreter's name for argv[0]
+ * (2) (optional) argument to interpreter
+ * (3) filename of shell script
+ *
+ * This is done in reverse order, because of how the
+ * user environment and arguments are stored.
+ */
+ p = copy_strings(1, &filename, page, p, 1);
+ argc++;
+ if (i_arg) {
+ p = copy_strings(1, &i_arg, page, p, 2);
+ argc++;
+ }
+ p = copy_strings(1, &i_name, page, p, 2);
+ argc++;
+ if (!p) {
+ retval = -ENOMEM;
+ goto exec_error1;
+ }
+ /*
+ * OK, now restart the process with the interpreter's inode.
+ */
+ old_fs = get_fs();
+ set_fs(get_ds());
+ if (!(inode=namei(interp))) { /* get executables inode */
+ set_fs(old_fs);
+ retval = -ENOENT;
+ goto exec_error1;
+ }
+ set_fs(old_fs);
+ goto restart_interp;
+ }
brelse(bh);
if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
- iput(inode);
- return -ENOEXEC;
+ retval = -ENOEXEC;
+ goto exec_error2;
}
- if (N_TXTOFF(ex) != BLOCK_SIZE)
- panic("N_TXTOFF != BLOCK_SIZE. See a.out.h.");
- argc = count(argv);
- envc = count(envp);
- p = copy_strings(envc,envp,page,PAGE_SIZE*MAX_ARG_PAGES-4);
- p = copy_strings(argc,argv,page,p);
- if (!p) {
- for (i=0 ; i<MAX_ARG_PAGES ; i++)
- free_page(page[i]);
- iput(inode);
- return -1;
+ if (N_TXTOFF(ex) != BLOCK_SIZE) {
+ printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
+ retval = -ENOEXEC;
+ goto exec_error2;
+ }
+ if (!sh_bang) {
+ p = copy_strings(envc,envp,page,p,0);
+ p = copy_strings(argc,argv,page,p,0);
+ if (!p) {
+ retval = -ENOMEM;
+ goto exec_error2;
+ }
}
/* OK, This is the point of no return */
+ if (buf)
+ free_s(buf, 1024);
for (i=0 ; i<32 ; i++)
- current->sig_fn[i] = NULL;
+ current->sigaction[i].sa_handler = NULL;
for (i=0 ; i<NR_OPEN ; i++)
if ((current->close_on_exec>>i)&1)
sys_close(i);
@@ -293,6 +415,8 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
(current->end_data = ex.a_data +
(current->end_code = ex.a_text));
current->start_stack = p & 0xfffff000;
+ current->euid = e_uid;
+ current->egid = e_gid;
i = read_area(inode,ex.a_text+ex.a_data);
iput(inode);
if (i<0)
@@ -303,4 +427,12 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
eip[0] = ex.a_entry; /* eip, magic happens :-) */
eip[3] = p; /* stack pointer */
return 0;
+exec_error2:
+ iput(inode);
+exec_error1:
+ if (buf)
+ free(buf);
+ for (i=0 ; i<MAX_ARG_PAGES ; i++)
+ free_page(page[i]);
+ return(retval);
}
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 169f376..c201aa8 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -1,3 +1,9 @@
+/*
+ * linux/fs/fcntl.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <string.h>
#include <errno.h>
#include <linux/sched.h>
diff --git a/fs/file_dev.c b/fs/file_dev.c
index da5d014..0c50eaa 100644
--- a/fs/file_dev.c
+++ b/fs/file_dev.c
@@ -1,3 +1,9 @@
+/*
+ * linux/fs/file_dev.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <errno.h>
#include <fcntl.h>
diff --git a/fs/file_table.c b/fs/file_table.c
index ab7cebf..e0589ac 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -1,3 +1,9 @@
+/*
+ * linux/fs/file_table.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <linux/fs.h>
struct file file_table[NR_FILE];
diff --git a/fs/inode.c b/fs/inode.c
index d06ff90..803347f 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1,4 +1,11 @@
+/*
+ * linux/fs/inode.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <string.h>
+#include <sys/stat.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -146,6 +153,10 @@ void iput(struct m_inode * inode)
return;
}
repeat:
+ if (S_ISBLK(inode->i_mode)) {
+ sync_dev(inode->i_zone[0]);
+ wait_on_inode(inode);
+ }
if (!inode->i_nlinks) {
truncate(inode);
free_inode(inode);
@@ -234,6 +245,24 @@ struct m_inode * iget(int dev,int nr)
continue;
}
inode->i_count++;
+ if (inode->i_mount) {
+ int i;
+
+ for (i = 0 ; i<NR_SUPER ; i++)
+ if (super_block[i].s_imount==inode)
+ break;
+ if (i >= NR_SUPER) {
+ printk("Mounted inode hasn't got sb\n");
+ if (empty)
+ iput(empty);
+ return inode;
+ }
+ iput(inode);
+ dev = super_block[i].s_dev;
+ nr = ROOT_INO;
+ inode = inode_table;
+ continue;
+ }
if (empty)
iput(empty);
return inode;
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 131561b..cb514a9 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -1,3 +1,9 @@
+/*
+ * linux/fs/ioctl.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
diff --git a/fs/namei.c b/fs/namei.c
index 600737b..cad3203 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1,3 +1,9 @@
+/*
+ * linux/fs/namei.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
@@ -34,13 +40,13 @@ static int permission(struct m_inode * inode,int mask)
/* special case: not even root can read/write a deleted file */
if (inode->i_dev && !inode->i_nlinks)
return 0;
- if (!(current->uid && current->euid))
- mode=0777;
- else if (current->uid==inode->i_uid || current->euid==inode->i_uid)
+ else if (current->euid==inode->i_uid)
mode >>= 6;
- else if (current->gid==inode->i_gid || current->egid==inode->i_gid)
+ else if (current->egid==inode->i_gid)
mode >>= 3;
- return mode & mask & 0007;
+ if (((mode & mask & 0007) == mask) || suser())
+ return 1;
+ return 0;
}
/*
@@ -74,14 +80,18 @@ static int match(int len,const char * name,struct dir_entry * de)
* returns the cache buffer in which the entry was found, and the entry
* itself (as a parameter - res_dir). It does NOT read the inode of the
* entry - you'll have to do that yourself if you want to.
+ *
+ * This also takes care of the few special cases due to '..'-traversal
+ * over a pseudo-root and a mount point.
*/
-static struct buffer_head * find_entry(struct m_inode * dir,
+static struct buffer_head * find_entry(struct m_inode ** dir,
const char * name, int namelen, struct dir_entry ** res_dir)
{
int entries;
int block,i;
struct buffer_head * bh;
struct dir_entry * de;
+ struct super_block * sb;
#ifdef NO_TRUNCATE
if (namelen > NAME_LEN)
@@ -90,13 +100,29 @@ static struct buffer_head * find_entry(struct m_inode * dir,
if (namelen > NAME_LEN)
namelen = NAME_LEN;
#endif
- entries = dir->i_size / (sizeof (struct dir_entry));
+ entries = (*dir)->i_size / (sizeof (struct dir_entry));
*res_dir = NULL;
if (!namelen)
return NULL;
- if (!(block = dir->i_zone[0]))
+/* check for '..', as we might have to do some "magic" for it */
+ if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') {
+/* '..' in a pseudo-root results in a faked '.' (just change namelen) */
+ if ((*dir) == current->root)
+ namelen=1;
+ else if ((*dir)->i_num == ROOT_INO) {
+/* '..' over a mount-point results in 'dir' being exchanged for the mounted
+ directory-inode. NOTE! We set mounted, so that we can iput the new dir */
+ sb=get_super((*dir)->i_dev);
+ if (sb->s_imount) {
+ iput(*dir);
+ (*dir)=sb->s_imount;
+ (*dir)->i_count++;
+ }
+ }
+ }
+ if (!(block = (*dir)->i_zone[0]))
return NULL;
- if (!(bh = bread(dir->i_dev,block)))
+ if (!(bh = bread((*dir)->i_dev,block)))
return NULL;
i = 0;
de = (struct dir_entry *) bh->b_data;
@@ -104,8 +130,8 @@ static struct buffer_head * find_entry(struct m_inode * dir,
if ((char *)de >= BLOCK_SIZE+bh->b_data) {
brelse(bh);
bh = NULL;
- if (!(block = bmap(dir,i/DIR_ENTRIES_PER_BLOCK)) ||
- !(bh = bread(dir->i_dev,block))) {
+ if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) ||
+ !(bh = bread((*dir)->i_dev,block))) {
i += DIR_ENTRIES_PER_BLOCK;
continue;
}
@@ -226,7 +252,7 @@ static struct m_inode * get_dir(const char * pathname)
/* nothing */ ;
if (!c)
return inode;
- if (!(bh = find_entry(inode,thisname,namelen,&de))) {
+ if (!(bh = find_entry(&inode,thisname,namelen,&de))) {
iput(inode);
return NULL;
}
@@ -282,7 +308,7 @@ struct m_inode * namei(const char * pathname)
return NULL;
if (!namelen) /* special case: '/usr/' etc */
return dir;
- bh = find_entry(dir,basename,namelen,&de);
+ bh = find_entry(&dir,basename,namelen,&de);
if (!bh) {
iput(dir);
return NULL;
@@ -327,7 +353,7 @@ int open_namei(const char * pathname, int flag, int mode,
iput(dir);
return -EISDIR;
}
- bh = find_entry(dir,basename,namelen,&de);
+ bh = find_entry(&dir,basename,namelen,&de);
if (!bh) {
if (!(flag & O_CREAT)) {
iput(dir);
@@ -342,6 +368,7 @@ int open_namei(const char * pathname, int flag, int mode,
iput(dir);
return -ENOSPC;
}
+ inode->i_uid = current->euid;
inode->i_mode = mode;
inode->i_dirt = 1;
bh = add_entry(dir,basename,namelen,&de);
@@ -367,7 +394,7 @@ int open_namei(const char * pathname, int flag, int mode,
if (!(inode=iget(dev,inr)))
return -EACCES;
if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
- permission(inode,ACC_MODE(flag))!=ACC_MODE(flag)) {
+ !permission(inode,ACC_MODE(flag))) {
iput(inode);
return -EPERM;
}
@@ -378,6 +405,57 @@ int open_namei(const char * pathname, int flag, int mode,
return 0;
}
+int sys_mknod(const char * filename, int mode, int dev)
+{
+ const char * basename;
+ int namelen;
+ struct m_inode * dir, * inode;
+ struct buffer_head * bh;
+ struct dir_entry * de;
+
+ if (!suser())
+ return -EPERM;
+ if (!(dir = dir_namei(filename,&namelen,&basename)))
+ return -ENOENT;
+ if (!namelen) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (!permission(dir,MAY_WRITE)) {
+ iput(dir);
+ return -EPERM;
+ }
+ bh = find_entry(&dir,basename,namelen,&de);
+ if (bh) {
+ brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ inode = new_inode(dir->i_dev);
+ if (!inode) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_mode = mode;
+ if (S_ISBLK(mode) || S_ISCHR(mode))
+ inode->i_zone[0] = dev;
+ inode->i_mtime = inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ bh = add_entry(dir,basename,namelen,&de);
+ if (!bh) {
+ iput(dir);
+ inode->i_nlinks=0;
+ iput(inode);
+ return -ENOSPC;
+ }
+ de->inode = inode->i_num;
+ bh->b_dirt = 1;
+ iput(dir);
+ iput(inode);
+ brelse(bh);
+ return 0;
+}
+
int sys_mkdir(const char * pathname, int mode)
{
const char * basename;
@@ -386,7 +464,7 @@ int sys_mkdir(const char * pathname, int mode)
struct buffer_head * bh, *dir_block;
struct dir_entry * de;
- if (current->euid && current->uid)
+ if (!suser())
return -EPERM;
if (!(dir = dir_namei(pathname,&namelen,&basename)))
return -ENOENT;
@@ -398,7 +476,7 @@ int sys_mkdir(const char * pathname, int mode)
iput(dir);
return -EPERM;
}
- bh = find_entry(dir,basename,namelen,&de);
+ bh = find_entry(&dir,basename,namelen,&de);
if (bh) {
brelse(bh);
iput(dir);
@@ -510,7 +588,7 @@ int sys_rmdir(const char * name)
struct buffer_head * bh;
struct dir_entry * de;
- if (current->euid && current->uid)
+ if (!suser())
return -EPERM;
if (!(dir = dir_namei(name,&namelen,&basename)))
return -ENOENT;
@@ -518,7 +596,7 @@ int sys_rmdir(const char * name)
iput(dir);
return -ENOENT;
}
- bh = find_entry(dir,basename,namelen,&de);
+ bh = find_entry(&dir,basename,namelen,&de);
if (!bh) {
iput(dir);
return -ENOENT;
@@ -584,7 +662,7 @@ int sys_unlink(const char * name)
iput(dir);
return -EPERM;
}
- bh = find_entry(dir,basename,namelen,&de);
+ bh = find_entry(&dir,basename,namelen,&de);
if (!bh) {
iput(dir);
return -ENOENT;
@@ -596,12 +674,25 @@ int sys_unlink(const char * name)
brelse(bh);
return -ENOENT;
}
- if (!S_ISREG(inode->i_mode)) {
+ if (S_ISDIR(inode->i_mode)) {
iput(inode);
iput(dir);
brelse(bh);
return -EPERM;
}
+ /*
+ * If the directory has the sticky bit, the user must either
+ * own the file or own the directory or be the superuser to
+ * delete a file in that directory. This is typically used
+ * for /tmp and /usr/tmp.
+ */
+ if ((dir->i_mode & S_ISVTX) && (current->euid != inode->i_uid) &&
+ (current->euid != dir->i_uid) && !suser()) {
+ iput(inode);
+ iput(dir);
+ brelse(bh);
+ return -EPERM;
+ }
if (!inode->i_nlinks) {
printk("Deleting nonexistent file (%04x:%d), %d\n",
inode->i_dev,inode->i_num,inode->i_nlinks);
@@ -629,7 +720,7 @@ int sys_link(const char * oldname, const char * newname)
oldinode=namei(oldname);
if (!oldinode)
return -ENOENT;
- if (!S_ISREG(oldinode->i_mode)) {
+ if (S_ISDIR(oldinode->i_mode)) {
iput(oldinode);
return -EPERM;
}
@@ -653,7 +744,7 @@ int sys_link(const char * oldname, const char * newname)
iput(oldinode);
return -EACCES;
}
- bh = find_entry(dir,basename,namelen,&de);
+ bh = find_entry(&dir,basename,namelen,&de);
if (bh) {
brelse(bh);
iput(dir);
diff --git a/fs/open.c b/fs/open.c
index 6918690..3695ff1 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1,3 +1,9 @@
+/*
+ * linux/fs/open.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <string.h>
#include <errno.h>
#include <fcntl.h>
@@ -10,6 +16,11 @@
#include <linux/kernel.h>
#include <asm/segment.h>
+int sys_ustat(int dev, struct ustat * ubuf)
+{
+ return -ENOSYS;
+}
+
int sys_utime(char * filename, struct utimbuf * times)
{
struct m_inode * inode;
@@ -29,27 +40,35 @@ int sys_utime(char * filename, struct utimbuf * times)
return 0;
}
+/*
+ * XXX should we use the real or effective uid? BSD uses the real uid,
+ * so as to make this call useful to setuid programs.
+ */
int sys_access(const char * filename,int mode)
{
struct m_inode * inode;
- int res;
+ int res, i_mode;
mode &= 0007;
if (!(inode=namei(filename)))
return -EACCES;
- res = inode->i_mode & 0777;
+ i_mode = res = inode->i_mode & 0777;
iput(inode);
- if (!(current->euid && current->uid))
- if (res & 0111)
- res = 0777;
- else
- res = 0666;
- if (current->euid == inode->i_uid)
+ if (current->uid == inode->i_uid)
res >>= 6;
- else if (current->egid == inode->i_gid)
+ else if (current->gid == inode->i_gid)
res >>= 6;
if ((res & 0007 & mode) == mode)
return 0;
+ /*
+ * XXX we are doing this test last because we really should be
+ * swapping the effective with the real user id (temporarily),
+ * and then calling suser() routine. If we do call the
+ * suser() routine, it needs to be called last.
+ */
+ if ((!current->uid) &&
+ (!(mode & 1) || (i_mode & 0111)))
+ return 0;
return -EACCES;
}
@@ -89,12 +108,10 @@ int sys_chmod(const char * filename,int mode)
if (!(inode=namei(filename)))
return -ENOENT;
- if (current->uid && current->euid)
- if (current->uid!=inode->i_uid && current->euid!=inode->i_uid) {
- iput(inode);
- return -EACCES;
- } else
- mode = (mode & 0777) | (inode->i_mode & 07000);
+ if ((current->euid != inode->i_uid) && !suser()) {
+ iput(inode);
+ return -EACCES;
+ }
inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
inode->i_dirt = 1;
iput(inode);
@@ -107,7 +124,7 @@ int sys_chown(const char * filename,int uid,int gid)
if (!(inode=namei(filename)))
return -ENOENT;
- if (current->uid && current->euid) {
+ if (!suser()) {
iput(inode);
return -EACCES;
}
@@ -156,6 +173,9 @@ int sys_open(const char * filename,int flag,int mode)
f->f_count=0;
return -EPERM;
}
+/* Likewise with block-devices: check for floppy_change */
+ if (S_ISBLK(inode->i_mode))
+ check_disk_change(inode->i_zone[0]);
f->f_mode = inode->i_mode;
f->f_flags = flag;
f->f_count = 1;
diff --git a/fs/pipe.c b/fs/pipe.c
index 7e03e13..dfc4480 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1,3 +1,9 @@
+/*
+ * linux/fs/pipe.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <signal.h>
#include <linux/sched.h>
@@ -6,47 +12,60 @@
int read_pipe(struct m_inode * inode, char * buf, int count)
{
- char * b=buf;
+ int chars, size, read = 0;
- while (PIPE_EMPTY(*inode)) {
- wake_up(&inode->i_wait);
- if (inode->i_count != 2) /* are there any writers left? */
- return 0;
- sleep_on(&inode->i_wait);
- }
- while (count>0 && !(PIPE_EMPTY(*inode))) {
- count --;
- put_fs_byte(((char *)inode->i_size)[PIPE_TAIL(*inode)],b++);
- INC_PIPE( PIPE_TAIL(*inode) );
+ while (count>0) {
+ while (!(size=PIPE_SIZE(*inode))) {
+ wake_up(&inode->i_wait);
+ if (inode->i_count != 2) /* are there any writers? */
+ return read;
+ sleep_on(&inode->i_wait);
+ }
+ chars = PAGE_SIZE-PIPE_TAIL(*inode);
+ if (chars > count)
+ chars = count;
+ if (chars > size)
+ chars = size;
+ count -= chars;
+ read += chars;
+ size = PIPE_TAIL(*inode);
+ PIPE_TAIL(*inode) += chars;
+ PIPE_TAIL(*inode) &= (PAGE_SIZE-1);
+ while (chars-->0)
+ put_fs_byte(((char *)inode->i_size)[size++],buf++);
}
wake_up(&inode->i_wait);
- return b-buf;
+ return read;
}
int write_pipe(struct m_inode * inode, char * buf, int count)
{
- char * b=buf;
+ int chars, size, written = 0;
- wake_up(&inode->i_wait);
- if (inode->i_count != 2) { /* no readers */
- current->signal |= (1<<(SIGPIPE-1));
- return -1;
- }
- while (count-->0) {
- while (PIPE_FULL(*inode)) {
+ while (count>0) {
+ while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) {
wake_up(&inode->i_wait);
- if (inode->i_count != 2) {
+ if (inode->i_count != 2) { /* no readers */
current->signal |= (1<<(SIGPIPE-1));
- return b-buf;
+ return written?written:-1;
}
sleep_on(&inode->i_wait);
}
- ((char *)inode->i_size)[PIPE_HEAD(*inode)] = get_fs_byte(b++);
- INC_PIPE( PIPE_HEAD(*inode) );
- wake_up(&inode->i_wait);
+ chars = PAGE_SIZE-PIPE_HEAD(*inode);
+ if (chars > count)
+ chars = count;
+ if (chars > size)
+ chars = size;
+ count -= chars;
+ written += chars;
+ size = PIPE_HEAD(*inode);
+ PIPE_HEAD(*inode) += chars;
+ PIPE_HEAD(*inode) &= (PAGE_SIZE-1);
+ while (chars-->0)
+ ((char *)inode->i_size)[size++]=get_fs_byte(buf++);
}
wake_up(&inode->i_wait);
- return b-buf;
+ return written;
}
int sys_pipe(unsigned long * fildes)
diff --git a/fs/read_write.c b/fs/read_write.c
index 93faac2..f8f4e3e 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -1,3 +1,9 @@
+/*
+ * linux/fs/read_write.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <sys/stat.h>
#include <errno.h>
#include <sys/types.h>
@@ -6,7 +12,7 @@
#include <linux/sched.h>
#include <asm/segment.h>
-extern int rw_char(int rw,int dev, char * buf, int count);
+extern int rw_char(int rw,int dev, char * buf, int count, off_t * pos);
extern int read_pipe(struct m_inode * inode, char * buf, int count);
extern int write_pipe(struct m_inode * inode, char * buf, int count);
extern int block_read(int dev, off_t * pos, char * buf, int count);
@@ -22,7 +28,7 @@ int sys_lseek(unsigned int fd,off_t offset, int origin)
int tmp;
if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode)
- || !IS_BLOCKDEV(MAJOR(file->f_inode->i_dev)))
+ || !IS_SEEKABLE(MAJOR(file->f_inode->i_dev)))
return -EBADF;
if (file->f_inode->i_pipe)
return -ESPIPE;
@@ -60,7 +66,7 @@ int sys_read(unsigned int fd,char * buf,int count)
if (inode->i_pipe)
return (file->f_mode&1)?read_pipe(inode,buf,count):-1;
if (S_ISCHR(inode->i_mode))
- return rw_char(READ,inode->i_zone[0],buf,count);
+ return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos);
if (S_ISBLK(inode->i_mode))
return block_read(inode->i_zone[0],&file->f_pos,buf,count);
if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {
@@ -87,7 +93,7 @@ int sys_write(unsigned int fd,char * buf,int count)
if (inode->i_pipe)
return (file->f_mode&2)?write_pipe(inode,buf,count):-1;
if (S_ISCHR(inode->i_mode))
- return rw_char(WRITE,inode->i_zone[0],buf,count);
+ return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos);
if (S_ISBLK(inode->i_mode))
return block_write(inode->i_zone[0],&file->f_pos,buf,count);
if (S_ISREG(inode->i_mode))
diff --git a/fs/stat.c b/fs/stat.c
index 4bec71d..61a4ceb 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -1,3 +1,9 @@
+/*
+ * linux/fs/stat.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <errno.h>
#include <sys/stat.h>
@@ -6,7 +12,7 @@
#include <linux/kernel.h>
#include <asm/segment.h>
-static int cp_stat(struct m_inode * inode, struct stat * statbuf)
+static void cp_stat(struct m_inode * inode, struct stat * statbuf)
{
struct stat tmp;
int i;
@@ -25,19 +31,17 @@ static int cp_stat(struct m_inode * inode, struct stat * statbuf)
tmp.st_ctime = inode->i_ctime;
for (i=0 ; i<sizeof (tmp) ; i++)
put_fs_byte(((char *) &tmp)[i],&((char *) statbuf)[i]);
- return (0);
}
int sys_stat(char * filename, struct stat * statbuf)
{
- int i;
struct m_inode * inode;
if (!(inode=namei(filename)))
return -ENOENT;
- i=cp_stat(inode,statbuf);
+ cp_stat(inode,statbuf);
iput(inode);
- return i;
+ return 0;
}
int sys_fstat(unsigned int fd, struct stat * statbuf)
@@ -46,6 +50,7 @@ int sys_fstat(unsigned int fd, struct stat * statbuf)
struct m_inode * inode;
if (fd >= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode))
- return -ENOENT;
- return cp_stat(inode,statbuf);
+ return -EBADF;
+ cp_stat(inode,statbuf);
+ return 0;
}
diff --git a/fs/super.c b/fs/super.c
index d832289..25ba5b6 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1,9 +1,22 @@
/*
+ * linux/fs/super.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* super.c contains code to handle the super-block tables.
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <asm/system.h>
+
+#include <errno.h>
+#include <sys/stat.h>
+
+int sync_dev(int dev);
+void wait_for_keypress(void);
/* set_bit uses setb, as gas doesn't recognize setc */
#define set_bit(bitnr,addr) ({ \
@@ -12,59 +25,217 @@ __asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \
__res; })
struct super_block super_block[NR_SUPER];
+/* this is initialized in init/main.c */
+int ROOT_DEV = 0;
-struct super_block * do_mount(int dev)
+static void lock_super(struct super_block * sb)
{
- struct super_block * p;
+ cli();
+ while (sb->s_lock)
+ sleep_on(&(sb->s_wait));
+ sb->s_lock = 1;
+ sti();
+}
+
+static void free_super(struct super_block * sb)
+{
+ cli();
+ sb->s_lock = 0;
+ wake_up(&(sb->s_wait));
+ sti();
+}
+
+static void wait_on_super(struct super_block * sb)
+{
+ cli();
+ while (sb->s_lock)
+ sleep_on(&(sb->s_wait));
+ sti();
+}
+
+struct super_block * get_super(int dev)
+{
+ struct super_block * s;
+
+ if (!dev)
+ return NULL;
+ s = 0+super_block;
+ while (s < NR_SUPER+super_block)
+ if (s->s_dev == dev) {
+ wait_on_super(s);
+ if (s->s_dev == dev)
+ return s;
+ s = 0+super_block;
+ } else
+ s++;
+ return NULL;
+}
+
+void put_super(int dev)
+{
+ struct super_block * sb;
+ int i;
+
+ if (dev == ROOT_DEV) {
+ printk("root diskette changed: prepare for armageddon\n\r");
+ return;
+ }
+ if (!(sb = get_super(dev)))
+ return;
+ if (sb->s_imount) {
+ printk("Mounted disk changed - tssk, tssk\n\r");
+ return;
+ }
+ lock_super(sb);
+ sb->s_dev = 0;
+ for(i=0;i<I_MAP_SLOTS;i++)
+ brelse(sb->s_imap[i]);
+ for(i=0;i<Z_MAP_SLOTS;i++)
+ brelse(sb->s_zmap[i]);
+ free_super(sb);
+ return;
+}
+
+static struct super_block * read_super(int dev)
+{
+ struct super_block * s;
struct buffer_head * bh;
int i,block;
- for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++ )
- if (!(p->s_dev))
- break;
- p->s_dev = -1; /* mark it in use */
- if (p >= &super_block[NR_SUPER])
+ if (!dev)
return NULL;
- if (!(bh = bread(dev,1)))
+ check_disk_change(dev);
+ if (s = get_super(dev))
+ return s;
+ for (s = 0+super_block ;; s++) {
+ if (s >= NR_SUPER+super_block)
+ return NULL;
+ if (!s->s_dev)
+ break;
+ }
+ s->s_dev = dev;
+ s->s_isup = NULL;
+ s->s_imount = NULL;
+ s->s_time = 0;
+ s->s_rd_only = 0;
+ s->s_dirt = 0;
+ lock_super(s);
+ if (!(bh = bread(dev,1))) {
+ s->s_dev=0;
+ free_super(s);
return NULL;
- *p = *((struct super_block *) bh->b_data);
+ }
+ *((struct d_super_block *) s) =
+ *((struct d_super_block *) bh->b_data);
brelse(bh);
- if (p->s_magic != SUPER_MAGIC) {
- p->s_dev = 0;
+ if (s->s_magic != SUPER_MAGIC) {
+ s->s_dev = 0;
+ free_super(s);
return NULL;
}
for (i=0;i<I_MAP_SLOTS;i++)
- p->s_imap[i] = NULL;
+ s->s_imap[i] = NULL;
for (i=0;i<Z_MAP_SLOTS;i++)
- p->s_zmap[i] = NULL;
+ s->s_zmap[i] = NULL;
block=2;
- for (i=0 ; i < p->s_imap_blocks ; i++)
- if (p->s_imap[i]=bread(dev,block))
+ for (i=0 ; i < s->s_imap_blocks ; i++)
+ if (s->s_imap[i]=bread(dev,block))
block++;
else
break;
- for (i=0 ; i < p->s_zmap_blocks ; i++)
- if (p->s_zmap[i]=bread(dev,block))
+ for (i=0 ; i < s->s_zmap_blocks ; i++)
+ if (s->s_zmap[i]=bread(dev,block))
block++;
else
break;
- if (block != 2+p->s_imap_blocks+p->s_zmap_blocks) {
+ if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) {
for(i=0;i<I_MAP_SLOTS;i++)
- brelse(p->s_imap[i]);
+ brelse(s->s_imap[i]);
for(i=0;i<Z_MAP_SLOTS;i++)
- brelse(p->s_zmap[i]);
- p->s_dev=0;
+ brelse(s->s_zmap[i]);
+ s->s_dev=0;
+ free_super(s);
return NULL;
}
- p->s_imap[0]->b_data[0] |= 1;
- p->s_zmap[0]->b_data[0] |= 1;
- p->s_dev = dev;
- p->s_isup = NULL;
- p->s_imount = NULL;
- p->s_time = 0;
- p->s_rd_only = 0;
- p->s_dirt = 0;
- return p;
+ s->s_imap[0]->b_data[0] |= 1;
+ s->s_zmap[0]->b_data[0] |= 1;
+ free_super(s);
+ return s;
+}
+
+int sys_umount(char * dev_name)
+{
+ struct m_inode * inode;
+ struct super_block * sb;
+ int dev;
+
+ if (!(inode=namei(dev_name)))
+ return -ENOENT;
+ dev = inode->i_zone[0];
+ if (!S_ISBLK(inode->i_mode)) {
+ iput(inode);
+ return -ENOTBLK;
+ }
+ iput(inode);
+ if (dev==ROOT_DEV)
+ return -EBUSY;
+ if (!(sb=get_super(dev)) || !(sb->s_imount))
+ 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++)
+ if (inode->i_dev==dev && inode->i_count)
+ return -EBUSY;
+ sb->s_imount->i_mount=0;
+ iput(sb->s_imount);
+ sb->s_imount = NULL;
+ iput(sb->s_isup);
+ sb->s_isup = NULL;
+ put_super(dev);
+ sync_dev(dev);
+ return 0;
+}
+
+int sys_mount(char * dev_name, char * dir_name, int rw_flag)
+{
+ struct m_inode * dev_i, * dir_i;
+ struct super_block * sb;
+ int dev;
+
+ if (!(dev_i=namei(dev_name)))
+ return -ENOENT;
+ dev = dev_i->i_zone[0];
+ if (!S_ISBLK(dev_i->i_mode)) {
+ iput(dev_i);
+ return -EPERM;
+ }
+ iput(dev_i);
+ if (!(dir_i=namei(dir_name)))
+ return -ENOENT;
+ if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO) {
+ iput(dir_i);
+ return -EBUSY;
+ }
+ if (!S_ISDIR(dir_i->i_mode)) {
+ iput(dir_i);
+ return -EPERM;
+ }
+ if (!(sb=read_super(dev))) {
+ iput(dir_i);
+ return -EBUSY;
+ }
+ if (sb->s_imount) {
+ iput(dir_i);
+ return -EBUSY;
+ }
+ if (dir_i->i_mount) {
+ iput(dir_i);
+ return -EPERM;
+ }
+ sb->s_imount=dir_i;
+ dir_i->i_mount=1;
+ dir_i->i_dirt=1; /* NOTE! we don't iput(dir_i) */
+ return 0; /* we do that in umount */
}
void mount_root(void)
@@ -77,11 +248,18 @@ void mount_root(void)
panic("bad i-node size");
for(i=0;i<NR_FILE;i++)
file_table[i].f_count=0;
- for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++)
+ if (MAJOR(ROOT_DEV) == 2) {
+ printk("Insert root floppy and press ENTER");
+ wait_for_keypress();
+ }
+ for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++) {
p->s_dev = 0;
- if (!(p=do_mount(ROOT_DEV)))
+ p->s_lock = 0;
+ p->s_wait = NULL;
+ }
+ if (!(p=read_super(ROOT_DEV)))
panic("Unable to mount root");
- if (!(mi=iget(ROOT_DEV,1)))
+ if (!(mi=iget(ROOT_DEV,ROOT_INO)))
panic("Unable to read root i-node");
mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
p->s_isup = p->s_imount = mi;
diff --git a/fs/truncate.c b/fs/truncate.c
index fd82db8..36f3ea2 100644
--- a/fs/truncate.c
+++ b/fs/truncate.c
@@ -1,3 +1,9 @@
+/*
+ * linux/fs/truncate.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <linux/sched.h>
#include <sys/stat.h>
diff --git a/fs/tty_ioctl.c b/fs/tty_ioctl.c
index b4d9bf7..fd936dc 100644
--- a/fs/tty_ioctl.c
+++ b/fs/tty_ioctl.c
@@ -1,3 +1,9 @@
+/*
+ * linux/fs/tty_ioctl.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <errno.h>
#include <termios.h>
@@ -62,6 +68,9 @@ static int get_termio(struct tty_struct * tty, struct termio * termio)
return 0;
}
+/*
+ * This only works as the 386 is low-byt-first
+ */
static int set_termio(struct tty_struct * tty, struct termio * termio)
{
int i;
diff --git a/include/asm/segment.h b/include/asm/segment.h
index 1a53b08..936ed72 100644
--- a/include/asm/segment.h
+++ b/include/asm/segment.h
@@ -36,3 +36,30 @@ extern inline void put_fs_long(unsigned long val,unsigned long * addr)
{
__asm__ ("movl %0,%%fs:%1"::"r" (val),"m" (*addr));
}
+
+/*
+ * Someone who knows GNU asm better than I should double check the followig.
+ * It seems to work, but I don't know if I'm doing something subtly wrong.
+ * --- TYT, 11/24/91
+ */
+
+extern inline unsigned long get_fs()
+{
+ unsigned short _v;
+ __asm__("mov %%fs,%%ax":"=a" (_v):);
+ return _v;
+}
+
+extern inline unsigned long get_ds()
+{
+ unsigned short _v;
+ __asm__("mov %%ds,%%ax":"=a" (_v):);
+ return _v;
+}
+
+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 4043d6e..ad7cb77 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 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 c84cacc..e515cf1 100644
--- a/include/linux/config.h
+++ b/include/linux/config.h
@@ -1,53 +1,40 @@
#ifndef _CONFIG_H
#define _CONFIG_H
-/* #define LASU_HD */
-#define LINUS_HD
-
/*
- * Amount of ram memory (in bytes, 640k-1M not discounted). Currently 8Mb.
- * Don't make this bigger without making sure that there are enough page
- * directory entries (boot/head.s)
+ * The root-device is no longer hard-coded. You can change the default
+ * root-device by changing the line ROOT_DEV = XXX in boot/bootsect.s
*/
-#if defined(LINUS_HD)
-#define HIGH_MEMORY (0x800000)
-#elif defined(LASU_HD)
-#define HIGH_MEMORY (0x400000)
-#else
-#error "must define hd"
-#endif
-/* End of buffer memory. Must be 0xA0000, or > 0x100000, 4096-byte aligned */
-#if (HIGH_MEMORY>=0x600000)
-#define BUFFER_END 0x200000
-#else
-#define BUFFER_END 0xA0000
-#endif
-
-/* Root device at bootup. */
-#if defined(LINUS_HD)
-#define ROOT_DEV 0x306
-#elif defined(LASU_HD)
-#define ROOT_DEV 0x302
-#else
-#error "must define HD"
-#endif
+/* define your keyboard here - US (KBD_US) or Finnish (KBD_FINNISH) */
+#define KBD_US
+/* #define KBD_FINNISH */
/*
- * HD type. If 2, put 2 structures with a comma. If just 1, put
- * only 1 struct. The structs are { HEAD, SECTOR, TRACKS, WPCOM, LZONE, CTL }
+ * Normally, Linux can get the drive parameters from the BIOS at
+ * startup, but if this for some unfathomable reason fails, you'd
+ * be left stranded. For this case, you can define HD_TYPE, which
+ * contains all necessary info on your harddisk.
+ *
+ * The HD_TYPE macro should look like this:
+ *
+ * #define HD_TYPE { head, sect, cyl, wpcom, lzone, ctl}
*
- * NOTE. CTL is supposed to be 0 for drives with less than 8 heads, and
- * 8 if heads >= 8. Don't know why, and I haven't tested it on a drive with
- * more than 8 heads, but that is what the bios-listings seem to imply. I
- * just love not having a manual.
+ * In case of two harddisks, the info should be sepatated by
+ * commas:
+ *
+ * #define HD_TYPE { h,s,c,wpcom,lz,ctl },{ h,s,c,wpcom,lz,ctl }
*/
-#if defined(LASU_HD)
-#define HD_TYPE { 7,35,915,65536,920,0 }
-#elif defined(LINUS_HD)
-#define HD_TYPE { 5,17,980,300,980,0 },{ 5,17,980,300,980,0 }
-#else
-#error "must define a hard-disk type"
-#endif
+/*
+ This is an example, two drives, first is type 2, second is type 3:
+
+#define HD_TYPE { 4,17,615,300,615,8 }, { 6,17,615,300,615,0 }
+
+ NOTE: ctl is 0 for all drives with heads<=8, and ctl=8 for drives
+ with more than 8 heads.
+
+ If you want the BIOS to tell what kind of drive you have, just
+ leave HD_TYPE undefined.
+*/
#endif
diff --git a/include/linux/fdreg.h b/include/linux/fdreg.h
new file mode 100644
index 0000000..01355af
--- /dev/null
+++ b/include/linux/fdreg.h
@@ -0,0 +1,71 @@
+/*
+ * This file contains some defines for the floppy disk controller.
+ * Various sources. Mostly "IBM Microcomputers: A Programmers
+ * Handbook", Sanches and Canton.
+ */
+#ifndef _FDREG_H
+#define _FDREG_H
+
+extern int ticks_to_floppy_on(unsigned int nr);
+extern void floppy_on(unsigned int nr);
+extern void floppy_off(unsigned int nr);
+extern void floppy_select(unsigned int nr);
+extern void floppy_deselect(unsigned int nr);
+
+/* Fd controller regs. S&C, about page 340 */
+#define FD_STATUS 0x3f4
+#define FD_DATA 0x3f5
+#define FD_DOR 0x3f2 /* Digital Output Register */
+#define FD_DIR 0x3f7 /* Digital Input Register (read) */
+#define FD_DCR 0x3f7 /* Diskette Control Register (write)*/
+
+/* Bits of main status register */
+#define STATUS_BUSYMASK 0x0F /* drive busy mask */
+#define STATUS_BUSY 0x10 /* FDC busy */
+#define STATUS_DMA 0x20 /* 0- DMA mode */
+#define STATUS_DIR 0x40 /* 0- cpu->fdc */
+#define STATUS_READY 0x80 /* Data reg ready */
+
+/* Bits of FD_ST0 */
+#define ST0_DS 0x03 /* drive select mask */
+#define ST0_HA 0x04 /* Head (Address) */
+#define ST0_NR 0x08 /* Not Ready */
+#define ST0_ECE 0x10 /* Equipment chech error */
+#define ST0_SE 0x20 /* Seek end */
+#define ST0_INTR 0xC0 /* Interrupt code mask */
+
+/* Bits of FD_ST1 */
+#define ST1_MAM 0x01 /* Missing Address Mark */
+#define ST1_WP 0x02 /* Write Protect */
+#define ST1_ND 0x04 /* No Data - unreadable */
+#define ST1_OR 0x10 /* OverRun */
+#define ST1_CRC 0x20 /* CRC error in data or addr */
+#define ST1_EOC 0x80 /* End Of Cylinder */
+
+/* Bits of FD_ST2 */
+#define ST2_MAM 0x01 /* Missing Addess Mark (again) */
+#define ST2_BC 0x02 /* Bad Cylinder */
+#define ST2_SNS 0x04 /* Scan Not Satisfied */
+#define ST2_SEH 0x08 /* Scan Equal Hit */
+#define ST2_WC 0x10 /* Wrong Cylinder */
+#define ST2_CRC 0x20 /* CRC error in data field */
+#define ST2_CM 0x40 /* Control Mark = deleted */
+
+/* Bits of FD_ST3 */
+#define ST3_HA 0x04 /* Head (Address) */
+#define ST3_TZ 0x10 /* Track Zero signal (1=track 0) */
+#define ST3_WP 0x40 /* Write Protect */
+
+/* Values for FD_COMMAND */
+#define FD_RECALIBRATE 0x07 /* move to track 0 */
+#define FD_SEEK 0x0F /* seek track */
+#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */
+#define FD_WRITE 0xC5 /* write with MT, MFM */
+#define FD_SENSEI 0x08 /* Sense Interrupt Status */
+#define FD_SPECIFY 0x03 /* specify HUT etc */
+
+/* DMA commands */
+#define DMA_READ 0x46
+#define DMA_WRITE 0x4A
+
+#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index e5db892..da58aec 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -21,17 +21,19 @@
* 7 - unnamed pipes
*/
-#define IS_BLOCKDEV(x) ((x)==2 || (x)==3)
+#define IS_SEEKABLE(x) ((x)>=1 && (x)<=3)
#define READ 0
#define WRITE 1
+#define READA 2 /* read-ahead - don't pause */
-void buffer_init(void);
+void buffer_init(long buffer_end);
#define MAJOR(a) (((unsigned)(a))>>8)
#define MINOR(a) ((a)&0xff)
#define NAME_LEN 14
+#define ROOT_INO 1
#define I_MAP_SLOTS 8
#define Z_MAP_SLOTS 8
@@ -44,6 +46,7 @@ void buffer_init(void);
#define NR_HASH 307
#define NR_BUFFERS nr_buffers
#define BLOCK_SIZE 1024
+#define BLOCK_SIZE_BITS 10
#ifndef NULL
#define NULL ((void *) 0)
#endif
@@ -51,6 +54,14 @@ void buffer_init(void);
#define INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct d_inode)))
#define DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct dir_entry)))
+#define PIPE_HEAD(inode) ((inode).i_zone[0])
+#define PIPE_TAIL(inode) ((inode).i_zone[1])
+#define PIPE_SIZE(inode) ((PIPE_HEAD(inode)-PIPE_TAIL(inode))&(PAGE_SIZE-1))
+#define PIPE_EMPTY(inode) (PIPE_HEAD(inode)==PIPE_TAIL(inode))
+#define PIPE_FULL(inode) (PIPE_SIZE(inode)==(PAGE_SIZE-1))
+#define INC_PIPE(head) \
+__asm__("incl %0\n\tandl $4095,%0"::"m" (head))
+
typedef char buffer_block[BLOCK_SIZE];
struct buffer_head {
@@ -101,14 +112,6 @@ struct m_inode {
unsigned char i_update;
};
-#define PIPE_HEAD(inode) (((long *)((inode).i_zone))[0])
-#define PIPE_TAIL(inode) (((long *)((inode).i_zone))[1])
-#define PIPE_SIZE(inode) ((PIPE_HEAD(inode)-PIPE_TAIL(inode))&(PAGE_SIZE-1))
-#define PIPE_EMPTY(inode) (PIPE_HEAD(inode)==PIPE_TAIL(inode))
-#define PIPE_FULL(inode) (PIPE_SIZE(inode)==(PAGE_SIZE-1))
-#define INC_PIPE(head) \
-__asm__("incl %0\n\tandl $4095,%0"::"m" (head))
-
struct file {
unsigned short f_mode;
unsigned short f_flags;
@@ -133,10 +136,23 @@ struct super_block {
struct m_inode * s_isup;
struct m_inode * s_imount;
unsigned long s_time;
+ struct task_struct * s_wait;
+ unsigned char s_lock;
unsigned char s_rd_only;
unsigned char s_dirt;
};
+struct d_super_block {
+ unsigned short s_ninodes;
+ unsigned short s_nzones;
+ unsigned short s_imap_blocks;
+ unsigned short s_zmap_blocks;
+ unsigned short s_firstdatazone;
+ unsigned short s_log_zone_size;
+ unsigned long s_max_size;
+ unsigned short s_magic;
+};
+
struct dir_entry {
unsigned short inode;
char name[NAME_LEN];
@@ -148,6 +164,11 @@ extern struct super_block super_block[NR_SUPER];
extern struct buffer_head * start_buffer;
extern int nr_buffers;
+extern void check_disk_change(int dev);
+extern int floppy_change(unsigned int nr);
+extern int ticks_to_floppy_on(unsigned int dev);
+extern void floppy_on(unsigned int dev);
+extern void floppy_off(unsigned int dev);
extern void truncate(struct m_inode * inode);
extern void sync_inodes(void);
extern void wait_on(struct m_inode * inode);
@@ -165,21 +186,15 @@ 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 struct buffer_head * breada(int dev,int block,...);
extern int new_block(int dev);
extern void free_block(int dev, int block);
extern struct m_inode * new_inode(int dev);
extern void free_inode(struct m_inode * inode);
+extern int sync_dev(int dev);
+extern struct super_block * get_super(int dev);
+extern int ROOT_DEV;
extern void mount_root(void);
-extern inline struct super_block * get_super(int dev)
-{
- struct super_block * s;
-
- for(s = 0+super_block;s < NR_SUPER+super_block; s++)
- if (s->s_dev == dev)
- return s;
- return NULL;
-}
-
#endif
diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h
index 04ebf87..e6c593f 100644
--- a/include/linux/hdreg.h
+++ b/include/linux/hdreg.h
@@ -6,40 +6,6 @@
#ifndef _HDREG_H
#define _HDREG_H
-/* currently supports only 1 hd, put type here */
-#define HARD_DISK_TYPE 17
-
-/*
- * Ok, hard-disk-type is currently hardcoded. Not beatiful,
- * but easier. We don't use BIOS for anything else, why should
- * we get HD-type from it? Get these values from Reference Guide.
- */
-
-#if HARD_DISK_TYPE == 17
-#define _CYL 977
-#define _HEAD 5
-#define __WPCOM 300
-#define _LZONE 977
-#define _SECT 17
-#define _CTL 0
-#elif HARD_DISK_TYPE == 18
-#define _CYL 977
-#define _HEAD 7
-#define __WPCOM (-1)
-#define _LZONE 977
-#define _SECT 17
-#define _CTL 0
-#else
-#error Define HARD_DISK_TYPE and parameters, add your own entries as well
-#endif
-
-/* Controller wants just wp-com/4 */
-#if __WPCOM >= 0
-#define _WPCOM ((__WPCOM)>>2)
-#else
-#define _WPCOM __WPCOM
-#endif
-
/* Hd controller regs. Ref: IBM AT Bios-listing */
#define HD_DATA 0x1f0 /* _CTL when writing */
#define HD_ERROR 0x1f1 /* see err-bits */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 9e533a7..2f2fb75 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -6,3 +6,16 @@ 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);
+
+#define free(x) free_s((x), 0)
+
+/*
+ * This is defined as a macro, but at some point this might become a
+ * real subroutine that sets a flag if it returns true (to do
+ * BSD-style accounting where the process is flagged if it uses root
+ * privs). The implication of this is that you should do normal
+ * permissions checks first, and check suser() last.
+ */
+#define suser() (current->euid == 0)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index bf6b639..f41827f 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -10,6 +10,7 @@
#include <linux/head.h>
#include <linux/fs.h>
#include <linux/mm.h>
+#include <signal.h>
#if (NR_OPEN > 32)
#error "Currently the close-on-exec-flags are in one word, max 32 files/proc"
@@ -80,8 +81,8 @@ struct task_struct {
long counter;
long priority;
long signal;
- fn_ptr sig_restorer;
- fn_ptr sig_fn[32];
+ struct sigaction sigaction[32];
+ long blocked; /* bitmap of masked signals */
/* various fields */
int exit_code;
unsigned long end_code,end_data,brk,start_stack;
@@ -110,13 +111,13 @@ struct task_struct {
*/
#define INIT_TASK \
/* state etc */ { 0,15,15, \
-/* signals */ 0,NULL,{(fn_ptr) 0,}, \
+/* signals */ 0,{{},},0, \
/* ec,brk... */ 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,0133,NULL,NULL,0, \
+/* fs info */ -1,0022,NULL,NULL,0, \
/* filp */ {NULL,}, \
{ \
{0,0}, \
@@ -139,6 +140,7 @@ extern long startup_time;
#define CURRENT_TIME (startup_time+jiffies/HZ)
+extern void add_timer(long jiffies, void (*fn)(void));
extern void sleep_on(struct task_struct ** p);
extern void interruptible_sleep_on(struct task_struct ** p);
extern void wake_up(struct task_struct ** p);
@@ -169,15 +171,15 @@ __asm__("str %%ax\n\t" \
struct {long a,b;} __tmp; \
__asm__("cmpl %%ecx,_current\n\t" \
"je 1f\n\t" \
- "xchgl %%ecx,_current\n\t" \
"movw %%dx,%1\n\t" \
+ "xchgl %%ecx,_current\n\t" \
"ljmp %0\n\t" \
- "cmpl %%ecx,%2\n\t" \
+ "cmpl %%ecx,_last_task_used_math\n\t" \
"jne 1f\n\t" \
"clts\n" \
"1:" \
::"m" (*&__tmp.a),"m" (*&__tmp.b), \
- "m" (last_task_used_math),"d" _TSS(n),"c" ((long) task[n])); \
+ "d" (_TSS(n)),"c" ((long) task[n])); \
}
#define PAGE_ALIGN(n) (((n)+0xfff)&0xfffff000)
diff --git a/include/linux/sys.h b/include/linux/sys.h
index acdcc95..33f172c 100644
--- a/include/linux/sys.h
+++ b/include/linux/sys.h
@@ -65,6 +65,9 @@ extern int sys_dup2();
extern int sys_getppid();
extern int sys_getpgrp();
extern int sys_setsid();
+extern int sys_sigaction();
+extern int sys_sgetmask();
+extern int sys_ssetmask();
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,
@@ -77,4 +80,4 @@ 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_getpgrp,sys_setsid,sys_sigaction,sys_sgetmask,sys_ssetmask };
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 1d103e0..ad846b3 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -33,11 +33,14 @@ struct tty_queue {
#define PUTCH(c,queue) \
(void)({(queue).buf[(queue).head]=(c);INC((queue).head);})
-#define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF])
#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR])
-#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP])
-#define START_CHAR(tty) ((tty)->termios.c_cc[VSTART])
+#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT])
#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE])
+#define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL])
+#define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF])
+#define START_CHAR(tty) ((tty)->termios.c_cc[VSTART])
+#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP])
+#define SUSPEND_CHAR(tty) ((tty)->termios.c_cc[VSUSP])
struct tty_struct {
struct termios termios;
@@ -53,11 +56,11 @@ extern struct tty_struct tty_table[];
/* intr=^C quit=^| erase=del kill=^U
eof=^D vtime=\0 vmin=\1 sxtc=\0
- start=^Q stop=^S susp=^Y eol=\0
+ start=^Q stop=^S susp=^Z eol=\0
reprint=^R discard=^U werase=^W lnext=^V
eol2=\0
*/
-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\031\0\022\017\027\026\0"
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
void rs_init(void);
void con_init(void);
diff --git a/include/signal.h b/include/signal.h
index b895813..0eea9a3 100644
--- a/include/signal.h
+++ b/include/signal.h
@@ -35,6 +35,8 @@ typedef unsigned int sigset_t; /* 32 bits */
/* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */
#define SA_NOCLDSTOP 1
+#define SA_NOMASK 0x40000000
+#define SA_ONESHOT 0x80000000
#define SIG_BLOCK 0 /* for blocking signals */
#define SIG_UNBLOCK 1 /* for unblocking signals */
@@ -47,6 +49,7 @@ struct sigaction {
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
+ void (*sa_restorer)(void);
};
void (*signal(int _sig, void (*_func)(int)))(int);
diff --git a/include/unistd.h b/include/unistd.h
index eb10771..4418363 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -124,6 +124,7 @@
#define __NR_getppid 64
#define __NR_getpgrp 65
#define __NR_setsid 66
+#define __NR_sigaction 67
#define _syscall0(type,name) \
type name(void) \
diff --git a/init/main.c b/init/main.c
index 1192119..ce55e24 100644
--- a/init/main.c
+++ b/init/main.c
@@ -1,3 +1,9 @@
+/*
+ * linux/init/main.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#define __LIBRARY__
#include <unistd.h>
#include <time.h>
@@ -16,7 +22,7 @@
*/
static inline _syscall0(int,fork)
static inline _syscall0(int,pause)
-static inline _syscall0(int,setup)
+static inline _syscall1(int,setup,void *,BIOS)
static inline _syscall0(int,sync)
#include <linux/tty.h>
@@ -37,11 +43,22 @@ static char printbuf[1024];
extern int vsprintf();
extern void init(void);
+extern void blk_dev_init(void);
+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 kernel_mktime(struct tm * tm);
extern long startup_time;
/*
+ * This is set up by the setup-routine at boot-time
+ */
+#define EXT_MEM_K (*(unsigned short *)0x90002)
+#define DRIVE_INFO (*(struct drive_info *)0x90080)
+#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
+
+/*
* Yeah, yeah, it's ugly, but I cannot find how to do this correctly
* and this seems to work. I anybody has more info on the real-time
* clock I'd be interested. Most of this was trial and error, and some
@@ -64,7 +81,7 @@ static void time_init(void)
time.tm_min = CMOS_READ(2);
time.tm_hour = CMOS_READ(4);
time.tm_mday = CMOS_READ(7);
- time.tm_mon = CMOS_READ(8)-1;
+ time.tm_mon = CMOS_READ(8);
time.tm_year = CMOS_READ(9);
} while (time.tm_sec != CMOS_READ(0));
BCD_TO_BIN(time.tm_sec);
@@ -73,21 +90,41 @@ static void time_init(void)
BCD_TO_BIN(time.tm_mday);
BCD_TO_BIN(time.tm_mon);
BCD_TO_BIN(time.tm_year);
+ time.tm_mon--;
startup_time = kernel_mktime(&time);
}
+static long memory_end = 0;
+static long buffer_memory_end = 0;
+
+struct drive_info { char dummy[32]; } drive_info;
+
void main(void) /* This really IS void, no error here. */
{ /* The startup routine assumes (well, ...) this */
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
- time_init();
- tty_init();
+ ROOT_DEV = ORIG_ROOT_DEV;
+ drive_info = DRIVE_INFO;
+ memory_end = (1<<20) + (EXT_MEM_K<<10);
+ memory_end &= 0xfffff000;
+ if (memory_end > 16*1024*1024)
+ memory_end = 16*1024*1024;
+ if (memory_end > 6*1024*1024)
+ buffer_memory_end = 2*1024*1024;
+ else
+ buffer_memory_end = 1*1024*1024;
+ mem_init(buffer_memory_end,memory_end);
trap_init();
+ blk_dev_init();
+ chr_dev_init();
+ tty_init();
+ time_init();
sched_init();
- buffer_init();
+ buffer_init(buffer_memory_end);
hd_init();
+ floppy_init();
sti();
move_to_user_mode();
if (!fork()) { /* we count on this going ok */
@@ -114,14 +151,14 @@ static int printf(const char *fmt, ...)
return i;
}
-static char * argv[] = { "-",NULL };
+static char * argv[] = { "-/bin/sh",NULL };
static char * envp[] = { "HOME=/usr/root", NULL };
void init(void)
{
int i,j;
- setup();
+ setup((void *) &drive_info);
if (!fork())
_exit(execve("/bin/update",NULL,NULL));
(void) open("/dev/tty0",O_RDWR,0);
@@ -129,6 +166,7 @@ void init(void)
(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");
diff --git a/kernel/Makefile b/kernel/Makefile
index 23fe7dd..d75e141 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -25,29 +25,28 @@ CPP =gcc -E -nostdinc -I../include
-c -o $*.o $<
OBJS = sched.o system_call.o traps.o asm.o fork.o \
- panic.o printk.o vsprintf.o tty_io.o console.o \
- keyboard.o rs_io.o hd.o sys.o exit.o serial.o \
- mktime.o
+ panic.o printk.o vsprintf.o sys.o exit.o \
+ signal.o mktime.o
kernel.o: $(OBJS)
$(LD) -r -o kernel.o $(OBJS)
sync
clean:
- rm -f core *.o *.a tmp_make
+ rm -f core *.o *.a tmp_make keyboard.s
for i in *.c;do rm -f `basename $$i .c`.s;done
+ (cd chr_drv; make clean)
+ (cd blk_drv; make clean)
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
+ (cd chr_drv; make dep)
+ (cd blk_drv; make dep)
### Dependencies:
-console.s console.o : console.c ../include/linux/sched.h ../include/linux/head.h \
- ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
- ../include/linux/tty.h ../include/termios.h ../include/asm/io.h \
- ../include/asm/system.h
exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \
../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
@@ -55,36 +54,29 @@ exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \
../include/asm/segment.h
fork.s fork.o : fork.c ../include/errno.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/linux/mm.h ../include/linux/kernel.h ../include/asm/segment.h \
- ../include/asm/system.h
-hd.s hd.o : hd.c ../include/linux/config.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/linux/mm.h ../include/linux/kernel.h ../include/linux/hdreg.h \
- ../include/asm/system.h ../include/asm/io.h ../include/asm/segment.h
+ ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
+ ../include/asm/segment.h ../include/asm/system.h
mktime.s mktime.o : mktime.c ../include/time.h
-panic.s panic.o : panic.c ../include/linux/kernel.h
+panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
+ ../include/linux/mm.h ../include/signal.h
printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \
../include/linux/kernel.h
sched.s sched.o : sched.c ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
- ../include/linux/kernel.h ../include/signal.h ../include/linux/sys.h \
- ../include/asm/system.h ../include/asm/io.h ../include/asm/segment.h
-serial.s serial.o : serial.c ../include/linux/tty.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/asm/system.h \
- ../include/asm/io.h
+ ../include/signal.h ../include/linux/kernel.h ../include/linux/sys.h \
+ ../include/linux/fdreg.h ../include/asm/system.h ../include/asm/io.h \
+ ../include/asm/segment.h
+signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
+ ../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h
sys.s sys.o : sys.c ../include/errno.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/linux/mm.h ../include/linux/tty.h ../include/termios.h \
- ../include/linux/kernel.h ../include/asm/segment.h ../include/sys/times.h \
- ../include/sys/utsname.h
+ ../include/linux/mm.h ../include/signal.h ../include/linux/tty.h \
+ ../include/termios.h ../include/linux/kernel.h ../include/asm/segment.h \
+ ../include/sys/times.h ../include/sys/utsname.h
traps.s traps.o : traps.c ../include/string.h ../include/linux/head.h \
../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/linux/mm.h ../include/linux/kernel.h ../include/asm/system.h \
- ../include/asm/segment.h
-tty_io.s tty_io.o : tty_io.c ../include/ctype.h ../include/errno.h \
- ../include/signal.h ../include/sys/types.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
- ../include/linux/tty.h ../include/termios.h ../include/asm/segment.h \
- ../include/asm/system.h
+ ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
+ ../include/asm/system.h ../include/asm/segment.h ../include/asm/io.h
vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h
diff --git a/kernel/asm.s b/kernel/asm.s
index 6fe1981..c19900f 100644
--- a/kernel/asm.s
+++ b/kernel/asm.s
@@ -1,4 +1,10 @@
/*
+ * linux/kernel/asm.s
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* asm.s contains the low-level code for most hardware faults.
* page_exception is handled by the mm, so that isn't here. This
* file also handles (hopefully) fpu-exceptions due to TS-bit, as
@@ -8,7 +14,7 @@
.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
.globl _device_not_available,_double_fault,_coprocessor_segment_overrun
.globl _invalid_TSS,_segment_not_present,_stack_segment
-.globl _general_protection,_coprocessor_error,_reserved
+.globl _general_protection,_coprocessor_error,_irq13,_reserved
_divide_error:
pushl $_do_divide_error
@@ -75,12 +81,9 @@ math_emulate:
_device_not_available:
pushl %eax
movl %cr0,%eax
- bt $2,%eax # EM (math emulation bit)
- jc math_emulate
+ testl $0x4,%eax # EM (math emulation bit)
+ jne math_emulate
clts # clear TS so that we can use math
- movl _current,%eax
- cmpl _last_task_used_math,%eax
- je 1f # shouldn't happen really ...
pushl %ecx
pushl %edx
push %ds
@@ -90,7 +93,7 @@ _device_not_available:
pop %ds
popl %edx
popl %ecx
-1: popl %eax
+ popl %eax
iret
_coprocessor_segment_overrun:
@@ -101,7 +104,18 @@ _reserved:
pushl $_do_reserved
jmp no_error_code
+_irq13:
+ pushl %eax
+ xorb %al,%al
+ outb %al,$0xF0
+ movb $0x20,%al
+ outb %al,$0x20
+ jmp 1f
+1: jmp 1f
+1: outb %al,$0xA0
+ popl %eax
_coprocessor_error:
+ fnclex
pushl $_do_coprocessor_error
jmp no_error_code
diff --git a/kernel/blk_drv/Makefile b/kernel/blk_drv/Makefile
new file mode 100644
index 0000000..a830c3f
--- /dev/null
+++ b/kernel/blk_drv/Makefile
@@ -0,0 +1,58 @@
+#
+# Makefile for the FREAX-kernel block device drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+AR =gar
+AS =gas
+LD =gld
+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 = ll_rw_blk.o floppy.o hd.o
+
+blk_drv.a: $(OBJS)
+ $(AR) rcs blk_drv.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:
+floppy.s floppy.o : floppy.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/linux/kernel.h \
+ ../../include/linux/fdreg.h ../../include/asm/system.h \
+ ../../include/asm/io.h ../../include/asm/segment.h blk.h
+hd.s hd.o : hd.c ../../include/linux/config.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h \
+ ../../include/sys/types.h ../../include/linux/mm.h ../../include/signal.h \
+ ../../include/linux/kernel.h ../../include/linux/hdreg.h \
+ ../../include/asm/system.h ../../include/asm/io.h \
+ ../../include/asm/segment.h blk.h
+ll_rw_blk.s ll_rw_blk.o : ll_rw_blk.c ../../include/errno.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h \
+ ../../include/sys/types.h ../../include/linux/mm.h ../../include/signal.h \
+ ../../include/linux/kernel.h ../../include/asm/system.h blk.h
diff --git a/kernel/blk_drv/blk.h b/kernel/blk_drv/blk.h
new file mode 100644
index 0000000..1682465
--- /dev/null
+++ b/kernel/blk_drv/blk.h
@@ -0,0 +1,116 @@
+#ifndef _BLK_H
+#define _BLK_H
+
+#define NR_BLK_DEV 7
+#define NR_REQUEST 64
+
+/*
+ * Ok, this is an expanded form so that we can use the same
+ * request for paging requests when that is implemented. In
+ * paging, 'bh' is NULL, and 'waiting' is used to wait for
+ * read/write completion.
+ */
+struct request {
+ int dev; /* -1 if no request */
+ int cmd; /* READ or WRITE */
+ int errors;
+ unsigned long sector;
+ unsigned long nr_sectors;
+ char * buffer;
+ struct task_struct * waiting;
+ struct buffer_head * bh;
+ struct request * next;
+};
+
+#define IN_ORDER(s1,s2) \
+((s1)->dev < (s2)->dev || ((s1)->dev == (s2)->dev && \
+(s1)->sector < (s2)->sector))
+
+struct blk_dev_struct {
+ void (*request_fn)(void);
+ struct request * current_request;
+};
+
+extern struct blk_dev_struct blk_dev[NR_BLK_DEV];
+extern struct request request[NR_REQUEST];
+extern struct task_struct * wait_for_request;
+
+#ifdef MAJOR_NR
+
+/*
+ * Add entries as needed. Currently the only block devices
+ * supported are hard-disks and floppies.
+ */
+#if (MAJOR_NR == 2)
+/* floppy */
+#define DEVICE_NAME "floppy"
+#define DEVICE_INTR do_floppy
+#define DEVICE_REQUEST do_fd_request
+#define DEVICE_NR(device) ((device) & 3)
+#define DEVICE_ON(device) floppy_on(DEVICE_NR(device))
+#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device))
+
+#elif (MAJOR_NR == 3)
+/* harddisk */
+#define DEVICE_NAME "harddisk"
+#define DEVICE_INTR do_hd
+#define DEVICE_REQUEST do_hd_request
+#define DEVICE_NR(device) (MINOR(device)/5)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif
+/* unknown blk device */
+#error "unknown blk device"
+
+#endif
+
+#define CURRENT (blk_dev[MAJOR_NR].current_request)
+#define CURRENT_DEV DEVICE_NR(CURRENT->dev)
+
+void (*DEVICE_INTR)(void) = NULL;
+static void (DEVICE_REQUEST)(void);
+
+extern inline void unlock_buffer(struct buffer_head * bh)
+{
+ if (!bh->b_lock)
+ printk(DEVICE_NAME ": free buffer being unlocked\n");
+ bh->b_lock=0;
+ wake_up(&bh->b_wait);
+}
+
+extern inline void end_request(int uptodate)
+{
+ DEVICE_OFF(CURRENT->dev);
+ if (CURRENT->bh) {
+ CURRENT->bh->b_uptodate = uptodate;
+ unlock_buffer(CURRENT->bh);
+ }
+ if (!uptodate) {
+ printk(DEVICE_NAME " I/O error\n\r");
+ printk("dev %04x, block %d\n\r",CURRENT->dev,
+ CURRENT->bh->b_blocknr);
+ }
+ wake_up(&CURRENT->waiting);
+ wake_up(&wait_for_request);
+ CURRENT->dev = -1;
+ CURRENT = CURRENT->next;
+}
+
+#define INIT_REQUEST \
+repeat: \
+ if (!CURRENT) \
+ return; \
+ if (MAJOR(CURRENT->dev) != MAJOR_NR) \
+ panic(DEVICE_NAME ": request list destroyed"); \
+ 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
+
+#endif
diff --git a/kernel/blk_drv/floppy.c b/kernel/blk_drv/floppy.c
new file mode 100644
index 0000000..47ee961
--- /dev/null
+++ b/kernel/blk_drv/floppy.c
@@ -0,0 +1,382 @@
+/*
+ * linux/kernel/floppy.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * 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
+ * call "floppy-on" directly, but have to set a special timer interrupt
+ * etc.
+ *
+ * Also, I'm not certain this works on more than 1 floppy. Bugs may
+ * abund.
+ */
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/fdreg.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
+#define MAJOR_NR 2
+#include "blk.h"
+
+static void reset_floppy(void);
+static void seek_interrupt(void);
+static void rw_interrupt(void);
+
+extern unsigned char current_DOR;
+extern unsigned char selected;
+
+#define immoutb_p(val,port) \
+__asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port))
+
+#define TYPE(x) ((x)>>2)
+#define DRIVE(x) ((x)&0x03)
+/*
+ * Note that MAX_ERRORS=10 doesn't imply that we retry every bad read
+ * max 10 times - some types of errors increase the errorcount by 2,
+ * so we might actually retry only 6-7 times before giving up.
+ */
+#define MAX_ERRORS 10
+
+/*
+ * globals used by 'result()'
+ */
+#define MAX_REPLIES 7
+static unsigned char reply_buffer[MAX_REPLIES];
+#define ST0 (reply_buffer[0])
+#define ST1 (reply_buffer[1])
+#define ST2 (reply_buffer[2])
+#define ST3 (reply_buffer[3])
+
+/*
+ * 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.
+ *
+ * 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 char gap,rate,spec1;
+} floppy_type[] = {
+ { 0, 0,0, 0,0,0x00,0x00,0x00 }, /* no testing */
+ { 720, 9,2,40,0,0x2A,0x02,0xDF }, /* 360kB PC diskettes */
+ { 2400,15,2,80,0,0x1B,0x00,0xDF }, /* 1.2 MB AT-diskettes */
+ { 720, 9,2,40,1,0x2A,0x02,0xDF }, /* 360kB in 720kB drive */
+ { 1440, 9,2,80,0,0x2A,0x02,0xDF }, /* 3.5" 720kB diskette */
+ { 720, 9,2,40,1,0x23,0x01,0xDF }, /* 360kB in 1.2MB drive */
+ { 1440, 9,2,80,0,0x23,0x01,0xDF }, /* 720kB in 1.2MB drive */
+ { 2880,18,2,80,0,0x1B,0x00,0xCF }, /* 1.44MB diskette */
+};
+/*
+ * Rate is 0 for 500kb/s, 2 for 300kbps, 1 for 250kbps
+ * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
+ * H is head unload time (1=16ms, 2=32ms, etc)
+ *
+ * Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms etc)
+ * and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA).
+ */
+
+extern void floppy_interrupt(void);
+extern char tmp_floppy_area[1024];
+
+/*
+ * These are global variables, as that's the easiest way to give
+ * information to interrupts. They are the data used for the current
+ * request.
+ */
+static int cur_spec1 = -1;
+static int cur_rate = -1;
+static struct floppy_struct * floppy = floppy_type;
+static unsigned char current_drive = 0;
+static unsigned char sector = 0;
+static unsigned char head = 0;
+static unsigned char track = 0;
+static unsigned char seek_track = 0;
+static unsigned char command = 0;
+
+/*
+ * floppy-change is never called from an interrupt, so we can relax a bit
+ * here.
+ */
+int floppy_change(unsigned int nr)
+{
+ floppy_on(nr);
+ floppy_select(nr);
+ if (inb(FD_DIR) & 0x80) {
+ floppy_off(nr);
+ return 1;
+ }
+ floppy_off(nr);
+ return 0;
+}
+
+#define copy_buffer(from,to) \
+__asm__("cld ; rep ; movsl" \
+ ::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \
+ :"cx","di","si")
+
+static void setup_DMA(void)
+{
+ long addr = (long) CURRENT->buffer;
+
+ if (addr >= 0x100000) {
+ addr = (long) tmp_floppy_area;
+ if (command == FD_WRITE)
+ copy_buffer(CURRENT->buffer,tmp_floppy_area);
+ }
+/* mask DMA 2 */
+ immoutb_p(4|2,10);
+/* output command byte. I don't know why, but everyone (minix, */
+/* sanches & canton) output this twice, first to 12 then to 11 */
+ __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t"
+ "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:"::
+ "a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE)));
+/* 8 low bits of addr */
+ immoutb_p(addr,4);
+ addr >>= 8;
+/* bits 8-15 of addr */
+ immoutb_p(addr,4);
+ addr >>= 8;
+/* bits 16-19 of addr */
+ immoutb_p(addr,0x81);
+/* low 8 bits of count-1 (1024-1=0x3ff) */
+ immoutb_p(0xff,5);
+/* high 8 bits of count-1 */
+ immoutb_p(3,5);
+/* activate DMA 2 */
+ immoutb_p(0|2,10);
+}
+
+static void output_byte(char byte)
+{
+ int counter;
+ unsigned char status;
+
+ for(counter = 0 ; counter < 10000 ; counter++) {
+ status = inb(FD_STATUS) & (STATUS_READY | STATUS_DIR);
+ if (status == STATUS_READY) {
+ outb(byte,FD_DATA);
+ return;
+ }
+ }
+ printk("Unable to send byte to FDC\n\r");
+}
+
+static int result(void)
+{
+ int i = 0, counter, status;
+
+ for (counter = 0 ; counter < 10000 ; counter++) {
+ status = inb(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);
+ }
+ }
+ printk("Getstatus times out\n\r");
+ return -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.
+ */
+static void seek_interrupt(void)
+{
+/* sense drive status */
+ output_byte(FD_SENSEI);
+ if (result() != 2 || (ST0 & 0xF8) != 0x20) {
+ CURRENT->errors++;
+ if (CURRENT->errors > MAX_ERRORS) {
+ floppy_deselect(current_drive);
+ end_request(0);
+ reset_floppy();
+ return;
+ }
+ output_byte(FD_RECALIBRATE);
+ output_byte(head<<2 | current_drive);
+ 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 */
+ setup_DMA();
+ do_floppy = rw_interrupt;
+ output_byte(command);
+ output_byte(head<<2 | current_drive);
+ output_byte(track);
+ output_byte(head);
+ output_byte(sector);
+ output_byte(2); /* sector size = 512 */
+ output_byte(floppy->sect);
+ output_byte(floppy->gap);
+ output_byte(0xFF); /* sector size (0xff when n!=0 ?) */
+}
+
+/*
+ * Ok, this interrupt is called after a DMA read/write has succeeded,
+ * so we check the results, and copy any buffers.
+ */
+static void rw_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);
+ 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();
+}
+
+/*
+ * This routine is called when everything should be correctly set up
+ * for the transfer (ie floppy motor is on and the correct floppy is
+ * selected).
+ */
+static void transfer(void)
+{
+ if (cur_spec1 != floppy->spec1) {
+ cur_spec1 = floppy->spec1;
+ output_byte(FD_SPECIFY);
+ output_byte(cur_spec1); /* hut etc */
+ output_byte(6); /* Head load time =6ms, DMA */
+ }
+ if (cur_rate != floppy->rate)
+ outb_p(cur_rate = floppy->rate,FD_DCR);
+ do_floppy = seek_interrupt;
+ if (seek_track) {
+ output_byte(FD_SEEK);
+ output_byte(head<<2 | current_drive);
+ output_byte(seek_track);
+ } else {
+ output_byte(FD_RECALIBRATE);
+ output_byte(head<<2 | current_drive);
+ }
+}
+
+/*
+ * Special case - used after a unexpected interrupt (or reset)
+ */
+static void recal_interrupt(void)
+{
+ do_floppy = NULL;
+ output_byte(FD_SENSEI);
+ if (result()!=2 || (ST0 & 0xE0) == 0x60) {
+ reset_floppy();
+ return;
+ }
+ do_fd_request();
+}
+
+void unexpected_floppy_interrupt(void)
+{
+ output_byte(FD_SENSEI);
+ if (result()!=2 || (ST0 & 0xE0) == 0x60) {
+ reset_floppy();
+ return;
+ }
+ do_floppy = recal_interrupt;
+ output_byte(FD_RECALIBRATE);
+ output_byte(head<<2 | current_drive);
+}
+
+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);
+}
+
+static void reset_floppy(void)
+{
+ printk("Reset-floppy called\n\r");
+ do_floppy = reset_interrupt;
+ outb_p(0,FD_DOR);
+ outb(current_DOR,FD_DOR);
+}
+
+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();
+}
+
+void do_fd_request(void)
+{
+ unsigned int block;
+
+ INIT_REQUEST;
+ floppy = (MINOR(CURRENT->dev)>>2) + floppy_type;
+ current_drive = CURRENT_DEV;
+ block = CURRENT->sector;
+ if (block+2 > floppy->size) {
+ end_request(0);
+ goto repeat;
+ }
+ sector = block % floppy->sect;
+ block /= floppy->sect;
+ head = block % floppy->head;
+ track = block / floppy->head;
+ seek_track = track << floppy->stretch;
+ sector++;
+ if (CURRENT->cmd == READ)
+ command = FD_READ;
+ else if (CURRENT->cmd == WRITE)
+ command = FD_WRITE;
+ else
+ panic("do_fd_request: unknown command");
+ add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt);
+}
+
+void floppy_init(void)
+{
+ blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+ set_intr_gate(0x26,&floppy_interrupt);
+ outb(inb_p(0x21)&~0x40,0x21);
+}
diff --git a/kernel/blk_drv/hd.c b/kernel/blk_drv/hd.c
new file mode 100644
index 0000000..bfb8701
--- /dev/null
+++ b/kernel/blk_drv/hd.c
@@ -0,0 +1,283 @@
+/*
+ * linux/kernel/hd.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * This is the low-level hd interrupt support. It traverses the
+ * request-list, using interrupts to jump between functions. As
+ * all the functions are called within interrupts, we may not
+ * sleep. Special care is recommended.
+ */
+
+#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/io.h>
+#include <asm/segment.h>
+
+#define MAJOR_NR 3
+#include "blk.h"
+
+/* Max read/write errors/sector */
+#define MAX_ERRORS 5
+#define MAX_HD 2
+
+/*
+ * This struct defines the HD's and their types.
+ */
+struct hd_i_struct {
+ int head,sect,cyl,wpcom,lzone,ctl;
+ };
+#ifdef HD_TYPE
+struct hd_i_struct hd_info[] = { HD_TYPE };
+#define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
+#else
+struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
+static int NR_HD = 0;
+#endif
+
+static struct hd_struct {
+ long start_sect;
+ long nr_sects;
+} hd[5*MAX_HD]={{0,0},};
+
+#define port_read(port,buf,nr) \
+__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
+
+#define port_write(port,buf,nr) \
+__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
+
+extern void hd_interrupt(void);
+
+/* This may be used only once, enforced by 'static int callable' */
+int sys_setup(void * BIOS)
+{
+ static int callable = 1;
+ int i,drive;
+ struct partition *p;
+ struct buffer_head * bh;
+
+ if (!callable)
+ return -1;
+ callable = 0;
+#ifndef HD_TYPE
+ for (drive=0 ; drive<2 ; drive++) {
+ hd_info[drive].cyl = *(unsigned short *) BIOS;
+ hd_info[drive].head = *(unsigned char *) (2+BIOS);
+ hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
+ hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
+ hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
+ hd_info[drive].sect = *(unsigned char *) (14+BIOS);
+ BIOS += 16;
+ }
+ if (hd_info[1].cyl)
+ NR_HD=2;
+ else
+ NR_HD=1;
+#endif
+ for (i=0 ; i<NR_HD ; i++) {
+ hd[i*5].start_sect = 0;
+ hd[i*5].nr_sects = hd_info[i].head*
+ hd_info[i].sect*hd_info[i].cyl;
+ }
+ for (drive=0 ; drive<NR_HD ; drive++) {
+ if (!(bh = bread(0x300 + drive*5,0))) {
+ printk("Unable to read partition table of drive %d\n\r",
+ drive);
+ panic("");
+ }
+ if (bh->b_data[510] != 0x55 || (unsigned char)
+ bh->b_data[511] != 0xAA) {
+ printk("Bad partition table on drive %d\n\r",drive);
+ panic("");
+ }
+ p = 0x1BE + (void *)bh->b_data;
+ for (i=1;i<5;i++,p++) {
+ hd[i+5*drive].start_sect = p->start_sect;
+ hd[i+5*drive].nr_sects = p->nr_sects;
+ }
+ brelse(bh);
+ }
+ printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
+ mount_root();
+ return (0);
+}
+
+static int controller_ready(void)
+{
+ int retries=1000;
+
+ while (--retries && (inb(HD_STATUS)&0xc0)!=0x40);
+ return (retries);
+}
+
+static int win_result(void)
+{
+ int i=inb(HD_STATUS);
+
+ if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
+ == (READY_STAT | SEEK_STAT))
+ return(0); /* ok */
+ if (i&1) i=inb(HD_ERROR);
+ return (1);
+}
+
+static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
+ unsigned int head,unsigned int cyl,unsigned int cmd,
+ void (*intr_addr)(void))
+{
+ register int port asm("dx");
+
+ if (drive>1 || head>15)
+ panic("Trying to write bad sector");
+ if (!controller_ready())
+ panic("HD controller not ready");
+ do_hd = intr_addr;
+ outb(hd_info[drive].ctl,HD_CMD);
+ port=HD_DATA;
+ outb_p(hd_info[drive].wpcom>>2,++port);
+ outb_p(nsect,++port);
+ outb_p(sect,++port);
+ outb_p(cyl,++port);
+ outb_p(cyl>>8,++port);
+ outb_p(0xA0|(drive<<4)|head,++port);
+ outb(cmd,++port);
+}
+
+static int drive_busy(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < 100000; i++)
+ if (READY_STAT == (inb(HD_STATUS) & (BUSY_STAT | READY_STAT)))
+ break;
+ i = inb(HD_STATUS);
+ i &= BUSY_STAT | READY_STAT | SEEK_STAT;
+ if (i == READY_STAT | SEEK_STAT)
+ return(0);
+ printk("HD controller times out\n\r");
+ return(1);
+}
+
+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 */;
+ if (drive_busy())
+ printk("HD-controller still busy\n\r");
+ if((i = inb(ERR_STAT)) != 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);
+}
+
+void unexpected_hd_interrupt(void)
+{
+ printk("Unexpected HD interrupt\n\r");
+}
+
+static void bad_rw_intr(void)
+{
+ int i = CURRENT_DEV;
+
+ if (CURRENT->errors++ >= MAX_ERRORS)
+ end_request(0);
+ reset_hd(i);
+}
+
+static void read_intr(void)
+{
+ if (win_result()) {
+ bad_rw_intr();
+ return;
+ }
+ port_read(HD_DATA,CURRENT->buffer,256);
+ CURRENT->errors = 0;
+ CURRENT->buffer += 512;
+ CURRENT->sector++;
+ if (--CURRENT->nr_sectors)
+ return;
+ end_request(1);
+ do_hd_request();
+}
+
+static void write_intr(void)
+{
+ if (win_result()) {
+ bad_rw_intr();
+ return;
+ }
+ if (--CURRENT->nr_sectors) {
+ CURRENT->sector++;
+ CURRENT->buffer += 512;
+ port_write(HD_DATA,CURRENT->buffer,256);
+ return;
+ }
+ end_request(1);
+ do_hd_request();
+}
+
+void do_hd_request(void)
+{
+ int i,r;
+ unsigned int block,dev;
+ unsigned int sec,head,cyl;
+ unsigned int nsect;
+
+ INIT_REQUEST;
+ dev = MINOR(CURRENT->dev);
+ block = CURRENT->sector;
+ if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) {
+ end_request(0);
+ goto repeat;
+ }
+ block += hd[dev].start_sect;
+ dev /= 5;
+ __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0),
+ "r" (hd_info[dev].sect));
+ __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0),
+ "r" (hd_info[dev].head));
+ sec++;
+ nsect = CURRENT->nr_sectors;
+ if (CURRENT->cmd == WRITE) {
+ hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
+ for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
+ /* nothing */ ;
+ if (!r) {
+ reset_hd(CURRENT_DEV);
+ return;
+ }
+ port_write(HD_DATA,CURRENT->buffer,256);
+ } else if (CURRENT->cmd == READ) {
+ hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
+ } else
+ panic("unknown hd-command");
+}
+
+void hd_init(void)
+{
+ blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+ set_trap_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
new file mode 100644
index 0000000..ae8741b
--- /dev/null
+++ b/kernel/blk_drv/ll_rw_blk.c
@@ -0,0 +1,143 @@
+/*
+ * linux/kernel/blk_dev/ll_rw.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * This handles all read/write requests to block devices
+ */
+#include <errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+
+#include "blk.h"
+
+/*
+ * The request-struct contains all necessary data
+ * to load a nr of sectors into memory
+ */
+struct request request[NR_REQUEST];
+
+/*
+ * used to wait on when there are no free requests
+ */
+struct task_struct * wait_for_request = NULL;
+
+/* blk_dev_struct is:
+ * do_request-address
+ * next-request
+ */
+struct blk_dev_struct blk_dev[NR_BLK_DEV] = {
+ { NULL, NULL }, /* no_dev */
+ { NULL, NULL }, /* dev mem */
+ { NULL, NULL }, /* dev fd */
+ { NULL, NULL }, /* dev hd */
+ { NULL, NULL }, /* dev ttyx */
+ { NULL, NULL }, /* dev tty */
+ { NULL, NULL } /* dev lp */
+};
+
+static inline void lock_buffer(struct buffer_head * bh)
+{
+ cli();
+ while (bh->b_lock)
+ sleep_on(&bh->b_wait);
+ bh->b_lock=1;
+ sti();
+}
+
+static inline void unlock_buffer(struct buffer_head * bh)
+{
+ if (!bh->b_lock)
+ printk("ll_rw_block.c: buffer not locked\n\r");
+ bh->b_lock = 0;
+ wake_up(&bh->b_wait);
+}
+
+/*
+ * add-request adds a request to the linked list.
+ * It disables interrupts so that it can muck with the
+ * request-lists in peace.
+ */
+static void add_request(struct blk_dev_struct * dev, struct request * req)
+{
+ struct request * tmp;
+
+ req->next = NULL;
+ cli();
+ 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;
+ }
+ sti();
+}
+
+static void make_request(int major,int rw, struct buffer_head * bh)
+{
+ struct request * req;
+
+/* READA is special case - the read 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 (bh->b_lock)
+ return;
+ else
+ rw=READ;
+ }
+ if (rw!=READ && rw!=WRITE)
+ panic("Bad block dev command, must be R/W/RA");
+ 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++)
+ if (req->dev<0)
+ break;
+ if (req==NR_REQUEST+request) {
+ sleep_on(&wait_for_request);
+ goto repeat;
+ }
+ req->dev = bh->b_dev;
+ req->cmd = rw;
+ req->errors=0;
+ req->sector = bh->b_blocknr<<1;
+ req->nr_sectors = 2;
+ req->buffer = bh->b_data;
+ req->waiting = NULL;
+ req->bh = bh;
+ req->next = NULL;
+ add_request(major+blk_dev,req);
+}
+
+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");
+ make_request(major,rw,bh);
+}
+
+void blk_dev_init(void)
+{
+ int i;
+
+ for (i=0 ; i<NR_REQUEST ; i++) {
+ request[i].dev = -1;
+ request[i].next = NULL;
+ }
+}
diff --git a/kernel/blk_drv/ramdisk.c b/kernel/blk_drv/ramdisk.c
new file mode 100644
index 0000000..0131376
--- /dev/null
+++ b/kernel/blk_drv/ramdisk.c
@@ -0,0 +1,40 @@
+/*
+ * linux/kernel/blk_drv/ramdisk.c
+ *
+ * Written by Theodore Ts'o
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/hdreg.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/memory.h>
+
+#define MAJOR_NR 1
+#include "blk.h"
+
+char *ram_disk; /* Start of ram disk */
+int ram_disk_size; /* Size of ram disk */
+
+void do_ram_request(void)
+{
+ int i,r;
+ unsigned int block,dev;
+ unsigned int sec,head,cyl;
+ unsigned int nsect;
+
+ INIT_REQUEST;
+ if (MINOR(CURRENT->dev) != 0) {
+ end_request(0);
+ goto repeat;
+ }
+ block = CURRENT->sector;
+ end_request(1);
+}
+
+void ram_init(void)
+{
+
+}
diff --git a/kernel/chr_drv/Makefile b/kernel/chr_drv/Makefile
new file mode 100644
index 0000000..1405638
--- /dev/null
+++ b/kernel/chr_drv/Makefile
@@ -0,0 +1,61 @@
+#
+# 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 = tty_io.o console.o keyboard.o serial.o rs_io.o
+
+chr_drv.a: $(OBJS)
+ $(AR) rcs chr_drv.a $(OBJS)
+ sync
+
+keyboard.s: keyboard.S ../../include/linux/config.h
+ $(CPP) -traditional keyboard.S -o keyboard.s
+
+clean:
+ rm -f core *.o *.a tmp_make keyboard.s
+ 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:
+console.s console.o : console.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/linux/tty.h ../../include/termios.h ../../include/asm/io.h \
+ ../../include/asm/system.h
+serial.s serial.o : serial.c ../../include/linux/tty.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/asm/system.h ../../include/asm/io.h
+tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \
+ ../../include/signal.h ../../include/sys/types.h \
+ ../../include/linux/sched.h ../../include/linux/head.h \
+ ../../include/linux/fs.h ../../include/linux/mm.h ../../include/linux/tty.h \
+ ../../include/termios.h ../../include/asm/segment.h \
+ ../../include/asm/system.h
diff --git a/kernel/console.c b/kernel/chr_drv/console.c
index 9e00b31..3ca4169 100644
--- a/kernel/console.c
+++ b/kernel/chr_drv/console.c
@@ -1,4 +1,10 @@
/*
+ * linux/kernel/console.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* console.c
*
* This module implements the console io functions
@@ -20,6 +26,12 @@
#include <asm/io.h>
#include <asm/system.h>
+/*
+ * These are set up by the setup-routine at boot-time:
+ */
+#define ORIG_X (*(unsigned char *)0x90000)
+#define ORIG_Y (*(unsigned char *)0x90001)
+
#define SCREEN_START 0xb8000
#define SCREEN_END 0xc0000
#define LINES 25
@@ -45,9 +57,10 @@ static unsigned char attr=0x07;
*/
#define RESPONSE "\033[?1;2c"
+/* NOTE! gotoxy thinks x==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 > columns || new_y >= lines)
return;
x=new_x;
y=new_y;
@@ -313,7 +326,7 @@ static void delete_line(void)
bottom=oldbottom;
}
-static void csi_at(int nr)
+static void csi_at(unsigned int nr)
{
if (nr>columns)
nr=columns;
@@ -323,7 +336,7 @@ static void csi_at(int nr)
insert_char();
}
-static void csi_L(int nr)
+static void csi_L(unsigned int nr)
{
if (nr>lines)
nr=lines;
@@ -333,7 +346,7 @@ static void csi_L(int nr)
insert_line();
}
-static void csi_P(int nr)
+static void csi_P(unsigned int nr)
{
if (nr>columns)
nr=columns;
@@ -343,7 +356,7 @@ static void csi_P(int nr)
delete_char();
}
-static void csi_M(int nr)
+static void csi_M(unsigned int nr)
{
if (nr>lines)
nr=lines;
@@ -364,9 +377,7 @@ static void save_cur(void)
static void restore_cur(void)
{
- x=saved_x;
- y=saved_y;
- pos=origin+((y*columns+x)<<1);
+ gotoxy(saved_x, saved_y);
}
void con_write(struct tty_struct * tty)
@@ -541,7 +552,7 @@ void con_init(void)
{
register unsigned char a;
- gotoxy(*(unsigned char *)(0x90000+510),*(unsigned char *)(0x90000+511));
+ gotoxy(ORIG_X,ORIG_Y);
set_trap_gate(0x21,&keyboard_interrupt);
outb_p(inb_p(0x21)&0xfd,0x21);
a=inb_p(0x61);
diff --git a/kernel/keyboard.s b/kernel/chr_drv/keyboard.S
index ba54be5..120ca12 100644
--- a/kernel/keyboard.s
+++ b/kernel/chr_drv/keyboard.S
@@ -1,7 +1,15 @@
/*
- * keyboard.s
+ * linux/kernel/keyboard.S
+ *
+ * (C) 1991 Linus Torvalds
*/
+/*
+ * Thanks to Alfred Leung for US keyboard patches
+ */
+
+#include <linux/config.h>
+
.text
.globl _keyboard_interrupt
@@ -18,6 +26,7 @@ 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
@@ -129,7 +138,9 @@ unrshift:
andb $0xfd,mode
ret
-caps: testb $0x80,mode
+caps: testb $0x1,flags
+ je ctrl
+ testb $0x80,mode
jne 1f
xorb $4,leds
xorb $0x40,mode
@@ -142,7 +153,9 @@ set_leds:
movb leds,%al
outb %al,$0x60
ret
-uncaps: andb $0x7f,mode
+uncaps: testb $0x1,flags
+ je unctrl
+ andb $0x7f,mode
ret
scroll:
xorb $1,leds
@@ -193,6 +206,13 @@ cur_table:
* this routine handles function keys
*/
func:
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ call _show_stat
+ popl %edx
+ popl %ecx
+ popl %eax
subb $0x3B,%al
jb end_func
cmpb $9,%al
@@ -219,12 +239,13 @@ func_table:
.long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b
.long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b
+#if defined(KBD_FINNISH)
key_map:
.byte 0,27
.ascii "1234567890+'"
.byte 127,9
.ascii "qwertyuiop}"
- .byte 0,10,0
+ .byte 0,13,0
.ascii "asdfghjkl|{"
.byte 0,0
.ascii "'zxcvbnm,.-"
@@ -240,7 +261,7 @@ shift_map:
.ascii "!\"#$%&/()=?`"
.byte 127,9
.ascii "QWERTYUIOP]^"
- .byte 10,0
+ .byte 13,0
.ascii "ASDFGHJKL\\["
.byte 0,0
.ascii "*ZXCVBNM;:_"
@@ -256,7 +277,7 @@ alt_map:
.ascii "\0@\0$\0\0{[]}\\\0"
.byte 0,0
.byte 0,0,0,0,0,0,0,0,0,0,0
- .byte '~,10,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
@@ -267,6 +288,60 @@ alt_map:
.byte '|
.fill 10,1,0
+#elif defined(KBD_US)
+
+key_map:
+ .byte 0,27
+ .ascii "1234567890-="
+ .byte 127,9
+ .ascii "qwertyuiop[]"
+ .byte 13,0
+ .ascii "asdfghjkl;'"
+ .byte '`,0
+ .ascii "\\zxcvbnm,./"
+ .byte 0,'*,0,32 /* 36-39 */
+ .fill 16,1,0 /* 3A-49 */
+ .byte '-,0,0,0,'+ /* 4A-4E */
+ .byte 0,0,0,0,0,0,0 /* 4F-55 */
+ .byte '<
+ .fill 10,1,0
+
+
+shift_map:
+ .byte 0,27
+ .ascii "!@#$%^&*()_+"
+ .byte 127,9
+ .ascii "QWERTYUIOP{}"
+ .byte 13,0
+ .ascii "ASDFGHJKL:\""
+ .byte '~,0
+ .ascii "|ZXCVBNM<>?"
+ .byte 0,'*,0,32 /* 36-39 */
+ .fill 16,1,0 /* 3A-49 */
+ .byte '-,0,0,0,'+ /* 4A-4E */
+ .byte 0,0,0,0,0,0,0 /* 4F-55 */
+ .byte '>
+ .fill 10,1,0
+
+alt_map:
+ .byte 0,0
+ .ascii "\0@\0$\0\0{[]}\\\0"
+ .byte 0,0
+ .byte 0,0,0,0,0,0,0,0,0,0,0
+ .byte '~,13,0
+ .byte 0,0,0,0,0,0,0,0,0,0,0
+ .byte 0,0
+ .byte 0,0,0,0,0,0,0,0,0,0,0
+ .byte 0,0,0,0 /* 36-39 */
+ .fill 16,1,0 /* 3A-49 */
+ .byte 0,0,0,0,0 /* 4A-4E */
+ .byte 0,0,0,0,0,0,0 /* 4F-55 */
+ .byte '|
+ .fill 10,1,0
+
+#else
+#error "KBD-type not defined"
+#endif
/*
* do_self handles "normal" keys, ie keys that don't change meaning
* and which have just one character returns.
@@ -286,7 +361,7 @@ do_self:
je 2f
cmpb $'a,%al
jb 2f
- cmpb $'z,%al
+ cmpb $'},%al
ja 2f
subb $32,%al
2: testb $0x0c,mode /* ctrl */
@@ -314,6 +389,19 @@ 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
@@ -335,7 +423,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_self,caps,func /* 38-3B alt sp caps f1 */
+ .long alt,do_space,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/rs_io.s b/kernel/chr_drv/rs_io.s
index 62f075f..b300643 100644
--- a/kernel/rs_io.s
+++ b/kernel/chr_drv/rs_io.s
@@ -1,4 +1,10 @@
/*
+ * linux/kernel/rs_io.s
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* rs_io.s
*
* This module implements the rs232 io interrupts.
@@ -99,10 +105,10 @@ read_char:
cmpl tail(%ecx),%ebx
je 1f
movl %ebx,head(%ecx)
- pushl %edx
+1: pushl %edx
call _do_tty_interrupt
addl $4,%esp
-1: ret
+ ret
.align 2
write_char:
diff --git a/kernel/serial.c b/kernel/chr_drv/serial.c
index f542513..aba25df 100644
--- a/kernel/serial.c
+++ b/kernel/chr_drv/serial.c
@@ -1,4 +1,10 @@
/*
+ * linux/kernel/serial.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* serial.c
*
* This module implements the rs232 io functions
diff --git a/kernel/tty_io.c b/kernel/chr_drv/tty_io.c
index 68a390c..ec92914 100644
--- a/kernel/tty_io.c
+++ b/kernel/chr_drv/tty_io.c
@@ -1,4 +1,10 @@
/*
+ * linux/kernel/tty_io.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* '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 ...)
@@ -8,6 +14,10 @@
#include <signal.h>
#define ALRMMASK (1<<(SIGALRM-1))
+#define KILLMASK (1<<(SIGKILL-1))
+#define INTMASK (1<<(SIGINT-1))
+#define QUITMASK (1<<(SIGQUIT-1))
+#define TSTPMASK (1<<(SIGTSTP-1))
#include <linux/sched.h>
#include <linux/tty.h>
@@ -39,7 +49,7 @@
struct tty_struct tty_table[] = {
{
- {0,
+ {ICRNL,
OPOST|ONLCR, /* change outgoing NL to CRNL */
0,
ICANON | ECHO | ECHOCTL | ECHOKE,
@@ -97,7 +107,7 @@ void tty_init(void)
con_init();
}
-void tty_intr(struct tty_struct * tty, int signal)
+void tty_intr(struct tty_struct * tty, int mask)
{
int i;
@@ -105,7 +115,7 @@ void tty_intr(struct tty_struct * tty, int signal)
return;
for (i=0;i<NR_TASKS;i++)
if (task[i] && task[i]->pgrp==tty->pgrp)
- task[i]->signal |= 1<<(signal-1);
+ task[i]->signal |= mask;
}
static void sleep_if_empty(struct tty_queue * queue)
@@ -126,6 +136,11 @@ static void sleep_if_full(struct tty_queue * queue)
sti();
}
+void wait_for_keypress(void)
+{
+ sleep_if_empty(&tty_table[0].secondary);
+}
+
void copy_to_cooked(struct tty_struct * tty)
{
signed char c;
@@ -168,7 +183,11 @@ void copy_to_cooked(struct tty_struct * tty)
}
if (!L_ISIG(tty)) {
if (c==INTR_CHAR(tty)) {
- tty_intr(tty,SIGINT);
+ tty_intr(tty,INTMASK);
+ continue;
+ }
+ if (c==KILL_CHAR(tty)) {
+ tty_intr(tty,KILLMASK);
continue;
}
}
@@ -299,8 +318,16 @@ int tty_write(unsigned channel, char * buf, int nr)
* hate intel for all time :-). We'll have to
* be careful and see to reinstating the interrupt
* chips before calling this, though.
+ *
+ * I don't think we sleep here under normal circumstances
+ * anyway, which is good, as the task sleeping might be
+ * totally innocent.
*/
void do_tty_interrupt(int tty)
{
copy_to_cooked(tty_table+tty);
}
+
+void chr_dev_init(void)
+{
+}
diff --git a/kernel/exit.c b/kernel/exit.c
index 3402c33..1b0aa03 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -1,3 +1,9 @@
+/*
+ * linux/kernel/exit.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
@@ -26,39 +32,69 @@ void release(struct task_struct * p)
panic("trying to release non-existent task");
}
-static inline void send_sig(long sig,struct task_struct * p,int priv)
+static inline int send_sig(long sig,struct task_struct * p,int priv)
{
if (!p || sig<1 || sig>32)
- return;
- if (priv ||
- current->uid==p->uid ||
- current->euid==p->uid ||
- current->uid==p->euid ||
- current->euid==p->euid)
+ return -EINVAL;
+ if (priv || (current->euid==p->euid) || suser())
p->signal |= (1<<(sig-1));
+ else
+ return -EPERM;
+ return 0;
}
-void do_kill(long pid,long sig,int priv)
+static void kill_session(void)
+{
+ struct task_struct **p = NR_TASKS + task;
+
+ while (--p > &FIRST_TASK) {
+ if (*p && (*p)->session == current->session)
+ (*p)->signal |= 1<<(SIGHUP-1);
+ }
+}
+
+/*
+ * XXX need to check permissions needed to send signals to process
+ * groups, etc. etc. kill() permissions semantics are tricky!
+ */
+int sys_kill(int pid,int sig)
{
struct task_struct **p = NR_TASKS + task;
+ int err, retval = 0;
if (!pid) while (--p > &FIRST_TASK) {
- if (*p && (*p)->pgrp == current->pid)
- send_sig(sig,*p,priv);
+ if (*p && (*p)->pgrp == current->pid)
+ if (err=send_sig(sig,*p,1))
+ retval = err;
} else if (pid>0) while (--p > &FIRST_TASK) {
- if (*p && (*p)->pid == pid)
- send_sig(sig,*p,priv);
+ if (*p && (*p)->pid == pid)
+ if (err=send_sig(sig,*p,0))
+ retval = err;
} else if (pid == -1) while (--p > &FIRST_TASK)
- send_sig(sig,*p,priv);
+ if (err = send_sig(sig,*p,0))
+ retval = err;
else while (--p > &FIRST_TASK)
if (*p && (*p)->pgrp == -pid)
- send_sig(sig,*p,priv);
+ if (err = send_sig(sig,*p,0))
+ retval = err;
+ return retval;
}
-int sys_kill(int pid,int sig)
+static void tell_father(int pid)
{
- do_kill(pid,sig,!(current->uid || current->euid));
- return 0;
+ int i;
+
+ if (pid)
+ for (i=0;i<NR_TASKS;i++) {
+ if (!task[i])
+ continue;
+ if (task[i]->pid != pid)
+ continue;
+ task[i]->signal |= (1<<(SIGCHLD-1));
+ return;
+ }
+/* if we don't find any fathers, we just release ourselves */
+ release(current);
}
int do_exit(long code)
@@ -81,12 +117,11 @@ int do_exit(long code)
tty_table[current->tty].pgrp = 0;
if (last_task_used_math == current)
last_task_used_math = NULL;
- if (current->father) {
- current->state = TASK_ZOMBIE;
- do_kill(current->father,SIGCHLD,1);
- current->exit_code = code;
- } else
- release(current);
+ if (current->leader)
+ kill_session();
+ current->state = TASK_ZOMBIE;
+ current->exit_code = code;
+ tell_father(current->father);
schedule();
return (-1); /* just to suppress warnings */
}
@@ -96,34 +131,52 @@ int sys_exit(int error_code)
return do_exit((error_code&0xff)<<8);
}
-int sys_waitpid(pid_t pid,int * stat_addr, int options)
+int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
{
- int flag=0;
+ int flag;
struct task_struct ** p;
verify_area(stat_addr,4);
repeat:
- for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
- if (*p && *p != current &&
- (pid==-1 || (*p)->pid==pid ||
- (pid==0 && (*p)->pgrp==current->pgrp) ||
- (pid<0 && (*p)->pgrp==-pid)))
- if ((*p)->father == current->pid) {
+ flag=0;
+ for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
+ if (!*p || *p == current)
+ continue;
+ if ((*p)->father != current->pid)
+ continue;
+ if (pid>0) {
+ if ((*p)->pid != pid)
+ continue;
+ } else if (!pid) {
+ if ((*p)->pgrp != current->pgrp)
+ continue;
+ } else if (pid != -1) {
+ if ((*p)->pgrp != -pid)
+ continue;
+ }
+ switch ((*p)->state) {
+ case TASK_STOPPED:
+ if (!(options & WUNTRACED))
+ continue;
+ put_fs_long(0x7f,stat_addr);
+ return (*p)->pid;
+ case TASK_ZOMBIE:
+ current->cutime += (*p)->utime;
+ current->cstime += (*p)->stime;
+ flag = (*p)->pid;
+ put_fs_long((*p)->exit_code,stat_addr);
+ release(*p);
+ return flag;
+ default:
flag=1;
- if ((*p)->state==TASK_ZOMBIE) {
- put_fs_long((*p)->exit_code,
- (unsigned long *) stat_addr);
- current->cutime += (*p)->utime;
- current->cstime += (*p)->stime;
- flag = (*p)->pid;
- release(*p);
- return flag;
- }
- }
+ continue;
+ }
+ }
if (flag) {
if (options & WNOHANG)
return 0;
- sys_pause();
+ current->state=TASK_INTERRUPTIBLE;
+ schedule();
if (!(current->signal &= ~(1<<(SIGCHLD-1))))
goto repeat;
else
diff --git a/kernel/fork.c b/kernel/fork.c
index 70f9ddd..f776896 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1,4 +1,10 @@
/*
+ * linux/kernel/fork.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* 'fork.c' contains the help-routines for the 'fork' system call
* (see also system_call.s), and some misc functions ('verify_area').
* Fork is rather simple, once you get the hang of it, but the memory
diff --git a/kernel/hd.c b/kernel/hd.c
deleted file mode 100644
index d3e6140..0000000
--- a/kernel/hd.c
+++ /dev/null
@@ -1,413 +0,0 @@
-#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/io.h>
-#include <asm/segment.h>
-
-/*
- * This code handles all hd-interrupts, and read/write requests to
- * the hard-disk. It is relatively straigthforward (not obvious maybe,
- * but interrupts never are), while still being efficient, and never
- * disabling interrupts (except to overcome possible race-condition).
- * The elevator block-seek algorithm doesn't need to disable interrupts
- * due to clever programming.
- */
-
-/* Max read/write errors/sector */
-#define MAX_ERRORS 5
-#define MAX_HD 2
-#define NR_REQUEST 32
-
-/*
- * This struct defines the HD's and their types.
- * Currently defined for CP3044's, ie a modified
- * type 17.
- */
-static struct hd_i_struct{
- int head,sect,cyl,wpcom,lzone,ctl;
- } hd_info[]= { HD_TYPE };
-
-#define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
-
-static struct hd_struct {
- long start_sect;
- long nr_sects;
-} hd[5*MAX_HD]={{0,0},};
-
-static struct hd_request {
- int hd; /* -1 if no request */
- int nsector;
- int sector;
- int head;
- int cyl;
- int cmd;
- int errors;
- struct buffer_head * bh;
- struct hd_request * next;
-} request[NR_REQUEST];
-
-#define IN_ORDER(s1,s2) \
-((s1)->hd<(s2)->hd || (s1)->hd==(s2)->hd && \
-((s1)->cyl<(s2)->cyl || (s1)->cyl==(s2)->cyl && \
-((s1)->head<(s2)->head || (s1)->head==(s2)->head && \
-((s1)->sector<(s2)->sector))))
-
-static struct hd_request * this_request = NULL;
-
-static int sorting=0;
-
-static void do_request(void);
-static void reset_controller(void);
-static void rw_abs_hd(int rw,unsigned int nr,unsigned int sec,unsigned int head,
- unsigned int cyl,struct buffer_head * bh);
-void hd_init(void);
-
-#define port_read(port,buf,nr) \
-__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
-
-#define port_write(port,buf,nr) \
-__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
-
-extern void hd_interrupt(void);
-
-static struct task_struct * wait_for_request=NULL;
-
-static inline void lock_buffer(struct buffer_head * bh)
-{
- if (bh->b_lock)
- printk("hd.c: buffer multiply locked\n");
- bh->b_lock=1;
-}
-
-static inline void unlock_buffer(struct buffer_head * bh)
-{
- if (!bh->b_lock)
- printk("hd.c: free buffer being unlocked\n");
- bh->b_lock=0;
- wake_up(&bh->b_wait);
-}
-
-static inline void wait_on_buffer(struct buffer_head * bh)
-{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
-}
-
-void rw_hd(int rw, struct buffer_head * bh)
-{
- unsigned int block,dev;
- unsigned int sec,head,cyl;
-
- block = bh->b_blocknr << 1;
- dev = MINOR(bh->b_dev);
- if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects)
- return;
- block += hd[dev].start_sect;
- dev /= 5;
- __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0),
- "r" (hd_info[dev].sect));
- __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0),
- "r" (hd_info[dev].head));
- rw_abs_hd(rw,dev,sec+1,head,cyl,bh);
-}
-
-/* This may be used only once, enforced by 'static int callable' */
-int sys_setup(void)
-{
- static int callable = 1;
- int i,drive;
- struct partition *p;
-
- if (!callable)
- return -1;
- callable = 0;
- for (drive=0 ; drive<NR_HD ; drive++) {
- rw_abs_hd(READ,drive,1,0,0,(struct buffer_head *) start_buffer);
- if (!start_buffer->b_uptodate) {
- printk("Unable to read partition table of drive %d\n\r",
- drive);
- panic("");
- }
- if (start_buffer->b_data[510] != 0x55 || (unsigned char)
- start_buffer->b_data[511] != 0xAA) {
- printk("Bad partition table on drive %d\n\r",drive);
- panic("");
- }
- p = 0x1BE + (void *)start_buffer->b_data;
- for (i=1;i<5;i++,p++) {
- hd[i+5*drive].start_sect = p->start_sect;
- hd[i+5*drive].nr_sects = p->nr_sects;
- }
- }
- printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
- mount_root();
- return (0);
-}
-
-/*
- * This is the pointer to a routine to be executed at every hd-interrupt.
- * Interesting way of doing things, but should be rather practical.
- */
-void (*do_hd)(void) = NULL;
-
-static int controller_ready(void)
-{
- int retries=1000;
-
- while (--retries && (inb(HD_STATUS)&0xc0)!=0x40);
- return (retries);
-}
-
-static int win_result(void)
-{
- int i=inb(HD_STATUS);
-
- if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
- == (READY_STAT | SEEK_STAT))
- return(0); /* ok */
- if (i&1) i=inb(HD_ERROR);
- return (1);
-}
-
-static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
- unsigned int head,unsigned int cyl,unsigned int cmd,
- void (*intr_addr)(void))
-{
- register int port asm("dx");
-
- if (drive>1 || head>15)
- panic("Trying to write bad sector");
- if (!controller_ready())
- panic("HD controller not ready");
- do_hd = intr_addr;
- outb(_CTL,HD_CMD);
- port=HD_DATA;
- outb_p(_WPCOM,++port);
- outb_p(nsect,++port);
- outb_p(sect,++port);
- outb_p(cyl,++port);
- outb_p(cyl>>8,++port);
- outb_p(0xA0|(drive<<4)|head,++port);
- outb(cmd,++port);
-}
-
-static int drive_busy(void)
-{
- unsigned int i;
-
- for (i = 0; i < 100000; i++)
- if (READY_STAT == (inb(HD_STATUS) & (BUSY_STAT | READY_STAT)))
- break;
- i = inb(HD_STATUS);
- i &= BUSY_STAT | READY_STAT | SEEK_STAT;
- if (i == READY_STAT | SEEK_STAT)
- return(0);
- printk("HD controller times out\n\r");
- return(1);
-}
-
-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 */;
- if (drive_busy())
- printk("HD-controller still busy\n\r");
- if((i = inb(ERR_STAT)) != 1)
- printk("HD-controller reset failed: %02x\n\r",i);
-}
-
-static void reset_hd(int nr)
-{
- reset_controller();
- hd_out(nr,_SECT,_SECT,_HEAD-1,_CYL,WIN_SPECIFY,&do_request);
-}
-
-void unexpected_hd_interrupt(void)
-{
- panic("Unexpected HD interrupt\n\r");
-}
-
-static void bad_rw_intr(void)
-{
- int i = this_request->hd;
-
- if (this_request->errors++ >= MAX_ERRORS) {
- this_request->bh->b_uptodate = 0;
- unlock_buffer(this_request->bh);
- wake_up(&wait_for_request);
- this_request->hd = -1;
- this_request=this_request->next;
- }
- reset_hd(i);
-}
-
-static void read_intr(void)
-{
- if (win_result()) {
- bad_rw_intr();
- return;
- }
- port_read(HD_DATA,this_request->bh->b_data+
- 512*(this_request->nsector&1),256);
- this_request->errors = 0;
- if (--this_request->nsector)
- return;
- this_request->bh->b_uptodate = 1;
- this_request->bh->b_dirt = 0;
- wake_up(&wait_for_request);
- unlock_buffer(this_request->bh);
- this_request->hd = -1;
- this_request=this_request->next;
- do_request();
-}
-
-static void write_intr(void)
-{
- if (win_result()) {
- bad_rw_intr();
- return;
- }
- if (--this_request->nsector) {
- port_write(HD_DATA,this_request->bh->b_data+512,256);
- return;
- }
- this_request->bh->b_uptodate = 1;
- this_request->bh->b_dirt = 0;
- wake_up(&wait_for_request);
- unlock_buffer(this_request->bh);
- this_request->hd = -1;
- this_request=this_request->next;
- do_request();
-}
-
-static void do_request(void)
-{
- int i,r;
-
- if (sorting)
- return;
- if (!this_request) {
- do_hd=NULL;
- return;
- }
- if (this_request->cmd == WIN_WRITE) {
- hd_out(this_request->hd,this_request->nsector,this_request->
- sector,this_request->head,this_request->cyl,
- this_request->cmd,&write_intr);
- for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
- /* nothing */ ;
- if (!r) {
- reset_hd(this_request->hd);
- return;
- }
- port_write(HD_DATA,this_request->bh->b_data+
- 512*(this_request->nsector&1),256);
- } else if (this_request->cmd == WIN_READ) {
- hd_out(this_request->hd,this_request->nsector,this_request->
- sector,this_request->head,this_request->cyl,
- this_request->cmd,&read_intr);
- } else
- panic("unknown hd-command");
-}
-
-/*
- * add-request adds a request to the linked list.
- * It sets the 'sorting'-variable when doing something
- * that interrupts shouldn't touch.
- */
-static void add_request(struct hd_request * req)
-{
- struct hd_request * tmp;
-
- if (req->nsector != 2)
- panic("nsector!=2 not implemented");
-/*
- * Not to mess up the linked lists, we never touch the two first
- * entries (not this_request, as it is used by current interrups,
- * and not this_request->next, as it can be assigned to this_request).
- * This is not too high a price to pay for the ability of not
- * disabling interrupts.
- */
- sorting=1;
- if (!(tmp=this_request))
- this_request=req;
- else {
- if (!(tmp->next))
- tmp->next=req;
- else {
- tmp=tmp->next;
- 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;
- }
- }
- sorting=0;
-/*
- * NOTE! As a result of sorting, the interrupts may have died down,
- * as they aren't redone due to locking with sorting=1. They might
- * also never have started, if this is the first request in the queue,
- * so we restart them if necessary.
- */
- if (!do_hd)
- do_request();
-}
-
-void rw_abs_hd(int rw,unsigned int nr,unsigned int sec,unsigned int head,
- unsigned int cyl,struct buffer_head * bh)
-{
- struct hd_request * req;
-
- if (rw!=READ && rw!=WRITE)
- panic("Bad hd command, must be R/W");
- lock_buffer(bh);
-repeat:
- for (req=0+request ; req<NR_REQUEST+request ; req++)
- if (req->hd<0)
- break;
- if (req==NR_REQUEST+request) {
- sleep_on(&wait_for_request);
- goto repeat;
- }
- req->hd=nr;
- req->nsector=2;
- req->sector=sec;
- req->head=head;
- req->cyl=cyl;
- req->cmd = ((rw==READ)?WIN_READ:WIN_WRITE);
- req->bh=bh;
- req->errors=0;
- req->next=NULL;
- add_request(req);
- wait_on_buffer(bh);
-}
-
-void hd_init(void)
-{
- int i;
-
- for (i=0 ; i<NR_REQUEST ; i++) {
- request[i].hd = -1;
- request[i].next = NULL;
- }
- for (i=0 ; i<NR_HD ; i++) {
- hd[i*5].start_sect = 0;
- hd[i*5].nr_sects = hd_info[i].head*
- hd_info[i].sect*hd_info[i].cyl;
- }
- set_trap_gate(0x2E,&hd_interrupt);
- outb_p(inb_p(0x21)&0xfb,0x21);
- outb(inb_p(0xA1)&0xbf,0xA1);
-}
diff --git a/kernel/malloc.c b/kernel/malloc.c
new file mode 100644
index 0000000..42723a7
--- /dev/null
+++ b/kernel/malloc.c
@@ -0,0 +1,232 @@
+/*
+ * malloc.c --- a general purpose kernel memory allocator for Linux.
+ *
+ * Written by Theodore Ts'o (tytso@mit.edu), 11/29/91
+ *
+ * This routine is written to be as fast as possible, so that it
+ * can be called from the interrupt level.
+ *
+ * Limitations: maximum size of memory we can allocate using this routine
+ * is 4k, the size of a page in Linux.
+ *
+ * The general game plan is that each page (called a bucket) will only hold
+ * objects of a given size. When all of the object on a page are released,
+ * the page can be returned to the general free pool. When malloc() is
+ * called, it looks for the smallest bucket size which will fulfill its
+ * request, and allocate a piece of memory from that bucket pool.
+ *
+ * Each bucket has as its control block a bucket descriptor which keeps
+ * track of how many objects are in use on that page, and the free list
+ * for that page. Like the buckets themselves, bucket descriptors are
+ * stored on pages requested from get_free_page(). However, unlike buckets,
+ * pages devoted to bucket descriptor pages are never released back to the
+ * system. Fortunately, a system should probably only need 1 or 2 bucket
+ * descriptor pages, since a page can hold 256 bucket descriptors (which
+ * corresponds to 1 megabyte worth of bucket pages.) If the kernel is using
+ * that much allocated memory, it's probably doing something wrong. :-)
+ *
+ * Note: malloc() and free() both call get_free_page() and free_page()
+ * in sections of code where interrupts are turned off, to allow
+ * malloc() and free() to be safely called from an interrupt routine.
+ * (We will probably need this functionality when networking code,
+ * particularily things like NFS, is added to Linux.) However, this
+ * presumes that get_free_page() and free_page() are interrupt-level
+ * safe, which they may not be once paging is added. If this is the
+ * case, we will need to modify malloc() to keep a few unused pages
+ * "pre-allocated" so that it can safely draw upon those pages if
+ * it is called from an interrupt routine.
+ *
+ * Another concern is that get_free_page() should not sleep; if it
+ * does, the code is carefully ordered so as to avoid any race
+ * conditions. The catch is that if malloc() is called re-entrantly,
+ * there is a chance that unecessary pages will be grabbed from the
+ * system. Except for the pages for the bucket descriptor page, the
+ * extra pages will eventually get released back to the system, though,
+ * so it isn't all that bad.
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/system.h>
+
+struct bucket_desc { /* 16 bytes */
+ void *page;
+ struct bucket_desc *next;
+ void *freeptr;
+ unsigned short refcnt;
+ unsigned short bucket_size;
+};
+
+struct _bucket_dir { /* 8 bytes */
+ int size;
+ struct bucket_desc *chain;
+};
+
+/*
+ * The following is the where we store a pointer to the first bucket
+ * descriptor for a given size.
+ *
+ * If it turns out that the Linux kernel allocates a lot of objects of a
+ * specific size, then we may want to add that specific size to this list,
+ * since that will allow the memory to be allocated more efficiently.
+ * However, since an entire page must be dedicated to each specific size
+ * on this list, some amount of temperance must be exercised here.
+ *
+ * Note that this list *must* be kept in order.
+ */
+struct _bucket_dir bucket_dir[] = {
+ { 16, (struct bucket_desc *) 0},
+ { 32, (struct bucket_desc *) 0},
+ { 64, (struct bucket_desc *) 0},
+ { 128, (struct bucket_desc *) 0},
+ { 256, (struct bucket_desc *) 0},
+ { 512, (struct bucket_desc *) 0},
+ { 1024, (struct bucket_desc *) 0},
+ { 2048, (struct bucket_desc *) 0},
+ { 4096, (struct bucket_desc *) 0},
+ { 0, (struct bucket_desc *) 0}}; /* End of list marker */
+
+/*
+ * This contains a linked list of free bucket descriptor blocks
+ */
+struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0;
+
+/*
+ * This routine initializes a bucket description page.
+ */
+static inline void init_bucket_desc()
+{
+ struct bucket_desc *bdesc, *first;
+ int i;
+
+ first = bdesc = (struct bucket_desc *) get_free_page();
+ if (!bdesc)
+ panic("Out of memory in init_bucket_desc()");
+ for (i = PAGE_SIZE/sizeof(struct bucket_desc); i > 1; i--) {
+ bdesc->next = bdesc+1;
+ bdesc++;
+ }
+ /*
+ * This is done last, to avoid race conditions in case
+ * get_free_page() sleeps and this routine gets called again....
+ */
+ bdesc->next = free_bucket_desc;
+ free_bucket_desc = first;
+}
+
+void *malloc(unsigned int len)
+{
+ struct _bucket_dir *bdir;
+ struct bucket_desc *bdesc;
+ void *retval;
+
+ /*
+ * First we search the bucket_dir to find the right bucket change
+ * for this request.
+ */
+ for (bdir = bucket_dir; bdir->size; bdir++)
+ if (bdir->size >= len)
+ break;
+ if (!bdir->size) {
+ printk("malloc called with impossibly large argument (%d)\n",
+ len);
+ panic("malloc: bad arg");
+ }
+ /*
+ * Now we search for a bucket descriptor which has free space
+ */
+ cli(); /* Avoid race conditions */
+ for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next)
+ if (bdesc->freeptr)
+ break;
+ /*
+ * If we didn't find a bucket with free space, then we'll
+ * allocate a new one.
+ */
+ if (!bdesc) {
+ char *cp;
+ int i;
+
+ if (!free_bucket_desc)
+ init_bucket_desc();
+ bdesc = free_bucket_desc;
+ free_bucket_desc = bdesc->next;
+ bdesc->refcnt = 0;
+ bdesc->bucket_size = bdir->size;
+ bdesc->page = bdesc->freeptr = (void *) cp = get_free_page();
+ if (!cp)
+ panic("Out of memory in kernel malloc()");
+ /* Set up the chain of free objects */
+ for (i=PAGE_SIZE/bdir->size; i > 1; i--) {
+ *((char **) cp) = cp + bdir->size;
+ cp += bdir->size;
+ }
+ *((char **) cp) = 0;
+ bdesc->next = bdir->chain; /* OK, link it in! */
+ bdir->chain = bdesc;
+ }
+ retval = (void *) bdesc->freeptr;
+ bdesc->freeptr = *((void **) retval);
+ bdesc->refcnt++;
+ sti(); /* OK, we're safe again */
+ return(retval);
+}
+
+/*
+ * Here is the free routine. If you know the size of the object that you
+ * are freeing, then free_s() will use that information to speed up the
+ * search for the bucket descriptor.
+ *
+ * We will #define a macro so that "free(x)" is becomes "free_s(x, 0)"
+ */
+void free_s(void *obj, int size)
+{
+ void *page;
+ struct _bucket_dir *bdir;
+ struct bucket_desc *bdesc, *prev;
+
+ /* Calculate what page this object lives in */
+ page = (void *) ((unsigned long) obj & 0xfffff000);
+ /* Now search the buckets looking for that page */
+ for (bdir = bucket_dir; bdir->size; bdir++) {
+ prev = 0;
+ /* If size is zero then this conditional is always false */
+ if (bdir->size < size)
+ continue;
+ for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) {
+ if (bdesc->page == page)
+ goto found;
+ prev = bdesc;
+ }
+ }
+ panic("Bad address passed to kernel free_s()");
+found:
+ cli(); /* To avoid race conditions */
+ *((void **)obj) = bdesc->freeptr;
+ bdesc->freeptr = obj;
+ bdesc->refcnt--;
+ if (bdesc->refcnt == 0) {
+ /*
+ * We need to make sure that prev is still accurate. It
+ * may not be, if someone rudely interrupted us....
+ */
+ if ((prev && (prev->next != bdesc)) ||
+ (!prev && (bdir->chain != bdesc)))
+ for (prev = bdir->chain; prev; prev = prev->next)
+ if (prev->next == bdesc)
+ break;
+ if (prev)
+ prev->next = bdesc->next;
+ else {
+ if (bdir->chain != bdesc)
+ panic("malloc bucket chains corrupted");
+ bdir->chain = bdesc->next;
+ }
+ free_page((unsigned long) bdesc->page);
+ bdesc->next = free_bucket_desc;
+ free_bucket_desc = bdesc;
+ }
+ sti();
+ return;
+}
+
diff --git a/kernel/mktime.c b/kernel/mktime.c
index 3ba79be..a67db96 100644
--- a/kernel/mktime.c
+++ b/kernel/mktime.c
@@ -1,3 +1,9 @@
+/*
+ * linux/kernel/mktime.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <time.h>
/*
diff --git a/kernel/panic.c b/kernel/panic.c
index feab0cc..7d8a06b 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -1,11 +1,24 @@
/*
+ * linux/kernel/panic.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* This function is used through-out the kernel (includeinh mm and fs)
* to indicate a major problem.
*/
#include <linux/kernel.h>
+#include <linux/sched.h>
+
+void sys_sync(void); /* it's really int */
volatile void panic(const char * s)
{
printk("Kernel panic: %s\n\r",s);
+ if (current == task[0])
+ printk("In swapper task - not syncing\n\r");
+ else
+ sys_sync();
for(;;);
}
diff --git a/kernel/printk.c b/kernel/printk.c
index 7a70dc3..c464d43 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -1,4 +1,10 @@
/*
+ * linux/kernel/printk.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* When in kernel-mode, we cannot use printf, as fs is liable to
* point to 'interesting' things. Make a printf with fs-saving, and
* all is well.
@@ -10,6 +16,8 @@
static char buf[1024];
+extern int vsprintf(char * buf, const char * fmt, va_list args);
+
int printk(const char *fmt, ...)
{
va_list args;
diff --git a/kernel/sched.c b/kernel/sched.c
index 03399fa..6788312 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1,4 +1,10 @@
/*
+ * linux/kernel/sched.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* 'sched.c' is the main kernel file. It contains scheduling primitives
* (sleep_on, wakeup, schedule etc) as well as a number of simple system
* call functions (type getpid(), which just extracts a field from
@@ -6,12 +12,32 @@
*/
#include <linux/sched.h>
#include <linux/kernel.h>
-#include <signal.h>
#include <linux/sys.h>
+#include <linux/fdreg.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
+#include <signal.h>
+
+#define _S(nr) (1<<((nr)-1))
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+void show_task(int nr,struct task_struct * p)
+{
+ printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state);
+ printk("eip=%04x:%08x\n\r",p->tss.cs&0xffff,p->tss.eip);
+}
+
+void show_stat(void)
+{
+ int i;
+
+ for (i=0;i<NR_TASKS;i++)
+ if (task[i])
+ show_task(i,task[i]);
+}
+
#define LATCH (1193180/HZ)
extern void mem_use(void);
@@ -28,7 +54,8 @@ static union task_union init_task = {INIT_TASK,};
long volatile jiffies=0;
long startup_time=0;
-struct task_struct *current = &(init_task.task), *last_task_used_math = NULL;
+struct task_struct *current = &(init_task.task);
+struct task_struct *last_task_used_math = NULL;
struct task_struct * task[NR_TASKS] = {&(init_task.task), };
@@ -44,11 +71,14 @@ struct {
*/
void math_state_restore()
{
- if (last_task_used_math)
+ if (last_task_used_math == current)
+ return;
+ if (last_task_used_math) {
__asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
- if (current->used_math)
+ }
+ if (current->used_math) {
__asm__("frstor %0"::"m" (current->tss.i387));
- else {
+ } else {
__asm__("fninit"::);
current->used_math=1;
}
@@ -78,7 +108,8 @@ void schedule(void)
(*p)->signal |= (1<<(SIGALRM-1));
(*p)->alarm = 0;
}
- if ((*p)->signal && (*p)->state==TASK_INTERRUPTIBLE)
+ if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
+ (*p)->state==TASK_INTERRUPTIBLE)
(*p)->state=TASK_RUNNING;
}
@@ -156,12 +187,152 @@ void wake_up(struct task_struct **p)
}
}
+/*
+ * OK, here are some floppy things that shouldn't be in the kernel
+ * proper. They are here because the floppy needs a timer, and this
+ * was the easiest way of doing it.
+ */
+static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL};
+static int mon_timer[4]={0,0,0,0};
+static int moff_timer[4]={0,0,0,0};
+unsigned char current_DOR = 0x0C;
+unsigned char selected = 0;
+struct task_struct * wait_on_floppy_select = NULL;
+
+void floppy_select(unsigned int nr)
+{
+ if (nr>3)
+ printk("floppy_select: nr>3\n\r");
+ cli();
+ while (selected)
+ sleep_on(&wait_on_floppy_select);
+ current_DOR &= 0xFC;
+ current_DOR |= nr;
+ outb(current_DOR,FD_DOR);
+ sti();
+}
+
+void floppy_deselect(unsigned int nr)
+{
+ if (nr != (current_DOR & 3))
+ printk("floppy_deselect: drive not selected\n\r");
+ selected = 0;
+ wake_up(&wait_on_floppy_select);
+}
+
+int ticks_to_floppy_on(unsigned int nr)
+{
+ unsigned char mask = 1<<(nr+4);
+
+ if (nr>3)
+ panic("floppy_on: nr>3");
+ moff_timer[nr]=10000; /* 100 s = very big :-) */
+ cli(); /* use floppy_off to turn it off */
+ if (!(mask & current_DOR)) {
+ current_DOR |= mask;
+ if (!selected) {
+ current_DOR &= 0xFC;
+ current_DOR |= nr;
+ }
+ outb(current_DOR,FD_DOR);
+ mon_timer[nr] = HZ;
+ }
+ sti();
+ return mon_timer[nr];
+}
+
+void floppy_on(unsigned int nr)
+{
+ cli();
+ while (ticks_to_floppy_on(nr))
+ sleep_on(nr+wait_motor);
+ sti();
+}
+
+void floppy_off(unsigned int nr)
+{
+ moff_timer[nr]=3*HZ;
+}
+
+void do_floppy_timer(void)
+{
+ int i;
+ unsigned char mask = 0x10;
+
+ for (i=0 ; i<4 ; i++,mask <<= 1) {
+ if (!(mask & current_DOR))
+ continue;
+ if (mon_timer[i]) {
+ if (!--mon_timer[i])
+ wake_up(i+wait_motor);
+ } else if (!moff_timer[i]) {
+ current_DOR &= ~mask;
+ outb(current_DOR,FD_DOR);
+ } else
+ moff_timer[i]--;
+ }
+}
+
+#define TIME_REQUESTS 64
+
+static struct timer_list {
+ long jiffies;
+ void (*fn)();
+ struct timer_list * next;
+} timer_list[TIME_REQUESTS], * next_timer = NULL;
+
+void add_timer(long jiffies, void (*fn)(void))
+{
+ struct timer_list * p;
+
+ if (!fn)
+ return;
+ cli();
+ if (jiffies <= 0)
+ (fn)();
+ else {
+ for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++)
+ if (!p->fn)
+ break;
+ if (p >= timer_list + TIME_REQUESTS)
+ panic("No more time requests free");
+ p->fn = fn;
+ p->jiffies = jiffies;
+ p->next = next_timer;
+ next_timer = p;
+ while (p->next && p->next->jiffies < p->jiffies) {
+ p->jiffies -= p->next->jiffies;
+ fn = p->fn;
+ p->fn = p->next->fn;
+ p->next->fn = fn;
+ jiffies = p->jiffies;
+ p->jiffies = p->next->jiffies;
+ p->next->jiffies = jiffies;
+ p = p->next;
+ }
+ }
+ sti();
+}
+
void do_timer(long cpl)
{
if (cpl)
current->utime++;
else
current->stime++;
+ if (next_timer) {
+ next_timer->jiffies--;
+ while (next_timer && next_timer->jiffies <= 0) {
+ void (*fn)(void);
+
+ fn = next_timer->fn;
+ next_timer->fn = NULL;
+ next_timer = next_timer->next;
+ (fn)();
+ }
+ }
+ if (current_DOR & 0xf0)
+ do_floppy_timer();
if ((--current->counter)>0) return;
current->counter=0;
if (!cpl) return;
@@ -170,8 +341,12 @@ void do_timer(long cpl)
int sys_alarm(long seconds)
{
+ int old = current->alarm;
+
+ if (old)
+ old = (old - jiffies) / HZ;
current->alarm = (seconds>0)?(jiffies+HZ*seconds):0;
- return seconds;
+ return (old);
}
int sys_getpid(void)
@@ -211,28 +386,13 @@ int sys_nice(long increment)
return 0;
}
-int sys_signal(long signal,long addr,long restorer)
-{
- long i;
-
- switch (signal) {
- case SIGHUP: case SIGINT: case SIGQUIT: case SIGILL:
- case SIGTRAP: case SIGABRT: case SIGFPE: case SIGUSR1:
- case SIGSEGV: case SIGUSR2: case SIGPIPE: case SIGALRM:
- case SIGCHLD:
- i=(long) current->sig_fn[signal-1];
- current->sig_fn[signal-1] = (fn_ptr) addr;
- current->sig_restorer = (fn_ptr) restorer;
- return i;
- default: return -1;
- }
-}
-
void sched_init(void)
{
int i;
struct desc_struct * p;
+ if (sizeof(struct sigaction) != 16)
+ panic("Struct sigaction MUST be 16 bytes");
set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
p = gdt+2+FIRST_TSS_ENTRY;
diff --git a/kernel/signal.c b/kernel/signal.c
new file mode 100644
index 0000000..79fb6ca
--- /dev/null
+++ b/kernel/signal.c
@@ -0,0 +1,119 @@
+/*
+ * linux/kernel/signal.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+
+#include <signal.h>
+
+volatile void do_exit(int error_code);
+
+int sys_sgetmask()
+{
+ return current->blocked;
+}
+
+int sys_ssetmask(int newmask)
+{
+ int old=current->blocked;
+
+ current->blocked = newmask & ~(1<<(SIGKILL-1));
+ return old;
+}
+
+static inline void save_old(char * from,char * to)
+{
+ int i;
+
+ verify_area(to, sizeof(struct sigaction));
+ for (i=0 ; i< sizeof(struct sigaction) ; i++) {
+ put_fs_byte(*from,to);
+ from++;
+ to++;
+ }
+}
+
+static inline void get_new(char * from,char * to)
+{
+ int i;
+
+ for (i=0 ; i< sizeof(struct sigaction) ; i++)
+ *(to++) = get_fs_byte(from++);
+}
+
+int sys_signal(int signum, long handler, long restorer)
+{
+ struct sigaction tmp;
+
+ if (signum<1 || signum>32 || signum==SIGKILL)
+ return -1;
+ tmp.sa_handler = (void (*)(int)) handler;
+ tmp.sa_mask = 0;
+ tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
+ tmp.sa_restorer = (void (*)(void)) restorer;
+ handler = (long) current->sigaction[signum-1].sa_handler;
+ current->sigaction[signum-1] = tmp;
+ return handler;
+}
+
+int sys_sigaction(int signum, const struct sigaction * action,
+ struct sigaction * oldaction)
+{
+ struct sigaction tmp;
+
+ if (signum<1 || signum>32 || signum==SIGKILL)
+ return -1;
+ tmp = current->sigaction[signum-1];
+ get_new((char *) action,
+ (char *) (signum-1+current->sigaction));
+ if (oldaction)
+ save_old((char *) &tmp,(char *) oldaction);
+ if (current->sigaction[signum-1].sa_flags & SA_NOMASK)
+ current->sigaction[signum-1].sa_mask = 0;
+ else
+ current->sigaction[signum-1].sa_mask |= (1<<(signum-1));
+ return 0;
+}
+
+void do_signal(long signr,long eax, long ebx, long ecx, long edx,
+ long fs, long es, long ds,
+ long eip, long cs, long eflags,
+ unsigned long * esp, long ss)
+{
+ 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;
+ if (sa_handler==1)
+ return;
+ if (!sa_handler) {
+ if (signr==SIGCHLD)
+ return;
+ else
+ do_exit(1<<(signr-1));
+ }
+ if (sa->sa_flags & SA_ONESHOT)
+ sa->sa_handler = NULL;
+ *(&eip) = sa_handler;
+ longs = (sa->sa_flags & SA_NOMASK)?7:8;
+ *(&esp) -= longs;
+ verify_area(esp,longs*4);
+ tmp_esp=esp;
+ put_fs_long((long) sa->sa_restorer,tmp_esp++);
+ put_fs_long(signr,tmp_esp++);
+ if (!(sa->sa_flags & SA_NOMASK))
+ put_fs_long(current->blocked,tmp_esp++);
+ put_fs_long(eax,tmp_esp++);
+ put_fs_long(ecx,tmp_esp++);
+ put_fs_long(edx,tmp_esp++);
+ put_fs_long(eflags,tmp_esp++);
+ put_fs_long(old_eip,tmp_esp++);
+ current->blocked |= sa->sa_mask;
+}
diff --git a/kernel/sys.c b/kernel/sys.c
index f18ee7e..2c01e67 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1,3 +1,9 @@
+/*
+ * linux/kernel/sys.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <errno.h>
#include <linux/sched.h>
@@ -12,31 +18,11 @@ int sys_ftime()
return -ENOSYS;
}
-int sys_mknod()
-{
- return -ENOSYS;
-}
-
int sys_break()
{
return -ENOSYS;
}
-int sys_mount()
-{
- return -ENOSYS;
-}
-
-int sys_umount()
-{
- return -ENOSYS;
-}
-
-int sys_ustat(int dev,struct ustat * ubuf)
-{
- return -1;
-}
-
int sys_ptrace()
{
return -ENOSYS;
@@ -62,18 +48,32 @@ int sys_prof()
return -ENOSYS;
}
-int sys_setgid(int gid)
+int sys_setregid(int rgid, int egid)
{
- if (current->euid && current->uid)
- if (current->gid==gid || current->sgid==gid)
- current->egid=gid;
+ if (rgid>0) {
+ if ((current->gid == rgid) ||
+ suser())
+ current->gid = rgid;
+ else
+ return(-EPERM);
+ }
+ if (egid>0) {
+ if ((current->gid == egid) ||
+ (current->egid == egid) ||
+ (current->sgid == egid) ||
+ suser())
+ current->egid = egid;
else
- return -EPERM;
- else
- current->gid=current->egid=gid;
+ return(-EPERM);
+ }
return 0;
}
+int sys_setgid(int gid)
+{
+ return(sys_setregid(gid, gid));
+}
+
int sys_acct()
{
return -ENOSYS;
@@ -111,35 +111,57 @@ int sys_time(long * tloc)
return i;
}
-int sys_setuid(int uid)
-{
- if (current->euid && current->uid)
- if (uid==current->uid || current->suid==current->uid)
- current->euid=uid;
+/*
+ * Unprivileged users may change the real user id to the effective uid
+ * or vice versa.
+ */
+int sys_setreuid(int ruid, int euid)
+{
+ int old_ruid = current->uid;
+
+ if (ruid>0) {
+ if ((current->euid==ruid) ||
+ (old_ruid == ruid) ||
+ suser())
+ current->uid = ruid;
else
- return -EPERM;
- else
- current->euid=current->uid=uid;
+ return(-EPERM);
+ }
+ if (euid>0) {
+ if ((old_ruid == euid) ||
+ (current->euid == euid) ||
+ suser())
+ current->euid = euid;
+ else {
+ current->uid = old_ruid;
+ return(-EPERM);
+ }
+ }
return 0;
}
+int sys_setuid(int uid)
+{
+ return(sys_setreuid(uid, uid));
+}
+
int sys_stime(long * tptr)
{
- if (current->euid && current->uid)
- return -1;
+ if (!suser())
+ return -EPERM;
startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ;
return 0;
}
int sys_times(struct tms * tbuf)
{
- if (!tbuf)
- return jiffies;
- verify_area(tbuf,sizeof *tbuf);
- put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime);
- put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime);
- put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime);
- put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime);
+ if (tbuf) {
+ verify_area(tbuf,sizeof *tbuf);
+ put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime);
+ put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime);
+ put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime);
+ put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime);
+ }
return jiffies;
}
@@ -163,7 +185,7 @@ int sys_setpgid(int pid, int pgid)
if (!pid)
pid = current->pid;
if (!pgid)
- pgid = pid;
+ pgid = current->pid;
for (i=0 ; i<NR_TASKS ; i++)
if (task[i] && task[i]->pid==pid) {
if (task[i]->leader)
@@ -183,9 +205,7 @@ int sys_getpgrp(void)
int sys_setsid(void)
{
- if (current->uid && current->euid)
- return -EPERM;
- if (current->leader)
+ if (current->leader && !suser())
return -EPERM;
current->leader = 1;
current->session = current->pgrp = current->pid;
@@ -200,11 +220,11 @@ int sys_uname(struct utsname * name)
};
int i;
- if (!name) return -1;
+ if (!name) return -ERROR;
verify_area(name,sizeof *name);
for(i=0;i<sizeof *name;i++)
put_fs_byte(((char *) &thisname)[i],i+(char *) name);
- return (0);
+ return 0;
}
int sys_umask(int mask)
diff --git a/kernel/system_call.s b/kernel/system_call.s
index df4f072..5f7cafc 100644
--- a/kernel/system_call.s
+++ b/kernel/system_call.s
@@ -1,7 +1,13 @@
/*
+ * linux/kernel/system_call.s
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* system_call.s contains the system-call low-level handling routines.
* This also contains the timer-interrupt handler, as some of the code is
- * the same. The hd-interrupt is also here.
+ * the same. The hd- and flopppy-interrupts are also here.
*
* NOTE: This code handles signal-recognition, which happens every time
* after a timer-interrupt and after each system call. Ordinary interrupts
@@ -25,6 +31,7 @@
*/
SIG_CHLD = 17
+
EAX = 0x00
EBX = 0x04
ECX = 0x08
@@ -42,12 +49,23 @@ state = 0 # these are offsets into the task-struct.
counter = 4
priority = 8
signal = 12
-restorer = 16 # address of info-restorer
-sig_fn = 20 # table of 32 signal addresses
+sigaction = 16 # MUST be 16 (=len of sigaction)
+blocked = (33*16)
+
+# offsets within sigaction
+sa_handler = 0
+sa_mask = 4
+sa_flags = 8
+sa_restorer = 12
-nr_system_calls = 67
+nr_system_calls = 70
-.globl _system_call,_sys_fork,_timer_interrupt,_hd_interrupt,_sys_execve
+/*
+ * Ok, I get parallel printer interrupts while using the floppy for some
+ * strange reason. Urgel. Now I just ignore them.
+ */
+.globl _system_call,_sys_fork,_timer_interrupt,_sys_execve
+.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt
.align 2
bad_sys_call:
@@ -83,46 +101,22 @@ ret_from_sys_call:
movl _current,%eax # task[0] cannot have signals
cmpl _task,%eax
je 3f
- movl CS(%esp),%ebx # was old code segment supervisor
- testl $3,%ebx # mode? If so - don't check signals
- je 3f
+ cmpw $0x0f,CS(%esp) # was old code segment supervisor ?
+ jne 3f
cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
jne 3f
-2: movl signal(%eax),%ebx # signals (bitmap, 32 signals)
- bsfl %ebx,%ecx # %ecx is signal nr, return if none
+ movl signal(%eax),%ebx
+ movl blocked(%eax),%ecx
+ notl %ecx
+ andl %ebx,%ecx
+ bsfl %ecx,%ecx
je 3f
- btrl %ecx,%ebx # clear it
+ btrl %ecx,%ebx
movl %ebx,signal(%eax)
- movl sig_fn(%eax,%ecx,4),%ebx # %ebx is signal handler address
- cmpl $1,%ebx
- jb default_signal # 0 is default signal handler - exit
- je 2b # 1 is ignore - find next signal
- movl $0,sig_fn(%eax,%ecx,4) # reset signal handler address
incl %ecx
- xchgl %ebx,EIP(%esp) # put new return address on stack
- subl $28,OLDESP(%esp)
- movl OLDESP(%esp),%edx # push old return address on stack
- pushl %eax # but first check that it's ok.
pushl %ecx
- pushl $28
- pushl %edx
- call _verify_area
- popl %edx
- addl $4,%esp
- popl %ecx
+ call _do_signal
popl %eax
- movl restorer(%eax),%eax
- movl %eax,%fs:(%edx) # flag/reg restorer
- movl %ecx,%fs:4(%edx) # signal nr
- movl EAX(%esp),%eax
- movl %eax,%fs:8(%edx) # old eax
- movl ECX(%esp),%eax
- movl %eax,%fs:12(%edx) # old ecx
- movl EDX(%esp),%eax
- movl %eax,%fs:16(%edx) # old edx
- movl EFLAGS(%esp),%eax
- movl %eax,%fs:20(%edx) # old eflags
- movl %ebx,%fs:24(%edx) # old return addr
3: popl %eax
popl %ebx
popl %ecx
@@ -132,15 +126,6 @@ ret_from_sys_call:
pop %ds
iret
-default_signal:
- incl %ecx
- cmpl $SIG_CHLD,%ecx
- je 2b
- pushl %ecx
- call _do_exit # remember to set bit 7 when dumping core
- addl $4,%esp
- jmp 3b
-
.align 2
_timer_interrupt:
push %ds # save ds,es and put kernel data space
@@ -197,7 +182,6 @@ _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
@@ -217,3 +201,35 @@ _hd_interrupt:
popl %eax
iret
+_floppy_interrupt:
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ push %ds
+ push %es
+ push %fs
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ mov %ax,%fs
+ movb $0x20,%al
+ outb %al,$0x20 # EOI to interrupt controller #1
+ movl _do_floppy,%eax
+ testl %eax,%eax
+ jne 1f
+ movl $_unexpected_floppy_interrupt,%eax
+1: call *%eax # "interesting" way of handling intr.
+ pop %fs
+ pop %es
+ pop %ds
+ popl %edx
+ popl %ecx
+ popl %eax
+ iret
+
+_parallel_interrupt:
+ pushl %eax
+ movb $0x20,%al
+ outb %al,$0x20
+ popl %eax
+ iret
diff --git a/kernel/traps.c b/kernel/traps.c
index b6e8bdb..f9bd8f1 100644
--- a/kernel/traps.c
+++ b/kernel/traps.c
@@ -1,4 +1,10 @@
/*
+ * linux/kernel/traps.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* 'Traps.c' handles hardware traps and faults after we have saved some
* state in 'asm.s'. Currently mostly a debugging-aid, will be extended
* to mainly kill the offending process (probably by giving it a signal,
@@ -11,6 +17,7 @@
#include <linux/kernel.h>
#include <asm/system.h>
#include <asm/segment.h>
+#include <asm/io.h>
#define get_seg_byte(seg,addr) ({ \
register char __res; \
@@ -50,6 +57,8 @@ void general_protection(void);
void page_fault(void);
void coprocessor_error(void);
void reserved(void);
+void parallel_interrupt(void);
+void irq13(void);
static void die(char * str,long esp_ptr,long nr)
{
@@ -159,12 +168,14 @@ void do_stack_segment(long esp,long error_code)
void do_coprocessor_error(long esp, long error_code)
{
+ if (last_task_used_math != current)
+ return;
die("coprocessor error",esp,error_code);
}
void do_reserved(long esp, long error_code)
{
- die("reserved (15,17-31) error",esp,error_code);
+ die("reserved (15,17-47) error",esp,error_code);
}
void trap_init(void)
@@ -188,12 +199,10 @@ void trap_init(void)
set_trap_gate(14,&page_fault);
set_trap_gate(15,&reserved);
set_trap_gate(16,&coprocessor_error);
- for (i=17;i<32;i++)
+ for (i=17;i<48;i++)
set_trap_gate(i,&reserved);
-/* __asm__("movl $0x3ff000,%%eax\n\t"
- "movl %%eax,%%db0\n\t"
- "movl $0x000d0303,%%eax\n\t"
- "movl %%eax,%%db7"
- :::"ax");*/
+ set_trap_gate(45,&irq13);
+ outb_p(inb_p(0x21)&0xfb,0x21);
+ outb(inb_p(0xA1)&0xdf,0xA1);
+ set_trap_gate(39,&parallel_interrupt);
}
-
diff --git a/kernel/vsprintf.c b/kernel/vsprintf.c
index 69c0578..06b910e 100644
--- a/kernel/vsprintf.c
+++ b/kernel/vsprintf.c
@@ -1,3 +1,9 @@
+/*
+ * linux/kernel/vsprintf.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
/*
* Wirzenius wrote this portably, Torvalds fucked it up :-)
diff --git a/lib/Makefile b/lib/Makefile
index a06698d..bc1ecf3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -42,3 +42,30 @@ dep:
cp tmp_make Makefile
### Dependencies:
+_exit.s _exit.o : _exit.c ../include/unistd.h ../include/sys/stat.h \
+ ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
+ ../include/utime.h
+close.s close.o : close.c ../include/unistd.h ../include/sys/stat.h \
+ ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
+ ../include/utime.h
+ctype.s ctype.o : ctype.c ../include/ctype.h
+dup.s dup.o : dup.c ../include/unistd.h ../include/sys/stat.h \
+ ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
+ ../include/utime.h
+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
+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
+setsid.s setsid.o : setsid.c ../include/unistd.h ../include/sys/stat.h \
+ ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
+ ../include/utime.h
+string.s string.o : string.c ../include/string.h
+wait.s wait.o : wait.c ../include/unistd.h ../include/sys/stat.h \
+ ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
+ ../include/utime.h ../include/sys/wait.h
+write.s write.o : write.c ../include/unistd.h ../include/sys/stat.h \
+ ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
+ ../include/utime.h
diff --git a/lib/_exit.c b/lib/_exit.c
index 44a74e1..c0c9d69 100644
--- a/lib/_exit.c
+++ b/lib/_exit.c
@@ -1,3 +1,9 @@
+/*
+ * linux/lib/_exit.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#define __LIBRARY__
#include <unistd.h>
diff --git a/lib/close.c b/lib/close.c
index 182d7eb..afd8364 100644
--- a/lib/close.c
+++ b/lib/close.c
@@ -1,3 +1,9 @@
+/*
+ * linux/lib/close.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#define __LIBRARY__
#include <unistd.h>
diff --git a/lib/ctype.c b/lib/ctype.c
index bf58aac..877e629 100644
--- a/lib/ctype.c
+++ b/lib/ctype.c
@@ -1,3 +1,9 @@
+/*
+ * linux/lib/ctype.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <ctype.h>
char _ctmp;
diff --git a/lib/dup.c b/lib/dup.c
index 03bd5d0..dd13414 100644
--- a/lib/dup.c
+++ b/lib/dup.c
@@ -1,3 +1,9 @@
+/*
+ * linux/lib/dup.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#define __LIBRARY__
#include <unistd.h>
diff --git a/lib/errno.c b/lib/errno.c
index 6e7bb62..50aca2e 100644
--- a/lib/errno.c
+++ b/lib/errno.c
@@ -1 +1,7 @@
+/*
+ * linux/lib/errno.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
int errno;
diff --git a/lib/execve.c b/lib/execve.c
index 03772e3..a89726d 100644
--- a/lib/execve.c
+++ b/lib/execve.c
@@ -1,3 +1,9 @@
+/*
+ * linux/lib/execve.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#define __LIBRARY__
#include <unistd.h>
diff --git a/lib/open.c b/lib/open.c
index 057039c..8c3fc58 100644
--- a/lib/open.c
+++ b/lib/open.c
@@ -1,3 +1,9 @@
+/*
+ * linux/lib/open.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#define __LIBRARY__
#include <unistd.h>
#include <stdarg.h>
diff --git a/lib/setsid.c b/lib/setsid.c
index 730abf0..68516c7 100644
--- a/lib/setsid.c
+++ b/lib/setsid.c
@@ -1,3 +1,9 @@
+/*
+ * linux/lib/setsid.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#define __LIBRARY__
#include <unistd.h>
diff --git a/lib/string.c b/lib/string.c
index f6befd9..1182e63 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -1,3 +1,9 @@
+/*
+ * linux/lib/string.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#ifndef __GNUC__
#error I want gcc!
#endif
diff --git a/lib/wait.c b/lib/wait.c
index a14555c..2815c16 100644
--- a/lib/wait.c
+++ b/lib/wait.c
@@ -1,3 +1,9 @@
+/*
+ * linux/lib/wait.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#define __LIBRARY__
#include <unistd.h>
#include <sys/wait.h>
diff --git a/lib/write.c b/lib/write.c
index 2613f17..df52e74 100644
--- a/lib/write.c
+++ b/lib/write.c
@@ -1,3 +1,9 @@
+/*
+ * linux/lib/write.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#define __LIBRARY__
#include <unistd.h>
diff --git a/mm/Makefile b/mm/Makefile
index cee1f09..3f20add 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -33,5 +33,4 @@ dep:
### Dependencies:
memory.o : memory.c ../include/signal.h ../include/sys/types.h \
- ../include/linux/config.h ../include/linux/head.h ../include/linux/kernel.h \
- ../include/asm/system.h
+ ../include/linux/head.h ../include/linux/kernel.h ../include/asm/system.h
diff --git a/mm/memory.c b/mm/memory.c
index 7cdcfb6..66bfa6c 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1,6 +1,11 @@
+/*
+ * linux/mm/memory.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
#include <signal.h>
-#include <linux/config.h>
#include <linux/head.h>
#include <linux/kernel.h>
#include <asm/system.h>
@@ -10,25 +15,19 @@ int do_exit(long code);
#define invalidate() \
__asm__("movl %%eax,%%cr3"::"a" (0))
-#if (BUFFER_END < 0x100000)
+/* these are not to be changed without changing head.s etc */
#define LOW_MEM 0x100000
-#else
-#define LOW_MEM BUFFER_END
-#endif
-
-/* these are not to be changed - thay are calculated from the above */
-#define PAGING_MEMORY (HIGH_MEMORY - LOW_MEM)
-#define PAGING_PAGES (PAGING_MEMORY/4096)
+#define PAGING_MEMORY (15*1024*1024)
+#define PAGING_PAGES (PAGING_MEMORY>>12)
#define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
+#define USED 100
-#if (PAGING_PAGES < 10)
-#error "Won't work"
-#endif
+static long HIGH_MEMORY = 0;
#define copy_page(from,to) \
__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
-static unsigned short mem_map [ PAGING_PAGES ] = {0,};
+static unsigned char mem_map [ PAGING_PAGES ] = {0,};
/*
* Get physical address of first (actually last :-) free page, and mark it
@@ -38,12 +37,12 @@ unsigned long get_free_page(void)
{
register unsigned long __res asm("ax");
-__asm__("std ; repne ; scasw\n\t"
+__asm__("std ; repne ; scasb\n\t"
"jne 1f\n\t"
- "movw $1,2(%%edi)\n\t"
+ "movb $1,1(%%edi)\n\t"
"sall $12,%%ecx\n\t"
+ "addl %2,%%ecx\n\t"
"movl %%ecx,%%edx\n\t"
- "addl %2,%%edx\n\t"
"movl $1024,%%ecx\n\t"
"leal 4092(%%edx),%%edi\n\t"
"rep ; stosl\n\t"
@@ -62,8 +61,8 @@ return __res;
*/
void free_page(unsigned long addr)
{
- if (addr<LOW_MEM) return;
- if (addr>HIGH_MEMORY)
+ if (addr < LOW_MEM) return;
+ if (addr > HIGH_MEMORY)
panic("trying to free nonexistent page");
addr -= LOW_MEM;
addr >>= 12;
@@ -244,6 +243,20 @@ void do_no_page(unsigned long error_code,unsigned long address)
do_exit(SIGSEGV);
}
+void mem_init(long start_mem, long end_mem)
+{
+ int i;
+
+ HIGH_MEMORY = end_mem;
+ for (i=0 ; i<PAGING_PAGES ; i++)
+ mem_map[i] = USED;
+ i = MAP_NR(start_mem);
+ end_mem -= start_mem;
+ end_mem >>= 12;
+ while (end_mem-->0)
+ mem_map[i++]=0;
+}
+
void calc_mem(void)
{
int i,j,k,free=0;
diff --git a/mm/page.s b/mm/page.s
index 27488c2..bd1c586 100644
--- a/mm/page.s
+++ b/mm/page.s
@@ -1,4 +1,10 @@
/*
+ * linux/mm/page.s
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
* page.s contains the low-level page-exception code.
* the real work is done in mm.c
*/
diff --git a/tools/build.c b/tools/build.c
index 6afe58c..2118b27 100644
--- a/tools/build.c
+++ b/tools/build.c
@@ -1,12 +1,42 @@
+/*
+ * linux/tools/build.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * This file builds a disk-image from three different files:
+ *
+ * - bootsect: max 510 bytes of 8086 machine code, loads the rest
+ * - setup: max 4 sectors of 8086 machine code, sets up system parm
+ * - system: 80386 code for actual system
+ *
+ * It does some checking that all files are of the correct type, and
+ * just writes the result to stdout, removing headers and padding to
+ * the right amount. It also writes some system data to stderr.
+ */
+
#include <stdio.h> /* fprintf */
+#include <string.h>
#include <stdlib.h> /* contains exit */
#include <sys/types.h> /* unistd.h needs this */
+#include <sys/stat.h>
+#include <linux/fs.h>
#include <unistd.h> /* contains read/write */
#include <fcntl.h>
#define MINIX_HEADER 32
#define GCC_HEADER 1024
+#define DEFAULT_MAJOR_ROOT 3
+#define DEFAULT_MINOR_ROOT 6
+
+/* max nr of sectors of setup: don't change unless you also change
+ * bootsect etc */
+#define SETUP_SECTS 4
+
+#define STRINGIFY(x) #x
+
void die(char * str)
{
fprintf(stderr,"%s\n",str);
@@ -15,16 +45,41 @@ void die(char * str)
void usage(void)
{
- die("Usage: build boot system [> image]");
+ die("Usage: build bootsect setup system [> image]");
}
int main(int argc, char ** argv)
{
int i,c,id;
char buf[1024];
+ char major_root, minor_root;
+ struct stat sb;
- if (argc != 3)
+ if ((argc != 4) && (argc != 5))
usage();
+ if (argc == 5) {
+ if (strcmp(argv[4], "FLOPPY")) {
+ if (stat(argv[4], &sb)) {
+ perror(argv[4]);
+ die("Couldn't stat root device.");
+ }
+ major_root = MAJOR(sb.st_rdev);
+ minor_root = MINOR(sb.st_rdev);
+ } else {
+ major_root = 0;
+ minor_root = 0;
+ }
+ } else {
+ major_root = DEFAULT_MAJOR_ROOT;
+ minor_root = DEFAULT_MINOR_ROOT;
+ }
+ fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
+ if ((major_root != 2) && (major_root != 3) &&
+ (major_root != 0)) {
+ fprintf(stderr, "Illegal root device (major = %d)\n",
+ major_root);
+ die("Bad root device --- major #");
+ }
for (i=0;i<sizeof buf; i++) buf[i]=0;
if ((id=open(argv[1],O_RDONLY,0))<0)
die("Unable to open 'boot'");
@@ -44,16 +99,53 @@ int main(int argc, char ** argv)
die("Illegal symbol table in 'boot'");
i=read(id,buf,sizeof buf);
fprintf(stderr,"Boot sector %d bytes.\n",i);
- if (i>510)
- die("Boot block may not exceed 510 bytes");
- buf[510]=0x55;
- buf[511]=0xAA;
+ if (i != 512)
+ die("Boot block must be exactly 512 bytes");
+ if ((*(unsigned short *)(buf+510)) != 0xAA55)
+ die("Boot block hasn't got boot flag (0xAA55)");
+ buf[508] = (char) minor_root;
+ buf[509] = (char) major_root;
i=write(1,buf,512);
if (i!=512)
die("Write call failed");
close (id);
if ((id=open(argv[2],O_RDONLY,0))<0)
+ die("Unable to open 'setup'");
+ if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
+ die("Unable to read header of 'setup'");
+ if (((long *) buf)[0]!=0x04100301)
+ die("Non-Minix header of 'setup'");
+ if (((long *) buf)[1]!=MINIX_HEADER)
+ die("Non-Minix header of 'setup'");
+ if (((long *) buf)[3]!=0)
+ die("Illegal data segment in 'setup'");
+ if (((long *) buf)[4]!=0)
+ die("Illegal bss in 'setup'");
+ if (((long *) buf)[5] != 0)
+ die("Non-Minix header of 'setup'");
+ if (((long *) buf)[7] != 0)
+ die("Illegal symbol table in 'setup'");
+ for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
+ if (write(1,buf,c)!=c)
+ die("Write call failed");
+ close (id);
+ if (i > SETUP_SECTS*512)
+ die("Setup exceeds " STRINGIFY(SETUP_SECTS)
+ " sectors - rewrite build/boot/setup");
+ fprintf(stderr,"Setup is %d bytes.\n",i);
+ for (c=0 ; c<sizeof(buf) ; c++)
+ buf[c] = '\0';
+ while (i<SETUP_SECTS*512) {
+ c = SETUP_SECTS*512-i;
+ if (c > sizeof(buf))
+ c = sizeof(buf);
+ if (write(1,buf,c) != c)
+ die("Write call failed");
+ i += c;
+ }
+
+ if ((id=open(argv[3],O_RDONLY,0))<0)
die("Unable to open 'system'");
if (read(id,buf,GCC_HEADER) != GCC_HEADER)
die("Unable to read header of 'system'");
@@ -63,6 +155,6 @@ int main(int argc, char ** argv)
if (write(1,buf,c)!=c)
die("Write call failed");
close(id);
- fprintf(stderr,"System %d bytes.\n",i);
+ fprintf(stderr,"System is %d bytes.\n",i);
return(0);
}