diff options
author | Linus Benedict Torvalds <torvalds@klaava.Helsinki.FI> | 1992-06-04 22:56:21 +0000 |
---|---|---|
committer | Nicolas Pitre <nico@cam.org> | 2007-08-19 14:19:04 -0400 |
commit | 13f296db85e43116f5e1de944b6997dd98093640 (patch) | |
tree | 7658905de163908272cc1291b5ad5c858356c7ac | |
parent | 46d255794351e97e7b06958d2859b6ec7c373f73 (diff) | |
download | archive-13f296db85e43116f5e1de944b6997dd98093640.tar.gz |
Second patch to 0.96av0.96a-pl2
I have just sent off the second patch to 0.96a: it should be on the
normal ftp-sites (nic, tsx-11 and banjo), although the only site which I
can make it directly readable on is banjo, so on the other sites it will
take the site-managers to make the patch available.
Patch 2 implements:
- itimers (by Darren Senn), which are now also used to implement the
alarm() system call.
- ultrastor scsi driver patches (by gentzel)
- [f]statfs() system call is implemented (so df can be made fs-
independent). Also some other minor fs-changes for the upcoming new
filesystem. Patches by Remy Card.
- preliminary core-file dumping code (linux creates a core-file, but
it's not in the correct format yet [*]).
- minor changes/bugfixes.
While patching in patch1 is a good idea for anybody, patch 2 isn't
really vital. I've made it available just so kernel hackers can keep up
with the kernel I have right now if they wish. Patch 2 is relative to
patch 1: you have to patch that in first.
[*] The current core-file is very simple, and the kernel code is there
just so that some enterprising character can expand it. A core-file
looks like this right now:
offset data
0x0000 "core-dump: regs=\n"
0x0040 struct pt_regs (see <sys/ptrace.c>)
0x0400 "floating-point regs:\n"
0x0440 struct i387 (see <linux/sched.h>)
0x0800 the first 1kB of user-space
Not very practical, but it /might/ help if the X-server dies of a
segmentation fault or similar (you can use pt_regs.eip to see where it
happened). The kernel code is very easy to change to accomodate for the
real core-file format, I just didn't know what it should be.
Linus
39 files changed, 767 insertions, 304 deletions
diff --git a/boot/bootsect.S b/boot/bootsect.S index 837be32..22ebdea 100644 --- a/boot/bootsect.S +++ b/boot/bootsect.S @@ -224,8 +224,7 @@ got_sectors: mov ax,#0x021c ! /dev/PS0 - 1.44Mb cmp bx,#18 je root_defined -undef_root: - jmp undef_root + mov ax,#0x0200 ! /dev/fd0 - autodetect root_defined: seg cs mov root_dev,ax @@ -21,7 +21,9 @@ #include <errno.h> #include <linux/string.h> #include <sys/stat.h> +#include <sys/ptrace.h> #include <a.out.h> +#include <fcntl.h> #include <linux/fs.h> #include <linux/sched.h> @@ -40,6 +42,86 @@ extern int sys_close(int fd); #define MAX_ARG_PAGES 32 /* + * These are the only things you should do on a core-file: use only these + * macros to write out all the necessary info. + */ +#define DUMP_WRITE(addr,nr) \ +while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump + +#define DUMP_SEEK(offset) \ +if (file.f_op->lseek) { \ + if (file.f_op->lseek(inode,&file,(offset),0) != (offset)) \ + goto close_coredump; \ +} else file.f_pos = (offset) + +/* + * Routine writes a core dump image in the current directory. + * Currently only a stub-function. + * + * Note that setuid/setgid files won't make a core-dump if the uid/gid + * changed due to the set[u|g]id. It's enforced by the "current->dumpable" + * field, which also makes sure the core-dumps won't be recursive if the + * dumping of the process results in another error.. + */ +int core_dump(long signr, struct pt_regs * regs) +{ + struct inode * inode = NULL; + struct file file; + unsigned short fs; + int has_dumped = 0; + + if (!current->dumpable) + return 0; + current->dumpable = 0; + __asm__("mov %%fs,%0":"=r" (fs)); + __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10)); + if (open_namei("core",O_CREAT | O_WRONLY | O_TRUNC,0600,&inode)) + goto end_coredump; + if (!S_ISREG(inode->i_mode)) + goto end_coredump; + if (!inode->i_op || !inode->i_op->default_file_ops) + goto end_coredump; + file.f_mode = 3; + 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_coredump; + if (!file.f_op->write) + goto close_coredump; + has_dumped = 1; +/* write and seek example: from kernel space */ + __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10)); + DUMP_WRITE("core-dump, regs=\n",17); + DUMP_SEEK(64); + DUMP_WRITE(regs,sizeof(*regs)); + if (current->used_math) { + if (last_task_used_math == current) + __asm__("clts ; fnsave %0"::"m" (current->tss.i387)); + DUMP_SEEK(1024); + DUMP_WRITE("floating-point regs=\n",21); + DUMP_SEEK(1088); + DUMP_WRITE(¤t->tss.i387,sizeof(current->tss.i387)); + } +/* now we start writing out the user space info */ + __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x17)); +/* the dummy dump-file contains the first block of user space... */ + DUMP_SEEK(2048); + DUMP_WRITE(0,1024); +close_coredump: + if (file.f_op->release) + file.f_op->release(inode,&file); +end_coredump: + __asm__("mov %0,%%fs"::"r" (fs)); + iput(inode); + return has_dumped; +} + +/* * Note that a shared library must be both readable and executable due to * security reasons. * @@ -406,6 +488,7 @@ restart_interp: } } /* OK, This is the point of no return */ + current->dumpable = 1; for (i=0; (ch = get_fs_byte(filename++)) != '\0';) if (ch == '/') i = 0; @@ -421,6 +504,9 @@ restart_interp: iput(current->libraries[i].library); current->libraries[i].library = NULL; } + if (e_uid != current->euid || e_gid != current->egid || + !permission(inode,MAY_READ)) + current->dumpable = 0; current->numlibraries = 0; current->executable = inode; current->signal = 0; @@ -454,7 +540,7 @@ restart_interp: eip[0] = ex.a_entry; /* eip, magic happens :-) */ eip[3] = p; /* stack pointer */ if (current->flags & PF_PTRACED) - send_sig(SIGTRAP, current, 0); + send_sig(SIGTRAP, current, 0); return 0; exec_error2: iput(inode); diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c index a7fd3c3..fe185a7 100644 --- a/fs/minix/bitmap.c +++ b/fs/minix/bitmap.c @@ -1,5 +1,5 @@ /* - * linux/fs/bitmap.c + * linux/fs/minix/bitmap.c * * (C) 1991 Linus Torvalds */ @@ -44,6 +44,35 @@ __asm__("cld\n" \ :"=c" (__res):"0" (0),"S" (addr):"ax","dx","si"); \ __res;}) +static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 }; + +static unsigned long count_used(struct buffer_head *map[], unsigned numblocks, + unsigned numbits) +{ + unsigned i, j, end, sum = 0; + struct buffer_head *bh; + + for (i=0; (i<numblocks) && numbits; i++) { + if (!(bh=map[i])) + return(0); + if (numbits >= (8*BLOCK_SIZE)) { + end = BLOCK_SIZE; + numbits -= 8*BLOCK_SIZE; + } else { + int tmp; + end = numbits >> 3; + numbits &= 0x7; + tmp = bh->b_data[end] & ((1<<numbits)-1); + sum += nibblemap[tmp&0xf] + nibblemap[(tmp>>4)&0xf]; + numbits = 0; + } + for (j=0; j<end; j++) + sum += nibblemap[bh->b_data[j] & 0xf] + + nibblemap[(bh->b_data[j]>>4)&0xf]; + } + return(sum); +} + int minix_free_block(int dev, int block) { struct super_block * sb; @@ -107,6 +136,12 @@ int minix_new_block(int dev) return j; } +unsigned long minix_count_free_blocks(struct super_block *sb) +{ + return (sb->s_nzones - count_used(sb->s_zmap,sb->s_zmap_blocks,sb->s_nzones)) + << sb->s_log_zone_size; +} + void minix_free_inode(struct inode * inode) { struct buffer_head * bh; @@ -182,3 +217,8 @@ struct inode * minix_new_inode(int dev) inode->i_op = NULL; return inode; } + +unsigned long minix_count_free_inodes(struct super_block *sb) +{ + return sb->s_ninodes - count_used(sb->s_imap,sb->s_imap_blocks,sb->s_ninodes); +} diff --git a/fs/minix/blkdev.c b/fs/minix/blkdev.c index fec1bc9..a70b513 100644 --- a/fs/minix/blkdev.c +++ b/fs/minix/blkdev.c @@ -1,5 +1,5 @@ /* - * linux/fs/chrdev.c + * linux/fs/minix/blkdev.c * * (C) 1991 Linus Torvalds */ @@ -19,7 +19,6 @@ static int blkdev_open(struct inode * inode, struct file * filp) { int i; - check_disk_change(inode->i_rdev); i = MAJOR(inode->i_rdev); if (i < MAX_BLKDEV) { filp->f_op = blkdev_fops[i]; diff --git a/fs/minix/chrdev.c b/fs/minix/chrdev.c index 489849f..8957eb4 100644 --- a/fs/minix/chrdev.c +++ b/fs/minix/chrdev.c @@ -1,5 +1,5 @@ /* - * linux/fs/chrdev.c + * linux/fs/minix/chrdev.c * * (C) 1991 Linus Torvalds */ diff --git a/fs/minix/dir.c b/fs/minix/dir.c index d09585a..467d227 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c @@ -1,7 +1,9 @@ /* - * linux/fs/minix/dir.c + * linux/fs/minix/dir.c * - * minix directory hadnling functions + * (C) 1991 Linus Torvalds + * + * minix directory handling functions */ #include <errno.h> diff --git a/fs/minix/file.c b/fs/minix/file.c index 9ebeebb..7b6e033 100644 --- a/fs/minix/file.c +++ b/fs/minix/file.c @@ -1,7 +1,9 @@ /* - * linux/fs/minix/file.c + * linux/fs/minix/file.c * - * minix regular file handling primitives + * (C) 1991 Linus Torvalds + * + * minix regular file handling primitives */ #include <errno.h> @@ -212,10 +214,8 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf brelse(bh); } inode->i_mtime = CURRENT_TIME; - if (!(filp->f_flags & O_APPEND)) { - filp->f_pos = pos; - inode->i_ctime = CURRENT_TIME; - } + inode->i_ctime = CURRENT_TIME; + filp->f_pos = pos; inode->i_dirt = 1; return written; } diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 4ddf5c2..df68ec5 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <asm/system.h> +#include <asm/segment.h> int sync_dev(int dev); @@ -40,12 +41,14 @@ static struct super_operations minix_sops = { minix_read_inode, minix_write_inode, minix_put_inode, - minix_put_super + minix_put_super, + minix_statfs }; struct super_block *minix_read_super(struct super_block *s,void *data) { struct buffer_head *bh; + struct minix_super_block *ms; int i,dev=s->s_dev,block; lock_super(s); @@ -55,8 +58,17 @@ struct super_block *minix_read_super(struct super_block *s,void *data) printk("bread failed\n"); return NULL; } - *((struct minix_super_block *) s) = - *((struct minix_super_block *) bh->b_data); +/* *((struct minix_super_block *) s) = + *((struct minix_super_block *) bh->b_data); */ + ms = (struct minix_super_block *) bh->b_data; + s->s_ninodes = ms->s_ninodes; + s->s_nzones = ms->s_nzones; + s->s_imap_blocks = ms->s_imap_blocks; + s->s_zmap_blocks = ms->s_zmap_blocks; + s->s_firstdatazone = ms->s_firstdatazone; + s->s_log_zone_size = ms->s_log_zone_size; + s->s_max_size = ms->s_max_size; + s->s_magic = ms->s_magic; brelse(bh); if (s->s_magic != MINIX_SUPER_MAGIC) { s->s_dev = 0; @@ -103,6 +115,21 @@ struct super_block *minix_read_super(struct super_block *s,void *data) return s; } +void minix_statfs (struct super_block *sb, struct statfs *buf) +{ + long tmp; + + put_fs_long(MINIX_SUPER_MAGIC, &buf->f_type); + put_fs_long(1024, &buf->f_bsize); + put_fs_long(sb->s_nzones << sb->s_log_zone_size, &buf->f_blocks); + tmp = minix_count_free_blocks(sb); + put_fs_long(tmp, &buf->f_bfree); + put_fs_long(tmp, &buf->f_bavail); + put_fs_long(sb->s_ninodes, &buf->f_files); + put_fs_long(minix_count_free_inodes(sb), &buf->f_ffree); + /* Don't know what value to put in buf->f_fsid */ +} + static int _minix_bmap(struct inode * inode,int block,int create) { struct buffer_head * bh; diff --git a/fs/minix/symlink.c b/fs/minix/symlink.c index 70fbeb0..0b5c5dc 100644 --- a/fs/minix/symlink.c +++ b/fs/minix/symlink.c @@ -1,7 +1,9 @@ /* - * linux/fs/minix/symlink.c + * linux/fs/minix/symlink.c * - * minix symlink handling code + * (C) 1991 Linus Torvalds + * + * minix symlink handling code */ #include <errno.h> @@ -201,7 +201,7 @@ int open_namei(const char * pathname, int flag, int mode, if ((flag & O_TRUNC) && !(flag & O_ACCMODE)) flag |= O_WRONLY; - mode &= 0777 & ~current->umask; + mode &= 07777 & ~current->umask; mode |= I_REGULAR; if (!(dir = dir_namei(pathname,&namelen,&basename,NULL))) return -ENOENT; @@ -33,14 +33,34 @@ int sys_ustat(int dev, struct ustat * ubuf) int sys_statfs(const char * path, struct statfs * buf) { - printk("statfs not implemented\n"); - return -ENOSYS; + struct inode * inode; + + verify_area(buf, sizeof(struct statfs)); + if (!(inode = namei(path))) + return -ENOENT; + if (!inode->i_sb->s_op->statfs) { + iput(inode); + return -ENOSYS; + } + inode->i_sb->s_op->statfs(inode->i_sb, buf); + iput(inode); + return 0; } int sys_fstatfs(unsigned int fd, struct statfs * buf) { - printk("fstatfs not implemented\n"); - return -ENOSYS; + struct inode * inode; + struct file * file; + + verify_area(buf, sizeof(struct statfs)); + if (fd >= NR_OPEN || !(file = current->filp[fd])) + return -EBADF; + if (!(inode = file->f_inode)) + return -ENOENT; + if (!inode->i_sb->s_op->statfs) + return -ENOSYS; + inode->i_sb->s_op->statfs(inode->i_sb, buf); + return 0; } int sys_truncate(const char * path, unsigned int length) @@ -256,13 +276,13 @@ int sys_open(const char * filename,int flag,int mode) if (!current->filp[fd]) break; if (fd>=NR_OPEN) - return -EINVAL; + return -EMFILE; current->close_on_exec &= ~(1<<fd); f=0+file_table; for (i=0 ; i<NR_FILE ; i++,f++) if (!f->f_count) break; if (i>=NR_FILE) - return -EINVAL; + return -ENFILE; (current->filp[fd] = f)->f_count++; if ((i = open_namei(filename,flag,mode,&inode))<0) { current->filp[fd]=NULL; @@ -174,6 +174,7 @@ int sys_pipe(unsigned long * fildes) } f[0]->f_inode = f[1]->f_inode = inode; f[0]->f_pos = f[1]->f_pos = 0; + f[0]->f_flags = f[1]->f_flags = 0; f[0]->f_op = &read_pipe_fops; f[0]->f_mode = 1; /* read */ f[1]->f_op = &write_pipe_fops; diff --git a/include/asm/io.h b/include/asm/io.h index af1c72f..dd7cb44 100644 --- a/include/asm/io.h +++ b/include/asm/io.h @@ -18,9 +18,11 @@ __asm__ volatile ("outb %0,%1" extern void inline outb_p(char value, unsigned short port) { __asm__ volatile ("outb %0,%1\n\t" +#ifdef REALLY_SLOW_IO "outb %0,$0x80\n\t" "outb %0,$0x80\n\t" "outb %0,$0x80\n\t" +#endif "outb %0,$0x80" ::"a" ((char) value),"d" ((unsigned short) port)); } @@ -37,9 +39,11 @@ extern unsigned char inline inb_p(unsigned short port) { unsigned char _v; __asm__ volatile ("inb %1,%0\n\t" +#ifdef REALLY_SLOW_IO "outb %0,$0x80\n\t" "outb %0,$0x80\n\t" "outb %0,$0x80\n\t" +#endif "outb %0,$0x80" :"=a" (_v):"d" ((unsigned short) port)); return _v; diff --git a/include/linux/fs.h b/include/linux/fs.h index c4bcb84..304b374 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -8,6 +8,7 @@ #include <sys/types.h> #include <sys/dirent.h> +#include <sys/vfs.h> /* devices are as follows: (same as minix, so we can use the minix * file system. These are major numbers.) @@ -135,12 +136,12 @@ typedef struct select_table_struct { } select_table; struct super_block { - unsigned short s_ninodes; - unsigned short s_nzones; - unsigned short s_imap_blocks; - unsigned short s_zmap_blocks; - unsigned short s_firstdatazone; - unsigned short s_log_zone_size; + unsigned long s_ninodes; + unsigned long s_nzones; + unsigned long s_imap_blocks; + unsigned long s_zmap_blocks; + unsigned long s_firstdatazone; + unsigned long s_log_zone_size; unsigned long s_max_size; unsigned short s_magic; /* These are only in memory */ @@ -191,6 +192,7 @@ struct super_operations { void (*write_inode) (struct inode *inode); void (*put_inode) (struct inode *inode); void (*put_super)(struct super_block *sb); + void (*statfs) (struct super_block *sb, struct statfs *buf); }; struct file_system_type { diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h index a51b60c..76f8f51 100644 --- a/include/linux/minix_fs.h +++ b/include/linux/minix_fs.h @@ -60,8 +60,10 @@ extern int minix_rename(struct inode * old_dir, const char * old_name, int old_l struct inode * new_dir, const char * new_name, int new_len); extern struct inode * minix_new_inode(int dev); extern void minix_free_inode(struct inode * inode); +extern unsigned long minix_count_free_inodes(struct super_block *sb); extern int minix_new_block(int dev); extern int minix_free_block(int dev, int block); +extern unsigned long minix_count_free_blocks(struct super_block *sb); extern int minix_create_block(struct inode *, int); extern int minix_bmap(struct inode *,int); @@ -72,6 +74,7 @@ extern struct super_block *minix_read_super(struct super_block *,void *); extern void minix_read_inode(struct inode *); extern void minix_write_inode(struct inode *); extern void minix_put_inode(struct inode *); +extern void minix_statfs(struct super_block *, struct statfs *); extern int minix_lseek(struct inode *, struct file *, off_t, int); extern int minix_read(struct inode *, struct file *, char *, int); diff --git a/include/linux/sched.h b/include/linux/sched.h index b52578d..e301b34 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -119,6 +119,7 @@ struct task_struct { long blocked; /* bitmap of masked signals */ /* various fields */ int exit_code; + int dumpable; unsigned long start_code,end_code,end_data,brk,start_stack; long pid,pgrp,session,leader; int groups[NGROUPS]; @@ -134,7 +135,9 @@ struct task_struct { struct task_struct *next_wait; unsigned short uid,euid,suid; unsigned short gid,egid,sgid; - unsigned long timeout,alarm; + unsigned long timeout; + unsigned long it_real_value, it_prof_value, it_virt_value; + unsigned long it_real_incr, it_prof_incr, it_virt_incr; long utime,stime,cutime,cstime,start_time; unsigned long min_flt, maj_flt; unsigned long cmin_flt, cmaj_flt; @@ -181,12 +184,12 @@ struct task_struct { #define INIT_TASK \ /* state etc */ { 0,15,15, \ /* signals */ 0,{{},},0, \ -/* ec,brk... */ 0,0,0,0,0,0, \ +/* ec,brk... */ 0,0,0,0,0,0,0, \ /* pid etc.. */ 0,0,0,0, \ /* suppl grps*/ {NOGROUP,}, \ /* proc links*/ &init_task.task,NULL,NULL,NULL,NULL, \ /* uid etc */ 0,0,0,0,0,0, \ -/* timeout */ 0,0,0,0,0,0,0, \ +/* timeout */ 0,0,0,0,0,0,0,0,0,0,0,0, \ /* min_flt */ 0,0,0,0, \ /* rlimits */ { {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \ {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \ diff --git a/include/linux/sys.h b/include/linux/sys.h index d35b1d7..79640f1 100644 --- a/include/linux/sys.h +++ b/include/linux/sys.h @@ -106,6 +106,8 @@ extern int sys_fstatfs(); extern int sys_ioperm(); extern int sys_socketcall(); extern int sys_syslog(); +extern int sys_getitimer(); +extern int sys_setitimer(); fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read, sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link, @@ -126,7 +128,7 @@ sys_select, sys_symlink, sys_lstat, sys_readlink, sys_uselib, sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap, sys_truncate, sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, sys_setpriority, sys_profil, sys_statfs, sys_fstatfs, sys_ioperm, -sys_socketcall, sys_syslog }; +sys_socketcall, sys_syslog, sys_setitimer, sys_getitimer }; /* So we don't have to do any more manual updating.... */ int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr); diff --git a/include/linux/unistd.h b/include/linux/unistd.h index 21e19ba..a9e8501 100644 --- a/include/linux/unistd.h +++ b/include/linux/unistd.h @@ -117,6 +117,9 @@ extern int errno; +#define __NR_setitimer 104 +#define __NR_getitimer 105 + /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ #define _syscall0(type,name) \ type name(void) \ diff --git a/include/signal.h b/include/signal.h index e4126d3..91df52e 100644 --- a/include/signal.h +++ b/include/signal.h @@ -43,9 +43,10 @@ typedef unsigned int sigset_t; /* 32 bits */ #define SIGPOLL SIGIO #define SIGXCPU 24 #define SIGXFSZ 25 +*/ + #define SIGVTALRM 26 #define SIGPROF 27 -*/ #define SIGWINCH 28 diff --git a/include/sys/time.h b/include/sys/time.h index 1165c26..9d1f785 100644 --- a/include/sys/time.h +++ b/include/sys/time.h @@ -54,6 +54,9 @@ struct itimerval { struct timeval it_value; /* current value */ }; +int getitimer(int which, struct itimerval *value); +int setitimer(int which, struct itimerval *value, struct itimerval *ovalue); + #include <time.h> #include <sys/types.h> diff --git a/kernel/Makefile b/kernel/Makefile index 716bcfd..8930f3f 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -28,7 +28,7 @@ CPP =cpp -nostdinc -I../include OBJS = sched.o sys_call.o traps.o asm.o fork.o \ panic.o printk.o vsprintf.o sys.o exit.o \ - signal.o mktime.o ptrace.o ioport.o + signal.o mktime.o ptrace.o ioport.o itimer.o kernel.o: $(OBJS) $(LD) -r -o kernel.o $(OBJS) diff --git a/kernel/blk_drv/blk.h b/kernel/blk_drv/blk.h index 1bc455c..4535f6d 100644 --- a/kernel/blk_drv/blk.h +++ b/kernel/blk_drv/blk.h @@ -149,47 +149,40 @@ extern inline void unlock_buffer(struct buffer_head * bh) wake_up(&bh->b_wait); } -extern inline void end_request(int uptodate) +static void end_request(int uptodate) { - struct request * tmp; - - tmp = CURRENT; - DEVICE_OFF(tmp->dev); - CURRENT = tmp->next; - if (tmp->bh) { - tmp->bh->b_uptodate = uptodate; - unlock_buffer(tmp->bh); - } - if (!uptodate) { - printk(DEVICE_NAME " I/O error\n\r"); - printk("dev %04x, block %d\n\r",tmp->dev, - tmp->bh->b_blocknr); - } - wake_up(&tmp->waiting); - tmp->dev = -1; - wake_up(&wait_for_request); -} - -extern inline void next_buffer(int uptodate) -{ - struct buffer_head *tmp; + struct request * req; + struct buffer_head * bh; - tmp = CURRENT->bh; - CURRENT->bh = tmp->b_reqnext; - tmp->b_reqnext = NULL; - tmp->b_uptodate = uptodate; - unlock_buffer(tmp); + req = CURRENT; + req->errors = 0; if (!uptodate) { printk(DEVICE_NAME " I/O error\n\r"); - printk("dev %04x, block %d\n\r",tmp->b_dev, tmp->b_blocknr); + printk("dev %04x, sector %d\n\r",req->dev,req->sector); + req->nr_sectors--; + req->nr_sectors &= ~1; + req->sector += 2; + req->sector &= ~1; } - if (!CURRENT->bh) { - printk("next_buffer: request buffer list destroyed\r\n"); - end_request(0); - return; + if (bh = req->bh) { + req->bh = bh->b_reqnext; + bh->b_reqnext = NULL; + bh->b_uptodate = uptodate; + unlock_buffer(bh); + if (bh = req->bh) { + if (req->nr_sectors < 2) { + req->nr_sectors = 2; + printk("end_request: buffer-list destroyed\n"); + } + req->buffer = bh->b_data; + return; + } } - CURRENT->buffer = CURRENT->bh->b_data; - CURRENT->errors = 0; + DEVICE_OFF(req->dev); + CURRENT = req->next; + wake_up(&req->waiting); + req->dev = -1; + wake_up(&wait_for_request); } #ifdef DEVICE_INTR diff --git a/kernel/blk_drv/floppy.c b/kernel/blk_drv/floppy.c index 2b9d238..c4af79e 100644 --- a/kernel/blk_drv/floppy.c +++ b/kernel/blk_drv/floppy.c @@ -35,7 +35,7 @@ /* * Automatic floppy-detection and formatting written by Werner Almesberger * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with - * the floppy-change signa| detection. + * the floppy-change signal detection. */ #include <linux/sched.h> @@ -942,7 +942,8 @@ static void config_types(void) { printk("Floppy drive(s): "); base_type[0] = find_base(0,(CMOS_READ(0x10) >> 4) & 15); - if (((CMOS_READ(0x14) >> 6) & 1) == 0) base_type[0] = NULL; + if (((CMOS_READ(0x14) >> 6) & 1) == 0) + base_type[1] = NULL; else { printk(", "); base_type[1] = find_base(1,CMOS_READ(0x10) & 15); diff --git a/kernel/blk_drv/hd.c b/kernel/blk_drv/hd.c index 6244567..e573315 100644 --- a/kernel/blk_drv/hd.c +++ b/kernel/blk_drv/hd.c @@ -24,6 +24,8 @@ #include <linux/fs.h> #include <linux/kernel.h> #include <linux/hdreg.h> + +#define REALLY_SLOW_IO #include <asm/system.h> #include <asm/io.h> #include <asm/segment.h> @@ -423,17 +425,8 @@ static void bad_rw_intr(void) if (!CURRENT) return; if (++CURRENT->errors >= MAX_ERRORS) - if (CURRENT->bh && CURRENT->nr_sectors > 2) { - CURRENT->nr_sectors--; - CURRENT->sector++; - if (CURRENT->nr_sectors & 1) { - CURRENT->nr_sectors--; - CURRENT->sector++; - } - next_buffer(0); - } else - end_request(0); - if (CURRENT->errors > MAX_ERRORS/2) + end_request(0); + else if (CURRENT->errors > MAX_ERRORS/2) reset = 1; else recalibrate = 1; @@ -457,16 +450,15 @@ static void read_intr(void) if ((i & STAT_MASK) != STAT_OK) goto bad_read; CURRENT->errors = 0; - if (CURRENT->bh && (CURRENT->nr_sectors&1) && CURRENT->nr_sectors > 2) - next_buffer(1); - else - CURRENT->buffer += 512; + CURRENT->buffer += 512; CURRENT->sector++; - if (--CURRENT->nr_sectors) { + i = --CURRENT->nr_sectors; + if (!i || (CURRENT->bh && !(i&1))) + end_request(1); + if (i > 0) { SET_INTR(&read_intr); return; } - end_request(1); #if (HD_DELAY > 0) last_req = read_timer(); #endif @@ -487,24 +479,22 @@ static void write_intr(void) i = (unsigned) inb_p(HD_STATUS); if ((i & STAT_MASK) != STAT_OK) goto bad_write; - if (CURRENT->nr_sectors < 2) { + if (CURRENT->nr_sectors > 1 && !(i & DRQ_STAT)) + goto bad_write; + CURRENT->sector++; + i = --CURRENT->nr_sectors; + CURRENT->buffer += 512; + if (!i || (CURRENT->bh && !(i & 1))) end_request(1); + if (i > 0) { + SET_INTR(&write_intr); + port_write(HD_DATA,CURRENT->buffer,256); + } else { #if (HD_DELAY > 0) last_req = read_timer(); #endif do_hd_request(); - return; } - if (!(i & DRQ_STAT)) - goto bad_write; - CURRENT->sector++; - CURRENT->nr_sectors--; - if (CURRENT->bh && !(CURRENT->nr_sectors & 1)) - next_buffer(1); - else - CURRENT->buffer += 512; - SET_INTR(&write_intr); - port_write(HD_DATA,CURRENT->buffer,256); return; bad_write: if (i & ERR_STAT) @@ -534,16 +524,7 @@ static void hd_times_out(void) printk("HD timeout\n\r"); cli(); if (++CURRENT->errors >= MAX_ERRORS) - if (CURRENT->bh && CURRENT->nr_sectors > 2) { - CURRENT->nr_sectors--; - CURRENT->sector++; - if (CURRENT->nr_sectors & 1) { - CURRENT->nr_sectors--; - CURRENT->sector++; - } - next_buffer(0); - } else - end_request(0); + end_request(0); do_hd_request(); } @@ -558,7 +539,7 @@ static void do_hd_request(void) dev = MINOR(CURRENT->dev); block = CURRENT->sector; nsect = CURRENT->nr_sectors; - if (dev >= (NR_HD<<6) || block+nsect > hd[dev].nr_sects) { + if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) { end_request(0); goto repeat; } diff --git a/kernel/blk_drv/ll_rw_blk.c b/kernel/blk_drv/ll_rw_blk.c index 18f58d4..cd6aef7 100644 --- a/kernel/blk_drv/ll_rw_blk.c +++ b/kernel/blk_drv/ll_rw_blk.c @@ -125,6 +125,11 @@ static void make_request(int major,int rw, struct buffer_head * bh) printk("Bad block dev command, must be R/W/RA/WA\n"); return; } + if (blk_size[major]) + if (blk_size[major][MINOR(bh->b_dev)] <= bh->b_blocknr) { + bh->b_dirt = bh->b_uptodate = 0; + return; + } lock_buffer(bh); if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) { unlock_buffer(bh); diff --git a/kernel/blk_drv/scsi/ultrastor.c b/kernel/blk_drv/scsi/ultrastor.c index 049fdd8..085e10f 100644 --- a/kernel/blk_drv/scsi/ultrastor.c +++ b/kernel/blk_drv/scsi/ultrastor.c @@ -1,16 +1,39 @@ /* * ultrastor.c (C) 1991 David B. Gentzel - * Low-level scsi driver for UltraStor 14F + * Low-level SCSI driver for UltraStor 14F * by David B. Gentzel, Whitfield Software Services, Carnegie, PA * (gentzel@nova.enet.dec.com) * Thanks to UltraStor for providing the necessary documentation */ -/* ??? Caveats: - This driver is VERY stupid. It takes no advantage of much of the power of - the UltraStor controller. We just sit-and-spin while waiting for commands - to complete. I hope to go back and beat it into shape, but PLEASE, anyone - else who would like to, please make improvements! */ +/* + * NOTES: + * The UltraStor 14F is an intelligent, high performance ISA SCSI-2 host + * adapter. It is essentially an ISA version of the UltraStor 24F EISA + * adapter. It supports first-party DMA, command queueing, and + * scatter/gather I/O. It can also emulate the standard AT MFM/RLL/IDE + * interface for use with OS's which don't support SCSI. + * + * This driver may also work (with some small changes) with the UltraStor + * 24F. I have no way of confirming this... + * + * Places flagged with a triple question-mark are things which are either + * unfinished, questionable, or wrong. + */ + +/* + * CAVEATS: ??? + * This driver is VERY stupid. It takes no advantage of much of the power + * of the UltraStor controller. We just sit-and-spin while waiting for + * commands to complete. I hope to go back and beat it into shape, but + * PLEASE, anyone else who would like to, please make improvements! + * + * By defining USE_QUEUECOMMAND as TRUE in ultrastor.h, you enable the + * queueing feature of the mid-level SCSI driver. This should improve + * performance somewhat. However, it does not seem to work. I believe + * this is due to a bug in the mid-level driver, but I haven't looked + * too closely. + */ #include <linux/config.h> @@ -19,22 +42,20 @@ #include <stddef.h> #include <linux/string.h> -#include <linux/config.h> #include <linux/sched.h> -#include <linux/fs.h> #include <linux/kernel.h> -#include <linux/hdreg.h> -#include <asm/system.h> #include <asm/io.h> -#include <asm/segment.h> +#include <asm/system.h> +#define ULTRASTOR_PRIVATE /* Get the private stuff from ultrastor.h */ #include "ultrastor.h" #include "scsi.h" #include "hosts.h" -#define VERSION "1.0 alpha" +#define VERSION "1.0 beta" #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0]) +#define BIT(n) (1ul << (n)) #define BYTE(num, n) ((unsigned char)((unsigned int)(num) >> ((n) * 8))) /* Simply using "unsigned long" in these structures won't work as it causes @@ -44,21 +65,32 @@ typedef struct { unsigned char bytes[4]; } Longword; +/* Used to fetch the configuration info from the config i/o registers. We + then store (in a friendlier format) in config. */ +struct config_1 { + unsigned char bios_segment: 3; + unsigned char reserved: 1; + unsigned char interrupt: 2; + unsigned char dma_channel: 2; +}; +struct config_2 { + unsigned char ha_scsi_id: 3; + unsigned char mapping_mode: 2; + unsigned char bios_drive_number: 1; + unsigned char tfr_port: 2; +}; + /* Used to store configuration info read from config i/o registers. Most of this is not used yet, but might as well save it. */ struct config { - struct { - unsigned char bios_segment: 3; - unsigned char reserved: 1; - unsigned char interrupt: 2; - unsigned char dma_channel: 2; - } config_1; - struct { - unsigned char ha_scsi_id: 3; - unsigned char mapping_mode: 2; - unsigned char bios_drive_number: 1; - unsigned char tfr_port: 2; - } config_2; + unsigned short port_address; + const void *bios_segment; + unsigned char interrupt: 4; + unsigned char dma_channel: 3; + unsigned char ha_scsi_id: 3; + unsigned char heads: 6; + unsigned char sectors: 6; + unsigned char bios_drive_number: 1; }; /* MailBox SCSI Command Packet. Basic command structure for communicating @@ -97,12 +129,11 @@ static const unsigned char interrupt_table[4] = { 15, 14, 11, 10 }; /* Allowed DMA channels for 14f (0 indicates reserved) */ static const unsigned char dma_channel_table[4] = { 5, 6, 7, 0 }; -#if 0 /* Not currently used, head/sector mappings allowed by 14f */ +/* Head/sector mappings allowed by 14f */ static const struct { unsigned char heads; unsigned char sectors; } mapping_table[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 0, 0 } }; -#endif /* Config info */ static struct config config; @@ -114,8 +145,7 @@ static int host_number; #ifdef PORT_OVERRIDE # define PORT_ADDRESS PORT_OVERRIDE #else -static unsigned short port_address = 0; -# define PORT_ADDRESS port_address +# define PORT_ADDRESS (config.port_address) #endif static volatile int aborted = 0; @@ -126,6 +156,10 @@ static const unsigned short ultrastor_ports[] = { }; #endif +void ultrastor_interrupt(void); + +static void (*ultrastor_done)(int, int) = 0; + static const struct { const char *signature; size_t offset; @@ -138,75 +172,105 @@ int ultrastor_14f_detect(int hostnum) { size_t i; unsigned char in_byte; - const void *base_address; + struct config_1 config_1; + struct config_2 config_2; -#ifdef DEBUG - printk("ultrastor_14f_detect: called\n"); +#if (ULTRASTOR_DEBUG & UD_DETECT) + printk("US14F: detect: called\n"); #endif #ifndef PORT_OVERRIDE -/* ??? This is easy to implement, but I'm not sure how "friendly" it is to - go off and read random i/o ports. */ -# error Not implemented! + PORT_ADDRESS = 0; + for (i = 0; i < ARRAY_SIZE(ultrastor_ports); i++) { + PORT_ADDRESS = ultrastor_ports[i]; #endif - if (!PORT_ADDRESS) { -#ifdef DEBUG - printk("ultrastor_14f_detect: no port address found!\n"); +#if (ULTRASTOR_DEBUG & UD_DETECT) + printk("US14F: detect: testing port address %03X\n", PORT_ADDRESS); #endif - return FALSE; - } -#ifdef DEBUG - printk("ultrastor_14f_detect: port address = %X\n", PORT_ADDRESS); + in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 0)); + if (in_byte != US14F_PRODUCT_ID_0) { +#if (ULTRASTOR_DEBUG & UD_DETECT) +# ifdef PORT_OVERRIDE + printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte); +# else + printk("US14F: detect: no adapter at port %03X", PORT_ADDRESS); +# endif #endif - - in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 0)); - if (in_byte != US14F_PRODUCT_ID_0) { -#ifdef DEBUG - printk("ultrastor_14f_detect: unknown product ID 0 - %02X\n", in_byte); +#ifdef PORT_OVERRIDE + return FALSE; +#else + continue; #endif - return FALSE; - } - in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 1)); - /* Only upper nibble is defined for Product ID 1 */ - if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) { -#ifdef DEBUG - printk("ultrastor_14f_detect: unknown product ID 1 - %02X\n", in_byte); + } + in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 1)); + /* Only upper nibble is defined for Product ID 1 */ + if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) { +#if (ULTRASTOR_DEBUG & UD_DETECT) +# ifdef PORT_OVERRIDE + printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte); +# else + printk("US14F: detect: no adapter at port %03X", PORT_ADDRESS); +# endif +#endif +#ifdef PORT_OVERRIDE + return FALSE; +#else + continue; #endif + } +#ifndef PORT_OVERRIDE + break; + } + if (i == ARRAY_SIZE(ultrastor_ports)) { +# if (ULTRASTOR_DEBUG & UD_DETECT) + printk("US14F: detect: no port address found!\n"); +# endif return FALSE; } +#endif + +#if (ULTRASTOR_DEBUG & UD_DETECT) + printk("US14F: detect: adapter found at port address %03X\n", + PORT_ADDRESS); +#endif /* All above tests passed, must be the right thing. Get some useful info. */ - *(char *)&config.config_1 = inb(CONFIG(PORT_ADDRESS + 0)); - *(char *)&config.config_2 = inb(CONFIG(PORT_ADDRESS + 1)); + *(char *)&config_1 = inb(CONFIG(PORT_ADDRESS + 0)); + *(char *)&config_2 = inb(CONFIG(PORT_ADDRESS + 1)); + config.bios_segment = bios_segment_table[config_1.bios_segment]; + config.interrupt = interrupt_table[config_1.interrupt]; + config.dma_channel = dma_channel_table[config_1.dma_channel]; + config.ha_scsi_id = config_2.ha_scsi_id; + config.heads = mapping_table[config_2.mapping_mode].heads; + config.sectors = mapping_table[config_2.mapping_mode].sectors; + config.bios_drive_number = config_2.bios_drive_number; /* To verify this card, we simply look for the UltraStor SCSI from the BIOS version notice. */ - base_address = bios_segment_table[config.config_1.bios_segment]; - if (base_address != NULL) { + if (config.bios_segment != NULL) { int found = 0; for (i = 0; !found && i < ARRAY_SIZE(signatures); i++) - if (memcmp((char *)base_address + signatures[i].offset, + if (memcmp((char *)config.bios_segment + signatures[i].offset, signatures[i].signature, signatures[i].length)) found = 1; if (!found) - base_address = NULL; + config.bios_segment = NULL; } - if (!base_address) { -#ifdef DEBUG - printk("ultrastor_14f_detect: not detected.\n"); + if (!config.bios_segment) { +#if (ULTRASTOR_DEBUG & UD_DETECT) + printk("US14F: detect: not detected.\n"); #endif return FALSE; } /* Final consistancy check, verify previous info. */ - if (!dma_channel_table[config.config_1.dma_channel] - || !(config.config_2.tfr_port & 0x2)) { -#ifdef DEBUG - printk("ultrastor_14f_detect: consistancy check failed\n"); + if (!config.dma_channel || !(config_2.tfr_port & 0x2)) { +#if (ULTRASTOR_DEBUG & UD_DETECT) + printk("US14F: detect: consistancy check failed\n"); #endif return FALSE; } @@ -216,18 +280,25 @@ int ultrastor_14f_detect(int hostnum) exhausted! */ /* Finally! Now I'm satisfied... */ -#ifdef DEBUG - printk("ultrastor_14f_detect: detect succeeded\n" +#if (ULTRASTOR_DEBUG & UD_DETECT) + printk("US14F: detect: detect succeeded\n" + " Port address: %03X\n" " BIOS segment: %05X\n" - " Interrupt: %d\n" - " DMA channel: %d\n" - " H/A SCSI ID: %d\n", - base_address, interrupt_table[config.config_1.interrupt], - dma_channel_table[config.config_1.dma_channel], - config.config_2.ha_scsi_id); + " Interrupt: %u\n" + " DMA channel: %u\n" + " H/A SCSI ID: %u\n", + PORT_ADDRESS, config.bios_segment, config.interrupt, + config.dma_channel, config.ha_scsi_id); #endif host_number = hostnum; - scsi_hosts[hostnum].this_id = config.config_2.ha_scsi_id; + 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); +#endif return TRUE; } @@ -238,64 +309,86 @@ const char *ultrastor_14f_info(void) " by David B. Gentzel\n"; } -#if 0 +static struct mscp mscp = { + OP_SCSI, DTD_SCSI, FALSE, TRUE, FALSE /* This stuff doesn't change */ +}; + int ultrastor_14f_queuecommand(unsigned char target, const void *cmnd, void *buff, int bufflen, void (*done)(int, int)) -#else -int ultrastor_14f_command(unsigned char target, const void *cmnd, - void *buff, int bufflen) -#endif { - struct mscp mscp = { - OP_SCSI, DTD_SCSI, FALSE, TRUE, FALSE, - target, 0, 0 /* LUN??? */, - *(Longword *)&buff, - *(Longword *)&bufflen, - { 0, 0, 0, 0 }, - 0, - 0, - 0, - ((*(char *)cmnd <= 0x1F) ? 6 : 10), - { 0 }, /* Filled in via memcpy below */ - 0, - 0, - { 0, 0, 0, 0 } - }; unsigned char in_byte; +#if (ULTRASTOR_DEBUG & UD_COMMAND) + printk("US14F: queuecommand: called\n"); +#endif + + /* Skip first (constant) byte */ + memset((char *)&mscp + 1, 0, sizeof (struct mscp) - 1); + mscp.target_id = target; + /* mscp.lun = ???; */ + mscp.transfer_data = *(Longword *)&buff; + mscp.transfer_data_length = *(Longword *)&bufflen, + mscp.length_of_scsi_cdbs = ((*(unsigned char *)cmnd <= 0x1F) ? 6 : 10); memcpy(mscp.scsi_cdbs, cmnd, mscp.length_of_scsi_cdbs); /* Find free OGM slot (OGMINT bit is 0) */ do - in_byte = inb(LCL_DOORBELL_INTR(PORT_ADDRESS)); + in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS)); while (!aborted && (in_byte & 1)); if (aborted) /* ??? is this right? */ return (aborted << 16); /* Store pointer in OGM address bytes */ - outb(BYTE(&mscp, 0), OGM_DATA_PTR(PORT_ADDRESS + 0)); - outb(BYTE(&mscp, 1), OGM_DATA_PTR(PORT_ADDRESS + 1)); - outb(BYTE(&mscp, 2), OGM_DATA_PTR(PORT_ADDRESS + 2)); - outb(BYTE(&mscp, 3), OGM_DATA_PTR(PORT_ADDRESS + 3)); + outb_p(BYTE(&mscp, 0), OGM_DATA_PTR(PORT_ADDRESS + 0)); + outb_p(BYTE(&mscp, 1), OGM_DATA_PTR(PORT_ADDRESS + 1)); + outb_p(BYTE(&mscp, 2), OGM_DATA_PTR(PORT_ADDRESS + 2)); + outb_p(BYTE(&mscp, 3), OGM_DATA_PTR(PORT_ADDRESS + 3)); /* Issue OGM interrupt */ - outb(0x1, LCL_DOORBELL_INTR(PORT_ADDRESS)); + outb_p(0x1, LCL_DOORBELL_INTR(PORT_ADDRESS)); + + ultrastor_done = done; + +#if (ULTRASTOR_DEBUG & UD_COMMAND) + printk("US14F: queuecommand: returning\n"); +#endif + + return 0; +} + +#if !USE_QUEUECOMMAND +int ultrastor_14f_command(unsigned char target, const void *cmnd, + void *buff, int bufflen) +{ + unsigned char in_byte; + +#if (ULTRASTOR_DEBUG & UD_COMMAND) + printk("US14F: command: called\n"); +#endif + + (void)ultrastor_14f_queuecommand(target, cmnd, buff, bufflen, 0); /* Wait for ICM interrupt */ do - in_byte = inb(SYS_DOORBELL_INTR(PORT_ADDRESS)); + in_byte = inb_p(SYS_DOORBELL_INTR(PORT_ADDRESS)); while (!aborted && !(in_byte & 1)); if (aborted) /* ??? is this right? */ return (aborted << 16); /* Clean ICM slot (set ICMINT bit to 0) */ - outb(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS)); + outb_p(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS)); + +#if (ULTRASTOR_DEBUG & UD_COMMAND) + printk("US14F: command: returning %08X\n", + (mscp.adapter_status << 16) | mscp.target_status); +#endif /* ??? not right, but okay for now? */ return (mscp.adapter_status << 16) | mscp.target_status; } +#endif int ultrastor_14f_abort(int code) { @@ -307,23 +400,71 @@ int ultrastor_14f_reset(void) { unsigned char in_byte; -#ifdef DEBUG - printk("ultrastor_14f_reset: called\n"); +#if (ULTRASTOR_DEBUG & UD_RESET) + printk("US14F: reset: called\n"); #endif /* Issue SCSI BUS reset */ - outb(0x20, LCL_DOORBELL_INTR(PORT_ADDRESS)); + outb_p(0x20, LCL_DOORBELL_INTR(PORT_ADDRESS)); + /* Wait for completion... */ do - in_byte = inb(LCL_DOORBELL_INTR(PORT_ADDRESS)); + in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS)); while (in_byte & 0x20); aborted = DID_RESET; -#ifdef DEBUG - printk("ultrastor_14f_reset: returning\n"); +#if (ULTRASTOR_DEBUG & UD_RESET) + printk("US14F: reset: returning\n"); #endif return 0; } +#if USE_QUEUECOMMAND +void ultrastor_interrupt_service(void) +{ + if (ultrastor_done == 0) { + printk("US14F: unexpected ultrastor interrupt\n\r"); + /* ??? Anything else we should do here? Reset? */ + return; + } + printk("US14F: got an ultrastor interrupt: %u\n\r", + (mscp.adapter_status << 16) | mscp.target_status); + ultrastor_done(host_number, + (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/blk_drv/scsi/ultrastor.h b/kernel/blk_drv/scsi/ultrastor.h index 13ded23..dfe34ee 100644 --- a/kernel/blk_drv/scsi/ultrastor.h +++ b/kernel/blk_drv/scsi/ultrastor.h @@ -9,10 +9,6 @@ #ifndef _ULTRASTOR_H #define _ULTRASTOR_H -/* ??? Some of the stuff in this file is really private to ultrastor.c and - should be moved elsewhere (as this file is included by higher-level driver - files). */ - /* ??? These don't really belong here */ #ifndef TRUE # define TRUE 1 @@ -21,32 +17,40 @@ # define FALSE 0 #endif +/* ??? This should go eventually, once the queueing bug is fixed */ +#define USE_QUEUECOMMAND FALSE + int ultrastor_14f_detect(int); const char *ultrastor_14f_info(void); -#if 0 /* ??? Future direction... */ int ultrastor_14f_queuecommand(unsigned char target, const void *cmnd, void *buff, int bufflen, void (*done)(int, int)); -#else +#if !USE_QUEUECOMMAND int ultrastor_14f_command(unsigned char target, const void *cmnd, void *buff, int bufflen); #endif int ultrastor_14f_abort(int); int ultrastor_14f_reset(void); -#if 0 /* ??? Future direction... */ -# define ULTRASTOR_14F \ - { "UltraStor 14F", ultrastor_14f_detect, ultrastor_14f_info, 0, \ - ultrastor_14f_queuecommand, ultrastor_14f_abort, ultrastor_14f_reset, \ - TRUE, 0, 0 } -#else -# define ULTRASTOR_14F \ +#if !USE_QUEUECOMMAND +#define ULTRASTOR_14F \ { "UltraStor 14F", ultrastor_14f_detect, ultrastor_14f_info, \ ultrastor_14f_command, 0, ultrastor_14f_abort, ultrastor_14f_reset, \ FALSE, 0, 0 } +#else +#define ULTRASTOR_14F \ + { "UltraStor 14F", ultrastor_14f_detect, ultrastor_14f_info, 0, \ + ultrastor_14f_queuecommand, ultrastor_14f_abort, ultrastor_14f_reset, \ + TRUE, 0, 0 } #endif -#define PORT_OVERRIDE 0x330 +#define UD_DETECT 0x1 +#define UD_COMMAND 0x2 +#define UD_RESET 0x4 + +#ifdef ULTRASTOR_PRIVATE + +/* #define PORT_OVERRIDE 0x330 */ /* Port addresses (relative to the base address) */ #define LCL_DOORBELL_MASK(port) ((port) + 0x0) @@ -82,3 +86,5 @@ int ultrastor_14f_reset(void); #define HA_CMD_WRITE_BUFF 0x4 #endif + +#endif diff --git a/kernel/chr_drv/console.c b/kernel/chr_drv/console.c index 8709a22..746692c 100644 --- a/kernel/chr_drv/console.c +++ b/kernel/chr_drv/console.c @@ -883,6 +883,8 @@ void con_init(void) char *display_ptr; int currcons = 0; long base; + int orig_x = ORIG_X; + int orig_y = ORIG_Y; video_num_columns = ORIG_VIDEO_COLS; video_size_row = video_num_columns * 2; @@ -975,7 +977,7 @@ void con_init(void) vt_cons[0].vt_mode = KD_TEXT; vc_cons[0].vc_bold_attr = -1; - gotoxy(currcons,ORIG_X,ORIG_Y); + gotoxy(currcons,orig_x,orig_y); for (currcons = 1; currcons<NR_CONSOLES; currcons++) { vc_cons[currcons] = vc_cons[0]; vt_cons[currcons] = vt_cons[0]; diff --git a/kernel/chr_drv/keyboard.c b/kernel/chr_drv/keyboard.c index 1398059..82f711d 100644 --- a/kernel/chr_drv/keyboard.c +++ b/kernel/chr_drv/keyboard.c @@ -1012,7 +1012,7 @@ void kb_ack(void) int i; for(i=0; i<0x10000; i++) - if (inb(0x64) == 0xfa) + if (inb(0x60) == 0xfa) break; } diff --git a/kernel/chr_drv/tty_io.c b/kernel/chr_drv/tty_io.c index 413ee86..e5cb171 100644 --- a/kernel/chr_drv/tty_io.c +++ b/kernel/chr_drv/tty_io.c @@ -25,6 +25,9 @@ #include <asm/segment.h> #include <asm/system.h> +#include <sys/kd.h> +#include "vt_kern.h" + #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif @@ -65,6 +68,8 @@ struct tty_queue * table_list[]={ void change_console(unsigned int new_console) { + if (vt_cons[fg_console].vt_mode == KD_GRAPHICS) + return; if (new_console == fg_console || new_console >= NR_CONSOLES) return; table_list[0] = con_queues + 0 + new_console*3; @@ -124,9 +129,14 @@ void copy_to_cooked(struct tty_struct * tty) ((EOF_CHAR(tty) != _POSIX_VDISABLE) && (c==EOF_CHAR(tty))))) { if (L_ECHO(tty)) { - if (c<32) - PUTCH(127,tty->write_q); - PUTCH(127,tty->write_q); + if (c<32) { + PUTCH(8,tty->write_q); + PUTCH(' ',tty->write_q); + PUTCH(8,tty->write_q); + } + PUTCH(8,tty->write_q); + PUTCH(' ',tty->write_q); + PUTCH(8,tty->write_q); TTY_WRITE_FLUSH(tty); } DEC(tty->secondary->head); @@ -141,9 +151,14 @@ void copy_to_cooked(struct tty_struct * tty) (c==EOF_CHAR(tty)))) continue; if (L_ECHO(tty)) { - if (c<32) - PUTCH(127,tty->write_q); - PUTCH(127,tty->write_q); + if (c<32) { + PUTCH(8,tty->write_q); + PUTCH(' ',tty->write_q); + PUTCH(8,tty->write_q); + } + PUTCH(8,tty->write_q); + PUTCH(32,tty->write_q); + PUTCH(8,tty->write_q); TTY_WRITE_FLUSH(tty); } DEC(tty->secondary->head); diff --git a/kernel/fork.c b/kernel/fork.c index 8a0dbe8..784cbad 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -116,7 +116,8 @@ int sys_fork(long ebx,long ecx,long edx, current->p_cptr = p; p->counter = p->priority; p->signal = 0; - p->alarm = 0; + p->it_real_value = p->it_virt_value = p->it_prof_value = 0; + p->it_real_incr = p->it_virt_incr = p->it_prof_incr = 0; p->leader = 0; /* process leadership doesn't inherit */ p->utime = p->stime = 0; p->cutime = p->cstime = 0; diff --git a/kernel/itimer.c b/kernel/itimer.c new file mode 100644 index 0000000..7362dc8 --- /dev/null +++ b/kernel/itimer.c @@ -0,0 +1,111 @@ +/* + * linux/kernel/itimer.c + * + * (C) 1992 Darren Senn + */ + +/* These are all the functions necessary to implement itimers */ + +#include <linux/sched.h> +#include <asm/segment.h> + +#include <signal.h> +#include <sys/time.h> +#include <errno.h> + +static unsigned long tvtojiffies(struct timeval *value) +{ + return((unsigned long )value->tv_sec * HZ + + (unsigned long )value->tv_usec / (1000000 / HZ)); +} + +static void jiffiestotv(unsigned long jiffies, struct timeval *value) +{ + value->tv_usec = (jiffies % HZ) * (1000000 / HZ); + value->tv_sec = jiffies / HZ; + return; +} + +int _getitimer(int which, struct itimerval *value) +{ + register unsigned long val, interval; + + switch (which) { + case ITIMER_REAL: + val = current->it_real_value; + interval = current->it_real_incr; + break; + case ITIMER_VIRTUAL: + val = current->it_virt_value; + interval = current->it_virt_incr; + break; + case ITIMER_PROF: + val = current->it_prof_value; + interval = current->it_prof_incr; + break; + default: + return(-EINVAL); + } + jiffiestotv(val, &value->it_value); + jiffiestotv(interval, &value->it_interval); + return(0); +} + +int sys_getitimer(int which, struct itimerval *value) +{ + struct itimerval get_buffer; + int k; + + if (!value) + return -EFAULT; + k = _getitimer(which, &get_buffer); + if (k < 0) + return k; + verify_area(value, sizeof(struct itimerval)); + memcpy_tofs(value, &get_buffer, sizeof(get_buffer)); + return 0; +} + +int _setitimer(int which, struct itimerval *value, struct itimerval *ovalue) +{ + register unsigned long i, j; + int k; + + i = tvtojiffies(&value->it_interval); + j = tvtojiffies(&value->it_value); + if (ovalue && (k = _getitimer(which, ovalue)) < 0) + return k; + switch (which) { + case ITIMER_REAL: + current->it_real_value = j; + current->it_real_incr = i; + break; + case ITIMER_VIRTUAL: + current->it_virt_value = j; + current->it_virt_incr = i; + break; + case ITIMER_PROF: + current->it_prof_value = j; + current->it_prof_incr = i; + break; + default: + return -EINVAL; + } + return 0; +} + +int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) +{ + struct itimerval set_buffer, get_buffer; + int k; + + if (!value) + return -EFAULT; + memcpy_fromfs(&set_buffer, value, sizeof(set_buffer)); + k = _setitimer(which, &set_buffer, ovalue ? &get_buffer : 0); + if (k < 0 || !ovalue) + return k; + verify_area(ovalue, sizeof(struct itimerval)); + memcpy_tofs(ovalue, &get_buffer, sizeof(get_buffer)); + return 0; +} diff --git a/kernel/math/ea.c b/kernel/math/ea.c index 85a1131..c4a219b 100644 --- a/kernel/math/ea.c +++ b/kernel/math/ea.c @@ -58,7 +58,7 @@ static char * sib(struct info * info, int mod) char * ea(struct info * info, unsigned short code) { unsigned char mod,rm; - long * tmp = &EAX; + long * tmp; int offset = 0; mod = (code >> 6) & 3; diff --git a/kernel/sched.c b/kernel/sched.c index 01d04a9..2d960bb 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -18,6 +18,7 @@ #include <asm/system.h> #include <asm/io.h> #include <asm/segment.h> +#include <sys/time.h> #include <signal.h> #include <errno.h> @@ -68,7 +69,7 @@ union task_union { char stack[PAGE_SIZE]; }; -static union task_union init_task = {INIT_TASK,}; +static union task_union init_task = {INIT_TASK, }; unsigned long volatile jiffies=0; unsigned long startup_time=0; @@ -134,10 +135,6 @@ void schedule(void) (*p)->timeout = 0; (*p)->state = TASK_RUNNING; } - if ((*p)->alarm && (*p)->alarm < jiffies) { - (*p)->signal |= (1<<(SIGALRM-1)); - (*p)->alarm = 0; - } if (((*p)->signal & ~(*p)->blocked) && (*p)->state==TASK_INTERRUPTIBLE) (*p)->state=TASK_RUNNING; @@ -352,7 +349,7 @@ static unsigned long cexp[3] = { 2014, /* 0.9834714538216174 * FSCALE, exp(-1/60) */ 2037, /* 0.9944598480048967 * FSCALE, exp(-1/180) */ }; -unsigned long averunnable[3]; /* fixed point numbers */ +unsigned long averunnable[3] = { 0, }; /* fixed point numbers */ void update_avg(void) { @@ -376,7 +373,8 @@ void do_timer(long cpl) { unsigned long mask; struct timer_struct *tp = timer_table+0; - static int avg_cnt; + struct task_struct ** task_p; + static int avg_cnt = 0; for (mask = 1 ; mask ; tp++,mask += mask) { if (mask > timer_active) @@ -390,6 +388,25 @@ void do_timer(long cpl) sti(); } + /* 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 + && !(--(*task_p)->it_real_value)) { + (*task_p)->signal |= (1<<(SIGALRM-1)); + (*task_p)->it_real_value = (*task_p)->it_real_incr; + need_resched = 1; + } + /* Update ITIMER_PROF for the current task */ + if (current->it_prof_value && !(--current->it_prof_value)) { + current->it_prof_value = current->it_prof_incr; + current->signal |= (1<<(SIGPROF-1)); + } + /* Update ITIMER_VIRT for current task if not in a system call */ + if (cpl && current->it_virt_value && !(--current->it_virt_value)) { + current->it_virt_value = current->it_virt_incr; + current->signal |= (1<<(SIGVTALRM-1)); + } + if (cpl) current->utime++; else @@ -420,12 +437,14 @@ void do_timer(long cpl) int sys_alarm(long seconds) { - int old = current->alarm; - - if (old) - old = (old - jiffies) / HZ; - current->alarm = (seconds>0)?(jiffies+HZ*seconds):0; - return (old); + extern int _setitimer(int, struct itimerval *, struct itimerval *); + struct itimerval new, old; + + new.it_interval.tv_sec = new.it_interval.tv_usec = 0; + new.it_value.tv_sec = seconds; + new.it_value.tv_usec = 0; + _setitimer(ITIMER_REAL, &new, &old); + return(old.it_value.tv_sec + (old.it_value.tv_usec / 1000000)); } int sys_getpid(void) diff --git a/kernel/signal.c b/kernel/signal.c index d1d5afd..77dd96d 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -10,8 +10,11 @@ #include <signal.h> #include <sys/wait.h> +#include <sys/ptrace.h> #include <errno.h> +extern int core_dump(long signr,struct pt_regs * regs); + int sys_sgetmask() { return current->blocked; @@ -117,44 +120,29 @@ int sys_sigaction(int signum, const struct sigaction * action, return 0; } -/* - * Routine writes a core dump image in the current directory. - * Currently not implemented. - */ -int core_dump(long signr) -{ - return(0); /* We didn't do a dump */ -} - extern int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); -int do_signal(long signr,long ebx, long ecx, long edx, - long esi, long edi, long ebp, long eax, - long ds, long es, long fs, long gs, - long orig_eax, - long eip, long cs, long eflags, - unsigned long * esp, long ss) +int do_signal(long signr,struct pt_regs * regs) { unsigned long sa_handler; - long old_eip=eip; + long old_eip = regs->eip; struct sigaction * sa = current->sigaction + signr - 1; int longs; - unsigned long * tmp_esp; #ifdef notdef printk("pid: %d, signr: %x, eax=%d, oeax = %d, int=%d\n", - current->pid, signr, eax, orig_eax, + current->pid, signr, regs->eax, regs->orig_eax, sa->sa_flags & SA_INTERRUPT); #endif - if ((orig_eax != -1) && - ((eax == -ERESTARTSYS) || (eax == -ERESTARTNOINTR))) { - if ((eax == -ERESTARTSYS) && ((sa->sa_flags & SA_INTERRUPT) || + if ((regs->orig_eax != -1) && + ((regs->eax == -ERESTARTSYS) || (regs->eax == -ERESTARTNOINTR))) { + if ((regs->eax == -ERESTARTSYS) && ((sa->sa_flags & SA_INTERRUPT) || signr < SIGCONT || signr > SIGTTOU)) - *(&eax) = -EINTR; + regs->eax = -EINTR; else { - *(&eax) = orig_eax; - *(&eip) = old_eip -= 2; + regs->eax = regs->orig_eax; + regs->eip = old_eip -= 2; } } sa_handler = (unsigned long) sa->sa_handler; @@ -191,7 +179,7 @@ int do_signal(long signr,long ebx, long ecx, long edx, case SIGIOT: case SIGFPE: case SIGSEGV: - if (core_dump(signr)) + if (core_dump(signr,regs)) do_exit(signr|0x80); /* fall through */ default: @@ -203,19 +191,19 @@ int do_signal(long signr,long ebx, long ecx, long edx, */ if (sa->sa_flags & SA_ONESHOT) sa->sa_handler = NULL; - *(&eip) = sa_handler; - longs = (sa->sa_flags & SA_NOMASK)?7:8; - *(&esp) -= longs; - verify_area(esp,longs*4); - tmp_esp=esp; + regs->eip = sa_handler; + longs = (sa->sa_flags & SA_NOMASK)?(7*4):(8*4); + regs->esp -= longs; + tmp_esp = (unsigned long *) regs->esp; + verify_area(tmp_esp,longs); put_fs_long((long) sa->sa_restorer,tmp_esp++); put_fs_long(signr,tmp_esp++); if (!(sa->sa_flags & SA_NOMASK)) put_fs_long(current->blocked,tmp_esp++); - put_fs_long(eax,tmp_esp++); - put_fs_long(ecx,tmp_esp++); - put_fs_long(edx,tmp_esp++); - put_fs_long(eflags,tmp_esp++); + put_fs_long(regs->eax,tmp_esp++); + put_fs_long(regs->ecx,tmp_esp++); + put_fs_long(regs->edx,tmp_esp++); + put_fs_long(regs->eflags,tmp_esp++); put_fs_long(old_eip,tmp_esp++); current->blocked |= sa->sa_mask; /* force a supervisor-mode page-in of the signal handler to reduce races */ diff --git a/kernel/sys.c b/kernel/sys.c index 2318a7e..75a86ba 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -180,14 +180,14 @@ void ctrl_alt_del(void) */ int sys_setregid(int rgid, int egid) { - if (rgid>0) { + if (rgid >= 0) { if ((current->gid == rgid) || suser()) current->gid = rgid; else return(-EPERM); } - if (egid>0) { + if (egid >= 0) { if ((current->gid == egid) || (current->egid == egid) || suser()) { @@ -267,17 +267,17 @@ int sys_setreuid(int ruid, int euid) { int old_ruid = current->uid; - if (ruid>0) { + if (ruid >= 0) { if ((current->euid==ruid) || - (old_ruid == ruid) || + (old_ruid == ruid) || suser()) current->uid = ruid; else return(-EPERM); } - if (euid>0) { + if (euid >= 0) { if ((old_ruid == euid) || - (current->euid == euid) || + (current->euid == euid) || suser()) { current->euid = euid; current->suid = euid; diff --git a/kernel/sys_call.S b/kernel/sys_call.S index ad70318..41014da 100644 --- a/kernel/sys_call.S +++ b/kernel/sys_call.S @@ -187,10 +187,13 @@ ret_from_sys_call: je 2f btrl %ecx,%ebx movl %ebx,signal(%eax) + movl %esp,%ebx + pushl %ebx incl %ecx pushl %ecx call _do_signal popl %ecx + popl %ebx testl %eax, %eax jne 1b # see if we need to switch tasks, or do more signals 2: popl %ebx diff --git a/lib/Makefile b/lib/Makefile index 94b649f..e58abc0 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -23,7 +23,7 @@ CPP =gcc -E -nostdinc -I../include -c -o $*.o $< 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 + execve.o wait.o string.o malloc.o itimer.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff --git a/tools/build.c b/tools/build.c index 1fa477b..e3a8a73 100644 --- a/tools/build.c +++ b/tools/build.c @@ -81,7 +81,7 @@ int main(int argc, char ** argv) } fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); if ((major_root != 2) && (major_root != 3) && - (major_root != 0)) { + (major_root != 8) && (major_root != 0)) { fprintf(stderr, "Illegal root device (major = %d)\n", major_root); die("Bad root device --- major #"); |