# 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
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
$(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)
### 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
--- /dev/null
+!
+! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
+! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
+! versions of linux
+!
+#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.
+!
+! It then loads 'setup' directly after itself (0x90200), and the system
+! at 0x10000, using BIOS interrupts.
+!
+! NOTE! currently system is at most 8*65536 bytes long. This should be no
+! problem, even in the future. I want to keep it simple. This 512 kB
+! kernel size should be enough, especially as this doesn't contain the
+! buffer cache as in minix
+!
+! The loader has been made as simple as possible, and continuos
+! read errors will result in a unbreakable loop. Reboot by hand. It
+! loads pretty fast by getting whole sectors at a time whenever possible.
+
+.globl begtext, begdata, begbss, endtext, enddata, endbss
+.text
+begtext:
+.data
+begdata:
+.bss
+begbss:
+.text
+
+SETUPLEN = 4 ! nr of setup-sectors
+BOOTSEG = 0x07c0 ! original address of boot-sector
+INITSEG = 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 & SWAP_DEV are now written by "build".
+ROOT_DEV = 0
+SWAP_DEV = 0
+
+entry start
+start:
+ mov ax,#BOOTSEG
+ mov ds,ax
+ mov ax,#INITSEG
+ mov es,ax
+ mov cx,#256
+ sub si,si
+ sub di,di
+ rep
+ movw
+ jmpi go,INITSEG
+
+go: mov ax,cs
+ mov dx,#0xfef4 ! arbitrary value >>512 - disk parm size
+
+ mov ds,ax
+ mov es,ax
+ 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:
+ 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
+
+ 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
+
+ok_load_setup:
+
+! Get disk drive parameters, specifically nr of sectors/track
+
+ xor dl,dl
+ mov ah,#0x08 ! AH=8 is get drive parameters
+ int 0x13
+ xor ch,ch
+ seg cs
+ mov sectors,cx
+ mov ax,#INITSEG
+ mov es,ax
+
+! Print some inane message
+
+ mov ah,#0x03 ! read cursor pos
+ xor bh,bh
+ int 0x10
+
+ mov cx,#9
+ mov bx,#0x0007 ! page 0, attribute 7 (normal)
+ mov bp,#msg1
+ mov ax,#0x1301 ! write string, move cursor
+ int 0x10
+
+! ok, we've written the message, now
+! we want to load the system (at 0x10000)
+
+ mov ax,#SYSSEG
+ mov es,ax ! segment of 0x010000
+ call read_it
+ call kill_motor
+ 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.
+! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
+! on the number of sectors that the BIOS reports currently.
+
+ seg cs
+ mov ax,root_dev
+ or ax,ax
+ jne root_defined
+ seg cs
+ mov bx,sectors
+ mov ax,#0x0208 ! /dev/ps0 - 1.2Mb
+ cmp bx,#15
+ je root_defined
+ mov ax,#0x021c ! /dev/PS0 - 1.44Mb
+ cmp bx,#18
+ je root_defined
+undef_root:
+ jmp undef_root
+root_defined:
+ seg cs
+ mov root_dev,ax
+
+! after that (everyting loaded), we jump to
+! the setup-routine loaded directly after
+! the bootblock:
+
+ jmpi 0,SETUPSEG
+
+! This routine loads the system at address 0x10000, making sure
+! no 64kB boundaries are crossed. We try to load it as fast as
+! possible, loading whole tracks whenever we can.
+!
+! in: es - starting address segment (normally 0x1000)
+!
+sread: .word 1+SETUPLEN ! sectors read of current track
+head: .word 0 ! current head
+track: .word 0 ! current track
+
+read_it:
+ mov ax,es
+ test ax,#0x0fff
+die: jne die ! es must be at 64kB boundary
+ xor bx,bx ! bx is starting address within segment
+rp_read:
+ mov ax,es
+ cmp ax,#ENDSEG ! have we loaded all yet?
+ jb ok1_read
+ ret
+ok1_read:
+ seg cs
+ mov ax,sectors
+ sub ax,sread
+ mov cx,ax
+ shl cx,#9
+ add cx,bx
+ jnc ok2_read
+ je ok2_read
+ xor ax,ax
+ sub ax,bx
+ shr ax,#9
+ok2_read:
+ call read_track
+ mov cx,ax
+ add ax,sread
+ seg cs
+ cmp ax,sectors
+ jne ok3_read
+ mov ax,#1
+ sub ax,head
+ jne ok4_read
+ inc track
+ok4_read:
+ mov head,ax
+ xor ax,ax
+ok3_read:
+ mov sread,ax
+ shl cx,#9
+ add bx,cx
+ jnc rp_read
+ mov ax,es
+ add ah,#0x10
+ mov es,ax
+ xor bx,bx
+ jmp rp_read
+
+read_track:
+ 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
+ and dx,#0x0100
+ mov ah,#2
+
+ push dx ! save for error dump
+ push cx
+ push bx
+ push ax
+
+ int 0x13
+ jc bad_rt
+ add sp, #8
+ popa
+ ret
+
+bad_rt: push ax ! save error code
+ call print_all ! ah = error, al = read
+
+
+ xor ah,ah
+ xor dl,dl
+ int 0x13
+
+
+ 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
+ * don't have to worry about it later.
+ */
+kill_motor:
+ push dx
+ mov dx,#0x3f2
+ xor al, al
+ outb
+ pop dx
+ ret
+
+sectors:
+ .word 0
+
+msg1:
+ .byte 13,10
+ .ascii "Loading"
+
+.org 506
+swap_dev:
+ .word SWAP_DEV
+root_dev:
+ .word ROOT_DEV
+boot_flag:
+ .word 0xAA55
+
+.text
+endtext:
+.data
+enddata:
+.bss
+endbss:
+
+++ /dev/null
-!
-! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
-! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
-! versions of linux
-!
-SYSSIZE = 0x3000
-!
-! bootsect.s (C) 1991 Linus Torvalds
-!
-! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
-! iself out of the way to address 0x90000, and jumps there.
-!
-! It then loads 'setup' directly after itself (0x90200), and the system
-! at 0x10000, using BIOS interrupts.
-!
-! NOTE! currently system is at most 8*65536 bytes long. This should be no
-! problem, even in the future. I want to keep it simple. This 512 kB
-! kernel size should be enough, especially as this doesn't contain the
-! buffer cache as in minix
-!
-! The loader has been made as simple as possible, and continuos
-! read errors will result in a unbreakable loop. Reboot by hand. It
-! loads pretty fast by getting whole sectors at a time whenever possible.
-
-.globl begtext, begdata, begbss, endtext, enddata, endbss
-.text
-begtext:
-.data
-begdata:
-.bss
-begbss:
-.text
-
-SETUPLEN = 4 ! nr of setup-sectors
-BOOTSEG = 0x07c0 ! original address of boot-sector
-INITSEG = 0x9000 ! we move boot here - out of the way
-SETUPSEG = 0x9020 ! setup starts here
-SYSSEG = 0x1000 ! system loaded at 0x10000 (65536).
-ENDSEG = SYSSEG + SYSSIZE ! where to stop loading
-
-! ROOT_DEV: 0x000 - same type of floppy as boot.
-! 0x301 - first partition on first drive etc
-ROOT_DEV = 0x306
-
-entry start
-start:
- mov ax,#BOOTSEG
- mov ds,ax
- mov ax,#INITSEG
- mov es,ax
- mov cx,#256
- sub si,si
- sub di,di
- rep
- movw
- jmpi go,INITSEG
-go: mov ax,cs
- mov ds,ax
- mov es,ax
-! put stack at 0x9ff00.
- mov ss,ax
- mov sp,#0xFF00 ! arbitrary value >>512
-
-! load the setup-sectors directly after the bootblock.
-! Note that 'es' is already set up.
-
-load_setup:
- mov dx,#0x0000 ! drive 0, head 0
- mov cx,#0x0002 ! sector 2, track 0
- mov bx,#0x0200 ! address = 512, in INITSEG
- mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors
- int 0x13 ! read it
- jnc ok_load_setup ! ok - continue
- mov dx,#0x0000
- mov ax,#0x0000 ! reset the diskette
- int 0x13
- j load_setup
-
-ok_load_setup:
-
-! Get disk drive parameters, specifically nr of sectors/track
-
- mov dl,#0x00
- mov ax,#0x0800 ! AH=8 is get drive parameters
- int 0x13
- mov ch,#0x00
- seg cs
- mov sectors,cx
- mov ax,#INITSEG
- mov es,ax
-
-! Print some inane message
-
- mov ah,#0x03 ! read cursor pos
- xor bh,bh
- int 0x10
-
- mov cx,#24
- mov bx,#0x0007 ! page 0, attribute 7 (normal)
- mov bp,#msg1
- mov ax,#0x1301 ! write string, move cursor
- int 0x10
-
-! ok, we've written the message, now
-! we want to load the system (at 0x10000)
-
- mov ax,#SYSSEG
- mov es,ax ! segment of 0x010000
- call read_it
- call kill_motor
-
-! After that we check which root-device to use. If the device is
-! defined (!= 0), nothing is done and the given device is used.
-! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
-! on the number of sectors that the BIOS reports currently.
-
- seg cs
- mov ax,root_dev
- cmp ax,#0
- jne root_defined
- seg cs
- mov bx,sectors
- mov ax,#0x0208 ! /dev/ps0 - 1.2Mb
- cmp bx,#15
- je root_defined
- mov ax,#0x021c ! /dev/PS0 - 1.44Mb
- cmp bx,#18
- je root_defined
-undef_root:
- jmp undef_root
-root_defined:
- seg cs
- mov root_dev,ax
-
-! after that (everyting loaded), we jump to
-! the setup-routine loaded directly after
-! the bootblock:
-
- jmpi 0,SETUPSEG
-
-! This routine loads the system at address 0x10000, making sure
-! no 64kB boundaries are crossed. We try to load it as fast as
-! possible, loading whole tracks whenever we can.
-!
-! in: es - starting address segment (normally 0x1000)
-!
-sread: .word 1+SETUPLEN ! sectors read of current track
-head: .word 0 ! current head
-track: .word 0 ! current track
-
-read_it:
- mov ax,es
- test ax,#0x0fff
-die: jne die ! es must be at 64kB boundary
- xor bx,bx ! bx is starting address within segment
-rp_read:
- mov ax,es
- cmp ax,#ENDSEG ! have we loaded all yet?
- jb ok1_read
- ret
-ok1_read:
- seg cs
- mov ax,sectors
- sub ax,sread
- mov cx,ax
- shl cx,#9
- add cx,bx
- jnc ok2_read
- je ok2_read
- xor ax,ax
- sub ax,bx
- shr ax,#9
-ok2_read:
- call read_track
- mov cx,ax
- add ax,sread
- seg cs
- cmp ax,sectors
- jne ok3_read
- mov ax,#1
- sub ax,head
- jne ok4_read
- inc track
-ok4_read:
- mov head,ax
- xor ax,ax
-ok3_read:
- mov sread,ax
- shl cx,#9
- add bx,cx
- jnc rp_read
- mov ax,es
- add ax,#0x1000
- mov es,ax
- xor bx,bx
- jmp rp_read
-
-read_track:
- push ax
- push bx
- push cx
- push dx
- mov dx,track
- mov cx,sread
- inc cx
- mov ch,dl
- mov dx,head
- mov dh,dl
- mov dl,#0
- and dx,#0x0100
- mov ah,#2
- int 0x13
- jc bad_rt
- pop dx
- pop cx
- pop bx
- pop ax
- ret
-bad_rt: mov ax,#0
- mov dx,#0
- int 0x13
- pop dx
- pop cx
- pop bx
- pop ax
- jmp read_track
-
-/*
- * This procedure turns off the floppy drive motor, so
- * that we enter the kernel in a known state, and
- * don't have to worry about it later.
- */
-kill_motor:
- push dx
- mov dx,#0x3f2
- mov al,#0
- outb
- pop dx
- ret
-
-sectors:
- .word 0
-
-msg1:
- .byte 13,10
- .ascii "Loading system ..."
- .byte 13,10,13,10
-
-.org 508
-root_dev:
- .word ROOT_DEV
-boot_flag:
- .word 0xAA55
-
-.text
-endtext:
-.data
-enddata:
-.bss
-endbss:
--- /dev/null
+!
+! setup.s (C) 1991 Linus Torvalds
+!
+! setup.s is responsible for getting the system data from the BIOS,
+! and putting them into the appropriate places in system memory.
+! both setup.s and system has been loaded by the bootblock.
+!
+! This code asks the bios for memory/disk/other parameters, and
+! puts them in a "safe" place: 0x90000-0x901FF, ie where the
+! boot-block used to be. It is then up to the protected mode
+! system to read them from there before the area is overwritten
+! for buffer-blocks.
+!
+
+! NOTE! These had better be the same as in bootsect.s!
+#include <linux/config.h>
+
+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
+begtext:
+.data
+begdata:
+.bss
+begbss:
+.text
+
+entry start
+start:
+
+! ok, the read went well so we get current cursor position and save it for
+! posterity.
+
+ mov ax,#INITSEG ! this is done in bootsect already, but...
+ mov ds,ax
+
+! Get memory size (extended mem, kB)
+
+ mov ah,#0x88
+ int 0x15
+ mov [2],ax
+
+! check for EGA/VGA and some config parameters
+
+ mov ah,#0x12
+ mov bl,#0x10
+ int 0x10
+ mov [8],ax
+ mov [10],bx
+ mov [12],cx
+ 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
+
+ mov ax,#0x0000
+ mov ds,ax
+ lds si,[4*0x41]
+ mov ax,#INITSEG
+ mov es,ax
+ mov di,#0x0080
+ mov cx,#0x10
+ rep
+ movsb
+
+! Get hd1 data
+
+ mov ax,#0x0000
+ mov ds,ax
+ lds si,[4*0x46]
+ mov ax,#INITSEG
+ mov es,ax
+ mov di,#0x0090
+ mov cx,#0x10
+ rep
+ movsb
+
+! Check that there IS a hd1 :-)
+
+ mov ax,#0x01500
+ mov dl,#0x81
+ int 0x13
+ jc no_disk1
+ cmp ah,#3
+ je is_disk1
+no_disk1:
+ mov ax,#INITSEG
+ mov es,ax
+ mov di,#0x0090
+ mov cx,#0x10
+ mov ax,#0x00
+ rep
+ stosb
+is_disk1:
+
+! now we want to move to protected mode ...
+
+ cli ! no interrupts allowed !
+
+! first we move the system to it's rightful place
+
+ mov ax,#0x0000
+ cld ! 'direction'=0, movs moves forward
+do_move:
+ mov es,ax ! destination segment
+ add ax,#0x1000
+ cmp ax,#0x9000
+ jz end_move
+ mov ds,ax ! source segment
+ sub di,di
+ sub si,si
+ mov cx,#0x8000
+ rep
+ movsw
+ jmp do_move
+
+! then we load the segment descriptors
+
+end_move:
+ mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-)
+ mov ds,ax
+ lidt idt_48 ! load idt with 0,0
+ lgdt gdt_48 ! load gdt with whatever appropriate
+
+! that was painless, now we enable A20
+
+ call empty_8042
+ mov al,#0xD1 ! command write
+ out #0x64,al
+ call empty_8042
+ mov al,#0xDF ! A20 on
+ out #0x60,al
+ call empty_8042
+
+! well, that went ok, I hope. Now we have to reprogram the interrupts :-(
+! we put them right after the intel-reserved hardware interrupts, at
+! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
+! messed this up with the original PC, and they haven't been able to
+! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
+! which is used for the internal hardware interrupts as well. We just
+! have to reprogram the 8259's, and it isn't fun.
+
+ mov al,#0x11 ! initialization sequence
+ out #0x20,al ! send it to 8259A-1
+ .word 0x00eb,0x00eb ! jmp $+2, jmp $+2
+ out #0xA0,al ! and to 8259A-2
+ .word 0x00eb,0x00eb
+ mov al,#0x20 ! start of hardware int's (0x20)
+ out #0x21,al
+ .word 0x00eb,0x00eb
+ mov al,#0x28 ! start of hardware int's 2 (0x28)
+ out #0xA1,al
+ .word 0x00eb,0x00eb
+ mov al,#0x04 ! 8259-1 is master
+ out #0x21,al
+ .word 0x00eb,0x00eb
+ mov al,#0x02 ! 8259-2 is slave
+ out #0xA1,al
+ .word 0x00eb,0x00eb
+ mov al,#0x01 ! 8086 mode for both
+ out #0x21,al
+ .word 0x00eb,0x00eb
+ out #0xA1,al
+ .word 0x00eb,0x00eb
+ mov al,#0xFF ! mask off all interrupts for now
+ out #0x21,al
+ .word 0x00eb,0x00eb
+ out #0xA1,al
+
+! well, that certainly wasn't fun :-(. Hopefully it works, and we don't
+! need no steenking BIOS anyway (except for the initial loading :-).
+! The BIOS-routine wants lots of unnecessary data, and it's less
+! "interesting" anyway. This is how REAL programmers do it.
+!
+! Well, now's the time to actually move into protected mode. To make
+! things as simple as possible, we do no register set-up or anything,
+! we let the gnu-compiled 32-bit programs do that. We just jump to
+! absolute address 0x00000, in 32-bit protected mode.
+
+ mov ax,#0x0001 ! protected mode (PE) bit
+ lmsw ax ! This is it!
+ jmpi 0,8 ! jmp offset 0 of segment 8 (cs)
+
+! This routine checks that the keyboard command queue is empty
+! No timeout is used - if this hangs there is something wrong with
+! the machine, and we probably couldn't proceed anyway.
+empty_8042:
+ .word 0x00eb,0x00eb
+ in al,#0x64 ! 8042 status port
+ test al,#2 ! is input buffer full?
+ jnz empty_8042 ! yes - loop
+ ret
+
+! 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
+
+ .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
+ .word 0x0000 ! base address=0
+ .word 0x9A00 ! code read/exec
+ .word 0x00C0 ! granularity=4096, 386
+
+ .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
+ .word 0x0000 ! base address=0
+ .word 0x9200 ! data read/write
+ .word 0x00C0 ! granularity=4096, 386
+
+idt_48:
+ .word 0 ! idt limit=0
+ .word 0,0 ! idt base=0L
+
+gdt_48:
+ .word 0x800 ! gdt limit=2048, 256 GDT entries
+ .word 512+gdt,0x9 ! gdt base = 0X9xxxx
+
+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:
+.data
+enddata:
+.bss
+endbss:
+++ /dev/null
-!
-! setup.s (C) 1991 Linus Torvalds
-!
-! setup.s is responsible for getting the system data from the BIOS,
-! and putting them into the appropriate places in system memory.
-! both setup.s and system has been loaded by the bootblock.
-!
-! This code asks the bios for memory/disk/other parameters, and
-! puts them in a "safe" place: 0x90000-0x901FF, ie where the
-! boot-block used to be. It is then up to the protected mode
-! system to read them from there before the area is overwritten
-! for buffer-blocks.
-!
-
-! NOTE! These had better be the same as in bootsect.s!
-
-INITSEG = 0x9000 ! we move boot here - out of the way
-SYSSEG = 0x1000 ! system loaded at 0x10000 (65536).
-SETUPSEG = 0x9020 ! this is the current segment
-
-.globl begtext, begdata, begbss, endtext, enddata, endbss
-.text
-begtext:
-.data
-begdata:
-.bss
-begbss:
-.text
-
-entry start
-start:
-
-! ok, the read went well so we get current cursor position and save it for
-! posterity.
-
- mov ax,#INITSEG ! this is done in bootsect already, but...
- mov ds,ax
- mov ah,#0x03 ! read cursor pos
- xor bh,bh
- int 0x10 ! save it in known place, con_init fetches
- mov [0],dx ! it from 0x90000.
-
-! Get memory size (extended mem, kB)
-
- mov ah,#0x88
- int 0x15
- mov [2],ax
-
-! Get video-card data:
-
- mov ah,#0x0f
- int 0x10
- mov [4],bx ! bh = display page
- mov [6],ax ! al = video mode, ah = window width
-
-! check for EGA/VGA and some config parameters
-
- mov ah,#0x12
- mov bl,#0x10
- int 0x10
- mov [8],ax
- mov [10],bx
- mov [12],cx
-
-! Get hd0 data
-
- mov ax,#0x0000
- mov ds,ax
- lds si,[4*0x41]
- mov ax,#INITSEG
- mov es,ax
- mov di,#0x0080
- mov cx,#0x10
- rep
- movsb
-
-! Get hd1 data
-
- mov ax,#0x0000
- mov ds,ax
- lds si,[4*0x46]
- mov ax,#INITSEG
- mov es,ax
- mov di,#0x0090
- mov cx,#0x10
- rep
- movsb
-
-! Check that there IS a hd1 :-)
-
- mov ax,#0x01500
- mov dl,#0x81
- int 0x13
- jc no_disk1
- cmp ah,#3
- je is_disk1
-no_disk1:
- mov ax,#INITSEG
- mov es,ax
- mov di,#0x0090
- mov cx,#0x10
- mov ax,#0x00
- rep
- stosb
-is_disk1:
-
-! now we want to move to protected mode ...
-
- cli ! no interrupts allowed !
-
-! first we move the system to it's rightful place
-
- mov ax,#0x0000
- cld ! 'direction'=0, movs moves forward
-do_move:
- mov es,ax ! destination segment
- add ax,#0x1000
- cmp ax,#0x9000
- jz end_move
- mov ds,ax ! source segment
- sub di,di
- sub si,si
- mov cx,#0x8000
- rep
- movsw
- jmp do_move
-
-! then we load the segment descriptors
-
-end_move:
- mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-)
- mov ds,ax
- lidt idt_48 ! load idt with 0,0
- lgdt gdt_48 ! load gdt with whatever appropriate
-
-! that was painless, now we enable A20
-
- call empty_8042
- mov al,#0xD1 ! command write
- out #0x64,al
- call empty_8042
- mov al,#0xDF ! A20 on
- out #0x60,al
- call empty_8042
-
-! well, that went ok, I hope. Now we have to reprogram the interrupts :-(
-! we put them right after the intel-reserved hardware interrupts, at
-! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
-! messed this up with the original PC, and they haven't been able to
-! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
-! which is used for the internal hardware interrupts as well. We just
-! have to reprogram the 8259's, and it isn't fun.
-
- mov al,#0x11 ! initialization sequence
- out #0x20,al ! send it to 8259A-1
- .word 0x00eb,0x00eb ! jmp $+2, jmp $+2
- out #0xA0,al ! and to 8259A-2
- .word 0x00eb,0x00eb
- mov al,#0x20 ! start of hardware int's (0x20)
- out #0x21,al
- .word 0x00eb,0x00eb
- mov al,#0x28 ! start of hardware int's 2 (0x28)
- out #0xA1,al
- .word 0x00eb,0x00eb
- mov al,#0x04 ! 8259-1 is master
- out #0x21,al
- .word 0x00eb,0x00eb
- mov al,#0x02 ! 8259-2 is slave
- out #0xA1,al
- .word 0x00eb,0x00eb
- mov al,#0x01 ! 8086 mode for both
- out #0x21,al
- .word 0x00eb,0x00eb
- out #0xA1,al
- .word 0x00eb,0x00eb
- mov al,#0xFF ! mask off all interrupts for now
- out #0x21,al
- .word 0x00eb,0x00eb
- out #0xA1,al
-
-! well, that certainly wasn't fun :-(. Hopefully it works, and we don't
-! need no steenking BIOS anyway (except for the initial loading :-).
-! The BIOS-routine wants lots of unnecessary data, and it's less
-! "interesting" anyway. This is how REAL programmers do it.
-!
-! Well, now's the time to actually move into protected mode. To make
-! things as simple as possible, we do no register set-up or anything,
-! we let the gnu-compiled 32-bit programs do that. We just jump to
-! absolute address 0x00000, in 32-bit protected mode.
-
- mov ax,#0x0001 ! protected mode (PE) bit
- lmsw ax ! This is it!
- jmpi 0,8 ! jmp offset 0 of segment 8 (cs)
-
-! This routine checks that the keyboard command queue is empty
-! No timeout is used - if this hangs there is something wrong with
-! the machine, and we probably couldn't proceed anyway.
-empty_8042:
- .word 0x00eb,0x00eb
- in al,#0x64 ! 8042 status port
- test al,#2 ! is input buffer full?
- jnz empty_8042 ! yes - loop
- ret
-
-gdt:
- .word 0,0,0,0 ! dummy
-
- .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
- .word 0x0000 ! base address=0
- .word 0x9A00 ! code read/exec
- .word 0x00C0 ! granularity=4096, 386
-
- .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
- .word 0x0000 ! base address=0
- .word 0x9200 ! data read/write
- .word 0x00C0 ! granularity=4096, 386
-
-idt_48:
- .word 0 ! idt limit=0
- .word 0,0 ! idt base=0L
-
-gdt_48:
- .word 0x800 ! gdt limit=2048, 256 GDT entries
- .word 512+gdt,0x9 ! gdt base = 0X9xxxx
-
-.text
-endtext:
-.data
-enddata:
-.bss
-endbss:
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:
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)
### 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
:"=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;
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)
#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;
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;
* 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>
*/
#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
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);
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)
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())) {
* 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++);
}
}
/* 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);
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;
#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);
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);
((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);
}
#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);
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;
#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])
/*
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;
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"
#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) */
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)) {
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;
}
}
* 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++))
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);
}
/*
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))) {
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))) {
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);
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);
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;
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;
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);
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);
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;
iput(oldinode);
return -EPERM;
}
- dir = dir_namei(newname,&namelen,&basename);
+ dir = dir_namei(newname,&namelen,&basename, NULL);
if (!dir) {
iput(oldinode);
return -EACCES;
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/kernel.h>
+
#include <asm/segment.h>
int sys_ustat(int dev, struct ustat * ubuf)
return 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;
}
/* 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]);
*/
#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)
{
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)
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;
}
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)
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;
}
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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
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;
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)
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;
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;
+}
void put_super(int dev)
{
struct super_block * sb;
- struct m_inode * inode;
int i;
if (dev == ROOT_DEV) {
#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;
}
"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"::)
#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
#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
#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];
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;
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);
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);
*/
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)
--- /dev/null
+/*
+ * 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
#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
/* 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 */
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 */
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)
/* 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}, \
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();
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,
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);
#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
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])
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
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
/* 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
#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);
#define NULL ((void *)0)
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-
#endif
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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 */
};
#define S_IFMT 00170000
+#define S_IFLNK 0120000
#define S_IFREG 0100000
#define S_IFBLK 0060000
#define S_IFDIR 0040000
#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)
--- /dev/null
+#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*/
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;
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;
#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];
#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') */
#define TIOCMSET 0x5418
#define TIOCGSOFTCAR 0x5419
#define TIOCSSOFTCAR 0x541A
-#define TIOCINQ 0x541B
+#define FIONREAD 0x541B
+#define TIOCINQ FIONREAD
struct winsize {
unsigned short ws_row;
#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 */
#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
#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);
typedef unsigned int size_t;
#endif
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
#define CLOCKS_PER_SEC 100
typedef long clock_t;
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);
#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
#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__
#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) \
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
#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);
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
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;
* 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;
* 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, ...)
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,
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));
--- /dev/null
+ .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
$(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
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
.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
pushl $_do_general_protection
jmp error_code
+_alignment_check:
+ pushl $_do_alignment_check
+ jmp error_code
+
### 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
extern struct request request[NR_REQUEST];
extern struct task_struct * wait_for_request;
+extern int * blk_size[NR_BLK_DEV];
+
#ifdef MAJOR_NR
/*
/* 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)
#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)
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) { \
{ 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),
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) {
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);
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.
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")
}
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);
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);
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);
}
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");
CURRENT->buffer += 512;
CURRENT->sector++;
if (--CURRENT->nr_sectors) {
- do_hd = &read_intr;
+ SET_INTR(&read_intr);
return;
}
end_request(1);
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;
}
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;
}
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();
{ 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();
* 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)
{
(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();
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;
-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:
### 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
* Hopefully this will be a rather complete VT102 implementation.
*
* Beeping thanks to John T Kohl.
+ *
+ * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
+ * Chars, and VT100 enhancements by Peter MacDonald.
*/
/*
#include <linux/sched.h>
#include <linux/tty.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+
#include <asm/io.h>
#include <asm/system.h>
+#include <asm/segment.h>
+
+#include <string.h>
+#include <errno.h>
+
+#define DEF_TERMIOS \
+(struct termios) { \
+ ICRNL, \
+ OPOST | ONLCR, \
+ 0, \
+ IXON | ISIG | ICANON | ECHO | ECHOCTL | ECHOKE, \
+ 0, \
+ INIT_C_CC \
+}
+
/*
* These are set up by the setup-routine at boot-time:
#define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004)
#define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff)
#define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8)
-#define ORIG_VIDEO_LINES (25)
+#define ORIG_VIDEO_LINES ((*(unsigned short *)0x9000e) & 0xff)
#define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008)
#define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a)
#define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c)
#define NPAR 16
+int NR_CONSOLES = 0;
+
extern void keyboard_interrupt(void);
static unsigned char video_type; /* Type of display being used */
static unsigned long video_num_columns; /* Number of text columns */
+static unsigned long video_mem_base; /* Base of video memory */
+static unsigned long video_mem_term; /* End of video memory */
static unsigned long video_size_row; /* Bytes per row */
static unsigned long video_num_lines; /* Number of test lines */
static unsigned char video_page; /* Initial video page */
-static unsigned long video_mem_start; /* Start of video RAM */
-static unsigned long video_mem_end; /* End of video RAM (sort of) */
static unsigned short video_port_reg; /* Video register select port */
static unsigned short video_port_val; /* Video register value port */
-static unsigned short video_erase_char; /* Char+Attrib to erase with */
-
-static unsigned long origin; /* Used for EGA/VGA fast scroll */
-static unsigned long scr_end; /* Used for EGA/VGA fast scroll */
-static unsigned long pos;
-static unsigned long x,y;
-static unsigned long top,bottom;
-static unsigned long state=0;
-static unsigned long npar,par[NPAR];
-static unsigned long ques=0;
-static unsigned char attr=0x07;
+static int can_do_colour = 0;
+
+static struct {
+ unsigned short vc_video_erase_char;
+ unsigned char vc_attr;
+ unsigned char vc_def_attr;
+ int vc_bold_attr;
+ unsigned long vc_ques;
+ unsigned long vc_state;
+ unsigned long vc_restate;
+ unsigned long vc_checkin;
+ unsigned long vc_origin; /* Used for EGA/VGA fast scroll */
+ unsigned long vc_scr_end; /* Used for EGA/VGA fast scroll */
+ unsigned long vc_pos;
+ unsigned long vc_x,vc_y;
+ unsigned long vc_top,vc_bottom;
+ unsigned long vc_npar,vc_par[NPAR];
+ unsigned long vc_video_mem_start; /* Start of video RAM */
+ unsigned long vc_video_mem_end; /* End of video RAM (sort of) */
+ unsigned int vc_saved_x;
+ unsigned int vc_saved_y;
+ unsigned int vc_iscolor;
+ char * vc_translate;
+} vc_cons [MAX_CONSOLES];
+
+#define origin (vc_cons[currcons].vc_origin)
+#define scr_end (vc_cons[currcons].vc_scr_end)
+#define pos (vc_cons[currcons].vc_pos)
+#define top (vc_cons[currcons].vc_top)
+#define bottom (vc_cons[currcons].vc_bottom)
+#define x (vc_cons[currcons].vc_x)
+#define y (vc_cons[currcons].vc_y)
+#define state (vc_cons[currcons].vc_state)
+#define restate (vc_cons[currcons].vc_restate)
+#define checkin (vc_cons[currcons].vc_checkin)
+#define npar (vc_cons[currcons].vc_npar)
+#define par (vc_cons[currcons].vc_par)
+#define ques (vc_cons[currcons].vc_ques)
+#define attr (vc_cons[currcons].vc_attr)
+#define saved_x (vc_cons[currcons].vc_saved_x)
+#define saved_y (vc_cons[currcons].vc_saved_y)
+#define translate (vc_cons[currcons].vc_translate)
+#define video_mem_start (vc_cons[currcons].vc_video_mem_start)
+#define video_mem_end (vc_cons[currcons].vc_video_mem_end)
+#define def_attr (vc_cons[currcons].vc_def_attr)
+#define video_erase_char (vc_cons[currcons].vc_video_erase_char)
+#define iscolor (vc_cons[currcons].vc_iscolor)
+
+int blankinterval = 0;
+int blankcount = 0;
static void sysbeep(void);
*/
#define RESPONSE "\033[?1;2c"
+static char * translations[] = {
+/* normal 7-bit ascii */
+ " !\"#$%&'()*+,-./0123456789:;<=>?"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
+ "`abcdefghijklmnopqrstuvwxyz{|}~ ",
+/* vt100 graphics */
+ " !\"#$%&'()*+,-./0123456789:;<=>?"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ "
+ "\004\261\007\007\007\007\370\361\007\007\275\267\326\323\327\304"
+ "\304\304\304\304\307\266\320\322\272\363\362\343\\007\234\007 "
+};
+
+#define NORM_TRANS (translations[0])
+#define GRAF_TRANS (translations[1])
+
/* NOTE! gotoxy thinks x==video_num_columns is ok */
-static inline void gotoxy(unsigned int new_x,unsigned int new_y)
+static inline void gotoxy(int currcons, int new_x,unsigned int new_y)
{
if (new_x > video_num_columns || new_y >= video_num_lines)
return;
- x=new_x;
- y=new_y;
- pos=origin + y*video_size_row + (x<<1);
+ x = new_x;
+ y = new_y;
+ pos = origin + y*video_size_row + (x<<1);
}
-static inline void set_origin(void)
+static inline void set_origin(int currcons)
{
+ if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
+ return;
+ if (currcons != fg_console)
+ return;
cli();
outb_p(12, video_port_reg);
- outb_p(0xff&((origin-video_mem_start)>>9), video_port_val);
+ outb_p(0xff&((origin-video_mem_base)>>9), video_port_val);
outb_p(13, video_port_reg);
- outb_p(0xff&((origin-video_mem_start)>>1), video_port_val);
+ outb_p(0xff&((origin-video_mem_base)>>1), video_port_val);
sti();
}
-static void scrup(void)
+static void scrup(int currcons)
{
+ if (bottom<=top)
+ return;
if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM)
{
if (!top && bottom == video_num_lines) {
"D" (scr_end-video_size_row)
:"cx","di");
}
- set_origin();
+ set_origin(currcons);
} else {
__asm__("cld\n\t"
"rep\n\t"
}
}
-static void scrdown(void)
+static void scrdown(int currcons)
{
+ if (bottom <= top)
+ return;
if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM)
{
__asm__("std\n\t"
}
}
-static void lf(void)
+static void lf(int currcons)
{
if (y+1<bottom) {
y++;
pos += video_size_row;
return;
}
- scrup();
+ scrup(currcons);
}
-static void ri(void)
+static void ri(int currcons)
{
if (y>top) {
y--;
pos -= video_size_row;
return;
}
- scrdown();
+ scrdown(currcons);
}
-static void cr(void)
+static void cr(int currcons)
{
pos -= x<<1;
x=0;
}
-static void del(void)
+static void del(int currcons)
{
if (x) {
pos -= 2;
}
}
-static void csi_J(int par)
+static void csi_J(int currcons, int vpar)
{
long count __asm__("cx");
long start __asm__("di");
- switch (par) {
+ switch (vpar) {
case 0: /* erase from cursor to end of display */
count = (scr_end-pos)>>1;
start = pos;
:"cx","di");
}
-static void csi_K(int par)
+static void csi_K(int currcons, int vpar)
{
long count __asm__("cx");
long start __asm__("di");
- switch (par) {
+ switch (vpar) {
case 0: /* erase from cursor to end of line */
if (x>=video_num_columns)
return;
:"cx","di");
}
-void csi_m(void)
+void csi_m(int currcons )
{
int i;
for (i=0;i<=npar;i++)
switch (par[i]) {
- case 0:attr=0x07;break;
- case 1:attr=0x0f;break;
- case 4:attr=0x0f;break;
- case 7:attr=0x70;break;
- case 27:attr=0x07;break;
+ case 0: attr=def_attr;break; /* default */
+ case 1: attr=(iscolor?attr|0x08:attr|0x0f);break; /* bold */
+ /*case 4: attr=attr|0x01;break;*/ /* underline */
+ case 4: /* bold */
+ if (!iscolor)
+ attr |= 0x01;
+ else
+ { /* check if forground == background */
+ if (vc_cons[currcons].vc_bold_attr != -1)
+ attr = (vc_cons[currcons].vc_bold_attr&0x0f)|(0xf0&(attr));
+ else
+ { short newattr = (attr&0xf0)|(0xf&(~attr));
+ attr = ((newattr&0xf)==((attr>>4)&0xf)?
+ (attr&0xf0)|(((attr&0xf)+1)%0xf):
+ newattr);
+ }
+ }
+ break;
+ case 5: attr=attr|0x80;break; /* blinking */
+ case 7: attr=(attr<<4)|(attr>>4);break; /* negative */
+ case 22: attr=attr&0xf7;break; /* not bold */
+ case 24: attr=attr&0xfe;break; /* not underline */
+ case 25: attr=attr&0x7f;break; /* not blinking */
+ case 27: attr=def_attr;break; /* positive image */
+ case 39: attr=(attr & 0xf0)|(def_attr & 0x0f); break;
+ case 49: attr=(attr & 0x0f)|(def_attr & 0xf0); break;
+ default:
+ if (!can_do_colour)
+ break;
+ iscolor = 1;
+ if ((par[i]>=30) && (par[i]<=38))
+ attr = (attr & 0xf0) | (par[i]-30);
+ else /* Background color */
+ if ((par[i]>=40) && (par[i]<=48))
+ attr = (attr & 0x0f) | ((par[i]-40)<<4);
+ else
+ break;
}
}
-static inline void set_cursor(void)
+static inline void set_cursor(int currcons)
{
+ blankcount = blankinterval;
+ if (currcons != fg_console)
+ return;
cli();
outb_p(14, video_port_reg);
- outb_p(0xff&((pos-video_mem_start)>>9), video_port_val);
+ outb_p(0xff&((pos-video_mem_base)>>9), video_port_val);
outb_p(15, video_port_reg);
- outb_p(0xff&((pos-video_mem_start)>>1), video_port_val);
+ outb_p(0xff&((pos-video_mem_base)>>1), video_port_val);
sti();
}
-static void respond(struct tty_struct * tty)
+static inline void hide_cursor(int currcons)
+{
+ outb_p(14, video_port_reg);
+ outb_p(0xff&((scr_end-video_mem_base)>>9), video_port_val);
+ outb_p(15, video_port_reg);
+ outb_p(0xff&((scr_end-video_mem_base)>>1), video_port_val);
+}
+
+static void respond(int currcons, struct tty_struct * tty)
{
char * p = RESPONSE;
copy_to_cooked(tty);
}
-static void insert_char(void)
+static void insert_char(int currcons)
{
int i=x;
unsigned short tmp, old = video_erase_char;
}
}
-static void insert_line(void)
+static void insert_line(int currcons)
{
int oldtop,oldbottom;
oldbottom=bottom;
top=y;
bottom = video_num_lines;
- scrdown();
+ scrdown(currcons);
top=oldtop;
bottom=oldbottom;
}
-static void delete_char(void)
+static void delete_char(int currcons)
{
int i;
unsigned short * p = (unsigned short *) pos;
*p = video_erase_char;
}
-static void delete_line(void)
+static void delete_line(int currcons)
{
int oldtop,oldbottom;
oldbottom=bottom;
top=y;
bottom = video_num_lines;
- scrup();
+ scrup(currcons);
top=oldtop;
bottom=oldbottom;
}
-static void csi_at(unsigned int nr)
+static void csi_at(int currcons, unsigned int nr)
{
if (nr > video_num_columns)
nr = video_num_columns;
else if (!nr)
nr = 1;
while (nr--)
- insert_char();
+ insert_char(currcons);
}
-static void csi_L(unsigned int nr)
+static void csi_L(int currcons, unsigned int nr)
{
if (nr > video_num_lines)
nr = video_num_lines;
else if (!nr)
nr = 1;
while (nr--)
- insert_line();
+ insert_line(currcons);
}
-static void csi_P(unsigned int nr)
+static void csi_P(int currcons, unsigned int nr)
{
if (nr > video_num_columns)
nr = video_num_columns;
else if (!nr)
nr = 1;
while (nr--)
- delete_char();
+ delete_char(currcons);
}
-static void csi_M(unsigned int nr)
+static void csi_M(int currcons, unsigned int nr)
{
if (nr > video_num_lines)
nr = video_num_lines;
else if (!nr)
nr=1;
while (nr--)
- delete_line();
+ delete_line(currcons);
}
-static int saved_x=0;
-static int saved_y=0;
-
-static void save_cur(void)
+static void save_cur(int currcons)
{
saved_x=x;
saved_y=y;
}
-static void restore_cur(void)
+static void restore_cur(int currcons)
{
- gotoxy(saved_x, saved_y);
+ gotoxy(currcons,saved_x, saved_y);
}
+
+enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
+ ESsetterm, ESsetgraph };
+
void con_write(struct tty_struct * tty)
{
int nr;
char c;
-
+ int currcons;
+
+ currcons = tty - tty_table;
+ if ((currcons>=MAX_CONSOLES) || (currcons<0))
+ panic("con_write: illegal tty");
+
nr = CHARS(tty->write_q);
while (nr--) {
+ if (tty->stopped)
+ break;
GETCH(tty->write_q,c);
+ if (c == 24 || c == 26)
+ state = ESnormal;
switch(state) {
- case 0:
+ case ESnormal:
if (c>31 && c<127) {
if (x>=video_num_columns) {
x -= video_num_columns;
pos -= video_size_row;
- lf();
+ lf(currcons);
}
- __asm__("movb _attr,%%ah\n\t"
+ __asm__("movb %2,%%ah\n\t"
"movw %%ax,%1\n\t"
- ::"a" (c),"m" (*(short *)pos)
+ ::"a" (translate[c-32]),
+ "m" (*(short *)pos),
+ "m" (attr)
:"ax");
pos += 2;
x++;
} else if (c==27)
- state=1;
+ state=ESesc;
else if (c==10 || c==11 || c==12)
- lf();
+ lf(currcons);
else if (c==13)
- cr();
+ cr(currcons);
else if (c==ERASE_CHAR(tty))
- del();
+ del(currcons);
else if (c==8) {
if (x) {
x--;
if (x>video_num_columns) {
x -= video_num_columns;
pos -= video_size_row;
- lf();
+ lf(currcons);
}
c=9;
} else if (c==7)
sysbeep();
+ else if (c == 14)
+ translate = GRAF_TRANS;
+ else if (c == 15)
+ translate = NORM_TRANS;
break;
- case 1:
- state=0;
- if (c=='[')
- state=2;
- else if (c=='E')
- gotoxy(0,y+1);
- else if (c=='M')
- ri();
- else if (c=='D')
- lf();
- else if (c=='Z')
- respond(tty);
- else if (x=='7')
- save_cur();
- else if (x=='8')
- restore_cur();
+ case ESesc:
+ state = ESnormal;
+ switch (c)
+ {
+ case '[':
+ state=ESsquare;
+ break;
+ case 'E':
+ gotoxy(currcons,0,y+1);
+ break;
+ case 'M':
+ ri(currcons);
+ break;
+ case 'D':
+ lf(currcons);
+ break;
+ case 'Z':
+ respond(currcons,tty);
+ break;
+ case '7':
+ save_cur(currcons);
+ break;
+ case '8':
+ restore_cur(currcons);
+ break;
+ case '(': case ')':
+ state = ESsetgraph;
+ break;
+ case 'P':
+ state = ESsetterm;
+ break;
+ case '#':
+ state = -1;
+ break;
+ case 'c':
+ tty->termios = DEF_TERMIOS;
+ state = restate = ESnormal;
+ checkin = 0;
+ top = 0;
+ bottom = video_num_lines;
+ break;
+ /* case '>': Numeric keypad */
+ /* case '=': Appl. keypad */
+ }
break;
- case 2:
+ case ESsquare:
for(npar=0;npar<NPAR;npar++)
par[npar]=0;
npar=0;
- state=3;
+ state=ESgetpars;
+ if (c =='[') /* Function key */
+ { state=ESfunckey;
+ break;
+ }
if (ques=(c=='?'))
break;
- case 3:
+ case ESgetpars:
if (c==';' && npar<NPAR-1) {
npar++;
break;
} else if (c>='0' && c<='9') {
par[npar]=10*par[npar]+c-'0';
break;
- } else state=4;
- case 4:
- state=0;
+ } else state=ESgotpars;
+ case ESgotpars:
+ state = ESnormal;
+ if (ques)
+ { ques =0;
+ break;
+ }
switch(c) {
case 'G': case '`':
if (par[0]) par[0]--;
- gotoxy(par[0],y);
+ gotoxy(currcons,par[0],y);
break;
case 'A':
if (!par[0]) par[0]++;
- gotoxy(x,y-par[0]);
+ gotoxy(currcons,x,y-par[0]);
break;
case 'B': case 'e':
if (!par[0]) par[0]++;
- gotoxy(x,y+par[0]);
+ gotoxy(currcons,x,y+par[0]);
break;
case 'C': case 'a':
if (!par[0]) par[0]++;
- gotoxy(x+par[0],y);
+ gotoxy(currcons,x+par[0],y);
break;
case 'D':
if (!par[0]) par[0]++;
- gotoxy(x-par[0],y);
+ gotoxy(currcons,x-par[0],y);
break;
case 'E':
if (!par[0]) par[0]++;
- gotoxy(0,y+par[0]);
+ gotoxy(currcons,0,y+par[0]);
break;
case 'F':
if (!par[0]) par[0]++;
- gotoxy(0,y-par[0]);
+ gotoxy(currcons,0,y-par[0]);
break;
case 'd':
if (par[0]) par[0]--;
- gotoxy(x,par[0]);
+ gotoxy(currcons,x,par[0]);
break;
case 'H': case 'f':
if (par[0]) par[0]--;
if (par[1]) par[1]--;
- gotoxy(par[1],par[0]);
+ gotoxy(currcons,par[1],par[0]);
break;
case 'J':
- csi_J(par[0]);
+ csi_J(currcons,par[0]);
break;
case 'K':
- csi_K(par[0]);
+ csi_K(currcons,par[0]);
break;
case 'L':
- csi_L(par[0]);
+ csi_L(currcons,par[0]);
break;
case 'M':
- csi_M(par[0]);
+ csi_M(currcons,par[0]);
break;
case 'P':
- csi_P(par[0]);
+ csi_P(currcons,par[0]);
break;
case '@':
- csi_at(par[0]);
+ csi_at(currcons,par[0]);
break;
case 'm':
- csi_m();
+ csi_m(currcons);
break;
case 'r':
if (par[0]) par[0]--;
}
break;
case 's':
- save_cur();
+ save_cur(currcons);
break;
case 'u':
- restore_cur();
+ restore_cur(currcons);
break;
+ case 'l': /* blank interval */
+ case 'b': /* bold attribute */
+ if (!((npar >= 2) &&
+ ((par[1]-13) == par[0]) &&
+ ((par[2]-17) == par[0])))
+ break;
+ if ((c=='l')&&(par[0]>=0)&&(par[0]<=60))
+ {
+ blankinterval = HZ*60*par[0];
+ blankcount = blankinterval;
+ }
+ if (c=='b')
+ vc_cons[currcons].vc_bold_attr
+ = par[0];
}
+ break;
+ case ESfunckey:
+ state = ESnormal;
+ break;
+ case ESsetterm: /* Setterm functions. */
+ state = ESnormal;
+ if (c == 'S') {
+ def_attr = attr;
+ video_erase_char = (video_erase_char&0x0ff) | (def_attr<<8);
+ } else if (c == 'L')
+ ; /*linewrap on*/
+ else if (c == 'l')
+ ; /*linewrap off*/
+ break;
+ case ESsetgraph:
+ state = ESnormal;
+ if (c == '0')
+ translate = GRAF_TRANS;
+ else if (c == 'B')
+ translate = NORM_TRANS;
+ break;
+ default:
+ state = ESnormal;
}
}
- set_cursor();
+ set_cursor(currcons);
}
/*
register unsigned char a;
char *display_desc = "????";
char *display_ptr;
+ int currcons = 0;
+ long base, term;
+ long video_memory;
video_num_columns = ORIG_VIDEO_COLS;
video_size_row = video_num_columns * 2;
video_num_lines = ORIG_VIDEO_LINES;
video_page = ORIG_VIDEO_PAGE;
video_erase_char = 0x0720;
+ blankcount = blankinterval;
- if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
+ if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
{
- video_mem_start = 0xb0000;
+ video_mem_base = 0xb0000;
video_port_reg = 0x3b4;
video_port_val = 0x3b5;
if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
{
video_type = VIDEO_TYPE_EGAM;
- video_mem_end = 0xb8000;
+ video_mem_term = 0xb8000;
display_desc = "EGAm";
}
else
{
video_type = VIDEO_TYPE_MDA;
- video_mem_end = 0xb2000;
+ video_mem_term = 0xb2000;
display_desc = "*MDA";
}
}
- else /* If not, it is color. */
+ else /* If not, it is color. */
{
- video_mem_start = 0xb8000;
+ can_do_colour = 1;
+ video_mem_base = 0xb8000;
video_port_reg = 0x3d4;
video_port_val = 0x3d5;
if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
{
video_type = VIDEO_TYPE_EGAC;
- video_mem_end = 0xbc000;
+ video_mem_term = 0xc0000;
display_desc = "EGAc";
}
else
{
video_type = VIDEO_TYPE_CGA;
- video_mem_end = 0xba000;
+ video_mem_term = 0xba000;
display_desc = "*CGA";
}
}
+ video_memory = video_mem_term - video_mem_base;
+ NR_CONSOLES = video_memory / (video_num_lines * video_size_row);
+ if (NR_CONSOLES > MAX_CONSOLES)
+ NR_CONSOLES = MAX_CONSOLES;
+ if (!NR_CONSOLES)
+ NR_CONSOLES = 1;
+ video_memory /= NR_CONSOLES;
/* Let the user known what kind of display driver we are using */
- display_ptr = ((char *)video_mem_start) + video_size_row - 8;
+ display_ptr = ((char *)video_mem_base) + video_size_row - 8;
while (*display_desc)
{
*display_ptr++ = *display_desc++;
/* Initialize the variables used for scrolling (mostly EGA/VGA) */
- origin = video_mem_start;
+ base = origin = video_mem_start = video_mem_base;
+ term = video_mem_end = base + video_memory;
scr_end = video_mem_start + video_num_lines * video_size_row;
top = 0;
bottom = video_num_lines;
+ attr = 0x07;
+ def_attr = 0x07;
+ restate = state = ESnormal;
+ checkin = 0;
+ ques = 0;
+ iscolor = 0;
+ translate = NORM_TRANS;
+ vc_cons[0].vc_bold_attr = -1;
- gotoxy(ORIG_X,ORIG_Y);
+ gotoxy(currcons,ORIG_X,ORIG_Y);
+ for (currcons = 1; currcons<NR_CONSOLES; currcons++) {
+ vc_cons[currcons] = vc_cons[0];
+ origin = video_mem_start = (base += video_memory);
+ scr_end = origin + video_num_lines * video_size_row;
+ video_mem_end = (term += video_memory);
+ gotoxy(currcons,0,0);
+ }
+ update_screen();
set_trap_gate(0x21,&keyboard_interrupt);
outb_p(inb_p(0x21)&0xfd,0x21);
a=inb_p(0x61);
outb_p(a|0x80,0x61);
- outb(a,0x61);
+ outb_p(a,0x61);
}
+
+void update_screen(void)
+{
+ set_origin(fg_console);
+ set_cursor(fg_console);
+}
+
/* from bsd-net-2: */
void sysbeepstop(void)
/* 1/8 second */
beepcount = HZ/8;
}
+
+int do_screendump(int arg)
+{
+ char *sptr, *buf = (char *)arg;
+ int currcons, l;
+
+ verify_area(buf,video_num_columns*video_num_lines);
+ currcons = get_fs_byte(buf);
+ if ((currcons<1) || (currcons>NR_CONSOLES))
+ return -EIO;
+ currcons--;
+ sptr = (char *) origin;
+ for (l=video_num_lines*video_num_columns; l>0 ; l--)
+ put_fs_byte(*sptr++,buf++);
+ return(0);
+}
+
+void blank_screen()
+{
+ if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
+ return;
+/* blank here. I can't find out how to do it, though */
+}
+
+void unblank_screen()
+{
+ if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
+ return;
+/* unblank here */
+}
+
+void console_print(const char * b)
+{
+ int currcons = fg_console;
+ char c;
+
+ while (c = *(b++)) {
+ if (c == 10) {
+ cr(currcons);
+ lf(currcons);
+ continue;
+ }
+ if (c == 13) {
+ cr(currcons);
+ continue;
+ }
+ if (x>=video_num_columns) {
+ x -= video_num_columns;
+ pos -= video_size_row;
+ lf(currcons);
+ }
+ __asm__("movb %2,%%ah\n\t"
+ "movw %%ax,%1\n\t"
+ ::"a" (c),
+ "m" (*(short *)pos),
+ "m" (attr)
+ :"ax");
+ pos += 2;
+ x++;
+ }
+ set_cursor(currcons);
+}
* 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
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
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
* 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
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
--- /dev/null
+/*
+ * 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);
+}
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
{
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);
}
{
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();
}
* 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
* or rs-channels. It also implements echoing, cooked mode etc.
*
- * Kill-line thanks to John T Kohl.
+ * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
*/
+
#include <ctype.h>
#include <errno.h>
#include <signal.h>
+#include <unistd.h>
#define ALRMMASK (1<<(SIGALRM-1))
-#define KILLMASK (1<<(SIGKILL-1))
-#define INTMASK (1<<(SIGINT-1))
-#define QUITMASK (1<<(SIGQUIT-1))
-#define TSTPMASK (1<<(SIGTSTP-1))
#include <linux/sched.h>
#include <linux/tty.h>
#include <asm/segment.h>
#include <asm/system.h>
+int kill_pg(int pgrp, int sig, int priv);
+int is_orphaned_pgrp(int pgrp);
+
#define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f)
#define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f)
#define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f)
#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
+#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
#define I_UCLC(tty) _I_FLAG((tty),IUCLC)
#define I_NLCR(tty) _I_FLAG((tty),INLCR)
#define I_CRNL(tty) _I_FLAG((tty),ICRNL)
#define I_NOCR(tty) _I_FLAG((tty),IGNCR)
+#define I_IXON(tty) _I_FLAG((tty),IXON)
#define O_POST(tty) _O_FLAG((tty),OPOST)
#define O_NLCR(tty) _O_FLAG((tty),ONLCR)
#define O_NLRET(tty) _O_FLAG((tty),ONLRET)
#define O_LCUC(tty) _O_FLAG((tty),OLCUC)
-struct tty_struct tty_table[] = {
- {
- {ICRNL, /* change incoming CR to NL */
- OPOST|ONLCR, /* change outgoing NL to CRNL */
- 0,
- ISIG | ICANON | ECHO | ECHOCTL | ECHOKE,
- 0, /* console termio */
- INIT_C_CC},
- 0, /* initial pgrp */
- 0, /* initial stopped */
- con_write,
- {0,0,0,0,""}, /* console read-queue */
- {0,0,0,0,""}, /* console write-queue */
- {0,0,0,0,""} /* console secondary queue */
- },{
- {0, /* no translation */
- 0, /* no translation */
- B2400 | CS8,
- 0,
- 0,
- INIT_C_CC},
- 0,
- 0,
- rs_write,
- {0x3f8,0,0,0,""}, /* rs 1 */
- {0x3f8,0,0,0,""},
- {0,0,0,0,""}
- },{
- {0, /* no translation */
- 0, /* no translation */
- B2400 | CS8,
- 0,
- 0,
- INIT_C_CC},
- 0,
- 0,
- rs_write,
- {0x2f8,0,0,0,""}, /* rs 2 */
- {0x2f8,0,0,0,""},
- {0,0,0,0,""}
- }
-};
+#define C_SPEED(tty) ((tty)->termios.c_cflag & CBAUD)
+#define C_HUP(tty) (C_SPEED((tty)) == B0)
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define QUEUES (3*(MAX_CONSOLES+NR_SERIALS+2*NR_PTYS))
+static struct tty_queue tty_queues[QUEUES];
+struct tty_struct tty_table[256];
+
+#define con_queues tty_queues
+#define rs_queues ((3*MAX_CONSOLES) + tty_queues)
+#define mpty_queues ((3*(MAX_CONSOLES+NR_SERIALS)) + tty_queues)
+#define spty_queues ((3*(MAX_CONSOLES+NR_SERIALS+NR_PTYS)) + tty_queues)
+
+#define con_table tty_table
+#define rs_table (64+tty_table)
+#define mpty_table (128+tty_table)
+#define spty_table (192+tty_table)
+
+int fg_console = 0;
/*
* these are the tables used by the machine code handlers.
- * you can implement pseudo-tty's or something by changing
- * them. Currently not done.
+ * you can implement virtual consoles.
*/
struct tty_queue * table_list[]={
- &tty_table[0].read_q, &tty_table[0].write_q,
- &tty_table[1].read_q, &tty_table[1].write_q,
- &tty_table[2].read_q, &tty_table[2].write_q
+ con_queues + 0, con_queues + 1,
+ rs_queues + 0, rs_queues + 1,
+ rs_queues + 3, rs_queues + 4
};
-void tty_init(void)
+void change_console(unsigned int new_console)
{
- rs_init();
- con_init();
-}
-
-void tty_intr(struct tty_struct * tty, int mask)
-{
- int i;
-
- if (tty->pgrp <= 0)
+ if (new_console == fg_console || new_console >= NR_CONSOLES)
return;
- for (i=0;i<NR_TASKS;i++)
- if (task[i] && task[i]->pgrp==tty->pgrp)
- task[i]->signal |= mask;
+ fg_console = new_console;
+ table_list[0] = con_queues + 0 + fg_console*3;
+ table_list[1] = con_queues + 1 + fg_console*3;
+ update_screen();
}
static void sleep_if_empty(struct tty_queue * queue)
{
cli();
- while (!current->signal && EMPTY(*queue))
+ while (!(current->signal & ~current->blocked) && EMPTY(queue))
interruptible_sleep_on(&queue->proc_list);
sti();
}
static void sleep_if_full(struct tty_queue * queue)
{
- if (!FULL(*queue))
+ if (!FULL(queue))
return;
cli();
- while (!current->signal && LEFT(*queue)<128)
+ while (!(current->signal & ~current->blocked) && LEFT(queue)<128)
interruptible_sleep_on(&queue->proc_list);
sti();
}
void wait_for_keypress(void)
{
- sleep_if_empty(&tty_table[0].secondary);
+ sleep_if_empty(tty_table[fg_console].secondary);
}
void copy_to_cooked(struct tty_struct * tty)
{
signed char c;
- while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) {
+ if (!(tty->read_q || tty->write_q || tty->secondary)) {
+ printk("copy_to_cooked: missing queues\n\r");
+ return;
+ }
+ while (1) {
+ if (EMPTY(tty->read_q))
+ break;
+ if (FULL(tty->secondary))
+ break;
GETCH(tty->read_q,c);
- if (c==13)
+ if (c==13) {
if (I_CRNL(tty))
c=10;
else if (I_NOCR(tty))
continue;
- else ;
- else if (c==10 && I_NLCR(tty))
+ } else if (c==10 && I_NLCR(tty))
c=13;
if (I_UCLC(tty))
c=tolower(c);
if (L_CANON(tty)) {
- if (c==KILL_CHAR(tty)) {
+ if ((KILL_CHAR(tty) != _POSIX_VDISABLE) &&
+ (c==KILL_CHAR(tty))) {
/* deal with killing the input line */
while(!(EMPTY(tty->secondary) ||
(c=LAST(tty->secondary))==10 ||
- c==EOF_CHAR(tty))) {
+ ((EOF_CHAR(tty) != _POSIX_VDISABLE) &&
+ (c==EOF_CHAR(tty))))) {
if (L_ECHO(tty)) {
if (c<32)
PUTCH(127,tty->write_q);
PUTCH(127,tty->write_q);
tty->write(tty);
}
- DEC(tty->secondary.head);
+ DEC(tty->secondary->head);
}
continue;
}
- if (c==ERASE_CHAR(tty)) {
+ if ((ERASE_CHAR(tty) != _POSIX_VDISABLE) &&
+ (c==ERASE_CHAR(tty))) {
if (EMPTY(tty->secondary) ||
(c=LAST(tty->secondary))==10 ||
- c==EOF_CHAR(tty))
+ ((EOF_CHAR(tty) != _POSIX_VDISABLE) &&
+ (c==EOF_CHAR(tty))))
continue;
if (L_ECHO(tty)) {
if (c<32)
PUTCH(127,tty->write_q);
tty->write(tty);
}
- DEC(tty->secondary.head);
+ DEC(tty->secondary->head);
continue;
}
- if (c==STOP_CHAR(tty)) {
+ }
+ if (I_IXON(tty)) {
+ if ((STOP_CHAR(tty) != _POSIX_VDISABLE) &&
+ (c==STOP_CHAR(tty))) {
tty->stopped=1;
+ tty->write(tty);
continue;
}
- if (c==START_CHAR(tty)) {
+ if ((START_CHAR(tty) != _POSIX_VDISABLE) &&
+ (c==START_CHAR(tty))) {
tty->stopped=0;
+ tty->write(tty);
continue;
}
}
if (L_ISIG(tty)) {
- if (c==INTR_CHAR(tty)) {
- tty_intr(tty,INTMASK);
+ if ((INTR_CHAR(tty) != _POSIX_VDISABLE) &&
+ (c==INTR_CHAR(tty))) {
+ kill_pg(tty->pgrp, SIGINT, 1);
+ continue;
+ }
+ if ((QUIT_CHAR(tty) != _POSIX_VDISABLE) &&
+ (c==QUIT_CHAR(tty))) {
+ kill_pg(tty->pgrp, SIGQUIT, 1);
continue;
}
- if (c==QUIT_CHAR(tty)) {
- tty_intr(tty,QUITMASK);
+ if ((SUSPEND_CHAR(tty) != _POSIX_VDISABLE) &&
+ (c==SUSPEND_CHAR(tty))) {
+ if (!is_orphaned_pgrp(tty->pgrp))
+ kill_pg(tty->pgrp, SIGTSTP, 1);
continue;
}
}
- if (c==10 || c==EOF_CHAR(tty))
- tty->secondary.data++;
+ if (c==10 || (EOF_CHAR(tty) != _POSIX_VDISABLE &&
+ c==EOF_CHAR(tty)))
+ tty->secondary->data++;
if (L_ECHO(tty)) {
if (c==10) {
PUTCH(10,tty->write_q);
}
PUTCH(c,tty->secondary);
}
- wake_up(&tty->secondary.proc_list);
+ wake_up(&tty->secondary->proc_list);
+}
+
+/*
+ * Called when we need to send a SIGTTIN or SIGTTOU to our process
+ * group
+ *
+ * We only request that a system call be restarted if there was if the
+ * default signal handler is being used. The reason for this is that if
+ * a job is catching SIGTTIN or SIGTTOU, the signal handler may not want
+ * the system call to be restarted blindly. If there is no way to reset the
+ * terminal pgrp back to the current pgrp (perhaps because the controlling
+ * tty has been released on logout), we don't want to be in an infinite loop
+ * while restarting the system call, and have it always generate a SIGTTIN
+ * or SIGTTOU. The default signal handler will cause the process to stop
+ * thus avoiding the infinite loop problem. Presumably the job-control
+ * cognizant parent will fix things up before continuging its child process.
+ */
+int tty_signal(int sig, struct tty_struct *tty)
+{
+ if (is_orphaned_pgrp(current->pgrp))
+ return -EIO; /* don't stop an orphaned pgrp */
+ (void) kill_pg(current->pgrp,sig,1);
+ if ((current->blocked & (1<<(sig-1))) ||
+ ((int) current->sigaction[sig-1].sa_handler == 1))
+ return -EIO; /* Our signal will be ignored */
+ else if (current->sigaction[sig-1].sa_handler)
+ return -EINTR; /* We _will_ be interrupted :-) */
+ else
+ return -ERESTARTSYS; /* We _will_ be interrupted :-) */
+ /* (but restart after we continue) */
}
int tty_read(unsigned channel, char * buf, int nr)
{
struct tty_struct * tty;
+ struct tty_struct * other_tty = NULL;
char c, * b=buf;
- int minimum,time,flag=0;
- long oldalarm;
+ int minimum,time;
- if (channel>2 || nr<0) return -1;
- tty = &tty_table[channel];
- oldalarm = current->alarm;
+ if (channel > 255)
+ return -EIO;
+ tty = TTY_TABLE(channel);
+ if (!(tty->write_q || tty->read_q || tty->secondary))
+ return -EIO;
+ if ((current->tty == channel) && (tty->pgrp != current->pgrp))
+ return(tty_signal(SIGTTIN, tty));
+ if (channel & 0x80)
+ other_tty = tty_table + (channel ^ 0x40);
time = 10L*tty->termios.c_cc[VTIME];
minimum = tty->termios.c_cc[VMIN];
- if (time && !minimum) {
- minimum=1;
- if (flag=(!oldalarm || time+jiffies<oldalarm))
- current->alarm = time+jiffies;
+ if (L_CANON(tty)) {
+ minimum = nr;
+ current->timeout = 0xffffffff;
+ time = 0;
+ } else if (minimum)
+ current->timeout = 0xffffffff;
+ else {
+ minimum = nr;
+ if (time)
+ current->timeout = time + jiffies;
+ time = 0;
}
if (minimum>nr)
- minimum=nr;
+ minimum = nr;
while (nr>0) {
- if (flag && (current->signal & ALRMMASK)) {
- current->signal &= ~ALRMMASK;
- break;
- }
- if (current->signal)
- break;
+ if (other_tty)
+ other_tty->write(other_tty);
+ cli();
if (EMPTY(tty->secondary) || (L_CANON(tty) &&
- !tty->secondary.data && LEFT(tty->secondary)>20)) {
- sleep_if_empty(&tty->secondary);
+ !FULL(tty->read_q) && !tty->secondary->data)) {
+ if (!current->timeout ||
+ (current->signal & ~current->blocked)) {
+ sti();
+ break;
+ }
+ if (IS_A_PTY_SLAVE(channel) && C_HUP(other_tty))
+ break;
+ interruptible_sleep_on(&tty->secondary->proc_list);
+ sti();
continue;
}
+ sti();
do {
GETCH(tty->secondary,c);
- if (c==EOF_CHAR(tty) || c==10)
- tty->secondary.data--;
- if (c==EOF_CHAR(tty) && L_CANON(tty))
- return (b-buf);
+ if ((EOF_CHAR(tty) != _POSIX_VDISABLE &&
+ c==EOF_CHAR(tty)) || c==10)
+ tty->secondary->data--;
+ if ((EOF_CHAR(tty) != _POSIX_VDISABLE &&
+ c==EOF_CHAR(tty)) && L_CANON(tty))
+ break;
else {
put_fs_byte(c,b++);
if (!--nr)
break;
}
- } while (nr>0 && !EMPTY(tty->secondary));
- if (time && !L_CANON(tty))
- if (flag=(!oldalarm || time+jiffies<oldalarm))
- current->alarm = time+jiffies;
- else
- current->alarm = oldalarm;
- if (L_CANON(tty)) {
- if (b-buf)
+ if (c==10 && L_CANON(tty))
break;
- } else if (b-buf >= minimum)
+ } while (nr>0 && !EMPTY(tty->secondary));
+ wake_up(&tty->read_q->proc_list);
+ if (time)
+ current->timeout = time+jiffies;
+ if (L_CANON(tty) || b-buf >= minimum)
break;
}
- current->alarm = oldalarm;
- if (current->signal && !(b-buf))
- return -EINTR;
+ current->timeout = 0;
+ if ((current->signal & ~current->blocked) && !(b-buf))
+ return -ERESTARTSYS;
return (b-buf);
}
struct tty_struct * tty;
char c, *b=buf;
- if (channel>2 || nr<0) return -1;
- tty = channel + tty_table;
+ if (channel > 255)
+ return -EIO;
+ tty = TTY_TABLE(channel);
+ if (!(tty->write_q || tty->read_q || tty->secondary))
+ return -EIO;
+ if (L_TOSTOP(tty) &&
+ (current->tty == channel) && (tty->pgrp != current->pgrp))
+ return(tty_signal(SIGTTOU, tty));
while (nr>0) {
- sleep_if_full(&tty->write_q);
- if (current->signal)
+ sleep_if_full(tty->write_q);
+ if (current->signal & ~current->blocked)
break;
while (nr>0 && !FULL(tty->write_q)) {
c=get_fs_byte(b);
*/
void do_tty_interrupt(int tty)
{
- copy_to_cooked(tty_table+tty);
+ copy_to_cooked(TTY_TABLE(tty));
}
void chr_dev_init(void)
{
}
+
+void tty_init(void)
+{
+ int i;
+
+ for (i=0 ; i < QUEUES ; i++)
+ tty_queues[i] = (struct tty_queue) {0,0,0,0,""};
+ rs_queues[0] = (struct tty_queue) {0x3f8,0,0,0,""};
+ rs_queues[1] = (struct tty_queue) {0x3f8,0,0,0,""};
+ rs_queues[3] = (struct tty_queue) {0x2f8,0,0,0,""};
+ rs_queues[4] = (struct tty_queue) {0x2f8,0,0,0,""};
+ for (i=0 ; i<256 ; i++) {
+ tty_table[i] = (struct tty_struct) {
+ {0, 0, 0, 0, 0, INIT_C_CC},
+ 0, 0, 0, NULL, NULL, NULL, NULL
+ };
+ }
+ con_init();
+ for (i = 0 ; i<NR_CONSOLES ; i++) {
+ con_table[i] = (struct tty_struct) {
+ {ICRNL, /* change incoming CR to NL */
+ OPOST|ONLCR, /* change outgoing NL to CRNL */
+ 0,
+ IXON | ISIG | ICANON | ECHO | ECHOCTL | ECHOKE,
+ 0, /* console termio */
+ INIT_C_CC},
+ 0, /* initial pgrp */
+ 0, /* initial session */
+ 0, /* initial stopped */
+ con_write,
+ con_queues+0+i*3,con_queues+1+i*3,con_queues+2+i*3
+ };
+ }
+ for (i = 0 ; i<NR_SERIALS ; i++) {
+ rs_table[i] = (struct tty_struct) {
+ {0, /* no translation */
+ 0, /* no translation */
+ B2400 | CS8,
+ 0,
+ 0,
+ INIT_C_CC},
+ 0,
+ 0,
+ 0,
+ rs_write,
+ rs_queues+0+i*3,rs_queues+1+i*3,rs_queues+2+i*3
+ };
+ }
+ for (i = 0 ; i<NR_PTYS ; i++) {
+ mpty_table[i] = (struct tty_struct) {
+ {0, /* no translation */
+ 0, /* no translation */
+ B9600 | CS8,
+ 0,
+ 0,
+ INIT_C_CC},
+ 0,
+ 0,
+ 0,
+ mpty_write,
+ mpty_queues+0+i*3,mpty_queues+1+i*3,mpty_queues+2+i*3
+ };
+ spty_table[i] = (struct tty_struct) {
+ {0, /* no translation */
+ 0, /* no translation */
+ B9600 | CS8,
+ IXON | ISIG | ICANON,
+ 0,
+ INIT_C_CC},
+ 0,
+ 0,
+ 0,
+ spty_write,
+ spty_queues+0+i*3,spty_queues+1+i*3,spty_queues+2+i*3
+ };
+ }
+ rs_init();
+ printk("%d virtual consoles\n\r",NR_CONSOLES);
+ printk("%d pty's\n\r",NR_PTYS);
+}
#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,
{
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();
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);
/*
* 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;
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);
}
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;
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);
* (C) 1991 Linus Torvalds
*/
+#define DEBUG_PROC_TREE
+
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
if (!p)
return;
+ if (p == current) {
+ printk("task releasing itself\n\r");
+ return;
+ }
for (i=1 ; i<NR_TASKS ; i++)
if (task[i]==p) {
task[i]=NULL;
+ /* Update links */
+ if (p->p_osptr)
+ p->p_osptr->p_ysptr = p->p_ysptr;
+ if (p->p_ysptr)
+ p->p_ysptr->p_osptr = p->p_osptr;
+ else
+ p->p_pptr->p_cptr = p->p_osptr;
free_page((long)p);
schedule();
return;
panic("trying to release non-existent task");
}
+#ifdef DEBUG_PROC_TREE
+/*
+ * Check to see if a task_struct pointer is present in the task[] array
+ * Return 0 if found, and 1 if not found.
+ */
+int bad_task_ptr(struct task_struct *p)
+{
+ int i;
+
+ if (!p)
+ return 0;
+ for (i=0 ; i<NR_TASKS ; i++)
+ if (task[i] == p)
+ return 0;
+ return 1;
+}
+
+/*
+ * This routine scans the pid tree and make sure the rep invarient still
+ * holds. Used for debugging only, since it's very slow....
+ *
+ * It looks a lot scarier than it really is.... we're doing ænothing more
+ * than verifying the doubly-linked list foundæin p_ysptr and p_osptr,
+ * and checking it corresponds with the process tree defined by p_cptr and
+ * p_pptr;
+ */
+void audit_ptree()
+{
+ int i;
+
+ for (i=1 ; i<NR_TASKS ; i++) {
+ if (!task[i])
+ continue;
+ if (bad_task_ptr(task[i]->p_pptr))
+ printk("Warning, pid %d's parent link is bad\n",
+ task[i]->pid);
+ if (bad_task_ptr(task[i]->p_cptr))
+ printk("Warning, pid %d's child link is bad\n",
+ task[i]->pid);
+ if (bad_task_ptr(task[i]->p_ysptr))
+ printk("Warning, pid %d's ys link is bad\n",
+ task[i]->pid);
+ if (bad_task_ptr(task[i]->p_osptr))
+ printk("Warning, pid %d's os link is bad\n",
+ task[i]->pid);
+ if (task[i]->p_pptr == task[i])
+ printk("Warning, pid %d parent link points to self\n");
+ if (task[i]->p_cptr == task[i])
+ printk("Warning, pid %d child link points to self\n");
+ if (task[i]->p_ysptr == task[i])
+ printk("Warning, pid %d ys link points to self\n");
+ if (task[i]->p_osptr == task[i])
+ printk("Warning, pid %d os link points to self\n");
+ if (task[i]->p_osptr) {
+ if (task[i]->p_pptr != task[i]->p_osptr->p_pptr)
+ printk(
+ "Warning, pid %d older sibling %d parent is %d\n",
+ task[i]->pid, task[i]->p_osptr->pid,
+ task[i]->p_osptr->p_pptr->pid);
+ if (task[i]->p_osptr->p_ysptr != task[i])
+ printk(
+ "Warning, pid %d older sibling %d has mismatched ys link\n",
+ task[i]->pid, task[i]->p_osptr->pid);
+ }
+ if (task[i]->p_ysptr) {
+ if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr)
+ printk(
+ "Warning, pid %d younger sibling %d parent is %d\n",
+ task[i]->pid, task[i]->p_osptr->pid,
+ task[i]->p_osptr->p_pptr->pid);
+ if (task[i]->p_ysptr->p_osptr != task[i])
+ printk(
+ "Warning, pid %d younger sibling %d has mismatched os link\n",
+ task[i]->pid, task[i]->p_ysptr->pid);
+ }
+ if (task[i]->p_cptr) {
+ if (task[i]->p_cptr->p_pptr != task[i])
+ printk(
+ "Warning, pid %d youngest child %d has mismatched parent link\n",
+ task[i]->pid, task[i]->p_cptr->pid);
+ if (task[i]->p_cptr->p_ysptr)
+ printk(
+ "Warning, pid %d youngest child %d has non-NULL ys link\n",
+ task[i]->pid, task[i]->p_cptr->pid);
+ }
+ }
+}
+#endif /* DEBUG_PROC_TREE */
+
static inline int send_sig(long sig,struct task_struct * p,int priv)
{
- if (!p || sig<1 || sig>32)
+ if (!p)
return -EINVAL;
- if (priv || (current->euid==p->euid) || suser())
- p->signal |= (1<<(sig-1));
- else
+ if (!priv && (current->euid!=p->euid) && !suser())
return -EPERM;
+ if ((sig == SIGKILL) || (sig == SIGCONT)) {
+ if (p->state == TASK_STOPPED)
+ p->state = TASK_RUNNING;
+ p->exit_code = 0;
+ p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
+ (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );
+ }
+ /* If the signal will be ignored, don't even post it */
+ if ((int) p->sigaction[sig-1].sa_handler == 1)
+ return 0;
+ /* Depends on order SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU */
+ if ((sig >= SIGSTOP) && (sig <= SIGTTOU))
+ p->signal &= ~(1<<(SIGCONT-1));
+ /* Actually deliver the signal */
+ p->signal |= (1<<(sig-1));
return 0;
}
-static void kill_session(void)
+int session_of_pgrp(int pgrp)
{
- struct task_struct **p = NR_TASKS + task;
-
- while (--p > &FIRST_TASK) {
- if (*p && (*p)->session == current->session)
- (*p)->signal |= 1<<(SIGHUP-1);
- }
+ struct task_struct **p;
+
+ for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
+ if ((*p)->pgrp == pgrp)
+ return((*p)->session);
+ return -1;
+}
+
+int kill_pg(int pgrp, int sig, int priv)
+{
+ struct task_struct **p;
+ int err,retval = -ESRCH;
+ int found = 0;
+
+ if (sig<1 || sig>32 || pgrp<=0)
+ return -EINVAL;
+ for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
+ if ((*p)->pgrp == pgrp) {
+ if (sig && (err = send_sig(sig,*p,priv)))
+ retval = err;
+ else
+ found++;
+ }
+ return(found ? 0 : retval);
+}
+
+int kill_proc(int pid, int sig, int priv)
+{
+ struct task_struct **p;
+
+ if (sig<1 || sig>32)
+ return -EINVAL;
+ for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
+ if ((*p)->pid == pid)
+ return(sig ? send_sig(sig,*p,priv) : 0);
+ return(-ESRCH);
}
/*
- * XXX need to check permissions needed to send signals to process
- * groups, etc. etc. kill() permissions semantics are tricky!
+ * POSIX specifies that kill(-1,sig) is unspecified, but what we have
+ * is probably wrong. Should make it like BSD or SYSV.
*/
int sys_kill(int pid,int sig)
{
struct task_struct **p = NR_TASKS + task;
int err, retval = 0;
- if (!pid) while (--p > &FIRST_TASK) {
- if (*p && (*p)->pgrp == current->pid)
- if (err=send_sig(sig,*p,1))
- retval = err;
- } else if (pid>0) while (--p > &FIRST_TASK) {
- if (*p && (*p)->pid == pid)
- if (err=send_sig(sig,*p,0))
- retval = err;
- } else if (pid == -1) while (--p > &FIRST_TASK)
- if (err = send_sig(sig,*p,0))
- retval = err;
- else while (--p > &FIRST_TASK)
- if (*p && (*p)->pgrp == -pid)
+ if (!pid)
+ return(kill_pg(current->pid,sig,0));
+ if (pid == -1) {
+ while (--p > &FIRST_TASK)
if (err = send_sig(sig,*p,0))
retval = err;
- return retval;
+ return(retval);
+ }
+ if (pid < 0)
+ return(kill_pg(-pid,sig,0));
+ /* Normal kill */
+ return(kill_proc(pid,sig,0));
}
-static void tell_father(int pid)
+/*
+ * Determine if a process group is "orphaned", according to the POSIX
+ * definition in 2.2.2.52. Orphaned process groups are not to be affected
+ * by terminal-generated stop signals. Newly orphaned process groups are
+ * to receive a SIGHUP and a SIGCONT.
+ *
+ * "I ask you, have you ever known what it is to be an orphan?"
+ */
+int is_orphaned_pgrp(int pgrp)
{
- int i;
+ struct task_struct **p;
- if (pid)
- for (i=0;i<NR_TASKS;i++) {
- if (!task[i])
- continue;
- if (task[i]->pid != pid)
- continue;
- task[i]->signal |= (1<<(SIGCHLD-1));
- return;
- }
-/* if we don't find any fathers, we just release ourselves */
-/* This is not really OK. Must change it to make father 1 */
- printk("BAD BAD - no father found\n\r");
- release(current);
+ for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
+ if (!(*p) ||
+ ((*p)->pgrp != pgrp) ||
+ ((*p)->state == TASK_ZOMBIE) ||
+ ((*p)->p_pptr->pid == 1))
+ continue;
+ if (((*p)->p_pptr->pgrp != pgrp) &&
+ ((*p)->p_pptr->session == (*p)->session))
+ return 0;
+ }
+ return(1); /* (sighing) "Often!" */
+}
+
+static int has_stopped_jobs(int pgrp)
+{
+ struct task_struct ** p;
+
+ for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
+ if ((*p)->pgrp != pgrp)
+ continue;
+ if ((*p)->state == TASK_STOPPED)
+ return(1);
+ }
+ return(0);
}
-int do_exit(long code)
+volatile void do_exit(long code)
{
+ struct task_struct *p;
int i;
free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
- for (i=0 ; i<NR_TASKS ; i++)
- if (task[i] && task[i]->father == current->pid) {
- task[i]->father = 1;
- if (task[i]->state == TASK_ZOMBIE)
- /* assumption task[1] is always init */
- (void) send_sig(SIGCHLD, task[1], 1);
- }
for (i=0 ; i<NR_OPEN ; i++)
if (current->filp[i])
sys_close(i);
iput(current->pwd);
- current->pwd=NULL;
+ current->pwd = NULL;
iput(current->root);
- current->root=NULL;
+ current->root = NULL;
iput(current->executable);
- current->executable=NULL;
- if (current->leader && current->tty >= 0)
- tty_table[current->tty].pgrp = 0;
- if (last_task_used_math == current)
- last_task_used_math = NULL;
- if (current->leader)
- kill_session();
+ current->executable = NULL;
+ iput(current->library);
+ current->library = NULL;
current->state = TASK_ZOMBIE;
current->exit_code = code;
- tell_father(current->father);
+ /*
+ * Check to see if any process groups have become orphaned
+ * as a result of our exiting, and if they have any stopped
+ * jobs, send them a SIGUP and then a SIGCONT. (POSIX 3.2.2.2)
+ *
+ * Case i: Our father is in a different pgrp than we are
+ * and we were the only connection outside, so our pgrp
+ * is about to become orphaned.
+ */
+ if ((current->p_pptr->pgrp != current->pgrp) &&
+ (current->p_pptr->session == current->session) &&
+ is_orphaned_pgrp(current->pgrp) &&
+ has_stopped_jobs(current->pgrp)) {
+ kill_pg(current->pgrp,SIGHUP,1);
+ kill_pg(current->pgrp,SIGCONT,1);
+ }
+ /* Let father know we died */
+ current->p_pptr->signal |= (1<<(SIGCHLD-1));
+
+ /*
+ * This loop does two things:
+ *
+ * A. Make init inherit all the child processes
+ * B. Check to see if any process groups have become orphaned
+ * as a result of our exiting, and if they have any stopped
+ * jons, send them a SIGUP and then a SIGCONT. (POSIX 3.2.2.2)
+ */
+ if (p = current->p_cptr) {
+ while (1) {
+ p->p_pptr = task[1];
+ if (p->state == TASK_ZOMBIE)
+ task[1]->signal |= (1<<(SIGCHLD-1));
+ /*
+ * process group orphan check
+ * Case ii: Our child is in a different pgrp
+ * than we are, and it was the only connection
+ * outside, so the child pgrp is now orphaned.
+ */
+ if ((p->pgrp != current->pgrp) &&
+ (p->session == current->session) &&
+ is_orphaned_pgrp(p->pgrp) &&
+ has_stopped_jobs(p->pgrp)) {
+ kill_pg(p->pgrp,SIGHUP,1);
+ kill_pg(p->pgrp,SIGCONT,1);
+ }
+ if (p->p_osptr) {
+ p = p->p_osptr;
+ continue;
+ }
+ /*
+ * This is it; link everything into init's children
+ * and leave
+ */
+ p->p_osptr = task[1]->p_cptr;
+ task[1]->p_cptr->p_ysptr = p;
+ task[1]->p_cptr = current->p_cptr;
+ current->p_cptr = 0;
+ break;
+ }
+ }
+ if (current->leader) {
+ struct task_struct **p;
+ struct tty_struct *tty;
+
+ if (current->tty >= 0) {
+ tty = TTY_TABLE(current->tty);
+ if (tty->pgrp>0)
+ kill_pg(tty->pgrp, SIGHUP, 1);
+ tty->pgrp = 0;
+ tty->session = 0;
+ }
+ for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
+ if ((*p)->session == current->session)
+ (*p)->tty = -1;
+ }
+ if (last_task_used_math == current)
+ last_task_used_math = NULL;
+#ifdef DEBUG_PROC_TREE
+ audit_ptree();
+#endif
schedule();
- return (-1); /* just to suppress warnings */
}
int sys_exit(int error_code)
{
- return do_exit((error_code&0xff)<<8);
+ do_exit((error_code&0xff)<<8);
}
int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
{
- int flag, code;
- struct task_struct ** p;
+ int flag;
+ struct task_struct *p;
+ unsigned long oldblocked;
verify_area(stat_addr,4);
repeat:
flag=0;
- for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
- if (!*p || *p == current)
- continue;
- if ((*p)->father != current->pid)
- continue;
+ for (p = current->p_cptr ; p ; p = p->p_osptr) {
if (pid>0) {
- if ((*p)->pid != pid)
+ if (p->pid != pid)
continue;
} else if (!pid) {
- if ((*p)->pgrp != current->pgrp)
+ if (p->pgrp != current->pgrp)
continue;
} else if (pid != -1) {
- if ((*p)->pgrp != -pid)
+ if (p->pgrp != -pid)
continue;
}
- switch ((*p)->state) {
+ switch (p->state) {
case TASK_STOPPED:
- if (!(options & WUNTRACED))
+ if (!(options & WUNTRACED) ||
+ !p->exit_code)
continue;
- put_fs_long(0x7f,stat_addr);
- return (*p)->pid;
+ put_fs_long((p->exit_code << 8) | 0x7f,
+ stat_addr);
+ p->exit_code = 0;
+ return p->pid;
case TASK_ZOMBIE:
- current->cutime += (*p)->utime;
- current->cstime += (*p)->stime;
- flag = (*p)->pid;
- code = (*p)->exit_code;
- release(*p);
- put_fs_long(code,stat_addr);
+ current->cutime += p->utime;
+ current->cstime += p->stime;
+ flag = p->pid;
+ put_fs_long(p->exit_code, stat_addr);
+ release(p);
+#ifdef DEBUG_PROC_TREE
+ audit_ptree();
+#endif
return flag;
default:
flag=1;
if (options & WNOHANG)
return 0;
current->state=TASK_INTERRUPTIBLE;
+ oldblocked = current->blocked;
+ current->blocked &= ~(1<<(SIGCHLD-1));
schedule();
- if (!(current->signal &= ~(1<<(SIGCHLD-1))))
- goto repeat;
+ current->blocked = oldblocked;
+ if (current->signal & ~(current->blocked | (1<<(SIGCHLD-1))))
+ return -ERESTARTSYS;
else
- return -EINTR;
+ goto repeat;
}
return -ECHILD;
}
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);
* 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)
{
*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;
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);
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;
}
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;
$(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)
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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * linux/kernel/math/convert.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+#include <linux/math_emu.h>
+
+/*
+ * NOTE!!! There is some "non-obvious" optimisations in the temp_to_long
+ * and temp_to_short conversion routines: don't touch them if you don't
+ * know what's going on. They are the adding of one in the rounding: the
+ * overflow bit is also used for adding one into the exponent. Thus it
+ * looks like the overflow would be incorrectly handled, but due to the
+ * way the IEEE numbers work, things are correct.
+ *
+ * There is no checking for total overflow in the conversions, though (ie
+ * if the temp-real number simply won't fit in a short- or long-real.)
+ */
+
+void short_to_temp(const short_real * a, temp_real * b)
+{
+ if (!(*a & 0x7fffffff)) {
+ b->a = b->b = 0;
+ if (*a)
+ b->exponent = 0x8000;
+ else
+ b->exponent = 0;
+ return;
+ }
+ b->exponent = ((*a>>23) & 0xff)-127+16383;
+ if (*a<0)
+ b->exponent |= 0x8000;
+ b->b = (*a<<8) | 0x80000000;
+ b->a = 0;
+}
+
+void long_to_temp(const long_real * a, temp_real * b)
+{
+ if (!a->a && !(a->b & 0x7fffffff)) {
+ b->a = b->b = 0;
+ if (a->b)
+ b->exponent = 0x8000;
+ else
+ b->exponent = 0;
+ return;
+ }
+ b->exponent = ((a->b >> 20) & 0x7ff)-1023+16383;
+ if (a->b<0)
+ b->exponent |= 0x8000;
+ b->b = 0x80000000 | (a->b<<11) | (((unsigned long)a->a)>>21);
+ b->a = a->a<<11;
+}
+
+void temp_to_short(const temp_real * a, short_real * b)
+{
+ if (!(a->exponent & 0x7fff)) {
+ *b = (a->exponent)?0x80000000:0;
+ return;
+ }
+ *b = ((((long) a->exponent)-16383+127) << 23) & 0x7f800000;
+ if (a->exponent < 0)
+ *b |= 0x80000000;
+ *b |= (a->b >> 8) & 0x007fffff;
+ switch (ROUNDING) {
+ case ROUND_NEAREST:
+ if ((a->b & 0xff) > 0x80)
+ ++*b;
+ break;
+ case ROUND_DOWN:
+ if ((a->exponent & 0x8000) && (a->b & 0xff))
+ ++*b;
+ break;
+ case ROUND_UP:
+ if (!(a->exponent & 0x8000) && (a->b & 0xff))
+ ++*b;
+ break;
+ }
+}
+
+void temp_to_long(const temp_real * a, long_real * b)
+{
+ if (!(a->exponent & 0x7fff)) {
+ b->a = 0;
+ b->b = (a->exponent)?0x80000000:0;
+ return;
+ }
+ b->b = (((0x7fff & (long) a->exponent)-16383+1023) << 20) & 0x7ff00000;
+ if (a->exponent < 0)
+ b->b |= 0x80000000;
+ b->b |= (a->b >> 11) & 0x000fffff;
+ b->a = a->b << 21;
+ b->a |= (a->a >> 11) & 0x001fffff;
+ switch (ROUNDING) {
+ case ROUND_NEAREST:
+ if ((a->a & 0x7ff) > 0x400)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ case ROUND_DOWN:
+ if ((a->exponent & 0x8000) && (a->b & 0xff))
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ case ROUND_UP:
+ if (!(a->exponent & 0x8000) && (a->b & 0xff))
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ }
+}
+
+void real_to_int(const temp_real * a, temp_int * b)
+{
+ int shift = 16383 + 63 - (a->exponent & 0x7fff);
+ unsigned long underflow;
+
+ b->a = b->b = underflow = 0;
+ b->sign = (a->exponent < 0);
+ if (shift < 0) {
+ set_OE();
+ return;
+ }
+ if (shift < 32) {
+ b->b = a->b; b->a = a->a;
+ } else if (shift < 64) {
+ b->a = a->b; underflow = a->a;
+ shift -= 32;
+ } else if (shift < 96) {
+ underflow = a->b;
+ shift -= 64;
+ } else
+ return;
+ __asm__("shrdl %2,%1,%0"
+ :"=r" (underflow),"=r" (b->a)
+ :"c" ((char) shift),"0" (underflow),"1" (b->a));
+ __asm__("shrdl %2,%1,%0"
+ :"=r" (b->a),"=r" (b->b)
+ :"c" ((char) shift),"0" (b->a),"1" (b->b));
+ __asm__("shrl %1,%0"
+ :"=r" (b->b)
+ :"c" ((char) shift),"0" (b->b));
+ switch (ROUNDING) {
+ case ROUND_NEAREST:
+ __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b)
+ ,"r" (0x7fffffff + (b->a & 1))
+ ,"m" (*&underflow));
+ break;
+ case ROUND_UP:
+ if (!b->sign && underflow)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ case ROUND_DOWN:
+ if (b->sign && underflow)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ }
+}
+
+void int_to_real(const temp_int * a, temp_real * b)
+{
+ b->a = a->a;
+ b->b = a->b;
+ if (b->a || b->b)
+ b->exponent = 16383 + 63 + (a->sign? 0x8000:0);
+ else {
+ b->exponent = 0;
+ return;
+ }
+ while (b->b >= 0) {
+ b->exponent--;
+ __asm__("addl %0,%0 ; adcl %1,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ }
+}
--- /dev/null
+/*
+ * 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];
+}
--- /dev/null
+/*
+ * linux/kernel/math/ea.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * Calculate the effective address.
+ */
+
+#include <stddef.h>
+
+#include <linux/math_emu.h>
+#include <asm/segment.h>
+
+static int __regoffset[] = {
+ offsetof(struct info,___eax),
+ offsetof(struct info,___ecx),
+ offsetof(struct info,___edx),
+ offsetof(struct info,___ebx),
+ offsetof(struct info,___esp),
+ offsetof(struct info,___ebp),
+ offsetof(struct info,___esi),
+ offsetof(struct info,___edi)
+};
+
+#define REG(x) (*(long *)(__regoffset[(x)]+(char *) info))
+
+static char * sib(struct info * info, int mod)
+{
+ unsigned char ss,index,base;
+ long offset = 0;
+
+ base = get_fs_byte((char *) EIP);
+ EIP++;
+ ss = base >> 6;
+ index = (base >> 3) & 7;
+ base &= 7;
+ if (index == 4)
+ offset = 0;
+ else
+ offset = REG(index);
+ offset <<= ss;
+ if (mod || base != 5)
+ offset += REG(base);
+ if (mod == 1) {
+ offset += (signed char) get_fs_byte((char *) EIP);
+ EIP++;
+ } else if (mod == 2 || base == 5) {
+ offset += (signed) get_fs_long((unsigned long *) EIP);
+ EIP += 4;
+ }
+ I387.foo = offset;
+ I387.fos = 0x17;
+ return (char *) offset;
+}
+
+char * ea(struct info * info, unsigned short code)
+{
+ unsigned char mod,rm;
+ long * tmp = &EAX;
+ int offset = 0;
+
+ mod = (code >> 6) & 3;
+ rm = code & 7;
+ if (rm == 4 && mod != 3)
+ return sib(info,mod);
+ if (rm == 5 && !mod) {
+ offset = get_fs_long((unsigned long *) EIP);
+ EIP += 4;
+ I387.foo = offset;
+ I387.fos = 0x17;
+ return (char *) offset;
+ }
+ tmp = & REG(rm);
+ switch (mod) {
+ case 0: offset = 0; break;
+ case 1:
+ offset = (signed char) get_fs_byte((char *) EIP);
+ EIP++;
+ break;
+ case 2:
+ offset = (signed) get_fs_long((unsigned long *) EIP);
+ EIP += 4;
+ break;
+ case 3:
+ math_abort(info,1<<(SIGILL-1));
+ }
+ I387.foo = offset;
+ I387.fos = 0x17;
+ return offset + (char *) *tmp;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * linux/kernel/math/get_put.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * This file handles all accesses to user memory: getting and putting
+ * ints/reals/BCD etc. This is the only part that concerns itself with
+ * other than temporary real format. All other cals are strictly temp_real.
+ */
+#include <signal.h>
+
+#include <linux/math_emu.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+
+void get_short_real(temp_real * tmp,
+ struct info * info, unsigned short code)
+{
+ char * addr;
+ short_real sr;
+
+ addr = ea(info,code);
+ sr = get_fs_long((unsigned long *) addr);
+ short_to_temp(&sr,tmp);
+}
+
+void get_long_real(temp_real * tmp,
+ struct info * info, unsigned short code)
+{
+ char * addr;
+ long_real lr;
+
+ addr = ea(info,code);
+ lr.a = get_fs_long((unsigned long *) addr);
+ lr.b = get_fs_long(1 + (unsigned long *) addr);
+ long_to_temp(&lr,tmp);
+}
+
+void get_temp_real(temp_real * tmp,
+ struct info * info, unsigned short code)
+{
+ char * addr;
+
+ addr = ea(info,code);
+ tmp->a = get_fs_long((unsigned long *) addr);
+ tmp->b = get_fs_long(1 + (unsigned long *) addr);
+ tmp->exponent = get_fs_word(4 + (unsigned short *) addr);
+}
+
+void get_short_int(temp_real * tmp,
+ struct info * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ ti.a = (signed short) get_fs_word((unsigned short *) addr);
+ ti.b = 0;
+ if (ti.sign = (ti.a < 0))
+ ti.a = - ti.a;
+ int_to_real(&ti,tmp);
+}
+
+void get_long_int(temp_real * tmp,
+ struct info * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ ti.a = get_fs_long((unsigned long *) addr);
+ ti.b = 0;
+ if (ti.sign = (ti.a < 0))
+ ti.a = - ti.a;
+ int_to_real(&ti,tmp);
+}
+
+void get_longlong_int(temp_real * tmp,
+ struct info * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ ti.a = get_fs_long((unsigned long *) addr);
+ ti.b = get_fs_long(1 + (unsigned long *) addr);
+ if (ti.sign = (ti.b < 0))
+ __asm__("notl %0 ; notl %1\n\t"
+ "addl $1,%0 ; adcl $0,%1"
+ :"=r" (ti.a),"=r" (ti.b)
+ :"0" (ti.a),"1" (ti.b));
+ int_to_real(&ti,tmp);
+}
+
+#define MUL10(low,high) \
+__asm__("addl %0,%0 ; adcl %1,%1\n\t" \
+"movl %0,%%ecx ; movl %1,%%ebx\n\t" \
+"addl %0,%0 ; adcl %1,%1\n\t" \
+"addl %0,%0 ; adcl %1,%1\n\t" \
+"addl %%ecx,%0 ; adcl %%ebx,%1" \
+:"=a" (low),"=d" (high) \
+:"0" (low),"1" (high):"cx","bx")
+
+#define ADD64(val,low,high) \
+__asm__("addl %4,%0 ; adcl $0,%1":"=r" (low),"=r" (high) \
+:"0" (low),"1" (high),"r" ((unsigned long) (val)))
+
+void get_BCD(temp_real * tmp, struct info * info, unsigned short code)
+{
+ int k;
+ char * addr;
+ temp_int i;
+ unsigned char c;
+
+ addr = ea(info,code);
+ addr += 9;
+ i.sign = 0x80 & get_fs_byte(addr--);
+ i.a = i.b = 0;
+ for (k = 0; k < 9; k++) {
+ c = get_fs_byte(addr--);
+ MUL10(i.a, i.b);
+ ADD64((c>>4), i.a, i.b);
+ MUL10(i.a, i.b);
+ ADD64((c&0xf), i.a, i.b);
+ }
+ int_to_real(&i,tmp);
+}
+
+void put_short_real(const temp_real * tmp,
+ struct info * info, unsigned short code)
+{
+ char * addr;
+ short_real sr;
+
+ addr = ea(info,code);
+ verify_area(addr,4);
+ temp_to_short(tmp,&sr);
+ put_fs_long(sr,(unsigned long *) addr);
+}
+
+void put_long_real(const temp_real * tmp,
+ struct info * info, unsigned short code)
+{
+ char * addr;
+ long_real lr;
+
+ addr = ea(info,code);
+ verify_area(addr,8);
+ temp_to_long(tmp,&lr);
+ put_fs_long(lr.a, (unsigned long *) addr);
+ put_fs_long(lr.b, 1 + (unsigned long *) addr);
+}
+
+void put_temp_real(const temp_real * tmp,
+ struct info * info, unsigned short code)
+{
+ char * addr;
+
+ addr = ea(info,code);
+ verify_area(addr,10);
+ put_fs_long(tmp->a, (unsigned long *) addr);
+ put_fs_long(tmp->b, 1 + (unsigned long *) addr);
+ put_fs_word(tmp->exponent, 4 + (short *) addr);
+}
+
+void put_short_int(const temp_real * tmp,
+ struct info * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ real_to_int(tmp,&ti);
+ verify_area(addr,2);
+ if (ti.sign)
+ ti.a = -ti.a;
+ put_fs_word(ti.a,(short *) addr);
+}
+
+void put_long_int(const temp_real * tmp,
+ struct info * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ real_to_int(tmp,&ti);
+ verify_area(addr,4);
+ if (ti.sign)
+ ti.a = -ti.a;
+ put_fs_long(ti.a,(unsigned long *) addr);
+}
+
+void put_longlong_int(const temp_real * tmp,
+ struct info * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ real_to_int(tmp,&ti);
+ verify_area(addr,8);
+ if (ti.sign)
+ __asm__("notl %0 ; notl %1\n\t"
+ "addl $1,%0 ; adcl $0,%1"
+ :"=r" (ti.a),"=r" (ti.b)
+ :"0" (ti.a),"1" (ti.b));
+ put_fs_long(ti.a,(unsigned long *) addr);
+ put_fs_long(ti.b,1 + (unsigned long *) addr);
+}
+
+#define DIV10(low,high,rem) \
+__asm__("divl %6 ; xchgl %1,%2 ; divl %6" \
+ :"=d" (rem),"=a" (low),"=b" (high) \
+ :"0" (0),"1" (high),"2" (low),"c" (10))
+
+void put_BCD(const temp_real * tmp,struct info * info, unsigned short code)
+{
+ int k,rem;
+ char * addr;
+ temp_int i;
+ unsigned char c;
+
+ addr = ea(info,code);
+ verify_area(addr,10);
+ real_to_int(tmp,&i);
+ if (i.sign)
+ put_fs_byte(0x80, addr+9);
+ else
+ put_fs_byte(0, addr+9);
+ for (k = 0; k < 9; k++) {
+ DIV10(i.a,i.b,rem);
+ c = rem;
+ DIV10(i.a,i.b,rem);
+ c += rem<<4;
+ put_fs_byte(c,addr++);
+ }
+}
*/
/*
- * This directory should contain the math-emulation code.
- * Currently only results in a signal.
+ * Limited emulation 27.12.91 - mostly loads/stores, which gcc wants
+ * even for soft-float, unless you use bruce evans' patches. The patches
+ * are great, but they have to be re-applied for every version, and the
+ * library is different for soft-float and 80387. So emulation is more
+ * practical, even though it's slower.
+ *
+ * 28.12.91 - loads/stores work, even BCD. I'll have to start thinking
+ * about add/sub/mul/div. Urgel. I should find some good source, but I'll
+ * just fake up something.
+ *
+ * 30.12.91 - add/sub/mul/div/com seem to work mostly. I should really
+ * test every possible combination.
+ */
+
+/*
+ * This file is full of ugly macros etc: one problem was that gcc simply
+ * didn't want to make the structures as they should be: it has to try to
+ * align them. Sickening code, but at least I've hidden the ugly things
+ * in this one file: the other files don't need to know about these things.
+ *
+ * The other files also don't care about ST(x) etc - they just get addresses
+ * to 80-bit temporary reals, and do with them as they please. I wanted to
+ * hide most of the 387-specific things here.
*/
#include <signal.h>
-#include <linux/sched.h>
+#define __ALIGNED_TEMP_REAL 1
+#include <linux/math_emu.h>
#include <linux/kernel.h>
#include <asm/segment.h>
-void math_emulate(long edi, long esi, long ebp, long sys_call_ret,
- long eax,long ebx,long ecx,long edx,
- unsigned short fs,unsigned short es,unsigned short ds,
- unsigned long eip,unsigned short cs,unsigned long eflags,
- unsigned short ss, unsigned long esp)
+#define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
+#define ST(x) (*__st((x)))
+#define PST(x) ((const temp_real *) __st((x)))
+
+/*
+ * We don't want these inlined - it gets too messy in the machine-code.
+ */
+static void fpop(void);
+static void fpush(void);
+static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b);
+static temp_real_unaligned * __st(int i);
+
+static void do_emu(struct info * info)
{
- unsigned char first, second;
+ unsigned short code;
+ temp_real tmp;
+ char * address;
+ if (I387.cwd & I387.swd & 0x3f)
+ I387.swd |= 0x8000;
+ else
+ I387.swd &= 0x7fff;
+ ORIG_EIP = EIP;
/* 0x0007 means user code space */
- if (cs != 0x000F) {
- printk("math_emulate: %04x:%08x\n\r",cs,eip);
+ if (CS != 0x000F) {
+ printk("math_emulate: %04x:%08x\n\r",CS,EIP);
panic("Math emulation needed in kernel");
}
- first = get_fs_byte((char *)((*&eip)++));
- second = get_fs_byte((char *)((*&eip)++));
- printk("%04x:%08x %02x %02x\n\r",cs,eip-2,first,second);
- current->signal |= 1<<(SIGFPE-1);
+ code = get_fs_word((unsigned short *) EIP);
+ bswapw(code);
+ code &= 0x7ff;
+ I387.fip = EIP;
+ *(unsigned short *) &I387.fcs = CS;
+ *(1+(unsigned short *) &I387.fcs) = code;
+ EIP += 2;
+ switch (code) {
+ case 0x1d0: /* fnop */
+ return;
+ case 0x1d1: case 0x1d2: case 0x1d3:
+ case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
+ math_abort(info,1<<(SIGILL-1));
+ case 0x1e0:
+ ST(0).exponent ^= 0x8000;
+ return;
+ case 0x1e1:
+ ST(0).exponent &= 0x7fff;
+ return;
+ case 0x1e2: case 0x1e3:
+ math_abort(info,1<<(SIGILL-1));
+ case 0x1e4:
+ ftst(PST(0));
+ return;
+ case 0x1e5:
+ printk("fxam not implemented\n\r");
+ math_abort(info,1<<(SIGILL-1));
+ case 0x1e6: case 0x1e7:
+ math_abort(info,1<<(SIGILL-1));
+ case 0x1e8:
+ fpush();
+ ST(0) = CONST1;
+ return;
+ case 0x1e9:
+ fpush();
+ ST(0) = CONSTL2T;
+ return;
+ case 0x1ea:
+ fpush();
+ ST(0) = CONSTL2E;
+ return;
+ case 0x1eb:
+ fpush();
+ ST(0) = CONSTPI;
+ return;
+ case 0x1ec:
+ fpush();
+ ST(0) = CONSTLG2;
+ return;
+ case 0x1ed:
+ fpush();
+ ST(0) = CONSTLN2;
+ return;
+ case 0x1ee:
+ fpush();
+ ST(0) = CONSTZ;
+ return;
+ case 0x1ef:
+ math_abort(info,1<<(SIGILL-1));
+ case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3:
+ case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7:
+ case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb:
+ case 0x1fc: case 0x1fd: case 0x1fe: case 0x1ff:
+ printk("%04x fxxx not implemented\n\r",code + 0xc800);
+ math_abort(info,1<<(SIGILL-1));
+ case 0x2e9:
+ fucom(PST(1),PST(0));
+ fpop(); fpop();
+ return;
+ case 0x3d0: case 0x3d1:
+ return;
+ case 0x3e2:
+ I387.swd &= 0x7f00;
+ return;
+ case 0x3e3:
+ I387.cwd = 0x037f;
+ I387.swd = 0x0000;
+ I387.twd = 0x0000;
+ return;
+ case 0x3e4:
+ return;
+ case 0x6d9:
+ fcom(PST(1),PST(0));
+ fpop(); fpop();
+ return;
+ case 0x7e0:
+ *(short *) &EAX = I387.swd;
+ return;
+ }
+ switch (code >> 3) {
+ case 0x18:
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 0x19:
+ fmul(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 0x1a:
+ fcom(PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 0x1b:
+ fcom(PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ fpop();
+ return;
+ case 0x1c:
+ real_to_real(&ST(code & 7),&tmp);
+ tmp.exponent ^= 0x8000;
+ fadd(PST(0),&tmp,&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 0x1d:
+ ST(0).exponent ^= 0x8000;
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 0x1e:
+ fdiv(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 0x1f:
+ fdiv(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 0x38:
+ fpush();
+ ST(0) = ST((code & 7)+1);
+ return;
+ case 0x39:
+ fxchg(&ST(0),&ST(code & 7));
+ return;
+ case 0x3b:
+ ST(code & 7) = ST(0);
+ fpop();
+ return;
+ case 0x98:
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return;
+ case 0x99:
+ fmul(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return;
+ case 0x9a:
+ fcom(PST(code & 7),PST(0));
+ return;
+ case 0x9b:
+ fcom(PST(code & 7),PST(0));
+ fpop();
+ return;
+ case 0x9c:
+ ST(code & 7).exponent ^= 0x8000;
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return;
+ case 0x9d:
+ real_to_real(&ST(0),&tmp);
+ tmp.exponent ^= 0x8000;
+ fadd(PST(code & 7),&tmp,&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return;
+ case 0x9e:
+ fdiv(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return;
+ case 0x9f:
+ fdiv(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return;
+ case 0xb8:
+ printk("ffree not implemented\n\r");
+ math_abort(info,1<<(SIGILL-1));
+ case 0xb9:
+ fxchg(&ST(0),&ST(code & 7));
+ return;
+ case 0xba:
+ ST(code & 7) = ST(0);
+ return;
+ case 0xbb:
+ ST(code & 7) = ST(0);
+ fpop();
+ return;
+ case 0xbc:
+ fucom(PST(code & 7),PST(0));
+ return;
+ case 0xbd:
+ fucom(PST(code & 7),PST(0));
+ fpop();
+ return;
+ case 0xd8:
+ fadd(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return;
+ case 0xd9:
+ fmul(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return;
+ case 0xda:
+ fcom(PST(code & 7),PST(0));
+ fpop();
+ return;
+ case 0xdc:
+ ST(code & 7).exponent ^= 0x8000;
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return;
+ case 0xdd:
+ real_to_real(&ST(0),&tmp);
+ tmp.exponent ^= 0x8000;
+ fadd(PST(code & 7),&tmp,&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return;
+ case 0xde:
+ fdiv(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return;
+ case 0xdf:
+ fdiv(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return;
+ case 0xf8:
+ printk("ffree not implemented\n\r");
+ math_abort(info,1<<(SIGILL-1));
+ fpop();
+ return;
+ case 0xf9:
+ fxchg(&ST(0),&ST(code & 7));
+ return;
+ case 0xfa:
+ case 0xfb:
+ ST(code & 7) = ST(0);
+ fpop();
+ return;
+ }
+ switch ((code>>3) & 0xe7) {
+ case 0x22:
+ put_short_real(PST(0),info,code);
+ return;
+ case 0x23:
+ put_short_real(PST(0),info,code);
+ fpop();
+ return;
+ case 0x24:
+ address = ea(info,code);
+ for (code = 0 ; code < 7 ; code++) {
+ ((long *) & I387)[code] =
+ get_fs_long((unsigned long *) address);
+ address += 4;
+ }
+ return;
+ case 0x25:
+ address = ea(info,code);
+ *(unsigned short *) &I387.cwd =
+ get_fs_word((unsigned short *) address);
+ return;
+ case 0x26:
+ address = ea(info,code);
+ verify_area(address,28);
+ for (code = 0 ; code < 7 ; code++) {
+ put_fs_long( ((long *) & I387)[code],
+ (unsigned long *) address);
+ address += 4;
+ }
+ return;
+ case 0x27:
+ address = ea(info,code);
+ verify_area(address,2);
+ put_fs_word(I387.cwd,(short *) address);
+ return;
+ case 0x62:
+ put_long_int(PST(0),info,code);
+ return;
+ case 0x63:
+ put_long_int(PST(0),info,code);
+ fpop();
+ return;
+ case 0x65:
+ fpush();
+ get_temp_real(&tmp,info,code);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 0x67:
+ put_temp_real(PST(0),info,code);
+ fpop();
+ return;
+ case 0xa2:
+ put_long_real(PST(0),info,code);
+ return;
+ case 0xa3:
+ put_long_real(PST(0),info,code);
+ fpop();
+ return;
+ case 0xa4:
+ address = ea(info,code);
+ for (code = 0 ; code < 27 ; code++) {
+ ((long *) & I387)[code] =
+ get_fs_long((unsigned long *) address);
+ address += 4;
+ }
+ return;
+ case 0xa6:
+ address = ea(info,code);
+ verify_area(address,108);
+ for (code = 0 ; code < 27 ; code++) {
+ put_fs_long( ((long *) & I387)[code],
+ (unsigned long *) address);
+ address += 4;
+ }
+ I387.cwd = 0x037f;
+ I387.swd = 0x0000;
+ I387.twd = 0x0000;
+ return;
+ case 0xa7:
+ address = ea(info,code);
+ verify_area(address,2);
+ put_fs_word(I387.swd,(short *) address);
+ return;
+ case 0xe2:
+ put_short_int(PST(0),info,code);
+ return;
+ case 0xe3:
+ put_short_int(PST(0),info,code);
+ fpop();
+ return;
+ case 0xe4:
+ fpush();
+ get_BCD(&tmp,info,code);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 0xe5:
+ fpush();
+ get_longlong_int(&tmp,info,code);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 0xe6:
+ put_BCD(PST(0),info,code);
+ fpop();
+ return;
+ case 0xe7:
+ put_longlong_int(PST(0),info,code);
+ fpop();
+ return;
+ }
+ switch (code >> 9) {
+ case 0:
+ get_short_real(&tmp,info,code);
+ break;
+ case 1:
+ get_long_int(&tmp,info,code);
+ break;
+ case 2:
+ get_long_real(&tmp,info,code);
+ break;
+ case 4:
+ get_short_int(&tmp,info,code);
+ }
+ switch ((code>>3) & 0x27) {
+ case 0:
+ fadd(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 1:
+ fmul(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 2:
+ fcom(&tmp,PST(0));
+ return;
+ case 3:
+ fcom(&tmp,PST(0));
+ fpop();
+ return;
+ case 4:
+ tmp.exponent ^= 0x8000;
+ fadd(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 5:
+ ST(0).exponent ^= 0x8000;
+ fadd(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 6:
+ fdiv(PST(0),&tmp,&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
+ case 7:
+ fdiv(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
+ }
+ if ((code & 0x138) == 0x100) {
+ fpush();
+ real_to_real(&tmp,&ST(0));
+ return;
+ }
+ printk("Unknown math-insns: %04x:%08x %04x\n\r",CS,EIP,code);
+ math_abort(info,1<<(SIGFPE-1));
+}
+
+void math_emulate(long ___false)
+{
+ if (!current->used_math) {
+ current->used_math = 1;
+ I387.cwd = 0x037f;
+ I387.swd = 0x0000;
+ I387.twd = 0x0000;
+ }
+/* &___false points to info->___orig_eip, so subtract 1 to get info */
+ do_emu((struct info *) ((&___false) - 1));
+}
+
+void __math_abort(struct info * info, unsigned int signal)
+{
+ EIP = ORIG_EIP;
+ current->signal |= signal;
+ __asm__("movl %0,%%esp ; ret"::"g" ((long) info));
+}
+
+static void fpop(void)
+{
+ unsigned long tmp;
+
+ tmp = I387.swd & 0xffffc7ff;
+ I387.swd += 0x00000800;
+ I387.swd &= 0x00003800;
+ I387.swd |= tmp;
+}
+
+static void fpush(void)
+{
+ unsigned long tmp;
+
+ tmp = I387.swd & 0xffffc7ff;
+ I387.swd += 0x00003800;
+ I387.swd &= 0x00003800;
+ I387.swd |= tmp;
+}
+
+static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b)
+{
+ temp_real_unaligned c;
+
+ c = *a;
+ *a = *b;
+ *b = c;
}
-void math_error(void)
+static temp_real_unaligned * __st(int i)
{
- __asm__("fnclex");
- if (last_task_used_math)
- last_task_used_math->signal |= 1<<(SIGFPE-1);
+ i += I387.swd >> 11;
+ i &= 7;
+ return (temp_real_unaligned *) (i*10 + (char *)(I387.st_space));
}
--- /dev/null
+/*
+ * linux/kernel/math/mul.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * temporary real multiplication routine.
+ */
+
+#include <linux/math_emu.h>
+
+static void shift(int * c)
+{
+ __asm__("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 mul64(const temp_real * a, const temp_real * b, int * c)
+{
+ __asm__("movl (%0),%%eax\n\t"
+ "mull (%1)\n\t"
+ "movl %%eax,(%2)\n\t"
+ "movl %%edx,4(%2)\n\t"
+ "movl 4(%0),%%eax\n\t"
+ "mull 4(%1)\n\t"
+ "movl %%eax,8(%2)\n\t"
+ "movl %%edx,12(%2)\n\t"
+ "movl (%0),%%eax\n\t"
+ "mull 4(%1)\n\t"
+ "addl %%eax,4(%2)\n\t"
+ "adcl %%edx,8(%2)\n\t"
+ "adcl $0,12(%2)\n\t"
+ "movl 4(%0),%%eax\n\t"
+ "mull (%1)\n\t"
+ "addl %%eax,4(%2)\n\t"
+ "adcl %%edx,8(%2)\n\t"
+ "adcl $0,12(%2)"
+ ::"b" ((long) a),"c" ((long) b),"D" ((long) c)
+ :"ax","dx");
+}
+
+void fmul(const temp_real * src1, const temp_real * src2, temp_real * result)
+{
+ int i,sign;
+ int tmp[4] = {0,0,0,0};
+
+ sign = (src1->exponent ^ src2->exponent) & 0x8000;
+ i = (src1->exponent & 0x7fff) + (src2->exponent & 0x7fff) - 16383 + 1;
+ if (i<0) {
+ result->exponent = sign;
+ result->a = result->b = 0;
+ return;
+ }
+ if (i>0x7fff) {
+ set_OE();
+ return;
+ }
+ mul64(src1,src2,tmp);
+ if (tmp[0] || tmp[1] || tmp[2] || tmp[3])
+ while (i && tmp[3] >= 0) {
+ i--;
+ shift(tmp);
+ }
+ else
+ i = 0;
+ result->exponent = i | sign;
+ result->a = tmp[2];
+ result->b = tmp[3];
+}
va_start(args, fmt);
i=vsprintf(buf,fmt,args);
va_end(args);
- __asm__("push %%fs\n\t"
- "push %%ds\n\t"
- "pop %%fs\n\t"
- "pushl %0\n\t"
- "pushl $_buf\n\t"
- "pushl $0\n\t"
- "call _tty_write\n\t"
- "addl $8,%%esp\n\t"
- "popl %0\n\t"
- "pop %%fs"
- ::"r" (i):"ax","cx","dx");
+ console_print(buf);
return i;
}
{
int i,j = 4096-sizeof(struct task_struct);
- printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state);
+ printk("%d: pid=%d, state=%d, father=%d, child=%d, ",nr,p->pid,
+ p->state, p->p_pptr->pid, p->p_cptr ? p->p_cptr->pid : -1);
i=0;
while (i<j && !((char *)(p+1))[i])
i++;
- printk("%d (of %d) chars free in kernel stack\n\r",i,j);
+ printk("%d/%d chars free in kstack\n\r",i,j);
+ printk(" PC=%08X.", *(1019 + (unsigned long *) p));
+ if (p->p_ysptr || p->p_osptr)
+ printk(" Younger sib=%d, older sib=%d\n\r",
+ p->p_ysptr ? p->p_ysptr->pid : -1,
+ p->p_osptr ? p->p_osptr->pid : -1);
+ else
+ printk("\n\r");
}
-void show_stat(void)
+void show_state(void)
{
int i;
+ printk("\rTask-info:\n\r");
for (i=0;i<NR_TASKS;i++)
if (task[i])
show_task(i,task[i]);
static union task_union init_task = {INIT_TASK,};
-long volatile jiffies=0;
-long startup_time=0;
+unsigned long volatile jiffies=0;
+unsigned long startup_time=0;
+int jiffies_offset = 0; /* # clock ticks to add to get "true
+ time". Should always be less than
+ 1 second's worth. For time fanatics
+ who like to syncronize their machines
+ to WWV :-) */
+
struct task_struct *current = &(init_task.task);
struct task_struct *last_task_used_math = NULL;
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p) {
+ if ((*p)->timeout && (*p)->timeout < jiffies) {
+ (*p)->timeout = 0;
+ if ((*p)->state == TASK_INTERRUPTIBLE)
+ (*p)->state = TASK_RUNNING;
+ }
if ((*p)->alarm && (*p)->alarm < jiffies) {
- (*p)->signal |= (1<<(SIGALRM-1));
- (*p)->alarm = 0;
- }
+ (*p)->signal |= (1<<(SIGALRM-1));
+ (*p)->alarm = 0;
+ }
if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
(*p)->state==TASK_INTERRUPTIBLE)
(*p)->state=TASK_RUNNING;
return 0;
}
-void sleep_on(struct task_struct **p)
+static inline void __sleep_on(struct task_struct **p, int state)
{
struct task_struct *tmp;
panic("task[0] trying to sleep");
tmp = *p;
*p = current;
- current->state = TASK_UNINTERRUPTIBLE;
- schedule();
- if (tmp)
+ current->state = state;
+repeat: schedule();
+ if (*p && *p != current) {
+ (**p).state = 0;
+ current->state = TASK_UNINTERRUPTIBLE;
+ goto repeat;
+ }
+ if (!*p)
+ printk("Warning: *P = NULL\n\r");
+ if (*p = tmp)
tmp->state=0;
}
void interruptible_sleep_on(struct task_struct **p)
{
- struct task_struct *tmp;
+ __sleep_on(p,TASK_INTERRUPTIBLE);
+}
- if (!p)
- return;
- if (current == &(init_task.task))
- panic("task[0] trying to sleep");
- tmp=*p;
- *p=current;
-repeat: current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (*p && *p != current) {
- (**p).state=0;
- goto repeat;
- }
- *p=NULL;
- if (tmp)
- tmp->state=0;
+void sleep_on(struct task_struct **p)
+{
+ __sleep_on(p,TASK_UNINTERRUPTIBLE);
}
void wake_up(struct task_struct **p)
{
if (p && *p) {
+ if ((**p).state == TASK_STOPPED)
+ printk("wake_up: TASK_STOPPED");
+ if ((**p).state == TASK_ZOMBIE)
+ printk("wake_up: TASK_ZOMBIE");
(**p).state=0;
- *p=NULL;
}
}
void do_timer(long cpl)
{
- extern int beepcount;
- extern void sysbeepstop(void);
+ static int blanked = 0;
+
+ if (blankcount || !blankinterval) {
+ if (blanked)
+ unblank_screen();
+ if (blankcount)
+ blankcount--;
+ blanked = 0;
+ } else if (!blanked) {
+ blank_screen();
+ blanked = 1;
+ }
+ if (hd_timeout)
+ if (!--hd_timeout)
+ hd_times_out();
if (beepcount)
if (!--beepcount)
int sys_getppid(void)
{
- return current->father;
+ return current->p_pptr->pid;
}
int sys_getuid(void)
#include <asm/segment.h>
#include <signal.h>
-
-volatile void do_exit(int error_code);
-
+#include <errno.h>
+
int sys_sgetmask()
{
return current->blocked;
{
int old=current->blocked;
- current->blocked = newmask & ~(1<<(SIGKILL-1));
+ current->blocked = newmask & ~(1<<(SIGKILL-1)) & ~(1<<(SIGSTOP-1));
return old;
}
+int sys_sigpending(sigset_t *set)
+{
+ /* fill in "set" with signals pending but blocked. */
+ verify_area(set,4);
+ put_fs_long(current->blocked & current->signal, (unsigned long *)set);
+ return 0;
+}
+
+/* atomically swap in the new signal mask, and wait for a signal.
+ *
+ * we need to play some games with syscall restarting. We get help
+ * from the syscall library interface. Note that we need to coordinate
+ * the calling convention with the libc routine.
+ *
+ * "set" is just the sigmask as described in 1003.1-1988, 3.3.7.
+ * It is assumed that sigset_t can be passed as a 32 bit quantity.
+ *
+ * "restart" holds a restart indication. If it's non-zero, then we
+ * install the old mask, and return normally. If it's zero, we store
+ * the current mask in old_mask and block until a signal comes in.
+ */
+int sys_sigsuspend(int restart, unsigned long old_mask, unsigned long set)
+{
+ extern int sys_pause(void);
+
+ if (restart) {
+ /* we're restarting */
+ current->blocked = old_mask;
+ return -EINTR;
+ }
+ /* we're not restarting. do the work */
+ *(&restart) = 1;
+ *(&old_mask) = current->blocked;
+ current->blocked = set;
+ (void) sys_pause(); /* return after a signal arrives */
+ return -ERESTARTNOINTR; /* handle the signal, and come back */
+}
+
static inline void save_old(char * from,char * to)
{
int i;
{
struct sigaction tmp;
- if (signum<1 || signum>32 || signum==SIGKILL)
- return -1;
+ if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
+ return -EINVAL;
tmp.sa_handler = (void (*)(int)) handler;
tmp.sa_mask = 0;
tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
{
struct sigaction tmp;
- if (signum<1 || signum>32 || signum==SIGKILL)
- return -1;
+ if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
+ return -EINVAL;
tmp = current->sigaction[signum-1];
get_new((char *) action,
(char *) (signum-1+current->sigaction));
return 0;
}
-void do_signal(long signr,long eax, long ebx, long ecx, long edx,
+/*
+ * Routine writes a core dump image in the current directory.
+ * Currently not implemented.
+ */
+int core_dump(long signr)
+{
+ return(0); /* We didn't do a dump */
+}
+
+int do_signal(long signr,long eax,long ebx, long ecx, long edx, long orig_eax,
long fs, long es, long ds,
long eip, long cs, long eflags,
unsigned long * esp, long ss)
long old_eip=eip;
struct sigaction * sa = current->sigaction + signr - 1;
int longs;
+
unsigned long * tmp_esp;
+#ifdef notdef
+ printk("pid: %d, signr: %x, eax=%d, oeax = %d, int=%d\n",
+ current->pid, signr, eax, orig_eax,
+ sa->sa_flags & SA_INTERRUPT);
+#endif
+ if ((orig_eax != -1) &&
+ ((eax == -ERESTARTSYS) || (eax == -ERESTARTNOINTR))) {
+ if ((eax == -ERESTARTSYS) && ((sa->sa_flags & SA_INTERRUPT) ||
+ signr < SIGCONT || signr > SIGTTOU))
+ *(&eax) = -EINTR;
+ else {
+ *(&eax) = orig_eax;
+ *(&eip) = old_eip -= 2;
+ }
+ }
sa_handler = (unsigned long) sa->sa_handler;
if (sa_handler==1)
- return;
+ return(1); /* Ignore, see if there are more signals... */
if (!sa_handler) {
- if (signr==SIGCHLD)
- return;
- else
- do_exit(1<<(signr-1));
+ switch (signr) {
+ case SIGCONT:
+ case SIGCHLD:
+ return(1); /* Ignore, ... */
+
+ case SIGSTOP:
+ case SIGTSTP:
+ case SIGTTIN:
+ case SIGTTOU:
+ current->state = TASK_STOPPED;
+ current->exit_code = signr;
+ if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
+ SA_NOCLDSTOP))
+ current->p_pptr->signal |= (1<<(SIGCHLD-1));
+ return(1); /* Reschedule another event */
+
+ case SIGQUIT:
+ case SIGILL:
+ case SIGTRAP:
+ case SIGIOT:
+ case SIGFPE:
+ case SIGSEGV:
+ if (core_dump(signr))
+ do_exit(signr|0x80);
+ /* fall through */
+ default:
+ do_exit(signr);
+ }
}
+ /*
+ * OK, we're invoking a handler
+ */
if (sa->sa_flags & SA_ONESHOT)
sa->sa_handler = NULL;
*(&eip) = sa_handler;
put_fs_long(eflags,tmp_esp++);
put_fs_long(old_eip,tmp_esp++);
current->blocked |= sa->sa_mask;
+ return(0); /* Continue, execute handler */
}
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/kernel.h>
+#include <linux/config.h>
#include <asm/segment.h>
#include <sys/times.h>
#include <sys/utsname.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <string.h>
+
+/*
+ * The timezone where the local system is located. Used as a default by some
+ * programs who obtain this value by using gettimeofday.
+ */
+struct timezone sys_tz = { 0, 0};
+
+extern int session_of_pgrp(int pgrp);
int sys_ftime()
{
return -ENOSYS;
}
+/*
+ * This is done BSD-style, with no consideration of the saved gid, except
+ * that if you set the effective gid, it sets the saved gid too. This
+ * makes it possible for a setgid program to completely drop its privileges,
+ * which is often a useful assertion to make when you are doing a security
+ * audit over a program.
+ *
+ * The general idea is that a program which uses just setregid() will be
+ * 100% compatible with BSD. A program which uses just setgid() will be
+ * 100% compatible with POSIX w/ Saved ID's.
+ */
int sys_setregid(int rgid, int egid)
{
if (rgid>0) {
if (egid>0) {
if ((current->gid == egid) ||
(current->egid == egid) ||
- (current->sgid == egid) ||
- suser())
+ suser()) {
current->egid = egid;
- else
+ current->sgid = egid;
+ } else
return(-EPERM);
}
return 0;
}
+/*
+ * setgid() is implemeneted like SysV w/ SAVED_IDS
+ */
int sys_setgid(int gid)
{
- return(sys_setregid(gid, gid));
+ if (suser())
+ current->gid = current->egid = current->sgid = gid;
+ else if ((gid == current->gid) || (gid == current->sgid))
+ current->egid = gid;
+ else
+ return -EPERM;
+ return 0;
}
int sys_acct()
/*
* Unprivileged users may change the real user id to the effective uid
- * or vice versa.
+ * or vice versa. (BSD-style)
+ *
+ * When you set the effective uid, it sets the saved uid too. This
+ * makes it possible for a setuid program to completely drop its privileges,
+ * which is often a useful assertion to make when you are doing a security
+ * audit over a program.
+ *
+ * The general idea is that a program which uses just setreuid() will be
+ * 100% compatible with BSD. A program which uses just setuid() will be
+ * 100% compatible with POSIX w/ Saved ID's.
*/
int sys_setreuid(int ruid, int euid)
{
if (euid>0) {
if ((old_ruid == euid) ||
(current->euid == euid) ||
- suser())
+ suser()) {
current->euid = euid;
- else {
+ current->suid = euid;
+ } else {
current->uid = old_ruid;
return(-EPERM);
}
return 0;
}
+/*
+ * setuid() is implemeneted like SysV w/ SAVED_IDS
+ *
+ * Note that SAVED_ID's is deficient in that a setuid root program
+ * like sendmail, for example, cannot set its uid to be a normal
+ * user and then switch back, because if you're root, setuid() sets
+ * the saved uid too. If you don't like this, blame the bright people
+ * in the POSIX commmittee and/or USG. Note that the BSD-style setreuid()
+ * will allow a root program to temporarily drop privileges and be able to
+ * regain them by swapping the real and effective uid.
+ */
int sys_setuid(int uid)
{
- return(sys_setreuid(uid, uid));
+ if (suser())
+ current->uid = current->euid = current->suid = uid;
+ else if ((uid == current->uid) || (uid == current->suid))
+ current->euid = uid;
+ else
+ return -EPERM;
+ return(0);
}
int sys_stime(long * tptr)
if (!suser())
return -EPERM;
startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ;
+ jiffies_offset = 0;
return 0;
}
* This needs some heave checking ...
* I just haven't get the stomach for it. I also don't fully
* understand sessions/pgrp etc. Let somebody who does explain it.
+ *
+ * OK, I think I have the protection semantics right.... this is really
+ * only important on a multi-user system anyway, to make sure one user
+ * can't send a signal to a process owned by another. -TYT, 12/12/91
*/
int sys_setpgid(int pid, int pgid)
{
- int i;
+ int i;
if (!pid)
pid = current->pid;
if (!pgid)
pgid = current->pid;
+ if (pgid < 0)
+ return -EINVAL;
for (i=0 ; i<NR_TASKS ; i++)
- if (task[i] && task[i]->pid==pid) {
+ if (task[i] && (task[i]->pid == pid) &&
+ ((task[i]->p_pptr == current) ||
+ (task[i] == current))) {
if (task[i]->leader)
return -EPERM;
- if (task[i]->session != current->session)
+ if ((task[i]->session != current->session) ||
+ ((pgid != pid) &&
+ (session_of_pgrp(pgid) != current->session)))
return -EPERM;
task[i]->pgrp = pgid;
return 0;
return current->pgrp;
}
+/*
+ * Supplementary group ID's
+ */
+int sys_getgroups(int gidsetsize, gid_t *grouplist)
+{
+ int i;
+
+ if (gidsetsize)
+ verify_area(grouplist, sizeof(gid_t) * gidsetsize);
+
+ for (i = 0; (i < NGROUPS) && (current->groups[i] != NOGROUP);
+ i++, grouplist++) {
+ if (gidsetsize) {
+ if (i >= gidsetsize)
+ return -EINVAL;
+ put_fs_word(current->groups[i], (short *) grouplist);
+ }
+ }
+ return(i);
+}
+
+int sys_setgroups(int gidsetsize, gid_t *grouplist)
+{
+ int i;
+
+ if (!suser())
+ return -EPERM;
+ if (gidsetsize > NGROUPS)
+ return -EINVAL;
+ for (i = 0; i < gidsetsize; i++, grouplist++) {
+ current->groups[i] = get_fs_word((unsigned short *) grouplist);
+ }
+ if (i < NGROUPS)
+ current->groups[i] = NOGROUP;
+ return 0;
+}
+
+int in_group_p(gid_t grp)
+{
+ int i;
+
+ if (grp == current->egid)
+ return 1;
+
+ for (i = 0; i < NGROUPS; i++) {
+ if (current->groups[i] == NOGROUP)
+ break;
+ if (current->groups[i] == grp)
+ return 1;
+ }
+ return 0;
+}
+
+static struct utsname thisname = {
+ UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION, UTS_MACHINE
+};
+
int sys_uname(struct utsname * name)
{
- static struct utsname thisname = {
- "linux .0","nodename","release ","version ","machine "
- };
int i;
if (!name) return -ERROR;
return 0;
}
+/*
+ * Only sethostname; gethostname can be implemented by calling uname()
+ */
+int sys_sethostname(char *name, int len)
+{
+ int i;
+
+ if (!suser())
+ return -EPERM;
+ if (len > MAXHOSTNAMELEN)
+ return -EINVAL;
+ for (i=0; i < len; i++) {
+ if ((thisname.nodename[i] = get_fs_byte(name+i)) == 0)
+ break;
+ }
+ if (thisname.nodename[i]) {
+ thisname.nodename[i>MAXHOSTNAMELEN ? MAXHOSTNAMELEN : i] = 0;
+ }
+ return 0;
+}
+
+int sys_getrlimit(int resource, struct rlimit *rlim)
+{
+ if (resource >= RLIM_NLIMITS)
+ return -EINVAL;
+ verify_area(rlim,sizeof *rlim);
+ put_fs_long(current->rlim[resource].rlim_cur,
+ (unsigned long *) rlim);
+ put_fs_long(current->rlim[resource].rlim_max,
+ ((unsigned long *) rlim)+1);
+ return 0;
+}
+
+int sys_setrlimit(int resource, struct rlimit *rlim)
+{
+ struct rlimit new, *old;
+
+ if (resource >= RLIM_NLIMITS)
+ return -EINVAL;
+ old = current->rlim + resource;
+ new.rlim_cur = get_fs_long((unsigned long *) rlim);
+ new.rlim_max = get_fs_long(((unsigned long *) rlim)+1);
+ if (((new.rlim_cur > old->rlim_max) ||
+ (new.rlim_max > old->rlim_max)) &&
+ !suser())
+ return -EPERM;
+ *old = new;
+ return 0;
+}
+
+/*
+ * It would make sense to put struct rusuage in the task_struct,
+ * except that would make the task_struct be *really big*. After
+ * task_struct gets moved into malloc'ed memory, it would
+ * make sense to do this. It will make moving the rest of the information
+ * a lot simpler! (Which we're not doing right now because we're not
+ * measuring them yet).
+ */
+int sys_getrusage(int who, struct rusage *ru)
+{
+ struct rusage r;
+ unsigned long *lp, *lpend, *dest;
+
+ if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
+ return -EINVAL;
+ verify_area(ru, sizeof *ru);
+ memset((char *) &r, 0, sizeof(r));
+ if (who == RUSAGE_SELF) {
+ r.ru_utime.tv_sec = CT_TO_SECS(current->utime);
+ r.ru_utime.tv_usec = CT_TO_USECS(current->utime);
+ r.ru_stime.tv_sec = CT_TO_SECS(current->stime);
+ r.ru_stime.tv_usec = CT_TO_USECS(current->stime);
+ } else {
+ r.ru_utime.tv_sec = CT_TO_SECS(current->cutime);
+ r.ru_utime.tv_usec = CT_TO_USECS(current->cutime);
+ r.ru_stime.tv_sec = CT_TO_SECS(current->cstime);
+ r.ru_stime.tv_usec = CT_TO_USECS(current->cstime);
+ }
+ lp = (unsigned long *) &r;
+ lpend = (unsigned long *) (&r+1);
+ dest = (unsigned long *) ru;
+ for (; lp < lpend; lp++, dest++)
+ put_fs_long(*lp, dest);
+ return(0);
+}
+
+int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ if (tv) {
+ verify_area(tv, sizeof *tv);
+ put_fs_long(startup_time + CT_TO_SECS(jiffies+jiffies_offset),
+ (unsigned long *) tv);
+ put_fs_long(CT_TO_USECS(jiffies+jiffies_offset),
+ ((unsigned long *) tv)+1);
+ }
+ if (tz) {
+ verify_area(tz, sizeof *tz);
+ put_fs_long(sys_tz.tz_minuteswest, (unsigned long *) tz);
+ put_fs_long(sys_tz.tz_dsttime, ((unsigned long *) tz)+1);
+ }
+ return 0;
+}
+
+/*
+ * The first time we set the timezone, we will warp the clock so that
+ * it is ticking GMT time instead of local time. Presumably,
+ * if someone is setting the timezone then we are running in an
+ * environment where the programs understand about timezones.
+ * This should be done at boot time in the /etc/rc script, as
+ * soon as possible, so that the clock can be set right. Otherwise,
+ * various programs will get confused when the clock gets warped.
+ */
+int sys_settimeofday(struct timeval *tv, struct timezone *tz)
+{
+ static int firsttime = 1;
+ void adjust_clock();
+
+ if (!suser())
+ return -EPERM;
+ if (tz) {
+ sys_tz.tz_minuteswest = get_fs_long((unsigned long *) tz);
+ sys_tz.tz_dsttime = get_fs_long(((unsigned long *) tz)+1);
+ if (firsttime) {
+ firsttime = 0;
+ if (!tv)
+ adjust_clock();
+ }
+ }
+ if (tv) {
+ int sec, usec;
+
+ sec = get_fs_long((unsigned long *)tv);
+ usec = get_fs_long(((unsigned long *)tv)+1);
+
+ startup_time = sec - jiffies/HZ;
+ jiffies_offset = usec * HZ / 1000000 - jiffies%HZ;
+ }
+ return 0;
+}
+
+/*
+ * Adjust the time obtained from the CMOS to be GMT time instead of
+ * local time.
+ *
+ * This is ugly, but preferable to the alternatives. Otherwise we
+ * would either need to write a program to do it in /etc/rc (and risk
+ * confusion if the program gets run more than once; it would also be
+ * hard to make the program warp the clock precisely n hours) or
+ * compile in the timezone information into the kernel. Bad, bad....
+ *
+ * XXX Currently does not adjust for daylight savings time. May not
+ * need to do anything, depending on how smart (dumb?) the BIOS
+ * is. Blast it all.... the best thing to do not depend on the CMOS
+ * clock at all, but get the time via NTP or timed if you're on a
+ * network.... - TYT, 1/1/92
+ */
+void adjust_clock()
+{
+ startup_time += sys_tz.tz_minuteswest*60;
+}
+
int sys_umask(int mask)
{
int old = current->umask;
current->umask = mask & 0777;
return (old);
}
+
--- /dev/null
+/*
+ * linux/kernel/system_call.s
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * system_call.s contains the system-call low-level handling routines.
+ * This also contains the timer-interrupt handler, as some of the code is
+ * the same. The hd- and flopppy-interrupts are also here.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call. Ordinary interrupts
+ * don't handle signal-recognition, as that would clutter them up totally
+ * unnecessarily.
+ *
+ * Stack layout in 'ret_from_system_call':
+ *
+ * 0(%esp) - %eax
+ * 4(%esp) - %ebx
+ * 8(%esp) - %ecx
+ * C(%esp) - %edx
+ * 10(%esp) - original %eax (-1 if not system call)
+ * 14(%esp) - %fs
+ * 18(%esp) - %es
+ * 1C(%esp) - %ds
+ * 20(%esp) - %eip
+ * 24(%esp) - %cs
+ * 28(%esp) - %eflags
+ * 2C(%esp) - %oldesp
+ * 30(%esp) - %oldss
+ */
+
+SIG_CHLD = 17
+
+EAX = 0x00
+EBX = 0x04
+ECX = 0x08
+EDX = 0x0C
+ORIG_EAX = 0x10
+FS = 0x14
+ES = 0x18
+DS = 0x1C
+EIP = 0x20
+CS = 0x24
+EFLAGS = 0x28
+OLDESP = 0x2C
+OLDSS = 0x30
+
+state = 0 # these are offsets into the task-struct.
+counter = 4
+priority = 8
+signal = 12
+sigaction = 16 # MUST be 16 (=len of sigaction)
+blocked = (33*16)
+
+# offsets within sigaction
+sa_handler = 0
+sa_mask = 4
+sa_flags = 8
+sa_restorer = 12
+
+nr_system_calls = 82
+
+ENOSYS = 38
+
+/*
+ * Ok, I get parallel printer interrupts while using the floppy for some
+ * strange reason. Urgel. Now I just ignore them.
+ */
+.globl _system_call,_sys_fork,_timer_interrupt,_sys_execve
+.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt
+.globl _device_not_available, _coprocessor_error
+
+.align 2
+bad_sys_call:
+ pushl $-ENOSYS
+ jmp ret_from_sys_call
+.align 2
+reschedule:
+ pushl $ret_from_sys_call
+ jmp _schedule
+.align 2
+_system_call:
+ push %ds
+ push %es
+ push %fs
+ pushl %eax # save the orig_eax
+ pushl %edx
+ pushl %ecx # push %ebx,%ecx,%edx as parameters
+ pushl %ebx # to the system call
+ movl $0x10,%edx # set up ds,es to kernel space
+ mov %dx,%ds
+ mov %dx,%es
+ movl $0x17,%edx # fs points to local data space
+ mov %dx,%fs
+ cmpl _NR_syscalls,%eax
+ jae bad_sys_call
+ call _sys_call_table(,%eax,4)
+ pushl %eax
+2:
+ movl _current,%eax
+ cmpl $0,state(%eax) # state
+ jne reschedule
+ cmpl $0,counter(%eax) # counter
+ je reschedule
+ret_from_sys_call:
+ movl _current,%eax
+ cmpl _task,%eax # task[0] cannot have signals
+ je 3f
+ cmpw $0x0f,CS(%esp) # was old code segment supervisor ?
+ jne 3f
+ cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
+ jne 3f
+ movl signal(%eax),%ebx
+ movl blocked(%eax),%ecx
+ notl %ecx
+ andl %ebx,%ecx
+ bsfl %ecx,%ecx
+ je 3f
+ btrl %ecx,%ebx
+ movl %ebx,signal(%eax)
+ incl %ecx
+ pushl %ecx
+ call _do_signal
+ popl %ecx
+ testl %eax, %eax
+ jne 2b # see if we need to switch tasks, or do more signals
+3: popl %eax
+ popl %ebx
+ popl %ecx
+ popl %edx
+ addl $4, %esp # skip orig_eax
+ pop %fs
+ pop %es
+ pop %ds
+ iret
+
+.align 2
+_coprocessor_error:
+ push %ds
+ push %es
+ push %fs
+ pushl $-1 # fill in -1 for orig_eax
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
+ pushl %eax
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ movl $0x17,%eax
+ mov %ax,%fs
+ pushl $ret_from_sys_call
+ jmp _math_error
+
+.align 2
+_device_not_available:
+ push %ds
+ push %es
+ push %fs
+ pushl $-1 # fill in -1 for orig_eax
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
+ pushl %eax
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ movl $0x17,%eax
+ mov %ax,%fs
+ pushl $ret_from_sys_call
+ clts # clear TS so that we can use math
+ movl %cr0,%eax
+ testl $0x4,%eax # EM (math emulation bit)
+ je _math_state_restore
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ pushl $0 # temporary storage for ORIG_EIP
+ call _math_emulate
+ addl $4,%esp
+ popl %edi
+ popl %esi
+ popl %ebp
+ ret
+
+.align 2
+_timer_interrupt:
+ push %ds # save ds,es and put kernel data space
+ push %es # into them. %fs is used by _system_call
+ push %fs
+ pushl $-1 # fill in -1 for orig_eax
+ pushl %edx # we save %eax,%ecx,%edx as gcc doesn't
+ pushl %ecx # save those across function calls. %ebx
+ pushl %ebx # is saved as we use that in ret_sys_call
+ pushl %eax
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ movl $0x17,%eax
+ mov %ax,%fs
+ incl _jiffies
+ movb $0x20,%al # EOI to interrupt controller #1
+ outb %al,$0x20
+ movl CS(%esp),%eax
+ andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor)
+ pushl %eax
+ call _do_timer # 'do_timer(long CPL)' does everything from
+ addl $4,%esp # task switching to accounting ...
+ jmp ret_from_sys_call
+
+.align 2
+_sys_execve:
+ lea EIP(%esp),%eax
+ pushl %eax
+ call _do_execve
+ addl $4,%esp
+ ret
+
+.align 2
+_sys_fork:
+ call _find_empty_process
+ testl %eax,%eax
+ js 1f
+ push %gs
+ pushl %esi
+ pushl %edi
+ pushl %ebp
+ pushl %eax
+ call _copy_process
+ addl $20,%esp
+1: ret
+
+_hd_interrupt:
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ push %ds
+ push %es
+ push %fs
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ movl $0x17,%eax
+ mov %ax,%fs
+ movb $0x20,%al
+ outb %al,$0xA0 # EOI to interrupt controller #1
+ jmp 1f # give port chance to breathe
+1: jmp 1f
+1: xorl %edx,%edx
+ movl %edx,_hd_timeout
+ xchgl _do_hd,%edx
+ testl %edx,%edx
+ jne 1f
+ movl $_unexpected_hd_interrupt,%edx
+1: outb %al,$0x20
+ call *%edx # "interesting" way of handling intr.
+ pop %fs
+ pop %es
+ pop %ds
+ popl %edx
+ popl %ecx
+ popl %eax
+ iret
+
+_floppy_interrupt:
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ push %ds
+ push %es
+ push %fs
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ movl $0x17,%eax
+ mov %ax,%fs
+ movb $0x20,%al
+ outb %al,$0x20 # EOI to interrupt controller #1
+ xorl %eax,%eax
+ xchgl _do_floppy,%eax
+ testl %eax,%eax
+ jne 1f
+ movl $_unexpected_floppy_interrupt,%eax
+1: call *%eax # "interesting" way of handling intr.
+ pop %fs
+ pop %es
+ pop %ds
+ popl %edx
+ popl %ecx
+ popl %eax
+ iret
+
+_parallel_interrupt:
+ pushl %eax
+ movb $0x20,%al
+ outb %al,$0x20
+ popl %eax
+ iret
+++ /dev/null
-/*
- * linux/kernel/system_call.s
- *
- * (C) 1991 Linus Torvalds
- */
-
-/*
- * system_call.s contains the system-call low-level handling routines.
- * This also contains the timer-interrupt handler, as some of the code is
- * the same. The hd- and flopppy-interrupts are also here.
- *
- * NOTE: This code handles signal-recognition, which happens every time
- * after a timer-interrupt and after each system call. Ordinary interrupts
- * don't handle signal-recognition, as that would clutter them up totally
- * unnecessarily.
- *
- * Stack layout in 'ret_from_system_call':
- *
- * 0(%esp) - %eax
- * 4(%esp) - %ebx
- * 8(%esp) - %ecx
- * C(%esp) - %edx
- * 10(%esp) - %fs
- * 14(%esp) - %es
- * 18(%esp) - %ds
- * 1C(%esp) - %eip
- * 20(%esp) - %cs
- * 24(%esp) - %eflags
- * 28(%esp) - %oldesp
- * 2C(%esp) - %oldss
- */
-
-SIG_CHLD = 17
-
-EAX = 0x00
-EBX = 0x04
-ECX = 0x08
-EDX = 0x0C
-FS = 0x10
-ES = 0x14
-DS = 0x18
-EIP = 0x1C
-CS = 0x20
-EFLAGS = 0x24
-OLDESP = 0x28
-OLDSS = 0x2C
-
-state = 0 # these are offsets into the task-struct.
-counter = 4
-priority = 8
-signal = 12
-sigaction = 16 # MUST be 16 (=len of sigaction)
-blocked = (33*16)
-
-# offsets within sigaction
-sa_handler = 0
-sa_mask = 4
-sa_flags = 8
-sa_restorer = 12
-
-nr_system_calls = 72
-
-/*
- * Ok, I get parallel printer interrupts while using the floppy for some
- * strange reason. Urgel. Now I just ignore them.
- */
-.globl _system_call,_sys_fork,_timer_interrupt,_sys_execve
-.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt
-.globl _device_not_available, _coprocessor_error
-
-.align 2
-bad_sys_call:
- movl $-1,%eax
- iret
-.align 2
-reschedule:
- pushl $ret_from_sys_call
- jmp _schedule
-.align 2
-_system_call:
- cmpl $nr_system_calls-1,%eax
- ja bad_sys_call
- push %ds
- push %es
- push %fs
- pushl %edx
- pushl %ecx # push %ebx,%ecx,%edx as parameters
- pushl %ebx # to the system call
- movl $0x10,%edx # set up ds,es to kernel space
- mov %dx,%ds
- mov %dx,%es
- movl $0x17,%edx # fs points to local data space
- mov %dx,%fs
- call _sys_call_table(,%eax,4)
- pushl %eax
- movl _current,%eax
- cmpl $0,state(%eax) # state
- jne reschedule
- cmpl $0,counter(%eax) # counter
- je reschedule
-ret_from_sys_call:
- movl _current,%eax # task[0] cannot have signals
- cmpl _task,%eax
- je 3f
- cmpw $0x0f,CS(%esp) # was old code segment supervisor ?
- jne 3f
- cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
- jne 3f
- movl signal(%eax),%ebx
- movl blocked(%eax),%ecx
- notl %ecx
- andl %ebx,%ecx
- bsfl %ecx,%ecx
- je 3f
- btrl %ecx,%ebx
- movl %ebx,signal(%eax)
- incl %ecx
- pushl %ecx
- call _do_signal
- popl %eax
-3: popl %eax
- popl %ebx
- popl %ecx
- popl %edx
- pop %fs
- pop %es
- pop %ds
- iret
-
-.align 2
-_coprocessor_error:
- push %ds
- push %es
- push %fs
- pushl %edx
- pushl %ecx
- pushl %ebx
- pushl %eax
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- movl $0x17,%eax
- mov %ax,%fs
- pushl $ret_from_sys_call
- jmp _math_error
-
-.align 2
-_device_not_available:
- push %ds
- push %es
- push %fs
- pushl %edx
- pushl %ecx
- pushl %ebx
- pushl %eax
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- movl $0x17,%eax
- mov %ax,%fs
- pushl $ret_from_sys_call
- clts # clear TS so that we can use math
- movl %cr0,%eax
- testl $0x4,%eax # EM (math emulation bit)
- je _math_state_restore
- pushl %ebp
- pushl %esi
- pushl %edi
- call _math_emulate
- popl %edi
- popl %esi
- popl %ebp
- ret
-
-.align 2
-_timer_interrupt:
- push %ds # save ds,es and put kernel data space
- push %es # into them. %fs is used by _system_call
- push %fs
- pushl %edx # we save %eax,%ecx,%edx as gcc doesn't
- pushl %ecx # save those across function calls. %ebx
- pushl %ebx # is saved as we use that in ret_sys_call
- pushl %eax
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- movl $0x17,%eax
- mov %ax,%fs
- incl _jiffies
- movb $0x20,%al # EOI to interrupt controller #1
- outb %al,$0x20
- movl CS(%esp),%eax
- andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor)
- pushl %eax
- call _do_timer # 'do_timer(long CPL)' does everything from
- addl $4,%esp # task switching to accounting ...
- jmp ret_from_sys_call
-
-.align 2
-_sys_execve:
- lea EIP(%esp),%eax
- pushl %eax
- call _do_execve
- addl $4,%esp
- ret
-
-.align 2
-_sys_fork:
- call _find_empty_process
- testl %eax,%eax
- js 1f
- push %gs
- pushl %esi
- pushl %edi
- pushl %ebp
- pushl %eax
- call _copy_process
- addl $20,%esp
-1: ret
-
-_hd_interrupt:
- pushl %eax
- pushl %ecx
- pushl %edx
- push %ds
- push %es
- push %fs
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- movl $0x17,%eax
- mov %ax,%fs
- movb $0x20,%al
- outb %al,$0xA0 # EOI to interrupt controller #1
- jmp 1f # give port chance to breathe
-1: jmp 1f
-1: xorl %edx,%edx
- xchgl _do_hd,%edx
- testl %edx,%edx
- jne 1f
- movl $_unexpected_hd_interrupt,%edx
-1: outb %al,$0x20
- call *%edx # "interesting" way of handling intr.
- pop %fs
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- popl %eax
- iret
-
-_floppy_interrupt:
- pushl %eax
- pushl %ecx
- pushl %edx
- push %ds
- push %es
- push %fs
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- movl $0x17,%eax
- mov %ax,%fs
- movb $0x20,%al
- outb %al,$0x20 # EOI to interrupt controller #1
- xorl %eax,%eax
- xchgl _do_floppy,%eax
- testl %eax,%eax
- jne 1f
- movl $_unexpected_floppy_interrupt,%eax
-1: call *%eax # "interesting" way of handling intr.
- pop %fs
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- popl %eax
- iret
-
-_parallel_interrupt:
- pushl %eax
- movb $0x20,%al
- outb %al,$0x20
- popl %eax
- iret
__asm__("mov %%fs,%%ax":"=a" (__res):); \
__res;})
-int do_exit(long code);
-
void page_exception(void);
void divide_error(void);
void reserved(void);
void parallel_interrupt(void);
void irq13(void);
+void alignment_check(void);
static void die(char * str,long esp_ptr,long nr)
{
die("general protection",esp,error_code);
}
+void do_alignment_check(long esp, long error_code)
+{
+ die("alignment check",esp,error_code);
+}
+
void do_divide_error(long esp, long error_code)
{
die("divide error",esp,error_code);
set_trap_gate(14,&page_fault);
set_trap_gate(15,&reserved);
set_trap_gate(16,&coprocessor_error);
- for (i=17;i<48;i++)
+ set_trap_gate(17,&alignment_check);
+ for (i=18;i<48;i++)
set_trap_gate(i,&reserved);
set_trap_gate(45,&irq13);
outb_p(inb_p(0x21)&0xfb,0x21);
$(CC) $(CFLAGS) \
-S -o $*.s $<
-OBJS = memory.o page.o
+OBJS = memory.o swap.o page.o
all: mm.o
### Dependencies:
memory.o : memory.c ../include/signal.h ../include/sys/types.h \
../include/asm/system.h ../include/linux/sched.h ../include/linux/head.h \
- ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h
+ ../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
+swap.o : swap.c ../include/string.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
+ ../include/sys/param.h ../include/sys/time.h ../include/time.h \
+ ../include/sys/resource.h
* Also corrected some "invalidate()"s - I wasn't doing enough of them.
*/
+/*
+ * Real VM (paging to/from disk) started 18.12.91. Much more work and
+ * thought has to go into this. Oh, well..
+ * 19.12.91 - works, somewhat. Sometimes I get faults, don't know why.
+ * Found it. Everything seems to work now.
+ * 20.12.91 - Ok, making the swap-device changeable like the root.
+ */
+
#include <signal.h>
#include <asm/system.h>
#include <linux/head.h>
#include <linux/kernel.h>
-volatile void do_exit(long code);
-
-static inline volatile void oom(void)
-{
- printk("out of memory\n\r");
- do_exit(SIGSEGV);
-}
-
-#define invalidate() \
-__asm__("movl %%eax,%%cr3"::"a" (0))
-
-/* these are not to be changed without changing head.s etc */
-#define LOW_MEM 0x100000
-#define PAGING_MEMORY (15*1024*1024)
-#define PAGING_PAGES (PAGING_MEMORY>>12)
-#define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
-#define USED 100
-
#define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \
current->start_code + current->end_code)
-static long HIGH_MEMORY = 0;
+unsigned long HIGH_MEMORY = 0;
#define copy_page(from,to) \
__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
-static unsigned char mem_map [ PAGING_PAGES ] = {0,};
-
-/*
- * Get physical address of first (actually last :-) free page, and mark it
- * used. If no free pages left, return 0.
- */
-unsigned long get_free_page(void)
-{
-register unsigned long __res asm("ax");
-
-__asm__("std ; repne ; scasb\n\t"
- "jne 1f\n\t"
- "movb $1,1(%%edi)\n\t"
- "sall $12,%%ecx\n\t"
- "addl %2,%%ecx\n\t"
- "movl %%ecx,%%edx\n\t"
- "movl $1024,%%ecx\n\t"
- "leal 4092(%%edx),%%edi\n\t"
- "rep ; stosl\n\t"
- "movl %%edx,%%eax\n"
- "1:"
- :"=a" (__res)
- :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
- "D" (mem_map+PAGING_PAGES-1)
- :"di","cx","dx");
-return __res;
-}
+unsigned char mem_map [ PAGING_PAGES ] = {0,};
/*
* Free a page of memory at physical address 'addr'. Used by
continue;
pg_table = (unsigned long *) (0xfffff000 & *dir);
for (nr=0 ; nr<1024 ; nr++) {
- if (1 & *pg_table)
- free_page(0xfffff000 & *pg_table);
- *pg_table = 0;
+ if (*pg_table) {
+ if (1 & *pg_table)
+ free_page(0xfffff000 & *pg_table);
+ else
+ swap_free(*pg_table >> 1);
+ *pg_table = 0;
+ }
pg_table++;
}
free_page(0xfffff000 & *dir);
unsigned long * to_page_table;
unsigned long this_page;
unsigned long * from_dir, * to_dir;
+ unsigned long new_page;
unsigned long nr;
if ((from&0x3fffff) || (to&0x3fffff))
nr = (from==0)?0xA0:1024;
for ( ; nr-- > 0 ; from_page_table++,to_page_table++) {
this_page = *from_page_table;
- if (!(1 & this_page))
+ if (!this_page)
+ continue;
+ if (!(1 & this_page)) {
+ if (!(new_page = get_free_page()))
+ return -1;
+ read_swap_page(this_page>>1, (char *) new_page);
+ *to_page_table = this_page;
+ *from_page_table = new_page | (PAGE_DIRTY | 7);
continue;
+ }
this_page &= ~2;
*to_page_table = this_page;
if (this_page > LOW_MEM) {
* out of memory (either when trying to access page-table or
* page.)
*/
-unsigned long put_page(unsigned long page,unsigned long address)
+static unsigned long put_page(unsigned long page,unsigned long address)
{
unsigned long tmp, *page_table;
else {
if (!(tmp=get_free_page()))
return 0;
- *page_table = tmp|7;
+ *page_table = tmp | 7;
page_table = (unsigned long *) tmp;
}
page_table[(address>>12) & 0x3ff] = page | 7;
return page;
}
+/*
+ * The previous function doesn't work very well if you also want to mark
+ * the page dirty: exec.c wants this, as it has earlier changed the page,
+ * and we want the dirty-status to be correct (for VM). Thus the same
+ * routine, but this time we mark it dirty too.
+ */
+unsigned long put_dirty_page(unsigned long page, unsigned long address)
+{
+ unsigned long tmp, *page_table;
+
+/* NOTE !!! This uses the fact that _pg_dir=0 */
+
+ if (page < LOW_MEM || page >= HIGH_MEMORY)
+ printk("Trying to put page %p at %p\n",page,address);
+ if (mem_map[(page-LOW_MEM)>>12] != 1)
+ printk("mem_map disagrees with %p at %p\n",page,address);
+ page_table = (unsigned long *) ((address>>20) & 0xffc);
+ if ((*page_table)&1)
+ page_table = (unsigned long *) (0xfffff000 & *page_table);
+ else {
+ if (!(tmp=get_free_page()))
+ return 0;
+ *page_table = tmp|7;
+ page_table = (unsigned long *) tmp;
+ }
+ page_table[(address>>12) & 0x3ff] = page | (PAGE_DIRTY | 7);
+/* no need for invalidate */
+ return page;
+}
+
void un_wp_page(unsigned long * table_entry)
{
unsigned long old_page,new_page;
oom();
if (old_page >= LOW_MEM)
mem_map[MAP_NR(old_page)]--;
+ copy_page(old_page,new_page);
*table_entry = new_page | 7;
invalidate();
- copy_page(old_page,new_page);
}
/*
*/
void do_wp_page(unsigned long error_code,unsigned long address)
{
+ if (address < TASK_SIZE)
+ printk("\n\rBAD! KERNEL MEMORY WP-ERR!\n\r");
+ if (address - current->start_code > TASK_SIZE) {
+ printk("Bad things happen: page error in do_wp_page\n\r");
+ do_exit(SIGSEGV);
+ }
#if 0
/* we cannot do this yet: the estdio library writes to code space */
/* stupid, stupid. I really want the libc.a from GNU */
* task.
*
* NOTE! This assumes we have checked that p != current, and that they
- * share the same executable.
+ * share the same executable or library.
*/
static int try_to_share(unsigned long address, struct task_struct * p)
{
* We first check if it is at all feasible by checking executable->i_count.
* It should be >1 if there are other tasks sharing this inode.
*/
-static int share_page(unsigned long address)
+static int share_page(struct m_inode * inode, unsigned long address)
{
struct task_struct ** p;
- if (!current->executable)
- return 0;
- if (current->executable->i_count < 2)
+ if (inode->i_count < 2 || !inode)
return 0;
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
if (!*p)
continue;
if (current == *p)
continue;
- if ((*p)->executable != current->executable)
- continue;
+ if (address < LIBRARY_OFFSET) {
+ if (inode != (*p)->executable)
+ continue;
+ } else {
+ if (inode != (*p)->library)
+ continue;
+ }
if (try_to_share(address,*p))
return 1;
}
unsigned long tmp;
unsigned long page;
int block,i;
+ struct m_inode * inode;
+ if (address < TASK_SIZE)
+ printk("\n\rBAD!! KERNEL PAGE MISSING\n\r");
+ if (address - current->start_code > TASK_SIZE) {
+ printk("Bad things happen: nonexistent page error in do_no_page\n\r");
+ do_exit(SIGSEGV);
+ }
+ page = *(unsigned long *) ((address >> 20) & 0xffc);
+ if (page & 1) {
+ page &= 0xfffff000;
+ page += (address >> 10) & 0xffc;
+ tmp = *(unsigned long *) page;
+ if (tmp && !(1 & tmp)) {
+ swap_in((unsigned long *) page);
+ return;
+ }
+ }
address &= 0xfffff000;
tmp = address - current->start_code;
- if (!current->executable || tmp >= current->end_data) {
+ if (tmp >= LIBRARY_OFFSET ) {
+ inode = current->library;
+ block = 1 + (tmp-LIBRARY_OFFSET) / BLOCK_SIZE;
+ } else if (tmp < current->end_data) {
+ inode = current->executable;
+ block = 1 + tmp / BLOCK_SIZE;
+ } else {
+ inode = NULL;
+ block = 0;
+ }
+ if (!inode) {
get_empty_page(address);
return;
}
- if (share_page(tmp))
+ if (share_page(inode,tmp))
return;
if (!(page = get_free_page()))
oom();
/* remember that 1 block is used for header */
- block = 1 + tmp/BLOCK_SIZE;
for (i=0 ; i<4 ; block++,i++)
- nr[i] = bmap(current->executable,block);
- bread_page(page,current->executable->i_dev,nr);
+ nr[i] = bmap(inode,block);
+ bread_page(page,inode->i_dev,nr);
i = tmp + 4096 - current->end_data;
+ if (i>4095)
+ i = 0;
tmp = page + 4096;
while (i-- > 0) {
tmp--;
mem_map[i++]=0;
}
-void calc_mem(void)
+void show_mem(void)
{
- int i,j,k,free=0;
- long * pg_tbl;
+ int i,j,k,free=0,total=0;
+ int shared=0;
+ unsigned long * pg_tbl;
- for(i=0 ; i<PAGING_PAGES ; i++)
- if (!mem_map[i]) free++;
- printk("%d pages free (of %d)\n\r",free,PAGING_PAGES);
- for(i=2 ; i<1024 ; i++) {
+ printk("Mem-info:\n\r");
+ for(i=0 ; i<PAGING_PAGES ; i++) {
+ if (mem_map[i] == USED)
+ continue;
+ total++;
+ if (!mem_map[i])
+ free++;
+ else
+ shared += mem_map[i]-1;
+ }
+ printk("%d free pages of %d\n\r",free,total);
+ printk("%d pages shared\n\r",shared);
+ k = 0;
+ for(i=4 ; i<1024 ;) {
if (1&pg_dir[i]) {
- pg_tbl=(long *) (0xfffff000 & pg_dir[i]);
- for(j=k=0 ; j<1024 ; j++)
- if (pg_tbl[j]&1)
- k++;
- printk("Pg-dir[%d] uses %d pages\n",i,k);
+ if (pg_dir[i]>HIGH_MEMORY) {
+ printk("page directory[%d]: %08X\n\r",
+ i,pg_dir[i]);
+ continue;
+ }
+ if (pg_dir[i]>LOW_MEM)
+ free++,k++;
+ pg_tbl=(unsigned long *) (0xfffff000 & pg_dir[i]);
+ for(j=0 ; j<1024 ; j++)
+ if ((pg_tbl[j]&1) && pg_tbl[j]>LOW_MEM)
+ if (pg_tbl[j]>HIGH_MEMORY)
+ printk("page_dir[%d][%d]: %08X\n\r",
+ i,j, pg_tbl[j]);
+ else
+ k++,free++;
+ }
+ i++;
+ if (!(i&15) && k) {
+ k++,free++; /* one page/process for task_struct */
+ printk("Process %d: %d pages\n\r",(i>>4)-1,k);
+ k = 0;
}
}
+ printk("Memory found: %d (%d)\n\r",free-shared,total);
}
--- /dev/null
+/*
+ * linux/mm/swap.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * This file should contain most things doing the swapping from/to disk.
+ * Started 18.12.91
+ */
+
+#include <string.h>
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/head.h>
+#include <linux/kernel.h>
+
+#define SWAP_BITS (4096<<3)
+
+#define bitop(name,op) \
+static inline int name(char * addr,unsigned int nr) \
+{ \
+int __res; \
+__asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \
+:"=g" (__res) \
+:"r" (nr),"m" (*(addr)),"0" (0)); \
+return __res; \
+}
+
+bitop(bit,"")
+bitop(setbit,"s")
+bitop(clrbit,"r")
+
+static char * swap_bitmap = NULL;
+int SWAP_DEV = 0;
+
+/*
+ * We never page the pages in task[0] - kernel memory.
+ * We page all other pages.
+ */
+#define FIRST_VM_PAGE (TASK_SIZE>>12)
+#define LAST_VM_PAGE (1024*1024)
+#define VM_PAGES (LAST_VM_PAGE - FIRST_VM_PAGE)
+
+static int get_swap_page(void)
+{
+ int nr;
+
+ if (!swap_bitmap)
+ return 0;
+ for (nr = 1; nr < 32768 ; nr++)
+ if (clrbit(swap_bitmap,nr))
+ return nr;
+ return 0;
+}
+
+void swap_free(int swap_nr)
+{
+ if (!swap_nr)
+ return;
+ if (swap_bitmap && swap_nr < SWAP_BITS)
+ if (!setbit(swap_bitmap,swap_nr))
+ return;
+ printk("Swap-space bad (swap_free())\n\r");
+ return;
+}
+
+void swap_in(unsigned long *table_ptr)
+{
+ int swap_nr;
+ unsigned long page;
+
+ if (!swap_bitmap) {
+ printk("Trying to swap in without swap bit-map");
+ return;
+ }
+ if (1 & *table_ptr) {
+ printk("trying to swap in present page\n\r");
+ return;
+ }
+ swap_nr = *table_ptr >> 1;
+ if (!swap_nr) {
+ printk("No swap page in swap_in\n\r");
+ return;
+ }
+ if (!(page = get_free_page()))
+ oom();
+ read_swap_page(swap_nr, (char *) page);
+ if (setbit(swap_bitmap,swap_nr))
+ printk("swapping in multiply from same page\n\r");
+ *table_ptr = page | (PAGE_DIRTY | 7);
+}
+
+int try_to_swap_out(unsigned long * table_ptr)
+{
+ unsigned long page;
+ unsigned long swap_nr;
+
+ page = *table_ptr;
+ if (!(PAGE_PRESENT & page))
+ return 0;
+ if (page - LOW_MEM > PAGING_MEMORY)
+ return 0;
+ if (PAGE_DIRTY & page) {
+ page &= 0xfffff000;
+ if (mem_map[MAP_NR(page)] != 1)
+ return 0;
+ if (!(swap_nr = get_swap_page()))
+ return 0;
+ *table_ptr = swap_nr<<1;
+ invalidate();
+ write_swap_page(swap_nr, (char *) page);
+ free_page(page);
+ return 1;
+ }
+ *table_ptr = 0;
+ invalidate();
+ free_page(page);
+ return 1;
+}
+
+/*
+ * Ok, this has a rather intricate logic - the idea is to make good
+ * and fast machine code. If we didn't worry about that, things would
+ * be easier.
+ */
+int swap_out(void)
+{
+ static int dir_entry = FIRST_VM_PAGE>>10;
+ static int page_entry = -1;
+ int counter = VM_PAGES;
+ int pg_table;
+
+ while (counter>0) {
+ pg_table = pg_dir[dir_entry];
+ if (pg_table & 1)
+ break;
+ counter -= 1024;
+ dir_entry++;
+ if (dir_entry >= 1024)
+ dir_entry = FIRST_VM_PAGE>>10;
+ }
+ pg_table &= 0xfffff000;
+ while (counter-- > 0) {
+ page_entry++;
+ if (page_entry >= 1024) {
+ page_entry = 0;
+ repeat:
+ dir_entry++;
+ if (dir_entry >= 1024)
+ dir_entry = FIRST_VM_PAGE>>10;
+ pg_table = pg_dir[dir_entry];
+ if (!(pg_table&1))
+ if ((counter -= 1024) > 0)
+ goto repeat;
+ else
+ break;
+ pg_table &= 0xfffff000;
+ }
+ if (try_to_swap_out(page_entry + (unsigned long *) pg_table))
+ return 1;
+ }
+ printk("Out of swap-memory\n\r");
+ return 0;
+}
+
+/*
+ * Get physical address of first (actually last :-) free page, and mark it
+ * used. If no free pages left, return 0.
+ */
+unsigned long get_free_page(void)
+{
+register unsigned long __res asm("ax");
+
+repeat:
+ __asm__("std ; repne ; scasb\n\t"
+ "jne 1f\n\t"
+ "movb $1,1(%%edi)\n\t"
+ "sall $12,%%ecx\n\t"
+ "addl %2,%%ecx\n\t"
+ "movl %%ecx,%%edx\n\t"
+ "movl $1024,%%ecx\n\t"
+ "leal 4092(%%edx),%%edi\n\t"
+ "rep ; stosl\n\t"
+ "movl %%edx,%%eax\n"
+ "1:"
+ :"=a" (__res)
+ :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
+ "D" (mem_map+PAGING_PAGES-1)
+ :"di","cx","dx");
+ if (__res >= HIGH_MEMORY)
+ goto repeat;
+ if (!__res && swap_out())
+ goto repeat;
+ return __res;
+}
+
+void init_swapping(void)
+{
+ extern int *blk_size[];
+ int swap_size,i,j;
+
+ if (!SWAP_DEV)
+ return;
+ if (!blk_size[MAJOR(SWAP_DEV)]) {
+ printk("Unable to get size of swap device\n\r");
+ return;
+ }
+ swap_size = blk_size[MAJOR(SWAP_DEV)][MINOR(SWAP_DEV)];
+ if (!swap_size)
+ return;
+ if (swap_size < 100) {
+ printk("Swap device too small (%d blocks)\n\r",swap_size);
+ return;
+ }
+ swap_size >>= 2;
+ if (swap_size > SWAP_BITS)
+ swap_size = SWAP_BITS;
+ swap_bitmap = (char *) get_free_page();
+ if (!swap_bitmap) {
+ printk("Unable to start swapping: out of memory :-)\n\r");
+ return;
+ }
+ read_swap_page(0,swap_bitmap);
+ if (strncmp("SWAP-SPACE",swap_bitmap+4086,10)) {
+ printk("Unable to find swap-space signature\n\r");
+ free_page((long) swap_bitmap);
+ swap_bitmap = NULL;
+ return;
+ }
+ memset(swap_bitmap+4086,0,10);
+ for (i = 0 ; i < SWAP_BITS ; i++) {
+ if (i == 1)
+ i = swap_size;
+ if (bit(swap_bitmap,i)) {
+ printk("Bad swap-space bit-map\n\r");
+ free_page((long) swap_bitmap);
+ swap_bitmap = NULL;
+ return;
+ }
+ }
+ j = 0;
+ for (i = 1 ; i < swap_size ; i++)
+ if (bit(swap_bitmap,i))
+ j++;
+ if (!j) {
+ free_page((long) swap_bitmap);
+ swap_bitmap = NULL;
+ return;
+ }
+ printk("Swap device ok: %d pages (%d bytes) swap-space\n\r",j,j*4096);
+}
/*
* Changes by tytso to allow root device specification
+ *
+ * Added swap-device specification: Linux 20.12.91
*/
#include <stdio.h> /* fprintf */
#define MINIX_HEADER 32
#define GCC_HEADER 1024
-#define SYS_SIZE 0x2000
+#define SYS_SIZE 0x3000
#define DEFAULT_MAJOR_ROOT 3
#define DEFAULT_MINOR_ROOT 6
+#define DEFAULT_MAJOR_SWAP 0
+#define DEFAULT_MINOR_SWAP 0
+
/* max nr of sectors of setup: don't change unless you also change
* bootsect etc */
#define SETUP_SECTS 4
int i,c,id;
char buf[1024];
char major_root, minor_root;
+ char major_swap, minor_swap;
struct stat sb;
- if ((argc != 4) && (argc != 5))
+ if ((argc < 4) || (argc > 6))
usage();
- if (argc == 5) {
+ if (argc > 4) {
if (strcmp(argv[4], "FLOPPY")) {
if (stat(argv[4], &sb)) {
perror(argv[4]);
major_root = DEFAULT_MAJOR_ROOT;
minor_root = DEFAULT_MINOR_ROOT;
}
+ if (argc == 6) {
+ if (strcmp(argv[5], "NONE")) {
+ if (stat(argv[5], &sb)) {
+ perror(argv[5]);
+ die("Couldn't stat root device.");
+ }
+ major_swap = MAJOR(sb.st_rdev);
+ minor_swap = MINOR(sb.st_rdev);
+ } else {
+ major_swap = 0;
+ minor_swap = 0;
+ }
+ } else {
+ major_swap = DEFAULT_MAJOR_SWAP;
+ minor_swap = DEFAULT_MINOR_SWAP;
+ }
fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
+ fprintf(stderr, "Swap device is (%d, %d)\n", major_swap, minor_swap);
if ((major_root != 2) && (major_root != 3) &&
(major_root != 0)) {
fprintf(stderr, "Illegal root device (major = %d)\n",
major_root);
die("Bad root device --- major #");
}
+ if (major_swap && major_swap != 3) {
+ fprintf(stderr, "Illegal swap device (major = %d)\n",
+ major_swap);
+ die("Bad root device --- major #");
+ }
for (i=0;i<sizeof buf; i++) buf[i]=0;
if ((id=open(argv[1],O_RDONLY,0))<0)
die("Unable to open 'boot'");
die("Boot block must be exactly 512 bytes");
if ((*(unsigned short *)(buf+510)) != 0xAA55)
die("Boot block hasn't got boot flag (0xAA55)");
+ buf[506] = (char) minor_swap;
+ buf[507] = (char) major_swap;
buf[508] = (char) minor_root;
buf[509] = (char) major_root;
i=write(1,buf,512);