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
#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>
*/
#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.
}
}
/* OK, This is the point of no return */
+ current->dumpable = 1;
for (i=0; (ch = get_fs_byte(filename++)) != '\0';)
if (ch == '/')
i = 0;
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;
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
*/
:"=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;
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;
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
*/
{
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>
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;
}
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/system.h>
+#include <asm/segment.h>
int sync_dev(int dev);
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);
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;
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>
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;
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)
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;
}
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;
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));
}
{
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;
#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.)
} 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 */
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 {
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);
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);
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];
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;
#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}, \
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,
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);
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) \
#define SIGPOLL SIGIO
#define SIGXCPU 24
#define SIGXFSZ 25
+*/
+
#define SIGVTALRM 26
#define SIGPROF 27
-*/
#define SIGWINCH 28
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>
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)
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
/*
* 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>
{
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);
#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>
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;
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
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)
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();
}
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;
}
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>
#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
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
/* 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;
#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;
};
#endif
+void ultrastor_interrupt(void);
+
+static void (*ultrastor_done)(int, int) = 0;
+
static const struct {
const char *signature;
size_t offset;
{
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;
}
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;
}
" 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)
{
{
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
#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
# 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)
#define HA_CMD_WRITE_BUFF 0x4
#endif
+
+#endif
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;
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];
int i;
for(i=0; i<0x10000; i++)
- if (inb(0x64) == 0xfa)
+ if (inb(0x60) == 0xfa)
break;
}
#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
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;
((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);
(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);
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;
--- /dev/null
+/*
+ * 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;
+}
char * ea(struct info * info, unsigned short code)
{
unsigned char mod,rm;
- long * tmp = &EAX;
+ long * tmp;
int offset = 0;
mod = (code >> 6) & 3;
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
+#include <sys/time.h>
#include <signal.h>
#include <errno.h>
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;
(*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;
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)
{
{
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)
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
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)
#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;
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;
case SIGIOT:
case SIGFPE:
case SIGSEGV:
- if (core_dump(signr))
+ if (core_dump(signr,regs))
do_exit(signr|0x80);
/* fall through */
default:
*/
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 */
*/
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()) {
{
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;
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
-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)
}
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 #");