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

Import 0.99.15d

parent 728d1c78
VERSION = 0.99
PATCHLEVEL = 15
ALPHA = c
ALPHA = d
all: Version zImage
......
......@@ -47,7 +47,7 @@ Please report bugs, etc to me at:
--Bill Metzenthen
Jan 1994
Feb 1994
----------------------- Internals of wm-FPU-emu -----------------------
......@@ -92,21 +92,12 @@ is confined to five files:
----------------------- Limitations of 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:
Segment overrides don't do anything yet.
All internal computations are performed at 64 bit or higher precision
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.
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
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
numbers in an FPU register with its identity as a PseudoDenormal, but
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 -----------------------
Speed.
......
......@@ -85,13 +85,15 @@ void emu_printall()
RE_ENTRANT_CHECK_OFF;
/* No need to verify_area(), we have previously fetched these bytes. */
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);
if ( (byte1 & 0xf8) == 0xd8 ) break;
printk("[%02x]", byte1);
address++;
}
if ( i == MAX_PRINTED_BYTES ) printk("[more..]");
printk("%02x ", byte1);
FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
partial_status = status_word();
......@@ -234,6 +236,7 @@ static struct {
0x126 in fpu_entry.c
0x127 in poly_2xm1.c
0x128 in fpu_entry.c
0x130 in get_address.c
0x2nn in an *.S file:
0x201 in reg_u_add.S
0x202 in reg_u_div.S
......@@ -310,11 +313,11 @@ void exception(int n)
#endif PRINT_MESSAGES
}
else
printk("FP emulator: Unknown Exception: 0x%04x!\n", n);
printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
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();
}
#ifdef PRINT_MESSAGES
......
......@@ -94,7 +94,11 @@ extern char emulating;
typedef void (*FUNC)(void);
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 )] )
......
......@@ -137,13 +137,14 @@ unsigned short FPU_data_selector;
char emulating=0;
#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)
{
unsigned char FPU_modrm, byte1;
overrides override;
fpu_addr_modes addr_modes;
int unmasked;
#ifdef PARANOID
......@@ -170,35 +171,40 @@ asmlinkage void math_emulate(long 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 (FPU_EFLAGS & 0x00020000)
{
math_abort(FPU_info,SIGILL);
}
if ( addr_modes.vm86 )
FPU_EIP += FPU_CS << 4;
/* user code space? */
if (FPU_CS == KERNEL_CS)
{
printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
panic("Math emulation needed in kernel");
}
FPU_ORIG_EIP = FPU_EIP;
/* We cannot handle multiple segments yet */
if (FPU_CS != USER_CS || FPU_DS != USER_DS)
if ( !addr_modes.vm86 )
{
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;
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;
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;
EXCEPTION(EX_INTERNAL|0x126);
math_abort(FPU_info,SIGILL);
......@@ -289,7 +295,11 @@ asmlinkage void math_emulate(long arg)
if ( FPU_modrm < 0300 )
{
/* 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) )
{
unsigned short status1 = partial_status;
......@@ -303,16 +313,16 @@ asmlinkage void math_emulate(long arg)
switch ( (byte1 >> 1) & 3 )
{
case 0:
unmasked = reg_load_single(override);
unmasked = reg_load_single();
break;
case 1:
reg_load_int32(override);
reg_load_int32();
break;
case 2:
unmasked = reg_load_double(override);
unmasked = reg_load_double();
break;
case 3:
reg_load_int16(override);
reg_load_int16();
break;
}
......@@ -440,7 +450,8 @@ asmlinkage void math_emulate(long arg)
}
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:
......@@ -527,10 +538,14 @@ asmlinkage void math_emulate(long arg)
if (FPU_lookahead && !need_resched)
{
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;
}
if ( addr_modes.vm86 )
FPU_EIP -= FPU_CS << 4;
RE_ENTRANT_CHECK_OFF;
}
......@@ -539,16 +554,17 @@ asmlinkage void math_emulate(long arg)
all prefix bytes, further changes are needed in the emulator code
which accesses user address space. Access to separate segments is
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 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;
FPU_code_verify_area(1);
byte = get_fs_byte((unsigned char *) FPU_EIP);
byte = get_fs_byte(ip);
RE_ENTRANT_CHECK_ON;
while ( 1 )
......@@ -558,6 +574,11 @@ static int valid_prefix(unsigned char *Byte, overrides *override)
case ADDR_SIZE_PREFIX:
override->address_size = ADDR_SIZE_PREFIX;
goto do_next_byte;
case OP_SIZE_PREFIX:
override->operand_size = OP_SIZE_PREFIX;
goto do_next_byte;
case PREFIX_CS:
override->segment = PREFIX_CS;
goto do_next_byte;
......@@ -585,12 +606,11 @@ static int valid_prefix(unsigned char *Byte, overrides *override)
case PREFIX_REPE:
case PREFIX_REPNE:
case OP_SIZE_PREFIX: /* Used often by gcc, but has no effect. */
do_next_byte:
FPU_EIP++;
ip++;
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
byte = get_fs_byte((unsigned char *) (FPU_EIP));
byte = get_fs_byte(ip);
RE_ENTRANT_CHECK_ON;
break;
case FWAIT_OPCODE:
......@@ -600,6 +620,7 @@ static int valid_prefix(unsigned char *Byte, overrides *override)
if ( (byte & 0xf8) == 0xd8 )
{
*Byte = byte;
*fpu_eip = ip;
return 1;
}
else
......@@ -607,7 +628,6 @@ static int valid_prefix(unsigned char *Byte, overrides *override)
/* Not a valid sequence of prefix bytes followed by
an FPU instruction. */
*Byte = byte; /* Needed for error message. */
FPU_EIP = ip;
return 0;
}
}
......
......@@ -63,10 +63,13 @@ extern void trig_a(void);
extern void trig_b(void);
/* 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 */
extern void load_store_instr(char type, overrides override);
extern void load_store_instr(char type, fpu_addr_modes addr_modes);
/* poly_2xm1.c */
extern int poly_2xm1(FPU_REG const *arg, FPU_REG *result);
......@@ -105,26 +108,26 @@ extern void fucompp(void);
extern void fconst(void);
/* reg_ld_str.c */
extern int reg_load_extended(overrides override);
extern int reg_load_double(overrides override);
extern int reg_load_single(overrides override);
extern void reg_load_int64(overrides override);
extern void reg_load_int32(overrides override);
extern void reg_load_int16(overrides override);
extern void reg_load_bcd(overrides override);
extern int reg_store_extended(overrides override);
extern int reg_store_double(overrides override);
extern int reg_store_single(overrides override);
extern int reg_store_int64(overrides override);
extern int reg_store_int32(overrides override);
extern int reg_store_int16(overrides override);
extern int reg_store_bcd(overrides override);
extern int reg_load_extended(void);
extern int reg_load_double(void);
extern int reg_load_single(void);
extern void reg_load_int64(void);
extern void reg_load_int32(void);
extern void reg_load_int16(void);
extern void reg_load_bcd(void);
extern int reg_store_extended(void);
extern int reg_store_double(void);
extern int reg_store_single(void);
extern int reg_store_int64(void);
extern int reg_store_int32(void);
extern int reg_store_int16(void);
extern int reg_store_bcd(void);
extern int round_to_int(FPU_REG *r);
extern char *fldenv(void);
extern void frstor(void);
extern char *fldenv(fpu_addr_modes addr_modes);
extern void frstor(fpu_addr_modes addr_modes);
extern unsigned short tag_word(void);
extern char *fstenv(void);
extern void fsave(void);
extern char *fstenv(fpu_addr_modes addr_modes);
extern void fsave(fpu_addr_modes addr_modes);
/* reg_mul.c */
extern int reg_mul(FPU_REG const *a, FPU_REG const *b,
......
......@@ -23,7 +23,12 @@
#define FPU_info (I387.soft.info)
#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_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_EFLAGS (FPU_info->___eflags)
#define FPU_EIP (FPU_info->___eip)
......
......@@ -41,16 +41,16 @@ static int reg_offset[] = {
/* 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;
long offset;
RE_ENTRANT_CHECK_OFF;
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;
FPU_EIP++;
(*fpu_eip)++;
ss = base >> 6;
index = (base >> 3) & 7;
base &= 7;
......@@ -77,23 +77,51 @@ static void *sib(int mod)
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF;
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;
FPU_EIP++;
(*fpu_eip)++;
}
else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
{
/* 32 bit displacment */
RE_ENTRANT_CHECK_OFF;
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;
}
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
......@@ -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;
long *cpu_reg_ptr;
......@@ -123,11 +152,20 @@ void get_address(unsigned char FPU_modrm, overrides override)
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;
if (FPU_rm == 4 && mod != 3)
{
FPU_data_address = sib(mod);
FPU_data_address = sib(mod, fpu_eip);
return;
}
......@@ -137,20 +175,11 @@ void get_address(unsigned char FPU_modrm, overrides override)
case 0:
if (FPU_rm == 5)
{
/* Special case: disp16 or disp32 */
/* Special case: disp32 */
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);
offset = get_fs_long((unsigned long *) FPU_EIP);
FPU_EIP += 4;
}
FPU_code_verify_area(4);
offset = get_fs_long((unsigned long *) (*fpu_eip));
(*fpu_eip) += 4;
RE_ENTRANT_CHECK_ON;
FPU_data_address = (void *) offset;
return;
......@@ -165,33 +194,125 @@ void get_address(unsigned char FPU_modrm, overrides override)
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF;
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;
FPU_EIP++;
(*fpu_eip)++;
break;
case 2:
/* 16 or 32 bit displacement */
/* 32 bit displacement */
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);
offset = (signed) get_fs_word((unsigned short *) FPU_EIP);
FPU_EIP += 2;
}
else
{
FPU_code_verify_area(4);
offset = (signed) get_fs_long((unsigned long *) FPU_EIP);
FPU_EIP += 4;
offset = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip));
(*fpu_eip) += 2;
RE_ENTRANT_CHECK_ON;
goto add_segment;
}
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;
break;
case 3:
/* Not legal for the FPU */
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;
if ( override.address_size == ADDR_SIZE_PREFIX )
FPU_data_address = (void *)((long)FPU_data_address & 0xffff);
add_segment:
offset &= 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] = {
_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
change if the emulator is re-entered. */
......@@ -85,7 +85,7 @@ switch ( type )
{
case 000: /* fld m32real */
clear_C1();
reg_load_single(override);
reg_load_single();
if ( (FPU_loaded_data.tag == TW_NaN) &&
real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) )
{
......@@ -96,12 +96,12 @@ switch ( type )
break;
case 001: /* fild m32int */
clear_C1();
reg_load_int32(override);
reg_load_int32();
reg_move(&FPU_loaded_data, pop_ptr);
break;
case 002: /* fld m64real */
clear_C1();
reg_load_double(override);
reg_load_double();
if ( (FPU_loaded_data.tag == TW_NaN) &&
real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) )
{
......@@ -112,58 +112,58 @@ switch ( type )
break;
case 003: /* fild m16int */
clear_C1();
reg_load_int16(override);
reg_load_int16();
reg_move(&FPU_loaded_data, pop_ptr);
break;
case 010: /* fst m32real */
clear_C1();
reg_store_single(override);
reg_store_single();
break;
case 011: /* fist m32int */
clear_C1();
reg_store_int32(override);
reg_store_int32();
break;
case 012: /* fst m64real */
clear_C1();
reg_store_double(override);
reg_store_double();
break;
case 013: /* fist m16int */
clear_C1();
reg_store_int16(override);
reg_store_int16();
break;
case 014: /* fstp m32real */
clear_C1();
if ( reg_store_single(override) )
if ( reg_store_single() )
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 015: /* fistp m32int */
clear_C1();
if ( reg_store_int32(override) )
if ( reg_store_int32() )
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 016: /* fstp m64real */
clear_C1();
if ( reg_store_double(override) )
if ( reg_store_double() )
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 017: /* fistp m16int */
clear_C1();
if ( reg_store_int16(override) )
if ( reg_store_int16() )
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 020: /* fldenv m14/28byte */
fldenv();
fldenv(addr_modes);
break;
case 022: /* frstor m94/108byte */
frstor();
frstor(addr_modes);
break;
case 023: /* fbld m80dec */
clear_C1();
reg_load_bcd(override);
reg_load_bcd();
reg_move(&FPU_loaded_data, pop_ptr);
break;
case 024: /* fldcw */
......@@ -183,25 +183,25 @@ switch ( type )
break;
case 025: /* fld m80real */
clear_C1();
reg_load_extended(override);
reg_load_extended();
reg_move(&FPU_loaded_data, pop_ptr);
break;
case 027: /* fild m64int */
clear_C1();
reg_load_int64(override);
reg_load_int64();
reg_move(&FPU_loaded_data, pop_ptr);
break;
case 030: /* fstenv m14/28byte */
fstenv();
fstenv(addr_modes);
NO_NET_DATA_EFFECT;
break;
case 032: /* fsave */
fsave();
fsave(addr_modes);
NO_NET_DATA_EFFECT;
break;
case 033: /* fbstp m80dec */
clear_C1();
if ( reg_store_bcd(override) )
if ( reg_store_bcd() )
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
......@@ -215,7 +215,7 @@ switch ( type )
break;
case 035: /* fstp m80real */
clear_C1();
if ( reg_store_extended(override) )
if ( reg_store_extended() )
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
......@@ -229,7 +229,7 @@ switch ( type )
break;
case 037: /* fistp m64int */
clear_C1();
if ( reg_store_int64(override) )
if ( reg_store_int64() )
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
......
......@@ -44,7 +44,7 @@ FPU_REG FPU_loaded_data;
/* 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;
unsigned long sigl, sigh, exp;
......@@ -145,7 +145,7 @@ int reg_load_extended(overrides override)
/* Get a double from user memory */
int reg_load_double(overrides override)
int reg_load_double(void)
{
double *dfloat = (double *)FPU_data_address;
int exp;
......@@ -223,7 +223,7 @@ int reg_load_double(overrides override)
/* Get a float from user memory */
int reg_load_single(overrides override)
int reg_load_single(void)
{
float *single = (float *)FPU_data_address;
unsigned m32;
......@@ -292,7 +292,7 @@ int reg_load_single(overrides override)
/* 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;
int e;
......@@ -324,7 +324,7 @@ void reg_load_int64(overrides override)
/* 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;
......@@ -356,7 +356,7 @@ void reg_load_int32(overrides override)
/* Get a short from user memory */
void reg_load_int16(overrides override)
void reg_load_int16(void)
{
short *_s = (short *)FPU_data_address;
int s, e;
......@@ -389,7 +389,7 @@ void reg_load_int16(overrides override)
/* 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;
int pos;
......@@ -436,7 +436,7 @@ void reg_load_bcd(overrides override)
/*===========================================================================*/
/* 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
......@@ -475,7 +475,7 @@ int reg_store_extended(overrides override)
/* Put a double into user memory */
int reg_store_double(overrides override)
int reg_store_double(void)
{
double *dfloat = (double *)FPU_data_address;
unsigned long l[2];
......@@ -670,7 +670,7 @@ int reg_store_double(overrides override)
/* Put a float into user memory */
int reg_store_single(overrides override)
int reg_store_single(void)
{
float *single = (float *)FPU_data_address;
long templ;
......@@ -859,7 +859,7 @@ int reg_store_single(overrides override)
/* 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;
FPU_REG t;
......@@ -918,7 +918,7 @@ int reg_store_int64(overrides override)
/* Put a long into user memory */
int reg_store_int32(overrides override)
int reg_store_int32(void)
{
long *d = (long *)FPU_data_address;
FPU_REG t;
......@@ -972,7 +972,7 @@ int reg_store_int32(overrides override)
/* Put a short into user memory */
int reg_store_int16(overrides override)
int reg_store_int16(void)
{
short *d = (short *)FPU_data_address;
FPU_REG t;
......@@ -1026,7 +1026,7 @@ int reg_store_int16(overrides override)
/* 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;
FPU_REG t;
......@@ -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;
unsigned short tag_word = 0;
unsigned char tag;
int i;
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;
if ( addr_modes.vm86
|| (addr_modes.override.operand_size == OP_SIZE_PREFIX) )
{
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, s, 0x0e);
control_word = get_fs_word((unsigned short *) s);
partial_status = get_fs_word((unsigned short *) (s+2));
tag_word = get_fs_word((unsigned short *) (s+4));
ip_offset = get_fs_word((unsigned short *) (s+6));
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;
......@@ -1226,21 +1250,21 @@ char *fldenv(void)
NO_NET_DATA_EFFECT;
NO_NET_INSTR_EFFECT;
return s + 0x1c;
return s;
}
void frstor(void)
void frstor(fpu_addr_modes addr_modes)
{
int i, stnr;
unsigned char tag;
char *s = fldenv();
char *s = fldenv(addr_modes);
for ( i = 0; i < 8; i++ )
{
/* Load each register. */
FPU_data_address = (void *)(s+i*10);
reg_load_extended((overrides){0,0});
reg_load_extended();
stnr = (i+top) & 7;
tag = regs[stnr].tag; /* Derived from the loaded tag word. */
reg_move(&FPU_loaded_data, &regs[stnr]);
......@@ -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;
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,28);
if ( addr_modes.vm86
|| (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
/* An 80486 sets all the reserved bits to 1. */
put_fs_long(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d);
put_fs_long(0xffff0000 | status_word(), (unsigned long *) (d+4));
put_fs_long(0xffff0000 | tag_word(), (unsigned long *) (d+8));
/* An 80486 sets all the reserved bits to 1. */
put_fs_long(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d);
put_fs_long(0xffff0000 | status_word(), (unsigned long *) (d+4));
put_fs_long(0xffff0000 | tag_word(), (unsigned long *) (d+8));
#else
put_fs_word(control_word, (unsigned short *) d);
put_fs_word(status_word(), (unsigned short *) (d+4));
put_fs_word(tag_word(), (unsigned short *) (d+8));
put_fs_word(control_word, (unsigned short *) d);
put_fs_word(status_word(), (unsigned short *) (d+4));
put_fs_word(tag_word(), (unsigned short *) (d+8));
#endif PECULIAR_486
put_fs_long(ip_offset, (unsigned long *) (d+0x0c));
put_fs_long(cs_selector & ~0xf8000000, (unsigned long *) (d+0x10));
put_fs_long(data_operand_offset, (unsigned long *) (d+0x14));
put_fs_long(ip_offset, (unsigned long *) (d+0x0c));
put_fs_long(cs_selector & ~0xf8000000, (unsigned long *) (d+0x10));
put_fs_long(data_operand_offset, (unsigned long *) (d+0x14));
#ifdef PECULIAR_486
/* An 80486 sets all the reserved bits to 1. */
put_fs_long(0xffff0000 | operand_selector, (unsigned long *) (d+0x18));
/* An 80486 sets all the reserved bits to 1. */
put_fs_long(0xffff0000 | operand_selector, (unsigned long *) (d+0x18));
#else
put_fs_long(operand_selector, (unsigned long *) (d+0x18));
put_fs_long(operand_selector, (unsigned long *) (d+0x18));
#endif PECULIAR_486
RE_ENTRANT_CHECK_ON;
RE_ENTRANT_CHECK_ON;
d += 0x1c;
}
control_word |= CW_Exceptions;
partial_status &= ~(SW_Summary | SW_Backward);
return d + 0x1c;
return d;
}
void fsave(void)
void fsave(fpu_addr_modes addr_modes)
{
char *d;
int i;
d = fstenv();
d = fstenv(addr_modes);
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,80);
RE_ENTRANT_CHECK_ON;
......
......@@ -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 = {
#endif
/* The first device defaults to I/O base '0', which means autoprobe. */
#ifdef EI8390
# define ETH0_ADDR EI8390
#else
#ifndef ETH0_ADDR
# define ETH0_ADDR 0
#endif
#ifdef EI8390_IRQ
# define ETH0_IRQ EI8390_IRQ
#else
#ifndef ETH0_IRQ
# define ETH0_IRQ 0
#endif
/* "eth0" defaults to autoprobe, other use a base of "-0x20", "don't probe".
......
......@@ -7,43 +7,12 @@
* This file is based upon code written by Eric Youndale for the ELF object
* file format.
*
* Revision information:
* 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.
* Author: Al Longyear (longyear@sii.com)
*
* 4 September 1993
* Al Longyear (longyear@sii.com)
* Added support for shared libraries.
*
* 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.
* Latest Revision:
* 3 Feburary 1994
* Al Longyear (longyear@sii.com)
* Cleared first page of bss section using put_fs_byte.
*/
#include <linux/fs.h>
......@@ -104,6 +73,37 @@ is_properly_aligned (COFF_SCNHDR *sect)
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.
*/
......@@ -521,11 +521,13 @@ load_object (struct linux_binprm * bprm, struct pt_regs *regs, int lib_ok)
zeromap_page_range (PAGE_ALIGN (bss_vaddr),
PAGE_ALIGN (bss_size),
PAGE_COPY);
status = clear_memory (bss_vaddr, bss_size);
}
/*
* Load any shared library for the executable.
*/
if (lib_ok && lib_count != 0) {
if (status >= 0 && lib_ok && lib_count != 0) {
int nIndex;
COFF_SCNHDR *sect_ptr = sect_bufr;
/*
......
/*
* linux/fs/nfs/proc.c
*
* Copyright (C) 1992 Rick Sladkey
* Copyright (C) 1992, 1993, 1994 Rick Sladkey
*
* OS-independent nfs remote procedure call functions
*/
......@@ -41,7 +41,7 @@ static int proc_debug = 0;
#endif /* !NFS_PROC_DEBUG */
static int *nfs_rpc_header(int *p, int procedure);
static int *nfs_rpc_header(int *p, int procedure, int ruid);
static int *nfs_rpc_verify(int *p);
static int nfs_stat_to_errno(int stat);
......@@ -192,11 +192,13 @@ int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
{
int *p, *p0;
int status;
int ruid = 0;
PRINTK("NFS call getattr\n");
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_GETATTR);
retry:
p = nfs_rpc_header(p0, NFSPROC_GETATTR, ruid);
p = xdr_encode_fhandle(p, fhandle);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
nfs_rpc_free(p0);
......@@ -208,8 +210,13 @@ int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply getattr\n");
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply getattr failed = %d\n", status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
}
......@@ -219,11 +226,13 @@ int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
{
int *p, *p0;
int status;
int ruid = 0;
PRINTK("NFS call setattr\n");
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_SETATTR);
retry:
p = nfs_rpc_header(p0, NFSPROC_SETATTR, ruid);
p = xdr_encode_fhandle(p, fhandle);
p = xdr_encode_sattr(p, sattr);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
......@@ -236,8 +245,13 @@ int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply setattr\n");
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply setattr failed = %d\n", status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
}
......@@ -247,6 +261,7 @@ int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *n
{
int *p, *p0;
int status;
int ruid = 0;
PRINTK("NFS call lookup %s\n", name);
#ifdef NFS_PROC_DEBUG
......@@ -255,7 +270,8 @@ int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *n
#endif
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_LOOKUP);
retry:
p = nfs_rpc_header(p0, NFSPROC_LOOKUP, ruid);
p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
......@@ -269,8 +285,13 @@ int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *n
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply lookup\n");
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply lookup failed = %d\n", status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
}
......@@ -280,11 +301,13 @@ int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
{
int *p, *p0;
int status;
int ruid = 0;
PRINTK("NFS call readlink\n");
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_READLINK);
retry:
p = nfs_rpc_header(p0, NFSPROC_READLINK, ruid);
p = xdr_encode_fhandle(p, fhandle);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
nfs_rpc_free(p0);
......@@ -300,8 +323,13 @@ int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
else
PRINTK("NFS reply readlink %s\n", res);
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply readlink failed = %d\n", status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
}
......@@ -311,12 +339,14 @@ int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
{
int *p, *p0;
int status;
int ruid = 0;
int len = 0; /* = 0 is for gcc */
PRINTK("NFS call read %d @ %d\n", count, offset);
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_READ);
retry:
p = nfs_rpc_header(p0, NFSPROC_READ, ruid);
p = xdr_encode_fhandle(p, fhandle);
*p++ = htonl(offset);
*p++ = htonl(count);
......@@ -336,8 +366,13 @@ int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
else
PRINTK("NFS reply read %d\n", len);
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply read failed = %d\n", status);
}
nfs_rpc_free(p0);
return (status == NFS_OK) ? len : -nfs_stat_to_errno(status);
}
......@@ -347,11 +382,13 @@ int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
{
int *p, *p0;
int status;
int ruid = 0;
PRINTK("NFS call write %d @ %d\n", count, offset);
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_WRITE);
retry:
p = nfs_rpc_header(p0, NFSPROC_WRITE, ruid);
p = xdr_encode_fhandle(p, fhandle);
*p++ = htonl(offset); /* traditional, could be any value */
*p++ = htonl(offset);
......@@ -367,8 +404,13 @@ int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply write\n");
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply write failed = %d\n", status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
}
......@@ -379,11 +421,13 @@ int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
{
int *p, *p0;
int status;
int ruid = 0;
PRINTK("NFS call create %s\n", name);
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_CREATE);
retry:
p = nfs_rpc_header(p0, NFSPROC_CREATE, ruid);
p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name);
p = xdr_encode_sattr(p, sattr);
......@@ -398,8 +442,13 @@ int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply create\n");
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply create failed = %d\n", status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
}
......@@ -408,11 +457,13 @@ int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *n
{
int *p, *p0;
int status;
int ruid = 0;
PRINTK("NFS call remove %s\n", name);
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_REMOVE);
retry:
p = nfs_rpc_header(p0, NFSPROC_REMOVE, ruid);
p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
......@@ -424,8 +475,13 @@ int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *n
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply remove\n");
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply remove failed = %d\n", status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
}
......@@ -436,11 +492,13 @@ int nfs_proc_rename(struct nfs_server *server,
{
int *p, *p0;
int status;
int ruid = 0;
PRINTK("NFS call rename %s -> %s\n", old_name, new_name);
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_RENAME);
retry:
p = nfs_rpc_header(p0, NFSPROC_RENAME, ruid);
p = xdr_encode_fhandle(p, old_dir);
p = xdr_encode_string(p, old_name);
p = xdr_encode_fhandle(p, new_dir);
......@@ -454,8 +512,13 @@ int nfs_proc_rename(struct nfs_server *server,
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply rename\n");
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply rename failed = %d\n", status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
}
......@@ -465,11 +528,13 @@ int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
{
int *p, *p0;
int status;
int ruid = 0;
PRINTK("NFS call link %s\n", name);
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_LINK);
retry:
p = nfs_rpc_header(p0, NFSPROC_LINK, ruid);
p = xdr_encode_fhandle(p, fhandle);
p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name);
......@@ -482,8 +547,13 @@ int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply link\n");
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply link failed = %d\n", status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
}
......@@ -493,11 +563,13 @@ int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
{
int *p, *p0;
int status;
int ruid = 0;
PRINTK("NFS call symlink %s -> %s\n", name, path);
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_SYMLINK);
retry:
p = nfs_rpc_header(p0, NFSPROC_SYMLINK, ruid);
p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name);
p = xdr_encode_string(p, path);
......@@ -511,8 +583,13 @@ int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply symlink\n");
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply symlink failed = %d\n", status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
}
......@@ -523,11 +600,13 @@ int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
{
int *p, *p0;
int status;
int ruid = 0;
PRINTK("NFS call mkdir %s\n", name);
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_MKDIR);
retry:
p = nfs_rpc_header(p0, NFSPROC_MKDIR, ruid);
p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name);
p = xdr_encode_sattr(p, sattr);
......@@ -542,8 +621,13 @@ int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply mkdir\n");
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply mkdir failed = %d\n", status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
}
......@@ -552,11 +636,13 @@ int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *na
{
int *p, *p0;
int status;
int ruid = 0;
PRINTK("NFS call rmdir %s\n", name);
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_RMDIR);
retry:
p = nfs_rpc_header(p0, NFSPROC_RMDIR, ruid);
p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
......@@ -568,8 +654,13 @@ int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *na
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply rmdir\n");
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply rmdir failed = %d\n", status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
}
......@@ -579,6 +670,7 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
{
int *p, *p0;
int status;
int ruid = 0;
int i = 0; /* = 0 is for gcc */
int size;
int eof;
......@@ -587,7 +679,8 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
size = server->rsize;
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_READDIR);
retry:
p = nfs_rpc_header(p0, NFSPROC_READDIR, ruid);
p = xdr_encode_fhandle(p, fhandle);
*p++ = htonl(cookie);
*p++ = htonl(size);
......@@ -615,8 +708,13 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
eof ? "eof" : "");
}
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply readdir failed = %d\n", status);
}
nfs_rpc_free(p0);
return (status == NFS_OK) ? i : -nfs_stat_to_errno(status);
}
......@@ -626,11 +724,13 @@ int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
{
int *p, *p0;
int status;
int ruid = 0;
PRINTK("NFS call statfs\n");
if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_STATFS);
retry:
p = nfs_rpc_header(p0, NFSPROC_STATFS, ruid);
p = xdr_encode_fhandle(p, fhandle);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
nfs_rpc_free(p0);
......@@ -642,8 +742,13 @@ int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
p = xdr_decode_fsinfo(p, res);
PRINTK("NFS reply statfs\n");
}
else
else {
if (!ruid && current->euid == 0 && current->uid != 0) {
ruid = 1;
goto retry;
}
PRINTK("NFS reply statfs failed = %d\n", status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
}
......@@ -652,7 +757,7 @@ int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
* Here are a few RPC-assist functions.
*/
static int *nfs_rpc_header(int *p, int procedure)
static int *nfs_rpc_header(int *p, int procedure, int ruid)
{
int *p1, *p2;
int i;
......@@ -673,7 +778,7 @@ static int *nfs_rpc_header(int *p, int procedure)
p1 = p++;
*p++ = htonl(CURRENT_TIME); /* traditional, could be anything */
p = xdr_encode_string(p, (char *) sys);
*p++ = htonl(current->euid);
*p++ = htonl(ruid ? current->uid : current->euid);
*p++ = htonl(current->egid);
p2 = p++;
for (i = 0; i < 16 && i < NGROUPS && current->groups[i] != NOGROUP; i++)
......
/*
* 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;
extern int nr_secondary_pages;
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
......
......@@ -183,6 +183,9 @@ asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
return -EINVAL;
p = signum - 1 + current->sigaction;
if (action) {
int err = verify_area(VERIFY_READ, action, sizeof(*action));
if (err)
return err;
memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
if (new_sa.sa_flags & SA_NOMASK)
new_sa.sa_mask = 0;
......@@ -194,8 +197,10 @@ asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
return -EFAULT;
}
if (oldaction) {
if (!verify_area(VERIFY_WRITE,oldaction, sizeof(struct sigaction)))
memcpy_tofs(oldaction, p, sizeof(struct sigaction));
int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction));
if (err)
return err;
memcpy_tofs(oldaction, p, sizeof(struct sigaction));
}
if (action) {
*p = new_sa;
......
......@@ -276,9 +276,12 @@ static int rt_new(struct rtentry *r)
mask = ((struct sockaddr_in *) &r->rt_genmask)->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)
mask = 0xffffffff;
else if (r->rt_genmask.sa_family != AF_INET)
else if (mask && r->rt_genmask.sa_family != AF_INET)
return -EAFNOSUPPORT;
if (flags & RTF_GATEWAY) {
......@@ -292,9 +295,6 @@ static int rt_new(struct rtentry *r)
if (dev == NULL)
return -ENETUNREACH;
if (bad_mask(mask, daddr))
mask = 0;
rt_add(flags, daddr, mask, gw, dev);
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