Commit b168ffdf authored by Linus Torvalds's avatar Linus Torvalds

Import 0.99.14v

parent bfeedc98
VERSION = 0.99
PATCHLEVEL = 14
ALPHA = u
ALPHA = v
all: Version zImage
......
......@@ -38,7 +38,8 @@ void Un_impl(void)
{
unsigned char byte1, FPU_modrm;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
/* No need to verify_area(), we have previously fetched these bytes. */
byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP);
FPU_modrm = get_fs_byte(1 + (unsigned char *) FPU_ORIG_EIP);
......@@ -49,7 +50,7 @@ void Un_impl(void)
printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
else
printk("/%d\n", (FPU_modrm >> 3) & 7);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
EXCEPTION(EX_Invalid);
......@@ -65,7 +66,8 @@ void emu_printall()
"DeNorm", "Inf", "NaN", "Empty" };
unsigned char byte1, FPU_modrm;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
/* No need to verify_area(), we have previously fetched these bytes. */
byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP);
FPU_modrm = get_fs_byte(1 + (unsigned char *) FPU_ORIG_EIP);
partial_status = status_word();
......@@ -154,7 +156,7 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n",
(long)(FPU_loaded_data.sigl & 0xFFFF),
FPU_loaded_data.exp - EXP_BIAS + 1);
printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
}
......@@ -261,7 +263,7 @@ void exception(int n)
}
}
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
if ( (~control_word & n & CW_Exceptions) || (n == EX_INTERNAL) )
{
#ifdef PRINT_MESSAGES
......@@ -303,7 +305,7 @@ void exception(int n)
*/
/* regs[0].tag |= TW_FPU_Interrupt; */
}
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
#ifdef __DEBUG__
math_abort(FPU_info,SIGFPE);
......
/*---------------------------------------------------------------------------+
| fpu_emu.h |
| |
| Copyright (C) 1992,1993 |
| Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
......@@ -62,8 +62,8 @@
#ifdef PARANOID
extern char emulating;
# define RE_ENTRANT_CHECK_OFF emulating = 0;
# define RE_ENTRANT_CHECK_ON emulating = 1;
# define RE_ENTRANT_CHECK_OFF emulating = 0
# define RE_ENTRANT_CHECK_ON emulating = 1
#else
# define RE_ENTRANT_CHECK_OFF
# define RE_ENTRANT_CHECK_ON
......
......@@ -209,6 +209,7 @@ asmlinkage void math_emulate(long arg)
do_another_FPU_instruction:
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
code = get_fs_word((unsigned short *) FPU_EIP);
RE_ENTRANT_CHECK_ON;
......@@ -301,6 +302,7 @@ asmlinkage void math_emulate(long arg)
{
FPU_EIP++;
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
code = get_fs_word((unsigned short *) FPU_EIP);
RE_ENTRANT_CHECK_ON;
}
......@@ -560,6 +562,7 @@ asmlinkage void math_emulate(long arg)
unsigned char next;
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
next = get_fs_byte((unsigned char *) FPU_EIP);
RE_ENTRANT_CHECK_ON;
if ( valid_prefix(next) )
......@@ -591,8 +594,10 @@ static int valid_prefix(unsigned char byte)
case PREFIX_GS:
case OP_SIZE_PREFIX: /* Used often by gcc, but has no effect. */
FPU_EIP++;
RE_ENTRANT_CHECK_OFF;
byte = get_fs_byte((unsigned char *) (++FPU_EIP));
FPU_code_verify_area(1);
byte = get_fs_byte((unsigned char *) (FPU_EIP));
RE_ENTRANT_CHECK_ON;
break;
case FWAIT_OPCODE:
......
/*---------------------------------------------------------------------------+
| fpu_system.h |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
+---------------------------------------------------------------------------*/
......@@ -41,6 +42,23 @@
#define data_operand_offset (I387.soft.foo)
#define operand_selector (I387.soft.fos)
#define FPU_verify_area(x,y,z) if ( verify_area(x,y,z) ) \
math_abort(FPU_info,SIGSEGV)
#undef FPU_IGNORE_CODE_SEGV
#ifdef FPU_IGNORE_CODE_SEGV
/* verify_area() is very expensive, and causes the emulator to run
about 20% slower if applied to the code. Anyway, errors due to bad
code addresses should be much rarer than errors due to bad data
addresses. */
#define FPU_code_verify_area(z)
#else
/* A simpler test than verify_area() can probably be done for
FPU_code_verify_area() because the only possible error is to step
past the upper boundary of a legal code area. */
#define FPU_code_verify_area(z) FPU_verify_area(VERIFY_READ,(void *)FPU_EIP,z)
#endif
/* ######## temporary and ugly ;-) */
#define FPU_data_address ((void *)(I387.soft.twd))
......
......@@ -3,7 +3,7 @@
| |
| Get the effective address from an FPU instruction. |
| |
| Copyright (C) 1992,1993 |
| Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
......@@ -46,9 +46,10 @@ static void *sib(int mod)
unsigned char ss,index,base;
long offset;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
base = get_fs_byte((char *) FPU_EIP); /* The SIB byte */
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
FPU_EIP++;
ss = base >> 6;
index = (base >> 3) & 7;
......@@ -74,17 +75,19 @@ static void *sib(int mod)
if (mod == 1)
{
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
offset += (signed char) get_fs_byte((char *) FPU_EIP);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
FPU_EIP++;
}
else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
{
/* 32 bit displacment */
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(4);
offset += (signed) get_fs_long((unsigned long *) FPU_EIP);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
FPU_EIP += 4;
}
......@@ -135,9 +138,10 @@ void get_address(unsigned char FPU_modrm)
if (FPU_rm == 5)
{
/* Special case: disp32 */
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(4);
offset = get_fs_long((unsigned long *) FPU_EIP);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
FPU_EIP += 4;
FPU_data_address = (void *) offset;
return;
......@@ -150,16 +154,18 @@ void get_address(unsigned char FPU_modrm)
}
case 1:
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
offset = (signed char) get_fs_byte((char *) FPU_EIP);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
FPU_EIP++;
break;
case 2:
/* 32 bit displacement */
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(4);
offset = (signed) get_fs_long((unsigned long *) FPU_EIP);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
FPU_EIP += 4;
break;
case 3:
......
......@@ -4,7 +4,7 @@
| This file contains most of the code to interpret the FPU instructions |
| which load and store from user memory. |
| |
| Copyright (C) 1992,1993 |
| Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
......@@ -168,6 +168,7 @@ switch ( type )
break;
case 024: /* fldcw */
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, FPU_data_address, 2);
control_word = get_fs_word((unsigned short *) FPU_data_address);
RE_ENTRANT_CHECK_ON;
if ( partial_status & ~control_word & CW_Exceptions )
......@@ -206,7 +207,7 @@ switch ( type )
break;
case 034: /* fstcw m16int */
RE_ENTRANT_CHECK_OFF;
verify_area(VERIFY_WRITE,FPU_data_address,2);
FPU_verify_area(VERIFY_WRITE,FPU_data_address,2);
put_fs_word(control_word, (short *) FPU_data_address);
RE_ENTRANT_CHECK_ON;
NO_NET_DATA_EFFECT;
......@@ -220,7 +221,7 @@ switch ( type )
break;
case 036: /* fstsw m2byte */
RE_ENTRANT_CHECK_OFF;
verify_area(VERIFY_WRITE,FPU_data_address,2);
FPU_verify_area(VERIFY_WRITE,FPU_data_address,2);
put_fs_word(status_word(),(short *) FPU_data_address);
RE_ENTRANT_CHECK_ON;
NO_NET_DATA_EFFECT;
......
......@@ -3,7 +3,7 @@
| |
| Computation of an approximation of the sin function by a polynomial |
| |
| Copyright (C) 1992,1993 |
| Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
......@@ -128,20 +128,20 @@ void poly_sine(FPU_REG const *arg, FPU_REG *result)
)
{
#ifdef DEBUGGING
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
printk("\nEXP=%d, MS=%08x, LS=%08x\n", result->exp,
result->sigh, result->sigl);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
#endif DEBUGGING
EXCEPTION(EX_INTERNAL|0x103);
}
#ifdef DEBUGGING
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
printk("\n***CORRECTING ILLEGAL RESULT*** in poly_sin() computation\n");
printk("EXP=%d, MS=%08x, LS=%08x\n", result->exp,
result->sigh, result->sigl);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
#endif DEBUGGING
result->sigl = 0; /* Truncate the result to 1.00 */
......
......@@ -3,7 +3,7 @@
| |
| All of the functions which transfer data between user memory and FPU_REGs.|
| |
| Copyright (C) 1992,1993 |
| Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
......@@ -49,13 +49,14 @@ int reg_load_extended(void)
long double *s = (long double *)FPU_data_address;
unsigned long sigl, sigh, exp;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, s, 10);
/* Use temporary variables here because FPU_loaded data is
static and hence re-entrancy problems can arise */
sigl = get_fs_long((unsigned long *) s);
sigh = get_fs_long(1 + (unsigned long *) s);
exp = get_fs_word(4 + (unsigned short *) s);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
FPU_loaded_data.tag = TW_Valid; /* Default */
FPU_loaded_data.sigl = sigl;
......@@ -150,10 +151,11 @@ int reg_load_double(void)
int exp;
unsigned m64, l64;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, dfloat, 8);
m64 = get_fs_long(1 + (unsigned long *) dfloat);
l64 = get_fs_long((unsigned long *) dfloat);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
if (m64 & 0x80000000)
FPU_loaded_data.sign = SIGN_NEG;
......@@ -227,9 +229,10 @@ int reg_load_single(void)
unsigned m32;
int exp;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, single, 4);
m32 = get_fs_long((unsigned long *) single);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
if (m32 & 0x80000000)
FPU_loaded_data.sign = SIGN_NEG;
......@@ -295,10 +298,11 @@ void reg_load_int64(void)
int e;
long long s;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, _s, 8);
((unsigned long *)&s)[0] = get_fs_long((unsigned long *) _s);
((unsigned long *)&s)[1] = get_fs_long(1 + (unsigned long *) _s);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
if (s == 0)
{ reg_move(&CONST_Z, &FPU_loaded_data); return; }
......@@ -326,9 +330,10 @@ void reg_load_int32(void)
long s;
int e;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, _s, 4);
s = (long)get_fs_long((unsigned long *) _s);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
if (s == 0)
{ reg_move(&CONST_Z, &FPU_loaded_data); return; }
......@@ -356,10 +361,11 @@ void reg_load_int16(void)
short *_s = (short *)FPU_data_address;
int s, e;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, _s, 2);
/* Cast as short to get the sign extended. */
s = (short)get_fs_word((unsigned short *) _s);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
if (s == 0)
{ reg_move(&CONST_Z, &FPU_loaded_data); return; }
......@@ -390,12 +396,15 @@ void reg_load_bcd(void)
unsigned char bcd;
long long l=0;
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, s, 10);
RE_ENTRANT_CHECK_ON;
for ( pos = 8; pos >= 0; pos--)
{
l *= 10;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
bcd = (unsigned char)get_fs_byte((unsigned char *) s+pos);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
l += bcd >> 4;
l *= 10;
l += bcd & 0x0f;
......@@ -403,11 +412,11 @@ void reg_load_bcd(void)
/* Finish all access to user memory before putting stuff into
the static FPU_loaded_data */
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
FPU_loaded_data.sign =
((unsigned char)get_fs_byte((unsigned char *) s+9)) & 0x80 ?
SIGN_NEG : SIGN_POS;
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
if (l == 0)
{
......@@ -438,7 +447,9 @@ int reg_store_extended(void)
if ( FPU_st0_tag != TW_Empty )
{
verify_area(VERIFY_WRITE, d, 10);
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE, d, 10);
RE_ENTRANT_CHECK_ON;
write_to_extended(FPU_st0_ptr, (char *) FPU_data_address);
return 1;
}
......@@ -450,7 +461,7 @@ int reg_store_extended(void)
/* The masked response */
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF;
verify_area(VERIFY_WRITE,d,10);
FPU_verify_area(VERIFY_WRITE,d,10);
put_fs_long(0, (unsigned long *) d);
put_fs_long(0xc0000000, 1 + (unsigned long *) d);
put_fs_word(0xffff, 4 + (short *) d);
......@@ -635,11 +646,11 @@ int reg_store_double(void)
{
/* The masked response */
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF
verify_area(VERIFY_WRITE,(void *)dfloat,8);
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
put_fs_long(0, (unsigned long *) dfloat);
put_fs_long(0xfff80000, 1 + (unsigned long *) dfloat);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
return 1;
}
else
......@@ -648,11 +659,11 @@ int reg_store_double(void)
if (FPU_st0_ptr->sign)
l[1] |= 0x80000000;
RE_ENTRANT_CHECK_OFF
verify_area(VERIFY_WRITE,(void *)dfloat,8);
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
put_fs_long(l[0], (unsigned long *)dfloat);
put_fs_long(l[1], 1 + (unsigned long *)dfloat);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
return 1;
}
......@@ -819,10 +830,10 @@ int reg_store_single(void)
{
/* The masked response */
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF
verify_area(VERIFY_WRITE,(void *)single,4);
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,(void *)single,4);
put_fs_long(0xffc00000, (unsigned long *) single);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
return 1;
}
else
......@@ -838,10 +849,10 @@ int reg_store_single(void)
if (FPU_st0_ptr->sign)
templ |= 0x80000000;
RE_ENTRANT_CHECK_OFF
verify_area(VERIFY_WRITE,(void *)single,4);
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,(void *)single,4);
put_fs_long(templ,(unsigned long *) single);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
return 1;
}
......@@ -896,11 +907,11 @@ int reg_store_int64(void)
tll = - tll;
}
RE_ENTRANT_CHECK_OFF
verify_area(VERIFY_WRITE,(void *)d,8);
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,(void *)d,8);
put_fs_long(((long *)&tll)[0],(unsigned long *) d);
put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
return 1;
}
......@@ -951,10 +962,10 @@ int reg_store_int32(void)
t.sigl = -(long)t.sigl;
}
RE_ENTRANT_CHECK_OFF
verify_area(VERIFY_WRITE,d,4);
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,4);
put_fs_long(t.sigl, (unsigned long *) d);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
return 1;
}
......@@ -1005,10 +1016,10 @@ int reg_store_int16(void)
t.sigl = -t.sigl;
}
RE_ENTRANT_CHECK_OFF
verify_area(VERIFY_WRITE,d,2);
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,2);
put_fs_word((short)t.sigl,(short *) d);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
return 1;
}
......@@ -1045,14 +1056,14 @@ int reg_store_bcd(void)
if ( control_word & CW_Invalid )
{
/* Produce the QNaN "indefinite" */
RE_ENTRANT_CHECK_OFF
verify_area(VERIFY_WRITE,d,10);
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,10);
for ( i = 0; i < 7; i++)
put_fs_byte(0, (unsigned char *) d+i); /* These bytes "undefined" */
put_fs_byte(0xc0, (unsigned char *) d+7); /* This byte "undefined" */
put_fs_byte(0xff, (unsigned char *) d+8);
put_fs_byte(0xff, (unsigned char *) d+9);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
return 1;
}
else
......@@ -1064,18 +1075,20 @@ int reg_store_bcd(void)
set_precision_flag(precision_loss);
}
verify_area(VERIFY_WRITE,d,10);
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,10);
RE_ENTRANT_CHECK_ON;
for ( i = 0; i < 9; i++)
{
b = div_small(&ll, 10);
b |= (div_small(&ll, 10)) << 4;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
put_fs_byte(b,(unsigned char *) d+i);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
}
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF;
put_fs_byte(sign,(unsigned char *) d+9);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
return 1;
}
......@@ -1157,7 +1170,8 @@ char *fldenv(void)
unsigned char tag;
int i;
RE_ENTRANT_CHECK_OFF
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));
......@@ -1165,7 +1179,7 @@ char *fldenv(void)
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
RE_ENTRANT_CHECK_ON;
top = (partial_status >> SW_Top_Shift) & 7;
......@@ -1275,9 +1289,8 @@ char *fstenv(void)
{
char *d = (char *)FPU_data_address;
verify_area(VERIFY_WRITE,d,28);
RE_ENTRANT_CHECK_OFF
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);
......@@ -1297,7 +1310,7 @@ char *fstenv(void)
#else
put_fs_long(operand_selector, (unsigned long *) (d+0x18));
#endif PECULIAR_486
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON;
control_word |= CW_Exceptions;
partial_status &= ~(SW_Summary | SW_Backward);
......@@ -1312,7 +1325,9 @@ void fsave(void)
int i;
d = fstenv();
verify_area(VERIFY_WRITE,d,80);
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,80);
RE_ENTRANT_CHECK_ON;
for ( i = 0; i < 8; i++ )
write_to_extended(&regs[(top + i) & 7], d + 10 * i);
......@@ -1324,7 +1339,7 @@ void fsave(void)
/*
A call to this function must be preceeded by a call to
verify_area() to verify access to the 10 bytes at d
FPU_verify_area() to verify access to the 10 bytes at d
*/
static void write_to_extended(FPU_REG *rp, char *d)
{
......
......@@ -9,5 +9,5 @@
| |
+---------------------------------------------------------------------------*/
#define FPU_VERSION "wm-FPU-emu version Beta 1.7"
#define FPU_VERSION "wm-FPU-emu version Beta 1.8"
......@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/errno.h>
......
......@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/busmouse.h>
#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/errno.h>
......
......@@ -967,7 +967,6 @@ void con_write(struct tty_struct * tty)
int c;
unsigned int currcons;
wake_up_interruptible(&tty->write_q.proc_list);
currcons = tty->line - 1;
if (currcons >= NR_CONSOLES) {
printk("con_write: illegal tty (%d)\n", currcons);
......@@ -1279,6 +1278,8 @@ void con_write(struct tty_struct * tty)
if (vcmode != KD_GRAPHICS)
set_cursor(currcons);
enable_bh(KEYBOARD_BH);
if (LEFT(&tty->write_q) > WAKEUP_CHARS)
wake_up_interruptible(&tty->write_q.proc_list);
}
void do_keyboard_interrupt(void)
......
......@@ -126,6 +126,8 @@ static unsigned char handle_diacr(unsigned char);
/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
static struct pt_regs * pt_regs;
static int got_break = 0;
static inline void kb_wait(void)
{
int i;
......@@ -343,7 +345,6 @@ static void put_queue(int ch)
if (LEFT(qp)) {
qp->buf[qp->head] = ch;
INC(qp->head);
wake_up_interruptible(&qp->proc_list);
}
}
......@@ -364,7 +365,6 @@ static void puts_queue(char *cp)
INC(qp->head);
}
}
wake_up_interruptible(&qp->proc_list);
}
static void applkey(int key, char mode)
......@@ -419,13 +419,13 @@ static void hold(void)
{
if (rep || !tty)
return;
if (vc_kbd_flag(kbd, VC_SCROLLOCK))
/* pressing srcoll lock 2nd time sends ^Q, ChN */
put_queue(START_CHAR(tty));
else
/* pressing scroll lock 1st time sends ^S, ChN */
put_queue(STOP_CHAR(tty));
chg_vc_kbd_flag(kbd,VC_SCROLLOCK);
/* pressing scroll lock 2nd time sends ^Q, ChN */
/* now done directly without regard to ISIG -- jlc */
if (!vc_kbd_flag(kbd, VC_SCROLLOCK))
stop_tty(tty);
else
start_tty(tty);
}
static void num(void)
......@@ -453,8 +453,7 @@ static void lastcons(void)
static void send_intr(void)
{
if (tty)
put_queue(INTR_CHAR(tty));
got_break = 1;
}
static void scrll_forw(void)
......@@ -814,6 +813,26 @@ static void kbd_bh(void * unused)
}
want_console = -1;
}
if (got_break) {
if (tty && !I_IGNBRK(tty)) {
if (I_BRKINT(tty)) {
flush_input(tty);
flush_output(tty);
if (tty->pgrp > 0)
kill_pg(tty->pgrp, SIGINT, 1);
} else {
cli();
if (LEFT(&tty->read_q) >= 2) {
set_bit(tty->read_q.head,
&tty->readq_flags);
put_queue(TTY_BREAK);
put_queue(0);
}
sti();
}
}
got_break = 0;
}
do_keyboard_interrupt();
cli();
if ((inb_p(0x64) & kbd_read_mask) == 0x01)
......
......@@ -31,7 +31,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/busmouse.h>
#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/errno.h>
......
......@@ -17,17 +17,20 @@
#include <linux/tty.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/string.h>
#include <asm/system.h>
#include <asm/bitops.h>
#define MIN(a,b) ((a) < (b) ? (a) : (b))
static void pty_close(struct tty_struct * tty, struct file * filp)
{
if (!tty)
return;
if (IS_A_PTY_MASTER(tty->line)) {
if (tty->count > 1)
return;
printk("master pty_close: count = %d!!\n", tty->count);
} else {
if (tty->count > 2)
return;
......@@ -40,32 +43,39 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
wake_up_interruptible(&tty->link->secondary.proc_list);
wake_up_interruptible(&tty->link->read_q.proc_list);
wake_up_interruptible(&tty->link->write_q.proc_list);
if (IS_A_PTY_MASTER(tty->line)) {
if (IS_A_PTY_MASTER(tty->line))
tty_hangup(tty->link);
flush_input(tty);
flush_output(tty);
else {
start_tty(tty);
set_bit(TTY_SLAVE_CLOSED, &tty->link->flags);
}
}
static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
{
int c;
unsigned long count, n;
struct tty_queue *fq, *tq;
while (!from->stopped && !EMPTY(&from->write_q)) {
if (FULL(&to->read_q)) {
TTY_READ_FLUSH(to);
if (FULL(&to->read_q))
break;
continue;
}
c = get_tty_queue(&from->write_q);
put_tty_queue(c, &to->read_q);
if (current->signal & ~current->blocked)
break;
if (from->stopped || EMPTY(&from->write_q))
return;
fq = &from->write_q;
/* Bypass the read_q if this is a pty master. */
tq = IS_A_PTY_MASTER(to->line) ? &to->secondary : &to->read_q;
count = MIN(CHARS(fq), LEFT(tq));
while (count) {
n = MIN(MIN(TTY_BUF_SIZE - fq->tail, TTY_BUF_SIZE - tq->head),
count);
memcpy(&tq->buf[tq->head], &fq->buf[fq->tail], n);
count -= n;
fq->tail = (fq->tail + n) & (TTY_BUF_SIZE - 1);
tq->head = (tq->head + n) & (TTY_BUF_SIZE - 1);
}
if (IS_A_PTY_MASTER(to->line))
wake_up_interruptible(&tq->proc_list);
else
TTY_READ_FLUSH(to);
if (!FULL(&from->write_q))
wake_up_interruptible(&from->write_q.proc_list);
if (LEFT(fq) > WAKEUP_CHARS)
wake_up_interruptible(&fq->proc_list);
if (from->write_data_cnt) {
set_bit(from->line, &tty_check_write);
mark_bh(TTY_BH);
......@@ -87,10 +97,8 @@ int pty_open(struct tty_struct *tty, struct file * filp)
{
if (!tty || !tty->link)
return -ENODEV;
if (IS_A_PTY_MASTER(tty->line))
clear_bit(TTY_SLAVE_OPENED, &tty->flags);
else
set_bit(TTY_SLAVE_OPENED, &tty->link->flags);
if (IS_A_PTY_SLAVE(tty->line))
clear_bit(TTY_SLAVE_CLOSED, &tty->link->flags);
tty->write = tty->link->write = pty_write;
tty->close = tty->link->close = pty_close;
wake_up_interruptible(&tty->read_q.proc_list);
......
......@@ -58,8 +58,6 @@
#undef ISR_HACK
#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
/*
* rs_event - Bitfield of serial lines that events pending
* to be processed at the next clock tick.
......@@ -418,7 +416,7 @@ static inline int check_modem_status(struct async_struct *info)
status = serial_in(info, UART_MSR);
if ((status & UART_MSR_DDCD) && !C_LOCAL(info->tty)) {
if ((status & UART_MSR_DDCD) && !C_CLOCAL(info->tty)) {
#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
printk("ttys%d CD now %s...", info->line,
(status & UART_MSR_DCD) ? "on" : "off");
......@@ -433,7 +431,7 @@ static inline int check_modem_status(struct async_struct *info)
rs_sched_event(info, RS_EVENT_HANGUP);
}
}
if (C_RTSCTS(info->tty)) {
if (C_CRTSCTS(info->tty)) {
if (info->tty->hw_stopped) {
if (status & UART_MSR_CTS) {
#ifdef SERIAL_DEBUG_INTR
......@@ -562,7 +560,7 @@ static inline void handle_rs_break(struct async_struct *info)
if (info->flags & ASYNC_SAK)
do_SAK(info->tty);
if (I_BRKINT(info->tty)) {
if (!I_IGNBRK(info->tty) && I_BRKINT(info->tty)) {
flush_input(info->tty);
flush_output(info->tty);
if (info->tty->pgrp > 0)
......@@ -1066,7 +1064,7 @@ static void rs_throttle(struct tty_struct * tty, int status)
switch (status) {
case TTY_THROTTLE_RQ_FULL:
info = rs_table + DEV_TO_SL(tty->line);
if (tty->termios->c_iflag & IXOFF) {
if (I_IXOFF(tty)) {
info->x_char = STOP_CHAR(tty);
} else {
mcr = serial_inp(info, UART_MCR);
......@@ -1076,7 +1074,7 @@ static void rs_throttle(struct tty_struct * tty, int status)
break;
case TTY_THROTTLE_RQ_AVAIL:
info = rs_table + DEV_TO_SL(tty->line);
if (tty->termios->c_iflag & IXOFF) {
if (I_IXOFF(tty)) {
if (info->x_char)
info->x_char = 0;
else
......@@ -1382,7 +1380,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
if (error)
return error;
put_fs_long(C_LOCAL(tty) ? 1 : 0,
put_fs_long(C_CLOCAL(tty) ? 1 : 0,
(unsigned long *) arg);
return 0;
case TIOCSSOFTCAR:
......@@ -1591,7 +1589,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
{
struct wait_queue wait = { current, NULL };
int retval;
int do_clocal = C_LOCAL(tty);
int do_clocal = C_CLOCAL(tty);
/*
* If the device is in the middle of being closed, then block
......
......@@ -32,6 +32,9 @@
* Added functionality to the OPOST tty handling. No delays, but all
* other bits should be there.
* -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
*
* Rewrote canonical mode and added more termios flags.
* -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
*/
#include <linux/types.h>
......@@ -98,7 +101,7 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
return 0;
}
void put_tty_queue(char c, struct tty_queue * queue)
void put_tty_queue(unsigned char c, struct tty_queue * queue)
{
int head;
unsigned long flags;
......@@ -121,8 +124,8 @@ int get_tty_queue(struct tty_queue * queue)
save_flags(flags);
cli();
if (queue->tail != queue->head) {
result = 0xff & queue->buf[queue->tail];
queue->tail = (queue->tail + 1) & (TTY_BUF_SIZE-1);
result = queue->buf[queue->tail];
INC(queue->tail);
}
restore_flags(flags);
return result;
......@@ -499,7 +502,220 @@ void wait_for_keypress(void)
sleep_on(&keypress_wait);
}
void copy_to_cooked(struct tty_struct * tty)
void stop_tty(struct tty_struct *tty)
{
if (tty->stopped)
return;
tty->stopped = 1;
if (tty->link && tty->link->packet) {
tty->ctrl_status &= ~TIOCPKT_START;
tty->ctrl_status |= TIOCPKT_STOP;
wake_up_interruptible(&tty->link->secondary.proc_list);
}
if (tty->stop)
(tty->stop)(tty);
if (IS_A_CONSOLE(tty->line)) {
set_vc_kbd_flag(kbd_table + fg_console, VC_SCROLLOCK);
set_leds();
}
}
void start_tty(struct tty_struct *tty)
{
if (!tty->stopped)
return;
tty->stopped = 0;
if (tty->link && tty->link->packet) {
tty->ctrl_status &= ~TIOCPKT_STOP;
tty->ctrl_status |= TIOCPKT_START;
wake_up_interruptible(&tty->link->secondary.proc_list);
}
if (tty->start)
(tty->start)(tty);
if (IS_A_CONSOLE(tty->line)) {
clr_vc_kbd_flag(kbd_table + fg_console, VC_SCROLLOCK);
set_leds();
}
TTY_WRITE_FLUSH(tty);
}
/* Perform OPOST processing. Returns -1 when the write_q becomes full
and the character must be retried. */
static int opost(unsigned char c, struct tty_struct *tty)
{
if (FULL(&tty->write_q))
return -1;
if (O_OPOST(tty)) {
switch (c) {
case '\n':
if (O_ONLRET(tty))
tty->column = 0;
if (O_ONLCR(tty)) {
if (LEFT(&tty->write_q) < 2)
return -1;
put_tty_queue('\r', &tty->write_q);
tty->column = 0;
}
tty->canon_column = tty->column;
break;
case '\r':
if (O_ONOCR(tty) && tty->column == 0)
return 0;
if (O_OCRNL(tty)) {
c = '\n';
if (O_ONLRET(tty))
tty->canon_column = tty->column = 0;
break;
}
tty->canon_column = tty->column = 0;
break;
case '\t':
if (O_TABDLY(tty) == XTABS) {
if (LEFT(&tty->write_q) < 8)
return -1;
do
put_tty_queue(' ', &tty->write_q);
while (++tty->column % 8);
return 0;
}
tty->column = (tty->column | 7) + 1;
break;
case '\b':
if (tty->column > 0)
tty->column--;
break;
default:
if (O_OLCUC(tty))
c = toupper(c);
if (!iscntrl(c))
tty->column++;
break;
}
}
put_tty_queue(c, &tty->write_q);
return 0;
}
/* Must be called only when L_ECHO(tty) is true. */
static void echo_char(unsigned char c, struct tty_struct *tty)
{
if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') {
opost('^', tty);
opost(c ^ 0100, tty);
} else
opost(c, tty);
}
static void eraser(unsigned char c, struct tty_struct *tty)
{
enum { ERASE, WERASE, KILL } kill_type;
int seen_alnums;
if (tty->secondary.head == tty->canon_head) {
/* opost('\a', tty); */ /* what do you think? */
return;
}
if (c == ERASE_CHAR(tty))
kill_type = ERASE;
else if (c == WERASE_CHAR(tty))
kill_type = WERASE;
else {
if (!L_ECHO(tty)) {
tty->secondary.head = tty->canon_head;
return;
}
if (!L_ECHOK(tty) || !L_ECHOKE(tty)) {
tty->secondary.head = tty->canon_head;
if (tty->erasing) {
opost('/', tty);
tty->erasing = 0;
}
echo_char(KILL_CHAR(tty), tty);
/* Add a newline if ECHOK is on and ECHOKE is off. */
if (L_ECHOK(tty))
opost('\n', tty);
return;
}
kill_type = KILL;
}
seen_alnums = 0;
while (tty->secondary.head != tty->canon_head) {
c = LAST(&tty->secondary);
if (kill_type == WERASE) {
/* Equivalent to BSD's ALTWERASE. */
if (isalnum(c) || c == '_')
seen_alnums++;
else if (seen_alnums)
break;
}
DEC(tty->secondary.head);
if (L_ECHO(tty)) {
if (L_ECHOPRT(tty)) {
if (!tty->erasing) {
opost('\\', tty);
tty->erasing = 1;
}
echo_char(c, tty);
} else if (!L_ECHOE(tty)) {
echo_char(ERASE_CHAR(tty), tty);
} else if (c == '\t') {
unsigned int col = tty->canon_column;
unsigned long tail = tty->canon_head;
/* Find the column of the last char. */
while (tail != tty->secondary.head) {
c = tty->secondary.buf[tail];
if (c == '\t')
col = (col | 7) + 1;
else if (iscntrl(c)) {
if (L_ECHOCTL(tty))
col += 2;
} else
col++;
INC(tail);
}
/* Now backup to that column. */
while (tty->column > col) {
/* Can't use opost here. */
put_tty_queue('\b', &tty->write_q);
tty->column--;
}
} else {
if (iscntrl(c) && L_ECHOCTL(tty)) {
opost('\b', tty);
opost(' ', tty);
opost('\b', tty);
}
if (!iscntrl(c) || L_ECHOCTL(tty)) {
opost('\b', tty);
opost(' ', tty);
opost('\b', tty);
}
}
}
if (kill_type == ERASE)
break;
}
if (tty->erasing && tty->secondary.head == tty->canon_head) {
opost('/', tty);
tty->erasing = 0;
}
}
static void isig(int sig, struct tty_struct *tty)
{
kill_pg(tty->pgrp, sig, 1);
if (!L_NOFLSH(tty)) {
flush_input(tty);
flush_output(tty);
}
}
static void copy_to_cooked(struct tty_struct * tty)
{
int c, special_flag;
unsigned long flags;
......@@ -525,19 +741,18 @@ void copy_to_cooked(struct tty_struct * tty)
if (c == 0)
break;
save_flags(flags); cli();
if (tty->read_q.tail != tty->read_q.head) {
c = 0xff & tty->read_q.buf[tty->read_q.tail];
if (!EMPTY(&tty->read_q)) {
c = tty->read_q.buf[tty->read_q.tail];
special_flag = clear_bit(tty->read_q.tail,
&tty->readq_flags);
tty->read_q.tail = (tty->read_q.tail + 1) &
(TTY_BUF_SIZE-1);
INC(tty->read_q.tail);
restore_flags(flags);
} else {
restore_flags(flags);
break;
}
if (special_flag) {
tty->char_error = c & 7;
tty->char_error = c;
continue;
}
if (tty->char_error) {
......@@ -545,6 +760,9 @@ void copy_to_cooked(struct tty_struct * tty)
tty->char_error = 0;
if (I_IGNBRK(tty))
continue;
/* A break is handled by the lower levels. */
if (I_BRKINT(tty))
continue;
if (I_PARMRK(tty)) {
put_tty_queue('\377', &tty->secondary);
put_tty_queue('\0', &tty->secondary);
......@@ -570,157 +788,131 @@ void copy_to_cooked(struct tty_struct * tty)
put_tty_queue('\0', &tty->secondary);
continue;
}
if (I_STRP(tty))
if (I_ISTRIP(tty))
c &= 0x7f;
else if (I_PARMRK(tty) && (c == '\377'))
put_tty_queue('\377', &tty->secondary);
if (c==13) {
if (I_CRNL(tty))
c=10;
else if (I_NOCR(tty))
if (!tty->lnext) {
if (c == '\r') {
if (I_IGNCR(tty))
continue;
} else if (c==10 && I_NLCR(tty))
c=13;
if (I_UCLC(tty))
if (I_ICRNL(tty))
c = '\n';
} else if (c == '\n' && I_INLCR(tty))
c = '\r';
}
if (I_IUCLC(tty) && L_IEXTEN(tty))
c=tolower(c);
if (c == __DISABLED_CHAR)
tty->lnext = 1;
if (L_CANON(tty) && !tty->lnext) {
if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || c == WERASE_CHAR(tty)) {
int seen_alnums =
(c == WERASE_CHAR(tty)) ? 0 : -1;
int cc;
/* deal with killing in the input line */
while(!(EMPTY(&tty->secondary) ||
(cc=LAST(&tty->secondary))==10 ||
((EOF_CHAR(tty) != __DISABLED_CHAR) &&
(cc==EOF_CHAR(tty))))) {
/* if killing just a word, kill all
non-alnum chars, then all alnum
chars. */
if (seen_alnums >= 0) {
if (isalnum(cc))
seen_alnums++;
else if (seen_alnums)
break;
if (L_ICANON(tty) && !tty->lnext) {
if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
(c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
eraser(c, tty);
continue;
}
if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
tty->lnext = 1;
if (L_ECHO(tty)) {
int ct = 1;
if (cc < 32)
ct = (L_ECHOCTL(tty) ? 2 : 0);
while(ct--) {
put_tty_queue('\b', &tty->write_q);
put_tty_queue(' ', &tty->write_q);
put_tty_queue('\b',&tty->write_q);
if (tty->erasing) {
opost('/', tty);
tty->erasing = 0;
}
if (L_ECHOCTL(tty)) {
opost('^', tty);
opost('\b', tty);
}
DEC(tty->secondary.head);
if(c == ERASE_CHAR(tty))
break;
}
continue;
}
if (c == LNEXT_CHAR(tty)) {
tty->lnext = 1;
if (L_ECHO(tty)) {
put_tty_queue('^',&tty->write_q);
put_tty_queue('\b',&tty->write_q);
if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
L_IEXTEN(tty)) {
unsigned long tail = tty->canon_head;
if (tty->erasing) {
opost('/', tty);
tty->erasing = 0;
}
echo_char(c, tty);
opost('\n', tty);
while (tail != tty->secondary.head) {
echo_char(tty->secondary.buf[tail],
tty);
INC(tail);
}
continue;
}
}
if (I_IXON(tty) && !tty->lnext) {
if (c == STOP_CHAR(tty)) {
tty->ctrl_status &= ~(TIOCPKT_START);
tty->ctrl_status |= TIOCPKT_STOP;
if (tty->link)
wake_up_interruptible(&tty->link->except_q);
tty->stopped=1;
if (tty->stop)
(tty->stop)(tty);
if (IS_A_CONSOLE(tty->line)) {
set_vc_kbd_flag(kbd_table + fg_console, VC_SCROLLOCK);
set_leds();
}
if ((tty->stopped && I_IXANY(tty) && L_IEXTEN(tty)) ||
c == START_CHAR(tty)) {
start_tty(tty);
continue;
}
if (((I_IXANY(tty)) && tty->stopped) ||
(c == START_CHAR(tty))) {
tty->ctrl_status &= ~(TIOCPKT_STOP);
tty->ctrl_status |= TIOCPKT_START;
tty->stopped=0;
if (tty->link)
wake_up_interruptible(&tty->link->except_q);
if (tty->start)
(tty->start)(tty);
if (IS_A_CONSOLE(tty->line)) {
clr_vc_kbd_flag(kbd_table + fg_console, VC_SCROLLOCK);
set_leds();
}
if (c == STOP_CHAR(tty)) {
stop_tty(tty);
continue;
}
}
if (L_ISIG(tty) && !tty->lnext) {
if (c == INTR_CHAR(tty)) {
kill_pg(tty->pgrp, SIGINT, 1);
if (! _L_FLAG(tty, NOFLSH)) {
flush_input(tty);
flush_output(tty);
}
isig(SIGINT, tty);
continue;
}
if (c == QUIT_CHAR(tty)) {
kill_pg(tty->pgrp, SIGQUIT, 1);
if (! _L_FLAG(tty, NOFLSH)) {
flush_input(tty);
flush_output(tty);
}
isig(SIGQUIT, tty);
continue;
}
if (c == SUSPEND_CHAR(tty)) {
if (!is_orphaned_pgrp(tty->pgrp)) {
kill_pg(tty->pgrp, SIGTSTP, 1);
if (! _L_FLAG(tty, NOFLSH)) {
flush_input(tty);
flush_output(tty);
}
}
if (c == SUSP_CHAR(tty)) {
if (!is_orphaned_pgrp(tty->pgrp))
isig(SIGTSTP, tty);
continue;
}
}
if (c==10 || (EOF_CHAR(tty) != __DISABLED_CHAR &&
c==EOF_CHAR(tty)))
tty->secondary.data++;
if ((c==10) && (L_ECHO(tty) || (L_CANON(tty) && L_ECHONL(tty)))) {
put_tty_queue('\n',&tty->write_q);
put_tty_queue('\r',&tty->write_q);
if (tty->erasing) {
opost('/', tty);
tty->erasing = 0;
}
if (c == '\n' && !tty->lnext) {
if (L_ECHO(tty) || (L_ICANON(tty) && L_ECHONL(tty)))
opost('\n', tty);
} else if (L_ECHO(tty)) {
if (c<32 && L_ECHOCTL(tty)) {
put_tty_queue('^',&tty->write_q);
put_tty_queue(c+'A'-1, &tty->write_q);
if (EOF_CHAR(tty) != __DISABLED_CHAR &&
c==EOF_CHAR(tty) && !tty->lnext) {
put_tty_queue('\b',&tty->write_q);
put_tty_queue('\b',&tty->write_q);
/* Don't echo the EOF char in canonical mode. Sun
handles this differently by echoing the char and
then backspacing, but that's a hack. */
if (c != EOF_CHAR(tty) || !L_ICANON(tty) ||
tty->lnext) {
/* Record the column of first canon char. */
if (tty->canon_head == tty->secondary.head)
tty->canon_column = tty->column;
echo_char(c, tty);
}
} else
put_tty_queue(c, &tty->write_q);
}
tty->lnext = 0;
if (I_PARMRK(tty) && c == (unsigned char) '\377' &&
(c != EOF_CHAR(tty) || !L_ICANON(tty) || tty->lnext))
put_tty_queue(c, &tty->secondary);
if (L_ICANON(tty) && !tty->lnext &&
(c == '\n' || c == EOF_CHAR(tty) || c == EOL_CHAR(tty) ||
(c == EOL2_CHAR(tty) && L_IEXTEN(tty)))) {
if (c == EOF_CHAR(tty))
c = __DISABLED_CHAR;
set_bit(tty->secondary.head, &tty->secondary_flags);
put_tty_queue(c, &tty->secondary);
tty->canon_head = tty->secondary.head;
tty->canon_data++;
} else
put_tty_queue(c, &tty->secondary);
tty->lnext = 0;
}
if (!EMPTY(&tty->write_q))
TTY_WRITE_FLUSH(tty);
if (!EMPTY(&tty->secondary))
if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary))
wake_up_interruptible(&tty->secondary.proc_list);
if (tty->write_q.proc_list && LEFT(&tty->write_q) > TTY_BUF_SIZE/2)
wake_up_interruptible(&tty->write_q.proc_list);
if (tty->throttle && (LEFT(&tty->read_q) >= RQ_THRESHOLD_HW)
&& clear_bit(TTY_RQ_THROTTLED, &tty->flags))
tty->throttle(tty, TTY_THROTTLE_RQ_AVAIL);
if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW)
&& clear_bit(TTY_SQ_THROTTLED, &tty->flags))
tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL);
}
int is_ignored(int sig)
......@@ -729,278 +921,205 @@ int is_ignored(int sig)
(current->sigaction[sig-1].sa_handler == SIG_IGN));
}
static int available_canon_input(struct tty_struct *);
static void __wait_for_canon_input(struct file * file, struct tty_struct *);
static void wait_for_canon_input(struct file * file, struct tty_struct * tty)
static inline int input_available_p(struct tty_struct *tty)
{
if (!available_canon_input(tty)) {
if (current->signal & ~current->blocked)
return;
__wait_for_canon_input(file, tty);
}
/* Avoid calling TTY_READ_FLUSH unnecessarily. */
if (L_ICANON(tty)) {
if (tty->canon_data || FULL(&tty->read_q))
return 1;
} else if (!EMPTY(&tty->secondary))
return 1;
/* Shuffle any pending data down the queues. */
TTY_READ_FLUSH(tty);
if (tty->link)
TTY_WRITE_FLUSH(tty->link);
if (L_ICANON(tty)) {
if (tty->canon_data || FULL(&tty->read_q))
return 1;
} else if (!EMPTY(&tty->secondary))
return 1;
return 0;
}
static int read_chan(struct tty_struct * tty, struct file * file, char * buf, int nr)
static int read_chan(struct tty_struct *tty, struct file *file,
unsigned char *buf, unsigned int nr)
{
struct wait_queue wait = { current, NULL };
int c;
char * b=buf;
int minimum,time;
unsigned char *b = buf;
int minimum, time;
int retval = 0;
if (L_CANON(tty))
minimum = time = current->timeout = 0;
else {
time = 10L*tty->termios->c_cc[VTIME];
minimum = tty->termios->c_cc[VMIN];
if (L_ICANON(tty)) {
minimum = time = 0;
current->timeout = (unsigned long) -1;
} else {
time = (HZ / 10) * TIME_CHAR(tty);
minimum = MIN_CHAR(tty);
if (minimum)
current->timeout = 0xffffffff;
current->timeout = (unsigned long) -1;
else {
if (time)
if (time) {
current->timeout = time + jiffies;
else
current->timeout = 0;
time = 0;
} else
current->timeout = 0;
minimum = 1;
}
}
if (file->f_flags & O_NONBLOCK) {
time = current->timeout = 0;
if (L_CANON(tty) && !available_canon_input(tty))
return -EAGAIN;
} else if (L_CANON(tty)) {
wait_for_canon_input(file, tty);
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
}
if (minimum>nr)
minimum = nr;
/* deal with packet mode: First test for status change */
if (tty->packet && tty->link && tty->link->ctrl_status) {
put_fs_byte (tty->link->ctrl_status, b);
tty->link->ctrl_status = 0;
return 1;
}
/* now bump the buffer up one. */
if (tty->packet) {
put_fs_byte (0,b++);
nr--;
/* this really shouldn't happen, but we need to
put it here. */
if (nr == 0)
return 1;
}
add_wait_queue(&tty->secondary.proc_list, &wait);
while (nr>0) {
if (tty_hung_up_p(file)) {
file->f_flags &= ~O_NONBLOCK;
break; /* force read() to return 0 */
}
TTY_READ_FLUSH(tty);
if (tty->link)
TTY_WRITE_FLUSH(tty->link);
while (nr > 0 && ((c = get_tty_queue(&tty->secondary)) >= 0)) {
if ((EOF_CHAR(tty) != __DISABLED_CHAR &&
c==EOF_CHAR(tty)) || c==10)
tty->secondary.data--;
if ((EOF_CHAR(tty) != __DISABLED_CHAR &&
c==EOF_CHAR(tty)) && L_CANON(tty))
break;
put_fs_byte(c,b++);
nr--;
if (time)
current->timeout = time+jiffies;
if (c==10 && L_CANON(tty))
break;
};
wake_up_interruptible(&tty->read_q.proc_list);
/*
* If there is enough space in the secondary queue
* now, let the low-level driver know.
*/
if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW)
&& clear_bit(TTY_SQ_THROTTLED, &tty->flags))
tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL);
if (tty->link) {
if (IS_A_PTY_MASTER(tty->line)) {
if ((tty->flags & (1 << TTY_SLAVE_OPENED))
&& tty->link->count <= 1) {
file->f_flags &= ~O_NONBLOCK;
while (1) {
/* Job control check -- must be done at start and after
every sleep (POSIX.1 7.1.1.4). */
/* don't stop on /dev/console */
if (file->f_inode->i_rdev != CONSOLE_DEV &&
current->tty == tty->line) {
if (tty->pgrp <= 0)
printk("read_chan: tty->pgrp <= 0!\n");
else if (current->pgrp != tty->pgrp) {
if (is_ignored(SIGTTIN) ||
is_orphaned_pgrp(current->pgrp)) {
retval = -EIO;
break;
}
} else if (!tty->link->count) {
file->f_flags &= ~O_NONBLOCK;
kill_pg(current->pgrp, SIGTTIN, 1);
retval = -ERESTARTSYS;
break;
}
}
if (b-buf >= minimum || !current->timeout)
/* First test for status change. */
if (tty->packet && tty->link->ctrl_status) {
if (b != buf)
break;
if (current->signal & ~current->blocked)
put_fs_byte(tty->link->ctrl_status, b++);
tty->link->ctrl_status = 0;
break;
TTY_READ_FLUSH(tty);
if (tty->link)
TTY_WRITE_FLUSH(tty->link);
if (!EMPTY(&tty->secondary))
continue;
current->state = TASK_INTERRUPTIBLE;
if (EMPTY(&tty->secondary))
schedule();
current->state = TASK_RUNNING;
}
remove_wait_queue(&tty->secondary.proc_list, &wait);
TTY_READ_FLUSH(tty);
if (tty->link && tty->link->write)
TTY_WRITE_FLUSH(tty->link);
current->timeout = 0;
/* packet mode sticks in an extra 0. If that's all we've got,
we should count it a zero bytes. */
if (tty->packet) {
if ((b-buf) > 1)
return b-buf;
} else {
if (b-buf)
return b-buf;
}
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
if (IS_A_PTY_MASTER(tty->line))
return -EIO;
return 0;
}
static void __wait_for_canon_input(struct file * file, struct tty_struct * tty)
{
struct wait_queue wait = { current, NULL };
add_wait_queue(&tty->secondary.proc_list, &wait);
while (1) {
/* This statement must be first before checking for input
so that any interrupt will set the state back to
TASK_RUNNING. */
current->state = TASK_INTERRUPTIBLE;
if (available_canon_input(tty))
break;
if (current->signal & ~current->blocked)
if (!input_available_p(tty)) {
if (tty->flags & (1 << TTY_SLAVE_CLOSED)) {
retval = -EIO;
break;
}
if (tty_hung_up_p(file))
break;
schedule();
}
current->state = TASK_RUNNING;
remove_wait_queue(&tty->secondary.proc_list, &wait);
}
static int available_canon_input(struct tty_struct * tty)
{
TTY_READ_FLUSH(tty);
if (tty->link)
if (tty->link->count)
TTY_WRITE_FLUSH(tty->link);
else
return 1;
if (FULL(&tty->read_q))
return 1;
if (tty->secondary.data)
return 1;
return 0;
}
static int write_chan(struct tty_struct * tty, struct file * file, char * buf, int nr)
{
struct wait_queue wait = { current, NULL };
char c, *b=buf;
if (nr < 0)
return -EINVAL;
if (!nr)
return 0;
add_wait_queue(&tty->write_q.proc_list, &wait);
while (nr>0) {
if (current->signal & ~current->blocked)
if (!current->timeout)
break;
if (tty_hung_up_p(file))
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
break;
if (tty->link && !tty->link->count) {
send_sig(SIGPIPE,current,0);
}
if (current->signal & ~current->blocked) {
retval = -ERESTARTSYS;
break;
}
current->state = TASK_INTERRUPTIBLE;
if (FULL(&tty->write_q)) {
TTY_WRITE_FLUSH(tty);
if (FULL(&tty->write_q))
schedule();
current->state = TASK_RUNNING;
continue;
}
current->state = TASK_RUNNING;
while (nr>0 && !FULL(&tty->write_q)) {
c=get_fs_byte(b);
if (O_POST(tty)) {
switch (c) {
case '\n':
if (O_NLRET(tty)) {
tty->column = 0;
/* Deal with packet mode. */
if (tty->packet && b == buf) {
put_fs_byte(TIOCPKT_DATA, b++);
nr--;
}
if (O_NLCR(tty)) {
if (!set_bit(TTY_CR_PENDING,&tty->flags)) {
c = '\r';
tty->column = 0;
b--; nr++;
} else {
clear_bit(TTY_CR_PENDING,&tty->flags);
while (nr > 0) {
int eol;
cli();
if (EMPTY(&tty->secondary)) {
sti();
break;
}
eol = clear_bit(tty->secondary.tail,
&tty->secondary_flags);
c = tty->secondary.buf[tty->secondary.tail];
INC(tty->secondary.tail);
sti();
if (eol) {
if (--tty->canon_data < 0) {
printk("read_chan: canon_data < 0!\n");
tty->canon_data = 0;
}
if (c == __DISABLED_CHAR)
break;
case '\r':
if (O_NOCR(tty) && tty->column == 0) {
b++; nr--;
continue;
}
if (O_CRNL(tty)) {
c = '\n';
if (O_NLRET(tty))
tty->column = 0;
put_fs_byte(c, b++);
nr--;
break;
}
tty->column = 0;
put_fs_byte(c, b++);
nr--;
}
/* If there is enough space in the secondary queue now, let the
low-level driver know. */
if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW)
&& !clear_bit(TTY_SQ_THROTTLED, &tty->flags))
tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL);
/* XXX packet mode's status byte is mistakenly counted */
if (b - buf >= minimum || !nr)
break;
case '\t':
if (O_TABDLY(tty) == XTABS) {
c = ' ';
tty->column++;
if (tty->column % 8 != 0) {
b--; nr++;
if (time)
current->timeout = time + jiffies;
}
remove_wait_queue(&tty->secondary.proc_list, &wait);
current->state = TASK_RUNNING;
current->timeout = 0;
return (b - buf) ? b - buf : retval;
}
static int write_chan(struct tty_struct * tty, struct file * file,
unsigned char * buf, unsigned int nr)
{
struct wait_queue wait = { current, NULL };
int c;
unsigned char *b = buf;
int retval = 0;
/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) {
retval = check_change(tty, tty->line);
if (retval)
return retval;
}
break;
case '\b':
tty->column--;
break;
default:
if (O_LCUC(tty))
c = toupper(c);
tty->column++;
add_wait_queue(&tty->write_q.proc_list, &wait);
while (1) {
current->state = TASK_INTERRUPTIBLE;
if (current->signal & ~current->blocked) {
retval = -ERESTARTSYS;
break;
}
if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
retval = -EIO;
break;
}
while (nr > 0) {
c = get_fs_byte(b);
/* Care is needed here: opost() can abort even
if the write_q is not full. */
if (opost(c, tty) < 0)
break;
b++; nr--;
put_tty_queue(c,&tty->write_q);
}
if (need_resched)
TTY_WRITE_FLUSH(tty);
if (!nr)
break;
if (EMPTY(&tty->write_q) && !need_resched)
continue;
schedule();
}
current->state = TASK_RUNNING;
remove_wait_queue(&tty->write_q.proc_list, &wait);
TTY_WRITE_FLUSH(tty);
if (b-buf)
return b-buf;
if (tty->link && !tty->link->count)
return -EPIPE;
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
return 0;
return (b - buf) ? b - buf : retval;
}
static int tty_read(struct inode * inode, struct file * file, char * buf, int count)
......@@ -1017,6 +1136,12 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co
tty = TTY_TABLE(dev);
if (!tty || (tty->flags & (1 << TTY_IO_ERROR)))
return -EIO;
/* This check not only needs to be done before reading, but also
whenever read_chan() gets woken up after sleeping, so I've
moved it to there. This should only be done for the N_TTY
line discipline, anyway. Same goes for write_chan(). -- jlc. */
#if 0
if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */
(tty->pgrp > 0) &&
(current->tty == dev) &&
......@@ -1027,8 +1152,10 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co
(void) kill_pg(current->pgrp, SIGTTIN, 1);
return -ERESTARTSYS;
}
#endif
if (ldiscs[tty->disc].read)
i = (ldiscs[tty->disc].read)(tty,file,buf,count);
/* XXX casts are for what kernel-wide prototypes should be. */
i = (ldiscs[tty->disc].read)(tty,file,(unsigned char *)buf,(unsigned int)count);
else
i = -EIO;
if (i > 0)
......@@ -1054,6 +1181,7 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c
tty = TTY_TABLE(dev);
if (!tty || !tty->write || (tty->flags & (1 << TTY_IO_ERROR)))
return -EIO;
#if 0
if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&
(current->tty == dev) && (tty->pgrp != current->pgrp)) {
if (is_orphaned_pgrp(current->pgrp))
......@@ -1063,8 +1191,10 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c
return -ERESTARTSYS;
}
}
#endif
if (ldiscs[tty->disc].write)
i = (ldiscs[tty->disc].write)(tty,file,buf,count);
/* XXX casts are for what kernel-wide prototypes should be. */
i = (ldiscs[tty->disc].write)(tty,file,(unsigned char *)buf,(unsigned int)count);
else
i = -EIO;
if (i > 0)
......@@ -1349,6 +1479,7 @@ static int tty_open(struct inode * inode, struct file * filp)
if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser())
return -EBUSY;
#if 0
/* clean up the packet stuff. */
/*
* Why is this not done in init_dev? Right here, if another
......@@ -1358,9 +1489,12 @@ static int tty_open(struct inode * inode, struct file * filp)
*
* Not to worry, a pty master can only be opened once.
* And rlogind and telnetd both use packet mode. -- jrs
*
* Not needed. These are cleared in initialize_tty_struct. -- jlc
*/
tty->ctrl_status = 0;
tty->packet = 0;
#endif
if (tty->open) {
retval = tty->open(tty, filp);
......@@ -1441,26 +1575,16 @@ static int normal_select(struct tty_struct * tty, struct inode * inode,
{
switch (sel_type) {
case SEL_IN:
if (L_CANON(tty)) {
if (available_canon_input(tty))
return 1;
} else if (!EMPTY(&tty->secondary))
if (input_available_p(tty))
return 1;
if (tty->link) {
if (IS_A_PTY_MASTER(tty->line)) {
if ((tty->flags & (1 << TTY_SLAVE_OPENED))
&& tty->link->count <= 1)
/* fall through */
case SEL_EX:
if (tty->packet && tty->link->ctrl_status)
return 1;
} else {
if (!tty->link->count)
if (tty->flags & (1 << TTY_SLAVE_CLOSED))
return 1;
}
}
/* see if the status byte can be read. */
if (tty->packet && tty->link && tty->link->ctrl_status)
if (tty_hung_up_p(file))
return 1;
select_wait(&tty->secondary.proc_list, wait);
return 0;
case SEL_OUT:
......@@ -1468,22 +1592,6 @@ static int normal_select(struct tty_struct * tty, struct inode * inode,
return 1;
select_wait(&tty->write_q.proc_list, wait);
return 0;
case SEL_EX:
if (tty->link) {
if (IS_A_PTY_MASTER(tty->line)) {
if ((tty->flags & (1 << TTY_SLAVE_OPENED))
&& tty->link->count <= 1)
return 1;
if (tty->packet
&& tty->link->ctrl_status)
return 1;
} else {
if (!tty->link->count)
return 1;
}
}
select_wait(&tty->except_q, wait);
return 0;
}
return 0;
}
......@@ -1645,8 +1753,6 @@ static void initialize_tty_struct(int line, struct tty_struct *tty)
tty->line = line;
tty->disc = N_TTY;
tty->pgrp = -1;
tty->winsize.ws_row = 0;
tty->winsize.ws_col = 0;
if (IS_A_CONSOLE(line)) {
tty->open = con_open;
tty->winsize.ws_row = video_num_lines;
......@@ -1656,31 +1762,26 @@ static void initialize_tty_struct(int line, struct tty_struct *tty)
} else if IS_A_PTY(line) {
tty->open = pty_open;
}
tty->except_q = NULL;
}
static void initialize_termios(int line, struct termios * tp)
{
memset(tp, 0, sizeof(struct termios));
memcpy(tp->c_cc, INIT_C_CC, NCCS);
if (IS_A_CONSOLE(line)) {
if (IS_A_CONSOLE(line) || IS_A_PTY_SLAVE(line)) {
tp->c_iflag = ICRNL | IXON;
tp->c_oflag = OPOST | ONLCR;
tp->c_cflag = B38400 | CS8 | CREAD;
tp->c_lflag = ISIG | ICANON | ECHO |
ECHOCTL | ECHOKE;
tp->c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
ECHOCTL | ECHOKE | IEXTEN;
} else if (IS_A_SERIAL(line)) {
tp->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tp->c_iflag = ICRNL | IXON;
tp->c_oflag = OPOST | ONLCR | XTABS;
} else if (IS_A_PTY_MASTER(line)) {
tp->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tp->c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
ECHOCTL | ECHOKE | IEXTEN;
} else if (IS_A_PTY_MASTER(line))
tp->c_cflag = B9600 | CS8 | CREAD;
} else if (IS_A_PTY_SLAVE(line)) {
tp->c_iflag = ICRNL | IXON;
tp->c_oflag = OPOST | ONLCR;
tp->c_cflag = B38400 | CS8 | CREAD;
tp->c_lflag = ISIG | ICANON | ECHO |
ECHOCTL | ECHOKE;
}
}
static struct tty_ldisc tty_ldisc_N_TTY = {
......
......@@ -17,6 +17,7 @@
#include <linux/major.h>
#include <linux/tty.h>
#include <linux/fcntl.h>
#include <linux/string.h>
#include <asm/io.h>
#include <asm/bitops.h>
......@@ -41,44 +42,43 @@ extern int paste_selection(struct tty_struct *tty);
static int tty_set_ldisc(struct tty_struct *tty, int ldisc);
static void flush(struct tty_queue * queue)
void flush_input(struct tty_struct * tty)
{
if (queue) {
cli();
queue->head = queue->tail;
tty->read_q.head = tty->read_q.tail = 0;
tty->secondary.head = tty->secondary.tail = 0;
tty->canon_head = tty->canon_data = tty->erasing = 0;
memset(&tty->readq_flags, 0, sizeof tty->readq_flags);
memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags);
sti();
wake_up_interruptible(&queue->proc_list);
}
}
void flush_input(struct tty_struct * tty)
{
if (!tty->link)
return;
/* No cli() since ptys don't use interrupts. */
tty->link->write_q.head = tty->link->write_q.tail = 0;
wake_up_interruptible(&tty->link->write_q.proc_list);
if (tty->link->packet) {
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
if (tty->link)
wake_up_interruptible(&tty->link->except_q);
flush(&tty->read_q);
wake_up_interruptible(&tty->read_q.proc_list);
flush(&tty->secondary);
tty->secondary.data = 0;
if ((tty = tty->link) != NULL) {
flush(&tty->write_q);
wake_up_interruptible(&tty->write_q.proc_list);
wake_up_interruptible(&tty->link->secondary.proc_list);
}
}
void flush_output(struct tty_struct * tty)
{
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
if (tty->link)
wake_up_interruptible(&tty->link->except_q);
flush(&tty->write_q);
cli();
tty->write_q.head = tty->write_q.tail = 0;
sti();
wake_up_interruptible(&tty->write_q.proc_list);
if ((tty = tty->link) != NULL) {
flush(&tty->read_q);
wake_up_interruptible(&tty->read_q.proc_list);
flush(&tty->secondary);
tty->secondary.data = 0;
if (!tty->link)
return;
/* No cli() since ptys don't use interrupts. */
tty->link->read_q.head = tty->link->read_q.tail = 0;
tty->link->secondary.head = tty->link->secondary.tail = 0;
tty->link->canon_head = tty->link->canon_data = tty->link->erasing = 0;
memset(&tty->link->readq_flags, 0, sizeof tty->readq_flags);
memset(&tty->link->secondary_flags, 0, sizeof tty->secondary_flags);
if (tty->link->packet) {
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
wake_up_interruptible(&tty->link->secondary.proc_list);
}
}
......@@ -156,65 +156,61 @@ static void unset_locked_termios(struct termios *termios,
old->c_cc[i] : termios->c_cc[i];
}
static int get_termios(struct tty_struct * tty, struct termios * termios)
{
int i;
i = verify_area(VERIFY_WRITE, termios, sizeof (*termios));
if (i)
return i;
for (i=0 ; i< (sizeof (*termios)) ; i++)
put_fs_byte( ((char *)tty->termios)[i] , i+(char *)termios );
return 0;
}
static int check_change(struct tty_struct * tty, int channel)
int check_change(struct tty_struct * tty, int channel)
{
/* If we try to set the state of terminal and we're not in the
foreground, send a SIGTTOU. If the signal is blocked or
ignored, go ahead and perform the operation. POSIX 7.2) */
if (current->tty != channel)
return 0;
if (tty->pgrp <= 0 || tty->pgrp == current->pgrp)
if (tty->pgrp <= 0) {
printk("check_change: tty->pgrp <= 0!\n");
return 0;
}
if (current->pgrp == tty->pgrp)
return 0;
if (is_orphaned_pgrp(current->pgrp))
return -EIO;
if (is_ignored(SIGTTOU))
return 0;
if (is_orphaned_pgrp(current->pgrp))
return -EIO;
(void) kill_pg(current->pgrp,SIGTTOU,1);
return -ERESTARTSYS;
}
static int set_termios(struct tty_struct * tty, struct termios * termios,
int channel)
static int set_termios_2(struct tty_struct * tty, struct termios * termios)
{
int i, old_flow, new_flow;
struct termios old_termios = *tty->termios;
int canon_change;
i = check_change(tty, channel);
if (i)
return i;
for (i=0 ; i< (sizeof (*termios)) ; i++)
((char *)tty->termios)[i]=get_fs_byte(i+(char *)termios);
canon_change = (old_termios.c_lflag ^ termios->c_lflag) & ICANON;
cli();
*tty->termios = *termios;
if (canon_change) {
memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags);
tty->canon_head = tty->secondary.tail;
tty->canon_data = 0;
tty->erasing = 0;
}
sti();
if (canon_change && !(tty->termios->c_lflag & ICANON) &&
!EMPTY(&tty->secondary))
/* Get characters left over from canonical mode. */
wake_up_interruptible(&tty->secondary.proc_list);
/* see if packet mode change of state */
old_flow = (old_termios.c_iflag & IXON) &&
(old_termios.c_cc[VSTOP] == '\023') &&
(old_termios.c_cc[VSTART] == '\021');
new_flow = (tty->termios->c_iflag & IXON) &&
(tty->termios->c_cc[VSTOP] == '\023') &&
(tty->termios->c_cc[VSTART] == '\021');
if (old_flow != new_flow) {
tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
if (new_flow)
/* The BSD man page pty.4 says that TIOCPKT_NOSTOP should be sent
if the new state differs from ^S/^Q, but that's a bad way of
detecting a new flow control scheme. Instead, a status byte
is only sent if IXON has changed. */
if (tty->link && tty->link->packet &&
(old_termios.c_iflag ^ tty->termios->c_iflag) & IXON) {
tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
if (tty->termios->c_iflag & IXON)
tty->ctrl_status |= TIOCPKT_DOSTOP;
else
tty->ctrl_status |= TIOCPKT_NOSTOP;
if (tty->link)
wake_up_interruptible(&tty->link->except_q);
wake_up_interruptible(&tty->link->secondary.proc_list);
}
#if 0
......@@ -241,12 +237,21 @@ static int set_termios(struct tty_struct * tty, struct termios * termios,
return 0;
}
static int set_termios(struct tty_struct * tty, struct termios * termios,
int channel)
{
struct termios tmp_termios;
memcpy_fromfs(&tmp_termios, termios, sizeof (struct termios));
return set_termios_2(tty, &tmp_termios);
}
static int get_termio(struct tty_struct * tty, struct termio * termio)
{
int i;
struct termio tmp_termio;
i = verify_area(VERIFY_WRITE, termio, sizeof (*termio));
i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
if (i)
return i;
tmp_termio.c_iflag = tty->termios->c_iflag;
......@@ -256,128 +261,41 @@ static int get_termio(struct tty_struct * tty, struct termio * termio)
tmp_termio.c_line = tty->termios->c_line;
for(i=0 ; i < NCC ; i++)
tmp_termio.c_cc[i] = tty->termios->c_cc[i];
for (i=0 ; i< (sizeof (*termio)) ; i++)
put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
return 0;
}
static int set_termio(struct tty_struct * tty, struct termio * termio,
int channel)
{
int i, old_flow, new_flow;
struct termio tmp_termio;
struct termios old_termios = *tty->termios;
struct termios tmp_termios;
#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
tmp_termios = *tty->termios;
memcpy_fromfs(&tmp_termio, termio, sizeof (struct termio));
i = check_change(tty, channel);
if (i)
return i;
memcpy_fromfs(&tmp_termio, termio, sizeof(*termio));
SET_LOW_BITS(tty->termios->c_iflag, tmp_termio.c_iflag);
SET_LOW_BITS(tty->termios->c_oflag, tmp_termio.c_oflag);
SET_LOW_BITS(tty->termios->c_cflag, tmp_termio.c_cflag);
SET_LOW_BITS(tty->termios->c_lflag, tmp_termio.c_lflag);
memcpy(tty->termios->c_cc, tmp_termio.c_cc, NCC);
/* see if packet mode change of state */
old_flow = (old_termios.c_iflag & IXON) &&
(old_termios.c_cc[VSTOP] == '\023') &&
(old_termios.c_cc[VSTART] == '\021');
new_flow = (tty->termios->c_iflag & IXON) &&
(tty->termios->c_cc[VSTOP] == '\023') &&
(tty->termios->c_cc[VSTART] == '\021');
if (old_flow != new_flow) {
tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
if (new_flow)
tty->ctrl_status |= TIOCPKT_DOSTOP;
else
tty->ctrl_status |= TIOCPKT_NOSTOP;
if (tty->link)
wake_up_interruptible(&tty->link->except_q);
}
unset_locked_termios(tty->termios, &old_termios,
termios_locked[tty->line]);
#if 0
retval = tty_set_ldisc(tty, tmp_termio.c_line);
if (retval)
return retval;
#endif
if (tty->set_termios)
(*tty->set_termios)(tty, &old_termios);
return 0;
}
static int get_lcktrmios(struct tty_struct * tty, struct termios * termios,
int channel)
{
int i;
i = verify_area(VERIFY_WRITE, termios, sizeof (*termios));
if (i)
return i;
for (i=0 ; i< (sizeof (*termios)) ; i++)
put_fs_byte( ((char *)termios_locked[channel])[i],
i+(char *)termios);
return 0;
}
#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
static int set_lcktrmios(struct tty_struct * tty, struct termios * termios,
int channel)
{
int i;
SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
if (!suser())
return -EPERM;
for (i=0 ; i< (sizeof (*termios)) ; i++)
((char *)termios_locked[channel])[i] =
get_fs_byte(i+(char *)termios);
#undef SET_LOW_BITS
return 0;
return set_termios_2(tty, &tmp_termios);
}
static int set_window_size(struct tty_struct * tty, struct winsize * ws)
{
int i,changed;
char c, * tmp;
struct winsize tmp_ws;
if (!ws)
return -EINVAL;
tmp = (char *) &tty->winsize;
changed = 0;
for (i = 0; i < sizeof (*ws) ; i++,tmp++) {
c = get_fs_byte(i + (char *) ws);
if (c == *tmp)
continue;
changed = 1;
*tmp = c;
}
if (changed)
memcpy_fromfs(&tmp_ws, ws, sizeof (struct winsize));
if (memcmp(&tmp_ws, &tty->winsize, sizeof (struct winsize)) &&
tty->pgrp > 0)
kill_pg(tty->pgrp, SIGWINCH, 1);
return 0;
}
static int get_window_size(struct tty_struct * tty, struct winsize * ws)
{
int i;
char * tmp;
if (!ws)
return -EINVAL;
i = verify_area(VERIFY_WRITE, ws, sizeof (*ws));
if (i)
return i;
tmp = (char *) ws;
for (i = 0; i < sizeof (struct winsize) ; i++,tmp++)
put_fs_byte(((char *) &tty->winsize)[i], tmp);
tty->winsize = tmp_ws;
return 0;
}
......@@ -406,20 +324,19 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
return 0;
}
static int inq_canon(struct tty_struct * tty)
static unsigned long inq_canon(struct tty_struct * tty)
{
int nr, head, tail;
if (!tty->secondary.data)
if (!tty->canon_data)
return 0;
head = tty->secondary.head;
head = tty->canon_head;
tail = tty->secondary.tail;
nr = (head - tail) & (TTY_BUF_SIZE-1);
/* Skip EOF-chars.. */
if (EOF_CHAR(tty) == __DISABLED_CHAR)
return nr;
while (head != tail) {
if (tty->secondary.buf[tail] == EOF_CHAR(tty))
if (test_bit(tail, &tty->secondary_flags) &&
tty->secondary.buf[tail] == __DISABLED_CHAR)
nr--;
INC(tail);
}
......@@ -432,7 +349,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
struct tty_struct * tty;
struct tty_struct * other_tty;
struct tty_struct * termios_tty;
int pgrp;
pid_t pgrp;
int dev;
int termios_dev;
int retval;
......@@ -449,68 +366,93 @@ int tty_ioctl(struct inode * inode, struct file * file,
other_tty = tty_table[PTY_OTHER(dev)];
else
other_tty = NULL;
termios_tty = tty;
termios_dev = dev;
if (IS_A_PTY_MASTER(dev)) {
termios_tty = other_tty;
termios_dev = PTY_OTHER(dev);
} else {
termios_tty = tty;
termios_dev = dev;
}
switch (cmd) {
case TCGETS:
return get_termios(termios_tty,(struct termios *) arg);
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (struct termios));
if (retval)
return retval;
memcpy_tofs((struct termios *) arg,
termios_tty->termios,
sizeof (struct termios));
return 0;
case TCSETSF:
flush_input(tty);
/* fallthrough */
case TCSETSW:
wait_until_sent(tty);
/* fallthrough */
case TCSETS:
return set_termios(termios_tty,(struct termios *) arg, termios_dev);
retval = check_change(termios_tty, termios_dev);
if (retval)
return retval;
if (cmd == TCSETSF || cmd == TCSETSW) {
if (cmd == TCSETSF)
flush_input(tty);
wait_until_sent(tty);
}
return set_termios(termios_tty, (struct termios *) arg,
termios_dev);
case TCGETA:
return get_termio(termios_tty,(struct termio *) arg);
case TCSETAF:
flush_input(tty);
/* fallthrough */
case TCSETAW:
wait_until_sent(tty); /* fallthrough */
case TCSETA:
return set_termio(termios_tty,(struct termio *) arg, termios_dev);
retval = check_change(termios_tty, termios_dev);
if (retval)
return retval;
if (cmd == TCSETAF || cmd == TCSETAW) {
if (cmd == TCSETAF)
flush_input(tty);
wait_until_sent(tty);
}
return set_termio(termios_tty, (struct termio *) arg,
termios_dev);
case TCXONC:
retval = check_change(tty, dev);
if (retval)
return retval;
switch (arg) {
case TCOOFF:
tty->stopped = 1;
if (tty->stop)
(tty->stop)(tty);
TTY_WRITE_FLUSH(tty);
return 0;
stop_tty(tty);
break;
case TCOON:
tty->stopped = 0;
if (tty->start)
(tty->start)(tty);
TTY_WRITE_FLUSH(tty);
return 0;
start_tty(tty);
break;
case TCIOFF:
if (STOP_CHAR(tty))
if (STOP_CHAR(tty) != __DISABLED_CHAR)
put_tty_queue(STOP_CHAR(tty),
&tty->write_q);
return 0;
break;
case TCION:
if (START_CHAR(tty))
if (START_CHAR(tty) != __DISABLED_CHAR)
put_tty_queue(START_CHAR(tty),
&tty->write_q);
return 0;
break;
default:
return -EINVAL;
}
return -EINVAL; /* not implemented */
return 0;
case TCFLSH:
if (arg==0)
retval = check_change(tty, dev);
if (retval)
return retval;
switch (arg) {
case TCIFLUSH:
flush_input(tty);
else if (arg==1)
flush_output(tty);
else if (arg==2) {
break;
case TCIOFLUSH:
flush_input(tty);
/* fall through */
case TCOFLUSH:
flush_output(tty);
} else
break;
default:
return -EINVAL;
}
return 0;
case TIOCEXCL:
set_bit(TTY_EXCLUSIVE, &tty->flags);
......@@ -550,16 +492,21 @@ int tty_ioctl(struct inode * inode, struct file * file,
tty->pgrp = current->pgrp;
return 0;
case TIOCGPGRP:
retval = verify_area(VERIFY_WRITE, (void *) arg,4);
if (!retval)
put_fs_long(termios_tty->pgrp,(unsigned long *) arg);
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (pid_t));
if (retval)
return retval;
put_fs_long(termios_tty->pgrp, (pid_t *) arg);
return 0;
case TIOCSPGRP:
retval = check_change(tty, dev);
if (retval)
return retval;
if ((current->tty < 0) ||
(current->tty != termios_dev) ||
(termios_tty->session != current->session))
return -ENOTTY;
pgrp=get_fs_long((unsigned long *) arg);
pgrp = get_fs_long((pid_t *) arg);
if (pgrp < 0)
return -EINVAL;
if (session_of_pgrp(pgrp) != current->session)
......@@ -567,16 +514,19 @@ int tty_ioctl(struct inode * inode, struct file * file,
termios_tty->pgrp = pgrp;
return 0;
case TIOCOUTQ:
retval = verify_area(VERIFY_WRITE, (void *) arg,4);
if (!retval)
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (unsigned long));
if (retval)
return retval;
put_fs_long(CHARS(&tty->write_q),
(unsigned long *) arg);
return retval;
return 0;
case TIOCINQ:
retval = verify_area(VERIFY_WRITE, (void *) arg,4);
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (unsigned long));
if (retval)
return retval;
if (L_CANON(tty))
if (L_ICANON(tty))
put_fs_long(inq_canon(tty),
(unsigned long *) arg);
else
......@@ -587,17 +537,20 @@ int tty_ioctl(struct inode * inode, struct file * file,
if ((current->tty != dev) && !suser())
return -EACCES;
put_tty_queue(get_fs_byte((char *) arg), &tty->read_q);
TTY_READ_FLUSH(tty);
return 0;
case TIOCGWINSZ:
return get_window_size(tty,(struct winsize *) arg);
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (struct winsize));
if (retval)
return retval;
memcpy_tofs((struct winsize *) arg, &tty->winsize,
sizeof (struct winsize));
return 0;
case TIOCSWINSZ:
if (IS_A_PTY_MASTER(dev))
set_window_size(other_tty,(struct winsize *) arg);
return set_window_size(tty,(struct winsize *) arg);
case TIOCGSOFTCAR:
return -EINVAL; /* not implemented */
case TIOCSSOFTCAR:
return -EINVAL; /* not implemented */
case TIOCLINUX:
switch (get_fs_byte((char *)arg))
{
......@@ -647,31 +600,55 @@ int tty_ioctl(struct inode * inode, struct file * file,
current->tty = -1;
return 0;
case TIOCGETD:
retval = verify_area(VERIFY_WRITE, (void *) arg,4);
if (!retval)
put_fs_long(tty->disc, (unsigned long *) arg);
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (unsigned long));
if (retval)
return retval;
put_fs_long(tty->disc, (unsigned long *) arg);
return 0;
case TIOCSETD:
retval = check_change(tty, dev);
if (retval)
return retval;
arg = get_fs_long((unsigned long *) arg);
return tty_set_ldisc(tty, arg);
case TIOCGLCKTRMIOS:
arg = get_fs_long((unsigned long *) arg);
return get_lcktrmios(tty, (struct termios *) arg,
termios_dev);
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (struct termios));
if (retval)
return retval;
memcpy_tofs((struct termios *) arg,
&termios_locked[termios_dev],
sizeof (struct termios));
return 0;
case TIOCSLCKTRMIOS:
if (!suser())
return -EPERM;
arg = get_fs_long((unsigned long *) arg);
return set_lcktrmios(tty, (struct termios *) arg,
termios_dev);
memcpy_fromfs(&termios_locked[termios_dev],
(struct termios *) arg,
sizeof (struct termios));
return 0;
case TIOCPKT:
if (!IS_A_PTY_MASTER(dev))
return -EINVAL;
retval = verify_area(VERIFY_READ,
(unsigned long *)arg, sizeof (unsigned long));
retval = verify_area(VERIFY_READ, (void *) arg,
sizeof (unsigned long));
if (retval)
return retval;
tty->packet = (get_fs_long ((unsigned long *)arg) != 0);
if (get_fs_long(arg)) {
if (!tty->packet) {
tty->packet = 1;
tty->ctrl_status = 0;
}
} else
tty->packet = 0;
return 0;
case TCSBRK: case TCSBRKP:
retval = check_change(tty, dev);
if (retval)
return retval;
wait_until_sent(tty);
if (!tty->ioctl)
return 0;
......
......@@ -36,7 +36,6 @@ static char *version =
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/string.h>
......
......@@ -563,8 +563,12 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev)
if (skb->free)
kfree_skb (skb, FREE_WRITE);
} else
{
/* Gimme!!! */
if(skb->free==0)
skb_kept_by_device(skb);
lp->tx_ring[entry].base = (int)(skb+1) | 0x83000000;
}
lp->cur_tx++;
/* Trigger an immediate send poll. */
......@@ -648,6 +652,9 @@ lance_interrupt(int reg_ptr)
struct sk_buff *skb = ((struct sk_buff *)databuff) - 1;
if (skb->free)
kfree_skb(skb, FREE_WRITE);
else
skb_device_release(skb,FREE_WRITE);
/* Warning: skb may well vanish at the point you call device_release! */
}
dirty_tx++;
}
......
......@@ -31,13 +31,11 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/socket.h>
#include <linux/termios.h>
#include <linux/sockios.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/tty.h>
#include <linux/in.h>
#include "inet.h"
#include "dev.h"
......
......@@ -262,6 +262,8 @@ asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
return -EPERM;
if (IS_RDONLY(inode))
return -EROFS;
if (mode == (mode_t) -1)
mode = inode->i_mode;
inode->i_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
if (!suser() && !in_group_p(inode->i_gid))
inode->i_mode &= ~S_ISGID;
......@@ -286,6 +288,8 @@ asmlinkage int sys_chmod(const char * filename, mode_t mode)
iput(inode);
return -EROFS;
}
if (mode == (mode_t) -1)
mode = inode->i_mode;
inode->i_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
if (!suser() && !in_group_p(inode->i_gid))
inode->i_mode &= ~S_ISGID;
......
......@@ -14,11 +14,6 @@
#define LONG_MAX ((long)(~0UL>>1))
#define ULONG_MAX (~0UL)
#define VERIFY_READ 0
#define VERIFY_WRITE 1
int verify_area(int type, void * addr, unsigned long count);
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
......
......@@ -2,9 +2,26 @@
#define _LINUX_MM_H
#include <linux/page.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#define VERIFY_READ 0
#define VERIFY_WRITE 1
int __verify_write(unsigned long addr, unsigned long count);
extern inline int verify_area(int type, void * addr, unsigned long size)
{
if (TASK_SIZE <= (unsigned long) addr)
return -EFAULT;
if (size > TASK_SIZE - (unsigned long) addr)
return -EFAULT;
if (wp_works_ok || type == VERIFY_READ || !size)
return 0;
return __verify_write((unsigned long) addr,size);
}
/*
* Linux kernel virtual memory manager primitives.
* The idea being to have a "virtual" mm in the same way
......
......@@ -13,6 +13,21 @@
#define HZ 100
/*
* System setup flags..
*/
extern int hard_math;
extern int x86;
extern int ignore_irq13;
extern int wp_works_ok;
/*
* Bus types (default is ISA, but people can check others with these..)
* MCA_bus hardcoded to 0 for now.
*/
extern int EISA_bus;
#define MCA_bus 0
#include <linux/tasks.h>
#include <asm/system.h>
......@@ -290,21 +305,6 @@ extern unsigned long volatile jiffies;
extern struct timeval xtime;
extern int need_resched;
/*
* System setup flags..
*/
extern int hard_math;
extern int x86;
extern int ignore_irq13;
extern int wp_works_ok;
/*
* Bus types (default is ISA, but people can check others with these..)
* MCA_bus hardcoded to 0 for now.
*/
extern int EISA_bus;
#define MCA_bus 0
#define CURRENT_TIME (xtime.tv_sec)
extern void sleep_on(struct wait_queue ** p);
......
......@@ -51,6 +51,7 @@
#define TIOCSLCKTRMIOS 0x5457
/* Used for packet mode */
#define TIOCPKT_DATA 0
#define TIOCPKT_FLUSHREAD 1
#define TIOCPKT_FLUSHWRITE 2
#define TIOCPKT_STOP 4
......
......@@ -62,7 +62,6 @@ extern struct screen_info screen_info;
#define TTY_BUF_SIZE 1024 /* Must be a power of 2 */
struct tty_queue {
unsigned long data;
unsigned long head;
unsigned long tail;
struct wait_queue * proc_list;
......@@ -143,60 +142,88 @@ struct serial_struct {
#define FULL(a) (!LEFT(a))
#define CHARS(a) (((a)->head-(a)->tail)&(TTY_BUF_SIZE-1))
extern void put_tty_queue(char c, struct tty_queue * queue);
extern void put_tty_queue(unsigned char c, struct tty_queue * queue);
extern int get_tty_queue(struct tty_queue * queue);
#define INTR_CHAR(tty) ((tty)->termios->c_cc[VINTR])
#define QUIT_CHAR(tty) ((tty)->termios->c_cc[VQUIT])
#define ERASE_CHAR(tty) ((tty)->termios->c_cc[VERASE])
#define KILL_CHAR(tty) ((tty)->termios->c_cc[VKILL])
#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE])
#define EOF_CHAR(tty) ((tty)->termios->c_cc[VEOF])
#define TIME_CHAR(tty) ((tty)->termios->c_cc[VTIME])
#define MIN_CHAR(tty) ((tty)->termios->c_cc[VMIN])
#define SWTC_CHAR(tty) ((tty)->termios->c_cc[VSWTC])
#define START_CHAR(tty) ((tty)->termios->c_cc[VSTART])
#define STOP_CHAR(tty) ((tty)->termios->c_cc[VSTOP])
#define SUSPEND_CHAR(tty) ((tty)->termios->c_cc[VSUSP])
#define SUSP_CHAR(tty) ((tty)->termios->c_cc[VSUSP])
#define EOL_CHAR(tty) ((tty)->termios->c_cc[VEOL])
#define REPRINT_CHAR(tty) ((tty)->termios->c_cc[VREPRINT])
#define DISCARD_CHAR(tty) ((tty)->termios->c_cc[VDISCARD])
#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE])
#define LNEXT_CHAR(tty) ((tty)->termios->c_cc[VLNEXT])
#define EOL2_CHAR(tty) ((tty)->termios->c_cc[VEOL2])
#define _L_FLAG(tty,f) ((tty)->termios->c_lflag & f)
#define _I_FLAG(tty,f) ((tty)->termios->c_iflag & f)
#define _O_FLAG(tty,f) ((tty)->termios->c_oflag & f)
#define _C_FLAG(tty,f) ((tty)->termios->c_cflag & f)
#define L_CANON(tty) _L_FLAG((tty),ICANON)
#define L_ISIG(tty) _L_FLAG((tty),ISIG)
#define L_ECHO(tty) _L_FLAG((tty),ECHO)
#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
#define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
#define _I_FLAG(tty,f) ((tty)->termios->c_iflag & (f))
#define _O_FLAG(tty,f) ((tty)->termios->c_oflag & (f))
#define _C_FLAG(tty,f) ((tty)->termios->c_cflag & (f))
#define _L_FLAG(tty,f) ((tty)->termios->c_lflag & (f))
#define I_IGNBRK(tty) _I_FLAG((tty),IGNBRK)
#define I_BRKINT(tty) _I_FLAG((tty),BRKINT)
#define I_IGNPAR(tty) _I_FLAG((tty),IGNPAR)
#define I_PARMRK(tty) _I_FLAG((tty),PARMRK)
#define I_INPCK(tty) _I_FLAG((tty),INPCK)
#define I_UCLC(tty) _I_FLAG((tty),IUCLC)
#define I_NLCR(tty) _I_FLAG((tty),INLCR)
#define I_CRNL(tty) _I_FLAG((tty),ICRNL)
#define I_NOCR(tty) _I_FLAG((tty),IGNCR)
#define I_ISTRIP(tty) _I_FLAG((tty),ISTRIP)
#define I_INLCR(tty) _I_FLAG((tty),INLCR)
#define I_IGNCR(tty) _I_FLAG((tty),IGNCR)
#define I_ICRNL(tty) _I_FLAG((tty),ICRNL)
#define I_IUCLC(tty) _I_FLAG((tty),IUCLC)
#define I_IXON(tty) _I_FLAG((tty),IXON)
#define I_IXANY(tty) _I_FLAG((tty),IXANY)
#define I_STRP(tty) _I_FLAG((tty),ISTRIP)
#define O_POST(tty) _O_FLAG((tty),OPOST)
#define O_LCUC(tty) _O_FLAG((tty),OLCUC)
#define O_NLCR(tty) _O_FLAG((tty),ONLCR)
#define O_CRNL(tty) _O_FLAG((tty),OCRNL)
#define O_NOCR(tty) _O_FLAG((tty),ONOCR)
#define O_NLRET(tty) _O_FLAG((tty),ONLRET)
#define I_IXOFF(tty) _I_FLAG((tty),IXOFF)
#define I_IMAXBEL(tty) _I_FLAG((tty),IMAXBEL)
#define O_OPOST(tty) _O_FLAG((tty),OPOST)
#define O_OLCUC(tty) _O_FLAG((tty),OLCUC)
#define O_ONLCR(tty) _O_FLAG((tty),ONLCR)
#define O_OCRNL(tty) _O_FLAG((tty),OCRNL)
#define O_ONOCR(tty) _O_FLAG((tty),ONOCR)
#define O_ONLRET(tty) _O_FLAG((tty),ONLRET)
#define O_OFILL(tty) _O_FLAG((tty),OFILL)
#define O_OFDEL(tty) _O_FLAG((tty),OFDEL)
#define O_NLDLY(tty) _O_FLAG((tty),NLDLY)
#define O_CRDLY(tty) _O_FLAG((tty),CRDLY)
#define O_TABDLY(tty) _O_FLAG((tty),TABDLY)
#define O_BSDLY(tty) _O_FLAG((tty),BSDLY)
#define O_VTDLY(tty) _O_FLAG((tty),VTDLY)
#define O_FFDLY(tty) _O_FLAG((tty),FFDLY)
#define C_BAUD(tty) _C_FLAG((tty),CBAUD)
#define C_CSIZE(tty) _C_FLAG((tty),CSIZE)
#define C_CSTOPB(tty) _C_FLAG((tty),CSTOPB)
#define C_CREAD(tty) _C_FLAG((tty),CREAD)
#define C_PARENB(tty) _C_FLAG((tty),PARENB)
#define C_PARODD(tty) _C_FLAG((tty),PARODD)
#define C_HUPCL(tty) _C_FLAG((tty),HUPCL)
#define C_CLOCAL(tty) _C_FLAG((tty),CLOCAL)
#define C_CIBAUD(tty) _C_FLAG((tty),CIBAUD)
#define C_CRTSCTS(tty) _C_FLAG((tty),CRTSCTS)
#define C_LOCAL(tty) _C_FLAG((tty),CLOCAL)
#define C_RTSCTS(tty) _C_FLAG((tty),CRTSCTS)
#define C_SPEED(tty) ((tty)->termios->c_cflag & CBAUD)
#define C_HUP(tty) (C_SPEED((tty)) == B0)
#define L_ISIG(tty) _L_FLAG((tty),ISIG)
#define L_ICANON(tty) _L_FLAG((tty),ICANON)
#define L_XCASE(tty) _L_FLAG((tty),XCASE)
#define L_ECHO(tty) _L_FLAG((tty),ECHO)
#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
#define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
#define L_NOFLSH(tty) _L_FLAG((tty),NOFLSH)
#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
#define L_ECHOPRT(tty) _L_FLAG((tty),ECHOPRT)
#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
#define L_FLUSHO(tty) _L_FLAG((tty),FLUSHO)
#define L_PENDIN(tty) _L_FLAG((tty),PENDIN)
#define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN)
/*
* Where all of the state associated with a tty is kept while the tty
......@@ -218,12 +245,13 @@ struct tty_struct {
int session;
unsigned char stopped:1, hw_stopped:1, packet:1, lnext:1;
unsigned char char_error:3;
unsigned char erasing:1;
unsigned char ctrl_status;
short line;
int disc;
int flags;
int count;
int column;
unsigned int column;
struct winsize winsize;
int (*open)(struct tty_struct * tty, struct file * filp);
void (*close)(struct tty_struct * tty, struct file * filp);
......@@ -241,10 +269,13 @@ struct tty_struct {
void (*write_data_callback)(void * data);
void * write_data_arg;
int readq_flags[TTY_BUF_SIZE/32];
int secondary_flags[TTY_BUF_SIZE/32];
int canon_data;
unsigned long canon_head;
unsigned int canon_column;
struct tty_queue read_q;
struct tty_queue write_q;
struct tty_queue secondary;
struct wait_queue * except_q;
void *disc_data;
};
......@@ -256,9 +287,9 @@ struct tty_ldisc {
int (*open)(struct tty_struct *);
void (*close)(struct tty_struct *);
int (*read)(struct tty_struct * tty, struct file * file,
char * buf, int nr);
unsigned char * buf, unsigned int nr);
int (*write)(struct tty_struct * tty, struct file * file,
char * buf, int nr);
unsigned char * buf, unsigned int nr);
int (*ioctl)(struct tty_struct * tty, struct file * file,
unsigned int cmd, unsigned long arg);
int (*select)(struct tty_struct * tty, struct inode * inode,
......@@ -313,12 +344,11 @@ struct tty_ldisc {
*/
#define TTY_WRITE_BUSY 0
#define TTY_READ_BUSY 1
#define TTY_CR_PENDING 2
#define TTY_SQ_THROTTLED 3
#define TTY_RQ_THROTTLED 4
#define TTY_IO_ERROR 5
#define TTY_SLAVE_OPENED 6
#define TTY_EXCLUSIVE 7
#define TTY_SQ_THROTTLED 2
#define TTY_RQ_THROTTLED 3
#define TTY_IO_ERROR 4
#define TTY_SLAVE_CLOSED 5
#define TTY_EXCLUSIVE 6
/*
* When a break, frame error, or parity error happens, these codes are
......@@ -336,6 +366,10 @@ struct tty_ldisc {
extern void tty_write_flush(struct tty_struct *);
extern void tty_read_flush(struct tty_struct *);
/* Number of chars that must be available in a write queue before
the queue is awakened. */
#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
extern struct tty_struct *tty_table[];
extern struct termios *tty_termios[];
extern struct termios *termios_locked[];
......@@ -366,7 +400,9 @@ extern long tty_init(long);
extern void flush_input(struct tty_struct * tty);
extern void flush_output(struct tty_struct * tty);
extern void wait_until_sent(struct tty_struct * tty);
extern void copy_to_cooked(struct tty_struct * tty);
extern int check_change(struct tty_struct * tty, int channel);
extern void stop_tty(struct tty_struct * tty);
extern void start_tty(struct tty_struct * tty);
extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
int buflen);
......
......@@ -56,7 +56,8 @@ static int find_empty_process(void)
}
if (task[i]->uid == current->uid)
this_user_tasks++;
if (task[i]->pid == last_pid || task[i]->pgrp == last_pid)
if (task[i]->pid == last_pid || task[i]->pgrp == last_pid ||
task[i]->session == last_pid)
goto repeat;
}
if (tasks_free <= MIN_TASKS_LEFT_FOR_ROOT ||
......
......@@ -9,7 +9,7 @@
_register_chrdev
_unregister_chrdev
_verify_area
___verify_write
_wake_up_interruptible
_current
......
......@@ -7,7 +7,6 @@
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/kernel.h>
#include <linux/times.h>
#include <linux/utsname.h>
......@@ -510,7 +509,7 @@ asmlinkage int sys_getpgrp(void)
asmlinkage int sys_setsid(void)
{
if (current->leader && !suser())
if (current->leader)
return -EPERM;
current->leader = 1;
current->session = current->pgrp = current->pid;
......
......@@ -651,17 +651,8 @@ void do_wp_page(unsigned long error_code, unsigned long address,
*pg_table = 0;
}
int verify_area(int type, void * addr, unsigned long size)
int __verify_write(unsigned long start, unsigned long size)
{
unsigned long start;
start = (unsigned long) addr;
if (start >= TASK_SIZE)
return -EFAULT;
if (size > TASK_SIZE - start)
return -EFAULT;
if (wp_works_ok || type == VERIFY_READ || !size)
return 0;
size--;
size += start & ~PAGE_MASK;
size >>= PAGE_SHIFT;
......
......@@ -1464,7 +1464,8 @@ ip_retransmit(struct sock *sk, int all)
/* If the interface is (still) up and running, kick it. */
if (dev->flags & IFF_UP) {
if (sk) dev->queue_xmit(skb, dev, sk->priority);
if (sk && !skb_device_locked(skb))
dev->queue_xmit(skb, dev, sk->priority);
/* else dev->queue_xmit(skb, dev, SOPRI_NORMAL ); CANNOT HAVE SK=NULL HERE */
}
......
......@@ -381,6 +381,12 @@ void kfree_skb(struct sk_buff *skb, int rw)
return;
}
IS_SKB(skb);
if(skb->lock)
{
skb->free=1; /* Free when unlocked */
return;
}
if(skb->free == 2)
printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n");
if(skb->list)
......@@ -424,6 +430,7 @@ void kfree_skb(struct sk_buff *skb, int rw)
return NULL;
skb->free= 2; /* Invalid so we pick up forgetful users */
skb->list= 0; /* Not on a list */
skb->lock= 0;
skb->truesize=size;
skb->mem_len=size;
skb->mem_addr=skb;
......@@ -452,3 +459,31 @@ void kfree_skbmem(void *mem,unsigned size)
}
}
/*
* Skbuff device locking
*/
void skb_kept_by_device(struct sk_buff *skb)
{
skb->lock++;
}
void skb_device_release(struct sk_buff *skb, int mode)
{
unsigned long flags;
save_flags(flags);
skb->lock--;
if(skb->lock==0)
{
if(skb->free==1)
kfree_skb(skb,mode);
}
restore_flags(flags);
}
int skb_device_locked(struct sk_buff *skb)
{
if(skb->lock)
return 1;
return 0;
}
......@@ -99,7 +99,9 @@ extern struct sk_buff * skb_peek(struct sk_buff * volatile *list);
extern struct sk_buff * skb_peek_copy(struct sk_buff * volatile *list);
extern struct sk_buff * alloc_skb(unsigned int size, int priority);
extern void kfree_skbmem(void *mem, unsigned size);
extern void skb_kept_by_device(struct sk_buff *skb);
extern void skb_device_release(struct sk_buff *skb, int mode);
extern int skb_device_locked(struct sk_buff *skb);
extern void skb_check(struct sk_buff *skb,int, char *);
#define IS_SKB(skb) skb_check((skb),__LINE__,__FILE__)
......
......@@ -583,8 +583,7 @@ tcp_check(struct tcphdr *th, int len,
}
void
tcp_send_check(struct tcphdr *th, unsigned long saddr,
void tcp_send_check(struct tcphdr *th, unsigned long saddr,
unsigned long daddr, int len, struct sock *sk)
{
th->check = 0;
......@@ -592,55 +591,33 @@ tcp_send_check(struct tcphdr *th, unsigned long saddr,
return;
}
static struct sk_buff * dequeue_partial(struct sock * sk)
{
struct sk_buff * skb;
unsigned long flags;
save_flags(flags);
cli();
skb = sk->send_tmp;
if (skb) {
sk->send_tmp = skb->next;
skb->next = NULL;
}
restore_flags(flags);
return skb;
}
static void enqueue_partial(struct sk_buff * skb, struct sock * sk)
static void tcp_send_skb(struct sock *sk, struct sk_buff *skb)
{
unsigned long flags;
int size;
save_flags(flags);
cli();
skb->next = sk->send_tmp;
sk->send_tmp = skb;
restore_flags(flags);
}
/* length of packet (not counting length of pre-tcp headers) */
size = skb->len - ((unsigned char *) skb->h.th - skb->data);
static void tcp_send_partial(struct sock *sk)
{
struct sk_buff *skb;
if (sk == NULL)
/* sanity check it.. */
if (size < sizeof(struct tcphdr) || size > skb->len) {
printk("tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %lu)\n",
skb, skb->data, skb->h.th, skb->len);
kfree_skb(skb, FREE_WRITE);
return;
while ((skb = dequeue_partial(sk)) != NULL) {
}
/* If we have queued a header size packet.. */
if(skb->len-(unsigned long)skb->h.th + (unsigned long)skb->data == sizeof(struct tcphdr)) {
if (size == sizeof(struct tcphdr)) {
/* If its got a syn or fin its notionally included in the size..*/
if(!skb->h.th->syn && !skb->h.th->fin) {
printk("tcp_send_partial: attempt to queue a bogon.\n");
printk("tcp_send_skb: attempt to queue a bogon.\n");
kfree_skb(skb,FREE_WRITE);
return;
}
}
/* We need to complete and send the packet. */
tcp_send_check(skb->h.th, sk->saddr, sk->daddr,
skb->len-(unsigned long)skb->h.th +
(unsigned long)skb->data, sk);
tcp_send_check(skb->h.th, sk->saddr, sk->daddr, size, sk);
skb->h.seq = sk->send_seq;
if (after(sk->send_seq , sk->window_seq) ||
......@@ -664,9 +641,49 @@ static void tcp_send_partial(struct sock *sk)
reset_timer(sk, TIME_PROBE0,
backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
} else {
sk->prot->queue_xmit(sk, skb->dev, skb,0);
sk->prot->queue_xmit(sk, skb->dev, skb, 0);
}
}
static struct sk_buff * dequeue_partial(struct sock * sk)
{
struct sk_buff * skb;
unsigned long flags;
save_flags(flags);
cli();
skb = sk->send_tmp;
if (skb) {
sk->send_tmp = skb->next;
skb->next = NULL;
}
restore_flags(flags);
return skb;
}
static void enqueue_partial(struct sk_buff * skb, struct sock * sk)
{
struct sk_buff * tmp;
unsigned long flags;
skb->next = NULL;
save_flags(flags);
cli();
tmp = sk->send_tmp;
sk->send_tmp = skb;
restore_flags(flags);
if (tmp)
tcp_send_skb(sk, tmp);
}
static void tcp_send_partial(struct sock *sk)
{
struct sk_buff *skb;
if (sk == NULL)
return;
while ((skb = dequeue_partial(sk)) != NULL)
tcp_send_skb(sk, skb);
}
......@@ -901,6 +918,7 @@ tcp_write(struct sock *sk, unsigned char *from,
continue;
}
#if 0
/*
* We also need to worry about the window.
* If window < 1/4 offered window, don't use it. That's
......@@ -915,6 +933,10 @@ tcp_write(struct sock *sk, unsigned char *from,
copy = sk->mtu;
copy = min(copy, sk->mtu);
copy = min(copy, len);
#else
/* This also prevents silly windows by simply ignoring the offered window.. */
copy = min(sk->mtu, len);
#endif
/* We should really check the window here also. */
if (sk->packets_out && copy < sk->mtu && !(flags & MSG_OOB)) {
......@@ -1011,34 +1033,7 @@ tcp_write(struct sock *sk, unsigned char *from,
enqueue_partial(send_tmp, sk);
continue;
}
tcp_send_check((struct tcphdr *)buff, sk->saddr, sk->daddr,
copy + sizeof(struct tcphdr), sk);
skb->h.seq = sk->send_seq;
if (after(sk->send_seq , sk->window_seq) ||
(sk->retransmits && sk->timeout == TIME_WRITE) ||
sk->packets_out >= sk->cong_window) {
DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n",
sk->cong_window, sk->packets_out));
DPRINTF((DBG_TCP, "sk->send_seq = %d, sk->window_seq = %d\n",
sk->send_seq, sk->window_seq));
skb->next = NULL;
skb->magic = TCP_WRITE_QUEUE_MAGIC;
if (sk->wback == NULL) {
sk->wfront = skb;
} else {
sk->wback->next = skb;
}
sk->wback = skb;
if (before(sk->window_seq, sk->wfront->h.seq) &&
sk->send_head == NULL &&
sk->ack_backlog == 0)
reset_timer(sk, TIME_PROBE0,
backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
} else {
prot->queue_xmit(sk, dev, skb,0);
}
tcp_send_skb(sk, skb);
}
sk->err = 0;
......@@ -3604,7 +3599,7 @@ tcp_send_probe0(struct sock *sk)
len = hlen + sizeof(struct tcphdr) + (data ? 1 : 0);
/* Allocate buffer. */
if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len,GFP_KERNEL)) == NULL) {
if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len, GFP_ATOMIC)) == NULL) {
/* printk("alloc failed raw %x th %x hlen %d data %d len %d\n",
raw, skb->h.th, hlen, data, len); */
reset_timer (sk, TIME_PROBE0, 10); /* try again real soon */
......
......@@ -28,7 +28,6 @@
#include <linux/stat.h>
#include <linux/socket.h>
#include <linux/fcntl.h>
#include <linux/termios.h>
#include <linux/net.h>
#include <linux/ddi.h>
......
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