Commit 2ab763b2 authored by Linus Torvalds's avatar Linus Torvalds

Linux-0.12 (January 15, 1992)

This was created from a re-packaged 0.12 tree

Major milestone! Over the christmas break, I implemented paging to disk,
meaning that you could actually use gcc on a 2MB system.  Some poor sod
(Robert Blum) wanted to use Linux on such a system, and couldn't get the
kernel to compile with anything less "bloated" than gcc.

[ Irony alert: this was back when gcc worked fine on a system with just
  4MB.  Gone are those days. _Loong_ gone. ]

The task size was still limited to 63 tasks of at most 64MB each, but
other than that we were actually getting usable.

Together with other improvements and fixes, 0.12 was actually a very
nice kernel.  It was by now clearly more usable than Minix, which caused
us to think that a 1.0 release was imminent.  The next kernel version
was to be named 0.95, which turned out to be less than a stellar idea.

This was also the point where we changed the copyright license.  See the
attached original release notes.

Other changes:

 - Ted Ts'o continued on his rampage, and implemented BSD process
   control (ie ^Z) etc.  This also introduced the process tree code,
   with pointers between parents and children, rather than iterating
   over the whole list of processes.

 - Ted also did SVR4-style "saved uid/gid" handling.

 - use the C preprocessor for assembly files, cleaning up a lot of
   duplicate definitions etc.

 - better boot loader diagnostics

 - boot sequence now can change the size of the text display.  Who the
   hell is d88-man?

 - fix nasty race condition between "truncate" and file IO.

 - add support for shared libraries with the "uselib()" system call.
   This (together with the fact that we could share clean executable
   pages) cut down on memory usage a lot.

 - supplemental group support.  Hey, what can I say? Unix users expected
   them.

 - symbolic link handling.  This was the first real extension to the
   standard Minix disk layout, and was made possible by the fact that I
   had written my own "mkfs" and "fsck".  Before that, we were still on
   crutches, in that a Linux system depended on a Minix installation for
   these fundamental system tools.

 - mkdir()/rmdir() isn't just for root, you know..  (Yes, seriously.
   Old-style UNIX used to limit them to root-only, since they were just
   special sequences of mknod's)

 - Virtual terminals by Peter MacDonald (who was to do the SLS
   distribution).

   Before having X, this was a _big_ deal.  The fact that Linux had
   virtual terminals with a good vt100 emulation actually made Linux
   stand out even among some of the big commercial unixes.  The Linux
   console was just _so_ much more pleasant to use that it isn't even
   funny.

 - first implementation of "select()", virtual terminals, and pty's.

   These too were originally done by Peter MacDonald, based on some
   patches that had been floating around for Minix for a long time (but
   were never accepted into Minix).

   They didn't get accepted into Linux either, but the patches _did_ end
   up inspiring me to re-do the select/pty parts in a way that was more
   palatable to me.

 - restartable system calls

   This was needed for Ted's code to do ^Z

 - Math emulation! The code was a total crock, and didn't bother with
   such unnecessary niceties as getting rounding right (or, to be
   honest, even getting more than about 60 bits right), but let's face
   it: it was enough to get work done.

   My math emulation was eventually to be entirely replaced by a much
   more complete, and much more precise implementation by Bill
   Metzenthen.  But my original stupid implementation actually ended
   living on at least for a while in BSD - I ended up making it
   available to the BSD people who couldn't use Bill's much better
   implementation due to licensing reasons.  I don't know whatever
   eventually happened to it.

 - support alignment check on i486+. Nobody seems to have ever used it,
   though.

Original release notes:

         RELEASE NOTES FOR LINUX v0.12

This is file mostly contains info on changed features of Linux, and
using old versions as a help-reference might be a good idea.

         COPYRIGHT

The Linux copyright will change: I've had a couple of requests to make
it compatible with the GNU copyleft, removing the "you may not
distribute it for money" condition.  I agree.  I propose that the
copyright be changed so that it confirms to GNU - pending approval of
the persons who have helped write code.  I assume this is going to be no
problem for anybody: If you have grievances ("I wrote that code assuming
the copyright would stay the same") mail me.  Otherwise The GNU copyleft
takes effect as of the first of February.  If you do not know the gist
of the GNU copyright - read it.

         INSTALLATION

This is a SHORT install-note. The installation is very similar to 0.11,
so read that (INSTALL-0.11) too. There are a couple of programs you will
need to install linux: something that writes disk images (rawrite.exe or
NU or...) and something that can create harddisk partitions (fdisk under
xenix or older versions of dos, edpart.exe or something like that).

NOTE! Repartitioning your harddisk will destroy all data on it (well,
not exactly, but if you know enough to get back the data you probably
didn't need this warning).  So be careful.

READ THIS THROUGH, THEN READ INSTALL-0.11, AND IF YOU ARE SURE YOU KNOW
WHAT YOU ARE DOING, CONTINUE.  OTHERWISE, PANIC.  OR WRITE ME FOR
EXPLANATIONS.  OR DO ANYTHING BUT INSTALL LINUX - IT'S VERY SIMPLE, BUT
IF YOU DON'T KNOW WHAT YOU ARE DOING YOU'LL PROBABLY BE SORRY.  I'D
RATHER ANSWER A FEW UNNECESSARY MAILS THAN GET MAIL SAYING "YOU KILLED
MY HARDDISK, BASTARD.  I'M GOING TO FIND YOU, AND YOU'LL BE SORRY WHEN I
DO".

1) back up everything you have on your harddisk - linux-0.12 is still in
   beta and might do weird things.  The only thing I guarantee is that
   it has worked fine on /my/ machine - for all I know it might eat your
   harddisk and spit it out in small pieces on any other hardware.

2) Test out the linux boot-disk with the root file system.  If it
   doesn't work, check the hardware requirements, and mail me if you
   still think it should work.  I might not be able to help you, but
   your bug-report would still be appreciated.

   Test that linux can read your harddisk at least partly: run the fdisk
   program on the root-disk, and see if it barfs.  If it tells you about
   any partitions at all, linux can successfully read at least part of
   your harddisk.

3) Make sure that you have a free /primary/ partition.  There can be 4
   primary partitions per drive: newer DOS fdisks seem to be able to
   create only 2 (one primary and one extended).  In that case use some
   other partitioning software: edpart.exe etc.  Linux fdisk currently
   only tells you the partition info - it doesn't write to the disk.

   Remember to check how big your partition was, as that can be used to
   tell which device Linux thinks it is.

4) Boot up linux again, fdisk to make sure you now have the new
   partition, and use mkfs to make a filesystem on one of the partitions
   fdisk reports.  Write "mkfs -c /dev/hdX nnn" where X is the device
   number reported by linux fdisk, and nnn is the size - also reported
   by fdisk.  nnn is the size in /blocks/, ie kilobytes.  You should be
   able to use the size info to determine which partition is represented
   by which device name.

5) Mount the new disk partition: "mount /dev/hdX /user".  Copy over the
   root filesystem to the harddisk, eg like this:

        # for i in bin dev etc usr tmp
        # do
        # cp +recursive /$i /user
        # done

   You caanot use just "cp +recursive / /user", as that will result in a
   loop.

6) Sync the filesystem after you have played around enough, and reboot.

        # sync
        <wait for it to sync>
        ctrl-alt-del

   The folklore says you should do this three times before rebooting:
   once should be enough, but I admit I do it three times anyway :) THIS
   IS IMPORTANT! NEVER EVER FORGET TO SYNC BEFORE KILLING THE MACHINE.

7) Change the bootdisk to understand which partition it should use as a
   root filesystem.  See INSTALL-0.11: it's still the word at offset
   508 into the image. You should be up and running.

That's it. Go back and read the INSTALL-0.11

         New features of 0.12, in order of appearance
         (ie in the order you see them)

        Linux now prints cute dots when loading

WoW. Run, don't walk, to see this :). Seriously, it should hopefully now
load even on machines that never got off the ground before, but
otherwise the loading hasn't changed. Implemented by drew.

        Super-VGA detection for extended alphamun modes

I cannot guarantee it, I didn't write it, but it works great on a ET400
SVGA card.  I'm addicted to the new look with 100x40 character editing,
instead of a cramped 80x25.  This only works on VGA-cards that support
higher text-resolutions, and which are correctly identified. Implemented
by d88-man.

        Job Control.

Ok, everybody used to typing ^Z after they started a long command, and
forgot to put it in the background - now it works on linux too.  Bash
knows the usualy job-control commands: bg, fg, jobs & kill.  I hope
there will be no nasty surprises.  Job control was implemented by
tytso@athena.mit.edu.

        Virtual consoles on EGA/VGA screens.

You can select one of several consoles by pressing the left alt-key and
a function key at the same time. Linux should report the number of
virtual consoles available upon bootup. /dev/tty0 is now "the current"
screen, /dev/tty1 is the main console, and /dev/tty2-8 can exist
depending on your text-mode or card.

NOTE! Scrolling is noticeably much slower with virtual consoles on a
EGA/VGA. The reason is that no longer does linux use all the screen
memory as a long buffer, but crams in several consoles in it. I think
it's worth it.

