Commit 3820d961 authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.98.4 (November 9, 1992)

Rename "malloc()/free()" as "kmalloc()/kfree()" to make people more
aware of some of the limitations.

Math emulator updates to handle the case that Linux (unlike the original
djgpp target) can get preempted by user space accesses.

Make "ll_rw_blk()" take an array of blocks to read/write.

VFS "notify_change()" callback, to allow the low-level filesystem to
decide what it wants to do about metadata changes.

Deprecate old "stat()" call by printing out a warning on use.

NR_OPEN is now 256 files per process, and the old "unsigned long" bitops
needed to go away. This causes lots of syntactic changes in select().

System call tracing implemented for ptrace().

[Original announcement below]

 - the inode caching bug (resulting in bad filesystem info when
   mounting/umounting devices) should be gone for good.

 - an elusive race-condition in the fs is fixed: this may have been the
   reason some people got fsck errors once in a while.  The
   race-condition was pretty hard to find, and depends on a lot of
   things (buffer cache size, speed of the disk and computer speed).

 - fpu emulator patches (mainly for the re-entrancy problem) by me and
   W. Metzenthen.

 - various wait-queue changes - the kernel uses the waiting mechanism
   more efficiently now.

 - the NFS client support code is there: the actual nfs code is still in
   alpha (although reported to be pretty stable) and has to be gotten
   separately.

 - NR_OPEN was changed from 32 to 256 (which is what SunOS seems to use,
   so I hope it won't need any further changes).  This has lead to some
   incompatibilities (GNU emacs and the term program seem to need
   recompilation to work correctly), as the 'select()' system call has a
   slightly changed interface due to the new fd_set definition.

 - the process kernel stack is now on a separate page (needed due to the
   fact that the task_struct has now grown to almost 3kB due to the
   NR_OPEN changes).  This also means 'ps' needs patches..  My patches
   to ps-0.98 are available as 'ps-diff.Z' in the same directory as the
   kernel sources and diffs.

 - various other changes: system call tracing by Ross Biro. Changed
   ll_rw_block interface (performance reasons: it will eventually be
   changed to accept several requests at once).  Malloc() was changed
   and renamed to kmalloc() due to the new interface.  Some tcp/ip
   patches (inode counting correction and some other changes).

0.98.4 should hopefully be pretty stable: the main problem areas are
probably still tcp/ip and some of the tty code.  I'd appreciate
comments, bug-reports etc.

                Linus
parent c6af1a5c
......@@ -78,7 +78,7 @@ SVGA_MODE= -DSVGA_MODE=1
# standard CFLAGS
#
CFLAGS =-Wall -O6 -fomit-frame-pointer $(LIMIT_MEMORY)
CFLAGS = -Wall -O6 -fomit-frame-pointer $(LIMIT_MEMORY)
#
# if you want the ram-disk device, define this to be the
......@@ -99,7 +99,7 @@ CPP =$(CC) -E $(LIMIT_MEMORY)
AR =ar
ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o net/net.o
FILESYSTEMS =fs/minix/minix.o fs/ext/ext.o fs/msdos/msdos.o fs/proc/proc.o
FILESYSTEMS =fs/filesystems.a
DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a \
kernel/blk_drv/scsi/scsi.a
MATH =kernel/FPU-emu/math.a
......@@ -127,7 +127,7 @@ linuxsubdirs: dummy
Version:
@./makever.sh
@echo \#define UTS_RELEASE \"0.98.pl3-`cat .version`\" > tools/version.h
@echo \#define UTS_RELEASE \"0.98.pl4-`cat .version`\" > tools/version.h
@echo \#define UTS_VERSION \"`date +%D`\" >> tools/version.h
@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
......@@ -218,4 +218,5 @@ init/main.o : init/main.c /usr/lib/gcc-lib/i386-linux/2.2.2d/include/stdarg.h /u
/usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h \
/usr/include/linux/kernel.h /usr/include/linux/signal.h /usr/include/linux/time.h \
/usr/include/linux/param.h /usr/include/linux/resource.h /usr/include/linux/vm86.h \
/usr/include/linux/tty.h /usr/include/linux/termios.h /usr/include/linux/unistd.h
/usr/include/linux/math_emu.h /usr/include/linux/tty.h /usr/include/linux/termios.h \
/usr/include/linux/unistd.h /usr/include/linux/string.h
......@@ -69,7 +69,24 @@ startup_32:
orl $0x10022,%eax # set NE and MP
2: movl %eax,%cr0
call check_x87
jmp after_page_tables
call setup_paging
lgdt gdt_descr
lidt idt_descr
ljmp $0x08,$1f
1: movl $0x10,%eax # reload all the segment registers
mov %ax,%ds # after changing gdt.
mov %ax,%es
mov %ax,%fs
mov %ax,%gs
lss _stack_start,%esp
pushl $0 # These are the parameters to main :-)
pushl $0
pushl $0
cld # gcc2 wants the direction flag cleared at all times
call _start_kernel
L6:
jmp L6 # main should never return here, but
# just in case, we know what happens.
/*
* We depend on ET to be correct. This checks for 287/387.
......@@ -116,6 +133,42 @@ rp_sidt:
jne rp_sidt
ret
/*
* Setup_paging
*
* This routine sets up paging by setting the page bit
* in cr0. The page tables are set up, identity-mapping
* the first 4MB. The rest are initialized later.
*
* (ref: added support for up to 32mb, 17Apr92) -- Rik Faith
* (ref: update, 25Sept92) -- croutons@crunchy.uucp
* (ref: 92.10.11 - Linus Torvalds. Corrected 16M limit - no upper memory limit)
*/
.align 2
setup_paging:
movl $1024*2,%ecx /* 2 pages - swapper_pg_dir+1 page table */
xorl %eax,%eax
movl $_swapper_pg_dir,%edi /* swapper_pg_dir is at 0x1000 */
cld;rep;stosl
/* Identity-map the kernel in low 4MB memory for ease of transition */
movl $_pg0+7,_swapper_pg_dir /* set present bit/user r/w */
/* But the real place is at 0xC0000000 */
movl $_pg0+7,_swapper_pg_dir+3072 /* set present bit/user r/w */
movl $_pg0+4092,%edi
movl $0x03ff007,%eax /* 4Mb - 4096 + 7 (r/w user,p) */
std
1: stosl /* fill the page backwards - more efficient :-) */
subl $0x1000,%eax
jge 1b
cld
movl $_swapper_pg_dir,%eax
movl %eax,%cr3 /* cr3 - page directory start */
movl %cr0,%eax
orl $0x80000000,%eax
movl %eax,%cr0 /* set paging (PG) bit */
ret /* this also flushes the prefetch-queue */
/*
* page 0 is made non-existent, so that kernel NULL pointer references get
* caught. Thus the swapper page directory has been moved to 0x1000
......@@ -152,26 +205,6 @@ _tmp_floppy_area:
_floppy_track_buffer:
.fill 512*2*18,1,0
after_page_tables:
call setup_paging
lgdt gdt_descr
lidt idt_descr
ljmp $0x08,$1f
1: movl $0x10,%eax # reload all the segment registers
mov %ax,%ds # after changing gdt.
mov %ax,%es
mov %ax,%fs
mov %ax,%gs
lss _stack_start,%esp
pushl $0 # These are the parameters to main :-)
pushl $0
pushl $0
cld # gcc2 wants the direction flag cleared at all times
call _start_kernel
L6:
jmp L6 # main should never return here, but
# just in case, we know what happens.
/* This is the default interrupt "handler" :-) */
int_msg:
.asciz "Unknown interrupt\n\r"
......@@ -199,58 +232,6 @@ ignore_int:
popl %eax
iret
/*
* Setup_paging
*
* This routine sets up paging by setting the page bit
* in cr0. The page tables are set up, identity-mapping
* the first 4MB. The rest are initialized later.
*
* NOTE! Although all physical memory should be identity
* mapped by this routine, only the kernel page functions
* use the >1Mb addresses directly. All "normal" functions
* use just the lower 1Mb, or the local data space, which
* will be mapped to some other place - mm keeps track of
* that.
*
* For those with more memory than 16 Mb - tough luck. I've
* not got it, why should you :-) The source is here. Change
* it. (Seriously - it shouldn't be too difficult. Mostly
* change some constants etc. I left it at 16Mb, as my machine
* even cannot be extended past that (ok, but it was cheap :-)
* I've tried to show which constants to change by having
* some kind of marker at them (search for "16Mb"), but I
* won't guarantee that's all :-( )
*
* (ref: added support for up to 32mb, 17Apr92) -- Rik Faith
* (ref: update, 25Sept92) -- croutons@crunchy.uucp
* (ref: 92.10.11 - Linus Torvalds. Corrected 16M limit - no upper memory limit)
*/
.align 2
setup_paging:
movl $1024*2,%ecx /* 2 pages - swapper_pg_dir+1 page table */
xorl %eax,%eax
movl $_swapper_pg_dir,%edi /* swapper_pg_dir is at 0x1000 */
cld;rep;stosl
/* Identity-map the kernel in low 4MB memory for ease of transition */
movl $_pg0+7,_swapper_pg_dir /* set present bit/user r/w */
/* But the real place is at 0xC0000000 */
movl $_pg0+7,_swapper_pg_dir+3072 /* set present bit/user r/w */
movl $_pg0+4092,%edi
movl $0x03ff007,%eax /* 4Mb - 4096 + 7 (r/w user,p) */
std
1: stosl /* fill the page backwards - more efficient :-) */
subl $0x1000,%eax
jge 1b
cld
movl $_swapper_pg_dir,%eax
movl %eax,%cr3 /* cr3 - page directory start */
movl %cr0,%eax
orl $0x80000000,%eax
movl %eax,%cr0 /* set paging (PG) bit */
ret /* this also flushes the prefetch-queue */
/*
* The interrupt descriptor table has room for 256 idt's
*/
......
This diff is collapsed.
......@@ -56,14 +56,16 @@ int nr_buffer_heads = 0;
*/
void __wait_on_buffer(struct buffer_head * bh)
{
add_wait_queue(&bh->b_wait,&current->wait);
struct wait_queue wait = { current, NULL };
add_wait_queue(&bh->b_wait, &wait);
repeat:
current->state = TASK_UNINTERRUPTIBLE;
if (bh->b_lock) {
schedule();
goto repeat;
}
remove_wait_queue(&bh->b_wait,&current->wait);
remove_wait_queue(&bh->b_wait, &wait);
current->state = TASK_RUNNING;
}
......@@ -78,7 +80,7 @@ static void sync_buffers(dev_t dev)
continue;
if (!bh->b_dirt)
continue;
ll_rw_block(WRITE,bh);
ll_rw_block(WRITE, 1, &bh);
}
}
......@@ -325,7 +327,7 @@ struct buffer_head * getblk(dev_t dev, int block, int size)
}
#if 0
if (tmp->b_dirt)
ll_rw_block(WRITEA,tmp);
ll_rw_block(WRITEA, 1, &tmp);
#endif
}
......@@ -386,7 +388,7 @@ struct buffer_head * bread(dev_t dev, int block, int size)
}
if (bh->b_uptodate)
return bh;
ll_rw_block(READ,bh);
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
if (bh->b_uptodate)
return bh;
......@@ -416,7 +418,7 @@ void bread_page(unsigned long address, dev_t dev, int b[4])
if (b[i]) {
if (bh[i] = getblk(dev, b[i], 1024))
if (!bh[i]->b_uptodate)
ll_rw_block(READ,bh[i]);
ll_rw_block(READ, 1, &bh[i]);
} else
bh[i] = NULL;
for (i=0 ; i<4 ; i++,address += BLOCK_SIZE)
......@@ -444,12 +446,12 @@ struct buffer_head * breada(dev_t dev,int first, ...)
return NULL;
}
if (!bh->b_uptodate)
ll_rw_block(READ,bh);
ll_rw_block(READ, 1, &bh);
while ((first=va_arg(args,int))>=0) {
tmp = getblk(dev, first, 1024);
if (tmp) {
if (!tmp->b_uptodate)
ll_rw_block(READA,tmp);
ll_rw_block(READA, 1, &tmp);
tmp->b_count--;
}
}
......@@ -461,9 +463,16 @@ struct buffer_head * breada(dev_t dev,int first, ...)
return (NULL);
}
/*
* See fs/inode.c for the weird use of volatile..
*/
static void put_unused_buffer_head(struct buffer_head * bh)
{
struct wait_queue * wait;
wait = ((volatile struct buffer_head *) bh)->b_wait;
memset((void *) bh,0,sizeof(*bh));
((volatile struct buffer_head *) bh)->b_wait = wait;
bh->b_next_free = unused_list;
unused_list = bh;
}
......@@ -620,7 +629,7 @@ int shrink_buffers(unsigned int priority)
else
wait_on_buffer(bh);
if (bh->b_dirt) {
ll_rw_block(WRITEA,bh);
ll_rw_block(WRITEA, 1, &bh);
continue;
}
if (try_to_free(bh))
......
......@@ -77,7 +77,8 @@ int core_dump(long signr, struct pt_regs * regs)
return 0;
current->dumpable = 0;
/* See if we have enough room to write the upage. */
if(current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE/1024) return 0;
if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE)
return 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,NULL)) {
......@@ -113,11 +114,11 @@ int core_dump(long signr, struct pt_regs * regs)
dump.u_ssize = ((unsigned long) (TASK_SIZE - dump.start_stack)) >> 12;
/* If the size of the dump file exceeds the rlimit, then see what would happen
if we wrote the stack, but not the data area. */
if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE/1024 >
if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE >
current->rlim[RLIMIT_CORE].rlim_cur)
dump.u_dsize = 0;
/* Make sure we have enough room to write the stack and data areas. */
if ((dump.u_ssize+1) * PAGE_SIZE / 1024 >
if ((dump.u_ssize+1) * PAGE_SIZE >
current->rlim[RLIMIT_CORE].rlim_cur)
dump.u_ssize = 0;
dump.u_comm = 0;
......@@ -588,9 +589,9 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
current->sigaction[i].sa_handler = NULL;
}
for (i=0 ; i<NR_OPEN ; i++)
if ((current->close_on_exec>>i)&1)
if (FD_ISSET(i,&current->close_on_exec))
sys_close(i);
current->close_on_exec = 0;
FD_ZERO(&current->close_on_exec);
clear_page_tables(current);
if (last_task_used_math == current)
last_task_used_math = NULL;
......
......@@ -37,9 +37,9 @@ blkdev.o : blkdev.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/in
/usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
/usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/ext_fs.h /usr/include/linux/tty.h \
/usr/include/linux/termios.h /usr/include/asm/system.h /usr/include/linux/stat.h \
/usr/include/linux/fcntl.h /usr/include/linux/errno.h
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/ext_fs.h \
/usr/include/linux/tty.h /usr/include/linux/termios.h /usr/include/asm/system.h \
/usr/include/linux/stat.h /usr/include/linux/fcntl.h /usr/include/linux/errno.h
chrdev.o : chrdev.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/include/linux/fs.h \
/usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/types.h \
/usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h \
......@@ -47,9 +47,9 @@ chrdev.o : chrdev.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/in
/usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
/usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/ext_fs.h /usr/include/linux/tty.h \
/usr/include/linux/termios.h /usr/include/asm/system.h /usr/include/linux/stat.h \
/usr/include/linux/fcntl.h /usr/include/linux/errno.h
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/ext_fs.h \
/usr/include/linux/tty.h /usr/include/linux/termios.h /usr/include/asm/system.h \
/usr/include/linux/stat.h /usr/include/linux/fcntl.h /usr/include/linux/errno.h
dir.o : dir.c /usr/include/asm/segment.h /usr/include/linux/errno.h /usr/include/linux/kernel.h \
/usr/include/linux/fs.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
/usr/include/linux/types.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
......@@ -63,7 +63,7 @@ fifo.o : fifo.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/includ
/usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
/usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/ext_fs.h
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/ext_fs.h
file.o : file.c /usr/include/asm/segment.h /usr/include/asm/system.h /usr/include/linux/sched.h \
/usr/include/linux/head.h /usr/include/linux/fs.h /usr/include/linux/limits.h \
/usr/include/linux/wait.h /usr/include/linux/types.h /usr/include/linux/dirent.h \
......@@ -72,8 +72,8 @@ file.o : file.c /usr/include/asm/segment.h /usr/include/asm/system.h /usr/includ
/usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h \
/usr/include/linux/kernel.h /usr/include/linux/signal.h /usr/include/linux/time.h \
/usr/include/linux/param.h /usr/include/linux/resource.h /usr/include/linux/vm86.h \
/usr/include/linux/ext_fs.h /usr/include/linux/errno.h /usr/include/linux/fcntl.h \
/usr/include/linux/stat.h
/usr/include/linux/math_emu.h /usr/include/linux/ext_fs.h /usr/include/linux/errno.h \
/usr/include/linux/fcntl.h /usr/include/linux/stat.h /usr/include/linux/locks.h
freelists.o : freelists.c /usr/include/linux/sched.h /usr/include/linux/head.h \
/usr/include/linux/fs.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
/usr/include/linux/types.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
......@@ -81,8 +81,8 @@ freelists.o : freelists.c /usr/include/linux/sched.h /usr/include/linux/head.h \
/usr/include/linux/msdos_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
/usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h /usr/include/linux/kernel.h \
/usr/include/linux/signal.h /usr/include/linux/time.h /usr/include/linux/param.h \
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/ext_fs.h \
/usr/include/linux/string.h
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/math_emu.h \
/usr/include/linux/ext_fs.h /usr/include/linux/string.h /usr/include/linux/locks.h
inode.o : inode.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/include/linux/fs.h \
/usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/types.h \
/usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h \
......@@ -90,8 +90,9 @@ inode.o : inode.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/incl
/usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
/usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/ext_fs.h /usr/include/linux/string.h \
/usr/include/linux/stat.h /usr/include/asm/system.h /usr/include/asm/segment.h
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/ext_fs.h \
/usr/include/linux/string.h /usr/include/linux/stat.h /usr/include/linux/locks.h \
/usr/include/asm/system.h /usr/include/asm/segment.h
namei.o : namei.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/include/linux/fs.h \
/usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/types.h \
/usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h \
......@@ -99,9 +100,9 @@ namei.o : namei.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/incl
/usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
/usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/ext_fs.h /usr/include/linux/string.h \
/usr/include/linux/stat.h /usr/include/linux/fcntl.h /usr/include/linux/errno.h \
/usr/include/asm/segment.h
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/ext_fs.h \
/usr/include/linux/string.h /usr/include/linux/stat.h /usr/include/linux/fcntl.h \
/usr/include/linux/errno.h /usr/include/asm/segment.h
symlink.o : symlink.c /usr/include/asm/segment.h /usr/include/linux/errno.h \
/usr/include/linux/sched.h /usr/include/linux/head.h /usr/include/linux/fs.h \
/usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/types.h \
......@@ -110,7 +111,8 @@ symlink.o : symlink.c /usr/include/asm/segment.h /usr/include/linux/errno.h \
/usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
/usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/ext_fs.h /usr/include/linux/stat.h
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/ext_fs.h \
/usr/include/linux/stat.h
truncate.o : truncate.c /usr/include/linux/sched.h /usr/include/linux/head.h \
/usr/include/linux/fs.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
/usr/include/linux/types.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
......@@ -118,6 +120,7 @@ truncate.o : truncate.c /usr/include/linux/sched.h /usr/include/linux/head.h \
/usr/include/linux/msdos_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
/usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h /usr/include/linux/kernel.h \
/usr/include/linux/signal.h /usr/include/linux/time.h /usr/include/linux/param.h \
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/ext_fs.h \
/usr/include/linux/tty.h /usr/include/linux/termios.h /usr/include/asm/system.h \
/usr/include/linux/stat.h /usr/include/linux/fcntl.h /usr/include/linux/errno.h
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/math_emu.h \
/usr/include/linux/ext_fs.h /usr/include/linux/tty.h /usr/include/linux/termios.h \
/usr/include/asm/system.h /usr/include/linux/stat.h /usr/include/linux/fcntl.h \
/usr/include/linux/errno.h
......@@ -100,7 +100,7 @@ static int ext_file_read(struct inode * inode, struct file * filp, char * buf, i
--blocks;
*bhb = ext_getblk(inode,block++,0);
if (*bhb && !(*bhb)->b_uptodate)
ll_rw_block(READ,*bhb);
ll_rw_block(READ, 1, bhb);
if (++bhb == &buflist[NBUF])
bhb = buflist;
......@@ -183,7 +183,7 @@ static int ext_file_write(struct inode * inode, struct file * filp, char * buf,
if (c > count-written)
c = count-written;
if (c != BLOCK_SIZE && !bh->b_uptodate) {
ll_rw_block(READ,bh);
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
if (!bh->b_uptodate) {
brelse(bh);
......
......@@ -181,10 +181,10 @@ void ext_free_inode(struct inode * inode)
if (!inode)
return;
if (!inode->i_dev) {
memset(inode,0,sizeof(*inode));
printk("free_inode: inode has no device\n");
return;
}
if (inode->i_count>1) {
if (inode->i_count != 1) {
printk("free_inode: inode has count=%d\n",inode->i_count);
return;
}
......@@ -227,7 +227,7 @@ printk("ext_free_inode: inode full, skipping to %d\n", inode->i_ino);
inode->i_sb->s_dirt = 1;
inode->i_sb->u.ext_sb.s_firstfreeinodeblock->b_dirt = 1;
unlock_super (inode->i_sb);
memset(inode,0,sizeof(*inode));
clear_inode(inode);
}
struct inode * ext_new_inode(struct super_block * sb)
......
......@@ -45,6 +45,7 @@ void ext_put_super(struct super_block *sb)
static struct super_operations ext_sops = {
ext_read_inode,
NULL,
ext_write_inode,
ext_put_inode,
ext_put_super,
......@@ -62,7 +63,7 @@ struct super_block *ext_read_super(struct super_block *s,void *data)
if (!(bh = bread(dev, 1, BLOCK_SIZE))) {
s->s_dev=0;
unlock_super(s);
printk("bread failed\n");
printk("EXT-fs: unable to read superblock\n");
return NULL;
}
es = (struct ext_super_block *) bh->b_data;
......@@ -81,7 +82,7 @@ struct super_block *ext_read_super(struct super_block *s,void *data)
if (s->s_magic != EXT_SUPER_MAGIC) {
s->s_dev = 0;
unlock_super(s);
printk("magic match failed\n");
printk("EXT-fs: magic match failed\n");
return NULL;
}
if (!s->u.ext_sb.s_firstfreeblocknumber)
......@@ -89,7 +90,7 @@ struct super_block *ext_read_super(struct super_block *s,void *data)
else
if (!(s->u.ext_sb.s_firstfreeblock = bread(dev,
s->u.ext_sb.s_firstfreeblocknumber, BLOCK_SIZE))) {
printk ("ext_read_super: unable to read first free block\n");
printk("ext_read_super: unable to read first free block\n");
s->s_dev = 0;
unlock_super(s);
return NULL;
......@@ -99,7 +100,7 @@ struct super_block *ext_read_super(struct super_block *s,void *data)
else {
block = 2 + (s->u.ext_sb.s_firstfreeinodenumber - 1) / EXT_INODES_PER_BLOCK;
if (!(s->u.ext_sb.s_firstfreeinodeblock = bread(dev, block, BLOCK_SIZE))) {
printk ("ext_read_super: unable to read first free inode block\n");
printk("ext_read_super: unable to read first free inode block\n");
brelse(s->u.ext_sb.s_firstfreeblock);
s->s_dev = 0;
unlock_super (s);
......@@ -112,7 +113,7 @@ struct super_block *ext_read_super(struct super_block *s,void *data)
s->s_op = &ext_sops;
if (!(s->s_mounted = iget(s,EXT_ROOT_INO))) {
s->s_dev=0;
printk("get root inode failed\n");
printk("EXT-fs: get root inode failed\n");
return NULL;
}
return s;
......@@ -253,7 +254,7 @@ static struct buffer_head * block_getblk(struct inode * inode,
if (!bh)
return NULL;
if (!bh->b_uptodate) {
ll_rw_block(READ,bh);
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
if (!bh->b_uptodate) {
brelse(bh);
......@@ -332,7 +333,7 @@ struct buffer_head * ext_bread(struct inode * inode, int block, int create)
bh = ext_getblk(inode,block,create);
if (!bh || bh->b_uptodate)
return bh;
ll_rw_block(READ,bh);
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
if (bh->b_uptodate)
return bh;
......
......@@ -30,7 +30,7 @@ static int dupfd(unsigned int fd, unsigned int arg)
break;
if (arg >= NR_OPEN)
return -EMFILE;
current->close_on_exec &= ~(1<<arg);
FD_CLR(arg, &current->close_on_exec);
(current->filp[arg] = current->filp[fd])->f_count++;
return arg;
}
......@@ -61,12 +61,12 @@ int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
case F_DUPFD:
return dupfd(fd,arg);
case F_GETFD:
return (current->close_on_exec>>fd)&1;
return FD_ISSET(fd, &current->close_on_exec);
case F_SETFD:
if (arg&1)
current->close_on_exec |= (1<<fd);
FD_SET(fd, &current->close_on_exec);
else
current->close_on_exec &= ~(1<<fd);
FD_CLR(fd, &current->close_on_exec);
return 0;
case F_GETFL:
return filp->f_flags;
......
/*
* linux/fs/filesystems.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* table of configured filesystems
*/
#include <linux/config.h>
#include <linux/fs.h>
#ifdef MINIX_FS
#include <linux/minix_fs.h>
#endif
#ifdef PROC_FS
#include <linux/proc_fs.h>
#endif
#ifdef EXT_FS
#include <linux/ext_fs.h>
#endif
#ifdef MSDOS_FS
#include <linux/msdos_fs.h>
#endif
#ifdef NFS_FS
#include <linux/nfs_fs.h>
#endif
struct file_system_type file_systems[] = {
#ifdef MINIX_FS
{minix_read_super, "minix", 1},
#endif
#ifdef EXT_FS
{ext_read_super, "ext", 1},
#endif
#ifdef MSDOS_FS
{msdos_read_super, "msdos", 1},
#endif
#ifdef PROC_FS
{proc_read_super, "proc", 0},
#endif
#ifdef NFS_FS
{nfs_read_super, "nfs", 0},
#endif
{NULL, NULL, 0}
};
......@@ -13,12 +13,55 @@
#include <asm/system.h>
static struct inode inode_table[NR_INODE];
static struct inode * last_inode = inode_table;
void inode_init(void)
{
memset(inode_table,0,sizeof(inode_table));
}
static void __wait_on_inode(struct inode *);
static inline void wait_on_inode(struct inode * inode)
{
if (inode->i_lock)
__wait_on_inode(inode);
}
static inline void lock_inode(struct inode * inode)
{
wait_on_inode(inode);
inode->i_lock = 1;
}
static inline void unlock_inode(struct inode * inode)
{
inode->i_lock = 0;
wake_up(&inode->i_wait);
}
/*
* Note that we don't want to disturb any wait-queues when we discard
* an inode.
*
* Argghh. Got bitten by a gcc problem with inlining: no way to tell
* the compiler that the inline asm function 'memset' changes 'inode'.
* I've been searching for the bug for days, and was getting desperate.
* Finally looked at the assembler output... Grrr.
*
* The solution is the weird use of 'volatile'. Ho humm. Have to report
* it to the gcc lists, and hope we can do this more cleanly some day..
*/
void clear_inode(struct inode * inode)
{
struct wait_queue * wait;
wait_on_inode(inode);
wait = ((volatile struct inode *) inode)->i_wait;
memset(inode,0,sizeof(*inode));
((volatile struct inode *) inode)->i_wait = wait;
}
int fs_may_mount(dev_t dev)
{
struct inode * inode;
......@@ -28,7 +71,7 @@ int fs_may_mount(dev_t dev)
continue;
if (inode->i_count || inode->i_dirt || inode->i_lock)
return 0;
inode->i_dev = 0;
clear_inode(inode);
}
return 1;
}
......@@ -37,61 +80,29 @@ int fs_may_umount(dev_t dev, struct inode * mount_root)
{
struct inode * inode;
for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++)
for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++) {
if (inode->i_dev==dev && inode->i_count)
if (inode == mount_root && inode->i_count == 1)
continue;
else
return 0;
return 1;
}
/*
* The "new" scheduling primitives (new as of 0.97 or so) allow this to
* be done without disabling interrupts (other than in the actual queue
* updating things: only a couple of 386 instructions). This should be
* much better for interrupt latency.
*/
static void __wait_on_inode(struct inode * inode)
{
add_wait_queue(&inode->i_wait,&current->wait);
repeat:
current->state = TASK_UNINTERRUPTIBLE;
if (inode->i_lock) {
schedule();
goto repeat;
}
remove_wait_queue(&inode->i_wait,&current->wait);
current->state = TASK_RUNNING;
}
static inline void wait_on_inode(struct inode * inode)
{
if (inode->i_lock)
__wait_on_inode(inode);
}
static inline void lock_inode(struct inode * inode)
{
wait_on_inode(inode);
inode->i_lock = 1;
}
static inline void unlock_inode(struct inode * inode)
{
inode->i_lock = 0;
wake_up(&inode->i_wait);
return 1;
}
static void write_inode(struct inode * inode)
{
if (!inode->i_dirt)
return;
lock_inode(inode);
inode->i_dirt = 0;
if (inode->i_dev && inode->i_sb &&
inode->i_sb->s_op && inode->i_sb->s_op->write_inode)
inode->i_sb->s_op->write_inode(inode);
wait_on_inode(inode);
if (!inode->i_dirt)
return;
if (!inode->i_sb || !inode->i_sb->s_op || !inode->i_sb->s_op->write_inode) {
inode->i_dirt = 0;
return;
}
inode->i_lock = 1;
inode->i_sb->s_op->write_inode(inode);
unlock_inode(inode);
}
......@@ -103,6 +114,22 @@ static void read_inode(struct inode * inode)
unlock_inode(inode);
}
/*
* notify_change is called for inode-changing operations such as
* chown, chmod, utime, and truncate. It is guaranteed (unlike
* write_inode) to be called from the context of the user requesting
* the change. It is not called for ordinary access-time updates.
* NFS uses this to get the authentication correct. -- jrs
*/
int notify_change(struct inode * inode)
{
if (inode->i_sb && inode->i_sb->s_op &&
inode->i_sb->s_op->notify_change)
return inode->i_sb->s_op->notify_change(inode);
return 0;
}
/*
* bmap is needed for demand-loading and paging: if this function
* doesn't exist for a filesystem, then those things are impossible:
......@@ -133,18 +160,16 @@ void invalidate_inodes(dev_t dev)
printk("inode in use on removed disk\n\r");
continue;
}
inode->i_dev = inode->i_dirt = 0;
clear_inode(inode);
}
}
}
void sync_inodes(dev_t dev)
{
int i;
struct inode * inode;
inode = 0+inode_table;
for(i=0 ; i<NR_INODE ; i++,inode++) {
for(inode = 0+inode_table ; inode < NR_INODE+inode_table ; inode++) {
wait_on_inode(inode);
if (inode->i_dirt)
write_inode(inode);
......@@ -176,10 +201,6 @@ void iput(struct inode * inode)
PIPE_BASE(*inode) = NULL;
free_page(page);
}
if (!inode->i_dev) {
inode->i_count--;
return;
}
if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode) {
inode->i_sb->s_op->put_inode(inode);
if (!inode->i_nlink)
......@@ -197,34 +218,38 @@ void iput(struct inode * inode)
struct inode * get_empty_inode(void)
{
struct inode * inode;
static struct inode * last_inode = inode_table;
int i;
do {
inode = NULL;
for (i = NR_INODE; i ; i--) {
if (++last_inode >= inode_table + NR_INODE)
last_inode = inode_table;
if (!last_inode->i_count) {
inode = last_inode;
if (!inode->i_dirt && !inode->i_lock)
break;
}
}
if (!inode) {
for (i=0 ; i<NR_INODE ; i++)
printk("(%04x: %d (%o)) ",inode_table[i].i_dev,
inode_table[i].i_ino,inode_table[i].i_mode);
panic("No free inodes in mem");
repeat:
inode = NULL;
for (i = NR_INODE; i ; i--) {
if (++last_inode >= inode_table + NR_INODE)
last_inode = inode_table;
if (!last_inode->i_count) {
inode = last_inode;
if (!inode->i_dirt && !inode->i_lock)
break;
}
}
if (!inode) {
for (i=0 ; i<NR_INODE ; i++)
printk("(%04x: %d (%o)) ",inode_table[i].i_dev,
inode_table[i].i_ino,inode_table[i].i_mode);
panic("No free inodes in mem");
}
if (inode->i_lock) {
wait_on_inode(inode);
while (inode->i_dirt) {
write_inode(inode);
wait_on_inode(inode);
}
} while (inode->i_count);
memset(inode,0,sizeof(*inode));
goto repeat;
}
if (inode->i_dirt) {
write_inode(inode);
goto repeat;
}
if (inode->i_count)
goto repeat;
clear_inode(inode);
inode->i_count = 1;
inode->i_nlink = 1;
return inode;
}
......@@ -255,12 +280,12 @@ struct inode * iget(struct super_block * sb,int nr)
empty = get_empty_inode();
inode = inode_table;
while (inode < NR_INODE+inode_table) {
if (inode->i_sb != sb || inode->i_ino != nr) {
if (inode->i_dev != sb->s_dev || inode->i_ino != nr) {
inode++;
continue;
}
wait_on_inode(inode);
if (inode->i_sb != sb || inode->i_ino != nr) {
if (inode->i_dev != sb->s_dev || inode->i_ino != nr) {
inode = inode_table;
continue;
}
......@@ -299,3 +324,24 @@ struct inode * iget(struct super_block * sb,int nr)
read_inode(inode);
return inode;
}
/*
* The "new" scheduling primitives (new as of 0.97 or so) allow this to
* be done without disabling interrupts (other than in the actual queue
* updating things: only a couple of 386 instructions). This should be
* much better for interrupt latency.
*/
static void __wait_on_inode(struct inode * inode)
{
struct wait_queue wait = { current, NULL };
add_wait_queue(&inode->i_wait, &wait);
repeat:
current->state = TASK_UNINTERRUPTIBLE;
if (inode->i_lock) {
schedule();
goto repeat;
}
remove_wait_queue(&inode->i_wait, &wait);
current->state = TASK_RUNNING;
}
......@@ -55,11 +55,11 @@ int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
return -EBADF;
switch (cmd) {
case FIOCLEX:
current->close_on_exec |= (1 << fd);
FD_SET(fd, &current->close_on_exec);
return 0;
case FIONCLEX:
current->close_on_exec &= ~(1 << fd);
FD_CLR(fd, &current->close_on_exec);
return 0;
case FIONBIO:
......
......@@ -37,7 +37,8 @@ bitmap.o : bitmap.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/in
/usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
/usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/minix_fs.h /usr/include/linux/string.h
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/minix_fs.h \
/usr/include/linux/string.h
blkdev.o : blkdev.c /usr/include/linux/errno.h /usr/include/linux/sched.h /usr/include/linux/head.h \
/usr/include/linux/fs.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
/usr/include/linux/types.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
......@@ -45,9 +46,9 @@ blkdev.o : blkdev.c /usr/include/linux/errno.h /usr/include/linux/sched.h /usr/i
/usr/include/linux/msdos_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
/usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h /usr/include/linux/kernel.h \
/usr/include/linux/signal.h /usr/include/linux/time.h /usr/include/linux/param.h \
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/minix_fs.h \
/usr/include/linux/tty.h /usr/include/linux/termios.h /usr/include/asm/system.h \
/usr/include/linux/stat.h /usr/include/linux/fcntl.h
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/math_emu.h \
/usr/include/linux/minix_fs.h /usr/include/linux/tty.h /usr/include/linux/termios.h \
/usr/include/asm/system.h /usr/include/linux/stat.h /usr/include/linux/fcntl.h
chrdev.o : chrdev.c /usr/include/linux/errno.h /usr/include/linux/sched.h /usr/include/linux/head.h \
/usr/include/linux/fs.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
/usr/include/linux/types.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
......@@ -55,9 +56,9 @@ chrdev.o : chrdev.c /usr/include/linux/errno.h /usr/include/linux/sched.h /usr/i
/usr/include/linux/msdos_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
/usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h /usr/include/linux/kernel.h \
/usr/include/linux/signal.h /usr/include/linux/time.h /usr/include/linux/param.h \
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/minix_fs.h \
/usr/include/linux/tty.h /usr/include/linux/termios.h /usr/include/asm/system.h \
/usr/include/linux/stat.h /usr/include/linux/fcntl.h
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/math_emu.h \
/usr/include/linux/minix_fs.h /usr/include/linux/tty.h /usr/include/linux/termios.h \
/usr/include/asm/system.h /usr/include/linux/stat.h /usr/include/linux/fcntl.h
dir.o : dir.c /usr/include/asm/segment.h /usr/include/linux/errno.h /usr/include/linux/fs.h \
/usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/types.h \
/usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h \
......@@ -71,7 +72,7 @@ fifo.o : fifo.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/includ
/usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
/usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/minix_fs.h
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/minix_fs.h
file.o : file.c /usr/include/asm/segment.h /usr/include/asm/system.h /usr/include/linux/sched.h \
/usr/include/linux/head.h /usr/include/linux/fs.h /usr/include/linux/limits.h \
/usr/include/linux/wait.h /usr/include/linux/types.h /usr/include/linux/dirent.h \
......@@ -80,8 +81,8 @@ file.o : file.c /usr/include/asm/segment.h /usr/include/asm/system.h /usr/includ
/usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h \
/usr/include/linux/kernel.h /usr/include/linux/signal.h /usr/include/linux/time.h \
/usr/include/linux/param.h /usr/include/linux/resource.h /usr/include/linux/vm86.h \
/usr/include/linux/minix_fs.h /usr/include/linux/errno.h /usr/include/linux/fcntl.h \
/usr/include/linux/stat.h
/usr/include/linux/math_emu.h /usr/include/linux/minix_fs.h /usr/include/linux/errno.h \
/usr/include/linux/fcntl.h /usr/include/linux/stat.h /usr/include/linux/locks.h
inode.o : inode.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/include/linux/fs.h \
/usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/types.h \
/usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h \
......@@ -89,8 +90,9 @@ inode.o : inode.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/incl
/usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
/usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/minix_fs.h /usr/include/linux/string.h \
/usr/include/linux/stat.h /usr/include/asm/system.h /usr/include/asm/segment.h
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/minix_fs.h \
/usr/include/linux/string.h /usr/include/linux/stat.h /usr/include/linux/locks.h \
/usr/include/asm/system.h /usr/include/asm/segment.h
namei.o : namei.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/include/linux/fs.h \
/usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/types.h \
/usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h \
......@@ -98,9 +100,9 @@ namei.o : namei.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/incl
/usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
/usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/minix_fs.h /usr/include/linux/string.h \
/usr/include/linux/stat.h /usr/include/linux/fcntl.h /usr/include/linux/errno.h \
/usr/include/asm/segment.h
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/minix_fs.h \
/usr/include/linux/string.h /usr/include/linux/stat.h /usr/include/linux/fcntl.h \
/usr/include/linux/errno.h /usr/include/asm/segment.h
symlink.o : symlink.c /usr/include/asm/segment.h /usr/include/linux/errno.h \
/usr/include/linux/sched.h /usr/include/linux/head.h /usr/include/linux/fs.h \
/usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/types.h \
......@@ -109,7 +111,8 @@ symlink.o : symlink.c /usr/include/asm/segment.h /usr/include/linux/errno.h \
/usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
/usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/minix_fs.h /usr/include/linux/stat.h
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/minix_fs.h \
/usr/include/linux/stat.h
truncate.o : truncate.c /usr/include/linux/errno.h /usr/include/linux/sched.h \
/usr/include/linux/head.h /usr/include/linux/fs.h /usr/include/linux/limits.h \
/usr/include/linux/wait.h /usr/include/linux/types.h /usr/include/linux/dirent.h \
......@@ -118,5 +121,6 @@ truncate.o : truncate.c /usr/include/linux/errno.h /usr/include/linux/sched.h \
/usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h \
/usr/include/linux/kernel.h /usr/include/linux/signal.h /usr/include/linux/time.h \
/usr/include/linux/param.h /usr/include/linux/resource.h /usr/include/linux/vm86.h \
/usr/include/linux/minix_fs.h /usr/include/linux/tty.h /usr/include/linux/termios.h \
/usr/include/asm/system.h /usr/include/linux/stat.h /usr/include/linux/fcntl.h
/usr/include/linux/math_emu.h /usr/include/linux/minix_fs.h /usr/include/linux/tty.h \
/usr/include/linux/termios.h /usr/include/asm/system.h /usr/include/linux/stat.h \
/usr/include/linux/fcntl.h
......@@ -158,10 +158,10 @@ void minix_free_inode(struct inode * inode)
if (!inode)
return;
if (!inode->i_dev) {
memset(inode,0,sizeof(*inode));
printk("free_inode: inode has no device\n");
return;
}
if (inode->i_count>1) {
if (inode->i_count != 1) {
printk("free_inode: inode has count=%d\n",inode->i_count);
return;
}
......@@ -182,9 +182,9 @@ void minix_free_inode(struct inode * inode)
return;
}
if (clear_bit(inode->i_ino&8191,bh->b_data))
printk("free_inode: bit already cleared.\n\r");
printk("free_inode: bit %d already cleared.\n",inode->i_ino);
bh->b_dirt = 1;
memset(inode,0,sizeof(*inode));
clear_inode(inode);
}
struct inode * minix_new_inode(struct super_block * sb)
......
......@@ -94,7 +94,7 @@ static int minix_file_read(struct inode * inode, struct file * filp, char * buf,
--blocks;
*bhb = minix_getblk(inode,block++,0);
if (*bhb && !(*bhb)->b_uptodate)
ll_rw_block(READ,*bhb);
ll_rw_block(READ, 1, bhb);
if (++bhb == &buflist[NBUF])
bhb = buflist;
......@@ -177,7 +177,7 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf
if (c > count-written)
c = count-written;
if (c != BLOCK_SIZE && !bh->b_uptodate) {
ll_rw_block(READ,bh);
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
if (!bh->b_uptodate) {
brelse(bh);
......
......@@ -40,6 +40,7 @@ void minix_put_super(struct super_block *sb)
static struct super_operations minix_sops = {
minix_read_inode,
NULL,
minix_write_inode,
minix_put_inode,
minix_put_super,
......@@ -53,11 +54,13 @@ struct super_block *minix_read_super(struct super_block *s,void *data)
struct minix_super_block *ms;
int i,dev=s->s_dev,block;
if (32 != sizeof (struct minix_inode))
panic("bad i-node size");
lock_super(s);
if (!(bh = bread(dev,1,BLOCK_SIZE))) {
s->s_dev=0;
unlock_super(s);
printk("bread failed\n");
printk("MINIX-fs: unable to read superblock\n");
return NULL;
}
ms = (struct minix_super_block *) bh->b_data;
......@@ -74,7 +77,7 @@ struct super_block *minix_read_super(struct super_block *s,void *data)
if (s->s_magic != MINIX_SUPER_MAGIC) {
s->s_dev = 0;
unlock_super(s);
printk("magic match failed\n");
printk("MINIX-fs magic match failed\n");
return NULL;
}
for (i=0;i < MINIX_I_MAP_SLOTS;i++)
......@@ -99,7 +102,7 @@ struct super_block *minix_read_super(struct super_block *s,void *data)
brelse(s->u.minix_sb.s_zmap[i]);
s->s_dev=0;
unlock_super(s);
printk("block failed\n");
printk("MINIX-fs: bad superblock or unable to read bitmaps\n");
return NULL;
}
s->u.minix_sb.s_imap[0]->b_data[0] |= 1;
......@@ -111,7 +114,7 @@ struct super_block *minix_read_super(struct super_block *s,void *data)
unlock_super(s);
if (!s->s_mounted) {
s->s_dev = 0;
printk("get root inode failed\n");
printk("MINIX-fs: get root inode failed\n");
return NULL;
}
return s;
......@@ -219,7 +222,7 @@ static struct buffer_head * block_getblk(struct inode * inode,
if (!bh)
return NULL;
if (!bh->b_uptodate) {
ll_rw_block(READ,bh);
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
if (!bh->b_uptodate) {
brelse(bh);
......@@ -291,7 +294,7 @@ struct buffer_head * minix_bread(struct inode * inode, int block, int create)
bh = minix_getblk(inode,block,create);
if (!bh || bh->b_uptodate)
return bh;
ll_rw_block(READ,bh);
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
if (bh->b_uptodate)
return bh;
......@@ -303,14 +306,16 @@ void minix_read_inode(struct inode * inode)
{
struct buffer_head * bh;
struct minix_inode * raw_inode;
int block;
int block, ino;
block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + inode->i_sb->u.minix_sb.s_zmap_blocks +
(inode->i_ino-1)/MINIX_INODES_PER_BLOCK;
ino = inode->i_ino;
block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks +
inode->i_sb->u.minix_sb.s_zmap_blocks +
(ino-1)/MINIX_INODES_PER_BLOCK;
if (!(bh=bread(inode->i_dev,block, BLOCK_SIZE)))
panic("unable to read i-node block");
raw_inode = ((struct minix_inode *) bh->b_data) +
(inode->i_ino-1)%MINIX_INODES_PER_BLOCK;
(ino-1)%MINIX_INODES_PER_BLOCK;
inode->i_mode = raw_inode->i_mode;
inode->i_uid = raw_inode->i_uid;
inode->i_gid = raw_inode->i_gid;
......@@ -366,7 +371,7 @@ void minix_write_inode(struct inode * inode)
raw_inode->i_zone[0] = inode->i_rdev;
else for (block = 0; block < 9; block++)
raw_inode->i_zone[block] = inode->u.minix_i.i_data[block];
bh->b_dirt=1;
inode->i_dirt=0;
bh->b_dirt=1;
brelse(bh);
}
......@@ -136,6 +136,9 @@ int minix_lookup(struct inode * dir,const char * name, int len,
* NOTE!! The inode part of 'de' is left at 0 - which means you
* may not sleep between calling this and putting something into
* the entry, as someone else might have used it while you slept.
*
* Arggh. To avoid race-conditions, we copy the name into kernel
* space before actually writing it into the buffer...
*/
static struct buffer_head * minix_add_entry(struct inode * dir,
const char * name, int namelen, struct minix_dir_entry ** res_dir)
......@@ -143,22 +146,25 @@ static struct buffer_head * minix_add_entry(struct inode * dir,
int i;
struct buffer_head * bh;
struct minix_dir_entry * de;
char name_buffer[MINIX_NAME_LEN];
*res_dir = NULL;
if (!dir)
return NULL;
if (namelen > MINIX_NAME_LEN) {
#ifdef NO_TRUNCATE
if (namelen > MINIX_NAME_LEN)
return NULL;
#else
if (namelen > MINIX_NAME_LEN)
namelen = MINIX_NAME_LEN;
#endif
}
if (!namelen)
return NULL;
bh = minix_bread(dir,0,0);
if (!bh)
return NULL;
for (i = 0; i < MINIX_NAME_LEN ; i++)
name_buffer[i] = (i<namelen) ? get_fs_byte(name+i) : 0;
i = 0;
de = (struct minix_dir_entry *) bh->b_data;
while (1) {
......@@ -177,8 +183,7 @@ static struct buffer_head * minix_add_entry(struct inode * dir,
}
if (!de->inode) {
dir->i_mtime = CURRENT_TIME;
for (i=0; i < MINIX_NAME_LEN ; i++)
de->name[i]=(i<namelen)?get_fs_byte(name+i):0;
memcpy(de->name,name_buffer,MINIX_NAME_LEN);
bh->b_dirt = 1;
*res_dir = de;
return bh;
......@@ -441,6 +446,7 @@ int minix_unlink(struct inode * dir, const char * name, int len)
struct buffer_head * bh;
struct minix_dir_entry * de;
repeat:
retval = -ENOENT;
inode = NULL;
bh = minix_find_entry(dir,name,len,&de);
......@@ -448,6 +454,13 @@ int minix_unlink(struct inode * dir, const char * name, int len)
goto end_unlink;
if (!(inode = iget(dir->i_sb, de->inode)))
goto end_unlink;
if (de->inode != inode->i_ino) {
iput(inode);
brelse(bh);
current->counter = 0;
schedule();
goto repeat;
}
retval = -EPERM;
if ((dir->i_mode & S_ISVTX) && !suser() &&
current->euid != inode->i_uid &&
......@@ -462,9 +475,11 @@ int minix_unlink(struct inode * dir, const char * name, int len)
}
de->inode = 0;
bh->b_dirt = 1;
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_dirt = 1;
inode->i_nlink--;
inode->i_dirt = 1;
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
retval = 0;
end_unlink:
brelse(bh);
......
......@@ -36,8 +36,8 @@ dir.o : dir.c /usr/include/asm/segment.h /usr/include/linux/sched.h /usr/include
/usr/include/linux/msdos_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
/usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h /usr/include/linux/kernel.h \
/usr/include/linux/signal.h /usr/include/linux/time.h /usr/include/linux/param.h \
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/msdos_fs.h \
/usr/include/linux/errno.h /usr/include/linux/stat.h
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/math_emu.h \
/usr/include/linux/msdos_fs.h /usr/include/linux/errno.h /usr/include/linux/stat.h
fat.o : fat.c /usr/include/linux/msdos_fs.h /usr/include/linux/fs.h /usr/include/linux/limits.h \
/usr/include/linux/wait.h /usr/include/linux/types.h /usr/include/linux/dirent.h \
/usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h \
......@@ -52,8 +52,8 @@ file.o : file.c /usr/include/asm/segment.h /usr/include/asm/system.h /usr/includ
/usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h \
/usr/include/linux/kernel.h /usr/include/linux/signal.h /usr/include/linux/time.h \
/usr/include/linux/param.h /usr/include/linux/resource.h /usr/include/linux/vm86.h \
/usr/include/linux/msdos_fs.h /usr/include/linux/errno.h /usr/include/linux/fcntl.h \
/usr/include/linux/stat.h
/usr/include/linux/math_emu.h /usr/include/linux/msdos_fs.h /usr/include/linux/errno.h \
/usr/include/linux/fcntl.h /usr/include/linux/stat.h
inode.o : inode.c /usr/include/linux/msdos_fs.h /usr/include/linux/fs.h /usr/include/linux/limits.h \
/usr/include/linux/wait.h /usr/include/linux/types.h /usr/include/linux/dirent.h \
/usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h \
......@@ -61,9 +61,9 @@ inode.o : inode.c /usr/include/linux/msdos_fs.h /usr/include/linux/fs.h /usr/inc
/usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/kernel.h \
/usr/include/linux/sched.h /usr/include/linux/head.h /usr/include/linux/mm.h \
/usr/include/linux/signal.h /usr/include/linux/time.h /usr/include/linux/param.h \
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/errno.h \
/usr/include/linux/string.h /usr/include/linux/ctype.h /usr/include/linux/stat.h \
/usr/include/asm/segment.h
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/math_emu.h \
/usr/include/linux/errno.h /usr/include/linux/string.h /usr/include/linux/ctype.h \
/usr/include/linux/stat.h /usr/include/linux/locks.h /usr/include/asm/segment.h
misc.o : misc.c /usr/include/linux/msdos_fs.h /usr/include/linux/fs.h /usr/include/linux/limits.h \
/usr/include/linux/wait.h /usr/include/linux/types.h /usr/include/linux/dirent.h \
/usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h \
......@@ -71,8 +71,8 @@ misc.o : misc.c /usr/include/linux/msdos_fs.h /usr/include/linux/fs.h /usr/inclu
/usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/sched.h \
/usr/include/linux/head.h /usr/include/linux/mm.h /usr/include/linux/kernel.h \
/usr/include/linux/signal.h /usr/include/linux/time.h /usr/include/linux/param.h \
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/errno.h \
/usr/include/linux/string.h /usr/include/linux/stat.h
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/math_emu.h \
/usr/include/linux/errno.h /usr/include/linux/string.h /usr/include/linux/stat.h
namei.o : namei.c /usr/include/asm/segment.h /usr/include/linux/sched.h /usr/include/linux/head.h \
/usr/include/linux/fs.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
/usr/include/linux/types.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
......@@ -80,5 +80,6 @@ namei.o : namei.c /usr/include/asm/segment.h /usr/include/linux/sched.h /usr/inc
/usr/include/linux/msdos_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
/usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h /usr/include/linux/kernel.h \
/usr/include/linux/signal.h /usr/include/linux/time.h /usr/include/linux/param.h \
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/msdos_fs.h \
/usr/include/linux/errno.h /usr/include/linux/string.h /usr/include/linux/stat.h
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/math_emu.h \
/usr/include/linux/msdos_fs.h /usr/include/linux/errno.h /usr/include/linux/string.h \
/usr/include/linux/stat.h
......@@ -24,7 +24,7 @@ void msdos_put_inode(struct inode *inode)
inode->i_size = 0;
msdos_truncate(inode);
depend = MSDOS_I(inode)->i_depend;
memset(inode,0,sizeof(struct inode));
clear_inode(inode);
if (depend) {
if (MSDOS_I(depend)->i_old != inode) {
printk("Invalid link (0x%X): expected 0x%X, got "
......@@ -50,6 +50,7 @@ void msdos_put_super(struct super_block *sb)
static struct super_operations msdos_sops = {
msdos_read_inode,
NULL,
msdos_write_inode,
msdos_put_inode,
msdos_put_super,
......
......@@ -144,6 +144,10 @@ static int dir_namei(const char * pathname, int * namelen, const char ** name,
if (error)
return error;
}
if (!base->i_op || !base->i_op->lookup) {
iput(base);
return -ENOTDIR;
}
*name = thisname;
*namelen = len;
*res_inode = base;
......
......@@ -15,6 +15,8 @@
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/tty.h>
#include <linux/time.h>
#include <asm/segment.h>
extern void fcntl_remove_locks(struct task_struct *, struct file *);
......@@ -87,8 +89,9 @@ int sys_truncate(const char * path, unsigned int length)
inode->i_op->truncate(inode);
inode->i_atime = inode->i_mtime = CURRENT_TIME;
inode->i_dirt = 1;
error = notify_change(inode);
iput(inode);
return 0;
return error;
}
int sys_ftruncate(unsigned int fd, unsigned int length)
......@@ -107,7 +110,7 @@ int sys_ftruncate(unsigned int fd, unsigned int length)
inode->i_op->truncate(inode);
inode->i_atime = inode->i_mtime = CURRENT_TIME;
inode->i_dirt = 1;
return 0;
return notify_change(inode);
}
/* If times==NULL, set access and modification to current time,
......@@ -144,9 +147,11 @@ int sys_utime(char * filename, struct utimbuf * times)
}
inode->i_atime = actime;
inode->i_mtime = modtime;
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
error = notify_change(inode);
iput(inode);
return 0;
return error;
}
/*
......@@ -239,7 +244,7 @@ int sys_fchmod(unsigned int fd, mode_t mode)
return -EROFS;
inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
inode->i_dirt = 1;
return 0;
return notify_change(inode);
}
int sys_chmod(const char * filename, mode_t mode)
......@@ -260,8 +265,9 @@ int sys_chmod(const char * filename, mode_t mode)
}
inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
inode->i_dirt = 1;
error = notify_change(inode);
iput(inode);
return 0;
return error;
}
int sys_fchown(unsigned int fd, uid_t user, gid_t group)
......@@ -275,13 +281,17 @@ int sys_fchown(unsigned int fd, uid_t user, gid_t group)
return -ENOENT;
if (IS_RDONLY(inode))
return -EROFS;
if (user == (uid_t) -1)
user = inode->i_uid;
if (group == (gid_t) -1)
group = inode->i_gid;
if ((current->euid == inode->i_uid && user == inode->i_uid &&
(in_group_p(group) || group == inode->i_gid)) ||
suser()) {
inode->i_uid = user;
inode->i_gid = group;
inode->i_dirt=1;
return 0;
inode->i_dirt = 1;
return notify_change(inode);
}
return -EPERM;
}
......@@ -298,14 +308,19 @@ int sys_chown(const char * filename, uid_t user, gid_t group)
iput(inode);
return -EROFS;
}
if (user == (uid_t) -1)
user = inode->i_uid;
if (group == (gid_t) -1)
group = inode->i_gid;
if ((current->euid == inode->i_uid && user == inode->i_uid &&
(in_group_p(group) || group == inode->i_gid)) ||
suser()) {
inode->i_uid = user;
inode->i_gid = group;
inode->i_dirt=1;
inode->i_dirt = 1;
error = notify_change(inode);
iput(inode);
return 0;
return error;
}
iput(inode);
return -EPERM;
......@@ -336,7 +351,7 @@ int sys_open(const char * filename,int flag,int mode)
break;
if (fd>=NR_OPEN)
return -EMFILE;
current->close_on_exec &= ~(1<<fd);
FD_CLR(fd,&current->close_on_exec);
f = get_empty_filp();
if (!f)
return -ENFILE;
......@@ -352,11 +367,17 @@ int sys_open(const char * filename,int flag,int mode)
f->f_count--;
return i;
}
if (flag & O_TRUNC)
if (inode->i_op && inode->i_op->truncate) {
inode->i_size = 0;
if (flag & O_TRUNC) {
inode->i_size = 0;
if (inode->i_op && inode->i_op->truncate)
inode->i_op->truncate(inode);
if ((i = notify_change(inode))) {
iput(inode);
current->filp[fd] = NULL;
f->f_count--;
return i;
}
}
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
......@@ -374,6 +395,7 @@ int sys_open(const char * filename,int flag,int mode)
current->filp[fd]=NULL;
return i;
}
f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
return (fd);
}
......@@ -382,7 +404,7 @@ int sys_creat(const char * pathname, int mode)
return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
}
static int close_fp(struct file *filp)
int close_fp(struct file *filp)
{
struct inode *inode;
......@@ -411,7 +433,7 @@ int sys_close(unsigned int fd)
if (fd >= NR_OPEN)
return -EINVAL;
current->close_on_exec &= ~(1<<fd);
FD_CLR(fd, &current->close_on_exec);
if (!(filp = current->filp[fd]))
return -EINVAL;
current->filp[fd] = NULL;
......@@ -494,7 +516,7 @@ int sys_vhangup(void)
/* finally close the file. */
(*process)->close_on_exec &= ~(1<<j);
FD_CLR(j, &(*process)->close_on_exec);
close_fp (filep);
}
}
......
......@@ -37,7 +37,7 @@ base.o : base.c /usr/include/asm/segment.h /usr/include/linux/errno.h /usr/inclu
/usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h \
/usr/include/linux/kernel.h /usr/include/linux/signal.h /usr/include/linux/time.h \
/usr/include/linux/param.h /usr/include/linux/resource.h /usr/include/linux/vm86.h \
/usr/include/linux/proc_fs.h /usr/include/linux/stat.h
/usr/include/linux/math_emu.h /usr/include/linux/proc_fs.h /usr/include/linux/stat.h
fd.o : fd.c /usr/include/asm/segment.h /usr/include/linux/errno.h /usr/include/linux/sched.h \
/usr/include/linux/head.h /usr/include/linux/fs.h /usr/include/linux/limits.h \
/usr/include/linux/wait.h /usr/include/linux/types.h /usr/include/linux/dirent.h \
......@@ -46,7 +46,7 @@ fd.o : fd.c /usr/include/asm/segment.h /usr/include/linux/errno.h /usr/include/l
/usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h \
/usr/include/linux/kernel.h /usr/include/linux/signal.h /usr/include/linux/time.h \
/usr/include/linux/param.h /usr/include/linux/resource.h /usr/include/linux/vm86.h \
/usr/include/linux/proc_fs.h /usr/include/linux/stat.h
/usr/include/linux/math_emu.h /usr/include/linux/proc_fs.h /usr/include/linux/stat.h
inode.o : inode.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/include/linux/fs.h \
/usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/types.h \
/usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h \
......@@ -54,8 +54,9 @@ inode.o : inode.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/incl
/usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
/usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/proc_fs.h /usr/include/linux/string.h \
/usr/include/linux/stat.h /usr/include/asm/system.h /usr/include/asm/segment.h
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/proc_fs.h \
/usr/include/linux/string.h /usr/include/linux/stat.h /usr/include/linux/locks.h \
/usr/include/asm/system.h /usr/include/asm/segment.h
link.o : link.c /usr/include/asm/segment.h /usr/include/linux/errno.h /usr/include/linux/sched.h \
/usr/include/linux/head.h /usr/include/linux/fs.h /usr/include/linux/limits.h \
/usr/include/linux/wait.h /usr/include/linux/types.h /usr/include/linux/dirent.h \
......@@ -64,7 +65,7 @@ link.o : link.c /usr/include/asm/segment.h /usr/include/linux/errno.h /usr/inclu
/usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h \
/usr/include/linux/kernel.h /usr/include/linux/signal.h /usr/include/linux/time.h \
/usr/include/linux/param.h /usr/include/linux/resource.h /usr/include/linux/vm86.h \
/usr/include/linux/minix_fs.h /usr/include/linux/stat.h
/usr/include/linux/math_emu.h /usr/include/linux/minix_fs.h /usr/include/linux/stat.h
mem.o : mem.c /usr/include/linux/types.h /usr/include/linux/errno.h /usr/include/linux/sched.h \
/usr/include/linux/head.h /usr/include/linux/fs.h /usr/include/linux/limits.h \
/usr/include/linux/wait.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
......@@ -72,8 +73,8 @@ mem.o : mem.c /usr/include/linux/types.h /usr/include/linux/errno.h /usr/include
/usr/include/linux/msdos_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
/usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h /usr/include/linux/kernel.h \
/usr/include/linux/signal.h /usr/include/linux/time.h /usr/include/linux/param.h \
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/asm/segment.h \
/usr/include/asm/io.h
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/math_emu.h \
/usr/include/asm/segment.h /usr/include/asm/io.h
root.o : root.c /usr/include/asm/segment.h /usr/include/linux/errno.h /usr/include/linux/sched.h \
/usr/include/linux/head.h /usr/include/linux/fs.h /usr/include/linux/limits.h \
/usr/include/linux/wait.h /usr/include/linux/types.h /usr/include/linux/dirent.h \
......@@ -82,4 +83,4 @@ root.o : root.c /usr/include/asm/segment.h /usr/include/linux/errno.h /usr/inclu
/usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/mm.h \
/usr/include/linux/kernel.h /usr/include/linux/signal.h /usr/include/linux/time.h \
/usr/include/linux/param.h /usr/include/linux/resource.h /usr/include/linux/vm86.h \
/usr/include/linux/proc_fs.h /usr/include/linux/stat.h
/usr/include/linux/math_emu.h /usr/include/linux/proc_fs.h /usr/include/linux/stat.h
......@@ -31,6 +31,7 @@ void proc_put_super(struct super_block *sb)
static struct super_operations proc_sops = {
proc_read_inode,
NULL,
proc_write_inode,
proc_put_inode,
proc_put_super,
......
......@@ -22,14 +22,20 @@
* Ok, Peter made a complicated, but straightforward multiple_wait() function.
* I have rewritten this, taking some shortcuts: This code may not be easy to
* follow, but it should be free of race-conditions, and it's practical. If you
* understand what I'm doing here, then you understand how the linux sleep/wakeup
* mechanism works.
* understand what I'm doing here, then you understand how the linux
* sleep/wakeup mechanism works.
*
* Two very simple procedures, select_wait() and free_wait() make all the work.
* select_wait() is a inline-function defined in <linux/fs.h>, as all select
* select_wait() is a inline-function defined in <linux/sched.h>, as all select
* functions have to call it to add an entry to the select table.
*/
/*
* I rewrote this again to make the select_table size variable, take some
* more shortcuts, improve responsiveness, and remove another race that
* Linus noticed. -- jrs
*/
static void free_wait(select_table * p)
{
struct select_table_entry * entry = p->entry + p->nr;
......@@ -42,89 +48,126 @@ static void free_wait(select_table * p)
}
/*
* The check_XX functions check out a file. We know it's either
* a pipe, a character device or a fifo
* The check function checks the ready status of a file using the vfs layer.
*
* If the file was not ready we were added to its wait queue. But in
* case it became ready just after the check and just before it called
* select_wait, we call it again, knowing we are already on its
* wait queue this time. The second call is not necessary if the
* select_table is NULL indicating an earlier file check was ready
* and we aren't going to sleep on the select_table. -- jrs
*/
static int check_in(select_table * wait, struct inode * inode, struct file * file)
{
if (file->f_op && file->f_op->select)
return file->f_op->select(inode,file,SEL_IN,wait);
if (inode && S_ISREG(inode->i_mode))
return 1;
return 0;
}
static int check_out(select_table * wait, struct inode * inode, struct file * file)
static int check(int flag, select_table * wait, struct file * file)
{
if (file->f_op && file->f_op->select)
return file->f_op->select(inode,file,SEL_OUT,wait);
if (inode && S_ISREG(inode->i_mode))
return 1;
return 0;
}
struct inode * inode;
struct file_operations *fops;
int (*select) (struct inode *, struct file *, int, select_table *);
static int check_ex(select_table * wait, struct inode * inode, struct file * file)
{
if (file->f_op && file->f_op->select)
return file->f_op->select(inode,file,SEL_EX,wait);
if (inode && S_ISREG(inode->i_mode))
inode = file->f_inode;
if ((fops = file->f_op) && (select = fops->select))
return select(inode, file, flag, wait)
|| (wait && select(inode, file, flag, NULL));
if (S_ISREG(inode->i_mode))
return 1;
return 0;
}
int do_select(fd_set in, fd_set out, fd_set ex,
fd_set *inp, fd_set *outp, fd_set *exp)
int do_select(int n, fd_set *in, fd_set *out, fd_set *ex,
fd_set *res_in, fd_set *res_out, fd_set *res_ex)
{
int count;
select_table wait_table;
struct file * file;
select_table wait_table, *wait;
struct select_table_entry *entry;
int i;
fd_set mask;
int max;
mask = in | out | ex;
for (i = 0 ; i < NR_OPEN ; i++,mask >>= 1) {
if (!(mask & 1))
max = -1;
for (i = 0 ; i < n ; i++) {
if (!FD_ISSET(i, in) &&
!FD_ISSET(i, out) &&
!FD_ISSET(i, ex))
continue;
if (!current->filp[i])
return -EBADF;
if (!current->filp[i]->f_inode)
return -EBADF;
max = i;
}
n = max + 1;
entry = (struct select_table_entry *) get_free_page(GFP_KERNEL);
if (!entry)
return -ENOMEM;
FD_ZERO(res_in);
FD_ZERO(res_out);
FD_ZERO(res_ex);
count = 0;
repeat:
wait_table.nr = 0;
*inp = *outp = *exp = 0;
count = 0;
wait_table.entry = entry;
current->state = TASK_INTERRUPTIBLE;
mask = 1;
for (i = 0 ; i < NR_OPEN ; i++, mask += mask) {
file = current->filp[i];
if (mask & in)
if (check_in(&wait_table,file->f_inode,file)) {
*inp |= mask;
count++;
}
if (mask & out)
if (check_out(&wait_table,file->f_inode,file)) {
*outp |= mask;
count++;
}
if (mask & ex)
if (check_ex(&wait_table,file->f_inode,file)) {
*exp |= mask;
count++;
}
wait = &wait_table;
for (i = 0 ; i < n ; i++) {
if (FD_ISSET(i,in) && check(SEL_IN,wait,current->filp[i])) {
FD_SET(i, res_in);
count++;
wait = NULL;
}
if (FD_ISSET(i,out) && check(SEL_OUT,wait,current->filp[i])) {
FD_SET(i, res_out);
count++;
wait = NULL;
}
if (FD_ISSET(i,ex) && check(SEL_EX,wait,current->filp[i])) {
FD_SET(i, res_ex);
count++;
wait = NULL;
}
}
if (!(current->signal & ~current->blocked) &&
current->timeout && !count) {
if (!count && current->timeout
&& !(current->signal & ~current->blocked)) {
schedule();
free_wait(&wait_table);
goto repeat;
}
free_wait(&wait_table);
free_page((unsigned long) entry);
current->state = TASK_RUNNING;
return count;
}
static void __get_fd_set(int nr, unsigned long * fs_pointer, unsigned long * fdset)
{
FD_ZERO(fdset);
if (!fs_pointer)
return;
while (nr > 0) {
*fdset = get_fs_long(fs_pointer);
fdset++;
fs_pointer++;
nr -= 32;
}
}
static void __set_fd_set(int nr, unsigned long * fs_pointer, unsigned long * fdset)
{
if (!fs_pointer)
return;
verify_area(fs_pointer, sizeof(fd_set));
while (nr > 0) {
put_fs_long(*fdset, fs_pointer);
fdset++;
fs_pointer++;
nr -= 32;
}
}
#define get_fd_set(nr,fsp,fdp) \
__get_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp))
#define set_fd_set(nr,fsp,fdp) \
__set_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp))
/*
* We can actually return ERESTARTSYS insetad of EINTR, but I'd
* like to be certain this leads to no problems. So I return
......@@ -134,29 +177,25 @@ int sys_select( unsigned long *buffer )
{
/* Perform the select(nd, in, out, ex, tv) system call. */
int i;
fd_set res_in, in = 0, *inp;
fd_set res_out, out = 0, *outp;
fd_set res_ex, ex = 0, *exp;
fd_set mask;
fd_set res_in, in, *inp;
fd_set res_out, out, *outp;
fd_set res_ex, ex, *exp;
int n;
struct timeval *tvp;
unsigned long timeout;
mask = get_fs_long(buffer++);
if (mask >= 32)
mask = ~0;
else
mask = ~((~0) << mask);
n = get_fs_long(buffer++);
if (n < 0)
return -EINVAL;
if (n > NR_OPEN)
n = NR_OPEN;
inp = (fd_set *) get_fs_long(buffer++);
outp = (fd_set *) get_fs_long(buffer++);
exp = (fd_set *) get_fs_long(buffer++);
tvp = (struct timeval *) get_fs_long(buffer);
if (inp)
in = mask & get_fs_long(inp);
if (outp)
out = mask & get_fs_long(outp);
if (exp)
ex = mask & get_fs_long(exp);
get_fd_set(n, inp, &in);
get_fd_set(n, outp, &out);
get_fd_set(n, exp, &ex);
timeout = 0xffffffff;
if (tvp) {
timeout = get_fs_long((unsigned long *)&tvp->tv_usec)/(1000000/HZ);
......@@ -164,7 +203,7 @@ int sys_select( unsigned long *buffer )
timeout += jiffies;
}
current->timeout = timeout;
i = do_select(in, out, ex, &res_in, &res_out, &res_ex);
i = do_select(n, &in, &out, &ex, &res_in, &res_out, &res_ex);
if (current->timeout > jiffies)
timeout = current->timeout - jiffies;
else
......@@ -181,17 +220,8 @@ int sys_select( unsigned long *buffer )
return i;
if (!i && (current->signal & ~current->blocked))
return -EINTR;
if (inp) {
verify_area(inp, 4);
put_fs_long(res_in,inp);
}
if (outp) {
verify_area(outp,4);
put_fs_long(res_out,outp);
}
if (exp) {
verify_area(exp,4);
put_fs_long(res_ex,exp);
}
set_fd_set(n, inp, &res_in);
set_fd_set(n, outp, &res_out);
set_fd_set(n, exp, &res_ex);
return i;
}
......@@ -15,8 +15,7 @@ static void cp_old_stat(struct inode * inode, struct old_stat * statbuf)
{
struct old_stat tmp;
if (inode->i_ino & 0xffff0000)
printk("Warning: using old stat() call on bigfs\n");
printk("Warning: using old stat() call. Recompile your binary.\n");
verify_area(statbuf,sizeof (*statbuf));
tmp.st_dev = inode->i_dev;
tmp.st_ino = inode->i_ino;
......@@ -69,9 +68,11 @@ static void cp_new_stat(struct inode * inode, struct new_stat * statbuf)
blocks += indirect;
}
tmp.st_blocks = blocks;
} else
tmp.st_blocks = (inode->i_blocks * inode->i_blksize) / 512;
tmp.st_blksize = 512;
tmp.st_blksize = BLOCK_SIZE;
} else {
tmp.st_blocks = inode->i_blocks;
tmp.st_blksize = inode->i_blksize;
}
memcpy_tofs(statbuf,&tmp,sizeof(tmp));
}
......
......@@ -9,63 +9,54 @@
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/proc_fs.h>
#include <linux/ext_fs.h>
#include <linux/msdos_fs.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/locks.h>
#include <asm/system.h>
#include <asm/segment.h>
/*
* The definition of file_systems that used to be here is now in
* filesystems.c. Now super.c contains no fs specific code. -- jrs
*/
void wait_for_keypress(void);
void fcntl_init_locks(void);
extern struct file_system_type file_systems[];
/* set_bit uses setb, as gas doesn't recognize setc */
#define set_bit(bitnr,addr) ({ \
register int __res __asm__("ax"); \
__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \
__res; })
extern void wait_for_keypress(void);
extern void fcntl_init_locks(void);
struct super_block super_block[NR_SUPER];
/* this is initialized in init/main.c */
dev_t ROOT_DEV = 0;
/* Move into include file later */
static struct file_system_type file_systems[] = {
{minix_read_super,"minix"},
{ext_read_super,"ext"},
{msdos_read_super,"msdos"},
{proc_read_super,"proc"},
{NULL,NULL}
};
/* end of include file */
struct file_system_type *get_fs_type(char *name)
{
int a;
if (!name)
return &file_systems[0];
for(a = 0 ; file_systems[a].read_super ; a++)
if (!strcmp(name,file_systems[a].name))
return(&file_systems[a]);
return(NULL);
return NULL;
}
void __wait_on_super(struct super_block * sb)
{
add_wait_queue(&sb->s_wait,&current->wait);
struct wait_queue wait = { current, NULL };
add_wait_queue(&sb->s_wait, &wait);
repeat:
current->state = TASK_UNINTERRUPTIBLE;
if (sb->s_lock) {
schedule();
goto repeat;
}
remove_wait_queue(&sb->s_wait,&current->wait);
remove_wait_queue(&sb->s_wait, &wait);
current->state = TASK_RUNNING;
}
......@@ -155,6 +146,43 @@ static struct super_block * read_super(dev_t dev,char *name,int flags,void *data
return s;
}
/*
* Unnamed block devices are dummy devices used by virtual
* filesystems which don't use real block-devices. -- jrs
*/
static char unnamed_dev_in_use[256];
static dev_t get_unnamed_dev(void)
{
static int first_use = 0;
int i;
if (first_use == 0) {
first_use = 1;
memset(unnamed_dev_in_use, 0, sizeof(unnamed_dev_in_use));
unnamed_dev_in_use[0] = 1; /* minor 0 (nodev) is special */
}
for (i = 0; i < 256; i++) {
if (!unnamed_dev_in_use[i]) {
unnamed_dev_in_use[i] = 1;
return (UNNAMED_MAJOR << 8) | i;
}
}
return 0;
}
static void put_unnamed_dev(dev_t dev)
{
if (!dev)
return;
if (!unnamed_dev_in_use[dev]) {
printk("put_unnamed_dev: trying to free unused device\n");
return;
}
unnamed_dev_in_use[dev] = 0;
}
static int do_umount(dev_t dev)
{
struct super_block * sb;
......@@ -173,38 +201,68 @@ static int do_umount(dev_t dev)
iput(sb->s_mounted);
sb->s_mounted = NULL;
if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
sb->s_op->write_super (sb);
sb->s_op->write_super(sb);
put_super(dev);
return 0;
}
int sys_umount(char * dev_name)
/*
* Now umount can handle mount points as well as block devices.
* This is important for filesystems which use unnamed block devices.
*
* There is a little kludge here with the dummy_inode. The current
* vfs release functions only use the r_dev field in the inode so
* we give them the info they need without using a real inode.
* If any other fields are ever needed by any block device release
* functions, they should be faked here. -- jrs
*/
int sys_umount(char * name)
{
struct inode * inode;
int dev,retval;
dev_t dev;
int retval;
struct inode dummy_inode;
struct file_operations * fops;
if (!suser())
return -EPERM;
retval = namei(dev_name,&inode);
retval = namei(name,&inode);
if (retval)
return retval;
dev = inode->i_rdev;
if (!S_ISBLK(inode->i_mode)) {
if (S_ISBLK(inode->i_mode)) {
dev = inode->i_rdev;
if (IS_NODEV(inode)) {
iput(inode);
return -EACCES;
}
} else if (S_ISDIR(inode->i_mode)) {
if (!inode || !inode->i_sb || inode != inode->i_sb->s_mounted) {
iput(inode);
return -EINVAL;
}
dev = inode->i_sb->s_dev;
iput(inode);
return -ENOTBLK;
}
if (IS_NODEV(inode)) {
memset(&dummy_inode, 0, sizeof(dummy_inode));
dummy_inode.i_rdev = dev;
inode = &dummy_inode;
} else {
iput(inode);
return -EACCES;
return -EINVAL;
}
if (MAJOR(dev) >= MAX_BLKDEV) {
iput(inode);
return -ENODEV;
return -ENXIO;
}
retval = do_umount(dev);
if (!retval && blkdev_fops[MAJOR(dev)] && blkdev_fops[MAJOR(dev)]->release)
blkdev_fops[MAJOR(dev)]->release(inode,NULL);
iput(inode);
if (!(retval = do_umount(dev))) {
fops = blkdev_fops[MAJOR(dev)];
if (fops && fops->release)
fops->release(inode,NULL);
if (MAJOR(dev) == UNNAMED_MAJOR)
put_unnamed_dev(dev);
}
if (inode != &dummy_inode)
iput(inode);
if (retval)
return retval;
sync_dev(dev);
......@@ -265,33 +323,51 @@ static int do_mount(dev_t dev, const char * dir, char * type, int flags, void *
* are talking to an older version that didn't understand them.
*/
int sys_mount(char * dev_name, char * dir_name, char * type,
unsigned long new_flags, void *data)
unsigned long new_flags, void * data)
{
struct file_system_type * fstype;
struct inode * inode;
struct file_operations * fops;
int dev;
dev_t dev;
int retval;
char tmp[100],*t;
char tmp[100], * t;
int i;
unsigned long flags = 0;
unsigned long page = 0;
if (!suser())
return -EPERM;
if (retval = namei(dev_name,&inode))
return retval;
dev = inode->i_rdev;
if (!S_ISBLK(inode->i_mode)) {
iput(inode);
return -ENOTBLK;
}
if (IS_NODEV(inode)) {
iput(inode);
return -EACCES;
}
if (MAJOR(dev) >= MAX_BLKDEV) {
iput(inode);
if (type) {
for (i = 0 ; i < 100 ; i++)
if (!(tmp[i] = get_fs_byte(type++)))
break;
t = tmp;
} else
t = NULL;
if (!(fstype = get_fs_type(t)))
return -ENODEV;
t = fstype->name;
if (fstype->requires_dev) {
if (retval = namei(dev_name,&inode))
return retval;
if (!S_ISBLK(inode->i_mode)) {
iput(inode);
return -ENOTBLK;
}
if (IS_NODEV(inode)) {
iput(inode);
return -EACCES;
}
dev = inode->i_rdev;
if (MAJOR(dev) >= MAX_BLKDEV) {
iput(inode);
return -ENXIO;
}
}
else {
if (!(dev = get_unnamed_dev()))
return -EMFILE;
inode = NULL;
}
fops = blkdev_fops[MAJOR(dev)];
if (fops && fops->open) {
......@@ -302,22 +378,18 @@ int sys_mount(char * dev_name, char * dir_name, char * type,
}
if ((new_flags & 0xffff0000) == 0xC0ED0000) {
flags = new_flags & 0xffff;
if (data && (unsigned long) data < TASK_SIZE)
if (data) {
if ((unsigned long) data >= TASK_SIZE) {
iput(inode);
return -EFAULT;
}
page = get_free_page(GFP_KERNEL);
i = TASK_SIZE - (unsigned long) data;
if (i < 0 || i > 4095)
i = 4095;
memcpy_fromfs((void *) page,data,i);
}
}
if (page) {
i = TASK_SIZE - (unsigned long) data;
if (i < 0 || i > 4095)
i = 4095;
memcpy_fromfs((void *) page,data,i);
}
if (type) {
for (i = 0 ; i < 100 ; i++)
if (!(tmp[i] = get_fs_byte(type++)))
break;
t = tmp;
} else
t = "minix";
retval = do_mount(dev,dir_name,t,flags,(void *) page);
free_page(page);
if (retval && fops && fops->release)
......@@ -328,39 +400,30 @@ int sys_mount(char * dev_name, char * dir_name, char * type,
void mount_root(void)
{
int i;
struct file_system_type * fs_type = file_systems;
struct super_block * p;
struct inode * mi;
if (32 != sizeof (struct minix_inode))
panic("bad i-node size");
for(i=0;i<NR_FILE;i++)
file_table[i].f_count=0;
struct file_system_type * fs_type;
struct super_block * sb;
struct inode * inode;
memset(file_table, 0, sizeof(file_table));
memset(super_block, 0, sizeof(super_block));
fcntl_init_locks();
if (MAJOR(ROOT_DEV) == 2) {
printk("Insert root floppy and press ENTER");
wait_for_keypress();
}
for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++) {
p->s_dev = 0;
p->s_blocksize = 0;
p->s_lock = 0;
p->s_wait = NULL;
p->s_mounted = p->s_covered = NULL;
}
while (fs_type->read_super && fs_type->name) {
p = read_super(ROOT_DEV,fs_type->name,0,NULL);
if (p) {
mi = p->s_mounted;
mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
p->s_covered = mi;
p->s_flags = 0;
current->pwd = mi;
current->root = mi;
for (fs_type = file_systems; fs_type->read_super; fs_type++) {
if (!fs_type->requires_dev)
continue;
sb = read_super(ROOT_DEV,fs_type->name,0,NULL);
if (sb) {
inode = sb->s_mounted;
inode->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
sb->s_covered = inode;
sb->s_flags = 0;
current->pwd = inode;
current->root = inode;
return;
}
fs_type++;
}
panic("Unable to mount root");
}
/* $Header: /sys/linux-0.97/include/asm/RCS/dma.h,v 1.4 1992/09/21 03:15:46 root Exp root $
* linux/include/asm/dma.h: Defines for using and allocating dma channels.
* Written by Hennus Bergman, 1992.
*
* High DMA channel support by Hannu Savolainen
*/
#ifndef _ASM_DMA_H
#define _ASM_DMA_H
#include <asm/io.h> /* need byte IO */
#include <linux/kernel.h> /* need panic() [FIXME] */
#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
#define outb outb_p
#endif
/* FIXME: better fix this code for dma channels>3!!!!!!! */
/*
* The routines below should in most cases (with optimizing on) result
* in equal or better code than similar code using macros.
......@@ -24,9 +23,16 @@
* that cross a 64k boundary. When the address reaches 0xNffff, it will wrap
* around to 0xN0000, rather than increment to 0x(N+1)0000 !
* Make sure you align your buffers properly! Runtime check recommended.
****** Correction!!!!!
* Channels 4-7 16 bit channels and capable to cross 64k boundaries
* but not 128k boundaries. Transfer count must be given as words.
* Maximum transfer size is 65k words = 128kb.
*
* NOTE2: DMA1..3 can only use the lower 1MB of physical memory. DMA4..7
* can access the lower 16MB. There are people with >16MB, so beware!
* **** Not correct!!! All channels are able to access the first 16MB *******
*/
......@@ -38,6 +44,7 @@
* The first DMA controller uses bytes, the second words.
*
* Where are the page regs for the second DMA controller?????
* (ch 5=0x8b, 6=0x89, 7=0x8a)
*/
......@@ -52,16 +59,18 @@
#define DMA1_MODE_REG 0x0B /* set modes for individual channels */
#define DMA1_CLEAR_FF_REG 0x0C /* Write 0 for LSB, 1 for MSB */
#define DMA1_RESET_REG 0x0D /* Write here to reset DMA controller */
/* don't have much info on the second DMA controller... */
#define DMA2_CMD_REG 0xD0 /* DMA command register */
#define DMA2_STAT_REG 0xD0 /* DMA status register */
#define DMA2_MASK_REG 0xD4
#define DMA2_MODE_REG 0xD6
/* #define DMA2_CLEAR_FF_REG 0xD8 -- pure guessing.... */
/************* #error This needs more work!!!!!!!*************/
#define DMA2_CLEAR_FF_REG 0xD8
#define DMA2_RESET_REG 0xDA /* Write here to reset DMA controller */
#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
#define DMA_MODE_CASCADE 0xC0 /* cascade mode (for DMA2 controller only) */
/* cascade mode (for DMA2 controller only) */
#define DMA_MODE_CASCADE 0x40 /* 0xC0 */
/* enable/disable a specific DMA channel */
......@@ -93,11 +102,7 @@ static __inline__ void clear_dma_ff(unsigned int dmanr)
if (dmanr<=3)
outb(0, DMA1_CLEAR_FF_REG);
else
#ifdef DMA2_CLEAR_FF_REG
outb(0, DMA2_CLEAR_FF_REG);
#else
panic("dma.h: Don't have CLEAR_FF for high dma channels!\n");
#endif
}
/* set mode (above) for a specific DMA channel */
......@@ -130,10 +135,16 @@ static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
outb(pagenr, 0x82);
break;
case 4:
outb(pagenr, 0x8f);
break;
case 5:
outb(pagenr, 0x8b);
break;
case 6:
outb(pagenr, 0x89);
break;
case 7:
panic("dma.h: don't know how to set DMA page regs for channels>3");
outb(pagenr, 0x8a);
break;
}
}
......@@ -141,12 +152,20 @@ static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
/* Set transfer address & page bits for specific DMA channel.
* Assumes dma flipflop is clear.
*
* NOTE! A word address is assumed for the channels 4 to 7.
*/
static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
{
unsigned int io_base = (dmanr<=3)? IO_DMA1_BASE : IO_DMA2_BASE;
unsigned int page = a>>16;
if (dmanr>3) page &= 0xfe; /* The last bit is never used */
set_dma_page(dmanr, page);
if (dmanr>3) a >>= 1;
set_dma_page(dmanr, a>>16);
outb(a & 0xff, ((dmanr&3)<<1) + io_base);
outb((a>>8) & 0xff, ((dmanr&3)<<1) + io_base);
}
......@@ -160,9 +179,12 @@ static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
*/
static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
{
unsigned int dc = count - 1;
unsigned int dc;
unsigned int io_base = (dmanr<=3)? IO_DMA1_BASE : IO_DMA2_BASE;
if (dmanr>3) count >>=1;
dc = count - 1;
outb(dc & 0xff, ((dmanr&3)<<1) + 1 + io_base);
outb((dc>>8) & 0xff, ((dmanr&3)<<1) + 1 + io_base);
}
......
/*
* NOTE!!! memcpy(dest,src,n) assumes ds=es=normal data segment. This
* goes for all kernel functions (ds=es=kernel space, fs=local data,
* gs=null), as well as for all well-behaving user programs (ds=es=
* user data space). This is NOT a bug, as any user program that changes
* es deserves to die if it isn't careful.
*/
#if 0
#define memcpy(dest,src,n) ({ \
void * _res = dest; \
__asm__ __volatile__ ("cld;rep;movsb" \
::"D" ((long)(_res)),"S" ((long)(src)),"c" ((long) (n)) \
:"di","si","cx"); \
_res; \
})
#else
/* this is basically memcpy_tofs. It should be faster.
I've reorder it. This should be a little faster. -RAB */
#define memcpy(dest, src, n) f_memcpy(dest, src, n)
extern inline void * f_memcpy(void * to, void * from, unsigned long n)
{
__asm__("cld\n\t"
"movl %%edx, %%ecx\n\t"
"shrl $2,%%ecx\n\t"
"rep ; movsl\n\t"
"testb $1,%%dl\n\t"
"je 1f\n\t"
"movsb\n"
"1:\ttestb $2,%%dl\n\t"
"je 2f\n\t"
"movsw\n"
"2:\n"
::"d" (n),"D" ((long) to),"S" ((long) from)
: "cx","di","si");
return (to);
}
#endif
......@@ -99,6 +99,16 @@ defined(CONFIG_CHR_DEV_ST)
#endif
#endif
/*
* Choose filesystems here.
*/
#define MINIX_FS
#define EXT_FS
#define MSDOS_FS
#define PROC_FS
#undef NFS_FS
#ifdef CONFIG_DISTRIBUTION
#include <linux/config.dist.h>
#else
......
......@@ -15,7 +15,7 @@
/* devices are as follows: (same as minix, so we can use the minix
* file system. These are major numbers.)
*
* 0 - unused (nodev)
* 0 - unnamed (minor 0 = true nodev)
* 1 - /dev/mem
* 2 - /dev/fd
* 3 - /dev/hd
......@@ -27,8 +27,14 @@
* 9 - /dev/st
* 10 - mice
* 11 - scsi cdrom
* 12 -
* 13 -
* 14 - sound card (?)
* 15 -
*/
#define UNNAMED_MAJOR 0
#define MAY_EXEC 1
#define MAY_WRITE 2
#define MAY_READ 4
......@@ -129,6 +135,9 @@ struct inode {
struct wait_queue * i_wait;
struct file_lock * i_flock;
struct vm_area_struct * i_mmap;
struct inode * i_next, * i_prev;
struct inode * i_hash_next, * i_hash_prev;
struct inode * i_bound_to, * i_bound_by;
unsigned short i_count;
unsigned short i_flags;
unsigned char i_lock;
......@@ -194,7 +203,7 @@ struct file_operations {
int (*lseek) (struct inode *, struct file *, off_t, int);
int (*read) (struct inode *, struct file *, char *, int);
int (*write) (struct inode *, struct file *, char *, int);
int (*readdir) (struct inode *, struct file *, struct dirent *, int count);
int (*readdir) (struct inode *, struct file *, struct dirent *, int);
int (*select) (struct inode *, struct file *, int, select_table *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned int);
int (*mmap) (void);
......@@ -214,23 +223,25 @@ struct inode_operations {
int (*mknod) (struct inode *,const char *,int,int,int);
int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int);
int (*readlink) (struct inode *,char *,int);
int (*follow_link) (struct inode *, struct inode *, int flag, int mode, struct inode ** res_inode);
int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **);
int (*bmap) (struct inode *,int);
void (*truncate) (struct inode *);
};
struct super_operations {
void (*read_inode)(struct inode *inode);
void (*write_inode) (struct inode *inode);
void (*put_inode) (struct inode *inode);
void (*put_super)(struct super_block *sb);
void (*write_super) (struct super_block *sb);
void (*statfs) (struct super_block *sb, struct statfs *buf);
void (*read_inode) (struct inode *);
int (*notify_change) (struct inode *);
void (*write_inode) (struct inode *);
void (*put_inode) (struct inode *);
void (*put_super) (struct super_block *);
void (*write_super) (struct super_block *);
void (*statfs) (struct super_block *, struct statfs *);
};
struct file_system_type {
struct super_block *(*read_super)(struct super_block *sb,void *mode);
struct super_block *(*read_super) (struct super_block *, void *);
char *name;
int requires_dev;
};
extern struct file_operations * chrdev_fops[MAX_CHRDEV];
......@@ -261,6 +272,7 @@ extern void sync_inodes(dev_t dev);
extern void sync_dev(dev_t dev);
extern void sync_supers(dev_t dev);
extern int bmap(struct inode * inode,int block);
extern int notify_change(struct inode * inode);
extern int namei(const char * pathname, struct inode ** res_inode);
extern int lnamei(const char * pathname, struct inode ** res_inode);
extern int permission(struct inode * inode,int mask);
......@@ -270,11 +282,12 @@ extern int do_mknod(const char * filename, int mode, dev_t dev);
extern void iput(struct inode * inode);
extern struct inode * iget(struct super_block * sb,int nr);
extern struct inode * get_empty_inode(void);
extern void clear_inode(struct inode *);
extern struct inode * get_pipe_inode(void);
extern struct file * get_empty_filp(void);
extern struct buffer_head * get_hash_table(dev_t dev, int block, int size);
extern struct buffer_head * getblk(dev_t dev, int block, int size);
extern void ll_rw_block(int rw, struct buffer_head * bh);
extern void ll_rw_block(int rw, int nr, struct buffer_head * bh[]);
extern void ll_rw_page(int rw, int dev, int nr, char * buffer);
extern void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buffer);
extern void brelse(struct buffer_head * buf);
......
......@@ -51,7 +51,10 @@
#define BBD_ERR 0x80 /* ? */
/* HDIO_GETGEO is the preferred choice - HDIO_REQ will be removed at some
later date */
#define HDIO_REQ 0x301
#define HDIO_GETGEO 0x301
struct hd_geometry {
unsigned char heads;
unsigned char sectors;
......
......@@ -10,10 +10,11 @@ volatile void panic(const char * str);
volatile void do_exit(long error_code);
unsigned long simple_strtoul(const char *,char **,unsigned int);
int printk(const char * fmt, ...);
void * malloc(unsigned int size);
void free_s(void * obj, int size);
#define free(x) free_s((x), 0)
void * kmalloc(unsigned int size, int priority);
void kfree_s(void * obj, int size);
#define kfree(x) kfree_s((x), 0)
/*
* This is defined as a macro, but at some point this might become a
......
......@@ -3,21 +3,29 @@
#define NAME_MAX 255
#define NR_OPEN 32
/*
* It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix
* that later. Anyway, now the file code is no longer dependent
* on bitmaps in unsigned longs, but uses the new fd_set structure..
*
* Some programs (notably those using select()) may have to be
* recompiled to take full advantage of the new limits..
*/
#define NR_OPEN 256
#define NR_INODE 128
#define NR_FILE 128
#define NR_SUPER 8
#define NR_SUPER 16
#define NR_HASH 997
#define NR_FILE_LOCKS 32
#define BLOCK_SIZE 1024
#define BLOCK_SIZE_BITS 10
#define MAX_CHRDEV 16
#define MAX_BLKDEV 16
#define MAX_CHRDEV 32
#define MAX_BLKDEV 32
#define NGROUPS_MAX 32 /* supplemental group IDs are available */
#define ARG_MAX 131072 /* # bytes of args + environ for exec() */
#define CHILD_MAX 999 /* no limit :-) */
#define OPEN_MAX 32 /* # open files a process may have */
#define OPEN_MAX 256 /* # open files a process may have */
#define LINK_MAX 127 /* # links a file may have */
#define MAX_CANON 255 /* size of the canonical input queue */
#define MAX_INPUT 255 /* size of the type-ahead buffer */
......
#ifndef _LINUX_MATH_EMU_H
#define _LINUX_MATH_EMU_H
#include <linux/sched.h>
struct fpu_reg {
char sign;
char tag;
long exp;
unsigned sigl;
unsigned sigh;
};
struct info {
long ___orig_eip;
......@@ -25,6 +31,7 @@ struct info {
long ___ss;
};
#if 0
#define EAX (info->___eax)
#define EBX (info->___ebx)
#define ECX (info->___ecx)
......@@ -41,145 +48,11 @@ struct info {
#define FS (*(unsigned short *) &(info->___fs))
#define CS (*(unsigned short *) &(info->___cs))
#define SS (*(unsigned short *) &(info->___ss))
#endif
void __math_abort(struct info *, unsigned int);
#define math_abort(x,y) \
(((volatile void (*)(struct info *,unsigned int)) __math_abort)((x),(y)))
/*
* Gcc forces this stupid alignment problem: I want to use only two longs
* for the temporary real 64-bit mantissa, but then gcc aligns out the
* structure to 12 bytes which breaks things in math_emulate.c. Shit. I
* want some kind of "no-alignt" pragma or something.
*/
typedef struct {
long a,b;
short exponent;
} temp_real;
typedef struct {
short m0,m1,m2,m3;
short exponent;
} temp_real_unaligned;
#define real_to_real(a,b) \
((*(long long *) (b) = *(long long *) (a)),((b)->exponent = (a)->exponent))
typedef struct {
long a,b;
} long_real;
typedef long short_real;
typedef struct {
long a,b;
short sign;
} temp_int;
struct swd {
int ie:1;
int de:1;
int ze:1;
int oe:1;
int ue:1;
int pe:1;
int sf:1;
int ir:1;
int c0:1;
int c1:1;
int c2:1;
int top:3;
int c3:1;
int b:1;
};
#define I387 (current->tss.i387)
#define SWD (*(struct swd *) &I387.swd)
#define ROUNDING ((I387.cwd >> 10) & 3)
#define PRECISION ((I387.cwd >> 8) & 3)
#define BITS24 0
#define BITS53 2
#define BITS64 3
#define ROUND_NEAREST 0
#define ROUND_DOWN 1
#define ROUND_UP 2
#define ROUND_0 3
#define CONSTZ (temp_real_unaligned) {0x0000,0x0000,0x0000,0x0000,0x0000}
#define CONST1 (temp_real_unaligned) {0x0000,0x0000,0x0000,0x8000,0x3FFF}
#define CONSTPI (temp_real_unaligned) {0xC235,0x2168,0xDAA2,0xC90F,0x4000}
#define CONSTLN2 (temp_real_unaligned) {0x79AC,0xD1CF,0x17F7,0xB172,0x3FFE}
#define CONSTLG2 (temp_real_unaligned) {0xF799,0xFBCF,0x9A84,0x9A20,0x3FFD}
#define CONSTL2E (temp_real_unaligned) {0xF0BC,0x5C17,0x3B29,0xB8AA,0x3FFF}
#define CONSTL2T (temp_real_unaligned) {0x8AFE,0xCD1B,0x784B,0xD49A,0x4000}
#define set_IE() (I387.swd |= 1)
#define set_DE() (I387.swd |= 2)
#define set_ZE() (I387.swd |= 4)
#define set_OE() (I387.swd |= 8)
#define set_UE() (I387.swd |= 16)
#define set_PE() (I387.swd |= 32)
#define set_C0() (I387.swd |= 0x0100)
#define set_C1() (I387.swd |= 0x0200)
#define set_C2() (I387.swd |= 0x0400)
#define set_C3() (I387.swd |= 0x4000)
/* ea.c */
char * ea(struct info * __info, unsigned short __code);
/* convert.c */
void frndint(const temp_real * __a, temp_real * __b);
void short_to_temp(const short_real * __a, temp_real * __b);
void long_to_temp(const long_real * __a, temp_real * __b);
void temp_to_short(const temp_real * __a, short_real * __b);
void temp_to_long(const temp_real * __a, long_real * __b);
void real_to_int(const temp_real * __a, temp_int * __b);
void int_to_real(const temp_int * __a, temp_real * __b);
/* get_put.c */
void get_short_real(temp_real *, struct info *, unsigned short);
void get_long_real(temp_real *, struct info *, unsigned short);
void get_temp_real(temp_real *, struct info *, unsigned short);
void get_short_int(temp_real *, struct info *, unsigned short);
void get_long_int(temp_real *, struct info *, unsigned short);
void get_longlong_int(temp_real *, struct info *, unsigned short);
void get_BCD(temp_real *, struct info *, unsigned short);
void put_short_real(const temp_real *, struct info *, unsigned short);
void put_long_real(const temp_real *, struct info *, unsigned short);
void put_temp_real(const temp_real *, struct info *, unsigned short);
void put_short_int(const temp_real *, struct info *, unsigned short);
void put_long_int(const temp_real *, struct info *, unsigned short);
void put_longlong_int(const temp_real *, struct info *, unsigned short);
void put_BCD(const temp_real *, struct info *, unsigned short);
/* add.c */
void fadd(const temp_real *, const temp_real *, temp_real *);
/* mul.c */
void fmul(const temp_real *, const temp_real *, temp_real *);
/* div.c */
void fdiv(const temp_real *, const temp_real *, temp_real *);
/* sqrt.c */
void fsqrt(const temp_real *, temp_real *);
/* compare.c */
void fcom(const temp_real *, const temp_real *);
void fucom(const temp_real *, const temp_real *);
void ftst(const temp_real *);
#endif
......@@ -47,41 +47,11 @@ struct vm_operations_struct {
int (*share)(struct vm_area_struct * old, struct vm_area_struct * new, unsigned long address);
};
/*
* BAD_PAGE is the page that is used for page faults when linux
* is out-of-memory. Older versions of linux just did a
* do_exit(), but using this instead means there is less risk
* for a process dying in kernel mode, possibly leaving a inode
* unused etc..
*
* BAD_PAGETABLE is the accompanying page-table: it is initialized
* to point to BAD_PAGE entries.
*/
extern unsigned long inline __bad_page(void)
{
extern char empty_bad_page[PAGE_SIZE];
__asm__ __volatile__("cld ; rep ; stosl"
::"a" (0),
"D" ((long) empty_bad_page),
"c" (1024)
:"di","cx");
return (unsigned long) empty_bad_page;
}
#define BAD_PAGE __bad_page()
extern unsigned long __bad_page(void);
extern unsigned long __bad_pagetable(void);
extern unsigned long inline __bad_pagetable(void)
{
extern char empty_bad_page_table[PAGE_SIZE];
__asm__ __volatile__("cld ; rep ; stosl"
::"a" (7+BAD_PAGE),
"D" ((long) empty_bad_page_table),
"c" (1024)
:"di","cx");
return (unsigned long) empty_bad_page_table;
}
#define BAD_PAGETABLE __bad_pagetable()
#define BAD_PAGE __bad_page()
extern volatile short free_page_ptr; /* used by malloc and tcp/ip. */
......
......@@ -19,6 +19,8 @@
#define PTRACE_ATTACH 0x10
#define PTRACE_DETACH 0x11
#define PTRACE_SYSCALL 24
/* use ptrace (3 or 6, pid, PT_EXCL, data); to read or write
the processes registers. */
......
#ifndef _LINUX_SCHED_H
#define _LINUX_SCHED_H
/*
* define DEBUG if you want the wait-queues to have some extra
* debugging code. It's not normally used, but might catch some
* wait-queue coding errors.
*
* #define DEBUG
*/
#define HZ 100
/*
......@@ -55,10 +64,7 @@
#include <linux/param.h>
#include <linux/resource.h>
#include <linux/vm86.h>
#if (NR_OPEN > 32)
#error "Currently the close-on-exec-flags and select masks are in one long, max 32 files/proc"
#endif
#include <linux/math_emu.h>
#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
......@@ -100,7 +106,10 @@ union i387_union {
long foo;
long fos;
long top;
long regs_space[32]; /* 8*16 bytes for each FP-reg = 112 bytes */
struct fpu_reg regs[8]; /* 8*16 bytes for each FP-reg = 112 bytes */
unsigned char lookahead;
struct info *info;
unsigned long entry_eip;
} soft;
};
......@@ -141,6 +150,8 @@ struct task_struct {
struct sigaction sigaction[32];
long blocked; /* bitmap of masked signals */
unsigned long saved_kernel_stack;
unsigned long kernel_stack_page;
unsigned int flags; /* per process flags, defined below */
/* various fields */
int exit_code;
int dumpable:1;
......@@ -158,7 +169,6 @@ struct task_struct {
* For ease of programming... Normal sleeps don't need to
* keep track of a wait-queue: every task has an entry of it's own
*/
struct wait_queue wait;
unsigned short uid,euid,suid;
unsigned short gid,egid,sgid;
unsigned long timeout;
......@@ -168,7 +178,6 @@ struct task_struct {
unsigned long min_flt, maj_flt;
unsigned long cmin_flt, cmaj_flt;
struct rlimit rlim[RLIM_NLIMITS];
unsigned int flags; /* per process flags, defined below */
unsigned short used_math;
unsigned short rss; /* number of resident pages */
char comm[8];
......@@ -190,9 +199,9 @@ struct task_struct {
} libraries[MAX_SHARED_LIBS];
int numlibraries;
struct file * filp[NR_OPEN];
unsigned long close_on_exec;
/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
struct desc_struct ldt[3];
fd_set close_on_exec;
/* ldt for this task 0 - zero 1 - cs 2 - ds&ss, rest unused */
struct desc_struct ldt[32];
/* tss for this task */
struct tss_struct tss;
};
......@@ -203,6 +212,7 @@ struct task_struct {
#define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */
/* Not implemented yet, only for 486*/
#define PF_PTRACED 0x00000010 /* set if ptrace (0) has been called. */
#define PF_TRACESYS 0x00000020 /* tracing system calls */
/*
* INIT_TASK is used to set up the first task table, touch at
......@@ -210,32 +220,33 @@ struct task_struct {
*/
#define INIT_TASK \
/* state etc */ { 0,15,15, \
/* signals */ 0,{{},},0,0, \
/* signals */ 0,{{},},0,0,0, \
/* flags */ 0, \
/* ec,brk... */ 0,0,0,0,0,0,0,0, \
/* pid etc.. */ 0,0,0,0, \
/* suppl grps*/ {NOGROUP,}, \
/* proc links*/ &init_task.task,&init_task.task,NULL,NULL,NULL, \
/* wait queue*/ {&init_task.task,NULL}, \
/* proc links*/ &init_task,&init_task,NULL,NULL,NULL, \
/* uid etc */ 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}, \
{0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}}, \
/* flags */ 0, \
/* math */ 0, \
/* rss */ 2, \
/* comm */ "swapper", \
/* vm86_info */ NULL, 0, \
/* fs info */ 0,-1,0022,NULL,NULL,NULL,NULL, \
/* libraries */ { { NULL, 0, 0}, }, 0, \
/* filp */ {NULL,}, 0, \
/* filp */ {NULL,}, \
/* cloe */ {0,}, \
{ \
{0,0}, \
/* ldt */ {0x9f,0xc0c0fa00}, \
{0x9f,0xc0c0f200} \
{0x9f,0xc0c0f200}, \
}, \
/*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&swapper_pg_dir,\
/*tss*/ {0,sizeof(init_kernel_stack) + (long) &init_kernel_stack, \
0x10,0,0,0,0,(long) &swapper_pg_dir,\
0,0,0,0,0,0,0,0, \
0,0,0x17,0x17,0x17,0x17,0x17,0x17, \
_LDT(0),0x80000000,{0xffffffff}, \
......@@ -368,26 +379,49 @@ extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue *
{
unsigned long flags;
struct wait_queue * tmp;
#ifdef DEBUG
unsigned long ok = 0;
#endif
__asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
if ((*p == wait) && ((*p = wait->next) == wait)) {
if ((*p == wait) &&
#ifdef DEBUG
(ok = 1) &&
#endif
((*p = wait->next) == wait)) {
*p = NULL;
} else {
tmp = wait;
while (tmp->next != wait)
while (tmp->next != wait) {
tmp = tmp->next;
#ifdef DEBUG
if (tmp == *p)
ok = 1;
#endif
}
tmp->next = wait->next;
}
wait->next = NULL;
__asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
#ifdef DEBUG
if (!ok) {
printk("removed wait_queue not on list.\n");
printk("list = %08x, queue = %08x\n",p,wait);
__asm__("call 1f\n1:\tpopl %0":"=r" (ok));
printk("eip = %08x\n",ok);
}
#endif
}
extern inline void select_wait(struct wait_queue ** wait_address, select_table * p)
{
struct select_table_entry * entry = p->entry + p->nr;
struct select_table_entry * entry;
if (!wait_address)
if (!p || !wait_address)
return;
if (p->nr >= __MAX_SELECT_TABLE_ENTRIES)
return;
entry = p->entry + p->nr;
entry->wait_address = wait_address;
entry->wait.task = current;
entry->wait.next = NULL;
......
......@@ -11,11 +11,11 @@ struct timezone {
int tz_dsttime; /* type of dst correction */
};
#define FD_SETSIZE (8*sizeof(fd_set))
#define FD_SET(fd,fdsetp) (*(fdsetp) |= (1 << (fd)))
#define FD_CLR(fd,fdsetp) (*(fdsetp) &= ~(1 << (fd)))
#define FD_ISSET(fd,fdsetp) ((*(fdsetp) >> fd) & 1)
#define FD_ZERO(fdsetp) (*(fdsetp) = 0)
#define FD_SETSIZE __FD_SETSIZE
#define FD_SET(fd,fdsetp) __FD_SET(fd,fdsetp)
#define FD_CLR(fd,fdsetp) __FD_CLR(fd,fdsetp)
#define FD_ISSET(fd,fdsetp) __FD_ISSET(fd,fdsetp)
#define FD_ZERO(fdsetp) __FD_ZERO(fdsetp)
/*
* Names of the interval timers, and structure
......
......@@ -32,6 +32,7 @@
#define FLOPPY_TIMER 17
#define SCSI_TIMER 18
#define NET_TIMER 19
#define SOUND_TIMER 20
struct timer_struct {
unsigned long expires;
......
......@@ -63,7 +63,41 @@ typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned long tcflag_t;
typedef unsigned long fd_set;
/*
* This allows for 256 file descriptors: if NR_OPEN is ever grown beyond that
* you'll have to change this too. But 256 fd's seem to be enough even for such
* "real" unices like SunOS, so hopefully this is one limit that doesn't have
* to be changed.
*
* Note that POSIX wants the FD_CLEAR(fd,fdsetp) defines to be in <sys/time.h>
* (and thus <linux/time.h>) - but this is a more logical place for them. Solved
* by having dummy defines in <sys/time.h>.
*/
#define __FDSET_LONGS 8
typedef struct fd_set {
unsigned long fd_mask[__FDSET_LONGS];
} fd_set;
#define __FD_SETSIZE (__FDSET_LONGS*32)
#define __FD_SET(fd,fdsetp) \
__asm__ __volatile__("btsl %1,%0":"=m" (*(struct fd_set *)fdsetp):"r" ((int) fd))
#define __FD_CLR(fd,fdsetp) \
__asm__ __volatile__("btrl %1,%0":"=m" (*(struct fd_set *)fdsetp):"r" ((int) fd))
#define __FD_ISSET(fd,fdsetp) \
({ char __result; \
__asm__ __volatile__("btl %1,%2 ; setb %0" \
:"=q" (__result) \
:"r" ((int) fd),"m" (*(struct fd_set *) fdsetp)); \
__result; })
#define __FD_ZERO(fdsetp) \
__asm__ __volatile__("cld ; rep ; stosl" \
:"=m" (*(struct fd_set *) fdsetp) \
:"a" (0), "c" (__FDSET_LONGS), "D" ((struct fd_set *) fdsetp) \
:"cx","di")
struct ustat {
daddr_t f_tfree;
......
#ifndef _LINUX_WAIT_H
#define _LINUX_WAIT_H
#include <linux/limits.h>
#define WNOHANG 1
#define WUNTRACED 2
......@@ -16,7 +14,9 @@ typedef struct select_table_struct {
struct select_table_entry {
struct wait_queue wait;
struct wait_queue ** wait_address;
} entry[NR_OPEN*3];
} * entry;
} select_table;
#define __MAX_SELECT_TABLE_ENTRIES (4096 / sizeof (struct select_table_entry))
#endif
This diff is collapsed.
......@@ -28,7 +28,7 @@ wm-FPU-emu is an FPU emulator for Linux. It is derived from wm-emu387
which is my 80387 emulator for djgpp (gcc under msdos); wm-emu387 was
in turn based upon emu387 which was written by DJ Delorie for djgpp.
The interface to the Linux kernel is based upon the original Linux
math emulator.
math emulator by Linus Torvalds.
My target FPU for wm-FPU-emu is that described in the Intel486
Programmer's Reference Manual (1992 edition). Numerous facets of the
......@@ -66,13 +66,25 @@ Numeric algorithms:
"optimal" polynomial approximations. My definition of "optimal" was
based upon getting good accuracy with reasonable speed.
--Bill Metzenthen
The code of the emulator is complicated slightly by the need to
account for a limited form of re-entrancy. Normally, the emulator will
emulate each FPU instruction to completion without interruption.
However, it may happen that when the emulator is accessing the user
memory space, swapping may be needed. In this case the emulator may be
temporarily suspended while disk i/o takes place. During this time
another process may use the emulator, thereby changing some static
variables (eg FPU_st0_ptr, etc). The code which accesses user memory
is confined to five files:
fpu_entry.c
reg_ld_str.c
load_store.c
get_address.c
errors.c
----------------------- Limitations of wm-FPU-emu -----------------------
There are a number of differences between the current wm-FPU-emu
(version ALPHA 0.5) and the 80486 FPU (apart from bugs). Some of the
(version ALPHA 0.7) and the 80486 FPU (apart from bugs). Some of the
more important differences are listed below:
Internal computations do not use de-normal numbers (but External
......@@ -93,10 +105,6 @@ The functions which load/store the FPU state are partially implemented,
but the implementation should be sufficient for handling FPU errors etc
in 32 bit protected mode.
--Bill Metzenthen
October 1992
----------------------- Performance of wm-FPU-emu -----------------------
Speed.
......@@ -132,9 +140,9 @@ function Turbo C djgpp 1.06 WM-emu387 wm-FPU-emu
exp() 479.1 6619.2 469.1 850.8
The performance under Linux can be improved if look-ahead code is used.
WM-emu387 uses such code. The following results show the improvement
which can be obtained under Linux. Also given are the times for the
The performance under Linux is improved by the use of look-ahead code.
The following results show the improvement which is obtained under
Linux due to the look-ahead code. Also given are the times for the
original Linux emulator with the 4.1 'soft' lib.
[ Linus' note: I changed look-ahead to be the default under linux, as
......
/*---------------------------------------------------------------------------+
| reg_constant.h |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
+---------------------------------------------------------------------------*/
#ifndef _REG_CONSTANT_H_
#define _REG_CONSTANT_H_
#include "fpu_emu.h"
extern FPU_REG CONST_1;
extern FPU_REG CONST_2;
extern FPU_REG CONST_HALF;
extern FPU_REG CONST_L2T;
extern FPU_REG CONST_L2E;
extern FPU_REG CONST_PI;
extern FPU_REG CONST_PI2;
extern FPU_REG CONST_PI4;
extern FPU_REG CONST_LG2;
extern FPU_REG CONST_LN2;
extern FPU_REG CONST_Z;
extern FPU_REG CONST_PINF;
extern FPU_REG CONST_INF;
extern FPU_REG CONST_MINF;
extern FPU_REG CONST_QNaN;
#endif _REG_CONSTANT_H_
......@@ -9,6 +9,13 @@
| |
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
| Note: |
| The file contains code which accesses user memory. |
| Emulator static data may change when user memory is accessed, due to |
| other processes using the emulator while swapping is in progress. |
+---------------------------------------------------------------------------*/
#include <linux/signal.h>
#include <asm/segment.h>
......@@ -21,17 +28,17 @@
#include "reg_constant.h"
#include "version.h"
extern unsigned char FPU_lookahead;
/* */
#undef PRINT_MESSAGES
/* */
void Un_impl(void)
{
unsigned char byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP);
unsigned char byte1, FPU_modrm;
RE_ENTRANT_CHECK_OFF
byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP);
FPU_modrm = get_fs_byte(1 + (unsigned char *) FPU_ORIG_EIP);
printk("Unimplemented FPU Opcode at eip=%p : %02x ",
FPU_ORIG_EIP, byte1);
......@@ -40,6 +47,7 @@ void Un_impl(void)
printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
else
printk("/%d\n", (FPU_modrm >> 3) & 7);
RE_ENTRANT_CHECK_ON
EXCEPTION(EX_Invalid);
......@@ -53,7 +61,11 @@ void emu_printall()
int i;
static char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR",
"DeNorm", "Inf", "NaN", "Empty" };
unsigned char byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP);
unsigned char byte1, FPU_modrm;
RE_ENTRANT_CHECK_OFF
byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP);
FPU_modrm = get_fs_byte(1 + (unsigned char *) FPU_ORIG_EIP);
#ifdef DEBUGGING
if ( status_word & SW_B ) printk("SW: backward compatibility (=ES)\n");
......@@ -103,7 +115,7 @@ printk(" CW: ic=%d rc=%d%d pc=%d%d iem=%d ef=%d%d%d%d%d%d\n",
for ( i = 0; i < 8; i++ )
{
struct reg *r = &st(i);
FPU_REG *r = &st(i);
switch (r->tag)
{
case TW_Empty:
......@@ -140,6 +152,7 @@ printk(" CW: ic=%d rc=%d%d pc=%d%d iem=%d ef=%d%d%d%d%d%d\n",
(long)(FPU_loaded_data.sigl & 0xFFFF),
FPU_loaded_data.exp - EXP_BIAS + 1);
printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
RE_ENTRANT_CHECK_ON
}
......@@ -224,6 +237,7 @@ void exception(int n)
status_word &= ~SW_C1;
}
RE_ENTRANT_CHECK_OFF
if ( (~control_word & n & CW_EXM) || (n == EX_INTERNAL) )
{
#ifdef PRINT_MESSAGES
......@@ -257,6 +271,7 @@ void exception(int n)
send_sig(SIGFPE, current, 1);
}
RE_ENTRANT_CHECK_ON
#ifdef __DEBUG__
math_abort(FPU_info,SIGFPE);
......@@ -268,9 +283,9 @@ void exception(int n)
/* Real operation attempted on two operands, one a NaN */
void real_2op_NaN(REG *a, REG *b, REG *dest)
void real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
{
REG *x;
FPU_REG *x;
x = a;
if (a->tag == TW_NaN)
......@@ -309,7 +324,7 @@ void real_2op_NaN(REG *a, REG *b, REG *dest)
}
/* Invalid arith operation on valid registers */
void arith_invalid(REG *dest)
void arith_invalid(FPU_REG *dest)
{
if ( control_word & EX_Invalid )
......@@ -326,7 +341,7 @@ void arith_invalid(REG *dest)
/* Divide a finite number by zero */
void divide_by_zero(int sign, REG *dest)
void divide_by_zero(int sign, FPU_REG *dest)
{
if ( control_word & EX_ZeroDiv )
......@@ -343,7 +358,7 @@ void divide_by_zero(int sign, REG *dest)
}
void arith_overflow(REG *dest)
void arith_overflow(FPU_REG *dest)
{
if ( control_word & EX_Overflow )
......@@ -367,7 +382,7 @@ void arith_overflow(REG *dest)
}
void arith_underflow(REG *dest)
void arith_underflow(FPU_REG *dest)
{
if ( control_word & EX_Underflow )
......@@ -395,7 +410,7 @@ void stack_overflow(void)
{
/* The masked response */
top--;
reg_move(&CONST_QNaN, st0_ptr = &st(0));
reg_move(&CONST_QNaN, FPU_st0_ptr = &st(0));
}
EXCEPTION(EX_StackOver);
......@@ -411,7 +426,7 @@ void stack_underflow(void)
if ( control_word & EX_Invalid )
{
/* The masked response */
reg_move(&CONST_QNaN, st0_ptr);
reg_move(&CONST_QNaN, FPU_st0_ptr);
}
EXCEPTION(EX_StackUnder);
......
......@@ -16,14 +16,14 @@
void fadd__()
{
/* fadd st,st(i) */
reg_add(st0_ptr, &st(FPU_rm), st0_ptr);
reg_add(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr);
}
void fmul__()
{
/* fmul st,st(i) */
reg_mul(st0_ptr, &st(FPU_rm), st0_ptr);
reg_mul(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr);
}
......@@ -31,28 +31,28 @@ void fmul__()
void fsub__()
{
/* fsub st,st(i) */
reg_sub(st0_ptr, &st(FPU_rm), st0_ptr);
reg_sub(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr);
}
void fsubr_()
{
/* fsubr st,st(i) */
reg_sub(&st(FPU_rm), st0_ptr, st0_ptr);
reg_sub(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr);
}
void fdiv__()
{
/* fdiv st,st(i) */
reg_div(st0_ptr, &st(FPU_rm), st0_ptr);
reg_div(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr);
}
void fdivr_()
{
/* fdivr st,st(i) */
reg_div(&st(FPU_rm), st0_ptr, st0_ptr);
reg_div(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr);
}
......@@ -60,14 +60,14 @@ void fdivr_()
void fadd_i()
{
/* fadd st(i),st */
reg_add(st0_ptr, &st(FPU_rm), &st(FPU_rm));
reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm));
}
void fmul_i()
{
/* fmul st(i),st */
reg_mul(&st(FPU_rm), st0_ptr, &st(FPU_rm));
reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm));
}
......@@ -75,8 +75,8 @@ void fsubri()
{
/* fsubr st(i),st */
/* This is the sense of the 80486 manual
reg_sub(&st(FPU_rm), st0_ptr, &st(FPU_rm)); */
reg_sub(st0_ptr, &st(FPU_rm), &st(FPU_rm));
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm)); */
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm));
}
......@@ -84,22 +84,22 @@ void fsub_i()
{
/* fsub st(i),st */
/* This is the sense of the 80486 manual
reg_sub(st0_ptr, &st(FPU_rm), &st(FPU_rm)); */
reg_sub(&st(FPU_rm), st0_ptr, &st(FPU_rm));
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm)); */
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm));
}
void fdivri()
{
/* fdivr st(i),st */
reg_div(st0_ptr, &st(FPU_rm), &st(FPU_rm));
reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm));
}
void fdiv_i()
{
/* fdiv st(i),st */
reg_div(&st(FPU_rm), st0_ptr, &st(FPU_rm));
reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm));
}
......@@ -107,7 +107,7 @@ void fdiv_i()
void faddp_()
{
/* faddp st(i),st */
reg_add(st0_ptr, &st(FPU_rm), &st(FPU_rm));
reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm));
pop();
}
......@@ -115,7 +115,7 @@ void faddp_()
void fmulp_()
{
/* fmulp st(i),st */
reg_mul(&st(FPU_rm), st0_ptr, &st(FPU_rm));
reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm));
pop();
}
......@@ -125,8 +125,8 @@ void fsubrp()
{
/* fsubrp st(i),st */
/* This is the sense of the 80486 manual
reg_sub(&st(FPU_rm), st0_ptr, &st(FPU_rm)); */
reg_sub(st0_ptr, &st(FPU_rm), &st(FPU_rm));
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm)); */
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm));
pop();
}
......@@ -135,8 +135,8 @@ void fsubp_()
{
/* fsubp st(i),st */
/* This is the sense of the 80486 manual
reg_sub(st0_ptr, &st(FPU_rm), &st(FPU_rm)); */
reg_sub(&st(FPU_rm), st0_ptr, &st(FPU_rm));
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm)); */
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm));
pop();
}
......@@ -144,7 +144,7 @@ void fsubp_()
void fdivrp()
{
/* fdivrp st(i),st */
reg_div(st0_ptr, &st(FPU_rm), &st(FPU_rm));
reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm));
pop();
}
......@@ -152,7 +152,7 @@ void fdivrp()
void fdivp_()
{
/* fdivp st(i),st */
reg_div(&st(FPU_rm), st0_ptr, &st(FPU_rm));
reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm));
pop();
}
......@@ -14,10 +14,6 @@
#include "fpu_emu.h"
#include "status_w.h"
extern struct info *FPU_info;
#define EAX_REG ((long)(FPU_info->___eax))
static void fclex()
......@@ -60,7 +56,7 @@ static void fstsw_ax()
status_word &= ~SW_TOP;
status_word |= (top&7) << SW_TOPS;
*(short *) &EAX_REG = status_word;
*(short *) &FPU_EAX = status_word;
}
......@@ -91,7 +87,7 @@ void fp_nop()
void fld_i_()
{
REG *st_new_ptr;
FPU_REG *st_new_ptr;
if ( STACK_OVERFLOW )
{ stack_overflow(); return; }
......@@ -117,10 +113,10 @@ void fld_i_()
void fxch_i()
{
/* fxch st(i) */
REG t;
register REG *sti_ptr = &st(FPU_rm);
reg_move(st0_ptr, &t);
reg_move(sti_ptr, st0_ptr);
FPU_REG t;
register FPU_REG *sti_ptr = &st(FPU_rm);
reg_move(FPU_st0_ptr, &t);
reg_move(sti_ptr, FPU_st0_ptr);
reg_move(&t, sti_ptr);
}
......@@ -135,14 +131,14 @@ void ffree_()
void fst_i_()
{
/* fst st(i) */
reg_move(st0_ptr, &st(FPU_rm));
reg_move(FPU_st0_ptr, &st(FPU_rm));
}
void fstp_i()
{
/* fstp st(i) */
reg_move(st0_ptr, &st(FPU_rm));
reg_move(FPU_st0_ptr, &st(FPU_rm));
pop();
}
......@@ -40,41 +40,39 @@
#ifndef __ASSEMBLER__
typedef void (*FUNC)();
#include <linux/math_emu.h>
#define REG struct reg
#ifdef PARANOID
extern char emulating;
# define RE_ENTRANT_CHECK_OFF emulating = 0;
# define RE_ENTRANT_CHECK_ON emulating = 1;
#else
# define RE_ENTRANT_CHECK_OFF
# define RE_ENTRANT_CHECK_ON
#endif PARANOID
struct reg {
char sign;
char tag;
/* short exp; *****/
long exp;
unsigned sigl;
unsigned sigh;
};
typedef void (*FUNC)();
typedef struct fpu_reg FPU_REG;
#define st(x) ( regs[((top+x) &7 )] )
#define STACK_OVERFLOW (st_new_ptr = &st(-1), st_new_ptr->tag != TW_Empty)
#define NOT_EMPTY(i) (st(i).tag != TW_Empty)
#define NOT_EMPTY_0 (st0_tag ^ TW_Empty)
#define NOT_EMPTY_0 (FPU_st0_tag ^ TW_Empty)
extern unsigned char FPU_modrm;
extern unsigned char FPU_rm;
extern char st0_tag;
extern REG *st0_ptr;
extern char FPU_st0_tag;
extern FPU_REG *FPU_st0_ptr;
extern void *FPU_data_address;
extern unsigned long FPU_entry_eip;
extern REG FPU_loaded_data;
extern FPU_REG FPU_loaded_data;
#define pop() { st0_ptr->tag = TW_Empty; \
top++; st0_ptr = &(regs[top&7]); }
#define pop() { FPU_st0_ptr->tag = TW_Empty; top++; }
/* push() does not affect the tags */
#define push() { top--; st0_ptr = st_new_ptr; }
#define push() { top--; FPU_st0_ptr = st_new_ptr; }
#define reg_move(x, y) { \
......@@ -84,7 +82,7 @@ extern REG FPU_loaded_data;
/*----- Prototypes for functions written in assembler -----*/
/* extern void reg_move(REG *a, REG *b); */
/* extern void reg_move(FPU_REG *a, FPU_REG *b); */
extern void mul64(long long *a, long long *b, long long *result);
extern void poly_div2(long long *x);
......@@ -92,13 +90,13 @@ extern void poly_div4(long long *x);
extern void poly_div16(long long *x);
extern void polynomial(unsigned accum[], unsigned x[],
unsigned short terms[][4], int n);
extern void normalize(REG *x);
extern void reg_div(REG *arg1, REG *arg2, REG *answ);
extern void reg_u_sub(REG *arg1, REG *arg2, REG *answ);
extern void reg_u_mul(REG *arg1, REG *arg2, REG *answ);
extern void reg_u_div(long long *arg1, long long *arg2, REG *answ);
extern void reg_u_add(REG *arg1, REG *arg2, REG *answ);
extern void wm_sqrt(REG *n);
extern void normalize(FPU_REG *x);
extern void reg_div(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ);
extern void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ);
extern void reg_u_mul(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ);
extern void reg_u_div(long long *arg1, long long *arg2, FPU_REG *answ);
extern void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ);
extern void wm_sqrt(FPU_REG *n);
extern unsigned shrx(void *l, unsigned x);
extern unsigned shrxs(void *v, unsigned x);
extern unsigned long div_small(unsigned long long *x, unsigned long y);
......
......@@ -11,6 +11,13 @@
| |
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
| Note: |
| The file contains code which accesses user memory. |
| Emulator static data may change when user memory is accessed, due to |
| other processes using the emulator while swapping is in progress. |
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
| math_emulate() is the sole entry point for wm-FPU-emu |
+---------------------------------------------------------------------------*/
......@@ -58,32 +65,30 @@ static unsigned char type_table[64] = {
};
unsigned char FPU_lookahead;
unsigned char FPU_modrm;
/* Be careful when using any of these global variables...
they might change if swapping is triggered */
unsigned char FPU_rm;
char st0_tag;
struct reg *st0_ptr;
struct info *FPU_info;
unsigned long FPU_entry_eip;
char FPU_st0_tag;
FPU_REG *FPU_st0_ptr;
#ifdef PARANOID
char emulating=0;
#endif PARANOID
#define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
void math_emulate(long arg)
{
unsigned char FPU_modrm;
unsigned short code;
#ifdef PARANOID
static int emulating=0;
if ( emulating )
{
printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\r\n");
}
emulating = 1;
RE_ENTRANT_CHECK_ON
#endif PARANOID
if (!current->used_math)
......@@ -114,50 +119,57 @@ emulating = 1;
FPU_entry_eip = FPU_ORIG_EIP = FPU_EIP;
RE_ENTRANT_CHECK_OFF
code = get_fs_word((unsigned short *) FPU_EIP);
RE_ENTRANT_CHECK_ON
if ( (code & 0xff) == 0x66 )
{
FPU_EIP++;
RE_ENTRANT_CHECK_OFF
code = get_fs_word((unsigned short *) FPU_EIP);
RE_ENTRANT_CHECK_ON
}
FPU_EIP += 2;
FPU_modrm = code >> 8;
FPU_rm = FPU_modrm & 7;
st0_ptr = &st(0);
st0_tag = st0_ptr->tag;
if ( FPU_modrm < 0300 )
{
/* All of these instructions use the mod/rm byte to get a data address */
get_address();
get_address(FPU_modrm);
if ( !(code & 1) )
{
switch ( (code >> 1) & 3 )
{
case 0:
reg_load_single();
break;
case 1:
reg_load_int32();
break;
case 2:
reg_load_double();
break;
case 3:
reg_load_int16();
break;
}
/* No more access to user memory, it is safe
to use static data now */
FPU_st0_ptr = &st(0);
FPU_st0_tag = FPU_st0_ptr->tag;
if ( NOT_EMPTY_0 )
{
switch ( (code >> 1) & 3 )
{
case 0:
reg_load_single();
break;
case 1:
reg_load_int32();
break;
case 2:
reg_load_double();
break;
case 3:
reg_load_int16();
break;
}
switch ( (FPU_modrm >> 3) & 7 )
{
case 0: /* fadd */
reg_add(st0_ptr, &FPU_loaded_data, st0_ptr);
reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
break;
case 1: /* fmul */
reg_mul(st0_ptr, &FPU_loaded_data, st0_ptr);
reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
break;
case 2: /* fcom */
compare_st_data();
......@@ -167,16 +179,16 @@ emulating = 1;
pop();
break;
case 4: /* fsub */
reg_sub(st0_ptr, &FPU_loaded_data, st0_ptr);
reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
break;
case 5: /* fsubr */
reg_sub(&FPU_loaded_data, st0_ptr, st0_ptr);
reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr);
break;
case 6: /* fdiv */
reg_div(st0_ptr, &FPU_loaded_data, st0_ptr);
reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
break;
case 7: /* fdivr */
reg_div(&FPU_loaded_data, st0_ptr, st0_ptr);
reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr);
break;
}
}
......@@ -184,13 +196,18 @@ emulating = 1;
stack_underflow();
}
else
load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1);
{
load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1);
}
data_operand_offset = FPU_data_address;
data_operand_offset = (unsigned long)FPU_data_address;
}
else
{
/* None of these instructions access user memory */
unsigned char instr_index = (FPU_modrm & 0x38) | (code & 7);
FPU_st0_ptr = &st(0);
FPU_st0_tag = FPU_st0_ptr->tag;
switch ( type_table[(int) instr_index] )
{
case _NONE_:
......@@ -231,7 +248,9 @@ emulating = 1;
{
unsigned char next;
skip_fwait:
RE_ENTRANT_CHECK_OFF
next = get_fs_byte((unsigned char *) FPU_EIP);
RE_ENTRANT_CHECK_ON
test_for_fp:
if ( (next & 0xf8) == 0xd8 )
{
......@@ -241,16 +260,15 @@ emulating = 1;
{ FPU_EIP++; goto skip_fwait; }
if ( next == 0x66 ) /* size prefix */
{
RE_ENTRANT_CHECK_OFF
next = get_fs_byte((unsigned char *) (FPU_EIP+1));
RE_ENTRANT_CHECK_ON
if ( (next & 0xf8) == 0xd8 )
goto test_for_fp;
}
}
#ifdef PARANOID
emulating = 0;
#endif PARANOID
RE_ENTRANT_CHECK_OFF
}
......
......@@ -20,7 +20,7 @@ static void fchs()
{
if ( NOT_EMPTY_0 )
{
st0_ptr->sign ^= SIGN_POS^SIGN_NEG;
FPU_st0_ptr->sign ^= SIGN_POS^SIGN_NEG;
status_word &= ~SW_C1;
}
else
......@@ -29,9 +29,9 @@ static void fchs()
static void fabs()
{
if ( st0_tag ^ TW_Empty )
if ( FPU_st0_tag ^ TW_Empty )
{
st0_ptr->sign = SIGN_POS;
FPU_st0_ptr->sign = SIGN_POS;
status_word &= ~SW_C1;
}
else
......@@ -41,13 +41,13 @@ static void fabs()
static void ftst_()
{
switch (st0_tag)
switch (FPU_st0_tag)
{
case TW_Zero:
setcc(SW_C3);
break;
case TW_Valid:
if (st0_ptr->sign == SIGN_POS)
if (FPU_st0_ptr->sign == SIGN_POS)
setcc(0);
else
setcc(SW_C0);
......@@ -57,7 +57,7 @@ static void ftst_()
EXCEPTION(EX_Invalid);
break;
case TW_Infinity:
if (st0_ptr->sign == SIGN_POS)
if (FPU_st0_ptr->sign == SIGN_POS)
setcc(0);
else
setcc(SW_C3);
......@@ -78,7 +78,7 @@ static void ftst_()
static void fxam()
{
int c=0;
switch (st0_tag)
switch (FPU_st0_tag)
{
case TW_Empty:
c = SW_C3|SW_C0;
......@@ -87,7 +87,7 @@ static void fxam()
c = SW_C3;
break;
case TW_Valid:
if (st0_ptr->sigh & 0x80000000)
if (FPU_st0_ptr->sigh & 0x80000000)
c = SW_C2;
else
c = SW_C3|SW_C2;
......@@ -99,7 +99,7 @@ static void fxam()
c = SW_C2|SW_C0;
break;
}
if (st0_ptr->sign == SIGN_NEG)
if (FPU_st0_ptr->sign == SIGN_NEG)
c |= SW_C1;
setcc(c);
}
......
......@@ -2,11 +2,11 @@
extern void Un_impl(void);
extern void emu_printall(void);
extern void exception(int n);
extern void real_2op_NaN(struct reg *a, struct reg *b, struct reg *dest);
extern void arith_invalid(struct reg *dest);
extern void divide_by_zero(int sign, struct reg *dest);
extern void arith_overflow(struct reg *dest);
extern void arith_underflow(struct reg *dest);
extern void real_2op_NaN(struct fpu_reg *a, struct fpu_reg *b, struct fpu_reg *dest);
extern void arith_invalid(struct fpu_reg *dest);
extern void divide_by_zero(int sign, struct fpu_reg *dest);
extern void arith_overflow(struct fpu_reg *dest);
extern void arith_underflow(struct fpu_reg *dest);
extern void stack_overflow(void);
extern void stack_underflow(void);
/* fpu_arith.c */
......@@ -43,30 +43,30 @@ extern void math_emulate(long arg);
/* fpu_etc.c */
extern void fp_etc(void);
/* fpu_trig.c */
extern void convert_l2reg(long *arg, struct reg *dest);
extern void convert_l2reg(long *arg, struct fpu_reg *dest);
extern void trig_a(void);
extern void trig_b(void);
/* get_address.c */
extern void get_address(void);
extern void get_address(unsigned char FPU_modrm);
/* load_store.c */
extern void load_store_instr(char type);
/* poly_2xm1.c */
extern int poly_2xm1(struct reg *arg, struct reg *result);
extern int poly_2xm1(struct fpu_reg *arg, struct fpu_reg *result);
/* poly_atan.c */
extern void poly_atan(struct reg *arg);
extern void poly_add_1(struct reg *src);
extern void poly_atan(struct fpu_reg *arg);
extern void poly_add_1(struct fpu_reg *src);
/* poly_l2.c */
extern void poly_l2(struct reg *arg, struct reg *result);
extern int poly_l2p1(struct reg *arg, struct reg *result);
extern void poly_l2(struct fpu_reg *arg, struct fpu_reg *result);
extern int poly_l2p1(struct fpu_reg *arg, struct fpu_reg *result);
/* poly_sin.c */
extern void poly_sine(struct reg *arg, struct reg *result);
extern void poly_sine(struct fpu_reg *arg, struct fpu_reg *result);
/* poly_tan.c */
extern void poly_tan(struct reg *arg, struct reg *y_reg);
extern void poly_tan(struct fpu_reg *arg, struct fpu_reg *y_reg);
/* reg_add_sub.c */
extern void reg_add(struct reg *a, struct reg *b, struct reg *dest);
extern void reg_sub(struct reg *a, struct reg *b, struct reg *dest);
extern void reg_add(struct fpu_reg *a, struct fpu_reg *b, struct fpu_reg *dest);
extern void reg_sub(struct fpu_reg *a, struct fpu_reg *b, struct fpu_reg *dest);
/* reg_compare.c */
extern int compare(struct reg *b);
extern int compare(struct fpu_reg *b);
extern void compare_st_data(void);
extern void fcom_st(void);
extern void fcompst(void);
......@@ -91,10 +91,10 @@ extern int reg_store_int64(void);
extern int reg_store_int32(void);
extern int reg_store_int16(void);
extern int reg_store_bcd(void);
extern int round_to_int(struct reg *r);
extern int round_to_int(struct fpu_reg *r);
extern char *fldenv(void);
extern void frstor(void);
extern char *fstenv(void);
extern void fsave(void);
/* reg_mul.c */
extern void reg_mul(struct reg *a, struct reg *b, struct reg *dest);
extern void reg_mul(struct fpu_reg *a, struct fpu_reg *b, struct fpu_reg *dest);
......@@ -11,18 +11,25 @@
/* system dependent definitions */
#include <linux/math_emu.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#define I387 (current->tss.i387)
#define FPU_info (I387.soft.info)
#define FPU_CS (*(unsigned short *) &(FPU_info->___cs))
#define FPU_DS (*(unsigned short *) &(FPU_info->___ds))
#define FPU_EAX (FPU_info->___eax)
#define FPU_EFLAGS (FPU_info->___eflags)
#define FPU_EIP (FPU_info->___eip)
#define FPU_ORIG_EIP (FPU_info->___orig_eip)
#define FPU_lookahead (I387.soft.lookahead)
#define FPU_entry_eip (I387.soft.entry_eip)
#define status_word (I387.soft.swd)
#define control_word (I387.soft.cwd)
#define regs ((REG *)(&(I387.soft.regs_space)))
#define regs (I387.soft.regs)
#define top (I387.soft.top)
#define ip_offset (I387.soft.fip)
......@@ -30,6 +37,4 @@
#define data_operand_offset (I387.soft.foo)
#define operand_selector (I387.soft.fos)
extern struct info *FPU_info;
#endif
This diff is collapsed.
......@@ -9,9 +9,15 @@
| |
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
| Note: |
| The file contains code which accesses user memory. |
| Emulator static data may change when user memory is accessed, due to |
| other processes using the emulator while swapping is in progress. |
+---------------------------------------------------------------------------*/
#include <linux/stddef.h>
#include <linux/math_emu.h>
#include <asm/segment.h>
......@@ -19,8 +25,6 @@
#include "exception.h"
#include "fpu_emu.h"
static int reg_offset[] = {
offsetof(struct info,___eax),
offsetof(struct info,___ecx),
......@@ -43,8 +47,10 @@ static void *sib(int mod)
{
unsigned char ss,index,base;
long offset;
RE_ENTRANT_CHECK_OFF
base = get_fs_byte((char *) FPU_EIP); /* The SIB byte */
RE_ENTRANT_CHECK_ON
FPU_EIP++;
ss = base >> 6;
index = (base >> 3) & 7;
......@@ -70,13 +76,17 @@ static void *sib(int mod)
if (mod == 1)
{
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF
offset += (signed char) get_fs_byte((char *) FPU_EIP);
RE_ENTRANT_CHECK_ON
FPU_EIP++;
}
else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
{
/* 32 bit displacment */
RE_ENTRANT_CHECK_OFF
offset += (signed) get_fs_long((unsigned long *) FPU_EIP);
RE_ENTRANT_CHECK_ON
FPU_EIP += 4;
}
......@@ -101,7 +111,7 @@ static void *sib(int mod)
*/
void get_address(void)
void get_address(unsigned char FPU_modrm)
{
unsigned char mod;
long *cpu_reg_ptr;
......@@ -122,7 +132,9 @@ void get_address(void)
if (FPU_rm == 5)
{
/* Special case: disp32 */
RE_ENTRANT_CHECK_OFF
offset = get_fs_long((unsigned long *) FPU_EIP);
RE_ENTRANT_CHECK_ON
FPU_EIP += 4;
FPU_data_address = (void *) offset;
return;
......@@ -135,12 +147,16 @@ void get_address(void)
}
case 1:
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF
offset = (signed char) get_fs_byte((char *) FPU_EIP);
RE_ENTRANT_CHECK_ON
FPU_EIP++;
break;
case 2:
/* 32 bit displacement */
RE_ENTRANT_CHECK_OFF
offset = (signed) get_fs_long((unsigned long *) FPU_EIP);
RE_ENTRANT_CHECK_ON
FPU_EIP += 4;
break;
case 3:
......
......@@ -10,6 +10,13 @@
| |
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
| Note: |
| The file contains code which accesses user memory. |
| Emulator static data may change when user memory is accessed, due to |
| other processes using the emulator while swapping is in progress. |
+---------------------------------------------------------------------------*/
#include <asm/segment.h>
#include "fpu_system.h"
......@@ -18,13 +25,14 @@
#include "status_w.h"
#define _NONE_ 0
#define _REG0_ 1 /* Need to check for not empty st(0) */
#define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */
#define _REGi_ 0 /* Uses st(rm) */
#define _NONE_ 0 /* FPU_st0_ptr etc not needed */
#define _REG0_ 1 /* Will be storing st(0) */
#define _PUSH_ 3 /* Need to check for space to push onto stack */
#define _null_ 4 /* Function illegal or not implemented */
#define pop_0() { pop_ptr->tag = TW_Empty; top++; }
static unsigned char type_table[32] = {
_PUSH_, _PUSH_, _PUSH_, _PUSH_,
_null_, _null_, _null_, _null_,
......@@ -38,18 +46,25 @@ static unsigned char type_table[32] = {
void load_store_instr(char type)
{
FPU_REG *pop_ptr; /* We need a version of FPU_st0_ptr which won't change. */
switch ( type_table[(int) (unsigned) type] )
{
case _NONE_:
break;
case _REG0_:
pop_ptr = &st(0); /* Some of these instructions pop after
storing */
FPU_st0_ptr = pop_ptr; /* Set the global variables. */
FPU_st0_tag = FPU_st0_ptr->tag;
break;
case _PUSH_:
{
REG *st_new_ptr;
if ( STACK_OVERFLOW )
pop_ptr = &st(-1);
if ( pop_ptr->tag != TW_Empty )
{ stack_overflow(); return; }
push();
top--;
}
break;
case _null_:
......@@ -64,19 +79,19 @@ switch ( type )
{
case 000: /* fld m32real */
reg_load_single();
reg_move(&FPU_loaded_data, st0_ptr);
reg_move(&FPU_loaded_data, pop_ptr);
break;
case 001: /* fild m32int */
reg_load_int32();
reg_move(&FPU_loaded_data, st0_ptr);
reg_move(&FPU_loaded_data, pop_ptr);
break;
case 002: /* fld m64real */
reg_load_double();
reg_move(&FPU_loaded_data, st0_ptr);
reg_move(&FPU_loaded_data, pop_ptr);
break;
case 003: /* fild m16int */
reg_load_int16();
reg_move(&FPU_loaded_data, st0_ptr);
reg_move(&FPU_loaded_data, pop_ptr);
break;
case 010: /* fst m32real */
reg_store_single();
......@@ -92,22 +107,22 @@ switch ( type )
break;
case 014: /* fstp m32real */
if ( reg_store_single() )
pop(); /* pop only if the number was actually stored
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 015: /* fistp m32int */
if ( reg_store_int32() )
pop(); /* pop only if the number was actually stored
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 016: /* fstp m64real */
if ( reg_store_double() )
pop(); /* pop only if the number was actually stored
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 017: /* fistp m16int */
if ( reg_store_int16() )
pop(); /* pop only if the number was actually stored
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 020: /* fldenv m14/28byte */
......@@ -118,10 +133,12 @@ switch ( type )
break;
case 023: /* fbld m80dec */
reg_load_bcd();
reg_move(&FPU_loaded_data, st0_ptr);
reg_move(&FPU_loaded_data, pop_ptr);
break;
case 024: /* fldcw */
RE_ENTRANT_CHECK_OFF
control_word = get_fs_word((unsigned short *) FPU_data_address);
RE_ENTRANT_CHECK_ON
#ifdef NO_UNDERFLOW_TRAP
if ( !(control_word & EX_Underflow) )
{
......@@ -133,11 +150,11 @@ switch ( type )
break;
case 025: /* fld m80real */
reg_load_extended();
reg_move(&FPU_loaded_data, st0_ptr);
reg_move(&FPU_loaded_data, pop_ptr);
break;
case 027: /* fild m64int */
reg_load_int64();
reg_move(&FPU_loaded_data, st0_ptr);
reg_move(&FPU_loaded_data, pop_ptr);
break;
case 030: /* fstenv m14/28byte */
fstenv();
......@@ -151,31 +168,35 @@ switch ( type )
break;
case 033: /* fbstp m80dec */
if ( reg_store_bcd() )
pop(); /* pop only if the number was actually stored
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 034: /* fstcw m16int */
RE_ENTRANT_CHECK_OFF
verify_area(FPU_data_address,2);
put_fs_word(control_word, (short *) FPU_data_address);
RE_ENTRANT_CHECK_ON
FPU_data_address = (void *)data_operand_offset; /* We want no net effect */
FPU_entry_eip = ip_offset; /* We want no net effect */
break;
case 035: /* fstp m80real */
if ( reg_store_extended() )
pop(); /* pop only if the number was actually stored
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 036: /* fstsw m2byte */
status_word &= ~SW_TOP;
status_word |= (top&7) << SW_TOPS;
RE_ENTRANT_CHECK_OFF
verify_area(FPU_data_address,2);
put_fs_word(status_word,(short *) FPU_data_address);
RE_ENTRANT_CHECK_ON
FPU_data_address = (void *)data_operand_offset; /* We want no net effect */
FPU_entry_eip = ip_offset; /* We want no net effect */
break;
case 037: /* fistp m64int */
if ( reg_store_int64() )
pop(); /* pop only if the number was actually stored
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
}
......
......@@ -37,11 +37,11 @@ static unsigned short lterms[HIPOWER][4] =
/*--- poly_2xm1() -----------------------------------------------------------+
| |
+---------------------------------------------------------------------------*/
int poly_2xm1(REG *arg, REG *result)
int poly_2xm1(FPU_REG *arg, FPU_REG *result)
{
short exponent;
long long Xll;
REG accum;
FPU_REG accum;
exponent = arg->exp - EXP_BIAS;
......
/*---------------------------------------------------------------------------+
| p_atan.c |
| |
| Compute the tan of a REG, using a polynomial approximation. |
| Compute the tan of a FPU_REG, using a polynomial approximation. |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
......@@ -45,12 +45,12 @@ static unsigned denomterm[2] =
/*--- poly_atan() -----------------------------------------------------------+
| |
+---------------------------------------------------------------------------*/
void poly_atan(REG *arg)
void poly_atan(FPU_REG *arg)
{
char recursions = 0;
short exponent;
REG odd_poly, even_poly, pos_poly, neg_poly;
REG argSq;
FPU_REG odd_poly, even_poly, pos_poly, neg_poly;
FPU_REG argSq;
long long arg_signif, argSqSq;
......@@ -90,7 +90,7 @@ void poly_atan(REG *arg)
/* convert the argument by an identity for atan */
if ( (exponent >= -1) || (arg->sigh > 0xd413ccd0) )
{
REG numerator, denom;
FPU_REG numerator, denom;
recursions++;
......@@ -183,7 +183,7 @@ void poly_atan(REG *arg)
i.e. have an exponent (not checked) of EXP_BIAS-1 but need not
be normalized.
This function adds 1.0 to the (assumed positive) argument. */
void poly_add_1(REG *src)
void poly_add_1(FPU_REG *src)
{
/* Rounding in a consistent direction produces better results
for the use of this function in poly_atan. Simple truncation
......
/*---------------------------------------------------------------------------+
| poly_l2.c |
| |
| Compute the base 2 logarithm of a REG, using a polynomial approximation. |
| Compute the base 2 log of a FPU_REG, using a polynomial approximation. |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
......@@ -38,13 +38,13 @@ static unsigned short lterms[HIPOWER][4] =
/*--- poly_l2() -------------------------------------------------------------+
| Base 2 logarithm by a polynomial approximation. |
+---------------------------------------------------------------------------*/
void poly_l2(REG *arg, REG *result)
void poly_l2(FPU_REG *arg, FPU_REG *result)
{
short exponent;
char zero; /* flag for an Xx == 0 */
unsigned short bits, shift;
long long Xsq;
REG accum, denom, num, Xx;
FPU_REG accum, denom, num, Xx;
exponent = arg->exp - EXP_BIAS;
......@@ -96,7 +96,7 @@ void poly_l2(REG *arg, REG *result)
/* If the exponent is zero, then we would lose precision by
sticking to fixed point computation here */
/* We need to re-compute Xx because of loss of precision. */
REG lXx;
FPU_REG lXx;
char sign;
sign = accum.sign;
......@@ -137,7 +137,6 @@ void poly_l2(REG *arg, REG *result)
reg_u_mul(&lXx, &accum, &accum);
accum.exp += - EXP_BIAS + 1;
/* normalize(&accum); ********/
reg_u_add(&lXx, &accum, result);
......@@ -222,11 +221,11 @@ void poly_l2(REG *arg, REG *result)
| Base 2 logarithm by a polynomial approximation. |
| log2(x+1) |
+---------------------------------------------------------------------------*/
int poly_l2p1(REG *arg, REG *result)
int poly_l2p1(FPU_REG *arg, FPU_REG *result)
{
char sign = 0;
long long Xsq;
REG arg_pl1, denom, accum, local_arg, poly_arg;
FPU_REG arg_pl1, denom, accum, local_arg, poly_arg;
sign = arg->sign;
......
......@@ -38,10 +38,10 @@ static unsigned short negterms[HIPOWER][4] =
/*--- poly_sine() -----------------------------------------------------------+
| |
+---------------------------------------------------------------------------*/
void poly_sine(REG *arg, REG *result)
void poly_sine(FPU_REG *arg, FPU_REG *result)
{
short exponent;
REG Xx, Xx2, Xx4, accum, negaccum;
FPU_REG Xx, Xx2, Xx4, accum, negaccum;
exponent = arg->exp - EXP_BIAS;
......@@ -129,18 +129,22 @@ void poly_sine(REG *arg, REG *result)
)
{
#ifdef DEBUGGING
RE_ENTRANT_CHECK_OFF
printk("\nEXP=%d, MS=%08x, LS=%08x\n", result->exp,
result->sigh, result->sigl);
RE_ENTRANT_CHECK_ON
#endif DEBUGGING
EXCEPTION(EX_INTERNAL|0x103);
}
#ifdef DEBUGGING
RE_ENTRANT_CHECK_OFF
printk("\n***CORRECTING ILLEGAL RESULT*** in poly_sin() computation\n");
printk("EXP=%d, MS=%08x, LS=%08x\n", result->exp,
result->sigh, result->sigl);
RE_ENTRANT_CHECK_ON
#endif DEBUGGING
result->sigl = 0; /* Truncate the result to 1.00 */
}
}
/*---------------------------------------------------------------------------+
| poly_tan.c |
| |
| Compute the tan of a REG, using a polynomial approximation. |
| Compute the tan of a FPU_REG, using a polynomial approximation. |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
......@@ -47,12 +47,12 @@ static unsigned short evennegterms[HIPOWERen][4] =
/*--- poly_tan() ------------------------------------------------------------+
| |
+---------------------------------------------------------------------------*/
void poly_tan(REG *arg, REG *y_reg)
void poly_tan(FPU_REG *arg, FPU_REG *y_reg)
{
char invert = 0;
short exponent;
REG odd_poly, even_poly, pos_poly, neg_poly;
REG argSq;
FPU_REG odd_poly, even_poly, pos_poly, neg_poly;
FPU_REG argSq;
long long arg_signif, argSqSq;
......
......@@ -10,8 +10,8 @@
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
| For each function, the destination may be any REG, including one of the |
| source REGs. |
| For each function, the destination may be any FPU_REG, including one of |
| the source FPU_REGs. |
+---------------------------------------------------------------------------*/
#include "exception.h"
......@@ -20,7 +20,7 @@
void reg_add(REG *a, REG *b, REG *dest)
void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
{
int diff;
......@@ -85,7 +85,7 @@ void reg_add(REG *a, REG *b, REG *dest)
/* Subtract b from a. (a-b) -> dest */
void reg_sub(REG *a, REG *b, REG *dest)
void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
{
int diff;
......
......@@ -10,7 +10,7 @@
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
| compare() is the core REG comparison function |
| compare() is the core FPU_REG comparison function |
+---------------------------------------------------------------------------*/
#include "fpu_system.h"
......@@ -19,13 +19,13 @@
#include "status_w.h"
int compare(REG *b)
int compare(FPU_REG *b)
{
int diff;
if ( st0_ptr->tag | b->tag )
if ( FPU_st0_ptr->tag | b->tag )
{
if ( st0_ptr->tag == TW_Zero )
if ( FPU_st0_ptr->tag == TW_Zero )
{
if ( b->tag == TW_Zero ) return COMP_A_EQ_B;
if ( b->tag == TW_Valid )
......@@ -35,29 +35,29 @@ int compare(REG *b)
}
else if ( b->tag == TW_Zero )
{
if ( st0_ptr->tag == TW_Valid )
if ( FPU_st0_ptr->tag == TW_Valid )
{
return (st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B ;
return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B ;
}
}
if ( st0_ptr->tag == TW_Infinity )
if ( FPU_st0_ptr->tag == TW_Infinity )
{
if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
{
return (st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B;
return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B;
}
else if ( b->tag == TW_Infinity )
{
/* The 80486 book says that infinities can be equal! */
return (st0_ptr->sign == b->sign) ? COMP_A_EQ_B :
((st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B);
return (FPU_st0_ptr->sign == b->sign) ? COMP_A_EQ_B :
((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B);
}
/* Fall through to the NaN code */
}
else if ( b->tag == TW_Infinity )
{
if ( (st0_ptr->tag == TW_Valid) || (st0_ptr->tag == TW_Zero) )
if ( (FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero) )
{
return (b->sign == SIGN_POS) ? COMP_A_LT_B : COMP_A_GT_B;
}
......@@ -66,9 +66,9 @@ int compare(REG *b)
/* The only possibility now should be that one of the arguments
is a NaN */
if ( (st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN) )
if ( (FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN) )
{
if ( ((st0_ptr->tag == TW_NaN) && !(st0_ptr->sigh & 0x40000000))
if ( ((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000))
|| ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
/* At least one arg is a signaling NaN */
return COMP_NOCOMP | COMP_SNAN | COMP_NAN;
......@@ -81,25 +81,25 @@ int compare(REG *b)
}
#ifdef PARANOID
if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
if (!(FPU_st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
#endif PARANOID
if (st0_ptr->sign != b->sign)
return (st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B;
if (FPU_st0_ptr->sign != b->sign)
return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B;
diff = st0_ptr->exp - b->exp;
diff = FPU_st0_ptr->exp - b->exp;
if ( diff == 0 )
{
diff = st0_ptr->sigh - b->sigh;
diff = FPU_st0_ptr->sigh - b->sigh;
if ( diff == 0 )
diff = st0_ptr->sigl - b->sigl;
diff = FPU_st0_ptr->sigl - b->sigl;
}
if ( diff > 0 )
return (st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B ;
return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B ;
if ( diff < 0 )
return (st0_ptr->sign == SIGN_POS) ? COMP_A_LT_B : COMP_A_GT_B ;
return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_LT_B : COMP_A_GT_B ;
return COMP_A_EQ_B;
}
......@@ -235,7 +235,7 @@ void fcompp()
if (FPU_rm != 1)
return Un_impl();
compare_st_st(1);
pop();
pop(); FPU_st0_ptr = &st(0);
pop();
}
......@@ -261,7 +261,7 @@ void fucompp()
if (FPU_rm == 1)
{
compare_u_st_st(1);
pop();
pop(); FPU_st0_ptr = &st(0);
pop();
}
else
......
/*---------------------------------------------------------------------------+
| reg_constant.c |
| |
| All of the constant REGs |
| All of the constant FPU_REGs |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
......@@ -15,45 +15,45 @@
#include "reg_constant.h"
struct reg CONST_1 = { SIGN_POS, TW_Valid, EXP_BIAS,
FPU_REG CONST_1 = { SIGN_POS, TW_Valid, EXP_BIAS,
0x00000000, 0x80000000 };
struct reg CONST_2 = { SIGN_POS, TW_Valid, EXP_BIAS+1,
FPU_REG CONST_2 = { SIGN_POS, TW_Valid, EXP_BIAS+1,
0x00000000, 0x80000000 };
struct reg CONST_HALF = { SIGN_POS, TW_Valid, EXP_BIAS-1,
FPU_REG CONST_HALF = { SIGN_POS, TW_Valid, EXP_BIAS-1,
0x00000000, 0x80000000 };
struct reg CONST_L2T = { SIGN_POS, TW_Valid, EXP_BIAS+1,
FPU_REG CONST_L2T = { SIGN_POS, TW_Valid, EXP_BIAS+1,
0xcd1b8afe, 0xd49a784b };
struct reg CONST_L2E = { SIGN_POS, TW_Valid, EXP_BIAS,
FPU_REG CONST_L2E = { SIGN_POS, TW_Valid, EXP_BIAS,
0x5c17f0bc, 0xb8aa3b29 };
struct reg CONST_PI = { SIGN_POS, TW_Valid, EXP_BIAS+1,
FPU_REG CONST_PI = { SIGN_POS, TW_Valid, EXP_BIAS+1,
0x2168c235, 0xc90fdaa2 };
struct reg CONST_PI2 = { SIGN_POS, TW_Valid, EXP_BIAS,
FPU_REG CONST_PI2 = { SIGN_POS, TW_Valid, EXP_BIAS,
0x2168c235, 0xc90fdaa2 };
struct reg CONST_PI4 = { SIGN_POS, TW_Valid, EXP_BIAS-1,
FPU_REG CONST_PI4 = { SIGN_POS, TW_Valid, EXP_BIAS-1,
0x2168c235, 0xc90fdaa2 };
struct reg CONST_LG2 = { SIGN_POS, TW_Valid, EXP_BIAS-2,
FPU_REG CONST_LG2 = { SIGN_POS, TW_Valid, EXP_BIAS-2,
0xfbcff799, 0x9a209a84 };
struct reg CONST_LN2 = { SIGN_POS, TW_Valid, EXP_BIAS-1,
FPU_REG CONST_LN2 = { SIGN_POS, TW_Valid, EXP_BIAS-1,
0xd1cf79ac, 0xb17217f7 };
/* Only the sign (and tag) is used in internal zeroes */
struct reg CONST_Z = { SIGN_POS, TW_Zero, 0, 0x0, 0x0 };
FPU_REG CONST_Z = { SIGN_POS, TW_Zero, 0, 0x0, 0x0 };
/* Only the sign and significand (and tag) are used in internal NaNs */
/* The 80486 never generates one of these
struct reg CONST_SNAN = { SIGN_POS, TW_NaN, EXP_OVER, 0x00000001, 0x80000000 };
FPU_REG CONST_SNAN = { SIGN_POS, TW_NaN, EXP_OVER, 0x00000001, 0x80000000 };
*/
/* This is the real indefinite QNaN */
struct reg CONST_QNaN = { SIGN_NEG, TW_NaN, EXP_OVER, 0x00000000, 0xC0000000 };
FPU_REG CONST_QNaN = { SIGN_NEG, TW_NaN, EXP_OVER, 0x00000000, 0xC0000000 };
/* Only the sign (and tag) is used in internal infinities */
struct reg CONST_INF = { SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x80000000 };
FPU_REG CONST_INF = { SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x80000000 };
static void fld_const(REG *c)
static void fld_const(FPU_REG *c)
{
REG *st_new_ptr;
FPU_REG *st_new_ptr;
if ( STACK_OVERFLOW )
{
......@@ -61,7 +61,7 @@ static void fld_const(REG *c)
return;
}
push();
reg_move(c, st0_ptr);
reg_move(c, FPU_st0_ptr);
status_word &= ~SW_C1;
}
......
......@@ -11,21 +11,20 @@
#include "fpu_emu.h"
extern REG CONST_1;
extern REG CONST_2;
extern REG CONST_HALF;
extern REG CONST_L2T;
extern REG CONST_L2E;
extern REG CONST_PI;
extern REG CONST_PI2;
extern REG CONST_PI4;
extern REG CONST_LG2;
extern REG CONST_LN2;
extern REG CONST_Z;
extern REG CONST_PINF;
extern REG CONST_INF;
extern REG CONST_MINF;
extern REG CONST_QNaN;
extern FPU_REG CONST_1;
extern FPU_REG CONST_2;
extern FPU_REG CONST_HALF;
extern FPU_REG CONST_L2T;
extern FPU_REG CONST_L2E;
extern FPU_REG CONST_PI;
extern FPU_REG CONST_PI2;
extern FPU_REG CONST_PI4;
extern FPU_REG CONST_LG2;
extern FPU_REG CONST_LN2;
extern FPU_REG CONST_Z;
extern FPU_REG CONST_PINF;
extern FPU_REG CONST_INF;
extern FPU_REG CONST_MINF;
extern FPU_REG CONST_QNaN;
#endif _REG_CONSTANT_H_
......@@ -2,13 +2,13 @@
/*---------------------------------------------------------------------------+
| reg_div.S |
| |
| Divide one REG by another and put the result in a destination REG. |
| Divide one FPU_REG by another and put the result in a destination FPU_REG.|
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| Call from C as: |
| void reg_div(REG *a, REG *b, REG *dest) |
| void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest) |
| |
+---------------------------------------------------------------------------*/
......
This diff is collapsed.
/*---------------------------------------------------------------------------+
| reg_mul.c |
| |
| Multiply one REG by another and put the result in a destination REG. |
| Multiply one FPU_REG by another, put the result in a destination FPU_REG. |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
......@@ -10,7 +10,7 @@
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
| The destination may be any REG, including one of the source REGs. |
| The destination may be any FPU_REG, including one of the source FPU_REGs. |
+---------------------------------------------------------------------------*/
#include "exception.h"
......@@ -19,7 +19,7 @@
/* This routine must be called with non-empty registers */
void reg_mul(REG *a, REG *b, REG *dest)
void reg_mul(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
{
if (!(a->tag | b->tag))
{
......@@ -29,9 +29,9 @@ void reg_mul(REG *a, REG *b, REG *dest)
dest->sign = (a->sign ^ b->sign);
dest->tag = TW_Valid;
if ( dest->exp <= EXP_UNDER )
{ arith_underflow(st0_ptr); }
{ arith_underflow(FPU_st0_ptr); }
else if ( dest->exp >= EXP_OVER )
{ arith_overflow(st0_ptr); }
{ arith_overflow(FPU_st0_ptr); }
return;
}
else if ((a->tag <= TW_Zero) && (b->tag <= TW_Zero))
......
......@@ -4,10 +4,10 @@
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| Normalize the value in a REG. |
| Normalize the value in a FPU_REG. |
| |
| Call from C as: |
| void normalize(REG *n) |
| void normalize(FPU_REG *n) |
| |
+---------------------------------------------------------------------------*/
......
......@@ -2,8 +2,8 @@
/*---------------------------------------------------------------------------+
| reg_u_add.S |
| |
| Add two valid (TW_Valid) REG numbers, of the same sign, and put result in |
| a destination REG. |
| Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the |
| result in a destination FPU_REG. |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
......
......@@ -13,7 +13,8 @@
/*---------------------------------------------------------------------------+
| Kernel for the division routines. |
| |
| void reg_u_div(unsigned long long *a, unsigned long long *a, REG *dest) |
| void reg_u_div(unsigned long long *a, unsigned long long *a, |
| FPU_REG *dest) |
| |
| Does not compute the destination exponent, but does adjust it. |
+---------------------------------------------------------------------------*/
......
......@@ -8,5 +8,5 @@
| |
+---------------------------------------------------------------------------*/
#define FPU_VERSION "wm-FPU-emu version ALPHA 0.61"
#define FPU_VERSION "wm-FPU-emu version ALPHA 0.7"
......@@ -8,12 +8,12 @@
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| Call from C as: |
| void wm_sqrt(REG *n) |
| void wm_sqrt(FPU_REG *n) |
| |
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
| wm_sqrt(REG *n) |
| wm_sqrt(FPU_REG *n) |
| returns the square root of n in n. |
| |
| Use Newton's method to compute the square root of a number, which must |
......
This diff is collapsed.
This diff is collapsed.
......@@ -330,11 +330,11 @@ int floppy_change(struct buffer_head * bh)
if (!bh)
return 0;
if (bh->b_dirt)
ll_rw_block(WRITE,bh);
ll_rw_block(WRITE, 1, &bh);
else {
buffer_track = -1;
bh->b_uptodate = 0;
ll_rw_block(READ,bh);
ll_rw_block(READ, 1, &bh);
}
cli();
while (bh->b_lock)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -775,7 +775,7 @@ static int set_modem_info(struct async_struct * info, unsigned int cmd,
default:
return -EINVAL;
}
outb(UART_MCR + port,control);
outb(control, UART_MCR + port);
return 0;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -41,7 +41,7 @@ malloc.o : malloc.c /usr/include/linux/kernel.h /usr/include/linux/mm.h /usr/inc
/usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h \
/usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/msdos_fs_i.h \
/usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
/usr/include/asm/system.h
/usr/include/linux/string.h /usr/include/asm/system.h
open.o : open.c /usr/include/linux/unistd.h /usr/lib/gcc-lib/i386-linux/2.2.2d/include/stdarg.h
setsid.o : setsid.c /usr/include/linux/types.h /usr/include/linux/unistd.h
string.o : string.c /usr/include/linux/types.h /usr/include/linux/string.h
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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