Commit 9000b87e authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.99.2 (January 1, 1993)

Bottom half race condition fix.

Return ENODEV for nonexistent special devices.

Fix Unix domain sockets to properly check for target equality.

Add 'wchan' to /proc/stat

[Original announcement below]

Yes, as you've probably noticed, it's now 1993 and I still haven't
released 1.0.  Sorry about that, and I have only another patchlevel to
offer.  The new kernel should mainly fix some of the keyboard problems
people have experienced, but does contain some other minor fixes.

Linux 0.99.2 is available now at nic.funet.fi: pub/OS/Linux/PEOPLE/Linus
as both sources and diffs against 0.99.1 the diffs are essentially the
same as the second alpha-diffs I released for limited testing, with only
minor fixes to fs/exec.c and fs/open.c.

Please try out 0.99.2: the more feedback (hopefully positive) I get on
it, the faster 1.0 will be out.

Changes from pl1 are mainly:
 - pretty much rewritten low-level keyboard handling IO - this time
   actually trying to do it by the book.  It now handles resend requests
   from the keyboard etc.
 - you can run executables from filesystems without bmap support.  This
   mainly means NFS and msdos.  Note that while it's possible, it's
   slower and less memory-efficient than using a "normal" linux
   filesystem, and should generally be avoided.
 - /proc filesystem changes: /proc/kmsg can be used to log the kernel
   messages under X11 (instead of using the older system call to do the
   same), and there are changes to the statistics routines (WCHAN).

+ various minor fixes (non-existent devices are handled better, some
changes to socket bind behaviour etc).

                Linus