The virtual consoles also have some new screen-handling commands: they
confirm even better to vt200 control codes than 0.11. Special graphic
characters etc: you can well use them as terminals to VMS (although
that's a shameful waste of resources).

        pty's

Ok. I have to admit that I didn't get the hangup-code working correctly,
but that should be easy to add. The general things are there.

        select

I've never used it, so I cannot say how well it works. My minor testing
seems to indicate that it works ok. vc's, pty's and select were
implemented by pmacdona, although I hacked it heavily.

        387-emulation.

It's not complete, but it works well enough to run those gcc2.0 compiled
programs I tested (few).  None of the "heavy" math-functions are
implemented yet.

        Symbolic links.

Try out a few "ln -s xx yy", and ls -l. Note that I think tar should be
recompiled to know anout them, and probably some other programs too. The
0.12 rootimage-disk has most of the recompiled fileutilities.

        Virtual memory.

In addition to the "mkfs" program, there is now a "mkswap" program on
the root disk.  The syntax is identical: "mkswap -c /dev/hdX nnn", and
again: this writes over the partition, so be careful.  Swapping can then
be enabled by changing the word at offset 506 in the bootimage to the
desired device.  Use the same program as for setting the root file
system (but change the 508 offset to 506 of course).

NOTE! This has been tested by Robert Blum, who has a 2M machine, and it
allows you to run gcc without much memory.  HOWEVER, I had to stop using
it, as my diskspace was eaten up by the beta-gcc-2.0, so I'd like to
hear that it still works: I've been totally unable to make a
swap-partition for even rudimentary testing since about christmastime.
Thus the new changes could possibly just have backfired on the VM, but I
doubt it.

        And that's it, I think.

Happy hacking.

         Linus
parent b65b60f4
......@@ -21,6 +21,7 @@ CPP =cpp -nostdinc -Iinclude
# default of /dev/hd6 is used by 'build'.
#
ROOT_DEV=/dev/hd6
SWAP_DEV=/dev/hd2
ARCHIVES=kernel/kernel.o mm/mm.o fs/fs.o
DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a
......@@ -39,7 +40,8 @@ LIBS =lib/lib.a
all: Image
Image: boot/bootsect boot/setup tools/system tools/build
tools/build boot/bootsect boot/setup tools/system $(ROOT_DEV) > Image
tools/build boot/bootsect boot/setup tools/system $(ROOT_DEV) \
$(SWAP_DEV) > Image
sync
disk: Image
......@@ -85,17 +87,19 @@ boot/setup: boot/setup.s
$(AS86) -o boot/setup.o boot/setup.s
$(LD86) -s -o boot/setup boot/setup.o
boot/setup.s: boot/setup.S include/linux/config.h
$(CPP) -traditional boot/setup.S -o boot/setup.s
boot/bootsect.s: boot/bootsect.S include/linux/config.h
$(CPP) -traditional boot/bootsect.S -o boot/bootsect.s
boot/bootsect: boot/bootsect.s
$(AS86) -o boot/bootsect.o boot/bootsect.s
$(LD86) -s -o boot/bootsect boot/bootsect.o
tmp.s: boot/bootsect.s tools/system
(echo -n "SYSSIZE = (";ls -l tools/system | grep system \
| cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s
cat boot/bootsect.s >> tmp.s
clean:
rm -f Image System.map tmp_make core boot/bootsect boot/setup
rm -f Image System.map tmp_make core boot/bootsect boot/setup \
boot/bootsect.s boot/setup.s
rm -f init/*.o tools/system tools/build boot/*.o
(cd mm;make clean)
(cd fs;make clean)
......@@ -116,8 +120,10 @@ dep:
### Dependencies:
init/main.o : init/main.c include/unistd.h include/sys/stat.h \
include/sys/types.h include/sys/times.h include/sys/utsname.h \
include/utime.h include/time.h include/linux/tty.h include/termios.h \
include/linux/sched.h include/linux/head.h include/linux/fs.h \
include/linux/mm.h include/signal.h include/asm/system.h include/asm/io.h \
include/stddef.h include/stdarg.h include/fcntl.h
include/sys/types.h include/sys/time.h include/time.h include/sys/times.h \
include/sys/utsname.h include/sys/param.h include/sys/resource.h \
include/utime.h include/linux/tty.h include/termios.h include/linux/sched.h \
include/linux/head.h include/linux/fs.h include/linux/mm.h \
include/linux/kernel.h include/signal.h include/asm/system.h \
include/asm/io.h include/stddef.h include/stdarg.h include/fcntl.h \
include/string.h
......@@ -3,9 +3,11 @@
! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
! versions of linux
!
SYSSIZE = 0x3000
#include <linux/config.h>
SYSSIZE = DEF_SYSSIZE
!
! bootsect.s (C) 1991 Linus Torvalds
! modified by Drew Eckhardt
!
! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
! iself out of the way to address 0x90000, and jumps there.
......@@ -33,14 +35,14 @@ begbss:
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).
INITSEG = DEF_INITSEG ! we move boot here - out of the way
SETUPSEG = DEF_SETUPSEG ! setup starts here
SYSSEG = DEF_SYSSEG ! 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 = 0x306
! ROOT_DEV & SWAP_DEV are now written by "build".
ROOT_DEV = 0
SWAP_DEV = 0
entry start
start:
......@@ -54,25 +56,83 @@ start:
rep
movw
jmpi go,INITSEG
go: mov ax,cs
go: mov ax,cs
mov dx,#0xfef4 ! arbitrary value >>512 - disk parm size
mov ds,ax
mov es,ax
! put stack at 0x9ff00.
mov ss,ax
mov sp,#0xFF00 ! arbitrary value >>512
push ax
mov ss,ax ! put stack at 0x9ff00 - 12.
mov sp,dx
/*
* Many BIOS's default disk parameter tables will not
* recognize multi-sector reads beyond the maximum sector number
* specified in the default diskette parameter tables - this may
* mean 7 sectors in some cases.
*
* Since single sector reads are slow and out of the question,
* we must take care of this by creating new parameter tables
* (for the first disk) in RAM. We will set the maximum sector
* count to 18 - the most we will encounter on an HD 1.44.
*
* High doesn't hurt. Low does.
*
* Segments are as follows: ds=es=ss=cs - INITSEG,
* fs = 0, gs = parameter table segment
*/
push #0
pop fs
mov bx,#0x78 ! fs:bx is parameter table address
seg fs
lgs si,(bx) ! gs:si is source
mov di,dx ! es:di is destination
mov cx,#6 ! copy 12 bytes
cld
rep
seg gs
movw
mov di,dx
movb 4(di),*18 ! patch sector count
seg fs
mov (bx),di
seg fs
mov 2(bx),es
pop ax
mov fs,ax
mov gs,ax
xor ah,ah ! reset FDC
xor dl,dl
int 0x13
! load the setup-sectors directly after the bootblock.
! Note that 'es' is already set up.
load_setup:
mov dx,#0x0000 ! drive 0, head 0
xor dx, dx ! 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
push ax ! dump error code
call print_nl
mov bp, sp
call print_hex
pop ax
xor dl, dl ! reset FDC
xor ah, ah
int 0x13
j load_setup
......@@ -80,10 +140,10 @@ ok_load_setup:
! Get disk drive parameters, specifically nr of sectors/track
mov dl,#0x00
mov ax,#0x0800 ! AH=8 is get drive parameters
xor dl,dl
mov ah,#0x08 ! AH=8 is get drive parameters
int 0x13
mov ch,#0x00
xor ch,ch
seg cs
mov sectors,cx
mov ax,#INITSEG
......@@ -95,7 +155,7 @@ ok_load_setup:
xor bh,bh
int 0x10
mov cx,#24
mov cx,#9
mov bx,#0x0007 ! page 0, attribute 7 (normal)
mov bp,#msg1
mov ax,#0x1301 ! write string, move cursor
......@@ -108,6 +168,7 @@ ok_load_setup:
mov es,ax ! segment of 0x010000
call read_it
call kill_motor
call print_nl
! After that we check which root-device to use. If the device is
! defined (!= 0), nothing is done and the given device is used.
......@@ -116,7 +177,7 @@ ok_load_setup:
seg cs
mov ax,root_dev
cmp ax,#0
or ax,ax
jne root_defined
seg cs
mov bx,sectors
......@@ -190,41 +251,122 @@ ok3_read:
add bx,cx
jnc rp_read
mov ax,es
add ax,#0x1000
add ah,#0x10
mov es,ax
xor bx,bx
jmp rp_read
read_track:
push ax
push bx
push cx
push dx
pusha
pusha
mov ax, #0xe2e ! loading... message 2e = .
mov bx, #7
int 0x10
popa
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
push dx ! save for error dump
push cx
push bx
push ax
int 0x13
jc bad_rt
pop dx
pop cx
pop bx
pop ax
add sp, #8
popa
ret
bad_rt: mov ax,#0
mov dx,#0
bad_rt: push ax ! save error code
call print_all ! ah = error, al = read
xor ah,ah
xor dl,dl
int 0x13
pop dx
pop cx
pop bx
pop ax
add sp, #10
popa
jmp read_track
/*
* print_all is for debugging purposes.
* It will print out all of the registers. The assumption is that this is
* called from a routine, with a stack frame like
* dx
* cx
* bx
* ax
* error
* ret <- sp
*
*/
print_all:
mov cx, #5 ! error code + 4 registers
mov bp, sp
print_loop:
push cx ! save count left
call print_nl ! nl for readability
jae no_reg ! see if register name is needed
mov ax, #0xe05 + 0x41 - 1
sub al, cl
int 0x10
mov al, #0x58 ! X
int 0x10
mov al, #0x3a ! :
int 0x10
no_reg:
add bp, #2 ! next register
call print_hex ! print it
pop cx
loop print_loop
ret
print_nl:
mov ax, #0xe0d ! CR
int 0x10
mov al, #0xa ! LF
int 0x10
ret
/*
* print_hex is for debugging purposes, and prints the word
* pointed to by ss:bp in hexadecmial.
*/
print_hex:
mov cx, #4 ! 4 hex digits
mov dx, (bp) ! load word into dx
print_digit:
rol dx, #4 ! rotate so that lowest 4 bits are used
mov ah, #0xe
mov al, dl ! mask off so we have only next nibble
and al, #0xf
add al, #0x30 ! convert to 0 based digit, '0'
cmp al, #0x39 ! check for overflow
jbe good_digit
add al, #0x41 - 0x30 - 0xa ! 'A' - '0' - 0xa
good_digit:
int 0x10
loop print_digit
ret
/*
* This procedure turns off the floppy drive motor, so
* that we enter the kernel in a known state, and
......@@ -233,7 +375,7 @@ bad_rt: mov ax,#0
kill_motor:
push dx
mov dx,#0x3f2
mov al,#0
xor al, al
outb
pop dx
ret
......@@ -243,10 +385,11 @@ sectors:
msg1:
.byte 13,10
.ascii "Loading system ..."
.byte 13,10,13,10
.ascii "Loading"
.org 508
.org 506
swap_dev:
.word SWAP_DEV
root_dev:
.word ROOT_DEV
boot_flag:
......@@ -258,3 +401,4 @@ endtext:
enddata:
.bss
endbss:
......@@ -13,10 +13,11 @@
!
! NOTE! These had better be the same as in bootsect.s!
#include <linux/config.h>
INITSEG = 0x9000 ! we move boot here - out of the way
SYSSEG = 0x1000 ! system loaded at 0x10000 (65536).
SETUPSEG = 0x9020 ! this is the current segment
INITSEG = DEF_INITSEG ! we move boot here - out of the way
SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536).
SETUPSEG = DEF_SETUPSEG ! this is the current segment
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
......@@ -35,10 +36,6 @@ start:
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)
......@@ -46,13 +43,6 @@ start:
int 0x15
mov [2],ax
! Get video-card data:
mov ah,#0x0f
int 0x10
mov [4],bx ! bh = display page
mov [6],ax ! al = video mode, ah = window width
! check for EGA/VGA and some config parameters
mov ah,#0x12
......@@ -61,6 +51,22 @@ start:
mov [8],ax
mov [10],bx
mov [12],cx
mov ax,#0x5019
cmp bl,#0x10
je novga
call chsvga
novga: mov [14],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 video-card data:
mov ah,#0x0f
int 0x10
mov [4],bx ! bh = display page
mov [6],ax ! al = video mode, ah = window width
! Get hd0 data
......@@ -202,6 +208,362 @@ empty_8042:
jnz empty_8042 ! yes - loop
ret
! Routine trying to recognize type of SVGA-board present (if any)
! and if it recognize one gives the choices of resolution it offers.
! If one is found the resolution chosen is given by al,ah (rows,cols).
chsvga: cld
push ds
push cs
pop ds
mov ax,#0xc000
mov es,ax
lea si,msg1
call prtstr
nokey: in al,#0x60
cmp al,#0x82
jb nokey
cmp al,#0xe0
ja nokey
cmp al,#0x9c
je svga
mov ax,#0x5019
pop ds
ret
svga: lea si,idati ! Check ATI 'clues'
mov di,#0x31
mov cx,#0x09
repe
cmpsb
jne noati
lea si,dscati
lea di,moati
lea cx,selmod
jmp cx
noati: mov ax,#0x200f ! Check Ahead 'clues'
mov dx,#0x3ce
out dx,ax
inc dx
in al,dx
cmp al,#0x20
je isahed
cmp al,#0x21
jne noahed
isahed: lea si,dscahead
lea di,moahead
lea cx,selmod
jmp cx
noahed: mov dx,#0x3c3 ! Check Chips & Tech. 'clues'
in al,dx
or al,#0x10
out dx,al
mov dx,#0x104
in al,dx
mov bl,al
mov dx,#0x3c3
in al,dx
and al,#0xef
out dx,al
cmp bl,[idcandt]
jne nocant
lea si,dsccandt
lea di,mocandt
lea cx,selmod
jmp cx
nocant: mov dx,#0x3d4 ! Check Cirrus 'clues'
mov al,#0x0c
out dx,al
inc dx
in al,dx
mov bl,al
xor al,al
out dx,al
dec dx
mov al,#0x1f
out dx,al
inc dx
in al,dx
mov bh,al
xor ah,ah
shl al,#4
mov cx,ax
mov al,bh
shr al,#4
add cx,ax
shl cx,#8
add cx,#6
mov ax,cx
mov dx,#0x3c4
out dx,ax
inc dx
in al,dx
and al,al
jnz nocirr
mov al,bh
out dx,al
in al,dx
cmp al,#0x01
jne nocirr
call rst3d4
lea si,dsccirrus
lea di,mocirrus
lea cx,selmod
jmp cx
rst3d4: mov dx,#0x3d4
mov al,bl
xor ah,ah
shl ax,#8
add ax,#0x0c
out dx,ax
ret
nocirr: call rst3d4 ! Check Everex 'clues'
mov ax,#0x7000
xor bx,bx
int 0x10
cmp al,#0x70
jne noevrx
shr dx,#4
cmp dx,#0x678
je istrid
cmp dx,#0x236
je istrid
lea si,dsceverex
lea di,moeverex
lea cx,selmod
jmp cx
istrid: lea cx,ev2tri
jmp cx
noevrx: lea si,idgenoa ! Check Genoa 'clues'
xor ax,ax
seg es
mov al,[0x37]
mov di,ax
mov cx,#0x04
dec si
dec di
l1: inc si
inc di
mov al,(si)
seg es
and al,(di)
cmp al,(si)
loope l1
cmp cx,#0x00
jne nogen
lea si,dscgenoa
lea di,mogenoa
lea cx,selmod
jmp cx
nogen: lea si,idparadise ! Check Paradise 'clues'
mov di,#0x7d
mov cx,#0x04
repe
cmpsb
jne nopara
lea si,dscparadise
lea di,moparadise
lea cx,selmod
jmp cx
nopara: mov dx,#0x3c4 ! Check Trident 'clues'
mov al,#0x0e
out dx,al
inc dx
in al,dx
xchg ah,al
mov al,#0x00
out dx,al
in al,dx
xchg al,ah
mov bl,al ! Strange thing ... in the book this wasn't
and bl,#0x02 ! necessary but it worked on my card which
jz setb2 ! is a trident. Without it the screen goes
and al,#0xfd ! blurred ...
jmp clrb2 !
setb2: or al,#0x02 !
clrb2: out dx,al
and ah,#0x0f
cmp ah,#0x02
jne notrid
ev2tri: lea si,dsctrident
lea di,motrident
lea cx,selmod
jmp cx
notrid: mov dx,#0x3cd ! Check Tseng 'clues'
in al,dx ! Could things be this simple ! :-)
mov bl,al
mov al,#0x55
out dx,al
in al,dx
mov ah,al
mov al,bl
out dx,al
cmp ah,#0x55
jne notsen
lea si,dsctseng
lea di,motseng
lea cx,selmod
jmp cx
notsen: mov dx,#0x3cc ! Check Video7 'clues'
in al,dx
mov dx,#0x3b4
and al,#0x01
jz even7
mov dx,#0x3d4
even7: mov al,#0x0c
out dx,al
inc dx
in al,dx
mov bl,al
mov al,#0x55
out dx,al
in al,dx
dec dx
mov al,#0x1f
out dx,al
inc dx
in al,dx
mov bh,al
dec dx
mov al,#0x0c
out dx,al
inc dx
mov al,bl
out dx,al
mov al,#0x55
xor al,#0xea
cmp al,bh
jne novid7
lea si,dscvideo7
lea di,movideo7
selmod: push si
lea si,msg2
call prtstr
xor cx,cx
mov cl,(di)
pop si
push si
push cx
tbl: pop bx
push bx
mov al,bl
sub al,cl
call dprnt
call spcing
lodsw
xchg al,ah
call dprnt
xchg ah,al
push ax
mov al,#0x78
call prnt1
pop ax
call dprnt
call docr
loop tbl
pop cx
call docr
lea si,msg3
call prtstr
pop si
add cl,#0x80
nonum: in al,#0x60 ! Quick and dirty...
cmp al,#0x82
jb nonum
cmp al,#0x8b
je zero
cmp al,cl
ja nonum
jmp nozero
zero: sub al,#0x0a
nozero: sub al,#0x80
dec al
xor ah,ah
add di,ax
inc di
push ax
mov al,(di)
int 0x10
pop ax
shl ax,#1
add si,ax
lodsw
pop ds
ret
novid7: pop ds ! Here could be code to support standard 80x50,80x30
mov ax,#0x5019
ret
! Routine that 'tabs' to next col.
spcing: mov al,#0x2e
call prnt1
mov al,#0x20
call prnt1
mov al,#0x20
call prnt1
mov al,#0x20
call prnt1
mov al,#0x20
call prnt1
ret
! Routine to print asciiz-string at DS:SI
prtstr: lodsb
and al,al
jz fin
call prnt1
jmp prtstr
fin: ret
! Routine to print a decimal value on screen, the value to be
! printed is put in al (i.e 0-255).
dprnt: push ax
push cx
mov ah,#0x00
mov cl,#0x0a
idiv cl
cmp al,#0x09
jbe lt100
call dprnt
jmp skip10
lt100: add al,#0x30
call prnt1
skip10: mov al,ah
add al,#0x30
call prnt1
pop cx
pop ax
ret
! Part of above routine, this one just prints ascii al
prnt1: push ax
push cx
mov bh,#0x00
mov cx,#0x01
mov ah,#0x0e
int 0x10
pop cx
pop ax
ret
! Prints <CR> + <LF>
docr: push ax
push cx
mov bh,#0x00
mov ah,#0x0e
mov al,#0x0a
mov cx,#0x01
int 0x10
mov al,#0x0d
int 0x10
pop cx
pop ax
ret
gdt:
.word 0,0,0,0 ! dummy
......@@ -222,6 +584,44 @@ idt_48:
gdt_48:
.word 0x800 ! gdt limit=2048, 256 GDT entries
.word 512+gdt,0x9 ! gdt base = 0X9xxxx
msg1: .ascii "Press <RETURN> to see SVGA-modes available or any other key to continue."
db 0x0d, 0x0a, 0x0a, 0x00
msg2: .ascii "Mode: COLSxROWS:"
db 0x0d, 0x0a, 0x0a, 0x00
msg3: .ascii "Choose mode by pressing the corresponding number."
db 0x0d, 0x0a, 0x00
idati: .ascii "761295520"
idcandt: .byte 0xa5
idgenoa: .byte 0x77, 0x00, 0x66, 0x99
idparadise: .ascii "VGA="
! Manufacturer: Numofmodes: Mode:
moati: .byte 0x02, 0x23, 0x33
moahead: .byte 0x05, 0x22, 0x23, 0x24, 0x2f, 0x34
mocandt: .byte 0x02, 0x60, 0x61
mocirrus: .byte 0x04, 0x1f, 0x20, 0x22, 0x31
moeverex: .byte 0x0a, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40
mogenoa: .byte 0x0a, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78
moparadise: .byte 0x02, 0x55, 0x54
motrident: .byte 0x07, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a
motseng: .byte 0x05, 0x26, 0x2a, 0x23, 0x24, 0x22
movideo7: .byte 0x06, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45
! msb = Cols lsb = Rows:
dscati: .word 0x8419, 0x842c
dscahead: .word 0x842c, 0x8419, 0x841c, 0xa032, 0x5042
dsccandt: .word 0x8419, 0x8432
dsccirrus: .word 0x8419, 0x842c, 0x841e, 0x6425
dsceverex: .word 0x5022, 0x503c, 0x642b, 0x644b, 0x8419, 0x842c, 0x501e, 0x641b, 0xa040, 0x841e
dscgenoa: .word 0x5020, 0x642a, 0x8419, 0x841d, 0x8420, 0x842c, 0x843c, 0x503c, 0x5042, 0x644b
dscparadise: .word 0x8419, 0x842b
dsctrident: .word 0x501e, 0x502b, 0x503c, 0x8419, 0x841e, 0x842b, 0x843c
dsctseng: .word 0x503c, 0x6428, 0x8419, 0x841c, 0x842c
dscvideo7: .word 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c
.text
endtext:
......
......@@ -3,7 +3,7 @@ AS =gas
CC =gcc
LD =gld
CFLAGS =-Wall -O -fstrength-reduce -fcombine-regs -fomit-frame-pointer \
-mstring-insns -nostdinc -I../include
-fno-defer-pop -mstring-insns -nostdinc -I../include
CPP =gcc -E -nostdinc -I../include
.c.s:
......@@ -17,7 +17,7 @@ CPP =gcc -E -nostdinc -I../include
OBJS= open.o read_write.o inode.o file_table.o buffer.o super.o \
block_dev.o char_dev.o file_dev.o stat.o exec.o pipe.o namei.o \
bitmap.o fcntl.o ioctl.o truncate.o
bitmap.o fcntl.o ioctl.o truncate.o select.o
fs.o: $(OBJS)
$(LD) -r -o fs.o $(OBJS)
......@@ -34,67 +34,96 @@ 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/signal.h ../include/linux/kernel.h
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h
block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
../include/asm/segment.h ../include/asm/system.h
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h ../include/asm/segment.h ../include/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
../include/sys/types.h ../include/linux/mm.h ../include/linux/kernel.h \
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/asm/system.h \
../include/asm/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/string.h \
../include/sys/stat.h ../include/sys/types.h ../include/a.out.h \
../include/linux/fs.h ../include/linux/sched.h ../include/linux/head.h \
../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
../include/asm/segment.h
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h ../include/asm/segment.h ../include/asm/io.h
exec.o : exec.c ../include/signal.h ../include/sys/types.h \
../include/errno.h ../include/string.h ../include/sys/stat.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/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h ../include/asm/segment.h
fcntl.o : fcntl.c ../include/string.h ../include/errno.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
../include/sys/types.h ../include/linux/mm.h ../include/signal.h \
../include/linux/kernel.h ../include/asm/segment.h ../include/fcntl.h \
../include/sys/stat.h
../include/sys/types.h ../include/linux/mm.h ../include/linux/kernel.h \
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/asm/segment.h \
../include/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/signal.h \
../include/linux/kernel.h ../include/asm/segment.h
../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/asm/segment.h
file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h
inode.o : inode.c ../include/string.h ../include/sys/stat.h \
../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \
../include/linux/kernel.h ../include/asm/system.h
../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/asm/system.h
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/signal.h
../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
../include/sys/time.h ../include/time.h ../include/sys/resource.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/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
../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
../include/sys/time.h ../include/time.h ../include/sys/resource.h \
../include/asm/segment.h ../include/string.h ../include/fcntl.h \
../include/errno.h ../include/const.h ../include/sys/stat.h
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/signal.h ../include/linux/tty.h \
../include/termios.h ../include/linux/kernel.h ../include/asm/segment.h
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h ../include/linux/tty.h ../include/termios.h \
../include/asm/segment.h
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
../include/errno.h ../include/termios.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/asm/segment.h
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/signal.h ../include/asm/segment.h
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/asm/segment.h
select.o : select.c ../include/linux/fs.h ../include/sys/types.h \
../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \
../include/linux/sched.h ../include/linux/head.h ../include/linux/mm.h \
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/asm/segment.h \
../include/asm/system.h ../include/sys/stat.h ../include/string.h \
../include/const.h ../include/errno.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/signal.h \
../include/linux/kernel.h ../include/asm/segment.h
../include/linux/head.h ../include/linux/mm.h ../include/linux/kernel.h \
../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/asm/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/signal.h ../include/linux/kernel.h \
../include/asm/system.h ../include/errno.h ../include/sys/stat.h
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h ../include/asm/system.h ../include/errno.h \
../include/sys/stat.h
truncate.o : truncate.c ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
../include/signal.h ../include/sys/stat.h
../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
../include/sys/time.h ../include/time.h ../include/sys/resource.h \
../include/sys/stat.h
......@@ -44,7 +44,7 @@ __asm__("cld\n" \
:"=c" (__res):"c" (0),"S" (addr):"ax","dx","si"); \
__res;})
void free_block(int dev, int block)
int free_block(int dev, int block)
{
struct super_block * sb;
struct buffer_head * bh;
......@@ -55,21 +55,22 @@ void free_block(int dev, int block)
panic("trying to free block not in datazone");
bh = get_hash_table(dev,block);
if (bh) {
if (bh->b_count != 1) {
printk("trying to free block (%04x:%d), count=%d\n",
dev,block,bh->b_count);
return;
if (bh->b_count > 1) {
brelse(bh);
return 0;
}
bh->b_dirt=0;
bh->b_uptodate=0;
brelse(bh);
if (bh->b_count)
brelse(bh);
}
block -= sb->s_firstdatazone - 1 ;
if (clear_bit(block&8191,sb->s_zmap[block/8192]->b_data)) {
printk("block (%04x:%d) ",dev,block+sb->s_firstdatazone-1);
panic("free_block: bit already cleared");
printk("free_block: bit already cleared\n");
}
sb->s_zmap[block/8192]->b_dirt = 1;
return 1;
}
int new_block(int dev)
......
......@@ -11,16 +11,25 @@
#include <asm/segment.h>
#include <asm/system.h>
extern int *blk_size[];
int block_write(int dev, long * pos, char * buf, int count)
{
int block = *pos >> BLOCK_SIZE_BITS;
int offset = *pos & (BLOCK_SIZE-1);
int chars;
int written = 0;
int size;
struct buffer_head * bh;
register char * p;
if (blk_size[MAJOR(dev)])
size = blk_size[MAJOR(dev)][MINOR(dev)];
else
size = 0x7fffffff;
while (count>0) {
if (block >= size)
return written?written:-EIO;
chars = BLOCK_SIZE - offset;
if (chars > count)
chars=count;
......@@ -49,11 +58,18 @@ int block_read(int dev, unsigned long * pos, char * buf, int count)
int block = *pos >> BLOCK_SIZE_BITS;
int offset = *pos & (BLOCK_SIZE-1);
int chars;
int size;
int read = 0;
struct buffer_head * bh;
register char * p;
if (blk_size[MAJOR(dev)])
size = blk_size[MAJOR(dev)][MINOR(dev)];
else
size = 0x7fffffff;
while (count>0) {
if (block >= size)
return read?read:-EIO;
chars = BLOCK_SIZE-offset;
if (chars > count)
chars = count;
......
......@@ -17,6 +17,7 @@
* was less than 2 hours work to get demand-loading completely implemented.
*/
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
......@@ -38,6 +39,28 @@ extern int sys_close(int fd);
*/
#define MAX_ARG_PAGES 32
int sys_uselib(const char * library)
{
struct m_inode * inode;
unsigned long base;
if (get_limit(0x17) != TASK_SIZE)
return -EINVAL;
if (library) {
if (!(inode=namei(library))) /* get library inode */
return -ENOENT;
} else
inode = NULL;
/* we should check filetypes (headers etc), but we don't */
iput(current->library);
current->library = NULL;
base = get_base(current->ldt[2]);
base += LIBRARY_OFFSET;
free_page_tables(base,LIBRARY_SIZE);
current->library = inode;
return 0;
}
/*
* create_tables() parses the env- and arg-strings in new user
* memory and creates the pointer tables from them, and puts their
......@@ -156,9 +179,8 @@ static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
unsigned long code_limit,data_limit,code_base,data_base;
int i;
code_limit = text_size+PAGE_SIZE -1;
code_limit &= 0xFFFFF000;
data_limit = 0x4000000;
code_limit = TASK_SIZE;
data_limit = TASK_SIZE;
code_base = get_base(current->ldt[1]);
data_base = code_base;
set_base(current->ldt[1],code_base);
......@@ -167,17 +189,20 @@ static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
set_limit(current->ldt[2],data_limit);
/* make sure fs points to the NEW data segment */
__asm__("pushl $0x17\n\tpop %%fs"::);
data_base += data_limit;
data_base += data_limit - LIBRARY_SIZE;
for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
data_base -= PAGE_SIZE;
if (page[i])
put_page(page[i],data_base);
put_dirty_page(page[i],data_base);
}
return data_limit;
}
/*
* 'do_execve()' executes a new program.
*
* NOTE! We leave 4MB free at the top of the data-area for a loadable
* library.
*/
int do_execve(unsigned long * eip,long tmp,char * filename,
char ** argv, char ** envp)
......@@ -211,7 +236,7 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
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)
else if (in_group_p(inode->i_gid))
i >>= 3;
if (!(i & 1) &&
!((inode->i_mode & 0111) && suser())) {
......@@ -229,13 +254,13 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
* Sorta complicated, but hopefully it will work. -TYT
*/
char buf[1023], *cp, *interp, *i_name, *i_arg;
char buf[128], *cp, *interp, *i_name, *i_arg;
unsigned long old_fs;
strncpy(buf, bh->b_data+2, 1022);
strncpy(buf, bh->b_data+2, 127);
brelse(bh);
iput(inode);
buf[1022] = '\0';
buf[127] = '\0';
if (cp = strchr(buf, '\n')) {
*cp = '\0';
for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
......@@ -316,11 +341,17 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
}
}
/* OK, This is the point of no return */
/* note that current->library stays unchanged by an exec */
if (current->executable)
iput(current->executable);
current->executable = inode;
for (i=0 ; i<32 ; i++)
current->sigaction[i].sa_handler = NULL;
current->signal = 0;
for (i=0 ; i<32 ; i++) {
current->sigaction[i].sa_mask = 0;
current->sigaction[i].sa_flags = 0;
if (current->sigaction[i].sa_handler != SIG_IGN)
current->sigaction[i].sa_handler = NULL;
}
for (i=0 ; i<NR_OPEN ; i++)
if ((current->close_on_exec>>i)&1)
sys_close(i);
......@@ -330,17 +361,15 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
if (last_task_used_math == current)
last_task_used_math = NULL;
current->used_math = 0;
p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
p += change_ldt(ex.a_text,page);
p -= LIBRARY_SIZE + MAX_ARG_PAGES*PAGE_SIZE;
p = (unsigned long) create_tables((char *)p,argc,envc);
current->brk = ex.a_bss +
(current->end_data = ex.a_data +
(current->end_code = ex.a_text));
current->start_stack = p & 0xfffff000;
current->euid = e_uid;
current->egid = e_gid;
i = ex.a_text+ex.a_data;
while (i&0xfff)
put_fs_byte(0,(char *) (i++));
current->suid = current->euid = e_uid;
current->sgid = current->egid = e_gid;
eip[0] = ex.a_entry; /* eip, magic happens :-) */
eip[3] = p; /* stack pointer */
return 0;
......
......@@ -12,6 +12,8 @@
#include <linux/mm.h>
#include <asm/system.h>
extern int *blk_size[];
struct m_inode inode_table[NR_INODE]={{0,},};
static void read_inode(struct m_inode * inode);
......@@ -156,6 +158,7 @@ void iput(struct m_inode * inode)
panic("iput: trying to free free inode");
if (inode->i_pipe) {
wake_up(&inode->i_wait);
wake_up(&inode->i_wait2);
if (--inode->i_count)
return;
free_page(inode->i_size);
......@@ -308,6 +311,13 @@ static void read_inode(struct m_inode * inode)
((struct d_inode *)bh->b_data)
[(inode->i_num-1)%INODES_PER_BLOCK];
brelse(bh);
if (S_ISBLK(inode->i_mode)) {
int i = inode->i_zone[0];
if (blk_size[MAJOR(i)])
inode->i_size = 1024*blk_size[MAJOR(i)][MINOR(i)];
else
inode->i_size = 0x7fffffff;
}
unlock_inode(inode);
}
......
......@@ -11,6 +11,7 @@
#include <linux/sched.h>
extern int tty_ioctl(int dev, int cmd, int arg);
extern int pipe_ioctl(struct m_inode *pino, int cmd, int arg);
typedef int (*ioctl_ptr)(int dev,int cmd,int arg);
......@@ -34,6 +35,8 @@ int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
if (fd >= NR_OPEN || !(filp = current->filp[fd]))
return -EBADF;
if (filp->f_inode->i_pipe)
return (filp->f_mode&1)?pipe_ioctl(filp->f_inode,cmd,arg):-EBADF;
mode=filp->f_inode->i_mode;
if (!S_ISCHR(mode) && !S_ISBLK(mode))
return -EINVAL;
......
......@@ -18,6 +18,9 @@
#include <const.h>
#include <sys/stat.h>
static struct m_inode * _namei(const char * filename, struct m_inode * base,
int follow_links);
#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])
/*
......@@ -46,7 +49,7 @@ static int permission(struct m_inode * inode,int mask)
return 0;
else if (current->euid==inode->i_uid)
mode >>= 6;
else if (current->egid==inode->i_gid)
else if (in_group_p(inode->i_gid))
mode >>= 3;
if (((mode & mask & 0007) == mask) || suser())
return 1;
......@@ -66,6 +69,9 @@ static int match(int len,const char * name,struct dir_entry * de)
if (!de || !de->inode || len > NAME_LEN)
return 0;
/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
return 1;
if (len < NAME_LEN && de->name[len])
return 0;
__asm__("cld\n\t"
......@@ -106,8 +112,6 @@ static struct buffer_head * find_entry(struct m_inode ** dir,
#endif
entries = (*dir)->i_size / (sizeof (struct dir_entry));
*res_dir = NULL;
if (!namelen)
return NULL;
/* check for '..', as we might have to do some "magic" for it */
if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') {
/* '..' in a pseudo-root results in a faked '.' (just change namelen) */
......@@ -219,33 +223,63 @@ static struct buffer_head * add_entry(struct m_inode * dir,
return NULL;
}
static struct m_inode * follow_link(struct m_inode * dir, struct m_inode * inode)
{
unsigned short fs;
struct buffer_head * bh;
if (!dir) {
dir = current->root;
dir->i_count++;
}
if (!inode) {
iput(dir);
return NULL;
}
if (!S_ISLNK(inode->i_mode)) {
iput(dir);
return inode;
}
__asm__("mov %%fs,%0":"=r" (fs));
if (fs != 0x17 || !inode->i_zone[0] ||
!(bh = bread(inode->i_dev, inode->i_zone[0]))) {
iput(dir);
iput(inode);
return NULL;
}
iput(inode);
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
inode = _namei(bh->b_data,dir,0);
__asm__("mov %0,%%fs"::"r" (fs));
brelse(bh);
return inode;
}
/*
* get_dir()
*
* Getdir traverses the pathname until it hits the topmost directory.
* It returns NULL on failure.
*/
static struct m_inode * get_dir(const char * pathname)
static struct m_inode * get_dir(const char * pathname, struct m_inode * inode)
{
char c;
const char * thisname;
struct m_inode * inode;
struct buffer_head * bh;
int namelen,inr,idev;
int namelen,inr;
struct dir_entry * de;
struct m_inode * dir;
if (!current->root || !current->root->i_count)
panic("No root inode");
if (!current->pwd || !current->pwd->i_count)
panic("No cwd inode");
if (!inode) {
inode = current->pwd;
inode->i_count++;
}
if ((c=get_fs_byte(pathname))=='/') {
iput(inode);
inode = current->root;
pathname++;
} else if (c)
inode = current->pwd;
else
return NULL; /* empty name is bad */
inode->i_count++;
inode->i_count++;
}
while (1) {
thisname = pathname;
if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) {
......@@ -261,10 +295,13 @@ static struct m_inode * get_dir(const char * pathname)
return NULL;
}
inr = de->inode;
idev = inode->i_dev;
brelse(bh);
iput(inode);
if (!(inode = iget(idev,inr)))
dir = inode;
if (!(inode = iget(dir->i_dev,inr))) {
iput(dir);
return NULL;
}
if (!(inode = follow_link(dir,inode)))
return NULL;
}
}
......@@ -276,13 +313,13 @@ static struct m_inode * get_dir(const char * pathname)
* specified name, and the name within that directory.
*/
static struct m_inode * dir_namei(const char * pathname,
int * namelen, const char ** name)
int * namelen, const char ** name, struct m_inode * base)
{
char c;
const char * basename;
struct m_inode * dir;
if (!(dir = get_dir(pathname)))
if (!(dir = get_dir(pathname,base)))
return NULL;
basename = pathname;
while (c=get_fs_byte(pathname++))
......@@ -293,40 +330,54 @@ static struct m_inode * dir_namei(const char * pathname,
return dir;
}
/*
* namei()
*
* is used by most simple commands to get the inode of a specified name.
* Open, link etc use their own routines, but this is enough for things
* like 'chmod' etc.
*/
struct m_inode * namei(const char * pathname)
struct m_inode * _namei(const char * pathname, struct m_inode * base,
int follow_links)
{
const char * basename;
int inr,dev,namelen;
struct m_inode * dir;
int inr,namelen;
struct m_inode * inode;
struct buffer_head * bh;
struct dir_entry * de;
if (!(dir = dir_namei(pathname,&namelen,&basename)))
if (!(base = dir_namei(pathname,&namelen,&basename,base)))
return NULL;
if (!namelen) /* special case: '/usr/' etc */
return dir;
bh = find_entry(&dir,basename,namelen,&de);
return base;
bh = find_entry(&base,basename,namelen,&de);
if (!bh) {
iput(dir);
iput(base);
return NULL;
}
inr = de->inode;
dev = dir->i_dev;
brelse(bh);
iput(dir);
dir=iget(dev,inr);
if (dir) {
dir->i_atime=CURRENT_TIME;
dir->i_dirt=1;
if (!(inode = iget(base->i_dev,inr))) {
iput(base);
return NULL;
}
return dir;
if (follow_links)
inode = follow_link(base,inode);
else
iput(base);
inode->i_atime=CURRENT_TIME;
inode->i_dirt=1;
return inode;
}
struct m_inode * lnamei(const char * pathname)
{
return _namei(pathname, NULL, 0);
}
/*
* namei()
*
* is used by most simple commands to get the inode of a specified name.
* Open, link etc use their own routines, but this is enough for things
* like 'chmod' etc.
*/
struct m_inode * namei(const char * pathname)
{
return _namei(pathname,NULL,1);
}
/*
......@@ -347,7 +398,7 @@ int open_namei(const char * pathname, int flag, int mode,
flag |= O_WRONLY;
mode &= 0777 & ~current->umask;
mode |= I_REGULAR;
if (!(dir = dir_namei(pathname,&namelen,&basename)))
if (!(dir = dir_namei(pathname,&namelen,&basename,NULL)))
return -ENOENT;
if (!namelen) { /* special case: '/usr/' etc */
if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
......@@ -392,10 +443,11 @@ int open_namei(const char * pathname, int flag, int mode,
inr = de->inode;
dev = dir->i_dev;
brelse(bh);
iput(dir);
if (flag & O_EXCL)
if (flag & O_EXCL) {
iput(dir);
return -EEXIST;
if (!(inode=iget(dev,inr)))
}
if (!(inode = follow_link(dir,iget(dev,inr))))
return -EACCES;
if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
!permission(inode,ACC_MODE(flag))) {
......@@ -419,7 +471,7 @@ int sys_mknod(const char * filename, int mode, int dev)
if (!suser())
return -EPERM;
if (!(dir = dir_namei(filename,&namelen,&basename)))
if (!(dir = dir_namei(filename,&namelen,&basename, NULL)))
return -ENOENT;
if (!namelen) {
iput(dir);
......@@ -468,9 +520,7 @@ int sys_mkdir(const char * pathname, int mode)
struct buffer_head * bh, *dir_block;
struct dir_entry * de;
if (!suser())
return -EPERM;
if (!(dir = dir_namei(pathname,&namelen,&basename)))
if (!(dir = dir_namei(pathname,&namelen,&basename, NULL)))
return -ENOENT;
if (!namelen) {
iput(dir);
......@@ -503,7 +553,6 @@ int sys_mkdir(const char * pathname, int mode)
inode->i_dirt = 1;
if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) {
iput(dir);
free_block(inode->i_dev,inode->i_zone[0]);
inode->i_nlinks--;
iput(inode);
return -ERROR;
......@@ -522,7 +571,6 @@ int sys_mkdir(const char * pathname, int mode)
bh = add_entry(dir,basename,namelen,&de);
if (!bh) {
iput(dir);
free_block(inode->i_dev,inode->i_zone[0]);
inode->i_nlinks=0;
iput(inode);
return -ENOSPC;
......@@ -592,9 +640,7 @@ int sys_rmdir(const char * name)
struct buffer_head * bh;
struct dir_entry * de;
if (!suser())
return -EPERM;
if (!(dir = dir_namei(name,&namelen,&basename)))
if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
return -ENOENT;
if (!namelen) {
iput(dir);
......@@ -668,7 +714,7 @@ int sys_unlink(const char * name)
struct buffer_head * bh;
struct dir_entry * de;
if (!(dir = dir_namei(name,&namelen,&basename)))
if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
return -ENOENT;
if (!namelen) {
iput(dir);
......@@ -718,6 +764,76 @@ int sys_unlink(const char * name)
return 0;
}
int sys_symlink(const char * oldname, const char * newname)
{
struct dir_entry * de;
struct m_inode * dir, * inode;
struct buffer_head * bh, * name_block;
const char * basename;
int namelen, i;
char c;
dir = dir_namei(newname,&namelen,&basename, NULL);
if (!dir)
return -EACCES;
if (!namelen) {
iput(dir);
return -EPERM;
}
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EACCES;
}
if (!(inode = new_inode(dir->i_dev))) {
iput(dir);
return -ENOSPC;
}
inode->i_mode = S_IFLNK | (0777 & ~current->umask);
inode->i_dirt = 1;
if (!(inode->i_zone[0]=new_block(inode->i_dev))) {
iput(dir);
inode->i_nlinks--;
iput(inode);
return -ENOSPC;
}
inode->i_dirt = 1;
if (!(name_block=bread(inode->i_dev,inode->i_zone[0]))) {
iput(dir);
inode->i_nlinks--;
iput(inode);
return -ERROR;
}
i = 0;
while (i < 1023 && (c=get_fs_byte(oldname++)))
name_block->b_data[i++] = c;
name_block->b_data[i] = 0;
name_block->b_dirt = 1;
brelse(name_block);
inode->i_size = i;
inode->i_dirt = 1;
bh = find_entry(&dir,basename,namelen,&de);
if (bh) {
inode->i_nlinks--;
iput(inode);
brelse(bh);
iput(dir);
return -EEXIST;
}
bh = add_entry(dir,basename,namelen,&de);
if (!bh) {
inode->i_nlinks--;
iput(inode);
iput(dir);
return -ENOSPC;
}
de->inode = inode->i_num;
bh->b_dirt = 1;
brelse(bh);
iput(dir);
iput(inode);
return 0;
}
int sys_link(const char * oldname, const char * newname)
{
struct dir_entry * de;
......@@ -733,7 +849,7 @@ int sys_link(const char * oldname, const char * newname)
iput(oldinode);
return -EPERM;
}
dir = dir_namei(newname,&namelen,&basename);
dir = dir_namei(newname,&namelen,&basename, NULL);
if (!dir) {
iput(oldinode);
return -EACCES;
......
......@@ -14,6 +14,7 @@
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/kernel.h>
#include <asm/segment.h>
int sys_ustat(int dev, struct ustat * ubuf)
......@@ -135,6 +136,38 @@ int sys_chown(const char * filename,int uid,int gid)
return 0;
}
static int check_char_dev(struct m_inode * inode, int dev, int flag)
{
struct tty_struct *tty;
int min;
if (MAJOR(dev) == 4 || MAJOR(dev) == 5) {
if (MAJOR(dev) == 5)
min = current->tty;
else
min = MINOR(dev);
if (min < 0)
return -1;
if ((IS_A_PTY_MASTER(min)) && (inode->i_count>1))
return -1;
tty = TTY_TABLE(min);
if (!(flag & O_NOCTTY) &&
current->leader &&
current->tty<0 &&
tty->session==0) {
current->tty = min;
tty->session= current->session;
tty->pgrp = current->pgrp;
}
if (flag & O_NONBLOCK) {
TTY_TABLE(min)->termios.c_cc[VMIN] =0;
TTY_TABLE(min)->termios.c_cc[VTIME] =0;
TTY_TABLE(min)->termios.c_lflag &= ~ICANON;
}
}
return 0;
}
int sys_open(const char * filename,int flag,int mode)
{
struct m_inode * inode;
......@@ -161,18 +194,12 @@ int sys_open(const char * filename,int flag,int mode)
}
/* ttys are somewhat special (ttyxx major==4, tty major==5) */
if (S_ISCHR(inode->i_mode))
if (MAJOR(inode->i_zone[0])==4) {
if (current->leader && current->tty<0) {
current->tty = MINOR(inode->i_zone[0]);
tty_table[current->tty].pgrp = current->pgrp;
}
} else if (MAJOR(inode->i_zone[0])==5)
if (current->tty<0) {
iput(inode);
current->filp[fd]=NULL;
f->f_count=0;
return -EPERM;
}
if (check_char_dev(inode,inode->i_zone[0],flag)) {
iput(inode);
current->filp[fd]=NULL;
f->f_count=0;
return -EAGAIN;
}
/* Likewise with block-devices: check for floppy_change */
if (S_ISBLK(inode->i_mode))
check_disk_change(inode->i_zone[0]);
......
......@@ -5,10 +5,13 @@
*/
#include <signal.h>
#include <errno.h>
#include <termios.h>
#include <linux/sched.h>
#include <linux/mm.h> /* for get_free_page */
#include <asm/segment.h>
#include <linux/kernel.h>
int read_pipe(struct m_inode * inode, char * buf, int count)
{
......@@ -16,10 +19,12 @@ int read_pipe(struct m_inode * inode, char * buf, int count)
while (count>0) {
while (!(size=PIPE_SIZE(*inode))) {
wake_up(&inode->i_wait);
wake_up(& PIPE_WRITE_WAIT(*inode));
if (inode->i_count != 2) /* are there any writers? */
return read;
sleep_on(&inode->i_wait);
if (current->signal & ~current->blocked)
return read?read:-ERESTARTSYS;
interruptible_sleep_on(& PIPE_READ_WAIT(*inode));
}
chars = PAGE_SIZE-PIPE_TAIL(*inode);
if (chars > count)
......@@ -34,7 +39,7 @@ int read_pipe(struct m_inode * inode, char * buf, int count)
while (chars-->0)
put_fs_byte(((char *)inode->i_size)[size++],buf++);
}
wake_up(&inode->i_wait);
wake_up(& PIPE_WRITE_WAIT(*inode));
return read;
}
......@@ -44,12 +49,12 @@ int write_pipe(struct m_inode * inode, char * buf, int count)
while (count>0) {
while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) {
wake_up(&inode->i_wait);
wake_up(& PIPE_READ_WAIT(*inode));
if (inode->i_count != 2) { /* no readers */
current->signal |= (1<<(SIGPIPE-1));
return written?written:-1;
}
sleep_on(&inode->i_wait);
sleep_on(& PIPE_WRITE_WAIT(*inode));
}
chars = PAGE_SIZE-PIPE_HEAD(*inode);
if (chars > count)
......@@ -64,7 +69,7 @@ int write_pipe(struct m_inode * inode, char * buf, int count)
while (chars-->0)
((char *)inode->i_size)[size++]=get_fs_byte(buf++);
}
wake_up(&inode->i_wait);
wake_up(& PIPE_READ_WAIT(*inode));
return written;
}
......@@ -109,3 +114,15 @@ int sys_pipe(unsigned long * fildes)
put_fs_long(fd[1],1+fildes);
return 0;
}
int pipe_ioctl(struct m_inode *pino, int cmd, int arg)
{
switch (cmd) {
case FIONREAD:
verify_area((void *) arg,4);
put_fs_long(PIPE_SIZE(*pino),(unsigned long *) arg);
return 0;
default:
return -EINVAL;
}
}
/*
* This file contains the procedures for the handling of select
*
* Created for Linux based loosely upon Mathius Lattner's minix
* patches by Peter MacDonald. Heavily edited by Linus.
*/
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/sched.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <const.h>
#include <errno.h>
#include <sys/time.h>
#include <signal.h>
/*
* Ok, Peter made a complicated, but straightforward multiple_wait() function.
* I have rewritten this, taking some shortcuts: This code may not be easy to
* follow, but it should be free of race-conditions, and it's practical. If you
* understand what I'm doing here, then you understand how the linux sleep/wakeup
* mechanism works.
*
* Two very simple procedures, add_wait() and free_wait() make all the work. We
* have to have interrupts disabled throughout the select, but that's not really
* such a loss: sleeping automatically frees interrupts when we aren't in this
* task.
*/
typedef struct {
struct task_struct * old_task;
struct task_struct ** wait_address;
} wait_entry;
typedef struct {
int nr;
wait_entry entry[NR_OPEN*3];
} select_table;
static void add_wait(struct task_struct ** wait_address, select_table * p)
{
int i;
if (!wait_address)
return;
for (i = 0 ; i < p->nr ; i++)
if (p->entry[i].wait_address == wait_address)
return;
p->entry[p->nr].wait_address = wait_address;
p->entry[p->nr].old_task = * wait_address;
*wait_address = current;
p->nr++;
}
static void free_wait(select_table * p)
{
int i;
struct task_struct ** tpp;
for (i = 0; i < p->nr ; i++) {
tpp = p->entry[i].wait_address;
while (*tpp && *tpp != current) {
(*tpp)->state = 0;
current->state = TASK_UNINTERRUPTIBLE;
schedule();
}
if (!*tpp)
printk("free_wait: NULL");
if (*tpp = p->entry[i].old_task)
(**tpp).state = 0;
}
p->nr = 0;
}
static struct tty_struct * get_tty(struct m_inode * inode)
{
int major, minor;
if (!S_ISCHR(inode->i_mode))
return NULL;
if ((major = MAJOR(inode->i_zone[0])) != 5 && major != 4)
return NULL;
if (major == 5)
minor = current->tty;
else
minor = MINOR(inode->i_zone[0]);
if (minor < 0)
return NULL;
return TTY_TABLE(minor);
}
/*
* The check_XX functions check out a file. We know it's either
* a pipe, a character device or a fifo (fifo's not implemented)
*/
static int check_in(select_table * wait, struct m_inode * inode)
{
struct tty_struct * tty;
if (tty = get_tty(inode))
if (!EMPTY(tty->secondary))
return 1;
else
add_wait(&tty->secondary->proc_list, wait);
else if (inode->i_pipe)
if (!PIPE_EMPTY(*inode))
return 1;
else
add_wait(&inode->i_wait, wait);
return 0;
}
static int check_out(select_table * wait, struct m_inode * inode)
{
struct tty_struct * tty;
if (tty = get_tty(inode))
if (!FULL(tty->write_q))
return 1;
else
add_wait(&tty->write_q->proc_list, wait);
else if (inode->i_pipe)
if (!PIPE_FULL(*inode))
return 1;
else
add_wait(&inode->i_wait, wait);
return 0;
}
static int check_ex(select_table * wait, struct m_inode * inode)
{
struct tty_struct * tty;
if (tty = get_tty(inode))
if (!FULL(tty->write_q))
return 0;
else
return 0;
else if (inode->i_pipe)
if (inode->i_count < 2)
return 1;
else
add_wait(&inode->i_wait,wait);
return 0;
}
int do_select(fd_set in, fd_set out, fd_set ex,
fd_set *inp, fd_set *outp, fd_set *exp)
{
int count;
select_table wait_table;
int i;
fd_set mask;
mask = in | out | ex;
for (i = 0 ; i < NR_OPEN ; i++,mask >>= 1) {
if (!(mask & 1))
continue;
if (!current->filp[i])
return -EBADF;
if (!current->filp[i]->f_inode)
return -EBADF;
if (current->filp[i]->f_inode->i_pipe)
continue;
if (S_ISCHR(current->filp[i]->f_inode->i_mode))
continue;
if (S_ISFIFO(current->filp[i]->f_inode->i_mode))
continue;
return -EBADF;
}
repeat:
wait_table.nr = 0;
*inp = *outp = *exp = 0;
count = 0;
mask = 1;
for (i = 0 ; i < NR_OPEN ; i++, mask += mask) {
if (mask & in)
if (check_in(&wait_table,current->filp[i]->f_inode)) {
*inp |= mask;
count++;
}
if (mask & out)
if (check_out(&wait_table,current->filp[i]->f_inode)) {
*outp |= mask;
count++;
}
if (mask & ex)
if (check_ex(&wait_table,current->filp[i]->f_inode)) {
*exp |= mask;
count++;
}
}
if (!(current->signal & ~current->blocked) &&
(wait_table.nr || current->timeout) && !count) {
current->state = TASK_INTERRUPTIBLE;
schedule();
free_wait(&wait_table);
goto repeat;
}
free_wait(&wait_table);
return count;
}
/*
* Note that we cannot return -ERESTARTSYS, as we change our input
* parameters. Sad, but there you are. We could do some tweaking in
* the library function ...
*/
int sys_select( unsigned long *buffer )
{
/* Perform the select(nd, in, out, ex, tv) system call. */
int i;
fd_set res_in, in = 0, *inp;
fd_set res_out, out = 0, *outp;
fd_set res_ex, ex = 0, *exp;
fd_set mask;
struct timeval *tvp;
unsigned long timeout;
mask = ~((~0) << get_fs_long(buffer++));
inp = (fd_set *) get_fs_long(buffer++);
outp = (fd_set *) get_fs_long(buffer++);
exp = (fd_set *) get_fs_long(buffer++);
tvp = (struct timeval *) get_fs_long(buffer);
if (inp)
in = mask & get_fs_long(inp);
if (outp)
out = mask & get_fs_long(outp);
if (exp)
ex = mask & get_fs_long(exp);
timeout = 0xffffffff;
if (tvp) {
timeout = get_fs_long((unsigned long *)&tvp->tv_usec)/(1000000/HZ);
timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ;
timeout += jiffies;
}
current->timeout = timeout;
cli();
i = do_select(in, out, ex, &res_in, &res_out, &res_ex);
if (current->timeout > jiffies)
timeout = current->timeout - jiffies;
else
timeout = 0;
sti();
current->timeout = 0;
if (i < 0)
return i;
if (inp) {
verify_area(inp, 4);
put_fs_long(res_in,inp);
}
if (outp) {
verify_area(outp,4);
put_fs_long(res_out,outp);
}
if (exp) {
verify_area(exp,4);
put_fs_long(res_ex,exp);
}
if (tvp) {
verify_area(tvp, sizeof(*tvp));
put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
timeout %= HZ;
timeout *= (1000000/HZ);
put_fs_long(timeout, (unsigned long *) &tvp->tv_usec);
}
if (!i && (current->signal & ~current->blocked))
return -EINTR;
return i;
}
......@@ -17,7 +17,7 @@ static void cp_stat(struct m_inode * inode, struct stat * statbuf)
struct stat tmp;
int i;
verify_area(statbuf,sizeof (* statbuf));
verify_area(statbuf,sizeof (struct stat));
tmp.st_dev = inode->i_dev;
tmp.st_ino = inode->i_num;
tmp.st_mode = inode->i_mode;
......@@ -30,7 +30,7 @@ static void cp_stat(struct m_inode * inode, struct stat * statbuf)
tmp.st_mtime = inode->i_mtime;
tmp.st_ctime = inode->i_ctime;
for (i=0 ; i<sizeof (tmp) ; i++)
put_fs_byte(((char *) &tmp)[i],&((char *) statbuf)[i]);
put_fs_byte(((char *) &tmp)[i],i + (char *) statbuf);
}
int sys_stat(char * filename, struct stat * statbuf)
......@@ -44,6 +44,17 @@ int sys_stat(char * filename, struct stat * statbuf)
return 0;
}
int sys_lstat(char * filename, struct stat * statbuf)
{
struct m_inode * inode;
if (!(inode = lnamei(filename)))
return -ENOENT;
cp_stat(inode,statbuf);
iput(inode);
return 0;
}
int sys_fstat(unsigned int fd, struct stat * statbuf)
{
struct file * f;
......@@ -54,3 +65,33 @@ int sys_fstat(unsigned int fd, struct stat * statbuf)
cp_stat(inode,statbuf);
return 0;
}
int sys_readlink(const char * path, char * buf, int bufsiz)
{
struct m_inode * inode;
struct buffer_head * bh;
int i;
char c;
if (bufsiz <= 0)
return -EBADF;
if (bufsiz > 1023)
bufsiz = 1023;
verify_area(buf,bufsiz);
if (!(inode = lnamei(path)))
return -ENOENT;
if (inode->i_zone[0])
bh = bread(inode->i_dev, inode->i_zone[0]);
else
bh = NULL;
iput(inode);
if (!bh)
return 0;
i = 0;
while (i<bufsiz && (c = bh->b_data[i])) {
i++;
put_fs_byte(c,buf++);
}
brelse(bh);
return i;
}
......@@ -74,7 +74,6 @@ struct super_block * get_super(int dev)
void put_super(int dev)
{
struct super_block * sb;
struct m_inode * inode;
int i;
if (dev == ROOT_DEV) {
......
......@@ -8,58 +8,92 @@
#include <sys/stat.h>
static void free_ind(int dev,int block)
static int free_ind(int dev,int block)
{
struct buffer_head * bh;
unsigned short * p;
int i;
int block_busy;
if (!block)
return;
return 1;
block_busy = 0;
if (bh=bread(dev,block)) {
p = (unsigned short *) bh->b_data;
for (i=0;i<512;i++,p++)
if (*p)
free_block(dev,*p);
if (free_block(dev,*p)) {
*p = 0;
bh->b_dirt = 1;
} else
block_busy = 1;
brelse(bh);
}
free_block(dev,block);
if (block_busy)
return 0;
else
return free_block(dev,block);
}
static void free_dind(int dev,int block)
static int free_dind(int dev,int block)
{
struct buffer_head * bh;
unsigned short * p;
int i;
int block_busy;
if (!block)
return;
return 1;
block_busy = 0;
if (bh=bread(dev,block)) {
p = (unsigned short *) bh->b_data;
for (i=0;i<512;i++,p++)
if (*p)
free_ind(dev,*p);
if (free_ind(dev,*p)) {
*p = 0;
bh->b_dirt = 1;
} else
block_busy = 1;
brelse(bh);
}
free_block(dev,block);
if (block_busy)
return 0;
else
return free_block(dev,block);
}
void truncate(struct m_inode * inode)
{
int i;
int block_busy;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return;
repeat:
block_busy = 0;
for (i=0;i<7;i++)
if (inode->i_zone[i]) {
free_block(inode->i_dev,inode->i_zone[i]);
inode->i_zone[i]=0;
if (free_block(inode->i_dev,inode->i_zone[i]))
inode->i_zone[i]=0;
else
block_busy = 1;
}
free_ind(inode->i_dev,inode->i_zone[7]);
free_dind(inode->i_dev,inode->i_zone[8]);
inode->i_zone[7] = inode->i_zone[8] = 0;
inode->i_size = 0;
if (free_ind(inode->i_dev,inode->i_zone[7]))
inode->i_zone[7] = 0;
else
block_busy = 1;
if (free_dind(inode->i_dev,inode->i_zone[8]))
inode->i_zone[8] = 0;
else
block_busy = 1;
inode->i_dirt = 1;
if (block_busy) {
current->counter = 0;
schedule();
goto repeat;
}
inode->i_size = 0;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
}
......@@ -7,10 +7,10 @@ __asm__ ("movl %%esp,%%eax\n\t" \
"pushl $1f\n\t" \
"iret\n" \
"1:\tmovl $0x17,%%eax\n\t" \
"movw %%ax,%%ds\n\t" \
"movw %%ax,%%es\n\t" \
"movw %%ax,%%fs\n\t" \
"movw %%ax,%%gs" \
"mov %%ax,%%ds\n\t" \
"mov %%ax,%%es\n\t" \
"mov %%ax,%%fs\n\t" \
"mov %%ax,%%gs" \
:::"ax")
#define sti() __asm__ ("sti"::)
......
......@@ -57,4 +57,8 @@ extern int errno;
#define ENOSYS 38
#define ENOTEMPTY 39
/* Should never be seen by user programs */
#define ERESTARTSYS 512
#define ERESTARTNOINTR 513
#endif
#ifndef _CONFIG_H
#define _CONFIG_H
/*
* Defines for what uname() should return
*/
#define UTS_SYSNAME "Linux"
#define UTS_NODENAME "(none)" /* set by sethostname() */
#define UTS_RELEASE "0" /* patchlevel */
#define UTS_VERSION "0.12"
#define UTS_MACHINE "i386" /* hardware type */
/* Don't touch these, unless you really know what your doing. */
#define DEF_INITSEG 0x9000
#define DEF_SYSSEG 0x1000
#define DEF_SETUPSEG 0x9020
#define DEF_SYSSIZE 0x3000
/*
* 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
*/
/*
* define your keyboard here -
* KBD_FINNISH for Finnish keyboards
* KBD_US for US-type
* KBD_GR for German keyboards
* KBD_FR for Frech keyboard
* The keyboard is now defined in kernel/chr_dev/keyboard.S
*/
/*#define KBD_US */
/*#define KBD_GR */
/*#define KBD_FR */
#define KBD_FINNISH
/*
* Normally, Linux can get the drive parameters from the BIOS at
......
......@@ -41,7 +41,7 @@ void buffer_init(long buffer_end);
#define SUPER_MAGIC 0x137F
#define NR_OPEN 20
#define NR_INODE 32
#define NR_INODE 64
#define NR_FILE 64
#define NR_SUPER 8
#define NR_HASH 307
......@@ -55,13 +55,18 @@ void buffer_init(long buffer_end);
#define INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct d_inode)))
#define DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct dir_entry)))
#define PIPE_READ_WAIT(inode) ((inode).i_wait)
#define PIPE_WRITE_WAIT(inode) ((inode).i_wait2)
#define PIPE_HEAD(inode) ((inode).i_zone[0])
#define PIPE_TAIL(inode) ((inode).i_zone[1])
#define PIPE_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))
#define NIL_FILP ((struct file *)0)
#define SEL_IN 1
#define SEL_OUT 2
#define SEL_EX 4
typedef char buffer_block[BLOCK_SIZE];
......@@ -100,6 +105,7 @@ struct m_inode {
unsigned short i_zone[9];
/* these are in memory also */
struct task_struct * i_wait;
struct task_struct * i_wait2; /* for pipes */
unsigned long i_atime;
unsigned long i_ctime;
unsigned short i_dev;
......@@ -176,6 +182,7 @@ extern void wait_on(struct m_inode * inode);
extern int bmap(struct m_inode * inode,int block);
extern int create_block(struct m_inode * inode,int block);
extern struct m_inode * namei(const char * pathname);
extern struct m_inode * lnamei(const char * pathname);
extern int open_namei(const char * pathname, int flag, int mode,
struct m_inode ** res_inode);
extern void iput(struct m_inode * inode);
......@@ -185,12 +192,13 @@ extern struct m_inode * get_pipe_inode(void);
extern struct buffer_head * get_hash_table(int dev, int block);
extern struct buffer_head * getblk(int dev, int block);
extern void ll_rw_block(int rw, struct buffer_head * bh);
extern void ll_rw_page(int rw, int dev, int nr, char * buffer);
extern void brelse(struct buffer_head * buf);
extern struct buffer_head * bread(int dev,int block);
extern void bread_page(unsigned long addr,int dev,int b[4]);
extern struct buffer_head * breada(int dev,int block,...);
extern int new_block(int dev);
extern void free_block(int dev, int block);
extern int free_block(int dev, int block);
extern struct m_inode * new_inode(int dev);
extern void free_inode(struct m_inode * inode);
extern int sync_dev(int dev);
......
......@@ -3,11 +3,22 @@
*/
void verify_area(void * addr,int count);
volatile void panic(const char * str);
volatile void do_exit(long error_code);
int printf(const char * fmt, ...);
int printk(const char * fmt, ...);
void console_print(const char * str);
int tty_write(unsigned ch,char * buf,int count);
void * malloc(unsigned int size);
void free_s(void * obj, int size);
extern void hd_times_out(void);
extern void sysbeepstop(void);
extern void blank_screen(void);
extern void unblank_screen(void);
extern int beepcount;
extern int hd_timeout;
extern int blankinterval;
extern int blankcount;
#define free(x) free_s((x), 0)
......
/*
* linux/include/linux/math_emu.h
*
* (C) 1991 Linus Torvalds
*/
#ifndef _LINUX_MATH_EMU_H
#define _LINUX_MATH_EMU_H
#include <linux/sched.h>
struct info {
long ___math_ret;
long ___orig_eip;
long ___edi;
long ___esi;
long ___ebp;
long ___sys_call_ret;
long ___eax;
long ___ebx;
long ___ecx;
long ___edx;
long ___orig_eax;
long ___fs;
long ___es;
long ___ds;
long ___eip;
long ___cs;
long ___eflags;
long ___esp;
long ___ss;
};
#define EAX (info->___eax)
#define EBX (info->___ebx)
#define ECX (info->___ecx)
#define EDX (info->___edx)
#define ESI (info->___esi)
#define EDI (info->___edi)
#define EBP (info->___ebp)
#define ESP (info->___esp)
#define EIP (info->___eip)
#define ORIG_EIP (info->___orig_eip)
#define EFLAGS (info->___eflags)
#define DS (*(unsigned short *) &(info->___ds))
#define ES (*(unsigned short *) &(info->___es))
#define FS (*(unsigned short *) &(info->___fs))
#define CS (*(unsigned short *) &(info->___cs))
#define SS (*(unsigned short *) &(info->___ss))
void __math_abort(struct info *, unsigned int);
#define math_abort(x,y) \
(((volatile void (*)(struct info *,unsigned int)) __math_abort)((x),(y)))
/*
* Gcc forces this stupid alignment problem: I want to use only two longs
* for the temporary real 64-bit mantissa, but then gcc aligns out the
* structure to 12 bytes which breaks things in math_emulate.c. Shit. I
* want some kind of "no-alignt" pragma or something.
*/
typedef struct {
long a,b;
short exponent;
} temp_real;
typedef struct {
short m0,m1,m2,m3;
short exponent;
} temp_real_unaligned;
#define real_to_real(a,b) \
((*(long long *) (b) = *(long long *) (a)),((b)->exponent = (a)->exponent))
typedef struct {
long a,b;
} long_real;
typedef long short_real;
typedef struct {
long a,b;
short sign;
} temp_int;
struct swd {
int ie:1;
int de:1;
int ze:1;
int oe:1;
int ue:1;
int pe:1;
int sf:1;
int ir:1;
int c0:1;
int c1:1;
int c2:1;
int top:3;
int c3:1;
int b:1;
};
#define I387 (current->tss.i387)
#define SWD (*(struct swd *) &I387.swd)
#define ROUNDING ((I387.cwd >> 10) & 3)
#define PRECISION ((I387.cwd >> 8) & 3)
#define BITS24 0
#define BITS53 2
#define BITS64 3
#define ROUND_NEAREST 0
#define ROUND_DOWN 1
#define ROUND_UP 2
#define ROUND_0 3
#define CONSTZ (temp_real_unaligned) {0x0000,0x0000,0x0000,0x0000,0x0000}
#define CONST1 (temp_real_unaligned) {0x0000,0x0000,0x0000,0x8000,0x3FFF}
#define CONSTPI (temp_real_unaligned) {0xC235,0x2168,0xDAA2,0xC90F,0x4000}
#define CONSTLN2 (temp_real_unaligned) {0x79AC,0xD1CF,0x17F7,0xB172,0x3FFE}
#define CONSTLG2 (temp_real_unaligned) {0xF799,0xFBCF,0x9A84,0x9A20,0x3FFD}
#define CONSTL2E (temp_real_unaligned) {0xF0BC,0x5C17,0x3B29,0xB8AA,0x3FFF}
#define CONSTL2T (temp_real_unaligned) {0x8AFE,0xCD1B,0x784B,0xD49A,0x4000}
#define set_IE() (I387.swd |= 1)
#define set_DE() (I387.swd |= 2)
#define set_ZE() (I387.swd |= 4)
#define set_OE() (I387.swd |= 8)
#define set_UE() (I387.swd |= 16)
#define set_PE() (I387.swd |= 32)
#define set_C0() (I387.swd |= 0x0100)
#define set_C1() (I387.swd |= 0x0200)
#define set_C2() (I387.swd |= 0x0400)
#define set_C3() (I387.swd |= 0x4000)
/* ea.c */
char * ea(struct info * __info, unsigned short __code);
/* convert.c */
void short_to_temp(const short_real * __a, temp_real * __b);
void long_to_temp(const long_real * __a, temp_real * __b);
void temp_to_short(const temp_real * __a, short_real * __b);
void temp_to_long(const temp_real * __a, long_real * __b);
void real_to_int(const temp_real * __a, temp_int * __b);
void int_to_real(const temp_int * __a, temp_real * __b);
/* get_put.c */
void get_short_real(temp_real *, struct info *, unsigned short);
void get_long_real(temp_real *, struct info *, unsigned short);
void get_temp_real(temp_real *, struct info *, unsigned short);
void get_short_int(temp_real *, struct info *, unsigned short);
void get_long_int(temp_real *, struct info *, unsigned short);
void get_longlong_int(temp_real *, struct info *, unsigned short);
void get_BCD(temp_real *, struct info *, unsigned short);
void put_short_real(const temp_real *, struct info *, unsigned short);
void put_long_real(const temp_real *, struct info *, unsigned short);
void put_temp_real(const temp_real *, struct info *, unsigned short);
void put_short_int(const temp_real *, struct info *, unsigned short);
void put_long_int(const temp_real *, struct info *, unsigned short);
void put_longlong_int(const temp_real *, struct info *, unsigned short);
void put_BCD(const temp_real *, struct info *, unsigned short);
/* add.c */
void fadd(const temp_real *, const temp_real *, temp_real *);
/* mul.c */
void fmul(const temp_real *, const temp_real *, temp_real *);
/* div.c */
void fdiv(const temp_real *, const temp_real *, temp_real *);
/* compare.c */
void fcom(const temp_real *, const temp_real *);
void fucom(const temp_real *, const temp_real *);
void ftst(const temp_real *);
#endif
......@@ -3,8 +3,43 @@
#define PAGE_SIZE 4096
#include <linux/kernel.h>
#include <signal.h>
extern int SWAP_DEV;
#define read_swap_page(nr,buffer) ll_rw_page(READ,SWAP_DEV,(nr),(buffer));
#define write_swap_page(nr,buffer) ll_rw_page(WRITE,SWAP_DEV,(nr),(buffer));
extern unsigned long get_free_page(void);
extern unsigned long put_page(unsigned long page,unsigned long address);
extern unsigned long put_dirty_page(unsigned long page,unsigned long address);
extern void free_page(unsigned long addr);
void swap_free(int page_nr);
void swap_in(unsigned long *table_ptr);
extern inline volatile void oom(void)
{
printk("out of memory\n\r");
do_exit(SIGSEGV);
}
#define invalidate() \
__asm__("movl %%eax,%%cr3"::"a" (0))
/* these are not to be changed without changing head.s etc */
#define LOW_MEM 0x100000
extern unsigned long HIGH_MEMORY;
#define PAGING_MEMORY (15*1024*1024)
#define PAGING_PAGES (PAGING_MEMORY>>12)
#define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
#define USED 100
extern unsigned char mem_map [ PAGING_PAGES ];
#define PAGE_DIRTY 0x40
#define PAGE_ACCESSED 0x20
#define PAGE_USER 0x04
#define PAGE_RW 0x02
#define PAGE_PRESENT 0x01
#endif
#ifndef _SCHED_H
#define _SCHED_H
#define NR_TASKS 64
#define HZ 100
#define NR_TASKS 64
#define TASK_SIZE 0x04000000
#define LIBRARY_SIZE 0x00400000
#if (TASK_SIZE & 0x3fffff)
#error "TASK_SIZE must be multiple of 4M"
#endif
#if (LIBRARY_SIZE & 0x3fffff)
#error "LIBRARY_SIZE must be a multiple of 4M"
#endif
#if (LIBRARY_SIZE >= (TASK_SIZE/2))
#error "LIBRARY_SIZE too damn big!"
#endif
#if (((TASK_SIZE>>16)*NR_TASKS) != 0x10000)
#error "TASK_SIZE*NR_TASKS must be 4GB"
#endif
#define LIBRARY_OFFSET (TASK_SIZE - LIBRARY_SIZE)
#define CT_TO_SECS(x) ((x) / HZ)
#define CT_TO_USECS(x) (((x) % HZ) * 1000000/HZ)
#define FIRST_TASK task[0]
#define LAST_TASK task[NR_TASKS-1]
#include <linux/head.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
#if (NR_OPEN > 32)
#error "Currently the close-on-exec-flags are in one word, max 32 files/proc"
#error "Currently the close-on-exec-flags and select masks are in one long, max 32 files/proc"
#endif
#define TASK_RUNNING 0
......@@ -86,11 +113,20 @@ struct task_struct {
/* various fields */
int exit_code;
unsigned long start_code,end_code,end_data,brk,start_stack;
long pid,father,pgrp,session,leader;
long pid,pgrp,session,leader;
int groups[NGROUPS];
/*
* pointers to parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
* p->p_pptr->pid)
*/
struct task_struct *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
unsigned short uid,euid,suid;
unsigned short gid,egid,sgid;
long alarm;
unsigned long timeout,alarm;
long utime,stime,cutime,cstime,start_time;
struct rlimit rlim[RLIM_NLIMITS];
unsigned int flags; /* per process flags, defined below */
unsigned short used_math;
/* file system info */
int tty; /* -1 if no tty, so it must be signed */
......@@ -98,6 +134,7 @@ struct task_struct {
struct m_inode * pwd;
struct m_inode * root;
struct m_inode * executable;
struct m_inode * library;
unsigned long close_on_exec;
struct file * filp[NR_OPEN];
/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
......@@ -106,6 +143,12 @@ struct task_struct {
struct tss_struct tss;
};
/*
* Per process flags
*/
#define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */
/* Not implemented yet, only for 486*/
/*
* INIT_TASK is used to set up the first task table, touch at
* your own risk!. Base=0, limit=0x9ffff (=640kB)
......@@ -114,11 +157,17 @@ struct task_struct {
/* state etc */ { 0,15,15, \
/* signals */ 0,{{},},0, \
/* ec,brk... */ 0,0,0,0,0,0, \
/* pid etc.. */ 0,-1,0,0,0, \
/* pid etc.. */ 0,0,0,0, \
/* suppl grps*/ {NOGROUP,}, \
/* proc links*/ &init_task.task,0,0,0, \
/* uid etc */ 0,0,0,0,0,0, \
/* alarm */ 0,0,0,0,0,0, \
/* timeout */ 0,0,0,0,0,0,0, \
/* rlimits */ { {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \
{0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \
{0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}}, \
/* flags */ 0, \
/* math */ 0, \
/* fs info */ -1,0022,NULL,NULL,NULL,0, \
/* fs info */ -1,0022,NULL,NULL,NULL,NULL,0, \
/* filp */ {NULL,}, \
{ \
{0,0}, \
......@@ -136,15 +185,17 @@ struct task_struct {
extern struct task_struct *task[NR_TASKS];
extern struct task_struct *last_task_used_math;
extern struct task_struct *current;
extern long volatile jiffies;
extern long startup_time;
extern unsigned long volatile jiffies;
extern unsigned long startup_time;
extern int jiffies_offset;
#define CURRENT_TIME (startup_time+jiffies/HZ)
#define CURRENT_TIME (startup_time+(jiffies+jiffies_offset)/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);
extern int in_group_p(gid_t grp);
/*
* Entry into gdt where to find first TSS. 0-nul, 1-cs, 2-ds, 3-syscall
......
/*
* Why isn't this a .c file? Enquiring minds....
*/
extern int sys_setup();
extern int sys_exit();
extern int sys_fork();
......@@ -70,6 +74,21 @@ extern int sys_sgetmask();
extern int sys_ssetmask();
extern int sys_setreuid();
extern int sys_setregid();
extern int sys_sigpending();
extern int sys_sigsuspend();
extern int sys_sethostname();
extern int sys_setrlimit();
extern int sys_getrlimit();
extern int sys_getrusage();
extern int sys_gettimeofday();
extern int sys_settimeofday();
extern int sys_getgroups();
extern int sys_setgroups();
extern int sys_select();
extern int sys_symlink();
extern int sys_lstat();
extern int sys_readlink();
extern int sys_uselib();
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,
......@@ -83,4 +102,10 @@ sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
sys_setreuid,sys_setregid };
sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending, sys_sethostname,
sys_setrlimit, sys_getrlimit, sys_getrusage, sys_gettimeofday,
sys_settimeofday, sys_getgroups, sys_setgroups, sys_select, sys_symlink,
sys_lstat, sys_readlink, sys_uselib };
/* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
......@@ -9,6 +9,12 @@
#ifndef _TTY_H
#define _TTY_H
#define MAX_CONSOLES 8
#define NR_SERIALS 2
#define NR_PTYS 4
extern int NR_CONSOLES;
#include <termios.h>
#define TTY_BUF_SIZE 1024
......@@ -21,17 +27,24 @@ struct tty_queue {
char buf[TTY_BUF_SIZE];
};
#define IS_A_CONSOLE(min) (((min) & 0xC0) == 0x00)
#define IS_A_SERIAL(min) (((min) & 0xC0) == 0x40)
#define IS_A_PTY(min) ((min) & 0x80)
#define IS_A_PTY_MASTER(min) (((min) & 0xC0) == 0x80)
#define IS_A_PTY_SLAVE(min) (((min) & 0xC0) == 0xC0)
#define PTY_OTHER(min) ((min) ^ 0x40)
#define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1))
#define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1))
#define EMPTY(a) ((a).head == (a).tail)
#define LEFT(a) (((a).tail-(a).head-1)&(TTY_BUF_SIZE-1))
#define LAST(a) ((a).buf[(TTY_BUF_SIZE-1)&((a).head-1)])
#define EMPTY(a) ((a)->head == (a)->tail)
#define LEFT(a) (((a)->tail-(a)->head-1)&(TTY_BUF_SIZE-1))
#define LAST(a) ((a)->buf[(TTY_BUF_SIZE-1)&((a)->head-1)])
#define FULL(a) (!LEFT(a))
#define CHARS(a) (((a).head-(a).tail)&(TTY_BUF_SIZE-1))
#define CHARS(a) (((a)->head-(a)->tail)&(TTY_BUF_SIZE-1))
#define GETCH(queue,c) \
(void)({c=(queue).buf[(queue).tail];INC((queue).tail);})
(void)({c=(queue)->buf[(queue)->tail];INC((queue)->tail);})
#define PUTCH(c,queue) \
(void)({(queue).buf[(queue).head]=(c);INC((queue).head);})
(void)({(queue)->buf[(queue)->head]=(c);INC((queue)->head);})
#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR])
#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT])
......@@ -45,14 +58,19 @@ struct tty_queue {
struct tty_struct {
struct termios termios;
int pgrp;
int session;
int stopped;
void (*write)(struct tty_struct * tty);
struct tty_queue read_q;
struct tty_queue write_q;
struct tty_queue secondary;
struct tty_queue *read_q;
struct tty_queue *write_q;
struct tty_queue *secondary;
};
extern struct tty_struct tty_table[];
extern int fg_console;
#define TTY_TABLE(nr) \
(tty_table + ((nr) ? (((nr) < 64)? (nr)-1:(nr)) : fg_console))
/* intr=^C quit=^| erase=del kill=^U
eof=^D vtime=\0 vmin=\1 sxtc=\0
......@@ -69,9 +87,13 @@ void tty_init(void);
int tty_read(unsigned c, char * buf, int n);
int tty_write(unsigned c, char * buf, int n);
void rs_write(struct tty_struct * tty);
void con_write(struct tty_struct * tty);
void rs_write(struct tty_struct * tty);
void mpty_write(struct tty_struct * tty);
void spty_write(struct tty_struct * tty);
void copy_to_cooked(struct tty_struct * tty);
void update_screen(void);
#endif
......@@ -35,6 +35,7 @@ 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_INTERRUPT 0x20000000
#define SA_NOMASK 0x40000000
#define SA_ONESHOT 0x80000000
......@@ -44,6 +45,12 @@ typedef unsigned int sigset_t; /* 32 bits */
#define SIG_DFL ((void (*)(int))0) /* default signal handling */
#define SIG_IGN ((void (*)(int))1) /* ignore signal */
#define SIG_ERR ((void (*)(int))-1) /* error return from signal */
#ifdef notdef
#define sigemptyset(mask) ((*(mask) = 0), 1)
#define sigfillset(mask) ((*(mask) = ~0), 1)
#endif
struct sigaction {
void (*sa_handler)(int);
......
......@@ -15,5 +15,4 @@ typedef unsigned long size_t;
#define NULL ((void *)0)
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#ifndef _SYS_PARAM_H
#define _SYS_PARAM_H
#define HZ 100
#define EXEC_PAGESIZE 4096
#define NGROUPS 32 /* Max number of groups per user */
#define NOGROUP -1
#define MAXHOSTNAMELEN 8
#endif
/*
* Resource control/accounting header file for linux
*/
#ifndef _SYS_RESOURCE_H
#define _SYS_RESOURCE_H
/*
* Definition of struct rusage taken from BSD 4.3 Reno
*
* We don't support all of these yet, but we might as well have them....
* Otherwise, each time we add new items, programs which depend on this
* structure will lose. This reduces the chances of that happening.
*/
#define RUSAGE_SELF 0
#define RUSAGE_CHILDREN -1
struct rusage {
struct timeval ru_utime; /* user time used */
struct timeval ru_stime; /* system time used */
long ru_maxrss; /* maximum resident set size */
long ru_ixrss; /* integral shared memory size */
long ru_idrss; /* integral unshared data size */
long ru_isrss; /* integral unshared stack size */
long ru_minflt; /* page reclaims */
long ru_majflt; /* page faults */
long ru_nswap; /* swaps */
long ru_inblock; /* block input operations */
long ru_oublock; /* block output operations */
long ru_msgsnd; /* messages sent */
long ru_msgrcv; /* messages received */
long ru_nsignals; /* signals received */
long ru_nvcsw; /* voluntary context switches */
long ru_nivcsw; /* involuntary " */
};
/*
* Resource limits
*/
#define RLIMIT_CPU 0 /* CPU time in ms */
#define RLIMIT_FSIZE 1 /* Maximum filesize */
#define RLIMIT_DATA 2 /* max data size */
#define RLIMIT_STACK 3 /* max stack size */
#define RLIMIT_CORE 4 /* max core file size */
#define RLIMIT_RSS 5 /* max resident set size */
#ifdef notdef
#define RLIMIT_MEMLOCK 6 /* max locked-in-memory address space*/
#define RLIMIT_NPROC 7 /* max number of processes */
#define RLIMIT_OFILE 8 /* max number of open files */
#endif
#define RLIM_NLIMITS 6
#define RLIM_INFINITY 0x7fffffff
struct rlimit {
int rlim_cur;
int rlim_max;
};
#endif /* _SYS_RESOURCE_H */
......@@ -18,6 +18,7 @@ struct stat {
};
#define S_IFMT 00170000
#define S_IFLNK 0120000
#define S_IFREG 0100000
#define S_IFBLK 0060000
#define S_IFDIR 0040000
......@@ -27,6 +28,7 @@ struct stat {
#define S_ISGID 0002000
#define S_ISVTX 0001000
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
......
#ifndef _SYS_TIME_H
#define _SYS_TIME_H
/* gettimofday returns this */
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
struct timezone {
int tz_minuteswest; /* minutes west of Greenwich */
int tz_dsttime; /* type of dst correction */
};
#define DST_NONE 0 /* not on dst */
#define DST_USA 1 /* USA style dst */
#define DST_AUST 2 /* Australian style dst */
#define DST_WET 3 /* Western European dst */
#define DST_MET 4 /* Middle European dst */
#define DST_EET 5 /* Eastern European dst */
#define DST_CAN 6 /* Canada */
#define DST_GB 7 /* Great Britain and Eire */
#define DST_RUM 8 /* Rumania */
#define DST_TUR 9 /* Turkey */
#define DST_AUSTALT 10 /* Australian style with shift in 1986 */
#define FD_SET(fd,fdsetp) (*(fdsetp) |= (1 << (fd)))
#define FD_CLR(fd,fdsetp) (*(fdsetp) &= ~(1 << (fd)))
#define FD_ISSET(fd,fdsetp) ((*(fdsetp) >> fd) & 1)
#define FD_ZERO(fdsetp) (*(fdsetp) = 0)
/*
* Operations on timevals.
*
* NB: timercmp does not work for >= or <=.
*/
#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
#define timercmp(tvp, uvp, cmp) \
((tvp)->tv_sec cmp (uvp)->tv_sec || \
(tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec)
#define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
/*
* Names of the interval timers, and structure
* defining a timer setting.
*/
#define ITIMER_REAL 0
#define ITIMER_VIRTUAL 1
#define ITIMER_PROF 2
struct itimerval {
struct timeval it_interval; /* timer interval */
struct timeval it_value; /* current value */
};
#include <time.h>
#include <sys/types.h>
int gettimeofday(struct timeval * tp, struct timezone * tz);
int select(int width, fd_set * readfds, fd_set * writefds,
fd_set * exceptfds, struct timeval * timeout);
#endif /*_SYS_TIME_H*/
......@@ -22,7 +22,7 @@ typedef long ptrdiff_t;
typedef int pid_t;
typedef unsigned short uid_t;
typedef unsigned char gid_t;
typedef unsigned short gid_t;
typedef unsigned short dev_t;
typedef unsigned short ino_t;
typedef unsigned short mode_t;
......@@ -33,6 +33,12 @@ typedef long off_t;
typedef unsigned char u_char;
typedef unsigned short ushort;
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned long tcflag_t;
typedef unsigned long fd_set;
typedef struct { int quot,rem; } div_t;
typedef struct { long quot,rem; } ldiv_t;
......
......@@ -2,10 +2,11 @@
#define _SYS_UTSNAME_H
#include <sys/types.h>
#include <sys/param.h>
struct utsname {
char sysname[9];
char nodename[9];
char nodename[MAXHOSTNAMELEN+1];
char release[9];
char version[9];
char machine[9];
......
......@@ -10,10 +10,11 @@
#define WNOHANG 1
#define WUNTRACED 2
#define WIFEXITED(s) (!((s)&0xFF)
#define WIFEXITED(s) (!((s)&0xFF))
#define WIFSTOPPED(s) (((s)&0xFF)==0x7F)
#define WEXITSTATUS(s) (((s)>>8)&0xFF)
#define WTERMSIG(s) ((s)&0x7F)
#define WCOREDUMP(s) ((s)&0x80)
#define WSTOPSIG(s) (((s)>>8)&0xFF)
#define WIFSIGNALED(s) (((unsigned int)(s)-1 & 0xFFFF) < 0xFF)
......
#ifndef _TERMIOS_H
#define _TERMIOS_H
#include <sys/types.h>
#define TTY_BUF_SIZE 1024
/* 0x54 is just a magic number to make these relatively uniqe ('T') */
......@@ -31,7 +33,8 @@
#define TIOCMSET 0x5418
#define TIOCGSOFTCAR 0x5419
#define TIOCSSOFTCAR 0x541A
#define TIOCINQ 0x541B
#define FIONREAD 0x541B
#define TIOCINQ FIONREAD
struct winsize {
unsigned short ws_row;
......@@ -52,12 +55,12 @@ struct termio {
#define NCCS 17
struct termios {
unsigned long c_iflag; /* input mode flags */
unsigned long c_oflag; /* output mode flags */
unsigned long c_cflag; /* control mode flags */
unsigned long c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[NCCS]; /* control characters */
tcflag_t c_iflag; /* input mode flags */
tcflag_t c_oflag; /* output mode flags */
tcflag_t c_cflag; /* control mode flags */
tcflag_t c_lflag; /* local mode flags */
cc_t c_line; /* line discipline */
cc_t c_cc[NCCS]; /* control characters */
};
/* c_cc characters */
......@@ -155,16 +158,13 @@ struct termios {
#define CS8 0000060
#define CSTOPB 0000100
#define CREAD 0000200
#define CPARENB 0000400
#define CPARODD 0001000
#define PARENB 0000400
#define PARODD 0001000
#define HUPCL 0002000
#define CLOCAL 0004000
#define CIBAUD 03600000 /* input baud rate (not used) */
#define CRTSCTS 020000000000 /* flow control */
#define PARENB CPARENB
#define PARODD CPARODD
/* c_lflag bits */
#define ISIG 0000001
#define ICANON 0000002
......@@ -211,8 +211,6 @@ struct termios {
#define TCSADRAIN 1
#define TCSAFLUSH 2
typedef int speed_t;
extern speed_t cfgetispeed(struct termios *termios_p);
extern speed_t cfgetospeed(struct termios *termios_p);
extern int cfsetispeed(struct termios *termios_p, speed_t speed);
......
......@@ -11,6 +11,10 @@ typedef long time_t;
typedef unsigned int size_t;
#endif
#ifndef NULL
#define NULL ((void *) 0)
#endif
#define CLOCKS_PER_SEC 100
typedef long clock_t;
......@@ -27,6 +31,9 @@ struct tm {
int tm_isdst;
};
#define __isleap(year) \
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 1000 == 0))
clock_t clock(void);
time_t time(time_t * tp);
double difftime(time_t time2, time_t time1);
......
......@@ -7,8 +7,8 @@
#define _POSIX_CHOWN_RESTRICTED /* only root can do a chown (I think..) */
#define _POSIX_NO_TRUNC /* no pathname truncation (but see in kernel) */
#define _POSIX_VDISABLE '\0' /* character to disable things like ^C */
/*#define _POSIX_SAVED_IDS */ /* we'll get to this yet */
/*#define _POSIX_JOB_CONTROL */ /* we aren't there quite yet. Soon hopefully */
#define _POSIX_JOB_CONTROL
#define _POSIX_SAVED_IDS /* Implemented, for whatever good it is */
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
......@@ -51,8 +51,10 @@
#define _PC_CHOWN_RESTRICTED 9
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/utsname.h>
#include <sys/resource.h>
#include <utime.h>
#ifdef __LIBRARY__
......@@ -129,6 +131,21 @@
#define __NR_ssetmask 69
#define __NR_setreuid 70
#define __NR_setregid 71
#define __NR_sigsuspend 72
#define __NR_sigpending 73
#define __NR_sethostname 74
#define __NR_setrlimit 75
#define __NR_getrlimit 76
#define __NR_getrusage 77
#define __NR_gettimeofday 78
#define __NR_settimeofday 79
#define __NR_getgroups 80
#define __NR_setgroups 81
#define __NR_select 82
#define __NR_symlink 83
#define __NR_lstat 84
#define __NR_readlink 85
#define __NR_uselib 86
#define _syscall0(type,name) \
type name(void) \
......@@ -249,5 +266,15 @@ int dup2(int oldfd, int newfd);
int getppid(void);
pid_t getpgrp(void);
pid_t setsid(void);
int sethostname(char *name, int len);
int setrlimit(int resource, struct rlimit *rlp);
int getrlimit(int resource, struct rlimit *rlp);
int getrusage(int who, struct rusage *rusage);
int gettimeofday(struct timeval *tv, struct timezone *tz);
int settimeofday(struct timeval *tv, struct timezone *tz);
int getgroups(int gidsetlen, gid_t *gidset);
int setgroups(int gidsetlen, gid_t *gidset);
int select(int width, fd_set * readfds, fd_set * writefds,
fd_set * exceptfds, struct timeval * timeout);
#endif
......@@ -39,8 +39,11 @@ static inline _syscall0(int,sync)
#include <linux/fs.h>
#include <string.h>
static char printbuf[1024];
extern char *strcpy();
extern int vsprintf();
extern void init(void);
extern void blk_dev_init(void);
......@@ -50,14 +53,27 @@ extern void floppy_init(void);
extern void mem_init(long start, long end);
extern long rd_init(long mem_start, int length);
extern long kernel_mktime(struct tm * tm);
extern long startup_time;
static int sprintf(char * str, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i = vsprintf(str, fmt, args);
va_end(args);
return i;
}
/*
* This is set up by the setup-routine at boot-time
*/
#define EXT_MEM_K (*(unsigned short *)0x90002)
#define CON_ROWS ((*(unsigned short *)0x9000e) & 0xff)
#define CON_COLS (((*(unsigned short *)0x9000e) & 0xff00) >> 8)
#define DRIVE_INFO (*(struct drive_info *)0x90080)
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
#define ORIG_SWAP_DEV (*(unsigned short *)0x901FA)
/*
* Yeah, yeah, it's ugly, but I cannot find how to do this correctly
......@@ -98,6 +114,13 @@ static void time_init(void)
static long memory_end = 0;
static long buffer_memory_end = 0;
static long main_memory_start = 0;
static char term[32];
static char * argv_rc[] = { "/bin/sh", NULL };
static char * envp_rc[] = { "HOME=/", NULL ,NULL };
static char * argv[] = { "-/bin/sh",NULL };
static char * envp[] = { "HOME=/usr/root", NULL, NULL };
struct drive_info { char dummy[32]; } drive_info;
......@@ -108,6 +131,10 @@ void main(void) /* This really IS void, no error here. */
* enable them
*/
ROOT_DEV = ORIG_ROOT_DEV;
SWAP_DEV = ORIG_SWAP_DEV;
sprintf(term, "TERM=con%dx%d", CON_COLS, CON_ROWS);
envp[1] = term;
envp_rc[1] = term;
drive_info = DRIVE_INFO;
memory_end = (1<<20) + (EXT_MEM_K<<10);
memory_end &= 0xfffff000;
......@@ -145,7 +172,8 @@ void main(void) /* This really IS void, no error here. */
* can run). For task0 'pause()' just means we go check if some other
* task can run, and if not we return here.
*/
for(;;) pause();
for(;;)
__asm__("int $0x80"::"a" (__NR_pause):"ax");
}
static int printf(const char *fmt, ...)
......@@ -159,18 +187,12 @@ static int printf(const char *fmt, ...)
return i;
}
static char * argv_rc[] = { "/bin/sh", NULL };
static char * envp_rc[] = { "HOME=/", NULL };
static char * argv[] = { "-/bin/sh",NULL };
static char * envp[] = { "HOME=/usr/root", NULL };
void init(void)
{
int pid,i;
setup((void *) &drive_info);
(void) open("/dev/tty0",O_RDWR,0);
(void) open("/dev/tty1",O_RDWR,0);
(void) dup(0);
(void) dup(0);
printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,
......@@ -194,7 +216,7 @@ void init(void)
if (!pid) {
close(0);close(1);close(2);
setsid();
(void) open("/dev/tty0",O_RDWR,0);
(void) open("/dev/tty1",O_RDWR,0);
(void) dup(0);
(void) dup(0);
_exit(execve("/bin/sh",argv,envp));
......
.file "init/main.c"
gcc_compiled.:
.text
LC0:
.ascii "out of memory\12\15\0"
.align 2
_sprintf:
movl 4(%esp),%edx
leal 12(%esp),%eax
pushl %eax
pushl 12(%esp)
pushl %edx
call _vsprintf
addl $12,%esp
ret
.align 2
_time_init:
pushl %ebp
movl %esp,%ebp
subl $44,%esp
L65:
movl $128,%eax
movl $112,%edx
/APP
outb %al,%dx
jmp 1f
1: jmp 1f
1:
/NO_APP
movl $113,%edx
/APP
inb %dx,%al
jmp 1f
1: jmp 1f
1:
/NO_APP
movb %al,-40(%ebp)
movzbl -40(%ebp),%eax
movl %eax,-36(%ebp)
movl $130,%eax
movl $112,%edx
/APP
outb %al,%dx
jmp 1f
1: jmp 1f
1:
/NO_APP
movl $113,%edx
/APP
inb %dx,%al
jmp 1f
1: jmp 1f
1:
/NO_APP
movb %al,-40(%ebp)
movzbl -40(%ebp),%eax
movl %eax,-32(%ebp)
movl $132,%eax
movl $112,%edx
/APP
outb %al,%dx
jmp 1f
1: jmp 1f
1:
/NO_APP
movl $113,%edx
/APP
inb %dx,%al
jmp 1f
1: jmp 1f
1:
/NO_APP
movb %al,-40(%ebp)
movzbl -40(%ebp),%eax
movl %eax,-28(%ebp)
movl $135,%eax
movl $112,%edx
/APP
outb %al,%dx
jmp 1f
1: jmp 1f
1:
/NO_APP
movl $113,%edx
/APP
inb %dx,%al
jmp 1f
1: jmp 1f
1:
/NO_APP
movb %al,-40(%ebp)
movzbl -40(%ebp),%eax
movl %eax,-24(%ebp)
movl $136,%eax
movl $112,%edx
/APP
outb %al,%dx
jmp 1f
1: jmp 1f
1:
/NO_APP
movl $113,%edx
/APP
inb %dx,%al
jmp 1f
1: jmp 1f
1:
/NO_APP
movb %al,-40(%ebp)
movzbl -40(%ebp),%eax
movl %eax,-20(%ebp)
movl $137,%eax
movl $112,%edx
/APP
outb %al,%dx
jmp 1f
1: jmp 1f
1:
/NO_APP
movl $113,%edx
/APP
inb %dx,%al
jmp 1f
1: jmp 1f
1:
/NO_APP
movb %al,-40(%ebp)
movzbl -40(%ebp),%eax
movl %eax,-16(%ebp)
movl $128,%eax
movl $112,%edx
/APP
outb %al,%dx
jmp 1f
1: jmp 1f
1:
/NO_APP
movl $113,%edx
/APP
inb %dx,%al
jmp 1f
1: jmp 1f
1:
/NO_APP
movb %al,-40(%ebp)
movzbl -40(%ebp),%eax
cmpl -36(%ebp),%eax
jne L65
movl -36(%ebp),%eax
andl $15,%eax
movl -36(%ebp),%edx
sarl $4,%edx
leal (%edx,%edx,4),%edx
leal (%eax,%edx,2),%eax
movl %eax,-36(%ebp)
movl -32(%ebp),%eax
andl $15,%eax
movl -32(%ebp),%edx
sarl $4,%edx
leal (%edx,%edx,4),%edx
leal (%eax,%edx,2),%eax
movl %eax,-32(%ebp)
movl -28(%ebp),%eax
andl $15,%eax
movl -28(%ebp),%edx
sarl $4,%edx
leal (%edx,%edx,4),%edx
leal (%eax,%edx,2),%eax
movl %eax,-28(%ebp)
movl -24(%ebp),%eax
andl $15,%eax
movl -24(%ebp),%edx
sarl $4,%edx
leal (%edx,%edx,4),%edx
leal (%eax,%edx,2),%eax
movl %eax,-24(%ebp)
movl -20(%ebp),%eax
andl $15,%eax
movl -20(%ebp),%edx
sarl $4,%edx
leal (%edx,%edx,4),%edx
leal (%eax,%edx,2),%eax
movl %eax,-20(%ebp)
movl -16(%ebp),%eax
andl $15,%eax
movl -16(%ebp),%edx
sarl $4,%edx
leal (%edx,%edx,4),%edx
leal (%eax,%edx,2),%eax
movl %eax,-16(%ebp)
decl -20(%ebp)
leal -36(%ebp),%eax
pushl %eax
call _kernel_mktime
movl %eax,_startup_time
leave
ret
.data
.align 2
_memory_end:
.long 0
.align 2
_buffer_memory_end:
.long 0
.align 2
_main_memory_start:
.long 0
.text
LC1:
.ascii "/bin/sh\0"
.data
.align 2
_argv_rc:
.long LC1
.long 0
.text
LC2:
.ascii "HOME=/\0"
.data
.align 2
_envp_rc:
.long LC2
.long 0
.long 0
.text
LC3:
.ascii "-/bin/sh\0"
.data
.align 2
_argv:
.long LC3
.long 0
.text
LC4:
.ascii "HOME=/usr/root\0"
.data
.align 2
_envp:
.long LC4
.long 0
.long 0
.text
LC5:
.ascii "TERM=con%dx%d\0"
.align 2
.globl _main
_main:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
pushl %edi
pushl %esi
movzwl 590332,%eax
movl %eax,_ROOT_DEV
movzwl 590330,%eax
movl %eax,_SWAP_DEV
movw 589838,%dx
andl $255,%edx
pushl %edx
movw 589838,%ax
andw $65280,%ax
shrw $8,%ax
movw %ax,-4(%ebp)
movzwl -4(%ebp),%eax
pushl %eax
pushl $LC5
pushl $_term
call _sprintf
movl $_term,_envp+4
movl $_term,_envp_rc+4
movl $_drive_info,%edi
movl $589952,%esi
movl $8,%ecx
cld
rep
movsl
movzwl 589826,%eax
sall $10,%eax
addl $1048576,%eax
movl %eax,_memory_end
andl $-4096,_memory_end
addl $16,%esp
cmpl $16777216,_memory_end
jle L69
movl $16777216,_memory_end
L69:
cmpl $12582912,_memory_end
jle L70
movl $4194304,_buffer_memory_end
jmp L71
.align 2
L70:
cmpl $6291456,_memory_end
jle L72
movl $2097152,_buffer_memory_end
jmp L71
.align 2
L72:
movl $1048576,_buffer_memory_end
L71:
movl _buffer_memory_end,%eax
movl %eax,_main_memory_start
pushl _memory_end
pushl _buffer_memory_end
call _mem_init
call _trap_init
call _blk_dev_init
call _chr_dev_init
call _tty_init
call _time_init
call _sched_init
pushl _buffer_memory_end
call _buffer_init
call _hd_init
call _floppy_init
/APP
sti
movl %esp,%eax
pushl $0x17
pushl %eax
pushfl
pushl $0x0f
pushl $1f
iret
1: movl $0x17,%eax
movw %ax,%ds
movw %ax,%es
movw %ax,%fs
movw %ax,%gs
/NO_APP
addl $12,%esp
movl $2,%eax
/APP
int $0x80
/NO_APP
movl %eax,%edx
testl %edx,%edx
jge L75
negl %edx
movl %edx,_errno
movl $-1,%edx
L75:
testl %edx,%edx
jne L74
call _init
L74:
L77:
movl $29,%eax
/APP
int $0x80
/NO_APP
jmp L77
.align 2
leal -16(%ebp),%esp
popl %esi
popl %edi
leave
ret
.align 2
_printf:
pushl %ebx
leal 12(%esp),%eax
pushl %eax
pushl 12(%esp)
pushl $_printbuf
call _vsprintf
movl %eax,%ebx
pushl %ebx
pushl $_printbuf
pushl $1
call _write
movl %ebx,%eax
addl $24,%esp
popl %ebx
ret
LC6:
.ascii "/dev/tty1\0"
LC7:
.ascii "%d buffers = %d bytes buffer space\12\15\0"
LC8:
.ascii "Free mem: %d bytes\12\15\0"
LC9:
.ascii "/etc/rc\0"
LC10:
.ascii "Fork failed in init\15\12\0"
LC11:
.ascii "\12\15child %d died with code %04x\12\15\0"
.align 2
.globl _init
_init:
pushl %ebp
movl %esp,%ebp
subl $4,%esp
pushl %edi
pushl %esi
pushl %ebx
xorl %eax,%eax
movl $_drive_info,%ebx
/APP
int $0x80
/NO_APP
testl %eax,%eax
jge L82
negl %eax
movl %eax,_errno
L82:
pushl $0
pushl $2
pushl $LC6
call _open
pushl $0
call _dup
pushl $0
call _dup
movl _nr_buffers,%eax
sall $10,%eax
pushl %eax
pushl _nr_buffers
pushl $LC7
call _printf
addl $32,%esp
movl _memory_end,%eax
subl _main_memory_start,%eax
pushl %eax
pushl $LC8
call _printf
addl $8,%esp
movl $2,%eax
/APP
int $0x80
/NO_APP
testl %eax,%eax
jl L86
movl %eax,%edi
jmp L85
.align 2
L86:
negl %eax
movl %eax,_errno
movl $-1,%edi
L85:
testl %edi,%edi
jne L84
pushl $0
call _close
pushl $0
pushl $0
pushl $LC9
call _open
addl $16,%esp
testl %eax,%eax
je L87
pushl $1
call __exit
.align 2
L87:
pushl $_envp_rc
pushl $_argv_rc
pushl $LC1
call _execve
pushl $2
call __exit
.align 2
L84:
testl %edi,%edi
jle L88
leal -4(%ebp),%esi
L89:
pushl %esi
call _wait
addl $4,%esp
cmpl %edi,%eax
jne L89
L88:
leal -4(%ebp),%esi
L91:
movl $2,%eax
/APP
int $0x80
/NO_APP
testl %eax,%eax
jge L94
negl %eax
movl %eax,_errno
movl $-1,%eax
L94:
movl %eax,%edi
testl %edi,%edi
jge L93
pushl $LC10
call _printf
addl $4,%esp
jmp L91
.align 2
L93:
testl %edi,%edi
jne L96
pushl $0
call _close
pushl $1
call _close
pushl $2
call _close
call _setsid
pushl $0
pushl $2
pushl $LC6
call _open
pushl $0
call _dup
pushl $0
call _dup
addl $32,%esp
pushl $_envp
pushl $_argv
pushl $LC1
call _execve
pushl %eax
call __exit
.align 2
L96:
L97:
pushl %esi
call _wait
addl $4,%esp
cmpl %edi,%eax
jne L97
pushl -4(%ebp)
pushl %edi
pushl $LC11
call _printf
addl $12,%esp
movl $36,%eax
/APP
int $0x80
/NO_APP
testl %eax,%eax
jge L91
negl %eax
movl %eax,_errno
jmp L91
.align 2
leal -16(%ebp),%esp
popl %ebx
popl %esi
popl %edi
leave
ret
.comm _drive_info,32
.lcomm _term,32
.lcomm _printbuf,1024
......@@ -24,7 +24,7 @@ CPP =gcc -E -nostdinc -I../include
$(CC) $(CFLAGS) \
-c -o $*.o $<
OBJS = sched.o system_call.o traps.o asm.o fork.o \
OBJS = sched.o sys_call.o traps.o asm.o fork.o \
panic.o printk.o vsprintf.o sys.o exit.o \
signal.o mktime.o
......@@ -51,33 +51,43 @@ dep:
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 \
../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \
../include/asm/segment.h
../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h ../include/linux/tty.h \
../include/termios.h ../include/asm/segment.h
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/signal.h ../include/linux/kernel.h \
../include/asm/segment.h ../include/asm/system.h
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h
mktime.s mktime.o : mktime.c ../include/time.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
../include/linux/mm.h ../include/signal.h ../include/sys/param.h \
../include/sys/time.h ../include/time.h ../include/sys/resource.h
printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \
../include/linux/kernel.h
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/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
../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
../include/sys/time.h ../include/time.h ../include/sys/resource.h \
../include/linux/sys.h ../include/linux/fdreg.h ../include/asm/system.h \
../include/asm/io.h ../include/asm/segment.h
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
../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
../include/sys/time.h ../include/time.h ../include/sys/resource.h \
../include/asm/segment.h ../include/errno.h
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/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
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h ../include/linux/tty.h ../include/termios.h \
../include/linux/config.h ../include/asm/segment.h ../include/sys/times.h \
../include/sys/utsname.h ../include/string.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/signal.h ../include/linux/kernel.h \
../include/asm/system.h ../include/asm/segment.h ../include/asm/io.h
../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
../include/sys/param.h ../include/sys/time.h ../include/time.h \
../include/sys/resource.h ../include/asm/system.h ../include/asm/segment.h \
../include/asm/io.h
vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h
......@@ -15,6 +15,7 @@
.globl _double_fault,_coprocessor_segment_overrun
.globl _invalid_TSS,_segment_not_present,_stack_segment
.globl _general_protection,_coprocessor_error,_irq13,_reserved
.globl _alignment_check
_divide_error:
pushl $_do_divide_error
......@@ -144,3 +145,7 @@ _general_protection:
pushl $_do_general_protection
jmp error_code
_alignment_check:
pushl $_do_alignment_check
jmp error_code
......@@ -43,16 +43,29 @@ dep:
### 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
../../include/linux/kernel.h ../../include/signal.h \
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/resource.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/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h \
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/resource.h ../../include/linux/hdreg.h \
../../include/asm/system.h ../../include/asm/io.h \
../../include/asm/segment.h blk.h
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
../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h \
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/resource.h ../../include/asm/system.h blk.h
ramdisk.s ramdisk.o : ramdisk.c ../../include/string.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/linux/kernel.h ../../include/signal.h \
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/resource.h ../../include/asm/system.h \
../../include/asm/segment.h ../../include/asm/memory.h blk.h
......@@ -51,6 +51,8 @@ extern struct blk_dev_struct blk_dev[NR_BLK_DEV];
extern struct request request[NR_REQUEST];
extern struct task_struct * wait_for_request;
extern int * blk_size[NR_BLK_DEV];
#ifdef MAJOR_NR
/*
......@@ -79,6 +81,7 @@ extern struct task_struct * wait_for_request;
/* harddisk */
#define DEVICE_NAME "harddisk"
#define DEVICE_INTR do_hd
#define DEVICE_TIMEOUT hd_timeout
#define DEVICE_REQUEST do_hd_request
#define DEVICE_NR(device) (MINOR(device)/5)
#define DEVICE_ON(device)
......@@ -96,6 +99,12 @@ extern struct task_struct * wait_for_request;
#ifdef DEVICE_INTR
void (*DEVICE_INTR)(void) = NULL;
#endif
#ifdef DEVICE_TIMEOUT
int DEVICE_TIMEOUT = 0;
#define SET_INTR(x) (DEVICE_INTR = (x),DEVICE_TIMEOUT = 200)
#else
#define SET_INTR(x) (DEVICE_INTR = (x))
#endif
static void (DEVICE_REQUEST)(void);
extern inline void unlock_buffer(struct buffer_head * bh)
......@@ -124,10 +133,25 @@ extern inline void end_request(int uptodate)
CURRENT = CURRENT->next;
}
#ifdef DEVICE_TIMEOUT
#define CLEAR_DEVICE_TIMEOUT DEVICE_TIMEOUT = 0;
#else
#define CLEAR_DEVICE_TIMEOUT
#endif
#ifdef DEVICE_INTR
#define CLEAR_DEVICE_INTR DEVICE_INTR = 0;
#else
#define CLEAR_DEVICE_INTR
#endif
#define INIT_REQUEST \
repeat: \
if (!CURRENT) \
if (!CURRENT) {\
CLEAR_DEVICE_INTR \
CLEAR_DEVICE_TIMEOUT \
return; \
} \
if (MAJOR(CURRENT->dev) != MAJOR_NR) \
panic(DEVICE_NAME ": request list destroyed"); \
if (CURRENT->bh) { \
......
......@@ -92,6 +92,7 @@ static struct floppy_struct {
{ 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),
......@@ -141,7 +142,7 @@ int floppy_change(unsigned int nr)
repeat:
floppy_on(nr);
while ((current_DOR & 3) != nr && selected)
interruptible_sleep_on(&wait_on_floppy_select);
sleep_on(&wait_on_floppy_select);
if ((current_DOR & 3) != nr)
goto repeat;
if (inb(FD_DIR) & 0x80) {
......@@ -454,8 +455,20 @@ void do_fd_request(void)
add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt);
}
static int floppy_sizes[] ={
0, 0, 0, 0,
360, 360 ,360, 360,
1200,1200,1200,1200,
360, 360, 360, 360,
720, 720, 720, 720,
360, 360, 360, 360,
720, 720, 720, 720,
1440,1440,1440,1440
};
void floppy_init(void)
{
blk_size[MAJOR_NR] = floppy_sizes;
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
set_trap_gate(0x26,&floppy_interrupt);
outb(inb_p(0x21)&~0x40,0x21);
......
......@@ -36,8 +36,8 @@ inb_p(0x71); \
static void recal_intr(void);
static int recalibrate = 1;
static int reset = 1;
static int recalibrate = 0;
static int reset = 0;
/*
* This struct defines the HD's and their types.
......@@ -58,6 +58,8 @@ static struct hd_struct {
long nr_sects;
} hd[5*MAX_HD]={{0,0},};
static int hd_sizes[5*MAX_HD] = {0, };
#define port_read(port,buf,nr) \
__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
......@@ -151,16 +153,20 @@ int sys_setup(void * BIOS)
}
brelse(bh);
}
for (i=0 ; i<5*MAX_HD ; i++)
hd_sizes[i] = hd[i].nr_sects>>1 ;
blk_size[MAJOR_NR] = hd_sizes;
if (NR_HD)
printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
rd_load();
init_swapping();
mount_root();
return (0);
}
static int controller_ready(void)
{
int retries=10000;
int retries = 100000;
while (--retries && (inb_p(HD_STATUS)&0xc0)!=0x40);
return (retries);
......@@ -187,7 +193,7 @@ static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
panic("Trying to write bad sector");
if (!controller_ready())
panic("HD controller not ready");
do_hd = intr_addr;
SET_INTR(intr_addr);
outb_p(hd_info[drive].ctl,HD_CMD);
port=HD_DATA;
outb_p(hd_info[drive].wpcom>>2,++port);
......@@ -202,14 +208,14 @@ static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
static int drive_busy(void)
{
unsigned int i;
unsigned char c;
for (i = 0; i < 10000; i++)
if (READY_STAT == (inb_p(HD_STATUS) & (BUSY_STAT|READY_STAT)))
break;
i = inb(HD_STATUS);
i &= BUSY_STAT | READY_STAT | SEEK_STAT;
if (i == READY_STAT | SEEK_STAT)
return(0);
for (i = 0; i < 50000; i++) {
c = inb_p(HD_STATUS);
c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
if (c == (READY_STAT | SEEK_STAT))
return 0;
}
printk("HD controller times out\n\r");
return(1);
}
......@@ -219,7 +225,7 @@ static void reset_controller(void)
int i;
outb(4,HD_CMD);
for(i = 0; i < 100; i++) nop();
for(i = 0; i < 1000; i++) nop();
outb(hd_info[0].ctl & 0x0f ,HD_CMD);
if (drive_busy())
printk("HD-controller still busy\n\r");
......@@ -259,7 +265,7 @@ static void read_intr(void)
CURRENT->buffer += 512;
CURRENT->sector++;
if (--CURRENT->nr_sectors) {
do_hd = &read_intr;
SET_INTR(&read_intr);
return;
}
end_request(1);
......@@ -276,7 +282,7 @@ static void write_intr(void)
if (--CURRENT->nr_sectors) {
CURRENT->sector++;
CURRENT->buffer += 512;
do_hd = &write_intr;
SET_INTR(&write_intr);
port_write(HD_DATA,CURRENT->buffer,256);
return;
}
......@@ -291,6 +297,14 @@ static void recal_intr(void)
do_hd_request();
}
void hd_times_out(void)
{
printk("HD timeout");
SET_INTR(NULL);
reset = 1;
do_hd_request();
}
void do_hd_request(void)
{
int i,r;
......@@ -327,7 +341,7 @@ void do_hd_request(void)
}
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++)
for(i=0 ; i<10000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
/* nothing */ ;
if (!r) {
bad_rw_intr();
......
......@@ -39,6 +39,15 @@ struct blk_dev_struct blk_dev[NR_BLK_DEV] = {
{ NULL, NULL } /* dev lp */
};
/*
* blk_size contains the size of all block-devices:
*
* blk_size[MAJOR][MINOR]
*
* if (!blk_size[MAJOR]) then no minor size checking is done.
*/
int * blk_size[NR_BLK_DEV] = { NULL, NULL, };
static inline void lock_buffer(struct buffer_head * bh)
{
cli();
......@@ -60,6 +69,9 @@ static inline void unlock_buffer(struct buffer_head * bh)
* add-request adds a request to the linked list.
* It disables interrupts so that it can muck with the
* request-lists in peace.
*
* Note that swapping requests always go before other requests,
* and are done in the order they appear.
*/
static void add_request(struct blk_dev_struct * dev, struct request * req)
{
......@@ -75,11 +87,17 @@ static void add_request(struct blk_dev_struct * dev, struct request * req)
(dev->request_fn)();
return;
}
for ( ; tmp->next ; tmp=tmp->next)
for ( ; tmp->next ; tmp=tmp->next) {
if (!req->bh)
if (tmp->next->bh)
break;
else
continue;
if ((IN_ORDER(tmp,req) ||
!IN_ORDER(tmp,tmp->next)) &&
IN_ORDER(req,tmp->next))
break;
}
req->next=tmp->next;
tmp->next=req;
sti();
......@@ -142,6 +160,41 @@ static void make_request(int major,int rw, struct buffer_head * bh)
add_request(major+blk_dev,req);
}
void ll_rw_page(int rw, int dev, int page, char * buffer)
{
struct request * req;
unsigned int major = MAJOR(dev);
if (major >= NR_BLK_DEV || !(blk_dev[major].request_fn)) {
printk("Trying to read nonexistent block-device\n\r");
return;
}
if (rw!=READ && rw!=WRITE)
panic("Bad block dev command, must be R/W");
repeat:
req = request+NR_REQUEST;
while (--req >= request)
if (req->dev<0)
break;
if (req < request) {
sleep_on(&wait_for_request);
goto repeat;
}
/* fill up the request-info, and add it to the queue */
req->dev = dev;
req->cmd = rw;
req->errors = 0;
req->sector = page<<3;
req->nr_sectors = 8;
req->buffer = buffer;
req->waiting = current;
req->bh = NULL;
req->next = NULL;
current->state = TASK_UNINTERRUPTIBLE;
add_request(major+blk_dev,req);
schedule();
}
void ll_rw_block(int rw, struct buffer_head * bh)
{
unsigned int major;
......
......@@ -25,13 +25,13 @@ CPP =gcc -E -nostdinc -I../../include
-c -o $*.o $<
OBJS = tty_io.o console.o keyboard.o serial.o rs_io.o \
tty_ioctl.o
tty_ioctl.o pty.o
chr_drv.a: $(OBJS)
$(AR) rcs chr_drv.a $(OBJS)
sync
keyboard.s: keyboard.S ../../include/linux/config.h
keyboard.s: keyboard.S
$(CPP) -traditional keyboard.S -o keyboard.s
clean:
......@@ -47,22 +47,42 @@ 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/signal.h \
../../include/linux/tty.h ../../include/termios.h ../../include/asm/io.h \
../../include/asm/system.h
../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h \
../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/resource.h ../../include/linux/tty.h \
../../include/termios.h ../../include/linux/config.h ../../include/asm/io.h \
../../include/asm/system.h ../../include/asm/segment.h \
../../include/string.h ../../include/errno.h
pty.s pty.o : pty.c ../../include/linux/tty.h ../../include/termios.h \
../../include/sys/types.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/linux/mm.h ../../include/linux/kernel.h \
../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
../../include/time.h ../../include/sys/resource.h \
../../include/asm/system.h ../../include/asm/io.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
../../include/sys/types.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/linux/mm.h ../../include/linux/kernel.h \
../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
../../include/time.h ../../include/sys/resource.h \
../../include/asm/system.h ../../include/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
tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.h \
../../include/linux/sched.h ../../include/linux/head.h \
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
../../include/signal.h ../../include/linux/kernel.h \
../../include/linux/tty.h ../../include/asm/io.h \
../../include/signal.h ../../include/sys/types.h ../../include/unistd.h \
../../include/sys/stat.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/times.h ../../include/sys/utsname.h \
../../include/sys/param.h ../../include/sys/resource.h \
../../include/utime.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/linux/mm.h ../../include/linux/kernel.h \
../../include/linux/tty.h ../../include/termios.h \
../../include/asm/segment.h ../../include/asm/system.h
tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.h \
../../include/sys/types.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/linux/mm.h ../../include/linux/kernel.h \
../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
../../include/time.h ../../include/sys/resource.h ../../include/linux/tty.h \
../../include/asm/io.h ../../include/asm/segment.h \
../../include/asm/system.h
This diff is collapsed.
......@@ -10,7 +10,12 @@
* Marc Corsini for the French keyboard
*/
#include <linux/config.h>
/* KBD_FINNISH for Finnish keyboards
* KBD_US for US-type
* KBD_GR for German keyboards
* KBD_FR for Frech keyboard
*/
#define KBD_FINNISH
.text
.globl _keyboard_interrupt
......@@ -44,7 +49,9 @@ _keyboard_interrupt:
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
xorl %al,%al /* %eax is scan code */
movl _blankinterval,%eax
movl %eax,_blankcount
xorl %eax,%eax /* %eax is scan code */
inb $0x60,%al
cmpb $0xe0,%al
je set_e0
......@@ -155,7 +162,12 @@ set_leds:
uncaps: andb $0x7f,mode
ret
scroll:
xorb $1,leds
testb $0x03,mode
je 1f
call _show_mem
jmp 2f
1: call _show_state
2: xorb $1,leds
jmp set_leds
num: xorb $2,leds
jmp set_leds
......@@ -208,13 +220,6 @@ 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
......@@ -225,11 +230,17 @@ func:
cmpb $11,%al
ja end_func
ok_func:
testb $0x10,mode
jne alt_func
cmpl $4,%ecx /* check that there is enough room */
jl end_func
movl func_table(,%eax,4),%eax
xorl %ebx,%ebx
jmp put_queue
alt_func:
pushl %eax
call _change_console
popl %eax
end_func:
ret
......
/*
* linux/kernel/chr_drv/pty.c
*
* (C) 1991 Linus Torvalds
*/
/*
* pty.c
*
* This module implements the pty functions
* void mpty_write(struct tty_struct * queue);
* void spty_write(struct tty_struct * queue);
*/
#include <linux/tty.h>
#include <linux/sched.h>
#include <asm/system.h>
#include <asm/io.h>
static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
{
char c;
while (!from->stopped && !EMPTY(from->write_q)) {
if (FULL(to->read_q)) {
if (FULL(to->secondary))
break;
copy_to_cooked(to);
continue;
}
GETCH(from->write_q,c);
PUTCH(c,to->read_q);
if (current->signal & ~current->blocked)
break;
}
copy_to_cooked(to);
wake_up(&from->write_q->proc_list);
}
/*
* This routine gets called when tty_write has put something into
* the write_queue. It copies the input to the output-queue of it's
* slave.
*/
void mpty_write(struct tty_struct * tty)
{
int nr = tty - tty_table;
if ((nr >> 6) != 2)
printk("bad mpty\n\r");
else
pty_copy(tty,tty+64);
}
void spty_write(struct tty_struct * tty)
{
int nr = tty - tty_table;
if ((nr >> 6) != 3)
printk("bad spty\n\r");
else
pty_copy(tty,tty-64);
}
......@@ -105,7 +105,8 @@ read_char:
cmpl tail(%ecx),%ebx
je 1f
movl %ebx,head(%ecx)
1: pushl %edx
1: addl $63,%edx
pushl %edx
call _do_tty_interrupt
addl $4,%esp
ret
......
......@@ -38,8 +38,8 @@ void rs_init(void)
{
set_intr_gate(0x24,rs1_interrupt);
set_intr_gate(0x23,rs2_interrupt);
init(tty_table[1].read_q.data);
init(tty_table[2].read_q.data);
init(tty_table[64].read_q->data);
init(tty_table[65].read_q->data);
outb(inb_p(0x21)&0xE7,0x21);
}
......@@ -54,6 +54,6 @@ void rs_write(struct tty_struct * tty)
{
cli();
if (!EMPTY(tty->write_q))
outb(inb_p(tty->write_q.data+1)|0x02,tty->write_q.data+1);
outb(inb_p(tty->write_q->data+1)|0x02,tty->write_q->data+1);
sti();
}
This diff is collapsed.
......@@ -15,6 +15,9 @@
#include <asm/segment.h>
#include <asm/system.h>
extern int session_of_pgrp(int pgrp);
extern int tty_signal(int sig, struct tty_struct *tty);
static unsigned short quotient[] = {
0, 2304, 1536, 1047, 857,
768, 576, 384, 192, 96,
......@@ -25,7 +28,7 @@ static void change_speed(struct tty_struct * tty)
{
unsigned short port,quot;
if (!(port = tty->read_q.data))
if (!(port = tty->read_q->data))
return;
quot = quotient[tty->termios.c_cflag & CBAUD];
cli();
......@@ -63,10 +66,19 @@ static int get_termios(struct tty_struct * tty, struct termios * termios)
return 0;
}
static int set_termios(struct tty_struct * tty, struct termios * termios)
static int set_termios(struct tty_struct * tty, struct termios * termios,
int channel)
{
int i;
int i, retsig;
/* If we try to set the state of terminal and we're not in the
foreground, send a SIGTTOU. If the signal is blocked or
ignored, go ahead and perform the operation. POSIX 7.2) */
if ((current->tty == channel) && (tty->pgrp != current->pgrp)) {
retsig = tty_signal(SIGTTOU, tty);
if (retsig == -ERESTARTSYS || retsig == -EINTR)
return retsig;
}
for (i=0 ; i< (sizeof (*termios)) ; i++)
((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
change_speed(tty);
......@@ -94,11 +106,17 @@ static int get_termio(struct tty_struct * tty, struct termio * termio)
/*
* This only works as the 386 is low-byt-first
*/
static int set_termio(struct tty_struct * tty, struct termio * termio)
static int set_termio(struct tty_struct * tty, struct termio * termio,
int channel)
{
int i;
int i, retsig;
struct termio tmp_termio;
if ((current->tty == channel) && (tty->pgrp != current->pgrp)) {
retsig = tty_signal(SIGTTOU, tty);
if (retsig == -ERESTARTSYS || retsig == -EINTR)
return retsig;
}
for (i=0 ; i< (sizeof (*termio)) ; i++)
((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
*(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag;
......@@ -115,30 +133,32 @@ static int set_termio(struct tty_struct * tty, struct termio * termio)
int tty_ioctl(int dev, int cmd, int arg)
{
struct tty_struct * tty;
int pgrp;
if (MAJOR(dev) == 5) {
dev=current->tty;
if (dev<0)
panic("tty_ioctl: dev<0");
} else
dev=MINOR(dev);
tty = dev + tty_table;
tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console);
switch (cmd) {
case TCGETS:
return get_termios(tty,(struct termios *) arg);
case TCSETSF:
flush(&tty->read_q); /* fallthrough */
flush(tty->read_q); /* fallthrough */
case TCSETSW:
wait_until_sent(tty); /* fallthrough */
case TCSETS:
return set_termios(tty,(struct termios *) arg);
return set_termios(tty,(struct termios *) arg, dev);
case TCGETA:
return get_termio(tty,(struct termio *) arg);
case TCSETAF:
flush(&tty->read_q); /* fallthrough */
flush(tty->read_q); /* fallthrough */
case TCSETAW:
wait_until_sent(tty); /* fallthrough */
case TCSETA:
return set_termio(tty,(struct termio *) arg);
return set_termio(tty,(struct termio *) arg, dev);
case TCSBRK:
if (!arg) {
wait_until_sent(tty);
......@@ -146,15 +166,33 @@ int tty_ioctl(int dev, int cmd, int arg)
}
return 0;
case TCXONC:
switch (arg) {
case TCOOFF:
tty->stopped = 1;
tty->write(tty);
return 0;
case TCOON:
tty->stopped = 0;
tty->write(tty);
return 0;
case TCIOFF:
if (STOP_CHAR(tty))
PUTCH(STOP_CHAR(tty),tty->write_q);
return 0;
case TCION:
if (START_CHAR(tty))
PUTCH(START_CHAR(tty),tty->write_q);
return 0;
}
return -EINVAL; /* not implemented */
case TCFLSH:
if (arg==0)
flush(&tty->read_q);
flush(tty->read_q);
else if (arg==1)
flush(&tty->write_q);
flush(tty->write_q);
else if (arg==2) {
flush(&tty->read_q);
flush(&tty->write_q);
flush(tty->read_q);
flush(tty->write_q);
} else
return -EINVAL;
return 0;
......@@ -169,7 +207,16 @@ int tty_ioctl(int dev, int cmd, int arg)
put_fs_long(tty->pgrp,(unsigned long *) arg);
return 0;
case TIOCSPGRP:
tty->pgrp=get_fs_long((unsigned long *) arg);
if ((current->tty < 0) ||
(current->tty != dev) ||
(tty->session != current->session))
return -ENOTTY;
pgrp=get_fs_long((unsigned long *) arg);
if (pgrp < 0)
return -EINVAL;
if (session_of_pgrp(pgrp) != current->session)
return -EPERM;
tty->pgrp = pgrp;
return 0;
case TIOCOUTQ:
verify_area((void *) arg,4);
......
This diff is collapsed.
......@@ -49,7 +49,7 @@ int copy_mem(int nr,struct task_struct * p)
panic("We don't support separate I&D");
if (data_limit < code_limit)
panic("Bad data_limit");
new_data_base = new_code_base = nr * 0x4000000;
new_data_base = new_code_base = nr * TASK_SIZE;
p->start_code = new_code_base;
set_base(p->ldt[1],new_code_base);
set_base(p->ldt[2],new_data_base);
......@@ -66,7 +66,7 @@ int copy_mem(int nr,struct task_struct * p)
* also copies the data segment in it's entirety.
*/
int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
long ebx,long ecx,long edx,
long ebx,long ecx,long edx, long orig_eax,
long fs,long es,long ds,
long eip,long cs,long eflags,long esp,long ss)
{
......@@ -81,7 +81,6 @@ int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
*p = *current; /* NOTE! this doesn't copy the supervisor stack */
p->state = TASK_UNINTERRUPTIBLE;
p->pid = last_pid;
p->father = current->pid;
p->counter = p->priority;
p->signal = 0;
p->alarm = 0;
......@@ -111,7 +110,7 @@ int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
p->tss.ldt = _LDT(nr);
p->tss.trace_bitmap = 0x80000000;
if (last_task_used_math == current)
__asm__("clts ; fnsave %0"::"m" (p->tss.i387));
__asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387));
if (copy_mem(nr,p)) {
task[nr] = NULL;
free_page((long) p);
......@@ -126,8 +125,17 @@ int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
current->root->i_count++;
if (current->executable)
current->executable->i_count++;
if (current->library)
current->library->i_count++;
set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
p->p_pptr = current;
p->p_cptr = 0;
p->p_ysptr = 0;
p->p_osptr = current->p_cptr;
if (p->p_osptr)
p->p_osptr->p_ysptr = p;
current->p_cptr = p;
p->state = TASK_RUNNING; /* do this last, just in case */
return last_pid;
}
......@@ -139,7 +147,9 @@ int find_empty_process(void)
repeat:
if ((++last_pid)<0) last_pid=1;
for(i=0 ; i<NR_TASKS ; i++)
if (task[i] && task[i]->pid == last_pid) goto repeat;
if (task[i] && ((task[i]->pid == last_pid) ||
(task[i]->pgrp == last_pid)))
goto repeat;
for(i=1 ; i<NR_TASKS ; i++)
if (!task[i])
return i;
......
......@@ -24,7 +24,8 @@ CPP =gcc -E -nostdinc -I../../include
$(CC) $(CFLAGS) \
-c -o $*.o $<
OBJS = math_emulate.o
OBJS = math_emulate.o error.o convert.o ea.o get_put.o \
add.o mul.o div.o compare.o
math.a: $(OBJS)
$(AR) rcs math.a $(OBJS)
......@@ -41,3 +42,42 @@ dep:
cp tmp_make Makefile
### Dependencies:
add.s add.o : add.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h
compare.s compare.o : compare.c ../../include/linux/math_emu.h \
../../include/linux/sched.h ../../include/linux/head.h \
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h
convert.s convert.o : convert.c ../../include/linux/math_emu.h \
../../include/linux/sched.h ../../include/linux/head.h \
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h
div.s div.o : div.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h
ea.s ea.o : ea.c ../../include/stddef.h ../../include/linux/math_emu.h \
../../include/linux/sched.h ../../include/linux/head.h \
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h \
../../include/asm/segment.h
error.s error.o : error.c ../../include/signal.h ../../include/sys/types.h \
../../include/linux/sched.h ../../include/linux/head.h \
../../include/linux/fs.h ../../include/linux/mm.h \
../../include/linux/kernel.h
get_put.s get_put.o : get_put.c ../../include/signal.h ../../include/sys/types.h \
../../include/linux/math_emu.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/linux/mm.h ../../include/linux/kernel.h \
../../include/asm/segment.h
math_emulate.s math_emulate.o : math_emulate.c ../../include/signal.h \
../../include/sys/types.h ../../include/linux/math_emu.h \
../../include/linux/sched.h ../../include/linux/head.h \
../../include/linux/fs.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/asm/segment.h
mul.s mul.o : mul.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/linux/mm.h \
../../include/linux/kernel.h ../../include/signal.h
/*
* linux/kernel/math/add.c
*
* (C) 1991 Linus Torvalds
*/
/*
* temporary real addition routine.
*
* NOTE! These aren't exact: they are only 62 bits wide, and don't do
* correct rounding. Fast hack. The reason is that we shift right the
* values by two, in order not to have overflow (1 bit), and to be able
* to move the sign into the mantissa (1 bit). Much simpler algorithms,
* and 62 bits (61 really - no rounding) accuracy is usually enough. The
* only time you should notice anything weird is when adding 64-bit
* integers together. When using doubles (52 bits accuracy), the
* 61-bit accuracy never shows at all.
*/
#include <linux/math_emu.h>
#define NEGINT(a) \
__asm__("notl %0 ; notl %1 ; addl $1,%0 ; adcl $0,%1" \
:"=r" (a->a),"=r" (a->b) \
:"0" (a->a),"1" (a->b))
static void signify(temp_real * a)
{
a->exponent += 2;
__asm__("shrdl $2,%1,%0 ; shrl $2,%1"
:"=r" (a->a),"=r" (a->b)
:"0" (a->a),"1" (a->b));
if (a->exponent < 0)
NEGINT(a);
a->exponent &= 0x7fff;
}
static void unsignify(temp_real * a)
{
if (!(a->a || a->b)) {
a->exponent = 0;
return;
}
a->exponent &= 0x7fff;
if (a->b < 0) {
NEGINT(a);
a->exponent |= 0x8000;
}
while (a->b >= 0) {
a->exponent--;
__asm__("addl %0,%0 ; adcl %1,%1"
:"=r" (a->a),"=r" (a->b)
:"0" (a->a),"1" (a->b));
}
}
void fadd(const temp_real * src1, const temp_real * src2, temp_real * result)
{
temp_real a,b;
int x1,x2,shift;
x1 = src1->exponent & 0x7fff;
x2 = src2->exponent & 0x7fff;
if (x1 > x2) {
a = *src1;
b = *src2;
shift = x1-x2;
} else {
a = *src2;
b = *src1;
shift = x2-x1;
}
if (shift >= 64) {
*result = a;
return;
}
if (shift >= 32) {
b.a = b.b;
b.b = 0;
shift -= 32;
}
__asm__("shrdl %4,%1,%0 ; shrl %4,%1"
:"=r" (b.a),"=r" (b.b)
:"0" (b.a),"1" (b.b),"c" ((char) shift));
signify(&a);
signify(&b);
__asm__("addl %4,%0 ; adcl %5,%1"
:"=r" (a.a),"=r" (a.b)
:"0" (a.a),"1" (a.b),"g" (b.a),"g" (b.b));
unsignify(&a);
*result = a;
}
/*
* linux/kernel/math/compare.c
*
* (C) 1991 Linus Torvalds
*/
/*
* temporary real comparison routines
*/
#include <linux/math_emu.h>
#define clear_Cx() (I387.swd &= ~0x4500)
static void normalize(temp_real * a)
{
int i = a->exponent & 0x7fff;
int sign = a->exponent & 0x8000;
if (!(a->a || a->b)) {
a->exponent = 0;
return;
}
while (i && a->b >= 0) {
i--;
__asm__("addl %0,%0 ; adcl %1,%1"
:"=r" (a->a),"=r" (a->b)
:"0" (a->a),"1" (a->b));
}
a->exponent = i | sign;
}
void ftst(const temp_real * a)
{
temp_real b;
clear_Cx();
b = *a;
normalize(&b);
if (b.a || b.b || b.exponent) {
if (b.exponent < 0)
set_C0();
} else
set_C3();
}
void fcom(const temp_real * src1, const temp_real * src2)
{
temp_real a;
a = *src1;
a.exponent ^= 0x8000;
fadd(&a,src2,&a);
ftst(&a);
}
void fucom(const temp_real * src1, const temp_real * src2)
{
fcom(src1,src2);
}
This diff is collapsed.
/*
* linux/kernel/math/div.c
*
* (C) 1991 Linus Torvalds
*/
/*
* temporary real division routine.
*/
#include <linux/math_emu.h>
static void shift_left(int * c)
{
__asm__ __volatile__("movl (%0),%%eax ; addl %%eax,(%0)\n\t"
"movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t"
"movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t"
"movl 12(%0),%%eax ; adcl %%eax,12(%0)"
::"r" ((long) c):"ax");
}
static void shift_right(int * c)
{
__asm__("shrl $1,12(%0) ; rcrl $1,8(%0) ; rcrl $1,4(%0) ; rcrl $1,(%0)"
::"r" ((long) c));
}
static int try_sub(int * a, int * b)
{
char ok;
__asm__ __volatile__("movl (%1),%%eax ; subl %%eax,(%2)\n\t"
"movl 4(%1),%%eax ; sbbl %%eax,4(%2)\n\t"
"movl 8(%1),%%eax ; sbbl %%eax,8(%2)\n\t"
"movl 12(%1),%%eax ; sbbl %%eax,12(%2)\n\t"
"setae %%al":"=a" (ok):"c" ((long) a),"d" ((long) b));
return ok;
}
static void div64(int * a, int * b, int * c)
{
int tmp[4];
int i;
unsigned int mask = 0;
c += 4;
for (i = 0 ; i<64 ; i++) {
if (!(mask >>= 1)) {
c--;
mask = 0x80000000;
}
tmp[0] = a[0]; tmp[1] = a[1];
tmp[2] = a[2]; tmp[3] = a[3];
if (try_sub(b,tmp)) {
*c |= mask;
a[0] = tmp[0]; a[1] = tmp[1];
a[2] = tmp[2]; a[3] = tmp[3];
}
shift_right(b);
}
}
void fdiv(const temp_real * src1, const temp_real * src2, temp_real * result)
{
int i,sign;
int a[4],b[4],tmp[4] = {0,0,0,0};
sign = (src1->exponent ^ src2->exponent) & 0x8000;
if (!(src2->a || src2->b)) {
set_ZE();
return;
}
i = (src1->exponent & 0x7fff) - (src2->exponent & 0x7fff) + 16383;
if (i<0) {
set_UE();
result->exponent = sign;
result->a = result->b = 0;
return;
}
a[0] = a[1] = 0;
a[2] = src1->a;
a[3] = src1->b;
b[0] = b[1] = 0;
b[2] = src2->a;
b[3] = src2->b;
while (b[3] >= 0) {
i++;
shift_left(b);
}
div64(a,b,tmp);
if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) {
while (i && tmp[3] >= 0) {
i--;
shift_left(tmp);
}
if (tmp[3] >= 0)
set_DE();
} else
i = 0;
if (i>0x7fff) {
set_OE();
return;
}
if (tmp[0] || tmp[1])
set_PE();
result->exponent = i | sign;
result->a = tmp[2];
result->b = tmp[3];
}
This diff is collapsed.
/*
* linux/kernel/math/error.c
*
* (C) 1991 Linus Torvalds
*/
#include <signal.h>
#include <linux/sched.h>
void math_error(void)
{
__asm__("fnclex");
if (last_task_used_math)
last_task_used_math->signal |= 1<<(SIGFPE-1);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment