11 #define PIC2_DATA 0xA1
15 #define ICW1_ICW4 0x01
16 #define ICW1_SINGLE 0x02
17 #define ICW1_INTERVAL4 0x04
18 #define ICW1_LEVEL 0x08
19 #define ICW1_INIT 0x10
20 #define ICW4_8086 0x01
21 #define ICW4_AUTO 0x02
22 #define ICW4_BUF_SLAVE 0x08
23 #define ICW4_BUF_MASTER 0x0C
24 #define ICW4_SFNM 0x10
26 static uint16_t idt
[256 * 4]; // the actual IDT that the CPU sees
27 extern uint32_t isr_table
[]; // defined in isr.asm - points to all the ISRs
29 // this is the default interrupt handler, so we can see
30 // if an interrupt fired that shouldn't have.
31 static void default_interrupt_handler(int vector
, struct interrupt_stack
*is
)
33 console_printf(get_vterm(0), "Interrupt 0x%X fired.\n", vector
);
34 console_printf(get_vterm(0), "Return address: 0x%.8X\n", is
->eip
);
35 if (vector
>= 0x20 && vector
< 0x30){
36 ack_irq(vector
- 0x20);
37 } else if (vector
<= 19){
38 panic("Unhandled exception!");
42 // tell the CPU where the IDT is. Note that
43 // it's convenient to consider the IDT
44 // as a uint16_t array.
45 static void load_idt_addr(uint16_t *idt
)
49 "movw %%cx,(%%esp) \n"
50 "movl %%eax,2(%%esp) \n"
53 :: "c" (256 * 8), "a" (idt
)
57 // small busy-wait loop for configuring the PIC
58 static void io_wait(void)
65 // remap PICs to use 0x20 and 0x28 as base vectors
66 static void remap_pics(void)
68 int pic1_offset
= 0x20;
69 int pic2_offset
= 0x28;
72 //a1 = inb(PIC1_DATA);
73 //a2 = inb(PIC2_DATA);
77 outb(PIC1_CMD
, ICW1_INIT
+ ICW1_ICW4
);
79 outb(PIC2_CMD
, ICW1_INIT
+ ICW1_ICW4
);
81 outb(PIC1_DATA
, pic1_offset
);
83 outb(PIC2_DATA
, pic2_offset
);
89 outb(PIC1_DATA
, ICW4_8086
);
91 outb(PIC2_DATA
, ICW4_8086
);
97 void interrupt_init(void)
102 default_handler_ptr
= (uint32_t)default_interrupt_handler
;
103 num_installed_interrupts
= 0;
106 for (i
=0; i
<256; i
++){
107 isr_addr
= isr_table
[i
];
108 idt
[i
* 4 + 0] = isr_addr
;
109 idt
[i
* 4 + 1] = SEG_DPL0_CODE
; // use the ring-0 code segment for interrupt handler
110 //idt[i * 4 + 2] = 0xEE00; // interrupt gate descriptor
111 idt
[i
* 4 + 2] = 0x8E00; // interrupt gate descriptor
112 idt
[i
* 4 + 3] = isr_addr
>> 16;
113 // set the default interrupt handler, too
114 interrupt_handlers
[i
] = default_interrupt_handler
;
116 // load the IDT address
122 // enable the cascade irq (so that the slave PIC can work,
123 // and we can service IRQs 8-15)
128 // set up an interrupt handler for interrupt 'vector'
129 void interrupt_set_handler(int vector
, isr_t handler
)
131 num_installed_interrupts
++;
132 interrupt_handlers
[vector
] = handler
;
135 // remove an interrupt handler (set it to the default handler)
136 void interrupt_clear_handler(int vector
)
138 if(num_installed_interrupts
){num_installed_interrupts
--;}
139 interrupt_handlers
[vector
] = default_interrupt_handler
;
142 void interrupt_set_flags(int vector
, int flags
)
144 if (flags
& INTR_USER
){
145 idt
[vector
* 4 + 2] = 0xEE00;
147 idt
[vector
* 4 + 2] = 0x8E00;
151 // get an interrupt vector from an IRQ
152 int irq_to_int(int irq
)
157 // get the irq number behind an interrupt vector
158 int int_to_irq(int vector
)
160 return vector
- 0x20;
163 // unmask (enable) IRQ n
164 void unmask_irq(int n
)
175 a
&= ~(1 << (n
- 8));
180 // mask (disable) IRQ n
201 outb(PIC2_CMD
, PIC_ACK
);
202 outb(PIC1_CMD
, PIC_ACK
);