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;
......
......@@ -14,44 +14,48 @@
*/
#include <signal.h>
#include <errno.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/tty.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
/*
* note that IRQ9 is what many docs call IRQ2 - on the AT hardware
* the old IRQ2 line has been changed to IRQ9. The serial_table
* structure considers IRQ2 to be the same as IRQ9.
*/
extern void IRQ9_interrupt(void);
extern void IRQ3_interrupt(void);
extern void IRQ4_interrupt(void);
extern void IRQ5_interrupt(void);
struct serial_struct serial_table[NR_SERIALS] = {
{ PORT_UNKNOWN, 0, 0x3F8, 4, NULL},
{ PORT_UNKNOWN, 1, 0x2F8, 3, NULL},
{ PORT_UNKNOWN, 2, 0x3E8, 4, NULL},
{ PORT_UNKNOWN, 3, 0x2E8, 3, NULL},
};
static struct serial_struct * irq_info[16] = { NULL, };
#define PORT_UNKNOWN 0
#define PORT_8250 1
#define PORT_16450 2
#define PORT_16550 3
#define PORT_16550A 4
int port_table[] = {
PORT_UNKNOWN,
PORT_UNKNOWN,
PORT_UNKNOWN,
PORT_UNKNOWN,
PORT_UNKNOWN
};
static void modem_status_intr(unsigned line, unsigned port, struct tty_struct * tty)
static void modem_status_intr(struct serial_struct * info)
{
unsigned char status = inb(port+6);
unsigned char status = inb(info->port+6);
if ((status & 0x88) == 0x08 && tty->pgrp > 0)
kill_pg(tty->pgrp,SIGHUP,1);
if ((status & 0x88) == 0x08 && info->tty->pgrp > 0)
kill_pg(info->tty->pgrp,SIGHUP,1);
#if 0
if ((status & 0x10) == 0x10)
tty->stopped = 0;
info->tty->stopped = 0;
else
tty->stopped = 1;
info->tty->stopped = 1;
#endif
}
......@@ -64,65 +68,65 @@ static void modem_status_intr(unsigned line, unsigned port, struct tty_struct *
* again. With serial lines, the interrupts can happen so often that the
* races actually are noticeable.
*/
static void send_intr(unsigned line, unsigned port, struct tty_struct * tty)
static void send_intr(struct serial_struct * info)
{
unsigned short port = info->port;
unsigned int timer = SER1_TIMEOUT + info->line;
struct tty_queue * queue = info->tty->write_q;
int c, i = 0;
#define TIMER ((SER1_TIMEOUT-1)+line)
timer_active &= ~(1 << TIMER);
timer_active &= ~(1 << timer);
do {
if ((c = GETCH(tty->write_q)) < 0)
if ((c = GETCH(queue)) < 0)
return;
outb(c,port);
i++;
} while ( port_table[line] == PORT_16550A &&
i < 14 && !EMPTY(tty->write_q));
timer_table[TIMER].expires = jiffies + 10;
timer_active |= 1 << TIMER;
if (LEFT(tty->write_q) > WAKEUP_CHARS)
wake_up(&tty->write_q->proc_list);
#undef TIMER
} while (info->type == PORT_16550A &&
i < 14 && !EMPTY(queue));
timer_table[timer].expires = jiffies + 10;
timer_active |= 1 << timer;
if (LEFT(queue) > WAKEUP_CHARS)
wake_up(&queue->proc_list);
}
static void receive_intr(unsigned line, unsigned port, struct tty_struct * tty)
static void receive_intr(struct serial_struct * info)
{
while (!FULL(tty->read_q)) {
if (!(inb(port+5) & 1))
break;
PUTCH(inb(port),tty->read_q);
};
timer_active |= (1<<(SER1_TIMER-1))<<line;
unsigned short port = info->port;
struct tty_queue * queue = info->tty->read_q;
while (inb(port+5) & 1)
PUTCH(inb(port),queue);
timer_active |= (1<<SER1_TIMER)<<info->line;
}
static void line_status_intr(unsigned line, unsigned port, struct tty_struct * tty)
static void line_status_intr(struct serial_struct * info)
{
unsigned char status = inb(port+5);
unsigned char status = inb(info->port+5);
/* printk("line status: %02x\n",status); */
}
static void (*jmp_table[4])(unsigned,unsigned,struct tty_struct *) = {
static void (*jmp_table[4])(struct serial_struct *) = {
modem_status_intr,
send_intr,
receive_intr,
line_status_intr
};
static void check_tty(unsigned line,struct tty_struct * tty)
static void check_tty(struct serial_struct * info)
{
unsigned short port;
unsigned char ident;
if (!(port = tty->read_q->data))
if (!info || !info->tty || !info->port)
return;
while (1) {
ident = inb(port+2) & 7;
ident = inb(info->port+2) & 7;
if (ident & 1)
return;
ident >>= 1;
if (ident > 3)
return;
jmp_table[ident](line,port,tty);
jmp_table[ident](info);
}
}
......@@ -131,8 +135,7 @@ static void check_tty(unsigned line,struct tty_struct * tty)
*/
void do_IRQ3(void)
{
check_tty(2,tty_table+65);
check_tty(4,tty_table+67);
check_tty(irq_info[3]);
}
/*
......@@ -140,8 +143,17 @@ void do_IRQ3(void)
*/
void do_IRQ4(void)
{
check_tty(1,tty_table+64);
check_tty(3,tty_table+66);
check_tty(irq_info[4]);
}
void do_IRQ5(void)
{
check_tty(irq_info[5]);
}
void do_IRQ9(void)
{
check_tty(irq_info[9]);
}
static void com1_timer(void)
......@@ -168,52 +180,51 @@ static void com4_timer(void)
* Again, we disable interrupts to be sure there aren't any races:
* see send_intr for details.
*/
static inline void do_rs_write(unsigned line, struct tty_struct * tty)
static inline void do_rs_write(struct serial_struct * info)
{
int port;
#define TIMER ((SER1_TIMEOUT-1)+line)
if (!tty || !tty->write_q || EMPTY(tty->write_q))
if (!info->tty || !info->port)
return;
if (!(port = tty->write_q->data))
if (!info->tty->write_q || EMPTY(info->tty->write_q))
return;
cli();
if (inb_p(port+5) & 0x20)
send_intr(line,port,tty);
if (inb_p(info->port+5) & 0x20)
send_intr(info);
else {
timer_table[TIMER].expires = jiffies + 10;
timer_active |= 1 << TIMER;
unsigned int timer = SER1_TIMEOUT+info->line;
timer_table[timer].expires = jiffies + 10;
timer_active |= 1 << timer;
}
sti();
#undef TIMER
}
static void com1_timeout(void)
{
do_rs_write(1,tty_table+64);
do_rs_write(serial_table);
}
static void com2_timeout(void)
{
do_rs_write(2,tty_table+65);
do_rs_write(serial_table + 1);
}
static void com3_timeout(void)
{
do_rs_write(3,tty_table+66);
do_rs_write(serial_table + 2);
}
static void com4_timeout(void)
{
do_rs_write(4,tty_table+67);
do_rs_write(serial_table + 3);
}
static void init(int port, int line)
static void init(struct serial_struct * info)
{
unsigned char status1, status2, scratch;
unsigned short port = info->port;
if (inb(port+5) == 0xff) {
port_table[line] = PORT_UNKNOWN;
info->type = PORT_UNKNOWN;
return;
}
......@@ -227,51 +238,57 @@ static void init(int port, int line)
outb_p(0x01, port+2);
scratch = inb(port+2) >> 6;
switch (scratch) {
case 0: printk("serial port at 0x%04x is a 16450\n", port);
port_table[line] = PORT_16450;
break;
case 1: printk("serial port at 0x%04x is unknown\n", port);
port_table[line] = PORT_UNKNOWN;
break;
case 2: printk("serial port at 0x%04x is a 16550 (FIFO's disabled)\n", port);
port_table[line] = PORT_16550;
outb_p(0x00, port+2);
break;
case 3: printk("serial port at 0x%04x is a 16550a (FIFO's enabled)\n", port);
port_table[line] = PORT_16550A;
outb_p(0xc7, port+2);
break;
case 0:
info->type = PORT_16450;
break;
case 1:
info->type = PORT_UNKNOWN;
break;
case 2:
info->type = PORT_16550;
outb_p(0x00, port+2);
break;
case 3:
info->type = PORT_16550A;
outb_p(0xc7, port+2);
break;
}
} else
printk("serial port at 0x%04x is a 8250\n", port);
info->type = PORT_8250;
outb_p(0x80,port+3); /* set DLAB of line control reg */
outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */
outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps) */
outb_p(0x00,port+1); /* MS of divisor */
outb_p(0x03,port+3); /* reset DLAB */
outb_p(0x00,port+4); /* reset DTR,RTS, OUT_2 */
outb_p(0x0f,port+1); /* enable all intrs */
outb_p(0x00,port+1); /* disable all intrs */
(void)inb(port); /* read data port to reset things (?) */
}
/*
* this routine enables interrupts on 'line', and disables them on
* 'line ^ 2', as they share the same IRQ. Braindamaged AT hardware.
*/
void serial_open(unsigned line)
void serial_close(unsigned line, struct file * filp)
{
unsigned short port;
unsigned short port2;
struct serial_struct * info;
int irq;
if (line>3)
if (line >= NR_SERIALS)
return;
port = tty_table[64+line].read_q->data;
if (!port)
info = serial_table + line;
if (!info->port)
return;
port2 = tty_table[64+(line ^ 2)].read_q->data;
cli();
if (port2)
outb_p(0x00,port2+4);
outb(0x00,info->port+4); /* reset DTR, RTS, */
irq = info->irq;
if (irq == 2)
irq = 9;
if (irq_info[irq] == info) {
irq_info[irq] = NULL;
if (irq < 8)
outb(inb_p(0x21) | (1<<irq),0x21);
else
outb(inb_p(0xA1) | (1<<(irq-8)),0xA1);
}
}
static void startup(unsigned short port)
{
outb_p(0x03,port+3); /* reset DLAB */
outb_p(0x0f,port+4); /* set DTR,RTS, OUT_2 */
outb_p(0x0f,port+1); /* enable all intrs */
......@@ -279,11 +296,106 @@ void serial_open(unsigned line)
inb_p(port+0);
inb_p(port+6);
inb(port+2);
}
/*
* this routine enables interrupts on 'line', and disables them for any
* other serial line that shared the same IRQ. Braindamaged AT hardware.
*/
int serial_open(unsigned line, struct file * filp)
{
struct serial_struct * info;
int irq;
unsigned short port;
if (line >= NR_SERIALS)
return -ENODEV;
info = serial_table + line;
if (!(port = info->port))
return -ENODEV;
irq = info->irq;
if (irq == 2)
irq = 9;
if (irq_info[irq] && irq_info[irq] != info)
return -EBUSY;
cli();
startup(port);
irq_info[irq] = info;
if (irq < 8)
outb(inb_p(0x21) & ~(1<<irq),0x21);
else
outb(inb_p(0xA1) & ~(1<<(irq-8)),0xA1);
sti();
return 0;
}
int get_serial_info(unsigned int line, struct serial_struct * info)
{
if (line >= NR_SERIALS)
return -ENODEV;
if (!info)
return -EFAULT;
memcpy_tofs(info,serial_table+line,sizeof(*info));
return 0;
}
int set_serial_info(unsigned int line, struct serial_struct * info)
{
struct serial_struct tmp;
unsigned new_port;
unsigned irq,new_irq;
if (!suser())
return -EPERM;
if (line >= NR_SERIALS)
return -ENODEV;
if (!info)
return -EFAULT;
memcpy_fromfs(&tmp,info,sizeof(tmp));
info = serial_table + line;
if (!(new_port = tmp.port))
new_port = info->port;
if (!(new_irq = tmp.irq))
new_irq = info->irq;
if (new_irq > 15 || new_port > 0xffff)
return -EINVAL;
if (new_irq == 2)
new_irq = 9;
irq = info->irq;
if (irq == 2)
irq = 9;
if (irq != new_irq) {
if (irq_info[new_irq])
return -EBUSY;
cli();
irq_info[new_irq] = irq_info[irq];
irq_info[irq] = NULL;
info->irq = new_irq;
if (irq < 8)
outb(inb_p(0x21) | (1<<irq),0x21);
else
outb(inb_p(0xA1) | (1<<(irq-8)),0xA1);
if (new_irq < 8)
outb(inb_p(0x21) & ~(1<<new_irq),0x21);
else
outb(inb_p(0xA1) & ~(1<<(new_irq-8)),0xA1);
}
cli();
if (new_port != info->port) {
outb(0x00,info->port+4); /* reset DTR, RTS, */
info->port = new_port;
init(info);
startup(new_port);
}
sti();
return 0;
}
long rs_init(long kmem_start)
{
int i;
struct serial_struct * info;
/* SERx_TIMER timers are used for receiving: timeout is always 0 (immediate) */
timer_table[SER1_TIMER].fn = com1_timer;
timer_table[SER1_TIMER].expires = 0;
......@@ -304,11 +416,26 @@ long rs_init(long kmem_start)
timer_table[SER4_TIMEOUT].expires = 0;
set_intr_gate(0x23,IRQ3_interrupt);
set_intr_gate(0x24,IRQ4_interrupt);
init(tty_table[64].read_q->data, 1);
init(tty_table[65].read_q->data, 2);
init(tty_table[66].read_q->data, 3);
init(tty_table[67].read_q->data, 4);
outb(inb_p(0x21)&0xE7,0x21);
set_intr_gate(0x25,IRQ5_interrupt);
set_intr_gate(0x29,IRQ9_interrupt);
for (i = 0, info = serial_table; i < NR_SERIALS; i++,info++) {
info->tty = (tty_table+64) + i;
init(info);
switch (info->type) {
case PORT_8250:
printk("serial port at 0x%04x is a 8250\n", info->port);
break;
case PORT_16450:
printk("serial port at 0x%04x is a 16450\n", info->port);
break;
case PORT_16550:
printk("serial port at 0x%04x is a 16550\n", info->port);
break;
case PORT_16550A:
printk("serial port at 0x%04x is a 16550A\n", info->port);
break;
}
}
return kmem_start;
}
......@@ -321,7 +448,7 @@ long rs_init(long kmem_start)
*/
void rs_write(struct tty_struct * tty)
{
int line = tty - tty_table - 63;
int line = tty - tty_table - 64;
do_rs_write(line,tty);
do_rs_write(serial_table+line);
}
......@@ -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