Commit 24c9da66 authored by Linus Torvalds's avatar Linus Torvalds

Second patch to 0.96a

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
parent 5b58d8fe
......@@ -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>
......@@ -39,6 +41,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(&current->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 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
}
}
/* 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 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
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 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
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);
......
/*
* 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);
}
/*
* 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];
......
/*
* linux/fs/chrdev.c
* linux/fs/minix/chrdev.c
*
* (C) 1991 Linus Torvalds
*/
......
/*
* 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>
......
/*
* 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;
}
......@@ -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;
......
/*
* 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;
......
......@@ -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;
......
......@@ -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 {
......
......@@ -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);
......
......@@ -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}, \
......
......@@ -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);
......@@ -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) \
......
......@@ -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
......
......@@ -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>
......
......@@ -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)
......
......@@ -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
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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);
......
/*
* 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
......@@ -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
......@@ -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];
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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;
......
/*
* 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;
}
......@@ -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;
......
......@@ -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)
......
......@@ -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 */
......
......@@ -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;
......
......@@ -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
......
......@@ -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)
......
......@@ -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 #");
......
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