kern

view src/intr.c @ 12:eaec918de072

- fixed the scrolling issue - other minor crap
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 22 Feb 2011 18:51:44 +0200
parents cccaa40f5432
children 7795225808b3 8ea6debe4265
line source
1 #include <stdio.h>
2 #include "intr.h"
3 #include "desc.h"
4 #include "segm.h"
5 #include "asmops.h"
6 #include "panic.h"
8 /* IDT gate descriptor bits */
9 #define GATE_TASK (5 << 8)
10 #define GATE_INTR (6 << 8)
11 #define GATE_TRAP (7 << 8)
12 #define GATE_DEFAULT (1 << 11)
13 #define GATE_PRESENT (1 << 15)
15 /* offset used to remap IRQ numbers (+32) */
16 #define IRQ_OFFSET 32
17 /* conversion macros between IRQ and interrupt numbers */
18 #define IRQ_TO_INTR(x) ((x) + IRQ_OFFSET)
19 #define INTR_TO_IRQ(x) ((x) - IRQ_OFFSET)
20 /* checks whether a particular interrupt is an remapped IRQ */
21 #define IS_IRQ(n) ((n) >= IRQ_OFFSET && (n) < IRQ_OFFSET + 16)
23 /* PIC command and data ports */
24 #define PIC1_CMD 0x20
25 #define PIC1_DATA 0x21
26 #define PIC2_CMD 0xa0
27 #define PIC2_DATA 0xa1
29 /* PIC initialization command word 1 bits */
30 #define ICW1_ICW4_NEEDED (1 << 0)
31 #define ICW1_SINGLE (1 << 1)
32 #define ICW1_INTERVAL4 (1 << 2)
33 #define ICW1_LEVEL (1 << 3)
34 #define ICW1_INIT (1 << 4)
35 /* PIC initialization command word 4 bits */
36 #define ICW4_8086 (1 << 0)
37 #define ICW4_AUTO_EOI (1 << 1)
38 #define ICW4_BUF_SLAVE (1 << 3) /* 1000 */
39 #define ICW4_BUF_MASTER (3 << 2) /* 1100 */
40 #define ICW4_SPECIAL (1 << 4)
42 /* PIC operation command word 2 bits */
43 #define OCW2_EOI (1 << 5)
46 /* structure used to pass the interrupt stack frame from the
47 * entry points to the C dispatch function.
48 */
49 struct intr_frame {
50 /* registers pushed by pusha in intr_entry_* */
51 uint32_t edi, esi, ebp, esp;
52 uint32_t ebx, edx, ecx, eax;
53 /* interrupt number and error code pushed in intr_entry_* */
54 uint32_t inum, err;
55 /* pushed by CPU during interrupt entry */
56 uint32_t eip, cs, eflags;
57 };
60 static void init_pic(int offset);
61 static void gate_desc(desc_t *desc, uint16_t sel, uint32_t addr, int dpl, int type);
62 static void set_intr_entry(int num, void (*handler)(void));
63 static void end_of_irq(int irq);
65 /* defined in intr-asm.S */
66 void set_idt(uint32_t addr, uint16_t limit);
67 void intr_entry_default(void);
69 /* the IDT (interrupt descriptor table) */
70 static desc_t idt[256];
71 /* table of handler functions for all interrupts */
72 static intr_func_t intr_func[256];
75 void init_intr(void)
76 {
77 int i;
79 set_idt((uint32_t)idt, sizeof idt - 1);
81 /* initialize all entry points and interrupt handlers */
82 for(i=0; i<256; i++) {
83 set_intr_entry(i, intr_entry_default);
84 interrupt(i, 0);
85 }
87 /* by including interrupts.h here (without ASM being defined)
88 * the series of INTR_ENTRY_* macros will be expanded to a series
89 * of function prototypes for all interrupt entry points and the
90 * corresponding calls to set_intr_entry to set up the IDT slots
91 */
92 #include "interrupts.h"
94 /* initialize the programmable interrupt controller
95 * setting up the maping of IRQs [0, 15] to interrupts [32, 47]
96 */
97 init_pic(IRQ_OFFSET);
99 /* we're done setting up, enable interrupts before returning */
100 enable_intr();
101 }
103 /* set an interrupt handler function for a particular interrupt */
104 void interrupt(int intr_num, intr_func_t func)
105 {
106 intr_func[intr_num] = func;
107 }
109 /* this function is called from all interrupt entry points
110 * it calls the appropriate interrupt handlers if available and handles
111 * sending an end-of-interrupt command to the PICs when finished.
112 */
113 void dispatch_intr(struct intr_frame frm)
114 {
115 if(intr_func[frm.inum]) {
116 intr_func[frm.inum](frm.inum, frm.err);
117 } else {
118 if(frm.inum < 32) {
119 panic("unhandled exception %d, error code: %d\n", frm.inum, frm.err);
120 }
121 printf("unhandled interrupt %d\n", frm.inum);
122 }
124 if(IS_IRQ(frm.inum)) {
125 end_of_irq(INTR_TO_IRQ(frm.inum));
126 }
127 }
129 static void init_pic(int offset)
130 {
131 /* send ICW1 saying we'll follow with ICW4 later on */
132 outb(ICW1_INIT | ICW1_ICW4_NEEDED, PIC1_CMD);
133 outb(ICW1_INIT | ICW1_ICW4_NEEDED, PIC2_CMD);
134 /* send ICW2 with IRQ remapping */
135 outb(offset, PIC1_DATA);
136 outb(offset + 8, PIC2_DATA);
137 /* send ICW3 to setup the master/slave relationship */
138 /* ... set bit3 = 3rd interrupt input has a slave */
139 outb(4, PIC1_DATA);
140 /* ... set slave ID to 2 */
141 outb(2, PIC2_DATA);
142 /* send ICW4 to set 8086 mode (no calls generated) */
143 outb(ICW4_8086, PIC1_DATA);
144 outb(ICW4_8086, PIC2_DATA);
145 /* done, just reset the data port to 0 */
146 outb(0, PIC1_DATA);
147 outb(0, PIC2_DATA);
148 }
150 static void gate_desc(desc_t *desc, uint16_t sel, uint32_t addr, int dpl, int type)
151 {
152 /* first 16bit part is the low 16bits of the entry address */
153 desc->d[0] = addr & 0xffff;
154 /* second 16bit part is the segment selector for the entry code */
155 desc->d[1] = sel;
156 /* third 16bit part has the privilege level, type, and present bit */
157 desc->d[2] = ((dpl & 3) << 13) | type | GATE_DEFAULT | GATE_PRESENT;
158 /* last 16bit part is the high 16bits of the entry address */
159 desc->d[3] = (addr & 0xffff0000) >> 16;
160 }
162 #define IS_TRAP(n) ((n) < 32)
163 static void set_intr_entry(int num, void (*handler)(void))
164 {
165 int type = IS_TRAP(num) ? GATE_TRAP : GATE_INTR;
166 gate_desc(idt + num, selector(SEGM_KCODE, 0), (uint32_t)handler, 0, type);
167 }
169 static void end_of_irq(int irq)
170 {
171 if(irq > 7) {
172 outb(OCW2_EOI, PIC2_CMD);
173 }
174 outb(OCW2_EOI, PIC1_CMD);
175 }