Commit a4c5b0f7 authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.99.15 (February 2, 1994)

sbpcd (Sound Blaster Pro CD interface) driver.

Andries Brouwer cleans up and re-does keyboard driver diacritical handling.

Lots of new sound drivers.

Sysvfs added (Xenix, SystemV/386 and Coherent support).  Linux was
starting to have a lot of users move over..

MAP_ANONYMOUS flag added to mmap().

Loadable modules added.

Alan Cox is active in networking.

[original changelog below]

Linux 0.99.15 released: Codefreeze for 1.0

People who look into my directory on ftp.funet.fi will already have
noticed that the latest version of linux (0.99.15) is available, and I
assume it will be available on most other linux sites soon.  As
explained in a previous announcement, 0.99.15 is "it", in that this will
be the base for 1.0 after about a month of testing.  No further patches
are accepted until the 1.0 release, unless they obviously fix a serious
bug.

**** NOTE 1 ****

  For this code-freeze to be effective yet still potential bugs be
  found, testing is needed, along with good reports of errors and
  problems.  Thus, nobody should think "hey, the *real* release will be
  out in a month, let's wait for that", but instead think: "hey, I'd
  better test this one, so that the *real* release won't result in any
  ugly surprises for me".

  In short: test it out, preferably even more than you usually do.  Run
  "crashme" for the whole month if you have the CPU-power to spare,
  and/or just misuse your machine as badly as you can.  And if there are
  problems, report them to me (and the better the report, the more
  likely I am to be able to do something about it).

