Commit 17e969fb authored by Linus Torvalds's avatar Linus Torvalds

Import 0.99.15d

parent 728d1c78
VERSION = 0.99 VERSION = 0.99
PATCHLEVEL = 15 PATCHLEVEL = 15
ALPHA = c ALPHA = d
all: Version zImage all: Version zImage
......
...@@ -47,7 +47,7 @@ Please report bugs, etc to me at: ...@@ -47,7 +47,7 @@ Please report bugs, etc to me at:
--Bill Metzenthen --Bill Metzenthen
Jan 1994 Feb 1994
----------------------- Internals of wm-FPU-emu ----------------------- ----------------------- Internals of wm-FPU-emu -----------------------
...@@ -92,21 +92,12 @@ is confined to five files: ...@@ -92,21 +92,12 @@ is confined to five files:
----------------------- Limitations of wm-FPU-emu ----------------------- ----------------------- Limitations of wm-FPU-emu -----------------------
There are a number of differences between the current wm-FPU-emu There are a number of differences between the current wm-FPU-emu
(version beta 1.5) and the 80486 FPU (apart from bugs). Some of the (version beta 1.10) and the 80486 FPU (apart from bugs). Some of the
more important differences are listed below: more important differences are listed below:
Segment overrides don't do anything yet. The Roundup flag does not have much meaning for the transcendental
functions and its 80486 value with these functions is likely to differ
All internal computations are performed at 64 bit or higher precision from its emulator value.
and the results rounded etc as required by the PC bits of the FPU
control word. Under the crt0 version for Linux current at June 1993,
the FPU PC bits specify 64 bits precision.
The precision flag (PE of the FPU status word) and the Roundup flag
(C1 of the status word) are now implemented. Does anyone write code
which uses these features? The Roundup flag does not have much meaning
for the transcendental functions and its 80486 value with these
functions is likely to differ from its emulator value.
In a few rare cases the Underflow flag obtained with the emulator will In a few rare cases the Underflow flag obtained with the emulator will
be different from that obtained with an 80486. This occurs when the be different from that obtained with an 80486. This occurs when the
...@@ -140,6 +131,19 @@ result of any arithmetic operation. An 80486 can keep one of these ...@@ -140,6 +131,19 @@ result of any arithmetic operation. An 80486 can keep one of these
numbers in an FPU register with its identity as a PseudoDenormal, but numbers in an FPU register with its identity as a PseudoDenormal, but
the emulator will not; they are always converted to a valid number. the emulator will not; they are always converted to a valid number.
Self modifying code can cause the emulator to fail. An example of such
code is:
movl %esp,[%ebx]
fld1
The FPU instruction may be (usually will be) loaded into the pre-fetch
queue of the cpu before the mov instruction is executed. If the
destination of the 'movl' overlaps the FPU instruction then the bytes
in the prefetch queue and memory will be inconsistent when the FPU
instruction is executed. The emulator will be invoked but will not be
able to find the instruction which caused the device-not-present
exception. For this case, the emulator cannot emulate the behaviour of
an 80486DX.
----------------------- Performance of wm-FPU-emu ----------------------- ----------------------- Performance of wm-FPU-emu -----------------------
Speed. Speed.
......
...@@ -85,13 +85,15 @@ void emu_printall() ...@@ -85,13 +85,15 @@ void emu_printall()
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. */
printk("At %p: ", (void *) address); printk("At %p: ", (void *) address);
while ( 1 ) #define MAX_PRINTED_BYTES 20
for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
{ {
byte1 = get_fs_byte((unsigned char *) address); byte1 = get_fs_byte((unsigned char *) address);
if ( (byte1 & 0xf8) == 0xd8 ) break; if ( (byte1 & 0xf8) == 0xd8 ) break;
printk("[%02x]", byte1); printk("[%02x]", byte1);
address++; address++;
} }
if ( i == MAX_PRINTED_BYTES ) printk("[more..]");
printk("%02x ", byte1); printk("%02x ", byte1);
FPU_modrm = get_fs_byte(1 + (unsigned char *) address); FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
partial_status = status_word(); partial_status = status_word();
...@@ -234,6 +236,7 @@ static struct { ...@@ -234,6 +236,7 @@ static struct {
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 0x128 in fpu_entry.c
0x130 in get_address.c
0x2nn in an *.S file: 0x2nn in an *.S file:
0x201 in reg_u_add.S 0x201 in reg_u_add.S
0x202 in reg_u_div.S 0x202 in reg_u_div.S
...@@ -310,11 +313,11 @@ void exception(int n) ...@@ -310,11 +313,11 @@ void exception(int n)
#endif PRINT_MESSAGES #endif PRINT_MESSAGES
} }
else else
printk("FP emulator: Unknown Exception: 0x%04x!\n", n); printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
if ( n == EX_INTERNAL ) if ( n == EX_INTERNAL )
{ {
printk("FP emulator: Internal error type 0x%04x\n", int_type); printk("FPU emulator: Internal error type 0x%04x\n", int_type);
emu_printall(); emu_printall();
} }
#ifdef PRINT_MESSAGES #ifdef PRINT_MESSAGES
......
...@@ -94,7 +94,11 @@ extern char emulating; ...@@ -94,7 +94,11 @@ 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; typedef struct { unsigned char address_size, operand_size, segment; }
overrides;
/* This structure is 32 bits: */
typedef struct { overrides override;
unsigned char vm86; } fpu_addr_modes;
#define st(x) ( regs[((top+x) &7 )] ) #define st(x) ( regs[((top+x) &7 )] )
......
...@@ -137,13 +137,14 @@ unsigned short FPU_data_selector; ...@@ -137,13 +137,14 @@ unsigned short FPU_data_selector;
char emulating=0; char emulating=0;
#endif PARANOID #endif PARANOID
static int valid_prefix(unsigned char *byte, overrides *override); static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
overrides *override);
asmlinkage void math_emulate(long arg) asmlinkage void math_emulate(long arg)
{ {
unsigned char FPU_modrm, byte1; unsigned char FPU_modrm, byte1;
overrides override; fpu_addr_modes addr_modes;
int unmasked; int unmasked;
#ifdef PARANOID #ifdef PARANOID
...@@ -170,35 +171,40 @@ asmlinkage void math_emulate(long arg) ...@@ -170,35 +171,40 @@ asmlinkage void math_emulate(long arg)
SETUP_DATA_AREA(arg); SETUP_DATA_AREA(arg);
FPU_ORIG_EIP = FPU_EIP; addr_modes.vm86 = (FPU_EFLAGS & 0x00020000) != 0;
/* We cannot handle emulation in v86-mode */ if ( addr_modes.vm86 )
if (FPU_EFLAGS & 0x00020000) FPU_EIP += FPU_CS << 4;
{
math_abort(FPU_info,SIGILL);
}
/* user code space? */ FPU_ORIG_EIP = FPU_EIP;
if (FPU_CS == KERNEL_CS)
{
printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
panic("Math emulation needed in kernel");
}
/* We cannot handle multiple segments yet */ if ( !addr_modes.vm86 )
if (FPU_CS != USER_CS || FPU_DS != USER_DS)
{ {
math_abort(FPU_info,SIGILL); /* user code space? */
if (FPU_CS == KERNEL_CS)
{
printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
panic("Math emulation needed in kernel");
}
/* We cannot handle multiple segments yet */
if (FPU_CS != USER_CS || FPU_DS != USER_DS)
{
math_abort(FPU_info,SIGILL);
}
} }
FPU_lookahead = 1; FPU_lookahead = 1;
if (current->flags & PF_PTRACED) if (current->flags & PF_PTRACED)
FPU_lookahead = 0; FPU_lookahead = 0;
if ( !valid_prefix(&byte1, &override) ) if ( !valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
&addr_modes.override) )
{ {
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
printk("FPU emulator: Unknown prefix byte 0x%02x\n", byte1); printk("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
"FPU emulator: self-modifying code! (emulation impossible)\n",
byte1);
RE_ENTRANT_CHECK_ON; RE_ENTRANT_CHECK_ON;
EXCEPTION(EX_INTERNAL|0x126); EXCEPTION(EX_INTERNAL|0x126);
math_abort(FPU_info,SIGILL); math_abort(FPU_info,SIGILL);
...@@ -289,7 +295,11 @@ asmlinkage void math_emulate(long arg) ...@@ -289,7 +295,11 @@ asmlinkage void math_emulate(long arg)
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, override); if ( addr_modes.vm86
^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
get_address_16(FPU_modrm, &FPU_EIP, addr_modes);
else
get_address(FPU_modrm, &FPU_EIP, addr_modes);
if ( !(byte1 & 1) ) if ( !(byte1 & 1) )
{ {
unsigned short status1 = partial_status; unsigned short status1 = partial_status;
...@@ -303,16 +313,16 @@ asmlinkage void math_emulate(long arg) ...@@ -303,16 +313,16 @@ asmlinkage void math_emulate(long arg)
switch ( (byte1 >> 1) & 3 ) switch ( (byte1 >> 1) & 3 )
{ {
case 0: case 0:
unmasked = reg_load_single(override); unmasked = reg_load_single();
break; break;
case 1: case 1:
reg_load_int32(override); reg_load_int32();
break; break;
case 2: case 2:
unmasked = reg_load_double(override); unmasked = reg_load_double();
break; break;
case 3: case 3:
reg_load_int16(override); reg_load_int16();
break; break;
} }
...@@ -440,7 +450,8 @@ asmlinkage void math_emulate(long arg) ...@@ -440,7 +450,8 @@ asmlinkage void math_emulate(long arg)
} }
else else
{ {
load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1, override); load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
addr_modes);
} }
reg_mem_instr_done: reg_mem_instr_done:
...@@ -527,10 +538,14 @@ asmlinkage void math_emulate(long arg) ...@@ -527,10 +538,14 @@ asmlinkage void math_emulate(long arg)
if (FPU_lookahead && !need_resched) if (FPU_lookahead && !need_resched)
{ {
FPU_ORIG_EIP = FPU_EIP; FPU_ORIG_EIP = FPU_EIP;
if ( valid_prefix(&byte1, &override) ) if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
&addr_modes.override) )
goto do_another_FPU_instruction; goto do_another_FPU_instruction;
} }
if ( addr_modes.vm86 )
FPU_EIP -= FPU_CS << 4;
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
} }
...@@ -539,16 +554,17 @@ asmlinkage void math_emulate(long arg) ...@@ -539,16 +554,17 @@ asmlinkage void math_emulate(long arg)
all prefix bytes, further changes are needed in the emulator code all prefix bytes, further changes are needed in the emulator code
which 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, overrides *override) static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
overrides *override)
{ {
unsigned char byte; unsigned char byte;
unsigned long ip = FPU_EIP; unsigned char *ip = *fpu_eip;
*override = (overrides) { 0, PREFIX_DS }; /* defaults */ *override = (overrides) { 0, 0, PREFIX_DS }; /* defaults */
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1); FPU_code_verify_area(1);
byte = get_fs_byte((unsigned char *) FPU_EIP); byte = get_fs_byte(ip);
RE_ENTRANT_CHECK_ON; RE_ENTRANT_CHECK_ON;
while ( 1 ) while ( 1 )
...@@ -558,6 +574,11 @@ static int valid_prefix(unsigned char *Byte, overrides *override) ...@@ -558,6 +574,11 @@ static int valid_prefix(unsigned char *Byte, overrides *override)
case ADDR_SIZE_PREFIX: case ADDR_SIZE_PREFIX:
override->address_size = ADDR_SIZE_PREFIX; override->address_size = ADDR_SIZE_PREFIX;
goto do_next_byte; goto do_next_byte;
case OP_SIZE_PREFIX:
override->operand_size = OP_SIZE_PREFIX;
goto do_next_byte;
case PREFIX_CS: case PREFIX_CS:
override->segment = PREFIX_CS; override->segment = PREFIX_CS;
goto do_next_byte; goto do_next_byte;
...@@ -585,12 +606,11 @@ static int valid_prefix(unsigned char *Byte, overrides *override) ...@@ -585,12 +606,11 @@ static int valid_prefix(unsigned char *Byte, overrides *override)
case PREFIX_REPE: case PREFIX_REPE:
case PREFIX_REPNE: case PREFIX_REPNE:
case OP_SIZE_PREFIX: /* Used often by gcc, but has no effect. */
do_next_byte: do_next_byte:
FPU_EIP++; ip++;
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1); FPU_code_verify_area(1);
byte = get_fs_byte((unsigned char *) (FPU_EIP)); byte = get_fs_byte(ip);
RE_ENTRANT_CHECK_ON; RE_ENTRANT_CHECK_ON;
break; break;
case FWAIT_OPCODE: case FWAIT_OPCODE:
...@@ -600,6 +620,7 @@ static int valid_prefix(unsigned char *Byte, overrides *override) ...@@ -600,6 +620,7 @@ static int valid_prefix(unsigned char *Byte, overrides *override)
if ( (byte & 0xf8) == 0xd8 ) if ( (byte & 0xf8) == 0xd8 )
{ {
*Byte = byte; *Byte = byte;
*fpu_eip = ip;
return 1; return 1;
} }
else else
...@@ -607,7 +628,6 @@ static int valid_prefix(unsigned char *Byte, overrides *override) ...@@ -607,7 +628,6 @@ static int valid_prefix(unsigned char *Byte, overrides *override)
/* Not a valid sequence of prefix bytes followed by /* Not a valid sequence of prefix bytes followed by
an FPU instruction. */ an FPU instruction. */
*Byte = byte; /* Needed for error message. */ *Byte = byte; /* Needed for error message. */
FPU_EIP = ip;
return 0; return 0;
} }
} }
......
...@@ -63,10 +63,13 @@ extern void trig_a(void); ...@@ -63,10 +63,13 @@ 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, overrides override); extern void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
fpu_addr_modes);
extern void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
fpu_addr_modes);
/* load_store.c */ /* load_store.c */
extern void load_store_instr(char type, overrides override); extern void load_store_instr(char type, fpu_addr_modes addr_modes);
/* 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);
...@@ -105,26 +108,26 @@ extern void fucompp(void); ...@@ -105,26 +108,26 @@ 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(overrides override); extern int reg_load_extended(void);
extern int reg_load_double(overrides override); extern int reg_load_double(void);
extern int reg_load_single(overrides override); extern int reg_load_single(void);
extern void reg_load_int64(overrides override); extern void reg_load_int64(void);
extern void reg_load_int32(overrides override); extern void reg_load_int32(void);
extern void reg_load_int16(overrides override); extern void reg_load_int16(void);
extern void reg_load_bcd(overrides override); extern void reg_load_bcd(void);
extern int reg_store_extended(overrides override); extern int reg_store_extended(void);
extern int reg_store_double(overrides override); extern int reg_store_double(void);
extern int reg_store_single(overrides override); extern int reg_store_single(void);
extern int reg_store_int64(overrides override); extern int reg_store_int64(void);
extern int reg_store_int32(overrides override); extern int reg_store_int32(void);
extern int reg_store_int16(overrides override); extern int reg_store_int16(void);
extern int reg_store_bcd(overrides override); extern int reg_store_bcd(void);
extern int round_to_int(FPU_REG *r); extern int round_to_int(FPU_REG *r);
extern char *fldenv(void); extern char *fldenv(fpu_addr_modes addr_modes);
extern void frstor(void); extern void frstor(fpu_addr_modes addr_modes);
extern unsigned short tag_word(void); extern unsigned short tag_word(void);
extern char *fstenv(void); extern char *fstenv(fpu_addr_modes addr_modes);
extern void fsave(void); extern void fsave(fpu_addr_modes addr_modes);
/* reg_mul.c */ /* reg_mul.c */
extern int reg_mul(FPU_REG const *a, FPU_REG const *b, extern int reg_mul(FPU_REG const *a, FPU_REG const *b,
......
...@@ -23,7 +23,12 @@ ...@@ -23,7 +23,12 @@
#define FPU_info (I387.soft.info) #define FPU_info (I387.soft.info)
#define FPU_CS (*(unsigned short *) &(FPU_info->___cs)) #define FPU_CS (*(unsigned short *) &(FPU_info->___cs))
#define FPU_SS (*(unsigned short *) &(FPU_info->___ss))
#define FPU_DS (*(unsigned short *) &(FPU_info->___ds)) #define FPU_DS (*(unsigned short *) &(FPU_info->___ds))
#define FPU_VM86_ES ((&FPU_SS)[2])
#define FPU_VM86_DS ((&FPU_SS)[4])
#define FPU_VM86_FS ((&FPU_SS)[6])
#define FPU_VM86_GS ((&FPU_SS)[8])
#define FPU_EAX (FPU_info->___eax) #define FPU_EAX (FPU_info->___eax)
#define FPU_EFLAGS (FPU_info->___eflags) #define FPU_EFLAGS (FPU_info->___eflags)
#define FPU_EIP (FPU_info->___eip) #define FPU_EIP (FPU_info->___eip)
......
...@@ -41,16 +41,16 @@ static int reg_offset[] = { ...@@ -41,16 +41,16 @@ static int reg_offset[] = {
/* Decode the SIB byte. This function assumes mod != 0 */ /* Decode the SIB byte. This function assumes mod != 0 */
static void *sib(int mod) static void *sib(int mod, unsigned long *fpu_eip)
{ {
unsigned char ss,index,base; unsigned char ss,index,base;
long offset; long offset;
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1); FPU_code_verify_area(1);
base = get_fs_byte((char *) FPU_EIP); /* The SIB byte */ base = get_fs_byte((char *) (*fpu_eip)); /* The SIB byte */
RE_ENTRANT_CHECK_ON; RE_ENTRANT_CHECK_ON;
FPU_EIP++; (*fpu_eip)++;
ss = base >> 6; ss = base >> 6;
index = (base >> 3) & 7; index = (base >> 3) & 7;
base &= 7; base &= 7;
...@@ -77,23 +77,51 @@ static void *sib(int mod) ...@@ -77,23 +77,51 @@ static void *sib(int mod)
/* 8 bit signed displacement */ /* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1); FPU_code_verify_area(1);
offset += (signed char) get_fs_byte((char *) FPU_EIP); offset += (signed char) get_fs_byte((char *) (*fpu_eip));
RE_ENTRANT_CHECK_ON; RE_ENTRANT_CHECK_ON;
FPU_EIP++; (*fpu_eip)++;
} }
else if (mod == 2 || base == 5) /* The second condition also has mod==0 */ else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
{ {
/* 32 bit displacment */ /* 32 bit displacment */
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
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; RE_ENTRANT_CHECK_ON;
FPU_EIP += 4; (*fpu_eip) += 4;
} }
return (void *) offset; return (void *) offset;
} }
static unsigned long vm86_segment(char segment)
{
switch ( segment )
{
case PREFIX_CS:
return FPU_CS << 4;
break;
case PREFIX_SS:
return FPU_SS << 4;
break;
case PREFIX_ES:
return FPU_VM86_ES << 4;
break;
case PREFIX_DS:
return FPU_VM86_DS << 4;
break;
case PREFIX_FS:
return FPU_VM86_FS << 4;
break;
case PREFIX_GS:
return FPU_VM86_GS << 4;
break;
default:
EXCEPTION(EX_INTERNAL|0x130);
return 0; /* Keep gcc quiet. */
}
}
/* /*
MOD R/M byte: MOD == 3 has a special use for the FPU MOD R/M byte: MOD == 3 has a special use for the FPU
...@@ -112,7 +140,8 @@ static void *sib(int mod) ...@@ -112,7 +140,8 @@ static void *sib(int mod)
*/ */
void get_address(unsigned char FPU_modrm, overrides override) void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
fpu_addr_modes addr_modes)
{ {
unsigned char mod; unsigned char mod;
long *cpu_reg_ptr; long *cpu_reg_ptr;
...@@ -123,11 +152,20 @@ void get_address(unsigned char FPU_modrm, overrides override) ...@@ -123,11 +152,20 @@ void get_address(unsigned char FPU_modrm, overrides override)
FPU_data_selector = FPU_DS; FPU_data_selector = FPU_DS;
#endif PECULIAR_486 #endif PECULIAR_486
/* Memory accessed via the cs selector is write protected
in 32 bit protected mode. */
#define FPU_WRITE_BIT 0x10
if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
&& (addr_modes.override.segment == PREFIX_CS) )
{
math_abort(FPU_info,SIGSEGV);
}
mod = (FPU_modrm >> 6) & 3; mod = (FPU_modrm >> 6) & 3;
if (FPU_rm == 4 && mod != 3) if (FPU_rm == 4 && mod != 3)
{ {
FPU_data_address = sib(mod); FPU_data_address = sib(mod, fpu_eip);
return; return;
} }
...@@ -137,20 +175,11 @@ void get_address(unsigned char FPU_modrm, overrides override) ...@@ -137,20 +175,11 @@ void get_address(unsigned char FPU_modrm, overrides override)
case 0: case 0:
if (FPU_rm == 5) if (FPU_rm == 5)
{ {
/* Special case: disp16 or disp32 */ /* Special case: disp32 */
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
if ( override.address_size == ADDR_SIZE_PREFIX ) FPU_code_verify_area(4);
{ offset = get_fs_long((unsigned long *) (*fpu_eip));
FPU_code_verify_area(2); (*fpu_eip) += 4;
offset = get_fs_word((unsigned short *) FPU_EIP);
FPU_EIP += 2;
}
else
{
FPU_code_verify_area(4);
offset = get_fs_long((unsigned long *) FPU_EIP);
FPU_EIP += 4;
}
RE_ENTRANT_CHECK_ON; RE_ENTRANT_CHECK_ON;
FPU_data_address = (void *) offset; FPU_data_address = (void *) offset;
return; return;
...@@ -165,33 +194,125 @@ void get_address(unsigned char FPU_modrm, overrides override) ...@@ -165,33 +194,125 @@ void get_address(unsigned char FPU_modrm, overrides override)
/* 8 bit signed displacement */ /* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1); FPU_code_verify_area(1);
offset = (signed char) get_fs_byte((char *) FPU_EIP); offset = (signed char) get_fs_byte((char *) (*fpu_eip));
RE_ENTRANT_CHECK_ON; RE_ENTRANT_CHECK_ON;
FPU_EIP++; (*fpu_eip)++;
break; break;
case 2: case 2:
/* 16 or 32 bit displacement */ /* 32 bit displacement */
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
if ( override.address_size == ADDR_SIZE_PREFIX ) FPU_code_verify_area(4);
offset = (signed) get_fs_long((unsigned long *) (*fpu_eip));
(*fpu_eip) += 4;
RE_ENTRANT_CHECK_ON;
break;
case 3:
/* Not legal for the FPU */
EXCEPTION(EX_Invalid);
}
if ( addr_modes.vm86 )
{
offset += vm86_segment(addr_modes.override.segment);
}
FPU_data_address = offset + (char *)*cpu_reg_ptr;
}
void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
fpu_addr_modes addr_modes)
{
unsigned char mod;
int offset = 0; /* Default used for mod == 0 */
#ifndef PECULIAR_486
/* This is a reasonable place to do this */
FPU_data_selector = FPU_DS;
#endif PECULIAR_486
/* Memory accessed via the cs selector is write protected
in 32 bit protected mode. */
#define FPU_WRITE_BIT 0x10
if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
&& (addr_modes.override.segment == PREFIX_CS) )
{
math_abort(FPU_info,SIGSEGV);
}
mod = (FPU_modrm >> 6) & 3;
switch (mod)
{
case 0:
if (FPU_rm == 6)
{ {
/* Special case: disp16 */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(2); FPU_code_verify_area(2);
offset = (signed) get_fs_word((unsigned short *) FPU_EIP); offset = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip));
FPU_EIP += 2; (*fpu_eip) += 2;
} RE_ENTRANT_CHECK_ON;
else goto add_segment;
{
FPU_code_verify_area(4);
offset = (signed) get_fs_long((unsigned long *) FPU_EIP);
FPU_EIP += 4;
} }
break;
case 1:
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
offset = (signed char) get_fs_byte((signed char *) (*fpu_eip));
RE_ENTRANT_CHECK_ON;
(*fpu_eip)++;
break;
case 2:
/* 16 bit displacement */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(2);
offset = (unsigned) get_fs_word((unsigned short *) (*fpu_eip));
(*fpu_eip) += 2;
RE_ENTRANT_CHECK_ON; RE_ENTRANT_CHECK_ON;
break; break;
case 3: case 3:
/* Not legal for the FPU */ /* Not legal for the FPU */
EXCEPTION(EX_Invalid); EXCEPTION(EX_Invalid);
break;
}
switch ( FPU_rm )
{
case 0:
offset += FPU_info->___ebx + FPU_info->___esi;
break;
case 1:
offset += FPU_info->___ebx + FPU_info->___edi;
break;
case 2:
offset += FPU_info->___ebp + FPU_info->___esi;
break;
case 3:
offset += FPU_info->___ebp + FPU_info->___edi;
break;
case 4:
offset += FPU_info->___esi;
break;
case 5:
offset += FPU_info->___edi;
break;
case 6:
offset += FPU_info->___ebp;
break;
case 7:
offset += FPU_info->___ebx;
break;
} }
FPU_data_address = offset + (char *)*cpu_reg_ptr; add_segment:
if ( override.address_size == ADDR_SIZE_PREFIX ) offset &= 0xffff;
FPU_data_address = (void *)((long)FPU_data_address & 0xffff);
if ( addr_modes.vm86 )
{
offset += vm86_segment(addr_modes.override.segment);
}
FPU_data_address = (void *)offset ;
} }
...@@ -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, overrides override) void load_store_instr(char type, fpu_addr_modes addr_modes)
{ {
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. */
...@@ -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(override); reg_load_single();
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(override); reg_load_int32();
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(override); reg_load_double();
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,58 +112,58 @@ switch ( type ) ...@@ -112,58 +112,58 @@ switch ( type )
break; break;
case 003: /* fild m16int */ case 003: /* fild m16int */
clear_C1(); clear_C1();
reg_load_int16(override); reg_load_int16();
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(override); reg_store_single();
break; break;
case 011: /* fist m32int */ case 011: /* fist m32int */
clear_C1(); clear_C1();
reg_store_int32(override); reg_store_int32();
break; break;
case 012: /* fst m64real */ case 012: /* fst m64real */
clear_C1(); clear_C1();
reg_store_double(override); reg_store_double();
break; break;
case 013: /* fist m16int */ case 013: /* fist m16int */
clear_C1(); clear_C1();
reg_store_int16(override); reg_store_int16();
break; break;
case 014: /* fstp m32real */ case 014: /* fstp m32real */
clear_C1(); clear_C1();
if ( reg_store_single(override) ) if ( reg_store_single() )
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(override) ) if ( reg_store_int32() )
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(override) ) if ( reg_store_double() )
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(override) ) if ( reg_store_int16() )
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 020: /* fldenv m14/28byte */ case 020: /* fldenv m14/28byte */
fldenv(); fldenv(addr_modes);
break; break;
case 022: /* frstor m94/108byte */ case 022: /* frstor m94/108byte */
frstor(); frstor(addr_modes);
break; break;
case 023: /* fbld m80dec */ case 023: /* fbld m80dec */
clear_C1(); clear_C1();
reg_load_bcd(override); reg_load_bcd();
reg_move(&FPU_loaded_data, pop_ptr); reg_move(&FPU_loaded_data, pop_ptr);
break; break;
case 024: /* fldcw */ case 024: /* fldcw */
...@@ -183,25 +183,25 @@ switch ( type ) ...@@ -183,25 +183,25 @@ switch ( type )
break; break;
case 025: /* fld m80real */ case 025: /* fld m80real */
clear_C1(); clear_C1();
reg_load_extended(override); reg_load_extended();
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(override); reg_load_int64();
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 */
fstenv(); fstenv(addr_modes);
NO_NET_DATA_EFFECT; NO_NET_DATA_EFFECT;
break; break;
case 032: /* fsave */ case 032: /* fsave */
fsave(); fsave(addr_modes);
NO_NET_DATA_EFFECT; NO_NET_DATA_EFFECT;
break; break;
case 033: /* fbstp m80dec */ case 033: /* fbstp m80dec */
clear_C1(); clear_C1();
if ( reg_store_bcd(override) ) if ( reg_store_bcd() )
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(override) ) if ( reg_store_extended() )
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(override) ) if ( reg_store_int64() )
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;
......
...@@ -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(overrides override) int reg_load_extended(void)
{ {
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(overrides override) ...@@ -145,7 +145,7 @@ int reg_load_extended(overrides override)
/* Get a double from user memory */ /* Get a double from user memory */
int reg_load_double(overrides override) int reg_load_double(void)
{ {
double *dfloat = (double *)FPU_data_address; double *dfloat = (double *)FPU_data_address;
int exp; int exp;
...@@ -223,7 +223,7 @@ int reg_load_double(overrides override) ...@@ -223,7 +223,7 @@ int reg_load_double(overrides override)
/* Get a float from user memory */ /* Get a float from user memory */
int reg_load_single(overrides override) int reg_load_single(void)
{ {
float *single = (float *)FPU_data_address; float *single = (float *)FPU_data_address;
unsigned m32; unsigned m32;
...@@ -292,7 +292,7 @@ int reg_load_single(overrides override) ...@@ -292,7 +292,7 @@ int reg_load_single(overrides override)
/* Get a long long from user memory */ /* Get a long long from user memory */
void reg_load_int64(overrides override) void reg_load_int64(void)
{ {
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(overrides override) ...@@ -324,7 +324,7 @@ void reg_load_int64(overrides override)
/* Get a long from user memory */ /* Get a long from user memory */
void reg_load_int32(overrides override) void reg_load_int32(void)
{ {
long *_s = (long *)FPU_data_address; long *_s = (long *)FPU_data_address;
long s; long s;
...@@ -356,7 +356,7 @@ void reg_load_int32(overrides override) ...@@ -356,7 +356,7 @@ void reg_load_int32(overrides override)
/* Get a short from user memory */ /* Get a short from user memory */
void reg_load_int16(overrides override) void reg_load_int16(void)
{ {
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(overrides override) ...@@ -389,7 +389,7 @@ void reg_load_int16(overrides override)
/* Get a packed bcd array from user memory */ /* Get a packed bcd array from user memory */
void reg_load_bcd(overrides override) void reg_load_bcd(void)
{ {
char *s = (char *)FPU_data_address; char *s = (char *)FPU_data_address;
int pos; int pos;
...@@ -436,7 +436,7 @@ void reg_load_bcd(overrides override) ...@@ -436,7 +436,7 @@ void reg_load_bcd(overrides override)
/*===========================================================================*/ /*===========================================================================*/
/* Put a long double into user memory */ /* Put a long double into user memory */
int reg_store_extended(overrides override) int reg_store_extended(void)
{ {
/* /*
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(overrides override) ...@@ -475,7 +475,7 @@ int reg_store_extended(overrides override)
/* Put a double into user memory */ /* Put a double into user memory */
int reg_store_double(overrides override) int reg_store_double(void)
{ {
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(overrides override) ...@@ -670,7 +670,7 @@ int reg_store_double(overrides override)
/* Put a float into user memory */ /* Put a float into user memory */
int reg_store_single(overrides override) int reg_store_single(void)
{ {
float *single = (float *)FPU_data_address; float *single = (float *)FPU_data_address;
long templ; long templ;
...@@ -859,7 +859,7 @@ int reg_store_single(overrides override) ...@@ -859,7 +859,7 @@ int reg_store_single(overrides override)
/* Put a long long into user memory */ /* Put a long long into user memory */
int reg_store_int64(overrides override) int reg_store_int64(void)
{ {
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(overrides override) ...@@ -918,7 +918,7 @@ int reg_store_int64(overrides override)
/* Put a long into user memory */ /* Put a long into user memory */
int reg_store_int32(overrides override) int reg_store_int32(void)
{ {
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(overrides override) ...@@ -972,7 +972,7 @@ int reg_store_int32(overrides override)
/* Put a short into user memory */ /* Put a short into user memory */
int reg_store_int16(overrides override) int reg_store_int16(void)
{ {
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(overrides override) ...@@ -1026,7 +1026,7 @@ int reg_store_int16(overrides override)
/* Put a packed bcd array into user memory */ /* Put a packed bcd array into user memory */
int reg_store_bcd(overrides override) int reg_store_bcd(void)
{ {
char *d = (char *)FPU_data_address; char *d = (char *)FPU_data_address;
FPU_REG t; FPU_REG t;
...@@ -1163,23 +1163,47 @@ int round_to_int(FPU_REG *r) ...@@ -1163,23 +1163,47 @@ int round_to_int(FPU_REG *r)
/*===========================================================================*/ /*===========================================================================*/
char *fldenv(void) char *fldenv(fpu_addr_modes addr_modes)
{ {
char *s = (char *)FPU_data_address; char *s = (char *)FPU_data_address;
unsigned short tag_word = 0; unsigned short tag_word = 0;
unsigned char tag; unsigned char tag;
int i; int i;
RE_ENTRANT_CHECK_OFF; if ( addr_modes.vm86
FPU_verify_area(VERIFY_READ, s, 0x1c); || (addr_modes.override.operand_size == OP_SIZE_PREFIX) )
control_word = get_fs_word((unsigned short *) s); {
partial_status = get_fs_word((unsigned short *) (s+4)); RE_ENTRANT_CHECK_OFF;
tag_word = get_fs_word((unsigned short *) (s+8)); FPU_verify_area(VERIFY_READ, s, 0x0e);
ip_offset = get_fs_long((unsigned long *) (s+0x0c)); control_word = get_fs_word((unsigned short *) s);
cs_selector = get_fs_long((unsigned long *) (s+0x10)); partial_status = get_fs_word((unsigned short *) (s+2));
data_operand_offset = get_fs_long((unsigned long *) (s+0x14)); tag_word = get_fs_word((unsigned short *) (s+4));
operand_selector = get_fs_long((unsigned long *) (s+0x18)); ip_offset = get_fs_word((unsigned short *) (s+6));
RE_ENTRANT_CHECK_ON; cs_selector = get_fs_word((unsigned short *) (s+8));
data_operand_offset = get_fs_word((unsigned short *) (s+0x0a));
operand_selector = get_fs_word((unsigned short *) (s+0x0c));
RE_ENTRANT_CHECK_ON;
s += 0x0e;
if ( addr_modes.vm86 )
{
ip_offset += (cs_selector & 0xf000) << 4;
data_operand_offset += (operand_selector & 0xf000) << 4;
}
}
else
{
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, s, 0x1c);
control_word = get_fs_word((unsigned short *) s);
partial_status = get_fs_word((unsigned short *) (s+4));
tag_word = get_fs_word((unsigned short *) (s+8));
ip_offset = get_fs_long((unsigned long *) (s+0x0c));
cs_selector = get_fs_long((unsigned long *) (s+0x10));
data_operand_offset = get_fs_long((unsigned long *) (s+0x14));
operand_selector = get_fs_long((unsigned long *) (s+0x18));
RE_ENTRANT_CHECK_ON;
s += 0x1c;
}
top = (partial_status >> SW_Top_Shift) & 7; top = (partial_status >> SW_Top_Shift) & 7;
...@@ -1226,21 +1250,21 @@ char *fldenv(void) ...@@ -1226,21 +1250,21 @@ char *fldenv(void)
NO_NET_DATA_EFFECT; NO_NET_DATA_EFFECT;
NO_NET_INSTR_EFFECT; NO_NET_INSTR_EFFECT;
return s + 0x1c; return s;
} }
void frstor(void) void frstor(fpu_addr_modes addr_modes)
{ {
int i, stnr; int i, stnr;
unsigned char tag; unsigned char tag;
char *s = fldenv(); char *s = fldenv(addr_modes);
for ( i = 0; i < 8; i++ ) for ( i = 0; i < 8; i++ )
{ {
/* Load each register. */ /* Load each register. */
FPU_data_address = (void *)(s+i*10); FPU_data_address = (void *)(s+i*10);
reg_load_extended((overrides){0,0}); reg_load_extended();
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]);
...@@ -1285,46 +1309,75 @@ unsigned short tag_word(void) ...@@ -1285,46 +1309,75 @@ unsigned short tag_word(void)
} }
char *fstenv(void) char *fstenv(fpu_addr_modes addr_modes)
{ {
char *d = (char *)FPU_data_address; char *d = (char *)FPU_data_address;
RE_ENTRANT_CHECK_OFF; if ( addr_modes.vm86
FPU_verify_area(VERIFY_WRITE,d,28); || (addr_modes.override.operand_size == OP_SIZE_PREFIX) )
{
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,14);
put_fs_word(control_word, (unsigned short *) d);
put_fs_word(status_word(), (unsigned short *) (d+2));
put_fs_word(tag_word(), (unsigned short *) (d+4));
put_fs_word(ip_offset, (unsigned short *) (d+6));
put_fs_word(data_operand_offset, (unsigned short *) (d+0x0a));
if ( addr_modes.vm86 )
{
put_fs_word((ip_offset & 0xf0000) >> 4,
(unsigned short *) (d+8));
put_fs_word((data_operand_offset & 0xf0000) >> 4,
(unsigned short *) (d+0x0c));
}
else
{
put_fs_word(cs_selector, (unsigned short *) (d+8));
put_fs_word(operand_selector, (unsigned short *) (d+0x0c));
}
RE_ENTRANT_CHECK_ON;
d += 0x0e;
}
else
{
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,28);
#ifdef PECULIAR_486 #ifdef PECULIAR_486
/* An 80486 sets all the reserved bits to 1. */ /* An 80486 sets all the reserved bits to 1. */
put_fs_long(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d); put_fs_long(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d);
put_fs_long(0xffff0000 | status_word(), (unsigned long *) (d+4)); put_fs_long(0xffff0000 | status_word(), (unsigned long *) (d+4));
put_fs_long(0xffff0000 | tag_word(), (unsigned long *) (d+8)); put_fs_long(0xffff0000 | tag_word(), (unsigned long *) (d+8));
#else #else
put_fs_word(control_word, (unsigned short *) d); put_fs_word(control_word, (unsigned short *) d);
put_fs_word(status_word(), (unsigned short *) (d+4)); put_fs_word(status_word(), (unsigned short *) (d+4));
put_fs_word(tag_word(), (unsigned short *) (d+8)); put_fs_word(tag_word(), (unsigned short *) (d+8));
#endif PECULIAR_486 #endif PECULIAR_486
put_fs_long(ip_offset, (unsigned long *) (d+0x0c)); put_fs_long(ip_offset, (unsigned long *) (d+0x0c));
put_fs_long(cs_selector & ~0xf8000000, (unsigned long *) (d+0x10)); put_fs_long(cs_selector & ~0xf8000000, (unsigned long *) (d+0x10));
put_fs_long(data_operand_offset, (unsigned long *) (d+0x14)); put_fs_long(data_operand_offset, (unsigned long *) (d+0x14));
#ifdef PECULIAR_486 #ifdef PECULIAR_486
/* An 80486 sets all the reserved bits to 1. */ /* An 80486 sets all the reserved bits to 1. */
put_fs_long(0xffff0000 | operand_selector, (unsigned long *) (d+0x18)); put_fs_long(0xffff0000 | operand_selector, (unsigned long *) (d+0x18));
#else #else
put_fs_long(operand_selector, (unsigned long *) (d+0x18)); put_fs_long(operand_selector, (unsigned long *) (d+0x18));
#endif PECULIAR_486 #endif PECULIAR_486
RE_ENTRANT_CHECK_ON; RE_ENTRANT_CHECK_ON;
d += 0x1c;
}
control_word |= CW_Exceptions; control_word |= CW_Exceptions;
partial_status &= ~(SW_Summary | SW_Backward); partial_status &= ~(SW_Summary | SW_Backward);
return d + 0x1c; return d;
} }
void fsave(void) void fsave(fpu_addr_modes addr_modes)
{ {
char *d; char *d;
int i; int i;
d = fstenv(); d = fstenv(addr_modes);
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,80); FPU_verify_area(VERIFY_WRITE,d,80);
RE_ENTRANT_CHECK_ON; RE_ENTRANT_CHECK_ON;
......
...@@ -9,5 +9,5 @@ ...@@ -9,5 +9,5 @@
| | | |
+---------------------------------------------------------------------------*/ +---------------------------------------------------------------------------*/
#define FPU_VERSION "wm-FPU-emu version Beta 1.9" #define FPU_VERSION "wm-FPU-emu version Beta 1.10"
...@@ -139,14 +139,10 @@ static struct device atp_dev = { ...@@ -139,14 +139,10 @@ static struct device atp_dev = {
#endif #endif
/* The first device defaults to I/O base '0', which means autoprobe. */ /* The first device defaults to I/O base '0', which means autoprobe. */
#ifdef EI8390 #ifndef ETH0_ADDR
# define ETH0_ADDR EI8390
#else
# define ETH0_ADDR 0 # define ETH0_ADDR 0
#endif #endif
#ifdef EI8390_IRQ #ifndef ETH0_IRQ
# define ETH0_IRQ EI8390_IRQ
#else
# define ETH0_IRQ 0 # define ETH0_IRQ 0
#endif #endif
/* "eth0" defaults to autoprobe, other use a base of "-0x20", "don't probe". /* "eth0" defaults to autoprobe, other use a base of "-0x20", "don't probe".
......
...@@ -7,43 +7,12 @@ ...@@ -7,43 +7,12 @@
* This file is based upon code written by Eric Youndale for the ELF object * This file is based upon code written by Eric Youndale for the ELF object
* file format. * file format.
* *
* Revision information: * Author: Al Longyear (longyear@sii.com)
* 28 August 1993
* Al Longyear (longyear@sii.com)
* initial release to alpha level testing. This version does not load
* shared libraries, but will identify them and log the file names.
* *
* 4 September 1993 * Latest Revision:
* Al Longyear (longyear@sii.com) * 3 Feburary 1994
* Added support for shared libraries. * Al Longyear (longyear@sii.com)
* * Cleared first page of bss section using put_fs_byte.
* 9 September 1993
* Al Longyear (longyear@sii.com)
* Load the FS register with the proper value prior to the call to
* sys_uselib().
*
* Built the parameter and envionment strings before destroying the
* current executable.
*
* 10 September 1993
* Al Longyear (longyear@sii.com)
* Added new parameter to the create_tables() function to allow the
* proper creation of the IBCS environment stack when the process is
* started.
*
* Added code to create_tables() which I mistakenly deleted in the
* last patch.
*
* 13 September 1993
* Al Longyear (longyear@sii.com)
* Removed erroneous code which mistakenly folded .data with .bss for
* a shared library.
*
* 8 Janurary 1994
* Al Longyear (longyear@sii.com)
* Corrected problem with read of library section returning the byte
* count rather than zero. This was a change between the pl12 and
* pl14 kernels which slipped by me.
*/ */
#include <linux/fs.h> #include <linux/fs.h>
...@@ -104,6 +73,37 @@ is_properly_aligned (COFF_SCNHDR *sect) ...@@ -104,6 +73,37 @@ is_properly_aligned (COFF_SCNHDR *sect)
return ((((vaddr - scnptr) & ~PAGE_MASK) != 0) ? -ENOEXEC : 0); return ((((vaddr - scnptr) & ~PAGE_MASK) != 0) ? -ENOEXEC : 0);
} }
/*
* Clear the bytes in the last page of data.
*/
static
int clear_memory (unsigned long addr, unsigned long size)
{
int status;
size = (PAGE_SIZE - (addr & ~PAGE_MASK)) & ~PAGE_MASK;
if (size == 0)
status = 0;
else {
#ifdef COFF_DEBUG
printk ("un-initialized storage in last page %d\n", size);
#endif
status = verify_area (VERIFY_WRITE,
(void *) addr, size);
#ifdef COFF_DEBUG
printk ("result from verify_area = %d\n", status);
#endif
if (status >= 0)
while (size-- != 0)
put_fs_byte (0, addr++);
}
return status;
}
/* /*
* Helper function to process the load operation. * Helper function to process the load operation.
*/ */
...@@ -521,11 +521,13 @@ load_object (struct linux_binprm * bprm, struct pt_regs *regs, int lib_ok) ...@@ -521,11 +521,13 @@ load_object (struct linux_binprm * bprm, struct pt_regs *regs, int lib_ok)
zeromap_page_range (PAGE_ALIGN (bss_vaddr), zeromap_page_range (PAGE_ALIGN (bss_vaddr),
PAGE_ALIGN (bss_size), PAGE_ALIGN (bss_size),
PAGE_COPY); PAGE_COPY);
status = clear_memory (bss_vaddr, bss_size);
} }
/* /*
* Load any shared library for the executable. * Load any shared library for the executable.
*/ */
if (lib_ok && lib_count != 0) { if (status >= 0 && lib_ok && lib_count != 0) {
int nIndex; int nIndex;
COFF_SCNHDR *sect_ptr = sect_bufr; COFF_SCNHDR *sect_ptr = sect_bufr;
/* /*
......
This diff is collapsed.
/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
* Miscellaneous internetwork definitions for kernel.
*
* Version: @(#)in_systm.h 1.0.0 12/17/93
*
* Authors: Original taken from Berkeley BSD UNIX 4.3-RENO.
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#ifndef _LINUX_IN_SYSTM_H
#define _LINUX_IN_SYSTM_H
/*
* Network types.
* The n_ types are network-order variants of their natural
* equivalents. The Linux kernel NET-2 code does not use
* them (yet), but it might in the future. This is mostly
* there for compatibility with BSD user-level programs.
*/
typedef u_short n_short; /* short as received from the net */
typedef u_long n_long; /* long as received from the net */
typedef u_long n_time; /* ms since 00:00 GMT, byte rev */
#endif /* _LINUX_IN_SYSTM_H */
...@@ -81,7 +81,7 @@ extern unsigned long free_page_list; ...@@ -81,7 +81,7 @@ extern unsigned long free_page_list;
extern int nr_secondary_pages; extern int nr_secondary_pages;
extern unsigned long secondary_page_list; extern unsigned long secondary_page_list;
#define MAX_SECONDARY_PAGES 10 #define MAX_SECONDARY_PAGES 20
/* /*
* This is timing-critical - most of the time in getting a new page * This is timing-critical - most of the time in getting a new page
......
...@@ -183,6 +183,9 @@ asmlinkage int sys_sigaction(int signum, const struct sigaction * action, ...@@ -183,6 +183,9 @@ asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
return -EINVAL; return -EINVAL;
p = signum - 1 + current->sigaction; p = signum - 1 + current->sigaction;
if (action) { if (action) {
int err = verify_area(VERIFY_READ, action, sizeof(*action));
if (err)
return err;
memcpy_fromfs(&new_sa, action, sizeof(struct sigaction)); memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
if (new_sa.sa_flags & SA_NOMASK) if (new_sa.sa_flags & SA_NOMASK)
new_sa.sa_mask = 0; new_sa.sa_mask = 0;
...@@ -194,8 +197,10 @@ asmlinkage int sys_sigaction(int signum, const struct sigaction * action, ...@@ -194,8 +197,10 @@ asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
return -EFAULT; return -EFAULT;
} }
if (oldaction) { if (oldaction) {
if (!verify_area(VERIFY_WRITE,oldaction, sizeof(struct sigaction))) int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction));
memcpy_tofs(oldaction, p, sizeof(struct sigaction)); if (err)
return err;
memcpy_tofs(oldaction, p, sizeof(struct sigaction));
} }
if (action) { if (action) {
*p = new_sa; *p = new_sa;
......
...@@ -276,9 +276,12 @@ static int rt_new(struct rtentry *r) ...@@ -276,9 +276,12 @@ static int rt_new(struct rtentry *r)
mask = ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr; mask = ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr;
gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr; gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr;
if (bad_mask(mask, daddr))
mask = 0;
if (flags & RTF_HOST) if (flags & RTF_HOST)
mask = 0xffffffff; mask = 0xffffffff;
else if (r->rt_genmask.sa_family != AF_INET) else if (mask && r->rt_genmask.sa_family != AF_INET)
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
if (flags & RTF_GATEWAY) { if (flags & RTF_GATEWAY) {
...@@ -292,9 +295,6 @@ static int rt_new(struct rtentry *r) ...@@ -292,9 +295,6 @@ static int rt_new(struct rtentry *r)
if (dev == NULL) if (dev == NULL)
return -ENETUNREACH; return -ENETUNREACH;
if (bad_mask(mask, daddr))
mask = 0;
rt_add(flags, daddr, mask, gw, dev); rt_add(flags, daddr, mask, gw, dev);
return 0; return 0;
} }
......
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