Added workaround for spurious interrupts on line 7/15 - they are no longer
forwarded to the standard interrupt handler. Untested, though. For more information on the subject: http://www.ggd.nsu.ru/~serg/bsdfaq/part3.html#316 Some cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12800 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -57,6 +57,10 @@
|
|||||||
#define PIC_INIT3_SLAVE_ID2 0x02
|
#define PIC_INIT3_SLAVE_ID2 0x02
|
||||||
#define PIC_INIT4_x86_MODE 0x01
|
#define PIC_INIT4_x86_MODE 0x01
|
||||||
|
|
||||||
|
#define PIC_CONTROL3 0x08
|
||||||
|
#define PIC_CONTROL3_READ_ISR 0x03
|
||||||
|
#define PIC_CONTROL3_READ_IRR 0x02
|
||||||
|
|
||||||
#define PIC_NON_SPECIFIC_EOI 0x20
|
#define PIC_NON_SPECIFIC_EOI 0x20
|
||||||
|
|
||||||
#define PIC_INT_BASE 0x20
|
#define PIC_INT_BASE 0x20
|
||||||
@@ -91,7 +95,7 @@ const char *kInterruptNames[] = {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
uint32 a, b;
|
uint32 a, b;
|
||||||
} desc_table;
|
} desc_table;
|
||||||
static desc_table *idt = NULL;
|
static desc_table *sIDT = NULL;
|
||||||
|
|
||||||
struct iframe_stack gBootFrameStack;
|
struct iframe_stack gBootFrameStack;
|
||||||
|
|
||||||
@@ -113,22 +117,47 @@ set_gate(desc_table *gate_addr, addr_t addr, int type, int dpl)
|
|||||||
static void
|
static void
|
||||||
set_intr_gate(int n, void *addr)
|
set_intr_gate(int n, void *addr)
|
||||||
{
|
{
|
||||||
set_gate(&idt[n], (addr_t)addr, 14, DPL_KERNEL);
|
set_gate(&sIDT[n], (addr_t)addr, 14, DPL_KERNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_system_gate(int n, void *addr)
|
set_system_gate(int n, void *addr)
|
||||||
{
|
{
|
||||||
set_gate(&idt[n], (unsigned int)addr, 15, DPL_USER);
|
set_gate(&sIDT[n], (unsigned int)addr, 15, DPL_USER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
x86_set_task_gate(int32 n, int32 segment)
|
x86_set_task_gate(int32 n, int32 segment)
|
||||||
{
|
{
|
||||||
idt[n].a = (segment << 16);
|
sIDT[n].a = (segment << 16);
|
||||||
idt[n].b = 0x8000 | (0 << 13) | (0x5 << 8); // present, dpl 0, type 5
|
sIDT[n].b = 0x8000 | (0 << 13) | (0x5 << 8); // present, dpl 0, type 5
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Tests if the interrupt in-service register of the responsible
|
||||||
|
* PIC is set for interrupts 7 and 15, and if that's not the case,
|
||||||
|
* it must assume it's a spurious interrupt.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool
|
||||||
|
pic_is_spurious_interrupt(int32 num)
|
||||||
|
{
|
||||||
|
int32 port, isr;
|
||||||
|
|
||||||
|
if (num == 7)
|
||||||
|
port = PIC_MASTER_CONTROL;
|
||||||
|
else if (num == 15)
|
||||||
|
port = PIC_SLAVE_CONTROL;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
out8(PIC_CONTROL3 | PIC_CONTROL3_READ_ISR, port);
|
||||||
|
isr = in8(port);
|
||||||
|
out8(PIC_CONTROL3 | PIC_CONTROL3_READ_IRR, port);
|
||||||
|
|
||||||
|
return (isr & 0x80) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -138,7 +167,7 @@ x86_set_task_gate(int32 n, int32 segment)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pic_end_of_interrupt(int num)
|
pic_end_of_interrupt(int32 num)
|
||||||
{
|
{
|
||||||
if (num >= PIC_INT_BASE && num <= PIC_INT_BASE + PIC_NUM_INTS) {
|
if (num >= PIC_INT_BASE && num <= PIC_INT_BASE + PIC_NUM_INTS) {
|
||||||
// PIC 8259 controlled interrupt
|
// PIC 8259 controlled interrupt
|
||||||
@@ -356,6 +385,12 @@ i386_handle_trap(struct iframe frame)
|
|||||||
default:
|
default:
|
||||||
if (frame.vector >= ARCH_INTERRUPT_BASE) {
|
if (frame.vector >= ARCH_INTERRUPT_BASE) {
|
||||||
pic_end_of_interrupt(frame.vector);
|
pic_end_of_interrupt(frame.vector);
|
||||||
|
|
||||||
|
// This is a workaround for spurious assertions of interrupts 7/15
|
||||||
|
// which seems to be an often seen problem on the PC platform
|
||||||
|
if (pic_is_spurious_interrupt(frame.vector - ARCH_INTERRUPT_BASE))
|
||||||
|
break;
|
||||||
|
|
||||||
ret = int_io_interrupt_handler(frame.vector - ARCH_INTERRUPT_BASE);
|
ret = int_io_interrupt_handler(frame.vector - ARCH_INTERRUPT_BASE);
|
||||||
} else {
|
} else {
|
||||||
panic("i386_handle_trap: unhandled trap 0x%x (%s) at ip 0x%x, thread 0x%x!\n",
|
panic("i386_handle_trap: unhandled trap 0x%x (%s) at ip 0x%x, thread 0x%x!\n",
|
||||||
@@ -392,8 +427,8 @@ i386_handle_trap(struct iframe frame)
|
|||||||
status_t
|
status_t
|
||||||
arch_int_init(kernel_args *args)
|
arch_int_init(kernel_args *args)
|
||||||
{
|
{
|
||||||
// set the global idt variable
|
// set the global sIDT variable
|
||||||
idt = (desc_table *)args->arch_args.vir_idt;
|
sIDT = (desc_table *)args->arch_args.vir_idt;
|
||||||
|
|
||||||
// setup the interrupt controller
|
// setup the interrupt controller
|
||||||
pic_init();
|
pic_init();
|
||||||
@@ -452,8 +487,8 @@ arch_int_init_post_vm(kernel_args *args)
|
|||||||
{
|
{
|
||||||
area_id area;
|
area_id area;
|
||||||
|
|
||||||
idt = (desc_table *)args->arch_args.vir_idt;
|
sIDT = (desc_table *)args->arch_args.vir_idt;
|
||||||
area = create_area("idt", (void *)&idt, B_EXACT_ADDRESS, B_PAGE_SIZE, B_ALREADY_WIRED,
|
area = create_area("idt", (void *)&sIDT, B_EXACT_ADDRESS, B_PAGE_SIZE, B_ALREADY_WIRED,
|
||||||
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
|
||||||
return area >= B_OK ? B_OK : area;
|
return area >= B_OK ? B_OK : area;
|
||||||
|
|||||||
Reference in New Issue
Block a user