parent 26a34b16
......@@ -66,7 +66,7 @@ SVGA_MODE= -DSVGA_MODE=1
# You should use one of the values 4096 (SB), 16384 (SB Pro), 32768 (PAS+)
# or 65536 (PAS16). The SBC_IRQ defines the IRQ line used by SoundBlaster and
# the PAS_IRQ is the IRQ number for ProAudioSpectrum.
# NOTE! The ProAudioSpectrum support is not available yet.
#
SOUND_SUPPORT = -DKERNEL_SOUNDCARD -DDSP_BUFFSIZE=16384 -DSBC_IRQ=7 -DPAS_IRQ=5
......@@ -97,6 +97,7 @@ CC =gcc -DKERNEL
MAKE =make
CPP =$(CC) -E
AR =ar
STRIP =strip
ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o net/net.o
FILESYSTEMS =fs/filesystems.a
......@@ -141,7 +142,7 @@ linuxsubdirs: dummy
Version: dummy
@./makever.sh
@echo \#define UTS_RELEASE \"0.99.pl1-`cat .version`\" > tools/version.h
@echo \#define UTS_RELEASE \"0.99.pl2-`cat .version`\" > tools/version.h
@echo \#define UTS_VERSION \"`date +%D`\" >> tools/version.h
@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
......@@ -149,7 +150,7 @@ Version: dummy
Image: $(CONFIGURATION) boot/bootsect boot/setup tools/system tools/build
cp tools/system system.tmp
strip system.tmp
$(STRIP) system.tmp
tools/build boot/bootsect boot/setup system.tmp $(ROOT_DEV) > Image
rm system.tmp
sync
......
......@@ -35,7 +35,19 @@ startup_32:
movl %eax,0x000000 # loop forever if it isn't
cmpl %eax,0x100000
je 1b
/*
* Initialize eflags. Some BIOS's leave bits like NT set. This would
* confuse the debugger if this code is traced.
* XXX - best to initialize before switching to protected mode.
*/
pushl $0
popfl
/* check if it is 486 or 386. */
/*
* XXX - this does a lot of unnecessary setup. Alignment checks don't
* apply at our cpl of 0 and the stack ought to be aligned already, and
* we don't need to preserve eflags.
*/
movl %esp,%edi # save stack pointer
andl $0xfffffffc,%esp # align stack to avoid AC fault
pushfl # push EFLAGS
......@@ -46,8 +58,9 @@ startup_32:
popfl # set EFLAGS
pushfl # get new EFLAGS
popl %eax # put it in eax
xorl %ecx,%eax # check if AC bit is changed. zero is 486.
jz 1f # 486
xorl %ecx,%eax # change in flags
andl $0x40000,%eax # check if AC bit changed
jnz 1f # 486
pushl %ecx # restore original EFLAGS
popfl
movl %edi,%esp # restore esp
......@@ -60,13 +73,15 @@ startup_32:
* mode. Then it would be unnecessary with the "verify_area()"-calls.
* 486 users probably want to set the NE (#5) bit also, so as to use
* int 16 for math errors.
* XXX - the above is out of date. We set all the bits, but don't take
* advantage of WP (26 Dec 92).
*/
1: pushl %ecx # restore original EFLAGS
popfl
movl %edi,%esp # restore esp
movl %cr0,%eax # 486
andl $0x80000011,%eax # Save PG,PE,ET
orl $0x10022,%eax # set NE and MP
orl $0x50022,%eax # set AM, WP, NE and MP
2: movl %eax,%cr0
call check_x87
call setup_paging
......
......@@ -253,17 +253,15 @@ no_output:
getkey:
in al,#0x60 ! Quick and dirty...
.word 0x00eb,0x00eb ! jmp $+2, jmp $+2
mov bl,al
in al,#0x61
.word 0x00eb,0x00eb
mov ah,al
or al,#0x80
out #0x61,al
.word 0x00eb,0x00eb
mov al,ah
out #0x61,al
ret
!
! Flush the keyboard buffer
!
flush: in al,#0x60
.word 0x00eb,0x00eb
mov al,bl
cmp al,#0x82
jae flush
ret
! Routine trying to recognize type of SVGA-board present (if any)
......@@ -287,11 +285,8 @@ chsvga: cld
jne svga
lea si,msg1
call prtstr
flush: in al,#0x60 ! Flush the keyboard buffer
cmp al,#0x82
jb nokey
jmp flush
nokey: call getkey
call flush
nokey: call getkey
cmp al,#0x9c ! enter ?
je svga ! yes - svga selection
cmp al,#0xb9 ! space ?
......@@ -317,7 +312,18 @@ extvga:
mov ax,#0x5032 ! return 80x50
ret
/* svga modes */
svga: cld
svga: cld
lea si,idf1280 ! Check for Orchid F1280 (dingbat@diku.dk)
mov di,#0x10a ! id string is at c000:010a
mov cx,#0x21 ! length
repe
cmpsb
jne nf1280
lea si,dscf1280
lea di,mof1280
lea cx,selmod
jmp cx
nf1280: cld
lea si,idati ! Check ATI 'clues'
mov di,#0x31
mov cx,#0x09
......@@ -701,6 +707,7 @@ idcandt: .byte 0xa5
idgenoa: .byte 0x77, 0x00, 0x66, 0x99
idparadise: .ascii "VGA="
idoakvga: .ascii "OAK VGA "
idf1280: .ascii "Orchid Technology Fahrenheit 1280"
! Manufacturer: Numofmodes: Mode:
......@@ -715,6 +722,7 @@ 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
mooakvga: .byte 0x05, 0x00, 0x07, 0x4f, 0x50, 0x51
mof1280: .byte 0x02, 0x54, 0x55
! msb = Cols lsb = Rows:
......@@ -729,6 +737,7 @@ dsctrident: .word 0x501e, 0x502b, 0x503c, 0x8419, 0x841e, 0x842b, 0x843c
dsctseng: .word 0x503c, 0x6428, 0x8419, 0x841c, 0x842c
dscvideo7: .word 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c
dscoakvga: .word 0x2819, 0x5019, 0x843c, 0x8419, 0x842C
dscf1280: .word 0x842b, 0x8419
modesave: .word SVGA_MODE
.text
......
......@@ -33,8 +33,6 @@ Adaptec AHA1542 support
CONFIG_SCSI_AHA1542 y/n y
Adaptec AHA1740 support
CONFIG_SCSI_AHA1740 y/n y
Always IN support
CONFIG_SCSI_ALWAYS y/n y
Future Domain SCSI support
CONFIG_SCSI_FUTURE_DOMAIN y/n y
Seagate ST-02 SCSI support
......@@ -62,7 +60,7 @@ CONFIG_ISO9660_FS y/n n
Various character device drivers..
.
Autoconfigure serial IRQ lines at bootup
CONFIG_AUTOIRQ y/n n
CONFIG_AUTO_IRQ y/n n
AST Fourport serial driver support
CONFIG_AST_FOURPORT y/n n
Accent Async 4 serial support
......
......@@ -194,6 +194,10 @@ int sys_uselib(const char * library)
iput(inode);
return -EACCES;
}
if (!inode->i_op || !inode->i_op->bmap) {
iput(inode);
return -ENOEXEC;
}
if (!(bh = bread(inode->i_dev,bmap(inode,0),inode->i_sb->s_blocksize))) {
iput(inode);
return -EACCES;
......@@ -365,35 +369,42 @@ static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
return data_limit;
}
static void read_omagic(struct inode *inode, int bytes)
/*
* Read in the complete executable. This is used for "-N" files
* that aren't on a block boundary, and for files on filesystems
* without bmap support.
*/
static int read_exec(struct inode *inode, unsigned long offset,
char * addr, unsigned long count)
{
struct buffer_head *bh;
int n, blkno, blk = 0;
char *dest = (char *) 0;
unsigned int block_size;
struct file file;
int result = -ENOEXEC;
block_size = 1024;
if (inode->i_sb)
block_size = inode->i_sb->s_blocksize;
while (bytes > 0) {
n = (blk ? block_size : block_size - sizeof(struct exec));
if (bytes < n)
n = bytes;
blkno = bmap(inode, blk);
if (blkno) {
bh = bread(inode->i_dev, blkno, block_size);
if (!bh)
sys_exit(-1);
memcpy_tofs(dest, (blk ? bh->b_data :
bh->b_data + sizeof(struct exec)), n);
brelse(bh);
}
++blk;
dest += n;
bytes -= n;
}
iput(inode);
current->executable = NULL;
if (!inode->i_op || !inode->i_op->default_file_ops)
goto end_readexec;
file.f_mode = 1;
file.f_flags = 0;
file.f_count = 1;
file.f_inode = inode;
file.f_pos = 0;
file.f_reada = 0;
file.f_op = inode->i_op->default_file_ops;
if (file.f_op->open)
if (file.f_op->open(inode,&file))
goto end_readexec;
if (!file.f_op || !file.f_op->read)
goto close_readexec;
if (file.f_op->lseek) {
if (file.f_op->lseek(inode,&file,offset,0) != offset)
goto close_readexec;
} else
file.f_pos = offset;
result = file.f_op->read(inode, &file, addr, count);
close_readexec:
if (file.f_op->release)
file.f_op->release(inode,&file);
end_readexec:
return result;
}
/*
......@@ -406,7 +417,8 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
char ** argv, char ** envp)
{
struct inode * inode;
struct buffer_head * bh;
char buf[128];
unsigned long old_fs;
struct exec ex;
unsigned long page[MAX_ARG_PAGES];
int i,argc,envc;
......@@ -463,32 +475,35 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
retval = -EACCES;
goto exec_error2;
}
if (!(bh = bread(inode->i_dev,bmap(inode,0),inode->i_sb->s_blocksize))) {
retval = -EACCES;
memset(buf,0,sizeof(buf));
old_fs = get_fs();
set_fs(get_ds());
retval = read_exec(inode,0,buf,128);
set_fs(old_fs);
if (retval < 0)
goto exec_error2;
}
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
ex = *((struct exec *) bh->b_data); /* read exec-header */
if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
ex = *((struct exec *) buf); /* exec-header */
if ((buf[0] == '#') && (buf[1] == '!') && (!sh_bang)) {
/*
* This section does the #! interpretation.
* Sorta complicated, but hopefully it will work. -TYT
*/
char buf[128], *cp, *interp, *i_name, *i_arg;
unsigned long old_fs;
char *cp, *interp, *i_name, *i_arg;
strncpy(buf, bh->b_data+2, 127);
brelse(bh);
iput(inode);
buf[127] = '\0';
if ((cp = strchr(buf, '\n')) != NULL) {
*cp = '\0';
for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
if ((cp = strchr(buf, '\n')) == NULL)
cp = buf+127;
*cp = '\0';
while (cp > buf) {
cp--;
if ((*cp == ' ') || (*cp == '\t'))
*cp = '\0';
else
break;
}
for (cp = buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
if (!cp || *cp == '\0') {
retval = -ENOEXEC; /* No interpreter name found */
goto exec_error1;
......@@ -499,10 +514,10 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
if (*cp == '/')
i_name = cp+1;
}
if (*cp) {
while ((*cp == ' ') || (*cp == '\t'))
*cp++ = '\0';
if (*cp)
i_arg = cp;
}
/*
* OK, we've parsed out the interpreter name and
* (optional) argument.
......@@ -542,7 +557,6 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
goto exec_error1;
goto restart_interp;
}
brelse(bh);
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC) ||
ex.a_trsize || ex.a_drsize ||
ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
......@@ -569,12 +583,13 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
if (ch == '/')
i = 0;
else
if (i < 8)
if (i < 15)
current->comm[i++] = ch;
if (i < 8)
current->comm[i] = '\0';
if (current->executable)
current->comm[i] = '\0';
if (current->executable) {
iput(current->executable);
current->executable = NULL;
}
i = current->numlibraries;
while (i-- > 0) {
iput(current->libraries[i].library);
......@@ -584,7 +599,6 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
!permission(inode,MAY_READ))
current->dumpable = 0;
current->numlibraries = 0;
current->executable = inode;
current->signal = 0;
for (i=0 ; i<32 ; i++) {
current->sigaction[i].sa_mask = 0;
......@@ -610,8 +624,14 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
current->rss = (TASK_SIZE - p + PAGE_SIZE-1) / PAGE_SIZE;
current->suid = current->euid = e_uid;
current->sgid = current->egid = e_gid;
if (N_MAGIC(ex) == OMAGIC)
read_omagic(inode, ex.a_text+ex.a_data);
if (N_MAGIC(ex) == OMAGIC) {
read_exec(inode, 32, (char *) 0, ex.a_text+ex.a_data);
iput(inode);
} else if (!inode->i_op || !inode->i_op->bmap) {
read_exec(inode, 1024, (char *) 0, ex.a_text+ex.a_data);
iput(inode);
} else
current->executable = inode;
eip[0] = ex.a_entry; /* eip, magic happens :-) */
eip[3] = p; /* stack pointer */
if (current->flags & PF_PTRACED)
......
......@@ -25,11 +25,11 @@ static int blkdev_open(struct inode * inode, struct file * filp)
int i;
i = MAJOR(inode->i_rdev);
if (i < MAX_BLKDEV) {
filp->f_op = blkdev_fops[i];
if (filp->f_op && filp->f_op->open)
return filp->f_op->open(inode,filp);
}
if (i >= MAX_BLKDEV || !blkdev_fops[i])
return -ENODEV;
filp->f_op = blkdev_fops[i];
if (filp->f_op->open)
return filp->f_op->open(inode,filp);
return 0;
}
......
......@@ -25,11 +25,11 @@ static int chrdev_open(struct inode * inode, struct file * filp)
int i;
i = MAJOR(inode->i_rdev);
if (i < MAX_CHRDEV) {
filp->f_op = chrdev_fops[i];
if (filp->f_op && filp->f_op->open)
return filp->f_op->open(inode,filp);
}
if (i >= MAX_CHRDEV || !chrdev_fops[i])
return -ENODEV;
filp->f_op = chrdev_fops[i];
if (filp->f_op->open)
return filp->f_op->open(inode,filp);
return 0;
}
......
......@@ -118,14 +118,14 @@ static int ext_file_read(struct inode * inode, struct file * filp, char * buf, i
buffers and caches. */
do {
bhrequest = 0;
uptodate = 1;
bhrequest = 0;
uptodate = 1;
while (blocks) {
--blocks;
*bhb = ext_getblk(inode, block++, 0);
if (*bhb && !(*bhb)->b_uptodate) {
uptodate = 0;
bhreq[bhrequest++] = *bhb;
uptodate = 0;
bhreq[bhrequest++] = *bhb;
}
if (++bhb == &buflist[NBUF])
......
......@@ -808,6 +808,11 @@ static int do_ext_rename(struct inode * old_dir, const char * old_name, int old_
retval = -EEXIST;
goto end_rename;
}
retval = -EPERM;
if (new_inode && (new_dir->i_mode & S_ISVTX) &&
current->euid != new_inode->i_uid &&
current->euid != new_dir->i_uid && !suser())
goto end_rename;
if (S_ISDIR(old_inode->i_mode)) {
retval = -EEXIST;
if (new_bh)
......
......@@ -24,11 +24,11 @@ static int blkdev_open(struct inode * inode, struct file * filp)
int i;
i = MAJOR(inode->i_rdev);
if (i < MAX_BLKDEV) {
filp->f_op = blkdev_fops[i];
if (filp->f_op && filp->f_op->open)
return filp->f_op->open(inode,filp);
}
if (i >= MAX_BLKDEV || !blkdev_fops[i])
return -ENODEV;
filp->f_op = blkdev_fops[i];
if (filp->f_op->open)
return filp->f_op->open(inode,filp);
return 0;
}
......
......@@ -24,11 +24,11 @@ static int chrdev_open(struct inode * inode, struct file * filp)
int i;
i = MAJOR(inode->i_rdev);
if (i < MAX_CHRDEV) {
filp->f_op = chrdev_fops[i];
if (filp->f_op && filp->f_op->open)
return filp->f_op->open(inode,filp);
}
if (i >= MAX_CHRDEV || !chrdev_fops[i])
return -ENODEV;
filp->f_op = chrdev_fops[i];
if (filp->f_op->open)
return filp->f_op->open(inode,filp);
return 0;
}
......
......@@ -19,11 +19,11 @@ static int blkdev_open(struct inode * inode, struct file * filp)
int i;
i = MAJOR(inode->i_rdev);
if (i < MAX_BLKDEV) {
filp->f_op = blkdev_fops[i];
if (filp->f_op && filp->f_op->open)
return filp->f_op->open(inode,filp);
}
if (i >= MAX_BLKDEV || !blkdev_fops[i])
return -ENODEV;
filp->f_op = blkdev_fops[i];
if (filp->f_op->open)
return filp->f_op->open(inode,filp);
return 0;
}
......
......@@ -19,11 +19,11 @@ static int chrdev_open(struct inode * inode, struct file * filp)
int i;
i = MAJOR(inode->i_rdev);
if (i < MAX_CHRDEV) {
filp->f_op = chrdev_fops[i];
if (filp->f_op && filp->f_op->open)
return filp->f_op->open(inode,filp);
}
if (i >= MAX_CHRDEV || !chrdev_fops[i])
return -ENODEV;
filp->f_op = chrdev_fops[i];
if (filp->f_op->open)
return filp->f_op->open(inode,filp);
return 0;
}
......
......@@ -113,13 +113,13 @@ static int minix_file_read(struct inode * inode, struct file * filp, char * buf,
do {
bhrequest = 0;
uptodate = 1;
uptodate = 1;
while (blocks) {
--blocks;
*bhb = minix_getblk(inode, block++, 0);
if (*bhb && !(*bhb)->b_uptodate) {
uptodate = 0;
bhreq[bhrequest++] = *bhb;
uptodate = 0;
bhreq[bhrequest++] = *bhb;
}
if (++bhb == &buflist[NBUF])
......
......@@ -683,6 +683,11 @@ static int do_minix_rename(struct inode * old_dir, const char * old_name, int ol
retval = -EEXIST;
goto end_rename;
}
retval = -EPERM;
if (new_inode && (new_dir->i_mode & S_ISVTX) &&
current->euid != new_inode->i_uid &&
current->euid != new_dir->i_uid && !suser())
goto end_rename;
if (S_ISDIR(old_inode->i_mode)) {
retval = -EEXIST;
if (new_bh)
......
......@@ -169,7 +169,6 @@ printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\n",
printk("Unsupported FS parameters\n");
return NULL;
}
if (!MSDOS_CAN_BMAP(MSDOS_SB(s))) printk("No bmap support\n");
s->s_magic = MSDOS_SUPER_MAGIC;
MSDOS_SB(s)->name_check = check;
MSDOS_SB(s)->conversion = conversion;
......@@ -266,7 +265,7 @@ void msdos_read_inode(struct inode *inode)
raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
[inode->i_ino & (MSDOS_DPB-1)];
if ((raw_entry->attr & ATTR_DIR) && *raw_entry->name && *(unsigned char *)
raw_entry->name != DELETED_FLAG) {
raw_entry->name != DELETED_FLAG) {
inode->i_mode = MSDOS_MKMODE(raw_entry->attr,0777 &
~MSDOS_SB(inode->i_sb)->fs_umask) | S_IFDIR;
inode->i_op = &msdos_dir_inode_operations;
......
......@@ -226,7 +226,7 @@ static void dump_fat(struct super_block *sb,int start)
printk("[");
while (start) {
printk("%d ",start);
start = fat_access(sb,start,-1);
start = fat_access(sb,start,-1);
if (!start) {
printk("ERROR");
break;
......
......@@ -19,11 +19,11 @@ static int blkdev_open(struct inode * inode, struct file * filp)
int i;
i = MAJOR(inode->i_rdev);
if (i < MAX_BLKDEV) {
filp->f_op = blkdev_fops[i];
if (filp->f_op && filp->f_op->open)
return filp->f_op->open(inode,filp);
}
if (i >= MAX_BLKDEV || !blkdev_fops[i])
return -ENODEV;
filp->f_op = blkdev_fops[i];
if (filp->f_op->open)
return filp->f_op->open(inode,filp);
return 0;
}
......
......@@ -19,11 +19,11 @@ static int chrdev_open(struct inode * inode, struct file * filp)
int i;
i = MAJOR(inode->i_rdev);
if (i < MAX_CHRDEV) {
filp->f_op = chrdev_fops[i];
if (filp->f_op && filp->f_op->open)
return filp->f_op->open(inode,filp);
}
if (i >= MAX_CHRDEV || !chrdev_fops[i])
return -ENODEV;
filp->f_op = chrdev_fops[i];
if (filp->f_op->open)
return filp->f_op->open(inode,filp);
return 0;
}
......
......@@ -243,6 +243,8 @@ int sys_fchmod(unsigned int fd, mode_t mode)
if (IS_RDONLY(inode))
return -EROFS;
inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
if (!suser() && !in_group_p(inode->i_gid))
inode->i_mode &= ~S_ISGID;
inode->i_dirt = 1;
return notify_change(inode);
}
......@@ -264,6 +266,8 @@ int sys_chmod(const char * filename, mode_t mode)
return -EROFS;
}
inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
if (!suser() && !in_group_p(inode->i_gid))
inode->i_mode &= ~S_ISGID;
inode->i_dirt = 1;
error = notify_change(inode);
iput(inode);
......
......@@ -14,7 +14,7 @@
.s.o:
$(AS) -o $*.o $<
OBJS= inode.o root.o base.o mem.o link.o fd.o array.o
OBJS= inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o
proc.o: $(OBJS)
$(LD) -r -o proc.o $(OBJS)
......
......@@ -26,8 +26,6 @@
#define SSIZE(stack) (KSTK_ESP(stack) ? _SSIZE(stack) : 0)
#define VSIZE(task,stack) ((task)->brk + 1023 + SSIZE(stack))
#define SIZE(task,stack) (((task)->brk - (task)->end_code + 1023 + \
SSIZE(stack)) / 1024)
static int get_loadavg(char * buffer)
......@@ -140,19 +138,42 @@ static int get_arg(int pid, char * buffer)
return get_array(p, (*p)->arg_start, (*p)->arg_end, buffer);
}
static unsigned long get_wchan(struct task_struct *p)
{
unsigned long ebp, eip;
unsigned long stack_page;
int count = 0;
if (!p || p == current)
return 0;
ebp = p->tss.ebp;
stack_page = p->kernel_stack_page;
do {
if (ebp < stack_page || ebp >= 4092+stack_page)
return 0;
eip = *(unsigned long *) (ebp+4);
if ((void *)eip != sleep_on &&
(void *)eip != interruptible_sleep_on)
return eip;
ebp = *(unsigned long *) ebp;
} while (count++ < 16);
return 0;
}
static int get_stat(int pid, char * buffer)
{
struct task_struct ** p = get_task(pid);
unsigned long sigignore=0, sigcatch=0, bit=1;
unsigned long sigignore=0, sigcatch=0, bit=1, wchan;
int i;
char state;
if (!p || !*p)
return 0;
if ((*p)->state < 0)
if ((*p)->state < 0 || (*p)->state > 5)
state = '.';
else
state = "RSDZTD"[(*p)->state];
wchan = get_wchan(*p);
for(i=0; i<32; ++i) {
switch((int) (*p)->sigaction[i].sa_handler) {
case 1: sigignore |= bit; break;
......@@ -200,7 +221,7 @@ static int get_stat(int pid, char * buffer)
(*p)->blocked,
sigignore,
sigcatch,
(*p)->tss.eip);
wchan);
}
static int get_statm(int pid, char * buffer)
......
......@@ -67,16 +67,6 @@ void proc_statfs(struct super_block *sb, struct statfs *buf)
/* Don't know what value to put in buf->f_fsid */
}
int proc_bmap(struct inode * inode,int block)
{
return 0;
}
int proc_create_block(struct inode * inode, int block)
{
return 0;
}
void proc_read_inode(struct inode * inode)
{
unsigned long ino, pid;
......@@ -111,6 +101,8 @@ void proc_read_inode(struct inode * inode)
if (!pid) {
inode->i_mode = S_IFREG | 0444;
inode->i_op = &proc_array_inode_operations;
if (ino == 5)
inode->i_op = &proc_kmsg_inode_operations;
return;
}
ino &= 0x0000ffff;
......
/*
* linux/fs/proc/kmsg.c
*
* Copyright (C) 1992 by Linus Torvalds
*
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <asm/segment.h>
#include <asm/io.h>
extern int sys_syslog(int type, char * bug, int count);
static int kmsg_open(struct inode * inode, struct file * file)
{
return sys_syslog(1,NULL,0);
}
static void kmsg_release(struct inode * inode, struct file * file)
{
(void) sys_syslog(0,NULL,0);
}
static int kmsg_read(struct inode * inode, struct file * file,char * buf, int count)
{
return sys_syslog(2,buf,count);
}
static struct file_operations proc_kmsg_operations = {
NULL, /* kmsg_lseek */
kmsg_read,
NULL, /* kmsg_write */
NULL, /* kmsg_readdir */
NULL, /* kmsg_select */
NULL, /* kmsg_ioctl */
NULL, /* mmap */
kmsg_open,
kmsg_release
};
struct inode_operations proc_kmsg_inode_operations = {
&proc_kmsg_operations, /* default base directory file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL /* truncate */
};
......@@ -54,7 +54,8 @@ static struct proc_dir_entry root_dir[] = {
{ 2,7,"loadavg" },
{ 3,6,"uptime" },
{ 4,7,"meminfo" },
{ 5,4,"self" } /* will change inode # */
{ 5,4,"kmsg" },
{ 6,4,"self" } /* will change inode # */
};
#define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
......@@ -81,7 +82,7 @@ static int proc_lookuproot(struct inode * dir,const char * name, int len,
*result = dir;
return 0;
}
if (ino == 5) /* self modifying inode ... */
if (ino == 6) /* self modifying inode ... */
ino = (current->pid << 16) + 2;
} else {
pid = 0;
......
......@@ -18,6 +18,8 @@
#include <asm/segment.h>
#include <asm/system.h>
#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
/*
* Ok, Peter made a complicated, but straightforward multiple_wait() function.
* I have rewritten this, taking some shortcuts: This code may not be easy to
......@@ -198,7 +200,7 @@ int sys_select( unsigned long *buffer )
timeout = 0xffffffff;
if (tvp) {
timeout = jiffies;
timeout += get_fs_long((unsigned long *)&tvp->tv_usec)/(1000000/HZ);
timeout += ROUND_UP(get_fs_long((unsigned long *)&tvp->tv_usec),(1000000/HZ));
timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ;
if (timeout <= jiffies)
timeout = 0;
......
......@@ -122,7 +122,15 @@ __asm__( \
"addl $8,%esp\n\t" \
"cli\n\t" \
UNBLK_##chip(mask) \
"call _do_bottom_half\n\t"\
"decl _intr_count\n\t" \
"jne ret_from_sys_call\n\t" \
"cmpl $0,_bh_active\n\t" \
"je ret_from_sys_call\n\t" \
"incl _intr_count\n\t" \
"sti\n\t" \
"call _do_bottom_half\n\t" \
"cli\n\t" \
"decl _intr_count\n\t" \
"jmp ret_from_sys_call\n" \
"\n.align 2\n" \
"_fast_IRQ" #nr "_interrupt:\n\t" \
......
#ifndef __ASM_SYSTEM_H
#define __ASM_SYSTEM_H
#define move_to_user_mode() \
__asm__ __volatile__ ("movl %%esp,%%eax\n\t" \
"pushl $0x17\n\t" \
......@@ -17,6 +20,14 @@ __asm__ __volatile__ ("movl %%esp,%%eax\n\t" \
#define cli() __asm__ __volatile__ ("cli"::)
#define nop() __asm__ __volatile__ ("nop"::)
extern inline int tas(char * m)
{
char res;
__asm__("xchg %0,%1":"=q" (res),"=m" (*m):"0" (0x1));
return res;
}
#define save_flags(x) \
__asm__ __volatile__("pushfl ; popl %0":"=r" (x))
......@@ -70,3 +81,5 @@ __asm__ __volatile__ ("movw $" #limit ",%1\n\t" \
#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),231,"0x89")
#define set_ldt_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),23,"0x82")
#endif
/*
* Automatically generated C config: don't edit
*/
/*
* General setup
*/
#define CONFIG_BLK_DEV_HD 1
#define CONFIG_TCPIP 1
#define CONFIG_MAX_16M 1
#define CONFIG_M486 1
/*
* SCSI support
*/
/*
* SCSI support type (disk, tape, CDrom)
*/
/*
* SCSI low-level drivers
*/
/*
* Filesystems
*/
#define CONFIG_MINIX_FS 1
#define CONFIG_PROC_FS 1
/*
* Various character device drivers..
*/
......@@ -22,7 +22,7 @@
#define DEF_INITSEG 0x9000
#define DEF_SYSSEG 0x1000
#define DEF_SETUPSEG 0x9020
#define DEF_SYSSIZE 0x7000
#define DEF_SYSSIZE 0x8000
/* internal svga startup constants */
#define NORMAL_VGA 0xffff /* 80x25 mode */
......
#define UTS_RELEASE "0.97.pl2-44"
#define UTS_VERSION "08/23/92"
......@@ -16,9 +16,15 @@ enum {
TIMER_BH = 0,
CONSOLE_BH,
SERIAL_BH,
INET_BH
INET_BH,
KEYBOARD_BH
};
void do_bottom_half();
extern inline void mark_bh(int nr)
{
__asm__ __volatile__("btsl %1,%0":"=m" (bh_active):"ir" (nr));
}
#endif
......@@ -30,32 +30,31 @@
* have extremely slow printing, or if the machine seems to slow down
* a lot when you print. If you have slow printing, increase this
* number and recompile, and if your system gets bogged down, decrease
* this number. This can be changed with the tunelp(8) command.
* this number. This can be changed with the tunelp(8) command as well.
*/
#define LP_INIT_CHAR 250
#define LP_INIT_CHAR 1000
/* The parallel port specs apparently say that there needs to be
* a .5usec wait before and after the strobe. Since there are wildly
* different computers running linux, I can't come up with a perfect
* value, but since it worked well on most printers before without,
* and I have seen some improvement on my computer by making it a
* small number, I'll initialize it to 2.
* I'll initialize it to 0.
*/
#define LP_INIT_WAIT 2
#define LP_INIT_WAIT 0
/* This is the amount of time that the driver waits for the printer to
* catch up when the printer's buffer appears to be filled. If you
* want to tune this and have a fast printer (i.e. HPIIIP), decrease
* this number, and if you have a slow printer, increase this number.
* This is in hundredths of a second, the default 10 being .1 second.
* This is in hundredths of a second, the default 2 being .05 second.
* Or use the tunelp(8) command, which is especially nice if you want
* change back and forth between character and graphics printing, which
* are wildly different...
*/
#define LP_INIT_TIME 10
#define LP_INIT_TIME 2
/* IOCTL numbers */
#define LPCHAR 0x0001 /* corresponds to LP_INIT_CHAR */
......
......@@ -5,12 +5,20 @@
* The minix filesystem constants/structures
*/
/*
* Thanks to Kees J Bot for sending me the definitions of the new
* minix filesystem (aka V2) with bigger inodes and 32-bit block
* pointers. It's not actually implemented yet, but I'll look into
* it.
*/
#define MINIX_NAME_LEN 14
#define MINIX_ROOT_INO 1
#define MINIX_I_MAP_SLOTS 8
#define MINIX_Z_MAP_SLOTS 8
#define MINIX_SUPER_MAGIC 0x137F
#define MINIX_I_MAP_SLOTS 8
#define MINIX_Z_MAP_SLOTS 8
#define MINIX_SUPER_MAGIC 0x137F
#define NEW_MINIX_SUPER_MAGIC 0x2468
#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
#define MINIX_DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_dir_entry)))
......@@ -25,6 +33,24 @@ struct minix_inode {
unsigned short i_zone[9];
};
/*
* The new minix inode has all the time entries, as well as
* long block numbers and a third indirect block (7+1+1+1
* instead of 7+1+1). Also, some previously 8-bit values are
* now 16-bit. The inode is now 64 bytes instead of 32.
*/
struct new_minix_inode {
unsigned short i_mode;
unsigned short i_nlinks;
unsigned short i_uid;
unsigned short i_gid;
unsigned long i_size;
unsigned long i_atime;
unsigned long i_mtime;
unsigned long i_ctime;
unsigned long i_zone[10];
};
/*
* minix super-block data on disk
*/
......
......@@ -27,6 +27,7 @@ extern struct inode_operations proc_root_inode_operations;
extern struct inode_operations proc_base_inode_operations;
extern struct inode_operations proc_mem_inode_operations;
extern struct inode_operations proc_array_inode_operations;
extern struct inode_operations proc_kmsg_inode_operations;
extern struct inode_operations proc_link_inode_operations;
extern struct inode_operations proc_fd_inode_operations;
......
......@@ -184,7 +184,7 @@ struct task_struct {
struct rlimit rlim[RLIM_NLIMITS];
unsigned short used_math;
unsigned short rss; /* number of resident pages */
char comm[8];
char comm[16];
struct vm86_struct * vm86_info;
unsigned long screen_bitmap;
/* file system info */
......
......@@ -82,7 +82,7 @@ typedef unsigned long tcflag_t;
#define __FDSET_LONGS 8
typedef struct fd_set {
unsigned long __bits [__FDSET_LONGS];
unsigned long fds_bits [__FDSET_LONGS];
} fd_set;
#undef __NFDBITS
......
......@@ -100,7 +100,7 @@ extern unsigned long scsi_dev_init(unsigned long, unsigned long);
*/
#define CMOS_READ(addr) ({ \
outb_p(0x80|addr,0x70); \
outb_p(addr,0x70); \
inb_p(0x71); \
})
......@@ -109,7 +109,11 @@ inb_p(0x71); \
static void time_init(void)
{
struct mktime time;
int i;
for (i = 0 ; i < 1000000 ; i++)
if (!(CMOS_READ(10) & 0x80))
break;
do {
time.sec = CMOS_READ(0);
time.min = CMOS_READ(2);
......
......@@ -115,7 +115,7 @@ void get_address(unsigned char FPU_modrm)
{
unsigned char mod;
long *cpu_reg_ptr;
int offset;
int offset = 0;
mod = (FPU_modrm >> 6) & 3;
......
......@@ -104,11 +104,9 @@ extern int last_reset[];
char * revision; /* Latest revision known to be bad. Not used yet */
};
#if 0
static struct blist blacklist[] =
{{"TANDBERG","TDC 3600","U07"}, /* Locks up if polled for lun != 0 */
{"SEAGATE","ST296","921"}, /* Responds to all lun */
{"NEWBURY","NDR3380S","2.10"}, /* Responds to all lun */
{NULL, NULL, NULL}};
static int blacklisted(char * response_data){
......@@ -122,7 +120,6 @@ static int blacklisted(char * response_data){
return 1;
};
};
#endif
/*
* As the actual SCSI command runs in the background, we must set up a
......@@ -324,11 +321,9 @@ static void scan_scsis (void)
};
++NR_SCSI_DEVICES;
#if 0
/* Some scsi devices cannot be polled for lun != 0
due to firmware bugs */
if(blacklisted(scsi_result)) break;
#endif
/* Some scsi-1 peripherals do not handle lun != 0.
I am assuming that scsi-2 peripherals do better */
if((scsi_result[2] & 0x07) == 1 &&
......
......@@ -62,7 +62,7 @@ static int sd_open(struct inode * inode, struct file * filp)
target = DEVICE_NR(MINOR(inode->i_rdev));
if(target >= NR_SD || !rscsi_disks[target].device)
return -EACCES; /* No such device */
return -ENODEV; /* No such device */
/* Make sure that only one process can do a check_change_disk at one time.
This is also used to lock out further access when the partition table is being re-read. */
......@@ -761,6 +761,7 @@ unsigned long sd_init(unsigned long memory_start, unsigned long memory_end)
{
int i;
blkdev_fops[MAJOR_NR] = &sd_fops; /* to get sd_open in table */
if (MAX_SD == 0) return memory_start;
sd_sizes = (int *) memory_start;
......@@ -779,7 +780,6 @@ unsigned long sd_init(unsigned long memory_start, unsigned long memory_end)
i = sd_init_onedisk(i);
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
blkdev_fops[MAJOR_NR] = &sd_fops;
/* If our host adapter is capable of scatter-gather, then we increase
the read-ahead to 8 blocks (16 sectors). If not, we use
......
......@@ -61,7 +61,7 @@ static volatile int st0x_aborted=0; /*
detect routine - but this
overides it.
*/
static unsigned char controller_type; /* set to SEAGATE for ST0x boards or FD for TMC-88x boards */
#define retcode(result) (((result) << 16) | (message << 8) | status)
#define STATUS (*(unsigned char *) st0x_cr_sr)
......@@ -76,11 +76,12 @@ typedef struct
char *signature ;
unsigned offset;
unsigned length;
unsigned char type;
} Signature;
static const Signature signatures[] = {
#ifdef CONFIG_SCSI_SEAGATE
{"SCSI BIOS 2.00 (C) Copyright 1987 Seagate", 15, 40},
{"SCSI BIOS 2.00 (C) Copyright 1987 Seagate", 15, 40, SEAGATE},
/*
The following two lines are NOT mistakes. One detects
......@@ -90,9 +91,8 @@ static const Signature signatures[] = {
are probably "good enough"
*/
{"SEAGATE SCSI BIOS ",16, 17},
{"SEAGATE SCSI BIOS ",17, 17},
#endif
{"SEAGATE SCSI BIOS ",16, 17, SEAGATE},
{"SEAGATE SCSI BIOS ",17, 17, SEAGATE},
/*
This is for the Future Domain 88x series. I've been told that
......@@ -101,8 +101,9 @@ static const Signature signatures[] = {
I believe it.
*/
#ifdef CONFIG_SCSI_FD_88x
{"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/90", 5, 46},
{"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/90", 5, 46, FD},
{"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90",5, 47, FD},
{"FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90", 5, 46, FD},
#endif
}
;
......@@ -168,14 +169,16 @@ static struct sigaction seagate_sigaction = {
for (j = 0; !base_address && j < NUM_SIGNATURES; ++j)
if (!memcmp ((void *) (seagate_bases[i] +
signatures[j].offset), (void *) signatures[j].signature,
signatures[j].length))
signatures[j].length)) {
base_address = (void *) seagate_bases[i];
controller_type = signatures[j].type;
}
#endif
if (base_address)
{
st0x_cr_sr =(void *) (((unsigned char *) base_address) + 0x1a00);
st0x_dr = (void *) (((unsigned char *) base_address )+ 0x1c00);
st0x_cr_sr =(void *) (((unsigned char *) base_address) + (controller_type == SEAGATE ? 0x1a00 : 0x1c00));
st0x_dr = (void *) (((unsigned char *) base_address ) + (controller_type == SEAGATE ? 0x1c00 : 0x1e00));
#ifdef DEBUG
printk("ST0x detected. Base address = %x, cr = %x, dr = %x\n", base_address, st0x_cr_sr, st0x_dr);
#endif
......@@ -369,7 +372,7 @@ static int internal_command(unsigned char target, unsigned char lun, const void
#endif
if (target > 6)
if (target == (controller_type == SEAGATE ? 7 : 6))
return DID_BAD_TARGET;
/*
......@@ -410,7 +413,7 @@ static int internal_command(unsigned char target, unsigned char lun, const void
* ID off of the BUS.
*/
if (!((temp = DATA) & 0x80))
if (!((temp = DATA) & (controller_type == SEAGATE ? 0x80 : 0x40)))
{
#if (DEBUG & PHASE_RESELECT)
printk("scsi%d : detected reconnect request to different target.\n"
......@@ -518,7 +521,7 @@ static int internal_command(unsigned char target, unsigned char lun, const void
/*
* We must assert both our ID and our target's ID on the bus.
*/
DATA = (unsigned char) ((1 << target) | 0x80);
DATA = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40));
/*
* If we are allowing ourselves to reconnect, then I will keep
......
......@@ -125,6 +125,9 @@ extern volatile int seagate_st0x_timeout;
#define eoi() __asm__("push %%eax\nmovb $0x20, %%al\noutb %%al, $0x20\npop %%eax"::)
#define SEAGATE 1 /* these determine the type of the controller */
#define FD 2
#endif
......@@ -257,7 +257,7 @@ static void rw_intr (Scsi_Cmnd * SCpnt)
static int sr_open(struct inode * inode, struct file * filp)
{
if(MINOR(inode->i_rdev) >= NR_SR ||
!scsi_CDs[MINOR(inode->i_rdev)].device) return -EACCES; /* No such device */
!scsi_CDs[MINOR(inode->i_rdev)].device) return -ENODEV; /* No such device */
check_disk_change(inode->i_rdev);
......@@ -601,6 +601,7 @@ unsigned long sr_init(unsigned long memory_start, unsigned long memory_end)
{
int i;
blkdev_fops[MAJOR_NR] = &sr_fops;
if(MAX_SR == 0) return memory_start;
sr_sizes = (int *) memory_start;
......@@ -628,6 +629,5 @@ unsigned long sr_init(unsigned long memory_start, unsigned long memory_end)
else
read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */
blkdev_fops[MAJOR_NR] = &sr_fops;
return memory_start;
}
......@@ -292,7 +292,7 @@ static int scsi_tape_open(struct inode * inode, struct file * filp)
dev = inode->i_rdev & 127;
if (dev >= NR_ST)
return (-ENXIO);
return (-ENODEV);
if (scsi_tapes[dev].in_use) {
printk("st%d: Device already in use.\n", dev);
return (-EBUSY);
......@@ -1227,12 +1227,12 @@ unsigned long st_init(unsigned long mem_start, unsigned long mem_end)
{
int i;
chrdev_fops[MAJOR_NR] = &st_fops;
if (NR_ST == 0) return mem_start;
#ifdef DEBUG
printk("st: Init tape.\n");
#endif
chrdev_fops[MAJOR_NR] = &st_fops;
for (i=0; i < NR_ST; ++i) {
scsi_tapes[i].capacity = 0xfffff;
......
......@@ -61,8 +61,6 @@
indices need not be involved.
*/
static void wd7000_set_sync(int id);
static struct {
struct wd_mailbox ogmb[OGMB_CNT];
struct wd_mailbox icmb[ICMB_CNT];
......@@ -576,21 +574,6 @@ const char *wd7000_info(void)
return info;
}
void wd7000_set_sync(int id)
{
volatile unchar icb[ICB_LEN] = {0x8a};
unchar speedval = 0x2c; /* Sets 4MHz for SBIC Revision A */
any2scsi(icb+2,1); /* Transfer 1 byte */
any2scsi(icb+5,&speedval); /* The speed buffer address */
icb[8]=0; icb[9]=2*id; /* The index into the table */
icb[ICB_PHASE] = 1;
mail_out( (struct scb *) icb );
while (icb[ICB_PHASE]) /* wait for completion */;
}
int wd7000_abort(Scsi_Cmnd * SCpnt, int i)
{
#ifdef DEBUG
......
......@@ -15,6 +15,7 @@
#include <linux/mm.h>
#include <linux/ptrace.h>
#include <linux/keyboard.h>
#include <linux/interrupt.h>
/*
* The default IO slowdown is doing 'inb()'s from 0x61, which should be
......@@ -39,6 +40,9 @@ struct kbd_struct kbd_table[NR_CONSOLES];
static struct kbd_struct * kbd = kbd_table;
static struct tty_struct * tty = NULL;
static volatile unsigned char acknowledge = 0;
static volatile unsigned char resend = 0;
typedef void (*fptr)(int);
static int diacr = -1;
......@@ -53,57 +57,87 @@ static unsigned int handle_diacr(unsigned int);
static struct pt_regs * pt_regs;
static inline void kb_wait(void)
{
int i;
for (i=0; i<0x10000; i++)
if ((inb_p(0x64) & 0x02) == 0)
break;
}
/*
* send_cmd() sends a command byte to the keyboard.
*/
static inline void send_cmd(unsigned char c)
{
kb_wait();
outb(c,0x64);
}
static inline unsigned char get_scancode(void)
{
kb_wait();
if (inb_p(0x64) & 0x01)
return inb(0x60);
return 0;
}
static void keyboard_interrupt(int int_pt_regs)
{
static unsigned char rep = 0xff;
unsigned char scancode;
pt_regs = (struct pt_regs *) int_pt_regs;
while (inb_p(0x64) & 1) {
kbd_prev_dead_keys |= kbd_dead_keys;
if (!kbd_dead_keys)
kbd_prev_dead_keys = 0;
kbd_dead_keys = 0;
scancode = inb_p(0x60);
tty = TTY_TABLE(0);
kbd = kbd_table + fg_console;
if (vc_kbd_flag(kbd,VC_RAW)) {
kbd_flags = 0;
put_queue(scancode);
continue;
}
if (scancode == 0xe0) {
set_kbd_dead(KGD_E0);
continue;
} else if (scancode == 0xe1) {
set_kbd_dead(KGD_E1);
continue;
}
/*
* The keyboard maintains its own internal caps lock and num lock
* statuses. In caps lock mode E0 AA precedes make code and E0 2A
* follows break code. In num lock mode, E0 2A precedes make
* code and E0 AA follows break code. We do our own book-keeping,
* so we will just ignore these.
*/
if (kbd_dead(KGD_E0) && (scancode == 0x2a || scancode == 0xaa))
continue;
/*
* Repeat a key only if the input buffers are empty or the
* characters get echoed locally. This makes key repeat usable
* with slow applications and unders heavy loads.
*/
if (scancode == rep) {
if (!(vc_kbd_flag(kbd,VC_REPEAT) && tty &&
(L_ECHO(tty) ||
(EMPTY(&tty->secondary) &&
EMPTY(&tty->read_q)))))
continue;
}
rep = scancode;
key_table[scancode](scancode);
kbd_prev_dead_keys |= kbd_dead_keys;
if (!kbd_dead_keys)
kbd_prev_dead_keys = 0;
kbd_dead_keys = 0;
send_cmd(0xAD);
scancode = get_scancode();
if (scancode == 0xfa) {
acknowledge = 1;
goto end_kbd_intr;
} else if (scancode == 0xfe) {
resend = 1;
goto end_kbd_intr;
}
tty = TTY_TABLE(0);
kbd = kbd_table + fg_console;
if (vc_kbd_flag(kbd,VC_RAW)) {
kbd_flags = 0;
put_queue(scancode);
goto end_kbd_intr;
}
if (scancode == 0xe0) {
set_kbd_dead(KGD_E0);
goto end_kbd_intr;
} else if (scancode == 0xe1) {
set_kbd_dead(KGD_E1);
goto end_kbd_intr;
}
/*
* The keyboard maintains its own internal caps lock and num lock
* statuses. In caps lock mode E0 AA precedes make code and E0 2A
* follows break code. In num lock mode, E0 2A precedes make
* code and E0 AA follows break code. We do our own book-keeping,
* so we will just ignore these.
*/
if (kbd_dead(KGD_E0) && (scancode == 0x2a || scancode == 0xaa))
goto end_kbd_intr;
/*
* Repeat a key only if the input buffers are empty or the
* characters get echoed locally. This makes key repeat usable
* with slow applications and unders heavy loads.
*/
if ((scancode != rep) ||
(vc_kbd_flag(kbd,VC_REPEAT) && tty &&
(L_ECHO(tty) || (EMPTY(&tty->secondary) && EMPTY(&tty->read_q)))))
key_table[scancode](scancode);
rep = scancode;
end_kbd_intr:
do_keyboard_interrupt();
send_cmd(0xAE);
}
static void put_queue(int ch)
......@@ -1273,51 +1307,48 @@ static void none(int sc)
}
/*
* kb_wait waits for the keyboard controller buffer to empty.
* send_data sends a character to the keyboard and waits
* for a acknowledge, possibly retrying if asked to. Returns
* the success status.
*/
static void kb_wait(void)
static int send_data(unsigned char data)
{
int retries = 3;
int i;
for (i=0; i<0x10000; i++)
if ((inb(0x64)&0x02) == 0)
break;
do {
kb_wait();
acknowledge = 0;
resend = 0;
outb_p(data, 0x60);
for(i=0; i<0x20000; i++) {
inb_p(0x64); /* just as a delay */
if (acknowledge)
return 1;
if (resend)
goto repeat;
}
return 0;
repeat:
} while (retries-- > 0);
return 0;
}
/*
* kb_ack waits for 0xfa to appear in port 0x60
*
* Suggested by Bruce Evans
* Added by Niels Skou Olsen [NSO]
* April 21, 1992
*
* Heavily inspired by kb_wait :-)
* I don't know how much waiting actually is required,
* but this seems to work
*/
static void kb_ack(void)
static void kbd_bh(void * unused)
{
int i;
static unsigned char old_leds = -1;
unsigned char leds = kbd_table[fg_console].flags & LED_MASK;
for(i=0; i<0x10000; i++)
if (inb(0x60) == 0xfa)
break;
if (leds == old_leds)
return;
old_leds = leds;
if (!send_data(0xed) || !send_data(leds))
send_data(0xf4); /* re-enable kbd if any errors */
}
void set_leds(void)
{
static unsigned char old_leds = -1;
unsigned char leds = kbd_table[fg_console].flags & LED_MASK;
if (leds != old_leds) {
old_leds = leds;
kb_wait();
outb(0xed, 0x60); /* set leds command */
kb_ack();
kb_wait();
outb(leds, 0x60);
kb_ack();
}
mark_bh(KEYBOARD_BH);
}
long no_idt[2] = {0, 0};
......@@ -1332,7 +1363,7 @@ void hard_reset_now(void)
int i, j;
extern unsigned long pg0[1024];
sti();
cli();
/* rebooting needs to touch the page at absolute addr 0 */
pg0[0] = 7;
*((unsigned short *)0x472) = 0x1234;
......@@ -1425,6 +1456,7 @@ unsigned long kbd_init(unsigned long kmem_start)
kbd->default_flags = KBD_DEFFLAGS;
kbd->kbd_flags = KBDFLAGS;
}
bh_base[KEYBOARD_BH].routine = kbd_bh;
request_irq(KEYBOARD_IRQ,keyboard_interrupt);
keyboard_interrupt(0);
return kmem_start;
......
......@@ -13,3 +13,7 @@ long soundcard_init(long mem_start)
{
return mem_start;
}
#ifdef CONFIG_SOUND
#error The Sound Driver not installed.
#endif
......@@ -1130,9 +1130,9 @@ long tty_init(long kmem_start)
tty_table[i] = 0;
tty_termios[i] = 0;
}
kmem_start = kbd_init(kmem_start);
kmem_start = con_init(kmem_start);
kmem_start = rs_init(kmem_start);
kmem_start = kbd_init(kmem_start);
printk("%d virtual consoles\n\r",NR_CONSOLES);
return kmem_start;
}
......@@ -61,18 +61,24 @@ void flush_output(struct tty_struct * tty)
void wait_until_sent(struct tty_struct * tty)
{
while (!(current->signal & ~current->blocked) &&
!EMPTY(&tty->write_q)) {
struct wait_queue wait = { current, NULL };
TTY_WRITE_FLUSH(tty);
if (EMPTY(&tty->write_q))
return;
add_wait_queue(&tty->write_q.proc_list, &wait);
current->counter = 0; /* make us low-priority */
while (1) {
current->state = TASK_INTERRUPTIBLE;
if (current->signal & ~current->blocked)
break;
TTY_WRITE_FLUSH(tty);
current->counter = 0;
cli();
if (EMPTY(&tty->write_q))
break;
else
interruptible_sleep_on(&tty->write_q.proc_list);
sti();
schedule();
}
sti();
current->state = TASK_RUNNING;
remove_wait_queue(&tty->write_q.proc_list, &wait);
}
static int do_get_ps_info(int arg)
......@@ -333,7 +339,14 @@ int tty_ioctl(struct inode * inode, struct file * file,
case TIOCNXCL:
return -EINVAL; /* not implemented */
case TIOCSCTTY:
return -EINVAL; /* set controlling term NI */
if (current->leader && current->tty < 0
&& tty->session == 0) {
current->tty = dev;
tty->session = current->session;
tty->pgrp = current->pgrp;
return 0;
}
return -EPERM;
case TIOCGPGRP:
verify_area((void *) arg,4);
put_fs_long(termios_tty->pgrp,(unsigned long *) arg);
......
......@@ -32,8 +32,7 @@
#include <asm/io.h>
#include <asm/irq.h>
void irq13(void);
#define CR0_NE 32
static unsigned long intr_count=0;
......@@ -41,55 +40,25 @@ static unsigned long intr_count=0;
int bh_active=0;
struct bh_struct bh_base[32];
/* interrupts should be on at the interrupt priority controller level. */
/* returns with interrupts off at the processor level. */
/*
* do_bottom_half() runs at normal kernel priority: all interrupts
* enabled. do_bottom_half() is atomic with respect to itself: a
* bottom_half handler need not be re-entrant. This function is
* called only when bh_active is non-zero and when there aren't any
* nested irq's active.
*/
void do_bottom_half(void)
{
struct bh_struct *bh;
int mask;
int count;
static int in_bh = 0;
cli();
if (intr_count > 1) {
intr_count--;
return;
}
/* don't just decrement it in case it is already 0 */
intr_count = 0;
/* any sort of real time test should go here. */
if (in_bh != 0) {
return;
}
in_bh = 1;
do {
count = 0;
for (mask = 1, bh = bh_base; mask ; bh++, mask = mask << 1) {
if (mask > bh_active)
break;
if (!(mask & bh_active))
continue;
int nr;
count++;
bh_active &= ~mask;
/* turn the interrupts back on. */
sti();
if (bh->routine != NULL)
bh->routine(bh->data);
else
printk ("irq.c:bad bottom half entry.\n");
/* and back off. */
cli();
}
} while (count > 0);
in_bh = 0;
__asm__ __volatile__("bsfl %1,%0":"=r" (nr):"m" (bh_active));
__asm__ __volatile__("btcl %1,%0":"=m" (bh_active):"r" (nr));
bh = bh_base+nr;
if (bh->routine != NULL)
bh->routine(bh->data);
else
printk ("irq.c:bad bottom half entry.\n");
}
/*
......@@ -267,12 +236,24 @@ void free_irq(unsigned int irq)
extern void do_coprocessor_error(long,long);
/*
* Note that on a 486, we don't want to do a SIGFPE on a irq13
* as the irq is unreliable, and exception 16 works correctly
* (ie as explained in the intel litterature). On a 386, you
* can't use exception 16 due to bad IBM design, so we have to
* rely on the less exact irq13.
*/
static void math_error_irq(int cpl)
{
outb(0,0xF0);
do_coprocessor_error(0,0);
}
static void math_error_irq_486(int cpl)
{
outb(0,0xF0); /* even this is probably not needed.. */
}
static void no_action(int cpl) { }
static struct sigaction ignore_IRQ = {
......@@ -285,20 +266,25 @@ static struct sigaction ignore_IRQ = {
void init_IRQ(void)
{
int i;
unsigned long cr0;
for (i = 0; i < 16 ; i++)
set_intr_gate(0x20+i,bad_interrupt[i]);
if (irqaction(2,&ignore_IRQ))
printk("Unable to get IRQ2 for cascade\n");
if (request_irq(13,math_error_irq))
__asm__("movl %%cr0,%%eax":"=a" (cr0));
if (cr0 & CR0_NE)
i = request_irq(13,math_error_irq_486);
else
i = request_irq(13,math_error_irq);
if (i)
printk("Unable to get IRQ13 for math-error handler\n");
/* intialize the bottom half routines. */
for (i = 0; i < 32; i++)
{
bh_base[i].routine = NULL;
bh_base[i].data = NULL;
}
for (i = 0; i < 32; i++) {
bh_base[i].routine = NULL;
bh_base[i].data = NULL;
}
bh_active = 0;
intr_count = 0;
}
......@@ -74,11 +74,11 @@ void math_state_restore()
{
if (last_task_used_math == current)
return;
__asm__("fwait");
if (last_task_used_math) {
__asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
}
last_task_used_math=current;
__asm__("fwait");
last_task_used_math = current;
if (current->used_math) {
__asm__("frstor %0"::"m" (current->tss.i387));
} else {
......
......@@ -149,6 +149,9 @@ _system_call:
call _schedule
.align 4,0x90
ret_from_sys_call:
/*
* XXX - interrupts are masked here about 3 times in 1000. Fishy.
*/
movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are
testl $VM_MASK,%eax # different then
jne 4f
......@@ -172,11 +175,11 @@ ret_from_sys_call:
movl blocked(%eax),%ecx
notl %ecx
andl %ebx,%ecx
je 2f # XXX - branch is almost always taken
bsfl %ecx,%ecx
je 2f
btrl %ecx,%ebx
btrl %ecx,signal(%eax) # change atomically (%ebx is stale)
jnc 2f # bit became clear (can't happen?)
incl %ecx
movl %ebx,signal(%eax)
movl %esp,%ebx
testl $VM_MASK,EFLAGS(%esp)
je 3f
......
......@@ -286,7 +286,7 @@ dev_rint(unsigned char *buff, long len, int flags,
sti();
if (backlog != NULL)
bh_active |= 1 << INET_BH;
mark_bh(INET_BH);
return (0);
}
......
......@@ -184,29 +184,9 @@ unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
return (unix_proto_read (sock, buff, len, nonblock));
}
/*
* Since unix domain sockets use filenames to communicate, two sockets are
* the same if their strings are the same, even if their lengths are different
* (due to possible null terminations). Verified under SunOS 4.1.2
*/
static int
same_path(char *s1, int l1, char *s2, int l2)
{
/*
* Skip chars while they're equal
*/
for (; l1 && l2 && *s1 == *s2; ++s1, ++s2, --l1, --l2);
/*
* Both must be exhausted, or one must be null terminated and the
* other either exhausted or null terminated, for the paths to be
* equivalent
*/
return ((l1 == 0 || *s1 == '\0') && (l2 == 0 || *s2 == '\0'));
}
static struct unix_proto_data *
unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len)
unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len,
struct inode *inode)
{
struct unix_proto_data *upd;
......@@ -214,9 +194,7 @@ unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len)
if (upd->refcnt && upd->socket &&
upd->socket->state == SS_UNCONNECTED &&
upd->sockaddr_un.sun_family == sockun->sun_family &&
same_path(sockun->sun_path, sockaddr_len - UN_PATH_OFFSET,
upd->sockaddr_un.sun_path,
upd->sockaddr_len - UN_PATH_OFFSET))
upd->inode == inode)
return upd;
}
return NULL;
......@@ -386,6 +364,7 @@ unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
#ifdef SOCK_DEBUG
sockaddr_un_printk(&upd->sockaddr_un, upd->sockaddr_len);
#endif
PRINTK("to inode 0x%x\n", upd->inode);
return 0;
}
......@@ -400,6 +379,9 @@ unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
int i;
struct unix_proto_data *serv_upd;
struct sockaddr_un sockun;
char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
unsigned long old_fs;
struct inode *inode;
PRINTK("unix_proto_connect: socket 0x%x, servlen=%d\n", sock,
sockaddr_len);
......@@ -423,8 +405,28 @@ unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
sockun.sun_family, AF_UNIX);
return -EINVAL;
}
if (!(serv_upd = unix_data_lookup(&sockun, sockaddr_len))) {
PRINTK("unix_proto_connect: can't locate peer\n");
/*
* try to open the name in the filesystem - this is how we
* identify ourselves and our server. Note that we don't
* hold onto the inode that long, just enough to find our
* server. When we're connected, we mooch off the server.
*/
memcpy(fname, sockun.sun_path, sockaddr_len-UN_PATH_OFFSET);
fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
old_fs = get_fs();
set_fs(get_ds());
i = open_namei(fname, 0, S_IFSOCK, &inode, NULL);
set_fs(old_fs);
if (i < 0) {
PRINTK("unix_proto_connect: can't open socket %s\n", fname);
return i;
}
serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode);
iput(inode);
if (!serv_upd) {
PRINTK("unix_proto_connect: can't locate peer %s at inode 0x%x\n",
fname, inode);
return -EINVAL;
}
if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0) {
......@@ -437,7 +439,7 @@ unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
}
/*
* to do a socketpair, we make just connect the two datas, easy! since we
* to do a socketpair, we just connect the two datas, easy! since we
* always wait on the socket inode, they're no contention for a wait area,
* and deadlock prevention in the case of a process writing to itself is,
* ignored, in true unix fashion!
......
......@@ -28,11 +28,12 @@
#include <sys/sysmacros.h>
#include <unistd.h> /* contains read/write */
#include <fcntl.h>
#include <linux/config.h>
#define MINIX_HEADER 32
#define GCC_HEADER 1024
#define SYS_SIZE 0x7000
#define SYS_SIZE DEF_SYSSIZE
#define DEFAULT_MAJOR_ROOT 0
#define DEFAULT_MINOR_ROOT 0
......@@ -43,6 +44,32 @@
#define STRINGIFY(x) #x
typedef union {
long l;
short s[2];
char b[4];
} conv;
long intel_long(long l)
{
conv t;
t.b[0] = l & 0xff; l >>= 8;
t.b[1] = l & 0xff; l >>= 8;
t.b[2] = l & 0xff; l >>= 8;
t.b[3] = l & 0xff; l >>= 8;
return t.l;
}
short intel_short(short l)
{
conv t;
t.b[0] = l & 0xff; l >>= 8;
t.b[1] = l & 0xff; l >>= 8;
return t.s[0];
}
void die(char * str)
{
fprintf(stderr,"%s\n",str);
......@@ -85,9 +112,9 @@ int main(int argc, char ** argv)
die("Unable to open 'boot'");
if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
die("Unable to read header of 'boot'");
if (((long *) buf)[0]!=0x04100301)
if (((long *) buf)[0]!=intel_long(0x04100301))
die("Non-Minix header of 'boot'");
if (((long *) buf)[1]!=MINIX_HEADER)
if (((long *) buf)[1]!=intel_long(MINIX_HEADER))
die("Non-Minix header of 'boot'");
if (((long *) buf)[3]!=0)
die("Illegal data segment in 'boot'");
......@@ -101,7 +128,7 @@ int main(int argc, char ** argv)
fprintf(stderr,"Boot sector %d bytes.\n",i);
if (i != 512)
die("Boot block must be exactly 512 bytes");
if ((*(unsigned short *)(buf+510)) != 0xAA55)
if ((*(unsigned short *)(buf+510)) != (unsigned short)intel_short(0xAA55))
die("Boot block hasn't got boot flag (0xAA55)");
buf[508] = (char) minor_root;
buf[509] = (char) major_root;
......@@ -114,9 +141,9 @@ int main(int argc, char ** argv)
die("Unable to open 'setup'");
if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
die("Unable to read header of 'setup'");
if (((long *) buf)[0]!=0x04100301)
if (((long *) buf)[0]!=intel_long(0x04100301))
die("Non-Minix header of 'setup'");
if (((long *) buf)[1]!=MINIX_HEADER)
if (((long *) buf)[1]!=intel_long(MINIX_HEADER))
die("Non-Minix header of 'setup'");
if (((long *) buf)[3]!=0)
die("Illegal data segment in 'setup'");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment