Commit d667c3cc authored by Linus Torvalds's avatar Linus Torvalds

Re: Too much uneaten serial causes system hang?

In article <arumble.709312764@extro.ucc.su.OZ.AU> arumble@extro.ucc.su.OZ.AU
(Anthony Rumble) writes:
>
>YES! I have noticed this VERY exact thing also!

Oh, well: it's a bug in the serial drivers that I have already fixed,
but I haven't done the c-diffs yet. I have rewritten big parts of the
serial line code to be more easily configured for different IRQ numbers,
and I noticed the bug while doing that. I'll make patch1 for 0.96b
available later today or tomorrow.

patch1 will be mostly just the serial driver code: it allows changing
the irq's (and port addresses) of serial devices on the fly (with an
ioctl call), so people that have ser4 on irq5 etc shouldn't have to
recompile the kernel. It also returns EBUSY if you try to open a serial
line that shares the irq-line with another line etc.

Another change in patch1 will the the handling of ctrl-alt-del: it will
send a SIGINT to the init process if the reset-function is disabled.
This makes it ideal for a controlled shutdown, but it does need a
/bin/init that knows about this.

            Linus

PS. It seems both the DOS-fs and the extended fs will be out for
alpha-testing next week, so I assume 0.97 will have them both if things
work out ok.
parent 0b098c16
......@@ -34,6 +34,23 @@ struct tty_queue {
unsigned char buf[TTY_BUF_SIZE];
};
struct serial_struct {
unsigned short type;
unsigned short line;
unsigned short port;
unsigned short irq;
struct tty_struct * tty;
};
/*
* These are the supported serial types.
*/
#define PORT_UNKNOWN 0
#define PORT_8250 1
#define PORT_16450 2
#define PORT_16550 3
#define PORT_16550A 4
#define IS_A_CONSOLE(min) (((min) & 0xC0) == 0x00)
#define IS_A_SERIAL(min) (((min) & 0xC0) == 0x40)
#define IS_A_PTY(min) ((min) & 0x80)
......@@ -161,6 +178,7 @@ do { \
} while (0)
extern struct tty_struct tty_table[];
extern struct serial_struct serial_table[];
extern struct tty_struct * redirect;
extern int fg_console;
extern unsigned long video_num_columns;
......@@ -195,7 +213,10 @@ extern void con_write(struct tty_struct * tty);
extern void mpty_write(struct tty_struct * tty);
extern void spty_write(struct tty_struct * tty);
extern void serial_open(unsigned int line);
extern int serial_open(unsigned int line, struct file * filp);
extern void serial_close(unsigned int line, struct file * filp);
extern int get_serial_info(unsigned int, struct serial_struct *);
extern int set_serial_info(unsigned int, struct serial_struct *);
void copy_to_cooked(struct tty_struct * tty);
......
......@@ -35,6 +35,8 @@
#define TIOCINQ FIONREAD
#define TIOCLINUX 0x541C
#define TIOCCONS 0x541D
#define TIOCGSERIAL 0x541E
#define TIOCSSERIAL 0x541F
struct winsize {
unsigned short ws_row;
......
This diff is collapsed.
......@@ -485,14 +485,13 @@ static int tty_open(struct inode * inode, struct file * filp)
tty->pgrp = current->pgrp;
}
if (IS_A_SERIAL(dev))
serial_open(dev-64);
return serial_open(dev-64,filp);
return 0;
}
static void tty_release(struct inode * inode, struct file * filp)
{
int dev;
unsigned short port;
struct tty_struct * tty, * slave;
dev = inode->i_rdev;
......@@ -507,9 +506,9 @@ static void tty_release(struct inode * inode, struct file * filp)
return;
if (tty == redirect)
redirect = NULL;
if (port = tty->read_q->data)
outb(0x0c,port+4); /* reset DTR, RTS, */
if (IS_A_PTY_MASTER(dev)) {
if (IS_A_SERIAL(dev))
serial_close(dev-64,filp);
else if (IS_A_PTY_MASTER(dev)) {
slave = tty_table + PTY_OTHER(dev);
if (slave->pgrp > 0)
kill_pg(slave->pgrp,SIGHUP,1);
......@@ -550,14 +549,6 @@ long tty_init(long kmem_start)
chrdev_fops[5] = &tty_fops;
for (i=0 ; i < QUEUES ; i++)
tty_queues[i] = (struct tty_queue) {0,0,0,0,""};
rs_queues[0] = (struct tty_queue) {0x3f8,0,0,0,""};
rs_queues[1] = (struct tty_queue) {0x3f8,0,0,0,""};
rs_queues[3] = (struct tty_queue) {0x2f8,0,0,0,""};
rs_queues[4] = (struct tty_queue) {0x2f8,0,0,0,""};
rs_queues[6] = (struct tty_queue) {0x3e8,0,0,0,""};
rs_queues[7] = (struct tty_queue) {0x3e8,0,0,0,""};
rs_queues[9] = (struct tty_queue) {0x2e8,0,0,0,""};
rs_queues[10] = (struct tty_queue) {0x2e8,0,0,0,""};
for (i=0 ; i<256 ; i++) {
tty_table[i] = (struct tty_struct) {
{0, 0, 0, 0, 0, INIT_C_CC},
......
......@@ -27,13 +27,13 @@ static unsigned short quotient[] = {
64, 48, 24, 12, 6, 3
};
static void change_speed(struct tty_struct * tty)
static void change_speed(struct serial_struct * info)
{
unsigned short port,quot;
if (!(port = tty->read_q->data))
if (!(port = info->port))
return;
quot = quotient[tty->termios.c_cflag & CBAUD];
quot = quotient[info->tty->termios.c_cflag & CBAUD];
cli();
outb_p(0x80,port+3); /* set DLAB */
outb_p(quot & 0xff,port); /* LS of divisor */
......@@ -75,11 +75,11 @@ static void wait_until_sent(struct tty_struct * tty)
sti();
}
static void send_break(struct tty_struct * tty)
static void send_break(struct serial_struct * info)
{
unsigned short port;
if (!(port = tty->read_q->data))
if (!(port = info->port))
return;
port += 3;
current->state = TASK_INTERRUPTIBLE;
......@@ -144,7 +144,8 @@ static int set_termios(struct tty_struct * tty, struct termios * termios,
}
for (i=0 ; i< (sizeof (*termios)) ; i++)
((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
change_speed(tty);
if (IS_A_SERIAL(channel))
change_speed(serial_table+channel-64);
return 0;
}
......@@ -192,7 +193,8 @@ static int set_termio(struct tty_struct * tty, struct termio * termio,
tty->termios.c_line = tmp_termio.c_line;
for(i=0 ; i < NCC ; i++)
tty->termios.c_cc[i] = tmp_termio.c_cc[i];
change_speed(tty);
if (IS_A_SERIAL(channel))
change_speed(serial_table+channel-64);
return 0;
}
......@@ -279,9 +281,11 @@ int tty_ioctl(struct inode * inode, struct file * file,
case TCSETA:
return set_termio(tty,(struct termio *) arg, dev);
case TCSBRK:
if (!IS_A_SERIAL(dev))
return -EINVAL;
wait_until_sent(tty);
if (!arg)
send_break(tty);
send_break(serial_table+dev-64);
return 0;
case TCXONC:
switch (arg) {
......@@ -394,6 +398,15 @@ int tty_ioctl(struct inode * inode, struct file * file,
else
redirect = tty;
return 0;
case TIOCGSERIAL:
if (!IS_A_SERIAL(dev))
return -EINVAL;
verify_area((void *) arg,sizeof(struct serial_struct));
return get_serial_info(dev-64,(struct serial_struct *) arg);
case TIOCSSERIAL:
if (!IS_A_SERIAL(dev))
return -EINVAL;
return set_serial_info(dev-64,(struct serial_struct *) arg);
default:
return vt_ioctl(tty, dev, cmd, arg);
}
......
......@@ -284,7 +284,10 @@ static void forget_original_parent(struct task_struct * father)
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p && (*p)->p_opptr == father)
(*p)->p_opptr = task[1];
if (task[1])
(*p)->p_opptr = task[1];
else
(*p)->p_opptr = task[0];
}
volatile void do_exit(long code)
......@@ -342,7 +345,10 @@ volatile void do_exit(long code)
current->p_cptr = p->p_osptr;
p->p_ysptr = NULL;
p->flags &= ~PF_PTRACED;
p->p_pptr = task[1];
if (task[1])
p->p_pptr = task[1];
else
p->p_pptr = task[0];
p->p_osptr = p->p_pptr->p_cptr;
p->p_osptr->p_ysptr = p;
p->p_pptr->p_cptr = p;
......
......@@ -84,7 +84,7 @@ char * ea(struct info * info, unsigned short code)
EIP += 4;
break;
case 3:
math_abort(info,1<<(SIGILL-1));
math_abort(info,SIGILL);
}
I387.foo = offset;
I387.fos = 0x17;
......
......@@ -79,7 +79,7 @@ static void do_emu(struct info * info)
return;
case 0x1d1: case 0x1d2: case 0x1d3:
case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
math_abort(info,1<<(SIGILL-1));
math_abort(info,SIGILL);
case 0x1e0:
ST(0).exponent ^= 0x8000;
return;
......@@ -87,15 +87,15 @@ static void do_emu(struct info * info)
ST(0).exponent &= 0x7fff;
return;
case 0x1e2: case 0x1e3:
math_abort(info,1<<(SIGILL-1));
math_abort(info,SIGILL);
case 0x1e4:
ftst(PST(0));
return;
case 0x1e5:
printk("fxam not implemented\n\r");
math_abort(info,1<<(SIGILL-1));
math_abort(info,SIGILL);
case 0x1e6: case 0x1e7:
math_abort(info,1<<(SIGILL-1));
math_abort(info,SIGILL);
case 0x1e8:
fpush();
ST(0) = CONST1;
......@@ -125,7 +125,7 @@ static void do_emu(struct info * info)
ST(0) = CONSTZ;
return;
case 0x1ef:
math_abort(info,1<<(SIGILL-1));
math_abort(info,SIGILL);
case 0x1fa:
fsqrt(PST(0),&tmp);
real_to_real(&tmp,&ST(0));
......@@ -135,7 +135,7 @@ static void do_emu(struct info * info)
case 0x1f8: case 0x1f9: case 0x1fb: case 0x1fd:
case 0x1fe: case 0x1ff:
printk("%04x fxxx not implemented\n\r",code + 0xd800);
math_abort(info,1<<(SIGILL-1));
math_abort(info,SIGILL);
case 0x1fc:
frndint(PST(0),&tmp);
real_to_real(&tmp,&ST(0));
......@@ -246,7 +246,7 @@ static void do_emu(struct info * info)
return;
case 0xb8:
printk("ffree not implemented\n\r");
math_abort(info,1<<(SIGILL-1));
math_abort(info,SIGILL);
case 0xb9:
fxchg(&ST(0),&ST(code & 7));
return;
......@@ -303,7 +303,7 @@ static void do_emu(struct info * info)
return;
case 0xf8:
printk("ffree not implemented\n\r");
math_abort(info,1<<(SIGILL-1));
math_abort(info,SIGILL);
fpop();
return;
case 0xf9:
......@@ -478,7 +478,7 @@ static void do_emu(struct info * info)
return;
}
printk("Unknown math-insns: %04x:%08x %04x\n\r",CS,EIP,code);
math_abort(info,1<<(SIGFPE-1));
math_abort(info,SIGFPE);
}
void math_emulate(long ___false)
......@@ -495,7 +495,7 @@ void math_emulate(long ___false)
void __math_abort(struct info * info, unsigned int signal)
{
EIP = ORIG_EIP;
current->signal |= signal;
send_sig(signal,current,1);
__asm__("movl %0,%%esp ; ret"::"g" (((long) info)-4));
}
......@@ -542,7 +542,7 @@ static temp_real_unaligned * __st(int i)
void math_emulate(long ___false)
{
current->signal |= 1<<(SIGFPE-1);
send_sig(SIGFPE,current,1);
schedule();
}
......
......@@ -164,6 +164,9 @@ void ctrl_alt_del(void)
{
if (C_A_D)
hard_reset_now();
else
if (task[1])
send_sig(SIGINT,task[1],1);
}
......
......@@ -89,7 +89,7 @@ ENOSYS = 38
.globl _general_protection,_irq13,_reserved
.globl _alignment_check,_page_fault
.globl _keyboard_interrupt,_hd_interrupt
.globl _IRQ3_interrupt,_IRQ4_interrupt
.globl _IRQ3_interrupt,_IRQ4_interrupt,_IRQ5_interrupt,_IRQ9_interrupt
#define SAVE_ALL \
cld; \
......@@ -274,6 +274,28 @@ _IRQ4_interrupt:
UNBLK_FIRST(0x10)
jmp ret_from_sys_call
.align 2
_IRQ5_interrupt:
pushl $-1
SAVE_ALL
ACK_FIRST(0x20)
sti
call _do_IRQ5
cli
UNBLK_FIRST(0x20)
jmp ret_from_sys_call
.align 2
_IRQ9_interrupt:
pushl $-1
SAVE_ALL
ACK_SECOND(0x02)
sti
call _do_IRQ9
cli
UNBLK_SECOND(0x02)
jmp ret_from_sys_call
.align 2
_timer_interrupt:
pushl $-1 # mark this as an int
......
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