kern

view src/intr.c @ 52:fa65b4f45366

picking this up again, let's fix it
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 07 Aug 2011 06:42:00 +0300
parents b1e8c8251884
children 88a6c4e192f9
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 /* PIC command and data ports */
16 #define PIC1_CMD 0x20
17 #define PIC1_DATA 0x21
18 #define PIC2_CMD 0xa0
19 #define PIC2_DATA 0xa1
21 /* PIC initialization command word 1 bits */
22 #define ICW1_ICW4_NEEDED (1 << 0)
23 #define ICW1_SINGLE (1 << 1)
24 #define ICW1_INTERVAL4 (1 << 2)
25 #define ICW1_LEVEL (1 << 3)
26 #define ICW1_INIT (1 << 4)
27 /* PIC initialization command word 4 bits */
28 #define ICW4_8086 (1 << 0)
29 #define ICW4_AUTO_EOI (1 << 1)
30 #define ICW4_BUF_SLAVE (1 << 3) /* 1000 */
31 #define ICW4_BUF_MASTER (3 << 2) /* 1100 */
32 #define ICW4_SPECIAL (1 << 4)
34 /* PIC operation command word 2 bits */
35 #define OCW2_EOI (1 << 5)
38 static void init_pic(int offset);
39 static void gate_desc(desc_t *desc, uint16_t sel, uint32_t addr, int dpl, int type);
40 static void set_intr_entry(int num, void (*handler)(void));
42 /* defined in intr-asm.S */
43 void set_idt(uint32_t addr, uint16_t limit);
44 void intr_entry_default(void);
46 /* the IDT (interrupt descriptor table) */
47 static desc_t idt[256];
48 /* table of handler functions for all interrupts */
49 static intr_func_t intr_func[256];
51 static struct intr_frame *cur_intr_frame;
54 void init_intr(void)
55 {
56 int i;
58 set_idt((uint32_t)idt, sizeof idt - 1);
60 /* initialize all entry points and interrupt handlers */
61 for(i=0; i<256; i++) {
62 set_intr_entry(i, intr_entry_default);
63 interrupt(i, 0);
64 }
66 /* by including interrupts.h here (without ASM being defined)
67 * the series of INTR_ENTRY_* macros will be expanded to a series
68 * of function prototypes for all interrupt entry points and the
69 * corresponding calls to set_intr_entry to set up the IDT slots
70 */
71 #include "interrupts.h"
73 /* initialize the programmable interrupt controller
74 * setting up the maping of IRQs [0, 15] to interrupts [32, 47]
75 */
76 init_pic(IRQ_OFFSET);
77 }
79 /* retrieve the current interrupt frame.
80 * returns 0 when called during kernel init.
81 */
82 struct intr_frame *get_intr_frame(void)
83 {
84 return cur_intr_frame;
85 }
87 /* set an interrupt handler function for a particular interrupt */
88 void interrupt(int intr_num, intr_func_t func)
89 {
90 intr_func[intr_num] = func;
91 }
93 /* this function is called from all interrupt entry points
94 * it calls the appropriate interrupt handlers if available and handles
95 * sending an end-of-interrupt command to the PICs when finished.
96 */
97 void dispatch_intr(struct intr_frame frm)
98 {
99 cur_intr_frame = &frm;
101 if(intr_func[frm.inum]) {
102 intr_func[frm.inum](frm.inum);
103 } else {
104 if(frm.inum < 32) {
105 panic("unhandled exception %d, error code: %d\n", frm.inum, frm.err);
106 }
107 printf("unhandled interrupt %d\n", frm.inum);
108 }
110 if(IS_IRQ(frm.inum)) {
111 end_of_irq(INTR_TO_IRQ(frm.inum));
112 }
113 }
115 static void init_pic(int offset)
116 {
117 /* send ICW1 saying we'll follow with ICW4 later on */
118 outb(ICW1_INIT | ICW1_ICW4_NEEDED, PIC1_CMD);
119 outb(ICW1_INIT | ICW1_ICW4_NEEDED, PIC2_CMD);
120 /* send ICW2 with IRQ remapping */
121 outb(offset, PIC1_DATA);
122 outb(offset + 8, PIC2_DATA);
123 /* send ICW3 to setup the master/slave relationship */
124 /* ... set bit3 = 3rd interrupt input has a slave */
125 outb(4, PIC1_DATA);
126 /* ... set slave ID to 2 */
127 outb(2, PIC2_DATA);
128 /* send ICW4 to set 8086 mode (no calls generated) */
129 outb(ICW4_8086, PIC1_DATA);
130 outb(ICW4_8086, PIC2_DATA);
131 /* done, just reset the data port to 0 */
132 outb(0, PIC1_DATA);
133 outb(0, PIC2_DATA);
134 }
136 static void gate_desc(desc_t *desc, uint16_t sel, uint32_t addr, int dpl, int type)
137 {
138 /* first 16bit part is the low 16bits of the entry address */
139 desc->d[0] = addr & 0xffff;
140 /* second 16bit part is the segment selector for the entry code */
141 desc->d[1] = sel;
142 /* third 16bit part has the privilege level, type, and present bit */
143 desc->d[2] = ((dpl & 3) << 13) | type | GATE_DEFAULT | GATE_PRESENT;
144 /* last 16bit part is the high 16bits of the entry address */
145 desc->d[3] = (addr & 0xffff0000) >> 16;
146 }
148 #define IS_TRAP(n) ((n) >= 32 && !IS_IRQ(n))
149 static void set_intr_entry(int num, void (*handler)(void))
150 {
151 int type = IS_TRAP(num) ? GATE_TRAP : GATE_INTR;
152 gate_desc(idt + num, selector(SEGM_KCODE, 0), (uint32_t)handler, 0, type);
153 }
155 void end_of_irq(int irq)
156 {
157 if(irq > 7) {
158 outb(OCW2_EOI, PIC2_CMD);
159 }
160 outb(OCW2_EOI, PIC1_CMD);
161 }