aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Benedict Torvalds <torvalds@klaava.Helsinki.FI>1992-07-11 20:40:11 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:05 -0400
commit1c368f1aedaa10a03fcec9d19eec9f9ba60015d2 (patch)
treee07b7f31e1a321407fa03f1b8c7eca3330df57d6
parentf79e5351608302264fbd909f99f5420b01079582 (diff)
downloadarchive-1c368f1aedaa10a03fcec9d19eec9f9ba60015d2.tar.gz
Patch1 to 0.96c outv0.96c-pl1
I have sent off my first patch to 0.96c: as usual it's available directly from banjo.concert.net while nic.funet.fi and tsx-11.mit.edu might take a day or two to put it into the right directories. linux-0.96c.patch1 contains more changes than I originally envisioned: I changed the IRQ routines and the serial code to be easier and cleaner (and hopefully more efficient) and I thought that would be it. I was wrong. I got several patches (and one bug-report) again, and while I haven't had time to check them all, some of them are in. Fixes: - Remy Cards correction to the out-of-space problem with the extended fs is here. Most people using the ext-fs might already have applied this patch, in which case you might have problems patching. - my ftruncate() fix is here. Again, if you already did the trivial patch by hand, you'll get errors when patching. - almesber's implementation of read-only filesystems is here (after editing by yours truly). The mount() system call now accepts a flags integer as well as a pointer to some arbitraty data in user space for some special mount() calls. The general flags allow (a) read-only mounting, (b) disabling of suid executables (c) disabling of device special files and (d) total disabling of executables on a per-filesystem basis. The filesystem specific mount() info isn't currently used by any fs, but can be used to specify additional information that depends on a special fs type (a password or similar would be possible..) - the rename() system call had a bug in that it allowed moving over a directory: I think the code to handle this was lost in the vfs editing, and although the GNU mv utility checked it, a malicious (or just unsuspecting) program can destroy the fs using this. Thanks for the bug-report: it was very easy to add once I saw the problem. - support for vesa-standard svga cards in setup.S. I'm unable to test this, but my svga card still works after the patch, so I left it in in the hope that it doesn't break for anybody else. - various minor editing by me, or minor patches sent in by others. The full cdiff is almost 50kB compressed, so this is a bigger-than-usual patch. Hope there are no problems. People who are using the new SCSI drivers might have problems with my changes to the SCSI irq-setup changes, so be careful (actually using the original sources might be a good idea, and then upgrading again). I hope to get the new SCSI drivers into the kernel soon (definitely in time for 0.98). I'd be interested to hear comments on serial line performance, bugs, features, etc. As usual, I'm hoping this release won't contain any new bugs while fixing all the old ones, but I guess that's likely to happen right after the first winter olympics in Hell. Linus PS. Maybe nobody noticed, but I actually never made the patches to 0.96c available. As nobody has complained, I assume everybody just got the complete kernel sources and used that. Unless somebody actually asks for them, I don't think there is any point in making them any more.
-rw-r--r--Makefile2
-rw-r--r--boot/setup.S273
-rw-r--r--fs/exec.c14
-rw-r--r--fs/ext/bitmap.c1
-rw-r--r--fs/ext/file.c6
-rw-r--r--fs/ext/freelists.c19
-rw-r--r--fs/ext/namei.c4
-rw-r--r--fs/inode.c1
-rw-r--r--fs/ioctl.c9
-rw-r--r--fs/minix/bitmap.c1
-rw-r--r--fs/minix/file.c6
-rw-r--r--fs/minix/namei.c4
-rw-r--r--fs/namei.c50
-rw-r--r--fs/open.c28
-rw-r--r--fs/super.c124
-rw-r--r--include/asm/irq.h75
-rw-r--r--include/linux/config.h2
-rw-r--r--include/linux/fs.h32
-rw-r--r--include/linux/hdreg.h1
-rw-r--r--include/linux/sched.h4
-rw-r--r--include/linux/tty.h3
-rw-r--r--include/sys/time.h2
-rw-r--r--init/main.c16
-rw-r--r--kernel/Makefile9
-rw-r--r--kernel/blk_drv/blk.h8
-rw-r--r--kernel/blk_drv/floppy.c34
-rw-r--r--kernel/blk_drv/hd.c40
-rw-r--r--kernel/blk_drv/ll_rw_blk.c41
-rw-r--r--kernel/blk_drv/ramdisk.c2
-rw-r--r--kernel/blk_drv/scsi/aha1542.c57
-rw-r--r--kernel/blk_drv/scsi/sd_ioctl.c4
-rw-r--r--kernel/blk_drv/scsi/ultrastor.c51
-rw-r--r--kernel/chr_drv/console.c50
-rw-r--r--kernel/chr_drv/keyboard.c4
-rw-r--r--kernel/chr_drv/pty.c10
-rw-r--r--kernel/chr_drv/serial.c184
-rw-r--r--kernel/chr_drv/tty_io.c161
-rw-r--r--kernel/chr_drv/tty_ioctl.c23
-rw-r--r--kernel/irq.c171
-rw-r--r--kernel/ptrace.c4
-rw-r--r--kernel/sched.c60
-rw-r--r--kernel/sys_call.S110
-rw-r--r--kernel/traps.c6
-rw-r--r--lib/Makefile4
44 files changed, 1172 insertions, 538 deletions
diff --git a/Makefile b/Makefile
index c582ab2..c942274 100644
--- a/Makefile
+++ b/Makefile
@@ -89,7 +89,7 @@ subdirs: dummy
Version:
@./makever.sh
- @echo \#define UTS_RELEASE \"0.96c-`cat .version`\" > include/linux/config_rel.h
+ @echo \#define UTS_RELEASE \"0.96c.pl1-`cat .version`\" > include/linux/config_rel.h
@echo \#define UTS_VERSION \"`date +%D`\" > include/linux/config_ver.h
touch include/linux/config.h
diff --git a/boot/setup.S b/boot/setup.S
index bd23161..88c23cd 100644
--- a/boot/setup.S
+++ b/boot/setup.S
@@ -189,9 +189,10 @@ end_move:
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0xFF ! mask off all interrupts for now
- out #0x21,al
- .word 0x00eb,0x00eb
out #0xA1,al
+ .word 0x00eb,0x00eb
+ mov al,#0xFB ! mask all irq's but irq2 which
+ out #0x21,al ! is cascaded
! well, that certainly wasn't fun :-(. Hopefully it works, and we don't
! need no steenking BIOS anyway (except for the initial loading :-).
@@ -241,10 +242,75 @@ chsvga: cld
push ds
push cs
pop ds
- mov ax,#0xc000
+
+! First try and execute a VESA BIOS call
+
+ mov ax,#0x4f00 ! AX = VESA BIOS func RETURN SVGA Info
+ push cs
+ pop es
+ lea di,vib ! ES:[DI] -> VESA Information Block Ptr
+ int 0x10
+
+ cmp ax,#0x004f ! Check result status
+ jne novesa ! VESA BIOS not supported or failed
+
+! OK! We got a VESA BIOS, let's figure out what we can do!
+
+! Print out the VESA information from the VIB
+
+ lea si,vib ! This should print out VESA
+ lodsb
+ call prnt1
+ lodsb
+ call prnt1
+ lodsb
+ call prnt1
+ lodsb
+ call prnt1
+ call space
+
+ mov al,vib+5 ! This is the version of VESA supported
+ call dprnt
+ mov al,#0x2e
+ call prnt1
+ mov al,vib+4
+ call dprnt
+ call space
+
+ push ds
+ lds si,vib+6 ! This prints out the OEM string
+ call prtstr
+ call space
+ pop ds
+
+ mov al,vib+10 ! This prints out the Vesa Capabilities
+ call dprnt
+ mov al,vib+11
+ call dprnt
+ mov al,vib+12
+ call dprnt
+ mov al,vib+13
+ call dprnt
+
+ push ds ! Finally, go through the list of modes
+ lds si,vib+14
+model: lodsw ! Get mode number
+ cmp ax,#0xFFFF
+ je isvesa
+ call addmod ! Check to see if this is a TEXT mode
+ jmp model
+
+isvesa: call docr
+ pop ds
+ lea si,dscvesa
+ lea di,movesa
+ lea cx,selmod
+ jmp cx
+
+novesa: mov ax,#0xc000
mov es,ax
lea si,msg1
- call prtstr
+ call prtstr ! Press <RETURN> to see SVGA-modes ...
flush: in al,#0x60 ! Flush the keyboard buffer
cmp al,#0x82
jb nokey
@@ -463,23 +529,38 @@ even7: mov al,#0x0c
mov al,#0x55
xor al,#0xea
cmp al,bh
- jne novid7
+ je isvideo7
+ lea cx,set8x8
+ jmp cx
+isvideo7:
lea si,dscvideo7
lea di,movideo7
+
+! Upon Entry to SELMOD, SI -> list of Modes, DI -> List of Mode Numbers
+
selmod: push si
- lea si,msg2
+ lea si,msg2 ! Numb: Mode: COLSxROWS
call prtstr
- xor cx,cx
- mov cl,(di)
+ mov cx,(di) ! This gets Number of Modes in list
pop si
push si
push cx
tbl: pop bx
push bx
- mov al,bl
- sub al,cl
- call dprnt
+ mov ax,bx
+ sub ax,cx
+ call hprntl ! Print out selection number
+ push ax
+ call spcing
+ pop ax
+ push di
+ add ax,ax
+ add ax,#2
+ add di,ax
+ mov ax,(di)
+ call hprntl ! Print out MODE number
call spcing
+ pop di
lodsw
xchg al,ah
call dprnt
@@ -493,7 +574,7 @@ tbl: pop bx
loop tbl
pop cx
call docr
- lea si,msg3
+ lea si,msg3 ! Choose Mode Number
call prtstr
pop si
add cl,#0x80
@@ -509,18 +590,38 @@ zero: sub al,#0x0a
nozero: sub al,#0x80
dec al
xor ah,ah
+ shl ax,#1
+ push ax
add di,ax
inc di
- push ax
- mov al,(di)
- int 0x10
+ inc di
+ mov ax,(di) ! AX = Mode
+ cmp ah,#0
+ jne setvesa
+ int 0x10 ! Set OLD style mode
+
+retmode:
pop ax
- shl ax,#1
add si,ax
- lodsw
+ lodsw ! Get COLSxROWS
pop ds
ret
-novid7:
+
+setvesa:
+ pop bx
+ cmp ah,#0xFF ! Special, mode FF, set 8x8 font
+ je set8x8
+
+ push bx
+ mov bx,ax ! Mode to set
+ mov ax,#0x4f02 ! Set VESA mode
+ int 0x10
+
+ jmp retmode
+
+! If we can't find the adapter in the table, at least set 80x50
+
+set8x8:
mov ax,#0x1112
mov bl,#0
int 0x10 ! use 8x8 font set (50 lines on VGA)
@@ -541,17 +642,83 @@ novid7:
mov ax,#0x5032 ! return 80x50
ret
+! Routine to add mode in ax to VESA selection table
+
+addmod: push cx
+ push ds
+ push es
+ push di
+ push bx
+ push dx
+ push ax
+
+ mov cx,ax ! CX = VESA mode number
+ push cs
+ pop es
+ lea di,mib ! ES:[DI] -> Mode Information Block
+ mov ax,#0x4f01 ! AX = Get VESA Mode Info
+ int 0x10
+
+ cmp ax,#0x004f ! If fails, assume it's not a TEXT mode
+ jne adfail
+
+ push cs
+ pop ds ! Make DS contain something reasonable
+
+ mov ax,mib ! Get Mode Attributes field
+ and al,#0x12 ! Mask Text and Extended bits
+ cmp al,#0x02 ! Text and Extended info available?
+ jne adfail
+
+ call space
+
+ mov ax,mib+18 ! Horizontal Resolution
+ mov bl,mib+22 ! X Char Size
+ div bl
+! HACK: For some reason, my Diamond Stealth card returns 160 cols for its
+! 132 coloumn modes, so don't return any sizes > 132?
+ sub al,#132
+ jbe orgcol
+ sub al,al
+orgcol: add al,#132 ! MIN(cols, 132)
+ mov dh,al ! Put num cols in DH
+ mov ax,mib+20 ! Vertical Resolution
+ mov bl,mib+23 ! Y Char Size
+ div bl
+ mov dl,al ! Put num rows in DL
+
+ mov bx,movesa ! Get current number of video modes
+ lea di,movesa
+ inc (di) ! This is a NEW mode
+ add bx,bx
+ add di,bx
+ add di,#2
+ pop ax ! Get Mode number back
+ push ax
+ mov (di),ax ! Mode number
+ lea di,dscvesa
+ add di,bx
+ mov (di),dx ! Screen resolution
+
+adfail: pop ax
+ pop dx
+ pop bx
+ pop di
+ pop es
+ pop ds
+ pop cx
+
+ ret
+
! Routine that 'tabs' to next col.
spcing: mov al,#0x2e
- call prnt1
- mov al,#0x20
call prnt1
- mov al,#0x20
+space3: mov al,#0x20
call prnt1
- mov al,#0x20
+space2: mov al,#0x20
call prnt1
- mov al,#0x20
+space: mov al,#0x20
call prnt1
ret
@@ -564,6 +731,39 @@ prtstr: lodsb
jmp prtstr
fin: ret
+! Routine to print out HEX values on screen.
+! The value to be printed is in the AX register.
+
+hprntl: xchg ah,al
+ call hprnt
+ xchg ah,al
+ call hprnt
+ ret
+
+! Routine to print out HEX values on the screen
+! The valueto be printed is in the AL register. AH is preserved.
+
+hprnt: push ax
+ shr al,4
+ and al,#0xf
+ call hprnt1
+ pop ax
+ push ax
+ and al,#0xf
+ call hprnt1
+ pop ax
+ ret
+
+! Routine to print out one HEX digit on the screen.
+! The value to be printed is in al (0-F)
+
+hprnt1: cmp al,#10
+ jl hdec
+ add al,#7 ! Convert 10-15 to A-F
+hdec: add al,#0x30 ! Convert to ASCII
+ call prnt1 ! print it
+ ret
+
! Routine to print a decimal value on screen, the value to be
! printed is put in al (i.e 0-255).
@@ -635,7 +835,7 @@ gdt_48:
msg1: .ascii "Press <RETURN> to see SVGA-modes available or any other key to continue."
db 0x0d, 0x0a, 0x0a, 0x00
-msg2: .ascii "Mode: COLSxROWS:"
+msg2: .ascii "Numb: Mode: COLSxROWS:"
db 0x0d, 0x0a, 0x0a, 0x00
msg3: .ascii "Choose mode by pressing the corresponding number."
db 0x0d, 0x0a, 0x00
@@ -647,16 +847,17 @@ 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
+moati: .word 0x02, 0x23, 0x33
+moahead: .word 0x05, 0x22, 0x23, 0x24, 0x2f, 0x34
+mocandt: .word 0x02, 0x60, 0x61
+mocirrus: .word 0x04, 0x1f, 0x20, 0x22, 0x31
+moeverex: .word 0x0a, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40
+mogenoa: .word 0x0a, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78
+moparadise: .word 0x02, 0x55, 0x54
+motrident: .word 0x07, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a
+motseng: .word 0x05, 0x26, 0x2a, 0x23, 0x24, 0x22
+movideo7: .word 0x06, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45
+movesa: .word 0x02, 0x03, 0xFFFF, 254*0
! msb = Cols lsb = Rows:
@@ -670,7 +871,11 @@ 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
+dscvesa: .word 0x5019, 0x5032, 254*0
+vib: .word 256*0
+mib: .word 256*0
+
.text
endtext:
.data
diff --git a/fs/exec.c b/fs/exec.c
index 4847eab..2bdbd9c 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -183,7 +183,7 @@ int sys_uselib(const char * library)
iput(inode);
return -EACCES;
}
- if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
+ if (!(bh = bread(inode->i_dev,bmap(inode,0)))) {
iput(inode);
return -EACCES;
}
@@ -406,7 +406,17 @@ restart_interp:
retval = -EACCES;
goto exec_error2;
}
+ if (IS_NOEXEC(inode)) { /* FS mustn't be mounted noexec */
+ retval = -EPERM;
+ goto exec_error2;
+ }
i = inode->i_mode;
+ if (IS_NOSUID(inode) && (((i & S_ISUID) && inode->i_uid != current->
+ euid) || ((i & S_ISGID) && inode->i_gid != current->egid)) &&
+ !suser()) {
+ retval = -EPERM;
+ goto exec_error2;
+ }
/* make sure we don't let suid, sgid files be ptraced. */
if (current->flags & PF_PTRACED) {
e_uid = current->euid;
@@ -424,7 +434,7 @@ restart_interp:
retval = -EACCES;
goto exec_error2;
}
- if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
+ if (!(bh = bread(inode->i_dev,bmap(inode,0)))) {
retval = -EACCES;
goto exec_error2;
}
diff --git a/fs/ext/bitmap.c b/fs/ext/bitmap.c
index 6125082..f5bad9f 100644
--- a/fs/ext/bitmap.c
+++ b/fs/ext/bitmap.c
@@ -203,6 +203,7 @@ struct inode * ext_new_inode(int dev)
iput(inode);
return NULL;
}
+ inode->i_flags = inode->i_sb->s_flags;
j = 8192;
for (i=0 ; i<8 ; i++)
if (bh=inode->i_sb->s_imap[i])
diff --git a/fs/ext/file.c b/fs/ext/file.c
index 28b365d..3fe77d3 100644
--- a/fs/ext/file.c
+++ b/fs/ext/file.c
@@ -153,8 +153,10 @@ static int ext_file_read(struct inode * inode, struct file * filp, char * buf, i
} while (left > 0);
if (!read)
return -EIO;
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
+ if (!IS_RDONLY(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
return read;
}
diff --git a/fs/ext/freelists.c b/fs/ext/freelists.c
index 8bdcf39..118fe09 100644
--- a/fs/ext/freelists.c
+++ b/fs/ext/freelists.c
@@ -70,12 +70,14 @@ int ext_free_block(int dev, int block)
if (bh->b_count)
brelse(bh);
}
- efb = (struct ext_free_block *) sb->s_zmap[1]->b_data;
- if (efb->count == 254) {
+ if (sb->s_zmap[1])
+ efb = (struct ext_free_block *) sb->s_zmap[1]->b_data;
+ if (!sb->s_zmap[1] || efb->count == 254) {
#ifdef EXTFS_DEBUG
printk("ext_free_block: block full, skipping to %d\n", block);
#endif
- brelse (sb->s_zmap[1]);
+ if (sb->s_zmap[1])
+ brelse (sb->s_zmap[1]);
if (!(sb->s_zmap[1] = bread (dev, block)))
panic ("ext_free_block: unable to read block to free\n");
efb = (struct ext_free_block *) sb->s_zmap[1]->b_data;
@@ -209,13 +211,15 @@ void ext_free_inode(struct inode * inode)
free_super (inode->i_sb);
return;
}
- efi = ((struct ext_free_inode *) inode->i_sb->s_imap[1]->b_data) +
- (((unsigned long) inode->i_sb->s_imap[0])-1)%EXT_INODES_PER_BLOCK;
- if (efi->count == 14) {
+ if (inode->i_sb->s_imap[1])
+ efi = ((struct ext_free_inode *) inode->i_sb->s_imap[1]->b_data) +
+ (((unsigned long) inode->i_sb->s_imap[0])-1)%EXT_INODES_PER_BLOCK;
+ if (!inode->i_sb->s_imap[1] || efi->count == 14) {
#ifdef EXTFS_DEBUG
printk("ext_free_inode: inode full, skipping to %d\n", inode->i_ino);
#endif
- brelse (inode->i_sb->s_imap[1]);
+ if (inode->i_sb->s_imap[1])
+ brelse (inode->i_sb->s_imap[1]);
block = 2 + (inode->i_ino - 1) / EXT_INODES_PER_BLOCK;
if (!(bh = bread(inode->i_dev, block)))
panic("ext_free_inode: unable to read inode block\n");
@@ -249,6 +253,7 @@ struct inode * ext_new_inode(int dev)
iput(inode);
return NULL;
}
+ inode->i_flags = inode->i_sb->s_flags;
if (!inode->i_sb->s_imap[1])
return 0;
lock_super (inode->i_sb);
diff --git a/fs/ext/namei.c b/fs/ext/namei.c
index 9fe48d4..b796a3a 100644
--- a/fs/ext/namei.c
+++ b/fs/ext/namei.c
@@ -808,6 +808,10 @@ start_up:
retval = 0;
goto end_rename;
}
+ if (S_ISDIR(new_inode->i_mode)) {
+ retval = -EEXIST;
+ goto end_rename;
+ }
if (S_ISDIR(old_inode->i_mode)) {
retval = -EEXIST;
if (new_bh)
diff --git a/fs/inode.c b/fs/inode.c
index f515afb..65637df 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -252,6 +252,7 @@ struct inode * iget(int dev,int nr)
}
inode->i_dev = dev;
inode->i_ino = nr;
+ inode->i_flags = inode->i_sb->s_flags;
read_inode(inode);
return inode;
}
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 84d6a9a..6c9ef40 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -6,6 +6,7 @@
#include <errno.h>
+#include <asm/segment.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/sched.h>
@@ -13,9 +14,17 @@
int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
+ int block;
if (fd >= NR_OPEN || !(filp = current->filp[fd]))
return -EBADF;
+ if (S_ISREG(filp->f_inode->i_mode) && cmd == BMAP_IOCTL &&
+ filp->f_inode->i_op->bmap) {
+ block = get_fs_long((long *) arg);
+ block = filp->f_inode->i_op->bmap(filp->f_inode,block);
+ put_fs_long(block,(long *) arg);
+ return 0;
+ }
if (filp->f_op && filp->f_op->ioctl)
return filp->f_op->ioctl(filp->f_inode, filp, cmd,arg);
return -EINVAL;
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index e4295db..4d560d4 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -191,6 +191,7 @@ struct inode * minix_new_inode(int dev)
iput(inode);
return NULL;
}
+ inode->i_flags = inode->i_sb->s_flags;
j = 8192;
for (i=0 ; i<8 ; i++)
if (bh=inode->i_sb->s_imap[i])
diff --git a/fs/minix/file.c b/fs/minix/file.c
index dba5631..cc7e33a 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -153,8 +153,10 @@ int minix_file_read(struct inode * inode, struct file * filp, char * buf, int co
} while (left > 0);
if (!read)
return -EIO;
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
+ if (!IS_RDONLY(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
return read;
}
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 6538c25..d7970cd 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -676,6 +676,10 @@ start_up:
retval = 0;
goto end_rename;
}
+ if (S_ISDIR(new_inode->i_mode)) {
+ retval = -EEXIST;
+ goto end_rename;
+ }
if (S_ISDIR(old_inode->i_mode)) {
retval = -EEXIST;
if (new_bh)
diff --git a/fs/namei.c b/fs/namei.c
index 510d38d..5c42fb7 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -229,6 +229,10 @@ int open_namei(const char * pathname, int flag, int mode,
iput(dir);
return -EACCES;
}
+ if (IS_RDONLY(dir)) {
+ iput(dir);
+ return -EROFS;
+ }
return dir->i_op->create(dir,basename,namelen,mode,res_inode);
}
if (flag & O_EXCL) {
@@ -238,17 +242,31 @@ int open_namei(const char * pathname, int flag, int mode,
}
if (!(inode = follow_link(dir,inode)))
return -ELOOP;
+ if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
+ if (IS_NODEV(inode)) {
+ iput(inode);
+ return -EACCES;
+ }
+ } else {
+ if (IS_RDONLY(inode) && (flag & (O_TRUNC | O_ACCMODE))) {
+ iput(inode);
+ return -EROFS;
+ }
+ }
if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
!permission(inode,ACC_MODE(flag))) {
iput(inode);
return -EPERM;
}
- inode->i_atime = CURRENT_TIME;
if (flag & O_TRUNC)
if (inode->i_op && inode->i_op->truncate) {
inode->i_size = 0;
inode->i_op->truncate(inode);
}
+ if (!IS_RDONLY(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
*res_inode = inode;
return 0;
}
@@ -265,6 +283,10 @@ int do_mknod(const char * filename, int mode, int dev)
iput(dir);
return -ENOENT;
}
+ if (IS_RDONLY(dir)) {
+ iput(dir);
+ return -EROFS;
+ }
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EACCES;
@@ -295,6 +317,10 @@ int sys_mkdir(const char * pathname, int mode)
iput(dir);
return -ENOENT;
}
+ if (IS_RDONLY(dir)) {
+ iput(dir);
+ return -EROFS;
+ }
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EACCES;
@@ -318,6 +344,10 @@ int sys_rmdir(const char * name)
iput(dir);
return -ENOENT;
}
+ if (IS_RDONLY(dir)) {
+ iput(dir);
+ return -EROFS;
+ }
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EACCES;
@@ -341,6 +371,10 @@ int sys_unlink(const char * name)
iput(dir);
return -EPERM;
}
+ if (IS_RDONLY(dir)) {
+ iput(dir);
+ return -EROFS;
+ }
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EACCES;
@@ -365,6 +399,10 @@ int sys_symlink(const char * oldname, const char * newname)
iput(dir);
return -ENOENT;
}
+ if (IS_RDONLY(dir)) {
+ iput(dir);
+ return -EROFS;
+ }
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EACCES;
@@ -395,6 +433,11 @@ int sys_link(const char * oldname, const char * newname)
iput(dir);
return -EPERM;
}
+ if (IS_RDONLY(dir)) {
+ iput(oldinode);
+ iput(dir);
+ return -EROFS;
+ }
if (dir->i_dev != oldinode->i_dev) {
iput(dir);
iput(oldinode);
@@ -454,6 +497,11 @@ int sys_rename(const char * oldname, const char * newname)
iput(new_dir);
return -EXDEV;
}
+ if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
+ iput(old_dir);
+ iput(new_dir);
+ return -EROFS;
+ }
if (!old_dir->i_op || !old_dir->i_op->rename) {
iput(old_dir);
iput(new_dir);
diff --git a/fs/open.c b/fs/open.c
index b047d39..275e429 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -73,6 +73,10 @@ int sys_truncate(const char * path, unsigned int length)
iput(inode);
return -EACCES;
}
+ if (IS_RDONLY(inode)) {
+ iput(inode);
+ return -EROFS;
+ }
inode->i_size = length;
if (inode->i_op && inode->i_op->truncate)
inode->i_op->truncate(inode);
@@ -91,7 +95,7 @@ int sys_ftruncate(unsigned int fd, unsigned int length)
return -EBADF;
if (!(inode = file->f_inode))
return -ENOENT;
- if (S_ISDIR(inode->i_mode) || !(file->f_flags & 2))
+ if (S_ISDIR(inode->i_mode) || !(file->f_mode & 2))
return -EACCES;
inode->i_size = length;
if (inode->i_op && inode->i_op->truncate)
@@ -112,6 +116,10 @@ int sys_utime(char * filename, struct utimbuf * times)
if (!(inode=namei(filename)))
return -ENOENT;
+ if (IS_RDONLY(inode)) {
+ iput(inode);
+ return -EROFS;
+ }
if (times) {
if ((current->euid != inode->i_uid) && !suser()) {
iput(inode);
@@ -215,6 +223,8 @@ int sys_fchmod(unsigned int fd, mode_t mode)
return -ENOENT;
if ((current->euid != inode->i_uid) && !suser())
return -EPERM;
+ if (IS_RDONLY(inode))
+ return -EROFS;
inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
inode->i_dirt = 1;
return 0;
@@ -230,6 +240,10 @@ int sys_chmod(const char * filename, mode_t mode)
iput(inode);
return -EPERM;
}
+ if (IS_RDONLY(inode)) {
+ iput(inode);
+ return -EROFS;
+ }
inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
inode->i_dirt = 1;
iput(inode);
@@ -245,6 +259,8 @@ int sys_fchown(unsigned int fd, uid_t user, gid_t group)
return -EBADF;
if (!(inode = file->f_inode))
return -ENOENT;
+ if (IS_RDONLY(inode))
+ return -EROFS;
if ((current->euid == inode->i_uid && user == inode->i_uid &&
(in_group_p(group) || group == inode->i_gid)) ||
suser()) {
@@ -262,6 +278,10 @@ int sys_chown(const char * filename, uid_t user, gid_t group)
if (!(inode = lnamei(filename)))
return -ENOENT;
+ if (IS_RDONLY(inode)) {
+ iput(inode);
+ return -EROFS;
+ }
if ((current->euid == inode->i_uid && user == inode->i_uid &&
(in_group_p(group) || group == inode->i_gid)) ||
suser()) {
@@ -325,6 +345,7 @@ int sys_creat(const char * pathname, int mode)
int sys_close(unsigned int fd)
{
struct file * filp;
+ struct inode * inode;
if (fd >= NR_OPEN)
return -EINVAL;
@@ -340,9 +361,10 @@ int sys_close(unsigned int fd)
filp->f_count--;
return 0;
}
+ inode = filp->f_inode;
if (filp->f_op && filp->f_op->release)
- filp->f_op->release(filp->f_inode,filp);
- iput(filp->f_inode);
+ filp->f_op->release(inode,filp);
filp->f_count--;
+ iput(inode);
return 0;
}
diff --git a/fs/super.c b/fs/super.c
index e85eeae..5e773ef 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -11,6 +11,7 @@
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/ext_fs.h>
+/* #include <linux/msdos_fs.h> */
#include <linux/kernel.h>
#include <linux/stat.h>
#include <asm/system.h>
@@ -18,6 +19,7 @@
#include <errno.h>
+
int sync_dev(int dev);
void wait_for_keypress(void);
@@ -36,6 +38,7 @@ int ROOT_DEV = 0;
static struct file_system_type file_systems[] = {
{minix_read_super,"minix"},
{ext_read_super,"ext"},
+ /* {msdos_read_super,"msdos"}, */
{NULL,NULL}
};
@@ -112,7 +115,7 @@ void put_super(int dev)
sb->s_op->put_super(sb);
}
-static struct super_block * read_super(int dev,char *name,void *data)
+static struct super_block * read_super(int dev,char *name,int flags,void *data)
{
struct super_block * s;
struct file_system_type *type;
@@ -133,6 +136,7 @@ static struct super_block * read_super(int dev,char *name,void *data)
break;
}
s->s_dev = dev;
+ s->s_flags = flags;
if (!type->read_super(s,data))
return(NULL);
s->s_dev = dev;
@@ -183,27 +187,23 @@ int sys_umount(char * dev_name)
return 0;
}
-int sys_mount(char * dev_name, char * dir_name, char * type, int rw_flag)
+/*
+ * do_mount() does the actual mounting after sys_mount has done the ugly
+ * parameter parsing. When enough time has gone by, and everything uses the
+ * new mount() parameters, sys_mount() can then be cleaned up.
+ *
+ * We cannot mount a filesystem if it has active, used, or dirty inodes.
+ * We also have to flush all inode-data for this device, as the new mount
+ * might need new info.
+ */
+static int do_mount(int dev, const char * dir, char * type, int flags, void * data)
{
- struct inode * dev_i, * dir_i;
+ struct inode * inode, * dir_i;
struct super_block * sb;
- int dev;
- char tmp[100],*t;
- int i;
- if (!suser())
- return -EPERM;
- if (!(dev_i = namei(dev_name)))
- return -ENOENT;
- dev = dev_i->i_rdev;
- if (!S_ISBLK(dev_i->i_mode)) {
- iput(dev_i);
- return -EPERM;
- }
- iput(dev_i);
- if (!(dir_i=namei(dir_name)))
+ if (!(dir_i = namei(dir)))
return -ENOENT;
- if (dir_i->i_count != 1 || dir_i->i_ino == MINIX_ROOT_INO) {
+ if (dir_i->i_count != 1 || dir_i->i_mount) {
iput(dir_i);
return -EBUSY;
}
@@ -211,29 +211,82 @@ int sys_mount(char * dev_name, char * dir_name, char * type, int rw_flag)
iput(dir_i);
return -EPERM;
}
- if (dir_i->i_mount) {
+ for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++) {
+ if (inode->i_dev != dev)
+ continue;
+ if (inode->i_count || inode->i_dirt || inode->i_lock) {
+ iput(dir_i);
+ return -EBUSY;
+ }
+ inode->i_dev = 0;
+ }
+ sb = read_super(dev,type,flags,data);
+ if (!sb || sb->s_covered) {
iput(dir_i);
+ return -EBUSY;
+ }
+ sb->s_flags = flags;
+ sb->s_covered = dir_i;
+ dir_i->i_mount = 1;
+ return 0; /* we don't iput(dir_i) - see umount */
+}
+
+/*
+ * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to
+ * be given to the mount() call (ie: read-only, no-dev, no-suid etc).
+ *
+ * data is a (void *) that can point to any structure up to 4095 bytes, which
+ * can contain arbitrary fs-dependent information (or be NULL).
+ *
+ * NOTE! As old versions of mount() didn't use this setup, the flags has to have
+ * a special 16-bit magic number in the hight word: 0xC0ED. If this magic word
+ * isn't present, the flags and data info isn't used, as the syscall assumes we
+ * are talking to an older version that didn't understand them.
+ */
+int sys_mount(char * dev_name, char * dir_name, char * type,
+ unsigned long new_flags, void *data)
+{
+ struct inode * inode;
+ int dev;
+ int retval = 0;
+ char tmp[100],*t;
+ int i;
+ unsigned long flags = 0;
+ unsigned long page = 0;
+
+ if (!suser())
return -EPERM;
+ if (!(inode = namei(dev_name)))
+ return -ENOENT;
+ dev = inode->i_rdev;
+ if (!S_ISBLK(inode->i_mode))
+ retval = -EPERM;
+ else if (IS_NODEV(inode))
+ retval = -EACCES;
+ iput(inode);
+ if (retval)
+ return retval;
+ if ((new_flags & 0xffff0000) == 0xC0ED0000) {
+ flags = new_flags & 0xffff;
+ if (data && (unsigned long) data < TASK_SIZE)
+ page = get_free_page();
+ }
+ if (page) {
+ i = TASK_SIZE - (unsigned long) data;
+ if (i < 0 || i > 4095)
+ i = 4095;
+ memcpy_fromfs((void *) page,data,i);
}
if (type) {
- i = 0;
- while (i < 100 && (tmp[i] = get_fs_byte(type++)))
- i++;
+ for (i = 0 ; i < 100 ; i++)
+ if (!(tmp[i] = get_fs_byte(type++)))
+ break;
t = tmp;
} else
t = "minix";
- if (!(sb = read_super(dev,t,NULL))) {
- iput(dir_i);
- return -EBUSY;
- }
- if (sb->s_covered) {
- iput(dir_i);
- return -EBUSY;
- }
- sb->s_covered = dir_i;
- dir_i->i_mount = 1;
- dir_i->i_dirt = 1; /* NOTE! we don't iput(dir_i) */
- return 0; /* we do that in umount */
+ retval = do_mount(dev,dir_name,t,flags,(void *) page);
+ free_page(page);
+ return retval;
}
void mount_root(void)
@@ -255,7 +308,7 @@ void mount_root(void)
p->s_lock = 0;
p->s_wait = NULL;
}
- if (!(p=read_super(ROOT_DEV,"minix",NULL)))
+ if (!(p=read_super(ROOT_DEV,"minix",0,NULL)))
panic("Unable to mount root");
/*wait_for_keypress();
if (!(mi=iget(ROOT_DEV,MINIX_ROOT_INO)))
@@ -264,6 +317,7 @@ void mount_root(void)
mi=p->s_mounted;
mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
p->s_mounted = p->s_covered = mi;
+ p->s_flags = 0;
current->pwd = mi;
current->root = mi;
free=0;
diff --git a/include/asm/irq.h b/include/asm/irq.h
new file mode 100644
index 0000000..a51e573
--- /dev/null
+++ b/include/asm/irq.h
@@ -0,0 +1,75 @@
+#ifndef _ASM_IRQ_H
+#define _ASM_IRQ_H
+
+/*
+ * linux/include/asm/irq.h
+ *
+ * (C) 1992 Linus Torvalds
+ */
+
+#define SAVE_ALL \
+ "cld\n\t" \
+ "push %gs\n\t" \
+ "push %fs\n\t" \
+ "push %es\n\t" \
+ "push %ds\n\t" \
+ "pushl %eax\n\t" \
+ "pushl %ebp\n\t" \
+ "pushl %edi\n\t" \
+ "pushl %esi\n\t" \
+ "pushl %edx\n\t" \
+ "pushl %ecx\n\t" \
+ "pushl %ebx\n\t" \
+ "movl $0x10,%edx\n\t" \
+ "mov %dx,%ds\n\t" \
+ "mov %dx,%es\n\t" \
+ "movl $0x17,%edx\n\t" \
+ "mov %dx,%fs\n\t"
+
+#define ACK_FIRST(mask) \
+ "inb $0x21,%al\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\torb $" #mask ",%al\n\t" \
+ "outb %al,$0x21\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\tmovb $0x20,%al\n\t" \
+ "outb %al,$0x20\n\t"
+
+#define ACK_SECOND(mask) \
+ "inb $0xA1,%al\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\torb $" #mask ",%al\n\t" \
+ "outb %al,$0xA1\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\tmovb $0x20,%al\n\t" \
+ "outb %al,$0xA0" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\toutb %al,$0x20\n\t"
+
+#define IRQ_NAME2(nr) nr##_interrupt()
+#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
+
+#define BUILD_IRQ(chip,nr,mask) \
+extern void IRQ_NAME(nr); \
+__asm__( \
+"\n.align 2\n" \
+".globl _IRQ" #nr "_interrupt\n" \
+"_IRQ" #nr "_interrupt:\n\t" \
+ "pushl $-1\n\t" \
+ SAVE_ALL \
+ "cli\n\t" \
+ ACK_##chip(mask) \
+ "sti\n\t" \
+ "movl %esp,%ebx\n\t" \
+ "pushl %ebx\n\t" \
+ "pushl $" #nr "\n\t" \
+ "call _do_IRQ\n\t" \
+ "addl $8,%esp\n\t" \
+ "jmp ret_from_sys_call");
+
+#endif
diff --git a/include/linux/config.h b/include/linux/config.h
index db499dc..0e5f4cd 100644
--- a/include/linux/config.h
+++ b/include/linux/config.h
@@ -26,7 +26,7 @@
#define DEF_INITSEG 0x9000
#define DEF_SYSSEG 0x1000
#define DEF_SETUPSEG 0x9020
-#define DEF_SYSSIZE 0x4000
+#define DEF_SYSSIZE 0x5000
/*
* The root-device is no longer hard-coded. You can change the default
diff --git a/include/linux/fs.h b/include/linux/fs.h
index cd6834d..9aa8f64 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -43,7 +43,7 @@ void buffer_init(long buffer_end);
#define NR_OPEN 32
#define NR_INODE 128
-#define NR_FILE 64
+#define NR_FILE 128
#define NR_SUPER 8
#define NR_HASH 307
#define NR_BUFFERS nr_buffers
@@ -71,6 +71,33 @@ void buffer_init(long buffer_end);
#define SEL_OUT 2
#define SEL_EX 4
+/*
+ * These are the fs-independent mount-flags: up to 16 flags are supported
+ */
+#define MS_RDONLY 1 /* mount read-only */
+#define MS_NOSUID 2 /* ignore suid and sgid bits */
+#define MS_NODEV 4 /* disallow access to device special files */
+#define MS_NOEXEC 8 /* disallow program execution */
+
+/*
+ * Note that read-only etc flags are inode-specific: setting some file-system
+ * flags just means all the inodes inherit those flags by default. It might be
+ * possible to overrride it sevelctively if you really wanted to with some
+ * ioctl() that is not currently implemented.
+ */
+#define IS_RDONLY(inode) ((inode)->i_flags & MS_RDONLY)
+#define IS_NOSUID(inode) ((inode)->i_flags & MS_NOSUID)
+#define IS_NODEV(inode) ((inode)->i_flags & MS_NODEV)
+#define IS_NOEXEC(inode) ((inode)->i_flags & MS_NOEXEC)
+
+/* the read-only stuff doesn't really belong here, but any other place is
+ probably as bad and I don't want to create yet another include file. */
+
+#define BLKROSET 4701 /* set device read-only (0 = read-write) */
+#define BLKROGET 4702 /* get read-only status (0 = read_write) */
+
+#define BMAP_IOCTL 1
+
typedef char buffer_block[BLOCK_SIZE];
struct buffer_head {
@@ -107,6 +134,7 @@ struct inode {
struct task_struct * i_wait;
struct task_struct * i_wait2; /* for pipes */
unsigned short i_count;
+ unsigned short i_flags;
unsigned char i_lock;
unsigned char i_dirt;
unsigned char i_pipe;
@@ -120,6 +148,7 @@ struct file {
unsigned short f_flags;
unsigned short f_count;
unsigned short f_reada;
+ unsigned short f_rdev; /* needed for /dev/tty */
struct inode * f_inode;
struct file_operations * f_op;
off_t f_pos;
@@ -159,6 +188,7 @@ struct super_block {
unsigned char s_dirt;
/* TUBE */
struct super_operations *s_op;
+ int s_flags;
};
struct file_operations {
diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h
index e7e1347..67e5386 100644
--- a/include/linux/hdreg.h
+++ b/include/linux/hdreg.h
@@ -69,5 +69,6 @@ struct hd_geometry {
unsigned char heads;
unsigned char sectors;
unsigned short cylinders;
+ unsigned long start;
};
#endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index e1e3559..206d9f1 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -228,6 +228,10 @@ 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);
+extern int request_irq(unsigned int irq,void (*handler)(int));
+extern void free_irq(unsigned int irq);
+extern int irqaction(unsigned int irq,struct sigaction * new);
+
/*
* Entry into gdt where to find first TSS. 0-nul, 1-cs, 2-ds, 3-syscall
* 4-TSS0, 5-LDT0, 6-TSS1 etc ...
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 7e54066..4970ded 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -69,8 +69,6 @@ struct serial_struct {
extern void put_tty_queue(char c, struct tty_queue * queue);
extern int get_tty_queue(struct tty_queue * queue);
-#define PUTCH(c,queue) put_tty_queue((c),(queue))
-#define GETCH(queue) get_tty_queue(queue)
#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR])
#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT])
#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE])
@@ -166,6 +164,7 @@ extern long tty_init(long);
extern void flush_input(struct tty_struct * tty);
extern void flush_output(struct tty_struct * tty);
+extern void wait_until_sent(struct tty_struct * tty);
extern void copy_to_cooked(struct tty_struct * tty);
extern int tty_ioctl(struct inode *, struct file *, unsigned int, unsigned int);
diff --git a/include/sys/time.h b/include/sys/time.h
index 9d1f785..1ef722b 100644
--- a/include/sys/time.h
+++ b/include/sys/time.h
@@ -55,7 +55,7 @@ struct itimerval {
};
int getitimer(int which, struct itimerval *value);
-int setitimer(int which, struct itimerval *value, struct itimerval *ovalue);
+int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
#include <time.h>
#include <sys/types.h>
diff --git a/init/main.c b/init/main.c
index c6ede55..1f6174d 100644
--- a/init/main.c
+++ b/init/main.c
@@ -53,6 +53,7 @@ static char printbuf[1024];
extern int vsprintf();
extern void init(void);
+extern void init_IRQ(void);
extern long blk_dev_init(long,long);
extern long chr_dev_init(long,long);
extern void hd_init(void);
@@ -164,6 +165,7 @@ void start_kernel(void)
buffer_memory_end = 1*1024*1024;
main_memory_start = buffer_memory_end;
trap_init();
+ init_IRQ();
sched_init();
main_memory_start = chr_dev_init(main_memory_start,memory_end);
main_memory_start = blk_dev_init(main_memory_start,memory_end);
@@ -183,14 +185,16 @@ void start_kernel(void)
init();
}
/*
- * NOTE!! For any other task 'pause()' would mean we have to get a
- * signal to awaken, but task0 is the sole exception (see 'schedule()')
- * as task 0 gets activated at every idle moment (when no other tasks
- * can run). For task0 'pause()' just means we go check if some other
- * task can run, and if not we return here.
+ * task[0] is meant to be used as an "idle" task: it may not sleep, but
+ * it might do some general things like count free pages or it could be
+ * used to implement a reasonable LRU algorithm for the paging routines:
+ * anything that can be useful, but shouldn't take time from the real
+ * processes.
+ *
+ * Right now task[0] just does a infinite loop in user mode.
*/
for(;;)
- __asm__("int $0x80"::"a" (__NR_pause):"ax");
+ /* nothing */ ;
}
static int printf(const char *fmt, ...)
diff --git a/kernel/Makefile b/kernel/Makefile
index d72629e..3b1c608 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -18,7 +18,7 @@
SUBDIRS = chr_drv blk_drv math
-OBJS = sched.o sys_call.o traps.o asm.o fork.o \
+OBJS = sched.o sys_call.o traps.o irq.o fork.o \
panic.o printk.o vsprintf.o sys.o exit.o \
signal.o mktime.o ptrace.o ioport.o itimer.o
@@ -73,6 +73,13 @@ ioport.o : ioport.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/
/usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/signal.h \
/usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h /usr/src/linux/include/time.h \
/usr/src/linux/include/sys/resource.h /usr/src/linux/include/errno.h
+irq.o : irq.c /usr/src/linux/include/signal.h /usr/src/linux/include/sys/types.h \
+ /usr/src/linux/include/stddef.h /usr/src/linux/include/errno.h /usr/src/linux/include/sys/ptrace.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/sys/param.h \
+ /usr/src/linux/include/sys/time.h /usr/src/linux/include/time.h /usr/src/linux/include/sys/resource.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/io.h /usr/src/linux/include/asm/irq.h
itimer.o : itimer.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
/usr/src/linux/include/linux/fs.h /usr/src/linux/include/sys/types.h /usr/src/linux/include/stddef.h \
/usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h \
diff --git a/kernel/blk_drv/blk.h b/kernel/blk_drv/blk.h
index 4535f6d..430d88e 100644
--- a/kernel/blk_drv/blk.h
+++ b/kernel/blk_drv/blk.h
@@ -54,6 +54,14 @@ extern struct task_struct * wait_for_request;
extern int * blk_size[NR_BLK_DEV];
+extern int is_read_only(int dev);
+extern void set_device_ro(int dev,int flag);
+
+#define RO_IOCTLS(dev,where) \
+ case BLKROSET: if (!suser()) return -EPERM; \
+ set_device_ro((dev),get_fs_long((long *) (where))); return 0; \
+ case BLKROGET: put_fs_long(is_read_only(dev),(long *) (where)); return 0;
+
#ifdef MAJOR_NR
/*
diff --git a/kernel/blk_drv/floppy.c b/kernel/blk_drv/floppy.c
index dde66a9..bf8f22a 100644
--- a/kernel/blk_drv/floppy.c
+++ b/kernel/blk_drv/floppy.c
@@ -38,6 +38,8 @@
* the floppy-change signal detection.
*/
+#define FLOPPY_IRQ 6
+
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
@@ -205,7 +207,6 @@ static struct format_descr format_req;
* and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA).
*/
-extern void floppy_interrupt(void);
extern char tmp_floppy_area[1024];
extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
@@ -560,7 +561,7 @@ static void recal_interrupt(void)
else redo_fd_request();
}
-void unexpected_floppy_interrupt(void)
+static void unexpected_floppy_interrupt(void)
{
current_track = NO_TRACK;
output_byte(FD_SENSEI);
@@ -831,6 +832,9 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
int drive,cnt,okay;
struct floppy_struct *this;
+ switch (cmd) {
+ RO_IOCTLS(inode->i_rdev,param);
+ }
if (!suser()) return -EPERM;
drive = MINOR(inode->i_rdev);
switch (cmd) {
@@ -975,6 +979,28 @@ static struct file_operations floppy_fops = {
floppy_release /* release */
};
+static void floppy_interrupt(int cpl)
+{
+ void (*handler)(void) = DEVICE_INTR;
+
+ DEVICE_INTR = NULL;
+ if (!handler)
+ handler = unexpected_floppy_interrupt;
+ handler();
+}
+
+/*
+ * This is the harddisk IRQ descruption. The SA_INTERRUPT in sa_flags
+ * means we run the IRQ-handler with interrupts disabled: this is bad for
+ * interrupt latency, but may be safer...
+ */
+static struct sigaction floppy_sigaction = {
+ floppy_interrupt,
+ 0,
+ SA_INTERRUPT,
+ NULL
+};
+
void floppy_init(void)
{
outb(current_DOR,FD_DOR);
@@ -984,6 +1010,6 @@ void floppy_init(void)
timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
timer_active &= ~(1 << FLOPPY_TIMER);
config_types();
- set_intr_gate(0x26,&floppy_interrupt);
- outb(inb_p(0x21)&~0x40,0x21);
+ if (irqaction(FLOPPY_IRQ,&floppy_sigaction))
+ printk("Unable to grab IRQ%d for the floppy driver\n",FLOPPY_IRQ);
}
diff --git a/kernel/blk_drv/hd.c b/kernel/blk_drv/hd.c
index e573315..8ff900d 100644
--- a/kernel/blk_drv/hd.c
+++ b/kernel/blk_drv/hd.c
@@ -16,7 +16,10 @@
* in the early extended-partition checks and added DM partitions
*/
+#define HD_IRQ 14
+
#include <errno.h>
+#include <signal.h>
#include <linux/config.h>
#include <linux/sched.h>
@@ -82,7 +85,6 @@ __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write(port,buf,nr) \
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
-extern void hd_interrupt(void);
extern void rd_load(void);
static unsigned int current_minor;
@@ -279,7 +281,9 @@ int sys_setup(void * BIOS)
blk_size[MAJOR_NR] = hd_sizes;
if (NR_HD)
printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
+#ifdef RAMDISK
rd_load();
+#endif
mount_root();
return (0);
}
@@ -517,7 +521,7 @@ static void recal_intr(void)
*/
static void hd_times_out(void)
{
- do_hd = NULL;
+ DEVICE_INTR = NULL;
reset = 1;
if (!CURRENT)
return;
@@ -601,7 +605,10 @@ static int hd_ioctl(struct inode * inode, struct file * file,
(char *) &loc->sectors);
put_fs_word(hd_info[dev].cyl,
(short *) &loc->cylinders);
+ put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
+ (long *) &loc->start);
return 0;
+ RO_IOCTLS(inode->i_rdev,arg);
default:
return -EINVAL;
}
@@ -627,12 +634,35 @@ static struct file_operations hd_fops = {
hd_release /* release */
};
+static void hd_interrupt(int cpl)
+{
+ void (*handler)(void) = DEVICE_INTR;
+
+ DEVICE_INTR = NULL;
+ timer_active &= ~(1<<HD_TIMER);
+ if (!handler)
+ handler = unexpected_hd_interrupt;
+ handler();
+}
+
+/*
+ * This is the harddisk IRQ descruption. The SA_INTERRUPT in sa_flags
+ * means we run the IRQ-handler with interrupts disabled: this is bad for
+ * interrupt latency, but anything else has led to problems on some
+ * machines...
+ */
+static struct sigaction hd_sigaction = {
+ hd_interrupt,
+ 0,
+ SA_INTERRUPT,
+ NULL
+};
+
void hd_init(void)
{
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
blkdev_fops[MAJOR_NR] = &hd_fops;
- set_intr_gate(0x2E,&hd_interrupt);
- outb_p(inb_p(0x21)&0xfb,0x21);
- outb(inb_p(0xA1)&0xbf,0xA1);
+ if (irqaction(HD_IRQ,&hd_sigaction))
+ printk("Unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
timer_table[HD_TIMER].fn = hd_times_out;
}
diff --git a/kernel/blk_drv/ll_rw_blk.c b/kernel/blk_drv/ll_rw_blk.c
index 9a09e7e..ab2d64e 100644
--- a/kernel/blk_drv/ll_rw_blk.c
+++ b/kernel/blk_drv/ll_rw_blk.c
@@ -8,6 +8,7 @@
* This handles all read/write requests to block devices
*/
#include <errno.h>
+#include <linux/string.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/system.h>
@@ -70,6 +71,31 @@ static inline void unlock_buffer(struct buffer_head * bh)
wake_up(&bh->b_wait);
}
+/* RO fail safe mechanism */
+
+static long ro_bits[NR_BLK_DEV][8];
+
+int is_read_only(int dev)
+{
+ int minor,major;
+
+ major = MAJOR(dev);
+ minor = MINOR(dev);
+ if (major < 0 || major >= NR_BLK_DEV) return 0;
+ return ro_bits[major][minor >> 5] & (1 << (minor & 31));
+}
+
+void set_device_ro(int dev,int flag)
+{
+ int minor,major;
+
+ major = MAJOR(dev);
+ minor = MINOR(dev);
+ if (major < 0 || major >= NR_BLK_DEV) return;
+ if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31);
+ else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
+}
+
/*
* add-request adds a request to the linked list.
* It disables interrupts so that it can muck with the
@@ -203,6 +229,10 @@ void ll_rw_page(int rw, int dev, int page, char * buffer)
}
if (rw!=READ && rw!=WRITE)
panic("Bad block dev command, must be R/W");
+ if (rw == WRITE && is_read_only(dev)) {
+ printk("Can't page to read-only device 0x%X\n\r",dev);
+ return;
+ }
cli();
repeat:
req = request+NR_REQUEST;
@@ -238,6 +268,12 @@ void ll_rw_block(int rw, struct buffer_head * bh)
if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV ||
!(blk_dev[major].request_fn)) {
printk("ll_rw_block: Trying to read nonexistent block-device\n\r");
+ bh->b_dirt = bh->b_uptodate = 0;
+ return;
+ }
+ if ((rw == WRITE || rw == WRITEA) && is_read_only(bh->b_dev)) {
+ printk("Can't write to read-only device 0x%X\n\r",bh->b_dev);
+ bh->b_dirt = bh->b_uptodate = 0;
return;
}
make_request(major,rw,bh);
@@ -251,6 +287,7 @@ long blk_dev_init(long mem_start, long mem_end)
request[i].dev = -1;
request[i].next = NULL;
}
+ memset(ro_bits,0,sizeof(ro_bits));
#ifdef RAMDISK
mem_start += rd_init(mem_start, RAMDISK*1024);
#endif
@@ -272,6 +309,10 @@ void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
printk("ll_rw_swap: bad block dev command, must be R/W");
return;
}
+ if (rw == WRITE && is_read_only(dev)) {
+ printk("Can't swap to read-only device 0x%X\n\r",dev);
+ return;
+ }
for (i=0; i<nb; i++, buf += BLOCK_SIZE)
{
diff --git a/kernel/blk_drv/ramdisk.c b/kernel/blk_drv/ramdisk.c
index 761b4f0..833322f 100644
--- a/kernel/blk_drv/ramdisk.c
+++ b/kernel/blk_drv/ramdisk.c
@@ -84,7 +84,7 @@ long rd_init(long mem_start, int length)
void rd_load(void)
{
struct buffer_head *bh;
- struct super_block s;
+ struct minix_super_block s;
int block = 256; /* Start at block 256 */
int i = 1;
int nblocks;
diff --git a/kernel/blk_drv/scsi/aha1542.c b/kernel/blk_drv/scsi/aha1542.c
index 635c080..f09a2f2 100644
--- a/kernel/blk_drv/scsi/aha1542.c
+++ b/kernel/blk_drv/scsi/aha1542.c
@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <linux/head.h>
#include <linux/string.h>
+#include <linux/sched.h>
#include <asm/system.h>
#include <asm/io.h>
#include <sys/types.h>
@@ -34,7 +35,6 @@ static struct ccb ccb;
long WAITtimeout, WAITnexttimeout = 3000000;
void (*do_done)() = NULL;
-extern void aha1542_interrupt();
#define aha1542_intr_reset() outb(IRST, CONTROL)
#define aha1542_enable_intr() outb(inb_p(0xA1) & ~8, 0xA1)
@@ -192,7 +192,7 @@ char *aha1542_info(void)
}
/* A "high" level interrupt handler */
-void aha1542_intr_handle(void)
+static void aha1542_interrupt(int cpl)
{
int flag = inb(INTRFLAGS);
void (*my_done)() = do_done;
@@ -200,7 +200,7 @@ void aha1542_intr_handle(void)
do_done = NULL;
#ifdef DEBUG
- printk("aha1542_intr_handle: ");
+ printk("aha1542_interrupt: ");
if (!(flag&ANYINTR)) printk("no interrupt?");
if (flag&MBIF) printk("MBIF ");
if (flag&MBOA) printk("MBOF ");
@@ -212,14 +212,14 @@ void aha1542_intr_handle(void)
#endif
aha1542_intr_reset();
if (!my_done) {
- printk("aha1542_intr_handle: Unexpected interrupt\n");
+ printk("aha1542_interrupt: Unexpected interrupt\n");
return;
}
/* is there mail :-) */
if (!mb[1].status) {
- DEB(printk("aha1542_intr_handle: strange: mbif but no mail!\n"));
+ DEB(printk("aha1542_interrupt: strange: mbif but no mail!\n"));
my_done(DID_TIME_OUT << 16);
return;
}
@@ -235,18 +235,18 @@ void aha1542_intr_handle(void)
if (ccb.tarstat == 2) {
int i;
- DEB(printk("aha1542_intr_handle: sense:"));
+ DEB(printk("aha1542_interrupt: sense:"));
for (i = 0; i < 12; i++)
printk("%02x ", ccb.cdb[ccb.cdblen+i]);
printk("\n");
/*
- DEB(printk("aha1542_intr_handle: buf:"));
+ DEB(printk("aha1542_interrupt: buf:"));
for (i = 0; i < bufflen; i++)
printk("%02x ", ((unchar *)buff)[i]);
printk("\n");
*/
}
- DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
+ DEB(if (errstatus) printk("aha1542_interrupt: returning %6x\n", errstatus));
my_done(errstatus);
return;
}
@@ -355,7 +355,14 @@ static void setup_mailboxes()
void call_buh()
{
- set_intr_gate(0x2b,&aha1542_interrupt);
+ struct sigaction sa;
+
+ sa.sa_handler = aha1542_interrupt;
+ sa.sa_flags = SA_INTERRUPT;
+ sa.sa_mask = 0;
+ sa.sa_restorer = NULL;
+ if (irqaction(intr_chan,&sa))
+ printk("Unable to allocate IRQ%d for aha controller\n", intr_chan);
}
/* return non-zero on detection */
@@ -448,35 +455,3 @@ int aha1542_reset(void)
DEB(printk("aha1542_reset called\n"));
return 0;
}
-
-__asm__("
-_aha1542_interrupt:
- cld
- 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: outb %al,$0x20
-# Please, someone, change this to use the timer
-# andl $0xfffeffff,_timer_active
- movl $_aha1542_intr_handle,%edx
- call *%edx # ``interesting'' way of handling intr.
- pop %fs
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- popl %eax
- iret
-");
diff --git a/kernel/blk_drv/scsi/sd_ioctl.c b/kernel/blk_drv/scsi/sd_ioctl.c
index 087f870..5c55e16 100644
--- a/kernel/blk_drv/scsi/sd_ioctl.c
+++ b/kernel/blk_drv/scsi/sd_ioctl.c
@@ -3,6 +3,9 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
+#include <asm/segment.h>
+#include "../blk.h"
+#include <errno.h>
#include "scsi.h"
#include "sd.h"
@@ -13,6 +16,7 @@ int sd_ioctl(struct inode * inode, struct file * file, unsigned long cmd, unsign
int dev = inode->i_rdev;
switch (cmd) {
+ RO_IOCTLS(dev,arg);
default:
return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device,cmd,(void *) arg);
}
diff --git a/kernel/blk_drv/scsi/ultrastor.c b/kernel/blk_drv/scsi/ultrastor.c
index 085e10f..ba30f21 100644
--- a/kernel/blk_drv/scsi/ultrastor.c
+++ b/kernel/blk_drv/scsi/ultrastor.c
@@ -156,7 +156,7 @@ static const unsigned short ultrastor_ports[] = {
};
#endif
-void ultrastor_interrupt(void);
+void ultrastor_interrupt(int cpl);
static void (*ultrastor_done)(int, int) = 0;
@@ -293,11 +293,17 @@ int ultrastor_14f_detect(int hostnum)
host_number = hostnum;
scsi_hosts[hostnum].this_id = config.ha_scsi_id;
#if USE_QUEUECOMMAND
- set_intr_gate(0x20 + config.interrupt, ultrastor_interrupt);
- /* gate to PIC 2 */
- outb_p(inb_p(0x21) & ~BIT(2), 0x21);
- /* enable the interrupt */
- outb(inb_p(0xA1) & ~BIT(config.interrupt - 8), 0xA1);
+ {
+ struct sigaction sa;
+ sa.sa_handler = ultrastor_interrupt;
+ sa.sa_flags = SA_INTERRUPT;
+ sa.sa_mask = 0;
+ sa.sa_restorer = NULL;
+ if (irqaction(config.interrupt,&sa)) {
+ printk("unable to get IRQ%d for ultrastor controller\n",config.interrupt);
+ return FALSE;
+ }
+ }
#endif
return TRUE;
}
@@ -421,7 +427,7 @@ int ultrastor_14f_reset(void)
}
#if USE_QUEUECOMMAND
-void ultrastor_interrupt_service(void)
+void ultrastor_interrupt(int cpl)
{
if (ultrastor_done == 0) {
printk("US14F: unexpected ultrastor interrupt\n\r");
@@ -434,37 +440,6 @@ void ultrastor_interrupt_service(void)
(mscp.adapter_status << 16) | mscp.target_status);
ultrastor_done = 0;
}
-
-__asm__("
-_ultrastor_interrupt:
- cld
- 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
- outb %al,$0x80 # give port chance to breathe
- outb %al,$0x80
- outb %al,$0x80
- outb %al,$0x80
- outb %al,$0x20
- call _ultrastor_interrupt_service
- pop %fs
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- popl %eax
- iret
-");
#endif
#endif
diff --git a/kernel/chr_drv/console.c b/kernel/chr_drv/console.c
index 79b0d15..e397a5a 100644
--- a/kernel/chr_drv/console.c
+++ b/kernel/chr_drv/console.c
@@ -30,6 +30,8 @@
* <g-hunt@ee.utah.edu>
*/
+#define KEYBOARD_IRQ 1
+
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/tty.h>
@@ -68,7 +70,7 @@
#define NPAR 16
extern void vt_init(void);
-extern void keyboard_interrupt(void);
+extern void keyboard_interrupt(int cpl);
extern void set_leds(void);
extern unsigned char kapplic;
extern unsigned char ckmode;
@@ -241,8 +243,8 @@ static char * translations[] = {
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
" !\"#$%&'()*+,-./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\0"
+ "\004\261\007\007\007\007\370\361\040\007\331\277\332\300\305\007"
+ "\007\304\007\007\303\264\301\302\263\007\007\007\007\007\234\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\040\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
@@ -250,11 +252,29 @@ static char * translations[] = {
"\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
"\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341"
"\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
- "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230"
+ "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230",
+/* IBM grapgics: minimal translations (CR, LF, LL and ESC) */
+ "\000\001\002\003\004\005\006\007\010\011\000\013\000\000\016\017"
+ "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037"
+ "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
+ "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
+ "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117"
+ "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137"
+ "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
+ "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177"
+ "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
+ "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
+ "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
+ "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
+ "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
+ "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
+ "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"
};
#define NORM_TRANS (translations[0])
#define GRAF_TRANS (translations[1])
+#define NULL_TRANS (translations[2])
static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
8,12,10,14, 9,13,11,15 };
@@ -605,7 +625,7 @@ static inline void set_cursor(int currcons)
static void respond_string(char * p, int currcons, struct tty_struct * tty)
{
while (*p) {
- PUTCH(*p,tty->read_q);
+ put_tty_queue(*p,tty->read_q);
p++;
}
TTY_READ_FLUSH(tty);
@@ -621,19 +641,19 @@ static void respond_num(unsigned int n, int currcons, struct tty_struct * tty)
n /= 10;
} while(n && i < 3); /* We'll take no chances */
while (i--) {
- PUTCH(buff[i],tty->read_q);
+ put_tty_queue(buff[i],tty->read_q);
}
/* caller must flush */
}
static void cursor_report(int currcons, struct tty_struct * tty)
{
- PUTCH('\033', tty->read_q);
- PUTCH('[', tty->read_q);
+ put_tty_queue('\033', tty->read_q);
+ put_tty_queue('[', tty->read_q);
respond_num(y + (decom ? top+1 : 1), currcons, tty);
- PUTCH(';', tty->read_q);
+ put_tty_queue(';', tty->read_q);
respond_num(x+1, currcons, tty);
- PUTCH('R', tty->read_q);
+ put_tty_queue('R', tty->read_q);
TTY_READ_FLUSH(tty);
}
@@ -905,7 +925,7 @@ void con_write(struct tty_struct * tty)
printk("con_write: illegal tty\n\r");
return;
}
- while (!tty->stopped && (c = GETCH(tty->write_q)) >= 0) {
+ while (!tty->stopped && (c = get_tty_queue(tty->write_q)) >= 0) {
if (state == ESnormal && translate[c]) {
if (need_wrap) {
cr(currcons);
@@ -1176,6 +1196,8 @@ void con_write(struct tty_struct * tty)
G0_charset = GRAF_TRANS;
else if (c == 'B')
G0_charset = NORM_TRANS;
+ else if (c == 'U')
+ G0_charset = NULL_TRANS;
if (charset == 0)
translate = G0_charset;
state = ESnormal;
@@ -1185,6 +1207,8 @@ void con_write(struct tty_struct * tty)
G1_charset = GRAF_TRANS;
else if (c == 'B')
G1_charset = NORM_TRANS;
+ else if (c == 'U')
+ G1_charset = NULL_TRANS;
if (charset == 1)
translate = G1_charset;
state = ESnormal;
@@ -1338,8 +1362,8 @@ long con_init(long kmem_start)
gotoxy(currcons,orig_x,orig_y);
update_screen(fg_console);
- set_trap_gate(0x21,&keyboard_interrupt);
- outb_p(inb_p(0x21)&0xfd,0x21);
+ if (request_irq(KEYBOARD_IRQ,keyboard_interrupt))
+ printk("Unable to get IRQ%d for keyboard driver\n",KEYBOARD_IRQ);
a=inb_p(0x61);
outb_p(a|0x80,0x61);
outb_p(a,0x61);
diff --git a/kernel/chr_drv/keyboard.c b/kernel/chr_drv/keyboard.c
index fad6a84..c867b55 100644
--- a/kernel/chr_drv/keyboard.c
+++ b/kernel/chr_drv/keyboard.c
@@ -58,7 +58,7 @@ static void cur(int);
static void kb_wait(void), kb_ack(void);
static unsigned int handle_diacr(unsigned int);
-void do_keyboard(void)
+void keyboard_interrupt(int cpl)
{
static unsigned char rep = 0xff, repke0 = 0;
unsigned char scancode, x;
@@ -874,7 +874,7 @@ unsigned int handle_diacr(unsigned int ch)
}
-#if defined KBD_FR || defined KBD_US
+#if defined KBD_FR || defined KBD_US || defined KBD_UK
static unsigned char num_table[] = "789-456+1230.";
#else
static unsigned char num_table[] = "789-456+1230,";
diff --git a/kernel/chr_drv/pty.c b/kernel/chr_drv/pty.c
index a0625c7..729be84 100644
--- a/kernel/chr_drv/pty.c
+++ b/kernel/chr_drv/pty.c
@@ -31,10 +31,6 @@ int pty_open(unsigned int dev, struct file * filp)
wake_up(&tty->read_q->proc_list);
if (filp->f_flags & O_NDELAY)
return 0;
- if (IS_A_PTY_MASTER(dev)) {
- tty->link->count++;
- return 0;
- }
while (!tty->link->count && !(current->signal & ~current->blocked))
interruptible_sleep_on(&tty->link->read_q->proc_list);
if (!tty->link->count)
@@ -48,8 +44,8 @@ void pty_close(unsigned int dev, struct file * filp)
tty = tty_table + dev;
wake_up(&tty->read_q->proc_list);
+ wake_up(&tty->link->write_q->proc_list);
if (IS_A_PTY_MASTER(dev)) {
- tty->link->count--;
if (tty->link->pgrp > 0)
kill_pg(tty->link->pgrp,SIGHUP,1);
}
@@ -66,8 +62,8 @@ static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
TTY_READ_FLUSH(to);
continue;
}
- c = GETCH(from->write_q);
- PUTCH(c,to->read_q);
+ c = get_tty_queue(from->write_q);
+ put_tty_queue(c,to->read_q);
if (current->signal & ~current->blocked)
break;
}
diff --git a/kernel/chr_drv/serial.c b/kernel/chr_drv/serial.c
index f814c3c..4bbad1c 100644
--- a/kernel/chr_drv/serial.c
+++ b/kernel/chr_drv/serial.c
@@ -26,16 +26,6 @@
#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
-/*
- * note that IRQ9 is what many docs call IRQ2 - on the AT hardware
- * the old IRQ2 line has been changed to IRQ9. The serial_table
- * structure considers IRQ2 to be the same as IRQ9.
- */
-extern void IRQ9_interrupt(void);
-extern void IRQ3_interrupt(void);
-extern void IRQ4_interrupt(void);
-extern void IRQ5_interrupt(void);
-
struct serial_struct serial_table[NR_SERIALS] = {
{ PORT_UNKNOWN, 0, 0x3F8, 4, NULL},
{ PORT_UNKNOWN, 1, 0x2F8, 3, NULL},
@@ -43,20 +33,20 @@ struct serial_struct serial_table[NR_SERIALS] = {
{ PORT_UNKNOWN, 3, 0x2E8, 3, NULL},
};
-static struct serial_struct * irq_info[16] = { NULL, };
-
static void modem_status_intr(struct serial_struct * info)
{
unsigned char status = inb(info->port+6);
- if ((status & 0x88) == 0x08 && info->tty->pgrp > 0)
- kill_pg(info->tty->pgrp,SIGHUP,1);
+ if (!(info->tty->termios.c_cflag & CLOCAL)) {
+ if ((status & 0x88) == 0x08 && info->tty->pgrp > 0)
+ kill_pg(info->tty->pgrp,SIGHUP,1);
#if 0
- if ((status & 0x10) == 0x10)
- info->tty->stopped = 0;
- else
- info->tty->stopped = 1;
+ if ((status & 0x10) == 0x10)
+ info->tty->stopped = 0;
+ else
+ info->tty->stopped = 1;
#endif
+ }
}
void send_break(unsigned int line)
@@ -94,15 +84,19 @@ static void send_intr(struct serial_struct * info)
int c, i = 0;
timer_active &= ~(1 << timer);
- do {
- if ((c = GETCH(queue)) < 0)
- return;
+ while (inb_p(info->port+5) & 0x20) {
+ if (queue->tail == queue->head)
+ goto end_send;
+ c = queue->buf[queue->tail];
+ queue->tail++;
+ queue->tail &= TTY_BUF_SIZE-1;
outb(c,port);
- i++;
- } while (info->type == PORT_16550A &&
- i < 14 && !EMPTY(queue));
+ if ((info->type != PORT_16550A) || (++i >= 14))
+ break;
+ }
timer_table[timer].expires = jiffies + 10;
timer_active |= 1 << timer;
+end_send:
if (LEFT(queue) > WAKEUP_CHARS)
wake_up(&queue->proc_list);
}
@@ -111,10 +105,18 @@ static void receive_intr(struct serial_struct * info)
{
unsigned short port = info->port;
struct tty_queue * queue = info->tty->read_q;
+ int head = queue->head;
+ int maxhead = (queue->tail-1) & (TTY_BUF_SIZE-1);
+ timer_active &= ~((1<<SER1_TIMER)<<info->line);
do {
- PUTCH(inb(port),queue);
+ queue->buf[head] = inb(port);
+ if (head != maxhead) {
+ head++;
+ head &= TTY_BUF_SIZE-1;
+ }
} while (inb(port+5) & 1);
+ queue->head = head;
timer_active |= (1<<SER1_TIMER)<<info->line;
}
@@ -149,11 +151,47 @@ static void check_tty(struct serial_struct * info)
}
}
-void do_IRQ(int irq)
+/*
+ * Again, we disable interrupts to be sure there aren't any races:
+ * see send_intr for details.
+ */
+static inline void do_rs_write(struct serial_struct * info)
+{
+ if (!info->tty || !info->port)
+ return;
+ if (!info->tty->write_q || EMPTY(info->tty->write_q))
+ return;
+ cli();
+ send_intr(info);
+ sti();
+}
+
+/*
+ * IRQ routines: one per line
+ */
+static void com1_IRQ(int cpl)
+{
+ check_tty(serial_table+0);
+}
+
+static void com2_IRQ(int cpl)
+{
+ check_tty(serial_table+1);
+}
+
+static void com3_IRQ(int cpl)
{
- check_tty(irq_info[irq]);
+ check_tty(serial_table+2);
}
+static void com4_IRQ(int cpl)
+{
+ check_tty(serial_table+3);
+}
+
+/*
+ * Receive timer routines: one per line
+ */
static void com1_timer(void)
{
TTY_READ_FLUSH(tty_table+64);
@@ -175,27 +213,8 @@ static void com4_timer(void)
}
/*
- * Again, we disable interrupts to be sure there aren't any races:
- * see send_intr for details.
+ * Send timeout routines: one per line
*/
-static inline void do_rs_write(struct serial_struct * info)
-{
- if (!info->tty || !info->port)
- return;
- if (!info->tty->write_q || EMPTY(info->tty->write_q))
- return;
- cli();
- if (inb_p(info->port+5) & 0x20)
- send_intr(info);
- else {
- unsigned int timer = SER1_TIMEOUT+info->line;
-
- timer_table[timer].expires = jiffies + 10;
- timer_active |= 1 << timer;
- }
- sti();
-}
-
static void com1_timeout(void)
{
do_rs_write(serial_table);
@@ -276,13 +295,7 @@ void serial_close(unsigned line, struct file * filp)
irq = info->irq;
if (irq == 2)
irq = 9;
- if (irq_info[irq] == info) {
- irq_info[irq] = NULL;
- if (irq < 8)
- outb(inb_p(0x21) | (1<<irq),0x21);
- else
- outb(inb_p(0xA1) | (1<<(irq-8)),0xA1);
- }
+ free_irq(irq);
}
static void startup(unsigned short port)
@@ -300,7 +313,7 @@ void change_speed(unsigned int line)
{
struct serial_struct * info;
unsigned short port,quot;
- unsigned cflag;
+ unsigned cflag,cval;
static unsigned short quotient[] = {
0, 2304, 1536, 1047, 857,
768, 576, 384, 192, 96,
@@ -318,22 +331,25 @@ void change_speed(unsigned int line)
outb(0x00,port+4);
else if (!inb(port+4))
startup(port);
+/* byte size and parity */
+ cval = cflag & (CSIZE | CSTOPB);
+ cval >>= 4;
+ if (cflag & PARENB)
+ cval |= 8;
+ if (!(cflag & PARODD))
+ cval |= 16;
cli();
- outb_p(0x80,port+3); /* set DLAB */
+ outb_p(cval | 0x80,port+3); /* set DLAB */
outb_p(quot & 0xff,port); /* LS of divisor */
outb_p(quot >> 8,port+1); /* MS of divisor */
- outb(0x03,port+3); /* reset DLAB */
+ outb(cval,port+3); /* reset DLAB */
sti();
-/* set byte size and parity */
- quot = cflag & (CSIZE | CSTOPB);
- quot >>= 4;
- if (cflag & PARENB)
- quot |= 8;
- if (!(cflag & PARODD))
- quot |= 16;
- outb(quot,port+3);
}
+static void (*serial_handler[NR_SERIALS])(int) = {
+ com1_IRQ,com2_IRQ,com3_IRQ,com4_IRQ
+};
+
/*
* this routine enables interrupts on 'line', and disables them for any
* other serial line that shared the same IRQ. Braindamaged AT hardware.
@@ -341,8 +357,9 @@ void change_speed(unsigned int line)
int serial_open(unsigned line, struct file * filp)
{
struct serial_struct * info;
- int irq;
+ int irq,retval;
unsigned short port;
+ void (*handler)(int) = serial_handler[line];
if (line >= NR_SERIALS)
return -ENODEV;
@@ -352,16 +369,9 @@ int serial_open(unsigned line, struct file * filp)
irq = info->irq;
if (irq == 2)
irq = 9;
- if (irq_info[irq] && irq_info[irq] != info)
- return -EBUSY;
- cli();
+ if (retval = request_irq(irq,handler))
+ return retval;
startup(port);
- irq_info[irq] = info;
- if (irq < 8)
- outb(inb_p(0x21) & ~(1<<irq),0x21);
- else
- outb(inb_p(0xA1) & ~(1<<(irq-8)),0xA1);
- sti();
return 0;
}
@@ -380,6 +390,8 @@ int set_serial_info(unsigned int line, struct serial_struct * info)
struct serial_struct tmp;
unsigned new_port;
unsigned irq,new_irq;
+ int retval;
+ void (*handler)(int) = serial_handler[line];
if (!suser())
return -EPERM;
@@ -401,20 +413,10 @@ int set_serial_info(unsigned int line, struct serial_struct * info)
if (irq == 2)
irq = 9;
if (irq != new_irq) {
- if (irq_info[new_irq])
- return -EBUSY;
- cli();
- irq_info[new_irq] = irq_info[irq];
- irq_info[irq] = NULL;
- info->irq = new_irq;
- if (irq < 8)
- outb(inb_p(0x21) | (1<<irq),0x21);
- else
- outb(inb_p(0xA1) | (1<<(irq-8)),0xA1);
- if (new_irq < 8)
- outb(inb_p(0x21) & ~(1<<new_irq),0x21);
- else
- outb(inb_p(0xA1) & ~(1<<(new_irq-8)),0xA1);
+ retval = request_irq(new_irq,handler);
+ if (retval)
+ return retval;
+ free_irq(irq);
}
cli();
if (new_port != info->port) {
@@ -450,10 +452,6 @@ long rs_init(long kmem_start)
timer_table[SER3_TIMEOUT].expires = 0;
timer_table[SER4_TIMEOUT].fn = com4_timeout;
timer_table[SER4_TIMEOUT].expires = 0;
- set_intr_gate(0x23,IRQ3_interrupt);
- set_intr_gate(0x24,IRQ4_interrupt);
- set_intr_gate(0x25,IRQ5_interrupt);
- set_intr_gate(0x29,IRQ9_interrupt);
for (i = 0, info = serial_table; i < NR_SERIALS; i++,info++) {
info->tty = (tty_table+64) + i;
init(info);
diff --git a/kernel/chr_drv/tty_io.c b/kernel/chr_drv/tty_io.c
index c4b3a77..d677f7f 100644
--- a/kernel/chr_drv/tty_io.c
+++ b/kernel/chr_drv/tty_io.c
@@ -154,7 +154,7 @@ void copy_to_cooked(struct tty_struct * tty)
while (1) {
if (FULL(tty->secondary))
break;
- c = GETCH(tty->read_q);
+ c = get_tty_queue(tty->read_q);
if (c < 0)
break;
if (I_STRP(tty))
@@ -178,13 +178,13 @@ void copy_to_cooked(struct tty_struct * tty)
(c==EOF_CHAR(tty))))) {
if (L_ECHO(tty)) {
if (c<32) {
- PUTCH(8,tty->write_q);
- PUTCH(' ',tty->write_q);
- PUTCH(8,tty->write_q);
+ put_tty_queue(8,tty->write_q);
+ put_tty_queue(' ',tty->write_q);
+ put_tty_queue(8,tty->write_q);
}
- PUTCH(8,tty->write_q);
- PUTCH(' ',tty->write_q);
- PUTCH(8,tty->write_q);
+ put_tty_queue(8,tty->write_q);
+ put_tty_queue(' ',tty->write_q);
+ put_tty_queue(8,tty->write_q);
TTY_WRITE_FLUSH(tty);
}
DEC(tty->secondary->head);
@@ -200,13 +200,13 @@ void copy_to_cooked(struct tty_struct * tty)
continue;
if (L_ECHO(tty)) {
if (c<32) {
- PUTCH(8,tty->write_q);
- PUTCH(' ',tty->write_q);
- PUTCH(8,tty->write_q);
+ put_tty_queue(8,tty->write_q);
+ put_tty_queue(' ',tty->write_q);
+ put_tty_queue(8,tty->write_q);
}
- PUTCH(8,tty->write_q);
- PUTCH(32,tty->write_q);
- PUTCH(8,tty->write_q);
+ put_tty_queue(8,tty->write_q);
+ put_tty_queue(32,tty->write_q);
+ put_tty_queue(8,tty->write_q);
TTY_WRITE_FLUSH(tty);
}
DEC(tty->secondary->head);
@@ -250,16 +250,16 @@ void copy_to_cooked(struct tty_struct * tty)
c==EOF_CHAR(tty)))
tty->secondary->data++;
if ((L_ECHO(tty) || (L_CANON(tty) && L_ECHONL(tty))) && (c==10)) {
- PUTCH(10,tty->write_q);
- PUTCH(13,tty->write_q);
+ put_tty_queue(10,tty->write_q);
+ put_tty_queue(13,tty->write_q);
} else if (L_ECHO(tty)) {
if (c<32 && L_ECHOCTL(tty)) {
- PUTCH('^',tty->write_q);
- PUTCH(c+64,tty->write_q);
+ put_tty_queue('^',tty->write_q);
+ put_tty_queue(c+64,tty->write_q);
} else
- PUTCH(c,tty->write_q);
+ put_tty_queue(c,tty->write_q);
}
- PUTCH(c,tty->secondary);
+ put_tty_queue(c,tty->secondary);
TTY_WRITE_FLUSH(tty);
}
TTY_WRITE_FLUSH(tty);
@@ -299,7 +299,6 @@ int tty_signal(int sig, struct tty_struct *tty)
static int read_chan(unsigned int channel, struct file * file, char * buf, int nr)
{
struct tty_struct * tty;
- struct tty_struct * other_tty = NULL;
int c;
char * b=buf;
int minimum,time;
@@ -316,8 +315,6 @@ static int read_chan(unsigned int channel, struct file * file, char * buf, int n
return -EIO;
else
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 (L_CANON(tty)) {
@@ -338,8 +335,8 @@ static int read_chan(unsigned int channel, struct file * file, char * buf, int n
minimum = nr;
TTY_READ_FLUSH(tty);
while (nr>0) {
- if (other_tty && other_tty->write)
- TTY_WRITE_FLUSH(other_tty);
+ if (tty->link && tty->link->write)
+ TTY_WRITE_FLUSH(tty->link);
cli();
if (EMPTY(tty->secondary) || (L_CANON(tty) &&
!FULL(tty->read_q) && !tty->secondary->data)) {
@@ -347,9 +344,7 @@ static int read_chan(unsigned int channel, struct file * file, char * buf, int n
break;
if (current->signal & ~current->blocked)
break;
- if (IS_A_PTY_SLAVE(channel) && C_HUP(other_tty))
- break;
- if (other_tty && !other_tty->count)
+ if (tty->link && !tty->link->count)
break;
interruptible_sleep_on(&tty->secondary->proc_list);
sti();
@@ -358,7 +353,7 @@ static int read_chan(unsigned int channel, struct file * file, char * buf, int n
}
sti();
do {
- c = GETCH(tty->secondary);
+ c = get_tty_queue(tty->secondary);
if ((EOF_CHAR(tty) != __DISABLED_CHAR &&
c==EOF_CHAR(tty)) || c==10)
tty->secondary->data--;
@@ -381,8 +376,8 @@ static int read_chan(unsigned int channel, struct file * file, char * buf, int n
}
sti();
TTY_READ_FLUSH(tty);
- if (other_tty && other_tty->write)
- TTY_WRITE_FLUSH(other_tty);
+ if (tty->link && tty->link->write)
+ TTY_WRITE_FLUSH(tty->link);
current->timeout = 0;
if (b-buf)
return b-buf;
@@ -419,6 +414,10 @@ static int write_chan(unsigned int channel, struct file * file, char * buf, int
while (nr>0) {
if (current->signal & ~current->blocked)
break;
+ if (tty->link && !tty->link->count) {
+ send_sig(SIGPIPE,current,0);
+ break;
+ }
if (FULL(tty->write_q)) {
TTY_WRITE_FLUSH(tty);
cli();
@@ -436,7 +435,7 @@ static int write_chan(unsigned int channel, struct file * file, char * buf, int
c='\r';
if (c=='\n' && !(tty->flags & TTY_CR_PENDING) && O_NLCR(tty)) {
tty->flags |= TTY_CR_PENDING;
- PUTCH(13,tty->write_q);
+ put_tty_queue(13,tty->write_q);
continue;
}
if (O_LCUC(tty))
@@ -444,7 +443,7 @@ static int write_chan(unsigned int channel, struct file * file, char * buf, int
}
b++; nr--;
tty->flags &= ~TTY_CR_PENDING;
- PUTCH(c,tty->write_q);
+ put_tty_queue(c,tty->write_q);
}
if (nr>0)
schedule();
@@ -452,6 +451,8 @@ static int write_chan(unsigned int channel, struct file * file, char * buf, int
TTY_WRITE_FLUSH(tty);
if (b-buf)
return b-buf;
+ if (tty->link && !tty->link->count)
+ return -EPIPE;
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
return 0;
@@ -460,18 +461,12 @@ static int write_chan(unsigned int channel, struct file * file, char * buf, int
static int tty_read(struct inode * inode, struct file * file, char * buf, int count)
{
int i;
-
- i = read_chan(current->tty,file,buf,count);
- if (i > 0)
- inode->i_atime = CURRENT_TIME;
- return i;
-}
-static int ttyx_read(struct inode * inode, struct file * file, char * buf, int count)
-{
- int i;
-
- i = read_chan(MINOR(inode->i_rdev),file,buf,count);
+ if (MAJOR(file->f_rdev) != 4) {
+ printk("tty_read: pseudo-major != 4\n");
+ return -EINVAL;
+ }
+ i = read_chan(MINOR(file->f_rdev),file,buf,count);
if (i > 0)
inode->i_atime = CURRENT_TIME;
return i;
@@ -481,17 +476,11 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c
{
int i;
- i = write_chan(current->tty,file,buf,count);
- if (i > 0)
- inode->i_mtime = CURRENT_TIME;
- return i;
-}
-
-static int ttyx_write(struct inode * inode, struct file * file, char * buf, int count)
-{
- int i;
-
- i = write_chan(MINOR(inode->i_rdev),file,buf,count);
+ if (MAJOR(file->f_rdev) != 4) {
+ printk("tty_write: pseudo-major != 4\n");
+ return -EINVAL;
+ }
+ i = write_chan(MINOR(file->f_rdev),file,buf,count);
if (i > 0)
inode->i_mtime = CURRENT_TIME;
return i;
@@ -522,14 +511,17 @@ static int tty_open(struct inode * inode, struct file * filp)
dev = MINOR(dev);
if (dev < 0)
return -ENODEV;
+ filp->f_rdev = 0x0400 | dev;
tty = TTY_TABLE(dev);
+ if (!tty->count && !(tty->link && tty->link->count)) {
+ flush_input(tty);
+ flush_output(tty);
+ }
if (IS_A_PTY_MASTER(dev)) {
if (tty->count)
return -EAGAIN;
- }
- if (!tty->count && (!tty->link || !tty->link->count)) {
- flush_input(tty);
- flush_output(tty);
+ if (tty->link)
+ tty->link->count++;
}
tty->count++;
retval = 0;
@@ -541,36 +533,50 @@ static int tty_open(struct inode * inode, struct file * filp)
tty->session = current->session;
tty->pgrp = current->pgrp;
}
- if (IS_A_SERIAL(dev))
+ if (IS_A_SERIAL(dev) && tty->count < 2)
retval = serial_open(dev-64,filp);
else if (IS_A_PTY(dev))
retval = pty_open(dev,filp);
- if (retval)
+ if (retval) {
tty->count--;
+ if (IS_A_PTY_MASTER(dev) && tty->link)
+ tty->link->count++;
+ }
return retval;
}
+/*
+ * Note that releasing a pty master also releases the child, so
+ * we have to make the redirection checks after that and on both
+ * sides of a pty.
+ */
static void tty_release(struct inode * inode, struct file * filp)
{
int dev;
struct tty_struct * tty;
- dev = inode->i_rdev;
- if (MAJOR(dev) == 5)
- dev = current->tty;
- else
- dev = MINOR(dev);
- if (dev < 0)
+ dev = filp->f_rdev;
+ if (MAJOR(dev) != 4) {
+ printk("tty_close: tty pseudo-major != 4\n");
return;
+ }
+ dev = MINOR(filp->f_rdev);
tty = TTY_TABLE(dev);
- if (--tty->count)
+ if (IS_A_PTY_MASTER(dev) && tty->link)
+ tty->link->count--;
+ tty->count--;
+ if (tty->count)
return;
- if (tty == redirect)
- redirect = NULL;
- if (IS_A_SERIAL(dev))
+ if (IS_A_SERIAL(dev)) {
+ wait_until_sent(tty);
serial_close(dev-64,filp);
- else if (IS_A_PTY(dev))
+ } else if (IS_A_PTY(dev))
pty_close(dev,filp);
+ if (!tty->count && (tty == redirect))
+ redirect = NULL;
+ if (tty = tty->link)
+ if (!tty->count && (tty == redirect))
+ redirect = NULL;
}
static struct file_operations tty_fops = {
@@ -584,17 +590,6 @@ static struct file_operations tty_fops = {
tty_release
};
-static struct file_operations ttyx_fops = {
- tty_lseek,
- ttyx_read,
- ttyx_write,
- NULL, /* ttyx_readdir */
- NULL, /* ttyx_select */
- tty_ioctl, /* ttyx_ioctl */
- tty_open,
- tty_release
-};
-
long tty_init(long kmem_start)
{
int i;
@@ -603,7 +598,7 @@ long tty_init(long kmem_start)
kmem_start += QUEUES * (sizeof (struct tty_queue));
table_list[0] = con_queues + 0;
table_list[1] = con_queues + 1;
- chrdev_fops[4] = &ttyx_fops;
+ chrdev_fops[4] = &tty_fops;
chrdev_fops[5] = &tty_fops;
for (i=0 ; i < QUEUES ; i++)
tty_queues[i] = (struct tty_queue) {0,0,0,0,""};
diff --git a/kernel/chr_drv/tty_ioctl.c b/kernel/chr_drv/tty_ioctl.c
index c06bff5..d508807 100644
--- a/kernel/chr_drv/tty_ioctl.c
+++ b/kernel/chr_drv/tty_ioctl.c
@@ -65,7 +65,7 @@ void flush_output(struct tty_struct * tty)
}
}
-static void wait_until_sent(struct tty_struct * tty)
+void wait_until_sent(struct tty_struct * tty)
{
while (!(current->signal & ~current->blocked) && !EMPTY(tty->write_q)) {
TTY_WRITE_FLUSH(tty);
@@ -122,6 +122,7 @@ static int set_termios(struct tty_struct * tty, struct termios * termios,
int channel)
{
int i;
+ unsigned short old_cflag = tty->termios.c_cflag;
/* 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
@@ -135,7 +136,7 @@ static int set_termios(struct tty_struct * tty, struct termios * termios,
}
for (i=0 ; i< (sizeof (*termios)) ; i++)
((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
- if (IS_A_SERIAL(channel))
+ if (IS_A_SERIAL(channel) && tty->termios.c_cflag != old_cflag)
change_speed(channel-64);
return 0;
}
@@ -166,6 +167,7 @@ static int set_termio(struct tty_struct * tty, struct termio * termio,
{
int i;
struct termio tmp_termio;
+ unsigned short old_cflag = tty->termios.c_cflag;
if ((current->tty == channel) &&
(tty->pgrp > 0) &&
@@ -184,7 +186,7 @@ static int set_termio(struct tty_struct * tty, struct termio * termio,
tty->termios.c_line = tmp_termio.c_line;
for(i=0 ; i < NCC ; i++)
tty->termios.c_cc[i] = tmp_termio.c_cc[i];
- if (IS_A_SERIAL(channel))
+ if (IS_A_SERIAL(channel) && tty->termios.c_cflag != old_cflag)
change_speed(channel-64);
return 0;
}
@@ -232,12 +234,11 @@ int tty_ioctl(struct inode * inode, struct file * file,
int pgrp;
int dev;
- if (MAJOR(inode->i_rdev) == 5) {
- dev = current->tty;
- if (dev<0)
- return -EINVAL;
- } else
- dev = MINOR(inode->i_rdev);
+ if (MAJOR(file->f_rdev) != 4) {
+ printk("tty_ioctl: tty pseudo-major != 4\n");
+ return -EINVAL;
+ }
+ dev = MINOR(file->f_rdev);
tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console);
if (IS_A_PTY(dev))
@@ -286,11 +287,11 @@ int tty_ioctl(struct inode * inode, struct file * file,
return 0;
case TCIOFF:
if (STOP_CHAR(tty))
- PUTCH(STOP_CHAR(tty),tty->write_q);
+ put_tty_queue(STOP_CHAR(tty),tty->write_q);
return 0;
case TCION:
if (START_CHAR(tty))
- PUTCH(START_CHAR(tty),tty->write_q);
+ put_tty_queue(START_CHAR(tty),tty->write_q);
return 0;
}
return -EINVAL; /* not implemented */
diff --git a/kernel/irq.c b/kernel/irq.c
new file mode 100644
index 0000000..c3b740d
--- /dev/null
+++ b/kernel/irq.c
@@ -0,0 +1,171 @@
+/*
+ * linux/kernel/irq.c
+ *
+ * (C) 1992 Linus Torvalds
+ *
+ * This file contains the code used by various IRQ handling routines:
+ * asking for different IRQ's should be done through these routines
+ * instead of just grabbing them. Thus setups with different IRQ numbers
+ * shouldn't result in any weird surprises, and installing new handlers
+ * should be easier.
+ */
+
+/*
+ * IRQ's are in fact implemented a bit like signal handlers for the kernel.
+ * The same sigaction struct is used, and with similar semantics (ie there
+ * is a SA_INTERRUPT flag etc). Naturally it's not a 1:1 relation, but there
+ * are similarities.
+ *
+ * sa_handler(int irq_NR) is the default function called.
+ * sa_mask is 0 if nothing uses this IRQ
+ * sa_flags contains various info: SA_INTERRUPT etc
+ * sa_restorer is the unused
+ */
+
+#include <signal.h>
+#include <errno.h>
+
+#include <sys/ptrace.h>
+
+#include <linux/sched.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+struct sigaction irq_sigaction[16] = {
+ { NULL, 0, 0, NULL },
+};
+
+/*
+ * This builds up the IRQ handler stubs using some ugly macros in irq.h
+ */
+BUILD_IRQ(FIRST,0,0x01)
+BUILD_IRQ(FIRST,1,0x02)
+BUILD_IRQ(FIRST,2,0x04)
+BUILD_IRQ(FIRST,3,0x08)
+BUILD_IRQ(FIRST,4,0x10)
+BUILD_IRQ(FIRST,5,0x20)
+BUILD_IRQ(FIRST,6,0x40)
+BUILD_IRQ(FIRST,7,0x80)
+BUILD_IRQ(SECOND,8,0x01)
+BUILD_IRQ(SECOND,9,0x02)
+BUILD_IRQ(SECOND,10,0x04)
+BUILD_IRQ(SECOND,11,0x08)
+BUILD_IRQ(SECOND,12,0x10)
+BUILD_IRQ(SECOND,13,0x20)
+BUILD_IRQ(SECOND,14,0x40)
+BUILD_IRQ(SECOND,15,0x80)
+
+/*
+ * This routine gets called at every IRQ request. Interrupts
+ * are enabled, the interrupt has been accnowledged and this
+ * particular interrupt is disabled when this is called.
+ *
+ * The routine has to call the appropriate handler (disabling
+ * interrupts if needed first), and then re-enable this interrupt-
+ * line if the handler was ok. If no handler exists, the IRQ isn't
+ * re-enabled.
+ *
+ * Note similarities on a very low level between this and the
+ * do_signal() function. Naturally this is simplified, but they
+ * get similar arguments, use them similarly etc... Note that
+ * unlike the signal-handlers, the IRQ-handlers don't get the IRQ
+ * (signal) number as argument, but the cpl value at the time of
+ * the interrupt.
+ */
+void do_IRQ(int irq, struct pt_regs * regs)
+{
+ struct sigaction * sa = irq + irq_sigaction;
+ void (*handler)(int);
+
+ if (!(handler = sa->sa_handler))
+ return;
+ if (sa->sa_flags & SA_INTERRUPT)
+ cli();
+ handler(regs->cs & 3);
+ cli();
+ if (irq < 8)
+ outb(inb_p(0x21) & ~(1<<irq),0x21);
+ else
+ outb(inb_p(0xA1) & ~(1<<(irq-8)),0xA1);
+ sti();
+}
+
+int irqaction(unsigned int irq, struct sigaction * new)
+{
+ struct sigaction * sa;
+ unsigned long flags;
+
+ if (irq > 15)
+ return -EINVAL;
+ if (irq == 2)
+ irq = 9;
+ sa = irq + irq_sigaction;
+ if (sa->sa_mask)
+ return -EBUSY;
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ *sa = *new;
+ sa->sa_mask = 1;
+ if (irq < 8)
+ outb(inb_p(0x21) & ~(1<<irq),0x21);
+ else
+ outb(inb_p(0xA1) & ~(1<<(irq-8)),0xA1);
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ return 0;
+}
+
+int request_irq(unsigned int irq, void (*handler)(int))
+{
+ struct sigaction sa;
+
+ sa.sa_handler = handler;
+ sa.sa_flags = 0;
+ sa.sa_mask = 0;
+ sa.sa_restorer = NULL;
+ return irqaction(irq,&sa);
+}
+
+void free_irq(unsigned int irq)
+{
+ struct sigaction * sa = irq + irq_sigaction;
+ unsigned long flags;
+
+ if (irq > 15) {
+ printk("Trying to free IRQ%d\n",irq);
+ return;
+ }
+ if (!sa->sa_mask) {
+ printk("Trying to free free IRQ%d\n",irq);
+ return;
+ }
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ if (irq < 8)
+ outb(inb_p(0x21) | (1<<irq),0x21);
+ else
+ outb(inb_p(0xA1) | (1<<(irq-8)),0xA1);
+ sa->sa_handler = NULL;
+ sa->sa_flags = 0;
+ sa->sa_mask = 0;
+ sa->sa_restorer = NULL;
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+}
+
+void init_IRQ(void)
+{
+ set_trap_gate(0x20,IRQ0_interrupt);
+ set_trap_gate(0x21,IRQ1_interrupt);
+ set_trap_gate(0x22,IRQ2_interrupt);
+ set_trap_gate(0x23,IRQ3_interrupt);
+ set_trap_gate(0x24,IRQ4_interrupt);
+ set_trap_gate(0x25,IRQ5_interrupt);
+ set_trap_gate(0x26,IRQ6_interrupt);
+ set_trap_gate(0x27,IRQ7_interrupt);
+ set_trap_gate(0x28,IRQ8_interrupt);
+ set_trap_gate(0x29,IRQ10_interrupt);
+ set_trap_gate(0x2a,IRQ10_interrupt);
+ set_trap_gate(0x2b,IRQ11_interrupt);
+ set_trap_gate(0x2c,IRQ12_interrupt);
+ set_trap_gate(0x2d,IRQ13_interrupt);
+ set_trap_gate(0x2e,IRQ14_interrupt);
+ set_trap_gate(0x2f,IRQ15_interrupt);
+}
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 8e1fd25..eac2ec5 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -39,7 +39,7 @@ static inline struct task_struct * get_task(int pid)
{
int i;
- for (i = 0; i < NR_TASKS; i++) {
+ for (i = 1; i < NR_TASKS; i++) {
if (task[i] != NULL && (task[i]->pid == pid))
return task[i];
}
@@ -238,6 +238,8 @@ int sys_ptrace(long request, long pid, long addr, long data)
if (request == PTRACE_ATTACH) {
long tmp;
+ if (child == current)
+ return -EPERM;
if ((!current->dumpable || (current->uid != child->euid) ||
(current->gid != child->egid)) && !suser())
return -EPERM;
diff --git a/kernel/sched.c b/kernel/sched.c
index 6e6716e..bb201b5 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -10,6 +10,9 @@
* call functions (type getpid(), which just extracts a field from
* current-task
*/
+
+#define TIMER_IRQ 0
+
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/kernel.h>
@@ -369,25 +372,26 @@ void update_avg(void)
unsigned long timer_active = 0;
struct timer_struct timer_table[32];
-void do_timer(long cpl)
+static void do_timer(int cpl)
{
unsigned long mask;
struct timer_struct *tp = timer_table+0;
struct task_struct ** task_p;
static int avg_cnt = 0;
- for (mask = 1 ; mask ; tp++,mask += mask) {
- if (mask > timer_active)
- break;
- if (!(mask & timer_active))
- continue;
- if (tp->expires > jiffies)
- continue;
- timer_active &= ~mask;
- tp->fn();
- sti();
+ jiffies++;
+ if (!cpl)
+ current->stime++;
+ else
+ current->utime++;
+ if (--avg_cnt < 0) {
+ avg_cnt = 500;
+ update_avg();
+ }
+ if ((--current->counter)<=0) {
+ current->counter=0;
+ need_resched = 1;
}
-
/* Update ITIMER_REAL for every task */
for (task_p = &LAST_TASK; task_p >= &FIRST_TASK; task_p--)
if (*task_p && (*task_p)->it_real_value
@@ -402,16 +406,21 @@ void do_timer(long cpl)
send_sig(SIGPROF,current,1);
}
/* Update ITIMER_VIRT for current task if not in a system call */
- if (cpl && current->it_virt_value && !(--current->it_virt_value)) {
+ if (current->it_virt_value && !(--current->it_virt_value)) {
current->it_virt_value = current->it_virt_incr;
send_sig(SIGVTALRM,current,1);
}
-
- if (cpl)
- current->utime++;
- else
- current->stime++;
-
+ for (mask = 1 ; mask ; tp++,mask += mask) {
+ if (mask > timer_active)
+ break;
+ if (!(mask & timer_active))
+ continue;
+ if (tp->expires > jiffies)
+ continue;
+ timer_active &= ~mask;
+ tp->fn();
+ sti();
+ }
if (next_timer) {
next_timer->jiffies--;
while (next_timer && next_timer->jiffies <= 0) {
@@ -425,14 +434,6 @@ void do_timer(long cpl)
}
if (current_DOR & 0xf0)
do_floppy_timer();
- if (--avg_cnt < 0) {
- avg_cnt = 500;
- update_avg();
- }
- if ((--current->counter)<=0) {
- current->counter=0;
- need_resched = 1;
- }
}
int sys_alarm(long seconds)
@@ -496,6 +497,7 @@ void sched_init(void)
panic("Struct sigaction MUST be 16 bytes");
set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
+ set_system_gate(0x80,&system_call);
p = gdt+2+FIRST_TSS_ENTRY;
for(i=1 ; i<NR_TASKS ; i++) {
task[i] = NULL;
@@ -511,7 +513,5 @@ void sched_init(void)
outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
outb_p(LATCH & 0xff , 0x40); /* LSB */
outb(LATCH >> 8 , 0x40); /* MSB */
- set_intr_gate(0x20,&timer_interrupt);
- outb(inb_p(0x21)&~0x01,0x21);
- set_system_gate(0x80,&system_call);
+ request_irq(TIMER_IRQ,do_timer);
}
diff --git a/kernel/sys_call.S b/kernel/sys_call.S
index 656feca..3486179 100644
--- a/kernel/sys_call.S
+++ b/kernel/sys_call.S
@@ -81,15 +81,14 @@ 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,_timer_interrupt,_sys_execve
+.globl _system_call,_sys_execve
.globl _device_not_available, _coprocessor_error
.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
.globl _double_fault,_coprocessor_segment_overrun
.globl _invalid_TSS,_segment_not_present,_stack_segment
.globl _general_protection,_irq13,_reserved
.globl _alignment_check,_page_fault
-.globl _keyboard_interrupt,_hd_interrupt
-.globl _IRQ3_interrupt,_IRQ4_interrupt,_IRQ5_interrupt,_IRQ9_interrupt
+.globl ret_from_sys_call
#define SAVE_ALL \
cld; \
@@ -170,15 +169,17 @@ ret_from_sys_call:
jne 2f
cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
jne 2f
-1: movl _current,%eax
- cmpl _task,%eax # task[0] cannot have signals
- je 2f
- cmpl $0,_need_resched
+1: cmpl $0,_need_resched
jne reschedule
+ movl _current,%eax
cmpl $0,state(%eax) # state
jne reschedule
cmpl $0,counter(%eax) # counter
je reschedule
+ movl $1,_need_resched
+ cmpl _task,%eax # task[0] cannot have signals
+ je 2f
+ movl $0,_need_resched
movl signal(%eax),%ebx
movl blocked(%eax),%ecx
notl %ecx
@@ -242,101 +243,6 @@ _device_not_available:
ret
.align 2
-_keyboard_interrupt:
- pushl $-1
- SAVE_ALL
- ACK_FIRST(0x02)
- sti
- call _do_keyboard
- cli
- UNBLK_FIRST(0x02)
- jmp ret_from_sys_call
-
-.align 2
-_IRQ3_interrupt:
- pushl $-1
- SAVE_ALL
- ACK_FIRST(0x08)
- sti
- pushl $3
- call _do_IRQ
- addl $4,%esp
- cli
- UNBLK_FIRST(0x08)
- jmp ret_from_sys_call
-
-.align 2
-_IRQ4_interrupt:
- pushl $-1
- SAVE_ALL
- ACK_FIRST(0x10)
- sti
- pushl $4
- call _do_IRQ
- addl $4,%esp
- cli
- UNBLK_FIRST(0x10)
- jmp ret_from_sys_call
-
-.align 2
-_IRQ5_interrupt:
- pushl $-1
- SAVE_ALL
- ACK_FIRST(0x20)
- sti
- pushl $5
- call _do_IRQ
- addl $4,%esp
- cli
- UNBLK_FIRST(0x20)
- jmp ret_from_sys_call
-
-.align 2
-_IRQ9_interrupt:
- pushl $-1
- SAVE_ALL
- ACK_SECOND(0x02)
- sti
- pushl $9
- call _do_IRQ
- addl $4,%esp
- cli
- UNBLK_SECOND(0x02)
- jmp ret_from_sys_call
-
-.align 2
-_timer_interrupt:
- pushl $-1 # mark this as an int
- SAVE_ALL
- ACK_FIRST(0x01)
- sti
- incl _jiffies
- 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 ...
- cli
- UNBLK_FIRST(0x01)
- jmp ret_from_sys_call
-
-.align 2
-_hd_interrupt:
- pushl $-1
- SAVE_ALL
- ACK_SECOND(0x40)
- andl $0xfffeffff,_timer_active
- xorl %edx,%edx
- xchgl _do_hd,%edx
- testl %edx,%edx
- jne 1f
- movl $_unexpected_hd_interrupt,%edx
-1: call *%edx # "interesting" way of handling intr.
- cli
- UNBLK_SECOND(0x40)
- jmp ret_from_sys_call
-
-.align 2
_sys_execve:
lea (EIP+4)(%esp),%eax # don't forget about the return address.
pushl %eax
diff --git a/kernel/traps.c b/kernel/traps.c
index c05b549..df2ec91 100644
--- a/kernel/traps.c
+++ b/kernel/traps.c
@@ -57,7 +57,6 @@ void general_protection(void);
void page_fault(void);
void coprocessor_error(void);
void reserved(void);
-void parallel_interrupt(void);
void irq13(void);
void alignment_check(void);
@@ -116,7 +115,7 @@ void do_int3(long esp, long error_code)
void do_nmi(long esp, long error_code)
{
- die("nmi",esp,error_code);
+ printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
}
void do_debug(long esp, long error_code)
@@ -201,7 +200,4 @@ void trap_init(void)
for (i=18;i<48;i++)
set_trap_gate(i,&reserved);
set_trap_gate(45,&irq13);
- outb_p(inb_p(0x21)&0xfb,0x21);
- outb(inb_p(0xA1)&0xdf,0xA1);
- set_trap_gate(39,&parallel_interrupt);
}
diff --git a/lib/Makefile b/lib/Makefile
index bbfc3b4..698c50d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -14,7 +14,7 @@
$(CC) $(CFLAGS) -c $<
OBJS = ctype.o _exit.o open.o close.o errno.o write.o dup.o setsid.o \
- execve.o wait.o string.o malloc.o itimer.o
+ execve.o wait.o string.o malloc.o
lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
@@ -36,8 +36,6 @@ ctype.o : ctype.c /usr/src/linux/include/linux/ctype.h
dup.o : dup.c /usr/src/linux/include/linux/unistd.h
errno.o : errno.c
execve.o : execve.c /usr/src/linux/include/linux/unistd.h
-itimer.o : itimer.c /usr/src/linux/include/linux/unistd.h /usr/src/linux/include/sys/time.h \
- /usr/src/linux/include/time.h /usr/src/linux/include/sys/types.h /usr/src/linux/include/stddef.h
malloc.o : malloc.c /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/mm.h \
/usr/src/linux/include/linux/fs.h /usr/src/linux/include/sys/types.h /usr/src/linux/include/stddef.h \
/usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h \