Added .gitignore
[comos.git] / kernel / interrupt.c
blob990025d5aea541ce35d477dfef049769200388ad
1 #include "interrupt.h"
2 #include "gdt.h"
3 #include "portio.h"
4 #include "console.h"
5 #include "general.h"
7 /* PIC registers */
8 #define PIC1_CMD 0x20
9 #define PIC1_DATA 0x21
10 #define PIC2_CMD 0xA0
11 #define PIC2_DATA 0xA1
13 /* PIC commands */
14 #define PIC_ACK 0x20
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)
47 asm volatile (
48 "subl $6,%%esp \n"
49 "movw %%cx,(%%esp) \n"
50 "movl %%eax,2(%%esp) \n"
51 "lidt (%%esp) \n"
52 "addl $6,%%esp \n"
53 :: "c" (256 * 8), "a" (idt)
54 : "cc");
57 // small busy-wait loop for configuring the PIC
58 static void io_wait(void)
60 int i;
61 for (i=0; i<16; i++)
62 outb(0x80, 0x00);
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;
70 unsigned char a1, a2;
72 //a1 = inb(PIC1_DATA);
73 //a2 = inb(PIC2_DATA);
74 a1 = 0xFF;
75 a2 = 0xFF;
77 outb(PIC1_CMD, ICW1_INIT + ICW1_ICW4);
78 io_wait();
79 outb(PIC2_CMD, ICW1_INIT + ICW1_ICW4);
80 io_wait();
81 outb(PIC1_DATA, pic1_offset);
82 io_wait();
83 outb(PIC2_DATA, pic2_offset);
84 io_wait();
85 outb(PIC1_DATA, 4);
86 io_wait();
87 outb(PIC2_DATA, 2);
88 io_wait();
89 outb(PIC1_DATA, ICW4_8086);
90 io_wait();
91 outb(PIC2_DATA, ICW4_8086);
92 io_wait();
93 outb(PIC1_DATA, a1);
94 outb(PIC2_DATA, a2);
97 void interrupt_init(void)
99 int i;
100 uint32_t isr_addr;
102 default_handler_ptr = (uint32_t)default_interrupt_handler;
103 num_installed_interrupts = 0;
105 // fill in the IDT
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
117 load_idt_addr(idt);
119 // remap the PICs
120 remap_pics();
122 // enable the cascade irq (so that the slave PIC can work,
123 // and we can service IRQs 8-15)
124 unmask_irq(2);
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;
146 } else {
147 idt[vector * 4 + 2] = 0x8E00;
151 // get an interrupt vector from an IRQ
152 int irq_to_int(int irq)
154 return irq + 0x20;
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)
166 unsigned char a;
167 if (n < 8){
168 // master PIC
169 a = inb(PIC1_DATA);
170 a &= ~(1 << n);
171 outb(PIC1_DATA, a);
172 } else {
173 // slave PIC
174 a = inb(PIC2_DATA);
175 a &= ~(1 << (n - 8));
176 outb(PIC2_DATA, a);
180 // mask (disable) IRQ n
181 void mask_irq(int n)
183 unsigned char a;
184 if (n < 8){
185 // master PIC
186 a = inb(PIC1_DATA);
187 a |= (1 << n);
188 outb(PIC1_DATA, a);
189 } else {
190 // slave PIC
191 a = inb(PIC2_DATA);
192 a |= (1 << (n - 8));
193 outb(PIC2_DATA, a);
197 // acknowledge IRQ n
198 void ack_irq(int n)
200 if (n >= 8)
201 outb(PIC2_CMD, PIC_ACK);
202 outb(PIC1_CMD, PIC_ACK);