**** NOTE 2 ****

  Bumping the linux version number to 1.0 doesn't mean anything more
  than that: it's only a version number change.  More explicitly, it
  does *NOT* mean that linux will become commercial (the copyright will
  remain as-is), nor does it mean that development stops here, and that
  1.0 will be anything special in that respect.

  I'm also afraid that just changing the version number will not make
  potential bugs magically disappear: this has been amply proven by
  various software houses over the years.  This code-freeze is there in
  order to avoid most of the problems that people sometimes associate
  with "X.0 releases", and I hope that it will mean that we have a
  reasonably stable release that we can call 1.0 and one that I won't
  have to be ashamed of.

  Ok, enough said, I hope.  The pl15 release is hopefully good, but I'll
  continue to make ALPHA patches against it along the whole month as
  problems crop up.  The networking code has been much maligned, and is
  not perfect by far yet, but it's getting its act together thanks to
  various developers and testers.  And as wiser men than I have said (or
  if they haven't, they should have):

      "There is life after 1.0"

  Any rumors that the world is coming to an end just because I'm about to
  release a 1.0-version are greatly exaggerated.  I think.

                    Linus

----------
Things that remained the same between 0.99.14 and 0.99.15:

- I again forgot to update the README before uploading the release.  In
  pl14, I talked about pl13, while the all new and improved README has
  now caught up with pl14.  Remind me to buy a new brain one of these
  days.

Changes between versions 0.99.14 and 0.99.15:

 - improved Pentium detection.  Some of you may have had linux report
   your 4086DX2 as a pentium machine, but the new kernel will tell you
   the sad truth.  Whee.
 - Network driver updates by Donald Becker.  New drivers added, old ones
   updated.
 - FPU emulation updates by Bill Metzenthen.  Various minor errors and
   misfeatures fixed (mostly error handling).
 - Support for the SoubdBlaster Pro CD-ROM driver added by Eberhard
   Moenkeberg.
 - extended support for keyboard re-definition, along with font
   re-programming (Eugene Crosser, Andries Brouwer et al).
 - tty handling fixes: true canonical mode with most features supported
   by Julian Cowley.  This may make your canonical mode behave funnily
   if you happen to use old and broken programs that happened to work
   with the old and broken behaviour (this includes at least some
   'getty' programs).
 - serial driver changes and tty fixes by Theodore Ts'o.
 - SCSI fixes by Drew Eckhardt, Eric Youngdale, Rik Faith, Kai Mdkisara
   et al.
 - Updated sound card driver to version 2.4 (Hannu Savolainen)
 - COFF binary loading support (but you will still need the experimental
   iBCS2 patches to run non-linux i386 COFF binaries) by Al Longyear.
 - Upgraded ext2fs filesystem routines (0.4a -> 0.4b), with new
   features.  Read the fs/ext2/CHANGES file for details.  Remy Card and
   Stephen Tweedie.  Get a new fsck that knows about the new features.
 - pipe behaviour fixed in the presense of multiple writers (now
   actually conforms to POSIX specs about atomic writes).  Much of the
   code by Florian Coosmann.
 - minix filesystem extended to support the clean flag: get a new fsck
   that knows about it.
 - System V filesystem (support for Xenix, Coherent and SysV
   filesystems) by Doug Evans, Paul Monday, Pascal Haible and Bruno
   Haible.
 - loadable modules (various authors, don't remember original author of
   the "modules" code).
 - Lots of networking fixes by various people: Alan Cox, Charles
   Hedrick, me and various other people.  Non-byte-aligned networks
   work, and the networking code should be much stabler in general.

 + various bugfixes and enhacements here and there (mcd driver update by
   Jon Tombs, atixlmouse fix by Chris Colohan, /dev/full by XXX etc etc)

All in all, the patches come out to 1.5MB uncompressed (about 400kB
gzip-9'd), so there is little or no idea to make patches to plain pl14
available.  Incremental patches and ALPHA-releases can be found on
ftp.funet.fi: pub/OS/Linux/PEOPLE/Linus/ALPHA-pl14.
parent 0d202675
VERSION = 0.99 VERSION = 0.99
PATCHLEVEL = 14 PATCHLEVEL = 15
ALPHA = z ALPHA =
all: Version zImage all: Version zImage
......
...@@ -111,13 +111,24 @@ startup_32: ...@@ -111,13 +111,24 @@ startup_32:
movl %ecx,%eax movl %ecx,%eax
xorl $0x200000,%eax # check ID flag xorl $0x200000,%eax # check ID flag
pushl %eax pushl %eax
popfl # if we are on a 486, popfl # if we are on a straight 486DX, SX, or
pushfl # we can't change it pushfl # 487SX we can't change it
popl %eax popl %eax
xorl %ecx,%eax xorl %ecx,%eax
andl $0x200000,%eax andl $0x200000,%eax
je is486 je is486
movl $5,_x86 # 586 setup same as 486 at least for now isnew: pushl %ecx # restore original EFLAGS
popfl
movl $1, %eax # Use the CPUID instruction to
.byte 0x0f, 0xa2 # check the processor type
andl $0xf00, %eax # Set _x86 with the family
shrl $8, %eax # returned.
movl %eax, _x86
movl %edi,%esp # restore esp
movl %cr0,%eax # 486+
andl $0x80000011,%eax # Save PG,PE,ET
orl $0x50022,%eax # set AM, WP, NE and MP
jmp 2f
is486: pushl %ecx # restore original EFLAGS is486: pushl %ecx # restore original EFLAGS
popfl popfl
movl %edi,%esp # restore esp movl %edi,%esp # restore esp
......
...@@ -59,7 +59,7 @@ else ...@@ -59,7 +59,7 @@ else
bool 'SLIP (serial line) support' CONFIG_SLIP n bool 'SLIP (serial line) support' CONFIG_SLIP n
if [ "$CONFIG_SLIP" = "y" ] if [ "$CONFIG_SLIP" = "y" ]
bool ' CSLIP compressed headers' SL_COMPRESSED y bool ' CSLIP compressed headers' SL_COMPRESSED y
bool ' SLIP debugging on' SL_DUMP y # bool ' SLIP debugging on' SL_DUMP y
fi fi
#bool 'PPP (point-to-point) support' CONFIG_PPP n #bool 'PPP (point-to-point) support' CONFIG_PPP n
bool 'PLIP (parallel port) support' CONFIG_PLIP n bool 'PLIP (parallel port) support' CONFIG_PLIP n
...@@ -104,8 +104,8 @@ bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n ...@@ -104,8 +104,8 @@ bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
* *
* character devices * character devices
* *
bool 'Keyboard meta-key sends ESC-prefix' CONFIG_KBD_META y #bool 'Keyboard meta-key sends ESC-prefix' CONFIG_KBD_META y
bool 'Keyboard Num Lock on by default' CONFIG_KBD_NUML y #bool 'Keyboard Num Lock on by default' CONFIG_KBD_NUML y
bool 'Parallel printer support' CONFIG_PRINTER y bool 'Parallel printer support' CONFIG_PRINTER y
bool 'Logitech busmouse support' CONFIG_BUSMOUSE n bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE y bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE y
......
...@@ -37,14 +37,20 @@ ...@@ -37,14 +37,20 @@
void Un_impl(void) void Un_impl(void)
{ {
unsigned char byte1, FPU_modrm; unsigned char byte1, FPU_modrm;
unsigned long address = FPU_ORIG_EIP;
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
/* No need to verify_area(), we have previously fetched these bytes. */ /* No need to verify_area(), we have previously fetched these bytes. */
byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP); printk("Unimplemented FPU Opcode at eip=%p : ", (void *) address);
FPU_modrm = get_fs_byte(1 + (unsigned char *) FPU_ORIG_EIP); while ( 1 )
{
printk("Unimplemented FPU Opcode at eip=%p : %02x ", byte1 = get_fs_byte((unsigned char *) address);
(void *) FPU_ORIG_EIP, byte1); if ( (byte1 & 0xf8) == 0xd8 ) break;
printk("[%02x]", byte1);
address++;
}
printk("%02x ", byte1);
FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
if (FPU_modrm >= 0300) if (FPU_modrm >= 0300)
printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
...@@ -57,6 +63,15 @@ void Un_impl(void) ...@@ -57,6 +63,15 @@ void Un_impl(void)
} }
/*
Called for opcodes which are illegal and which are known to result in a
SIGILL with a real 80486.
*/
void FPU_illegal(void)
{
math_abort(FPU_info,SIGILL);
}
void emu_printall() void emu_printall()
...@@ -65,11 +80,20 @@ void emu_printall() ...@@ -65,11 +80,20 @@ void emu_printall()
static char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR", static char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR",
"DeNorm", "Inf", "NaN", "Empty" }; "DeNorm", "Inf", "NaN", "Empty" };
unsigned char byte1, FPU_modrm; unsigned char byte1, FPU_modrm;
unsigned long address = FPU_ORIG_EIP;
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
/* No need to verify_area(), we have previously fetched these bytes. */ /* No need to verify_area(), we have previously fetched these bytes. */
byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP); printk("At %p: ", (void *) address);
FPU_modrm = get_fs_byte(1 + (unsigned char *) FPU_ORIG_EIP); while ( 1 )
{
byte1 = get_fs_byte((unsigned char *) address);
if ( (byte1 & 0xf8) == 0xd8 ) break;
printk("[%02x]", byte1);
address++;
}
printk("%02x ", byte1);
FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
partial_status = status_word(); partial_status = status_word();
#ifdef DEBUGGING #ifdef DEBUGGING
...@@ -88,7 +112,6 @@ if ( partial_status & SW_Denorm_Op ) printk("SW: denormalized operand\n"); ...@@ -88,7 +112,6 @@ if ( partial_status & SW_Denorm_Op ) printk("SW: denormalized operand\n");
if ( partial_status & SW_Invalid ) printk("SW: invalid operation\n"); if ( partial_status & SW_Invalid ) printk("SW: invalid operation\n");
#endif DEBUGGING #endif DEBUGGING
printk("At %p: %02x ", (void *) FPU_ORIG_EIP, byte1);
if (FPU_modrm >= 0300) if (FPU_modrm >= 0300)
printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
else else
...@@ -210,6 +233,7 @@ static struct { ...@@ -210,6 +233,7 @@ static struct {
0x125 in fpu_trig.c 0x125 in fpu_trig.c
0x126 in fpu_entry.c 0x126 in fpu_entry.c
0x127 in poly_2xm1.c 0x127 in poly_2xm1.c
0x128 in fpu_entry.c
0x2nn in an *.S file: 0x2nn in an *.S file:
0x201 in reg_u_add.S, reg_round.S 0x201 in reg_u_add.S, reg_round.S
0x202 in reg_u_div.S 0x202 in reg_u_div.S
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
| | | |
| Code to implement some of the FPU auxiliary instructions. | | Code to implement some of the FPU auxiliary instructions. |
| | | |
| Copyright (C) 1992,1993 | | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au | | Australia. E-mail billm@vaxc.cc.monash.edu.au |
| | | |
...@@ -48,7 +48,8 @@ void finit() ...@@ -48,7 +48,8 @@ void finit()
} }
static FUNC const finit_table[] = { static FUNC const finit_table[] = {
Un_impl, Un_impl, fclex, finit, Un_impl, Un_impl, Un_impl, Un_impl Un_impl, Un_impl, fclex, finit,
Un_impl, FPU_illegal, FPU_illegal, FPU_illegal
}; };
void finit_() void finit_()
...@@ -64,7 +65,8 @@ static void fstsw_ax(void) ...@@ -64,7 +65,8 @@ static void fstsw_ax(void)
} }
static FUNC const fstsw_table[] = { static FUNC const fstsw_table[] = {
fstsw_ax, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal,
FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
}; };
void fstsw_() void fstsw_()
...@@ -79,7 +81,8 @@ static void fnop(void) ...@@ -79,7 +81,8 @@ static void fnop(void)
} }
static FUNC const fp_nop_table[] = { static FUNC const fp_nop_table[] = {
fnop, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl fnop, FPU_illegal, FPU_illegal, FPU_illegal,
FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
}; };
void fp_nop() void fp_nop()
......
...@@ -69,6 +69,19 @@ extern char emulating; ...@@ -69,6 +69,19 @@ extern char emulating;
# define RE_ENTRANT_CHECK_ON # define RE_ENTRANT_CHECK_ON
#endif PARANOID #endif PARANOID
#define FWAIT_OPCODE 0x9b
#define OP_SIZE_PREFIX 0x66
#define ADDR_SIZE_PREFIX 0x67
#define PREFIX_CS 0x2e
#define PREFIX_DS 0x3e
#define PREFIX_ES 0x26
#define PREFIX_SS 0x36
#define PREFIX_FS 0x64
#define PREFIX_GS 0x65
#define PREFIX_REPE 0xf3
#define PREFIX_REPNE 0xf2
#define PREFIX_LOCK 0xf0
/* These are to defeat the default action, giving the instruction /* These are to defeat the default action, giving the instruction
no net effect: */ no net effect: */
#define NO_NET_DATA_EFFECT \ #define NO_NET_DATA_EFFECT \
...@@ -81,6 +94,7 @@ extern char emulating; ...@@ -81,6 +94,7 @@ extern char emulating;
typedef void (*FUNC)(void); typedef void (*FUNC)(void);
typedef struct fpu_reg FPU_REG; typedef struct fpu_reg FPU_REG;
typedef struct { unsigned char address_size, segment; } overrides;
#define st(x) ( regs[((top+x) &7 )] ) #define st(x) ( regs[((top+x) &7 )] )
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
| | | |
| The entry function for wm-FPU-emu | | The entry function for wm-FPU-emu |
| | | |
| Copyright (C) 1992,1993 | | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au | | Australia. E-mail billm@vaxc.cc.monash.edu.au |
| | | |
...@@ -34,17 +34,7 @@ ...@@ -34,17 +34,7 @@
#include <asm/segment.h> #include <asm/segment.h>
#define FWAIT_OPCODE 0x9b #define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */
#define OP_SIZE_PREFIX 0x66
#define ADDR_SIZE_PREFIX 0x67
#define PREFIX_CS 0x2e
#define PREFIX_DS 0x3e
#define PREFIX_ES 0x26
#define PREFIX_SS 0x36
#define PREFIX_FS 0x64
#define PREFIX_GS 0x65
#define __BAD__ Un_impl /* Not implemented */
#ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by default. */ #ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by default. */
...@@ -147,14 +137,13 @@ unsigned short FPU_data_selector; ...@@ -147,14 +137,13 @@ unsigned short FPU_data_selector;
char emulating=0; char emulating=0;
#endif PARANOID #endif PARANOID
#define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x)) static int valid_prefix(unsigned char *byte, overrides *override);
static int valid_prefix(unsigned char byte);
asmlinkage void math_emulate(long arg) asmlinkage void math_emulate(long arg)
{ {
unsigned char FPU_modrm; unsigned char FPU_modrm, byte1;
unsigned short code; overrides override;
int unmasked; int unmasked;
#ifdef PARANOID #ifdef PARANOID
...@@ -181,10 +170,11 @@ asmlinkage void math_emulate(long arg) ...@@ -181,10 +170,11 @@ asmlinkage void math_emulate(long arg)
SETUP_DATA_AREA(arg); SETUP_DATA_AREA(arg);
FPU_ORIG_EIP = FPU_EIP;
/* We cannot handle emulation in v86-mode */ /* We cannot handle emulation in v86-mode */
if (FPU_EFLAGS & 0x00020000) if (FPU_EFLAGS & 0x00020000)
{ {
FPU_ORIG_EIP = FPU_EIP;
math_abort(FPU_info,SIGILL); math_abort(FPU_info,SIGILL);
} }
...@@ -198,7 +188,6 @@ asmlinkage void math_emulate(long arg) ...@@ -198,7 +188,6 @@ asmlinkage void math_emulate(long arg)
/* We cannot handle multiple segments yet */ /* We cannot handle multiple segments yet */
if (FPU_CS != USER_CS || FPU_DS != USER_DS) if (FPU_CS != USER_CS || FPU_DS != USER_DS)
{ {
FPU_ORIG_EIP = FPU_EIP;
math_abort(FPU_info,SIGILL); math_abort(FPU_info,SIGILL);
} }
...@@ -206,12 +195,18 @@ asmlinkage void math_emulate(long arg) ...@@ -206,12 +195,18 @@ asmlinkage void math_emulate(long arg)
if (current->flags & PF_PTRACED) if (current->flags & PF_PTRACED)
FPU_lookahead = 0; FPU_lookahead = 0;
do_another_FPU_instruction: if ( !valid_prefix(&byte1, &override) )
{
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1); printk("FPU emulator: Unknown prefix byte 0x%02x\n", byte1);
code = get_fs_word((unsigned short *) FPU_EIP);
RE_ENTRANT_CHECK_ON; RE_ENTRANT_CHECK_ON;
EXCEPTION(EX_INTERNAL|0x126);
math_abort(FPU_info,SIGILL);
}
do_another_FPU_instruction:
FPU_EIP++; /* We have fetched the prefix and first code bytes. */
#ifdef PECULIAR_486 #ifdef PECULIAR_486
/* It would be more logical to do this only in get_address(), /* It would be more logical to do this only in get_address(),
...@@ -220,41 +215,36 @@ asmlinkage void math_emulate(long arg) ...@@ -220,41 +215,36 @@ asmlinkage void math_emulate(long arg)
FPU_data_selector = FPU_DS; FPU_data_selector = FPU_DS;
#endif PECULIAR_486 #endif PECULIAR_486
if ( (code & 0xf8) != 0xd8 ) if ( (byte1 & 0xf8) != 0xd8 )
{ {
if ( (code & 0xff) == FWAIT_OPCODE ) if ( byte1 == FWAIT_OPCODE )
{ {
if (partial_status & SW_Summary) if (partial_status & SW_Summary)
goto do_the_FPU_interrupt; goto do_the_FPU_interrupt;
else else
{
FPU_EIP++;
goto FPU_fwait_done; goto FPU_fwait_done;
} }
}
else if ( valid_prefix(code & 0xff) )
{
goto do_another_FPU_instruction;
}
#ifdef PARANOID #ifdef PARANOID
EXCEPTION(EX_INTERNAL|0x128);
math_abort(FPU_info,SIGILL);
#endif PARANOID
}
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
printk("FPU emulator: Unknown prefix byte 0x%02x\n", code & 0xff); FPU_code_verify_area(1);
FPU_modrm = get_fs_byte((unsigned short *) FPU_EIP);
RE_ENTRANT_CHECK_ON; RE_ENTRANT_CHECK_ON;
EXCEPTION(EX_INTERNAL|0x126);
FPU_EIP++; FPU_EIP++;
goto do_the_FPU_interrupt;
#endif PARANOID
}
if (partial_status & SW_Summary) if (partial_status & SW_Summary)
{ {
/* Ignore the error for now if the current instruction is a no-wait /* Ignore the error for now if the current instruction is a no-wait
control instruction */ control instruction */
/* The 80486 manual contradicts itself on this topic, /* The 80486 manual contradicts itself on this topic,
so I use the following list of such instructions until but a real 80486 uses the following instructions:
I can check on a real 80486:
fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex. fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
*/ */
unsigned short code = (FPU_modrm << 8) | byte1;
if ( ! ( (((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */ if ( ! ( (((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
(((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv, (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
fnstsw */ fnstsw */
...@@ -290,32 +280,17 @@ asmlinkage void math_emulate(long arg) ...@@ -290,32 +280,17 @@ asmlinkage void math_emulate(long arg)
} }
} }
FPU_entry_eip = FPU_ORIG_EIP = FPU_EIP; FPU_entry_eip = FPU_ORIG_EIP;
{ FPU_entry_op_cs = (byte1 << 24) | (FPU_modrm << 16) | (FPU_CS & 0xffff) ;
unsigned short swapped_code = code;
bswapw(swapped_code);
FPU_entry_op_cs = (swapped_code << 16) | (FPU_CS & 0xffff) ;
}
if ( (code & 0xff) == OP_SIZE_PREFIX )
{
FPU_EIP++;
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
code = get_fs_word((unsigned short *) FPU_EIP);
RE_ENTRANT_CHECK_ON;
}
FPU_EIP += 2;
FPU_modrm = code >> 8;
FPU_rm = FPU_modrm & 7; FPU_rm = FPU_modrm & 7;
if ( FPU_modrm < 0300 ) if ( FPU_modrm < 0300 )
{ {
/* All of these instructions use the mod/rm byte to get a data address */ /* All of these instructions use the mod/rm byte to get a data address */
get_address(FPU_modrm); get_address(FPU_modrm, override);
if ( !(code & 1) ) if ( !(byte1 & 1) )
{ {
unsigned short status1 = partial_status; unsigned short status1 = partial_status;
FPU_st0_ptr = &st(0); FPU_st0_ptr = &st(0);
...@@ -325,19 +300,19 @@ asmlinkage void math_emulate(long arg) ...@@ -325,19 +300,19 @@ asmlinkage void math_emulate(long arg)
if ( NOT_EMPTY_0 ) if ( NOT_EMPTY_0 )
{ {
unmasked = 0; /* Do this here to stop compiler warnings. */ unmasked = 0; /* Do this here to stop compiler warnings. */
switch ( (code >> 1) & 3 ) switch ( (byte1 >> 1) & 3 )
{ {
case 0: case 0:
unmasked = reg_load_single(); unmasked = reg_load_single(override);
break; break;
case 1: case 1:
reg_load_int32(); reg_load_int32(override);
break; break;
case 2: case 2:
unmasked = reg_load_double(); unmasked = reg_load_double(override);
break; break;
case 3: case 3:
reg_load_int16(); reg_load_int16(override);
break; break;
} }
...@@ -465,7 +440,7 @@ asmlinkage void math_emulate(long arg) ...@@ -465,7 +440,7 @@ asmlinkage void math_emulate(long arg)
} }
else else
{ {
load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1); load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1, override);
} }
reg_mem_instr_done: reg_mem_instr_done:
...@@ -478,7 +453,7 @@ asmlinkage void math_emulate(long arg) ...@@ -478,7 +453,7 @@ asmlinkage void math_emulate(long arg)
else else
{ {
/* None of these instructions access user memory */ /* None of these instructions access user memory */
unsigned char instr_index = (FPU_modrm & 0x38) | (code & 7); unsigned char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
#ifdef PECULIAR_486 #ifdef PECULIAR_486
/* This is supposed to be undefined, but a real 80486 seems /* This is supposed to be undefined, but a real 80486 seems
...@@ -523,7 +498,7 @@ asmlinkage void math_emulate(long arg) ...@@ -523,7 +498,7 @@ asmlinkage void math_emulate(long arg)
case _PUSH_: /* Only used by the fld st(i) instruction */ case _PUSH_: /* Only used by the fld st(i) instruction */
break; break;
case _null_: case _null_:
Un_impl(); FPU_illegal();
goto FPU_instruction_done; goto FPU_instruction_done;
default: default:
EXCEPTION(EX_INTERNAL|0x111); EXCEPTION(EX_INTERNAL|0x111);
...@@ -534,14 +509,6 @@ asmlinkage void math_emulate(long arg) ...@@ -534,14 +509,6 @@ asmlinkage void math_emulate(long arg)
FPU_instruction_done: FPU_instruction_done:
#ifdef DEBUG
{ /* !!!!!!!!!!! */
static unsigned int count = 0;
if ( (++count % 10000) == 0 )
printk("%d FP instr., current=0x%04x\n", count, code);
} /* !!!!!!!!!!! */
#endif DEBUG
ip_offset = FPU_entry_eip; ip_offset = FPU_entry_eip;
cs_selector = FPU_entry_op_cs; cs_selector = FPU_entry_op_cs;
data_operand_offset = (unsigned long)FPU_data_address; data_operand_offset = (unsigned long)FPU_data_address;
...@@ -559,13 +526,8 @@ asmlinkage void math_emulate(long arg) ...@@ -559,13 +526,8 @@ asmlinkage void math_emulate(long arg)
if (FPU_lookahead && !need_resched) if (FPU_lookahead && !need_resched)
{ {
unsigned char next; FPU_ORIG_EIP = FPU_EIP;
if ( valid_prefix(&byte1, &override) )
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
next = get_fs_byte((unsigned char *) FPU_EIP);
RE_ENTRANT_CHECK_ON;
if ( valid_prefix(next) )
goto do_another_FPU_instruction; goto do_another_FPU_instruction;
} }
...@@ -573,27 +535,54 @@ asmlinkage void math_emulate(long arg) ...@@ -573,27 +535,54 @@ asmlinkage void math_emulate(long arg)
} }
/* This function is not yet complete. To properly handle all prefix /* Support for prefix bytes is not yet complete. To properly handle
bytes, it will be necessary to change all emulator code which all prefix bytes, further changes are needed in the emulator code
accesses user address space. Access to separate segments is which accesses user address space. Access to separate segments is
important for msdos emulation. */ important for msdos emulation. */
static int valid_prefix(unsigned char byte) static int valid_prefix(unsigned char *Byte, overrides *override)
{ {
unsigned char byte;
unsigned long ip = FPU_EIP; unsigned long ip = FPU_EIP;
*override = (overrides) { 0, PREFIX_DS }; /* defaults */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
byte = get_fs_byte((unsigned char *) FPU_EIP);
RE_ENTRANT_CHECK_ON;
while ( 1 ) while ( 1 )
{ {
switch ( byte ) switch ( byte )
{ {
case ADDR_SIZE_PREFIX: case ADDR_SIZE_PREFIX:
case PREFIX_DS: /* Redundant */ override->address_size = ADDR_SIZE_PREFIX;
goto do_next_byte;
case PREFIX_CS: case PREFIX_CS:
override->segment = PREFIX_CS;
goto do_next_byte;
case PREFIX_ES: case PREFIX_ES:
override->segment = PREFIX_ES;
goto do_next_byte;
case PREFIX_SS: case PREFIX_SS:
override->segment = PREFIX_SS;
goto do_next_byte;
case PREFIX_FS: case PREFIX_FS:
override->segment = PREFIX_FS;
goto do_next_byte;
case PREFIX_GS: case PREFIX_GS:
override->segment = PREFIX_GS;
goto do_next_byte;
case PREFIX_DS: /* Redundant unless preceded by another override. */
override->segment = PREFIX_DS;
/* rep.. prefixes have no meaning for FPU instructions */
case PREFIX_LOCK:
case PREFIX_REPE:
case PREFIX_REPNE:
case OP_SIZE_PREFIX: /* Used often by gcc, but has no effect. */ case OP_SIZE_PREFIX: /* Used often by gcc, but has no effect. */
do_next_byte:
FPU_EIP++; FPU_EIP++;
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1); FPU_code_verify_area(1);
...@@ -601,10 +590,14 @@ static int valid_prefix(unsigned char byte) ...@@ -601,10 +590,14 @@ static int valid_prefix(unsigned char byte)
RE_ENTRANT_CHECK_ON; RE_ENTRANT_CHECK_ON;
break; break;
case FWAIT_OPCODE: case FWAIT_OPCODE:
*Byte = byte;
return 1; return 1;
default: default:
if ( (byte & 0xf8) == 0xd8 ) if ( (byte & 0xf8) == 0xd8 )
{
*Byte = byte;
return 1; return 1;
}
else else
{ {
FPU_EIP = ip; FPU_EIP = ip;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
| | | |
| Implement a few FPU instructions. | | Implement a few FPU instructions. |
| | | |
| Copyright (C) 1992,1993 | | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au | | Australia. E-mail billm@vaxc.cc.monash.edu.au |
| | | |
...@@ -118,7 +118,7 @@ static void fxam(void) ...@@ -118,7 +118,7 @@ static void fxam(void)
} }
static FUNC const fp_etc_table[] = { static FUNC const fp_etc_table[] = {
fchs, fabs, Un_impl, Un_impl, ftst_, fxam, Un_impl, Un_impl fchs, fabs, FPU_illegal, FPU_illegal, ftst_, fxam, FPU_illegal, FPU_illegal
}; };
void fp_etc() void fp_etc()
......
/* errors.c */ /* errors.c */
extern void Un_impl(void); extern void Un_impl(void);
extern void FPU_illegal(void);
extern void emu_printall(void); extern void emu_printall(void);
extern void stack_overflow(void); extern void stack_overflow(void);
extern void stack_underflow(void); extern void stack_underflow(void);
...@@ -62,10 +63,10 @@ extern void trig_a(void); ...@@ -62,10 +63,10 @@ extern void trig_a(void);
extern void trig_b(void); extern void trig_b(void);
/* get_address.c */ /* get_address.c */
extern void get_address(unsigned char FPU_modrm); extern void get_address(unsigned char FPU_modrm, overrides override);
/* load_store.c */ /* load_store.c */
extern void load_store_instr(char type); extern void load_store_instr(char type, overrides override);
/* poly_2xm1.c */ /* poly_2xm1.c */
extern int poly_2xm1(FPU_REG const *arg, FPU_REG *result); extern int poly_2xm1(FPU_REG const *arg, FPU_REG *result);
...@@ -104,20 +105,20 @@ extern void fucompp(void); ...@@ -104,20 +105,20 @@ extern void fucompp(void);
extern void fconst(void); extern void fconst(void);
/* reg_ld_str.c */ /* reg_ld_str.c */
extern int reg_load_extended(void); extern int reg_load_extended(overrides override);
extern int reg_load_double(void); extern int reg_load_double(overrides override);
extern int reg_load_single(void); extern int reg_load_single(overrides override);
extern void reg_load_int64(void); extern void reg_load_int64(overrides override);
extern void reg_load_int32(void); extern void reg_load_int32(overrides override);
extern void reg_load_int16(void); extern void reg_load_int16(overrides override);
extern void reg_load_bcd(void); extern void reg_load_bcd(overrides override);
extern int reg_store_extended(void); extern int reg_store_extended(overrides override);
extern int reg_store_double(void); extern int reg_store_double(overrides override);
extern int reg_store_single(void); extern int reg_store_single(overrides override);
extern int reg_store_int64(void); extern int reg_store_int64(overrides override);
extern int reg_store_int32(void); extern int reg_store_int32(overrides override);
extern int reg_store_int16(void); extern int reg_store_int16(overrides override);
extern int reg_store_bcd(void); extern int reg_store_bcd(overrides override);
extern int round_to_int(FPU_REG *r); extern int round_to_int(FPU_REG *r);
extern char *fldenv(void); extern char *fldenv(void);
extern void frstor(void); extern void frstor(void);
......
...@@ -112,7 +112,7 @@ static void *sib(int mod) ...@@ -112,7 +112,7 @@ static void *sib(int mod)
*/ */
void get_address(unsigned char FPU_modrm) void get_address(unsigned char FPU_modrm, overrides override)
{ {
unsigned char mod; unsigned char mod;
long *cpu_reg_ptr; long *cpu_reg_ptr;
...@@ -137,12 +137,21 @@ void get_address(unsigned char FPU_modrm) ...@@ -137,12 +137,21 @@ void get_address(unsigned char FPU_modrm)
case 0: case 0:
if (FPU_rm == 5) if (FPU_rm == 5)
{ {
/* Special case: disp32 */ /* Special case: disp16 or disp32 */
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
if ( override.address_size == ADDR_SIZE_PREFIX )
{
FPU_code_verify_area(2);
offset = get_fs_word((unsigned short *) FPU_EIP);
FPU_EIP += 2;
}
else
{
FPU_code_verify_area(4); FPU_code_verify_area(4);
offset = get_fs_long((unsigned long *) FPU_EIP); offset = get_fs_long((unsigned long *) FPU_EIP);
RE_ENTRANT_CHECK_ON;
FPU_EIP += 4; FPU_EIP += 4;
}
RE_ENTRANT_CHECK_ON;
FPU_data_address = (void *) offset; FPU_data_address = (void *) offset;
return; return;
} }
...@@ -161,12 +170,21 @@ void get_address(unsigned char FPU_modrm) ...@@ -161,12 +170,21 @@ void get_address(unsigned char FPU_modrm)
FPU_EIP++; FPU_EIP++;
break; break;
case 2: case 2:
/* 32 bit displacement */ /* 16 or 32 bit displacement */
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
if ( override.address_size == ADDR_SIZE_PREFIX )
{
FPU_code_verify_area(2);
offset = (signed) get_fs_word((unsigned short *) FPU_EIP);
FPU_EIP += 2;
}
else
{
FPU_code_verify_area(4); FPU_code_verify_area(4);
offset = (signed) get_fs_long((unsigned long *) FPU_EIP); offset = (signed) get_fs_long((unsigned long *) FPU_EIP);
RE_ENTRANT_CHECK_ON;
FPU_EIP += 4; FPU_EIP += 4;
}
RE_ENTRANT_CHECK_ON;
break; break;
case 3: case 3:
/* Not legal for the FPU */ /* Not legal for the FPU */
...@@ -174,4 +192,6 @@ void get_address(unsigned char FPU_modrm) ...@@ -174,4 +192,6 @@ void get_address(unsigned char FPU_modrm)
} }
FPU_data_address = offset + (char *)*cpu_reg_ptr; FPU_data_address = offset + (char *)*cpu_reg_ptr;
if ( override.address_size == ADDR_SIZE_PREFIX )
FPU_data_address = (void *)((long)FPU_data_address & 0xffff);
} }
...@@ -46,7 +46,7 @@ static unsigned char const type_table[32] = { ...@@ -46,7 +46,7 @@ static unsigned char const type_table[32] = {
_NONE_, _REG0_, _NONE_, _REG0_ _NONE_, _REG0_, _NONE_, _REG0_
}; };
void load_store_instr(char type) void load_store_instr(char type, overrides override)
{ {
FPU_REG *pop_ptr; /* We need a version of FPU_st0_ptr which won't FPU_REG *pop_ptr; /* We need a version of FPU_st0_ptr which won't
change if the emulator is re-entered. */ change if the emulator is re-entered. */
...@@ -72,7 +72,7 @@ void load_store_instr(char type) ...@@ -72,7 +72,7 @@ void load_store_instr(char type)
} }
break; break;
case _null_: case _null_:
Un_impl(); FPU_illegal();
return; return;
#ifdef PARANOID #ifdef PARANOID
default: default:
...@@ -85,7 +85,7 @@ switch ( type ) ...@@ -85,7 +85,7 @@ switch ( type )
{ {
case 000: /* fld m32real */ case 000: /* fld m32real */
clear_C1(); clear_C1();
reg_load_single(); reg_load_single(override);
if ( (FPU_loaded_data.tag == TW_NaN) && if ( (FPU_loaded_data.tag == TW_NaN) &&
real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) ) real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) )
{ {
...@@ -96,12 +96,12 @@ switch ( type ) ...@@ -96,12 +96,12 @@ switch ( type )
break; break;
case 001: /* fild m32int */ case 001: /* fild m32int */
clear_C1(); clear_C1();
reg_load_int32(); reg_load_int32(override);
reg_move(&FPU_loaded_data, pop_ptr); reg_move(&FPU_loaded_data, pop_ptr);
break; break;
case 002: /* fld m64real */ case 002: /* fld m64real */
clear_C1(); clear_C1();
reg_load_double(); reg_load_double(override);
if ( (FPU_loaded_data.tag == TW_NaN) && if ( (FPU_loaded_data.tag == TW_NaN) &&
real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) ) real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) )
{ {
...@@ -112,46 +112,46 @@ switch ( type ) ...@@ -112,46 +112,46 @@ switch ( type )
break; break;
case 003: /* fild m16int */ case 003: /* fild m16int */
clear_C1(); clear_C1();
reg_load_int16(); reg_load_int16(override);
reg_move(&FPU_loaded_data, pop_ptr); reg_move(&FPU_loaded_data, pop_ptr);
break; break;
case 010: /* fst m32real */ case 010: /* fst m32real */
clear_C1(); clear_C1();
reg_store_single(); reg_store_single(override);
break; break;
case 011: /* fist m32int */ case 011: /* fist m32int */
clear_C1(); clear_C1();
reg_store_int32(); reg_store_int32(override);
break; break;
case 012: /* fst m64real */ case 012: /* fst m64real */
clear_C1(); clear_C1();
reg_store_double(); reg_store_double(override);
break; break;
case 013: /* fist m16int */ case 013: /* fist m16int */
clear_C1(); clear_C1();
reg_store_int16(); reg_store_int16(override);
break; break;
case 014: /* fstp m32real */ case 014: /* fstp m32real */
clear_C1(); clear_C1();
if ( reg_store_single() ) if ( reg_store_single(override) )
pop_0(); /* pop only if the number was actually stored pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */ (see the 80486 manual p16-28) */
break; break;
case 015: /* fistp m32int */ case 015: /* fistp m32int */
clear_C1(); clear_C1();
if ( reg_store_int32() ) if ( reg_store_int32(override) )
pop_0(); /* pop only if the number was actually stored pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */ (see the 80486 manual p16-28) */
break; break;
case 016: /* fstp m64real */ case 016: /* fstp m64real */
clear_C1(); clear_C1();
if ( reg_store_double() ) if ( reg_store_double(override) )
pop_0(); /* pop only if the number was actually stored pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */ (see the 80486 manual p16-28) */
break; break;
case 017: /* fistp m16int */ case 017: /* fistp m16int */
clear_C1(); clear_C1();
if ( reg_store_int16() ) if ( reg_store_int16(override) )
pop_0(); /* pop only if the number was actually stored pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */ (see the 80486 manual p16-28) */
break; break;
...@@ -163,7 +163,7 @@ switch ( type ) ...@@ -163,7 +163,7 @@ switch ( type )
break; break;
case 023: /* fbld m80dec */ case 023: /* fbld m80dec */
clear_C1(); clear_C1();
reg_load_bcd(); reg_load_bcd(override);
reg_move(&FPU_loaded_data, pop_ptr); reg_move(&FPU_loaded_data, pop_ptr);
break; break;
case 024: /* fldcw */ case 024: /* fldcw */
...@@ -183,12 +183,12 @@ switch ( type ) ...@@ -183,12 +183,12 @@ switch ( type )
break; break;
case 025: /* fld m80real */ case 025: /* fld m80real */
clear_C1(); clear_C1();
reg_load_extended(); reg_load_extended(override);
reg_move(&FPU_loaded_data, pop_ptr); reg_move(&FPU_loaded_data, pop_ptr);
break; break;
case 027: /* fild m64int */ case 027: /* fild m64int */
clear_C1(); clear_C1();
reg_load_int64(); reg_load_int64(override);
reg_move(&FPU_loaded_data, pop_ptr); reg_move(&FPU_loaded_data, pop_ptr);
break; break;
case 030: /* fstenv m14/28byte */ case 030: /* fstenv m14/28byte */
...@@ -201,7 +201,7 @@ switch ( type ) ...@@ -201,7 +201,7 @@ switch ( type )
break; break;
case 033: /* fbstp m80dec */ case 033: /* fbstp m80dec */
clear_C1(); clear_C1();
if ( reg_store_bcd() ) if ( reg_store_bcd(override) )
pop_0(); /* pop only if the number was actually stored pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */ (see the 80486 manual p16-28) */
break; break;
...@@ -215,7 +215,7 @@ switch ( type ) ...@@ -215,7 +215,7 @@ switch ( type )
break; break;
case 035: /* fstp m80real */ case 035: /* fstp m80real */
clear_C1(); clear_C1();
if ( reg_store_extended() ) if ( reg_store_extended(override) )
pop_0(); /* pop only if the number was actually stored pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */ (see the 80486 manual p16-28) */
break; break;
...@@ -229,7 +229,7 @@ switch ( type ) ...@@ -229,7 +229,7 @@ switch ( type )
break; break;
case 037: /* fistp m64int */ case 037: /* fistp m64int */
clear_C1(); clear_C1();
if ( reg_store_int64() ) if ( reg_store_int64(override) )
pop_0(); /* pop only if the number was actually stored pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */ (see the 80486 manual p16-28) */
break; break;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
| | | |
| Compare two floating point registers | | Compare two floating point registers |
| | | |
| Copyright (C) 1992,1993 | | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au | | Australia. E-mail billm@vaxc.cc.monash.edu.au |
| | | |
...@@ -336,7 +336,7 @@ void fcompp() ...@@ -336,7 +336,7 @@ void fcompp()
/* fcompp */ /* fcompp */
if (FPU_rm != 1) if (FPU_rm != 1)
{ {
Un_impl(); FPU_illegal();
return; return;
} }
if ( !compare_st_st(1) ) if ( !compare_st_st(1) )
...@@ -375,5 +375,5 @@ void fucompp() ...@@ -375,5 +375,5 @@ void fucompp()
} }
} }
else else
Un_impl(); FPU_illegal();
} }
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
| | | |
| All of the constant FPU_REGs | | All of the constant FPU_REGs |
| | | |
| Copyright (C) 1992,1993 | | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au | | Australia. E-mail billm@vaxc.cc.monash.edu.au |
| | | |
...@@ -107,7 +107,7 @@ static void fldz(void) ...@@ -107,7 +107,7 @@ static void fldz(void)
} }
static FUNC constants_table[] = { static FUNC constants_table[] = {
fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, Un_impl fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, FPU_illegal
}; };
void fconst(void) void fconst(void)
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
| | | |
| Divide one FPU_REG by another and put the result in a destination FPU_REG.| | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
| | | |
| Copyright (C) 1992,1993 | | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au | | Australia. E-mail billm@vaxc.cc.monash.edu.au |
| | | |
......
...@@ -44,7 +44,7 @@ FPU_REG FPU_loaded_data; ...@@ -44,7 +44,7 @@ FPU_REG FPU_loaded_data;
/* Get a long double from user memory */ /* Get a long double from user memory */
int reg_load_extended(void) int reg_load_extended(overrides override)
{ {
long double *s = (long double *)FPU_data_address; long double *s = (long double *)FPU_data_address;
unsigned long sigl, sigh, exp; unsigned long sigl, sigh, exp;
...@@ -145,7 +145,7 @@ int reg_load_extended(void) ...@@ -145,7 +145,7 @@ int reg_load_extended(void)
/* Get a double from user memory */ /* Get a double from user memory */
int reg_load_double(void) int reg_load_double(overrides override)
{ {
double *dfloat = (double *)FPU_data_address; double *dfloat = (double *)FPU_data_address;
int exp; int exp;
...@@ -223,7 +223,7 @@ int reg_load_double(void) ...@@ -223,7 +223,7 @@ int reg_load_double(void)
/* Get a float from user memory */ /* Get a float from user memory */
int reg_load_single(void) int reg_load_single(overrides override)
{ {
float *single = (float *)FPU_data_address; float *single = (float *)FPU_data_address;
unsigned m32; unsigned m32;
...@@ -292,7 +292,7 @@ int reg_load_single(void) ...@@ -292,7 +292,7 @@ int reg_load_single(void)
/* Get a long long from user memory */ /* Get a long long from user memory */
void reg_load_int64(void) void reg_load_int64(overrides override)
{ {
long long *_s = (long long *)FPU_data_address; long long *_s = (long long *)FPU_data_address;
int e; int e;
...@@ -324,7 +324,7 @@ void reg_load_int64(void) ...@@ -324,7 +324,7 @@ void reg_load_int64(void)
/* Get a long from user memory */ /* Get a long from user memory */
void reg_load_int32(void) void reg_load_int32(overrides override)
{ {
long *_s = (long *)FPU_data_address; long *_s = (long *)FPU_data_address;
long s; long s;
...@@ -356,7 +356,7 @@ void reg_load_int32(void) ...@@ -356,7 +356,7 @@ void reg_load_int32(void)
/* Get a short from user memory */ /* Get a short from user memory */
void reg_load_int16(void) void reg_load_int16(overrides override)
{ {
short *_s = (short *)FPU_data_address; short *_s = (short *)FPU_data_address;
int s, e; int s, e;
...@@ -389,7 +389,7 @@ void reg_load_int16(void) ...@@ -389,7 +389,7 @@ void reg_load_int16(void)
/* Get a packed bcd array from user memory */ /* Get a packed bcd array from user memory */
void reg_load_bcd(void) void reg_load_bcd(overrides override)
{ {
char *s = (char *)FPU_data_address; char *s = (char *)FPU_data_address;
int pos; int pos;
...@@ -436,7 +436,7 @@ void reg_load_bcd(void) ...@@ -436,7 +436,7 @@ void reg_load_bcd(void)
/*===========================================================================*/ /*===========================================================================*/
/* Put a long double into user memory */ /* Put a long double into user memory */
int reg_store_extended(void) int reg_store_extended(overrides override)
{ {
/* /*
The only exception raised by an attempt to store to an The only exception raised by an attempt to store to an
...@@ -475,7 +475,7 @@ int reg_store_extended(void) ...@@ -475,7 +475,7 @@ int reg_store_extended(void)
/* Put a double into user memory */ /* Put a double into user memory */
int reg_store_double(void) int reg_store_double(overrides override)
{ {
double *dfloat = (double *)FPU_data_address; double *dfloat = (double *)FPU_data_address;
unsigned long l[2]; unsigned long l[2];
...@@ -670,7 +670,7 @@ int reg_store_double(void) ...@@ -670,7 +670,7 @@ int reg_store_double(void)
/* Put a float into user memory */ /* Put a float into user memory */
int reg_store_single(void) int reg_store_single(overrides override)
{ {
float *single = (float *)FPU_data_address; float *single = (float *)FPU_data_address;
long templ; long templ;
...@@ -859,7 +859,7 @@ int reg_store_single(void) ...@@ -859,7 +859,7 @@ int reg_store_single(void)
/* Put a long long into user memory */ /* Put a long long into user memory */
int reg_store_int64(void) int reg_store_int64(overrides override)
{ {
long long *d = (long long *)FPU_data_address; long long *d = (long long *)FPU_data_address;
FPU_REG t; FPU_REG t;
...@@ -918,7 +918,7 @@ int reg_store_int64(void) ...@@ -918,7 +918,7 @@ int reg_store_int64(void)
/* Put a long into user memory */ /* Put a long into user memory */
int reg_store_int32(void) int reg_store_int32(overrides override)
{ {
long *d = (long *)FPU_data_address; long *d = (long *)FPU_data_address;
FPU_REG t; FPU_REG t;
...@@ -972,7 +972,7 @@ int reg_store_int32(void) ...@@ -972,7 +972,7 @@ int reg_store_int32(void)
/* Put a short into user memory */ /* Put a short into user memory */
int reg_store_int16(void) int reg_store_int16(overrides override)
{ {
short *d = (short *)FPU_data_address; short *d = (short *)FPU_data_address;
FPU_REG t; FPU_REG t;
...@@ -1026,7 +1026,7 @@ int reg_store_int16(void) ...@@ -1026,7 +1026,7 @@ int reg_store_int16(void)
/* Put a packed bcd array into user memory */ /* Put a packed bcd array into user memory */
int reg_store_bcd(void) int reg_store_bcd(overrides override)
{ {
char *d = (char *)FPU_data_address; char *d = (char *)FPU_data_address;
FPU_REG t; FPU_REG t;
...@@ -1240,7 +1240,7 @@ void frstor(void) ...@@ -1240,7 +1240,7 @@ void frstor(void)
{ {
/* Load each register. */ /* Load each register. */
FPU_data_address = (void *)(s+i*10); FPU_data_address = (void *)(s+i*10);
reg_load_extended(); reg_load_extended((overrides){0,0});
stnr = (i+top) & 7; stnr = (i+top) & 7;
tag = regs[stnr].tag; /* Derived from the loaded tag word. */ tag = regs[stnr].tag; /* Derived from the loaded tag word. */
reg_move(&FPU_loaded_data, &regs[stnr]); reg_move(&FPU_loaded_data, &regs[stnr]);
......
...@@ -9,5 +9,5 @@ ...@@ -9,5 +9,5 @@
| | | |
+---------------------------------------------------------------------------*/ +---------------------------------------------------------------------------*/
#define FPU_VERSION "wm-FPU-emu version Beta 1.8" #define FPU_VERSION "wm-FPU-emu version Beta 1.9"
...@@ -624,8 +624,7 @@ static void update_attr(int currcons) ...@@ -624,8 +624,7 @@ static void update_attr(int currcons)
attr = (attr & 0xf0) | 0x08; attr = (attr & 0xf0) | 0x08;
} }
if (decscnm) if (decscnm)
video_erase_char = ((color & 0x88) | (((color >> 4) | video_erase_char = (((color & 0x88) | (((color >> 4) | (color << 4)) & 0x77)) << 8) | ' ';
(color << 4)) & 0x77) << 8) | ' ';
else else
video_erase_char = (color << 8) | ' '; video_erase_char = (color << 8) | ' ';
} }
......
...@@ -267,7 +267,8 @@ void ext2_free_blocks (struct super_block * sb, unsigned long block, ...@@ -267,7 +267,8 @@ void ext2_free_blocks (struct super_block * sb, unsigned long block,
if (block < es->s_first_data_block || if (block < es->s_first_data_block ||
(block + count) > es->s_blocks_count) { (block + count) > es->s_blocks_count) {
ext2_error (sb, "ext2_free_blocks", ext2_error (sb, "ext2_free_blocks",
"Freeing blocks not in datazone"); "Freeing blocks not in datazone\n"
"block = %lu, count = %lu", block, count);
unlock_super (sb); unlock_super (sb);
return; return;
} }
...@@ -303,11 +304,13 @@ void ext2_free_blocks (struct super_block * sb, unsigned long block, ...@@ -303,11 +304,13 @@ void ext2_free_blocks (struct super_block * sb, unsigned long block,
ext2_warning (sb, "ext2_free_blocks", ext2_warning (sb, "ext2_free_blocks",
"bit already cleared for block %lu", "bit already cleared for block %lu",
block); block);
else {
gdp->bg_free_blocks_count++;
es->s_free_blocks_count++;
}
} }
gdp->bg_free_blocks_count += count;
bh2->b_dirt = 1; bh2->b_dirt = 1;
es->s_free_blocks_count += count;
sb->u.ext2_sb.s_sbh->b_dirt = 1; sb->u.ext2_sb.s_sbh->b_dirt = 1;
bh->b_dirt = 1; bh->b_dirt = 1;
...@@ -356,6 +359,11 @@ int ext2_new_block (struct super_block * sb, unsigned long goal, ...@@ -356,6 +359,11 @@ int ext2_new_block (struct super_block * sb, unsigned long goal,
ext2_debug ("goal=%lu.\n", goal); ext2_debug ("goal=%lu.\n", goal);
if (goal < es->s_first_data_block || goal >= es->s_blocks_count) {
ext2_warning (sb, "ext2_new_block",
"Goal out of bounds: %lu", goal);
goal = es->s_first_data_block;
}
repeat: repeat:
/* /*
* First, test whether the goal block is free. * First, test whether the goal block is free.
......
...@@ -88,10 +88,10 @@ static int get_loadavg(char * buffer) ...@@ -88,10 +88,10 @@ static int get_loadavg(char * buffer)
static int get_kstat(char * buffer) static int get_kstat(char * buffer)
{ {
return sprintf(buffer, "cpu %u,%u,%u,%lu\n" return sprintf(buffer, "cpu %u %u %u %lu\n"
"disk %u,%u,%u,%u\n" "disk %u %u %u %u\n"
"page %u,%u\n" "page %u %u\n"
"swap %u,%u\n" "swap %u %u\n"
"intr %u\n" "intr %u\n"
"ctxt %u\n" "ctxt %u\n"
"btime %lu\n", "btime %lu\n",
......
...@@ -50,6 +50,10 @@ static int proc_follow_link(struct inode * dir, struct inode * inode, ...@@ -50,6 +50,10 @@ static int proc_follow_link(struct inode * dir, struct inode * inode,
iput(dir); iput(dir);
if (!inode) if (!inode)
return -ENOENT; return -ENOENT;
if (!permission(inode, MAY_EXEC)) {
iput(inode);
return -EACCES;
}
ino = inode->i_ino; ino = inode->i_ino;
pid = ino >> 16; pid = ino >> 16;
ino &= 0x0000ffff; ino &= 0x0000ffff;
......
...@@ -167,14 +167,14 @@ void math_error(void) ...@@ -167,14 +167,14 @@ void math_error(void)
} }
env = &last_task_used_math->tss.i387.hard; env = &last_task_used_math->tss.i387.hard;
send_sig(SIGFPE, last_task_used_math, 1); send_sig(SIGFPE, last_task_used_math, 1);
current->tss.trap_no = 16; last_task_used_math->tss.trap_no = 16;
current->tss.error_code = 0; last_task_used_math->tss.error_code = 0;
__asm__ __volatile__("fnsave %0":"=m" (*env)); __asm__ __volatile__("fnsave %0":"=m" (*env));
last_task_used_math = NULL; last_task_used_math = NULL;
stts(); stts();
env->fcs = (env->swd & 0x0000ffff) | (env->fcs & 0xffff0000); env->fcs = (env->swd & 0x0000ffff) | (env->fcs & 0xffff0000);
env->fos = env->twd; env->fos = env->twd;
env->swd &= 0xffff0000; env->swd &= 0xffff3800;
env->twd = 0xffffffff; env->twd = 0xffffffff;
} }
......
...@@ -251,19 +251,14 @@ arp_send_q(void) ...@@ -251,19 +251,14 @@ arp_send_q(void)
/* Create and send our response to an ARP request. */ /* Create and send our response to an ARP request. */
static int
/* arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
* We are now a bit smarter. We know the old buffer must be big enough
* so why allocate a new one for the reply ?
*/
static int arp_response(struct sk_buff *skb,struct arphdr *arp1, struct device *dev, int addrtype)
{ {
struct arphdr *arp2; struct arphdr *arp2;
struct sk_buff *skb;
unsigned long src, dst; unsigned long src, dst;
unsigned char *ptr1, *ptr2; unsigned char *ptr1, *ptr2;
int hlen; int hlen;
int len;
struct arp_table *apt = NULL;/* =NULL otherwise the compiler gives warnings */ struct arp_table *apt = NULL;/* =NULL otherwise the compiler gives warnings */
/* Decode the source (REQUEST) message. */ /* Decode the source (REQUEST) message. */
...@@ -275,28 +270,24 @@ static int arp_response(struct sk_buff *skb,struct arphdr *arp1, struct device * ...@@ -275,28 +270,24 @@ static int arp_response(struct sk_buff *skb,struct arphdr *arp1, struct device *
{ {
apt=arp_lookup_proxy(dst); apt=arp_lookup_proxy(dst);
if(apt==NULL) if(apt==NULL)
{
kfree_skb(skb,FREE_READ);
return(1); return(1);
} }
}
skb->h.raw=skb->data;
skb->len+=dev->hard_header_len; /* Grow the packet back to its original form */
/* Can't check for exceeding the size - some people pad. */ /* Get some mem and initialize it for the return trip. */
len= sizeof(struct arphdr) + (2 * arp1->ar_hln) + (2 * arp1->ar_pln) + dev->hard_header_len; skb = alloc_skb(sizeof(struct sk_buff) +
if(len>skb->len) sizeof(struct arphdr) +
{ (2 * arp1->ar_hln) + (2 * arp1->ar_pln) +
printk("Received runt ARP request!\n"); dev->hard_header_len, GFP_ATOMIC);
kfree_skb(skb,FREE_READ); if (skb == NULL) {
return 1; printk("ARP: no memory available for ARP REPLY!\n");
return(1);
} }
skb->len = len; skb->mem_addr = skb;
skb->len = sizeof(struct arphdr) + (2 * arp1->ar_hln) +
(2 * arp1->ar_pln) + dev->hard_header_len;
skb->mem_len = sizeof(struct sk_buff) + skb->len;
hlen = dev->hard_header(skb->data, dev, ETH_P_ARP, src, dst, skb->len); hlen = dev->hard_header(skb->data, dev, ETH_P_ARP, src, dst, skb->len);
if (hlen < 0) { if (hlen < 0) {
printk("ARP: cannot create HW frame header for REPLY !\n"); printk("ARP: cannot create HW frame header for REPLY !\n");
kfree_skb(skb, FREE_WRITE); kfree_skb(skb, FREE_WRITE);
...@@ -587,7 +578,8 @@ arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -587,7 +578,8 @@ arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
* Yes, it is for us. * Yes, it is for us.
* Allocate, fill in and send an ARP REPLY packet. * Allocate, fill in and send an ARP REPLY packet.
*/ */
ret = arp_response(skb,arp, dev, addr_hint); ret = arp_response(arp, dev, addr_hint);
kfree_skb(skb, FREE_READ);
return(ret); return(ret);
} }
...@@ -616,12 +608,14 @@ arp_send(unsigned long paddr, struct device *dev, unsigned long saddr) ...@@ -616,12 +608,14 @@ arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
/* Fill in the request. */ /* Fill in the request. */
skb->sk = NULL; skb->sk = NULL;
skb->mem_addr = skb;
skb->len = sizeof(struct arphdr) + skb->len = sizeof(struct arphdr) +
dev->hard_header_len + (2 * dev->addr_len) + 8; dev->hard_header_len + (2 * dev->addr_len) + 8;
skb->mem_len = sizeof(struct sk_buff) + skb->len;
skb->arp = 1; skb->arp = 1;
skb->dev = dev; skb->dev = dev;
skb->free = 1;
skb->next = NULL; skb->next = NULL;
skb->free = 1;
tmp = dev->hard_header(skb->data, dev, ETH_P_ARP, 0, saddr, skb->len); tmp = dev->hard_header(skb->data, dev, ETH_P_ARP, 0, saddr, skb->len);
if (tmp < 0) { if (tmp < 0) {
kfree_skb(skb,FREE_WRITE); kfree_skb(skb,FREE_WRITE);
......
...@@ -423,8 +423,8 @@ void kfree_skb(struct sk_buff *skb, int rw) ...@@ -423,8 +423,8 @@ void kfree_skb(struct sk_buff *skb, int rw)
* fields and also do memory statistics to find all the [BEEP] leaks. * fields and also do memory statistics to find all the [BEEP] leaks.
*/ */
struct sk_buff *alloc_skb(unsigned int size,int priority) struct sk_buff *alloc_skb(unsigned int size,int priority)
{ {
struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority); struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority);
if(skb==NULL) if(skb==NULL)
return NULL; return NULL;
...@@ -440,7 +440,7 @@ void kfree_skb(struct sk_buff *skb, int rw) ...@@ -440,7 +440,7 @@ void kfree_skb(struct sk_buff *skb, int rw)
skb->magic_debug_cookie=SK_GOOD_SKB; skb->magic_debug_cookie=SK_GOOD_SKB;
skb->users=0; skb->users=0;
return skb; return skb;
} }
/* /*
* Free an skbuff by memory * Free an skbuff by memory
......
...@@ -634,7 +634,7 @@ static void tcp_send_skb(struct sock *sk, struct sk_buff *skb) ...@@ -634,7 +634,7 @@ static void tcp_send_skb(struct sock *sk, struct sk_buff *skb)
skb->next = NULL; skb->next = NULL;
skb->magic = TCP_WRITE_QUEUE_MAGIC; skb->magic = TCP_WRITE_QUEUE_MAGIC;
if (sk->wback == NULL) { if (sk->wback == NULL) {
sk->wfront=skb; sk->wfront = skb;
} else { } else {
sk->wback->next = skb; sk->wback->next = skb;
} }
...@@ -685,7 +685,7 @@ void tcp_enqueue_partial(struct sk_buff * skb, struct sock * sk) ...@@ -685,7 +685,7 @@ void tcp_enqueue_partial(struct sk_buff * skb, struct sock * sk)
if (tmp) if (tmp)
del_timer(&sk->partial_timer); del_timer(&sk->partial_timer);
sk->partial = skb; sk->partial = skb;
sk->partial_timer.expires = 5*HZ; sk->partial_timer.expires = HZ;
sk->partial_timer.function = (void (*)(unsigned long)) tcp_send_partial; sk->partial_timer.function = (void (*)(unsigned long)) tcp_send_partial;
sk->partial_timer.data = (unsigned long) sk; sk->partial_timer.data = (unsigned long) sk;
add_timer(&sk->partial_timer); add_timer(&sk->partial_timer);
...@@ -2182,7 +2182,7 @@ tcp_close(struct sock *sk, int timeout) ...@@ -2182,7 +2182,7 @@ tcp_close(struct sock *sk, int timeout)
reset_timer(sk, TIME_WRITE, sk->rto); reset_timer(sk, TIME_WRITE, sk->rto);
buff->next = NULL; buff->next = NULL;
if (sk->wback == NULL) { if (sk->wback == NULL) {
sk->wfront=buff; sk->wfront = buff;
} else { } else {
sk->wback->next = buff; sk->wback->next = buff;
} }
...@@ -2224,7 +2224,7 @@ tcp_write_xmit(struct sock *sk) ...@@ -2224,7 +2224,7 @@ tcp_write_xmit(struct sock *sk)
&& sk->packets_out < sk->cong_window) { && sk->packets_out < sk->cong_window) {
skb = sk->wfront; skb = sk->wfront;
IS_SKB(skb); IS_SKB(skb);
sk->wfront =(struct sk_buff *)skb->next; sk->wfront = skb->next;
if (sk->wfront == NULL) sk->wback = NULL; if (sk->wfront == NULL) sk->wback = NULL;
skb->next = NULL; skb->next = NULL;
if (skb->magic != TCP_WRITE_QUEUE_MAGIC) { if (skb->magic != TCP_WRITE_QUEUE_MAGIC) {
......
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