kern
diff src/intr.c @ 11:cccaa40f5432
forgot to add a load of stuff
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 19 Feb 2011 04:41:51 +0200 |
parents | |
children | eaec918de072 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/intr.c Sat Feb 19 04:41:51 2011 +0200 1.3 @@ -0,0 +1,175 @@ 1.4 +#include <stdio.h> 1.5 +#include "intr.h" 1.6 +#include "desc.h" 1.7 +#include "segm.h" 1.8 +#include "asmops.h" 1.9 +#include "panic.h" 1.10 + 1.11 +/* IDT gate descriptor bits */ 1.12 +#define GATE_TASK (5 << 8) 1.13 +#define GATE_INTR (6 << 8) 1.14 +#define GATE_TRAP (7 << 8) 1.15 +#define GATE_DEFAULT (1 << 11) 1.16 +#define GATE_PRESENT (1 << 15) 1.17 + 1.18 +/* offset used to remap IRQ numbers (+32) */ 1.19 +#define IRQ_OFFSET 32 1.20 +/* conversion macros between IRQ and interrupt numbers */ 1.21 +#define IRQ_TO_INTR(x) ((x) + IRQ_OFFSET) 1.22 +#define INTR_TO_IRQ(x) ((x) - IRQ_OFFSET) 1.23 +/* checks whether a particular interrupt is an remapped IRQ */ 1.24 +#define IS_IRQ(n) ((n) >= IRQ_OFFSET && (n) < IRQ_OFFSET + 16) 1.25 + 1.26 +/* PIC command and data ports */ 1.27 +#define PIC1_CMD 0x20 1.28 +#define PIC1_DATA 0x21 1.29 +#define PIC2_CMD 0xa0 1.30 +#define PIC2_DATA 0xa1 1.31 + 1.32 +/* PIC initialization command word 1 bits */ 1.33 +#define ICW1_ICW4_NEEDED (1 << 0) 1.34 +#define ICW1_SINGLE (1 << 1) 1.35 +#define ICW1_INTERVAL4 (1 << 2) 1.36 +#define ICW1_LEVEL (1 << 3) 1.37 +#define ICW1_INIT (1 << 4) 1.38 +/* PIC initialization command word 4 bits */ 1.39 +#define ICW4_8086 (1 << 0) 1.40 +#define ICW4_AUTO_EOI (1 << 1) 1.41 +#define ICW4_BUF_SLAVE (1 << 3) /* 1000 */ 1.42 +#define ICW4_BUF_MASTER (3 << 2) /* 1100 */ 1.43 +#define ICW4_SPECIAL (1 << 4) 1.44 + 1.45 +/* PIC operation command word 2 bits */ 1.46 +#define OCW2_EOI (1 << 5) 1.47 + 1.48 + 1.49 +/* structure used to pass the interrupt stack frame from the 1.50 + * entry points to the C dispatch function. 1.51 + */ 1.52 +struct intr_frame { 1.53 + /* registers pushed by pusha in intr_entry_* */ 1.54 + uint32_t edi, esi, ebp, esp; 1.55 + uint32_t ebx, edx, ecx, eax; 1.56 + /* interrupt number and error code pushed in intr_entry_* */ 1.57 + uint32_t inum, err; 1.58 + /* pushed by CPU during interrupt entry */ 1.59 + uint32_t eip, cs, eflags; 1.60 +}; 1.61 + 1.62 + 1.63 +static void init_pic(int offset); 1.64 +static void gate_desc(desc_t *desc, uint16_t sel, uint32_t addr, int dpl, int type); 1.65 +static void set_intr_entry(int num, void (*handler)(void)); 1.66 +static void end_of_irq(int irq); 1.67 + 1.68 +/* defined in intr-asm.S */ 1.69 +void set_idt(uint32_t addr, uint16_t limit); 1.70 +void intr_entry_default(void); 1.71 + 1.72 +/* the IDT (interrupt descriptor table) */ 1.73 +static desc_t idt[256]; 1.74 +/* table of handler functions for all interrupts */ 1.75 +static intr_func_t intr_func[256]; 1.76 + 1.77 + 1.78 +void init_intr(void) 1.79 +{ 1.80 + int i; 1.81 + 1.82 + set_idt((uint32_t)idt, sizeof idt - 1); 1.83 + 1.84 + /* initialize all entry points and interrupt handlers */ 1.85 + for(i=0; i<256; i++) { 1.86 + set_intr_entry(i, intr_entry_default); 1.87 + interrupt(i, 0); 1.88 + } 1.89 + 1.90 + /* by including interrupts.h here (without ASM being defined) 1.91 + * the series of INTR_ENTRY_* macros will be expanded to a series 1.92 + * of function prototypes for all interrupt entry points and the 1.93 + * corresponding calls to set_intr_entry to set up the IDT slots 1.94 + */ 1.95 +#include "interrupts.h" 1.96 + 1.97 + /* initialize the programmable interrupt controller 1.98 + * setting up the maping of IRQs [0, 15] to interrupts [32, 47] 1.99 + */ 1.100 + init_pic(IRQ_OFFSET); 1.101 + 1.102 + /* we're done setting up, enable interrupts before returning */ 1.103 + enable_intr(); 1.104 +} 1.105 + 1.106 +/* set an interrupt handler function for a particular interrupt */ 1.107 +void interrupt(int intr_num, intr_func_t func) 1.108 +{ 1.109 + intr_func[intr_num] = func; 1.110 +} 1.111 + 1.112 +/* this function is called from all interrupt entry points 1.113 + * it calls the appropriate interrupt handlers if available and handles 1.114 + * sending an end-of-interrupt command to the PICs when finished. 1.115 + */ 1.116 +void dispatch_intr(struct intr_frame frm) 1.117 +{ 1.118 + if(intr_func[frm.inum]) { 1.119 + intr_func[frm.inum](frm.inum, frm.err); 1.120 + } else { 1.121 + if(frm.inum < 32) { 1.122 + panic("unhandled exception %d, error code: %d\n", frm.inum, frm.err); 1.123 + } 1.124 + printf("unhandled interrupt %d\n", frm.inum); 1.125 + } 1.126 + 1.127 + if(IS_IRQ(frm.inum)) { 1.128 + end_of_irq(INTR_TO_IRQ(frm.inum)); 1.129 + } 1.130 +} 1.131 + 1.132 +static void init_pic(int offset) 1.133 +{ 1.134 + /* send ICW1 saying we'll follow with ICW4 later on */ 1.135 + outb(ICW1_INIT | ICW1_ICW4_NEEDED, PIC1_CMD); 1.136 + outb(ICW1_INIT | ICW1_ICW4_NEEDED, PIC2_CMD); 1.137 + /* send ICW2 with IRQ remapping */ 1.138 + outb(offset, PIC1_DATA); 1.139 + outb(offset + 8, PIC2_DATA); 1.140 + /* send ICW3 to setup the master/slave relationship */ 1.141 + /* ... set bit3 = 3rd interrupt input has a slave */ 1.142 + outb(4, PIC1_DATA); 1.143 + /* ... set slave ID to 2 */ 1.144 + outb(2, PIC2_DATA); 1.145 + /* send ICW4 to set 8086 mode (no calls generated) */ 1.146 + outb(ICW4_8086, PIC1_DATA); 1.147 + outb(ICW4_8086, PIC2_DATA); 1.148 + /* done, just reset the data port to 0 */ 1.149 + outb(0, PIC1_DATA); 1.150 + outb(0, PIC2_DATA); 1.151 +} 1.152 + 1.153 +static void gate_desc(desc_t *desc, uint16_t sel, uint32_t addr, int dpl, int type) 1.154 +{ 1.155 + /* first 16bit part is the low 16bits of the entry address */ 1.156 + desc->d[0] = addr & 0xffff; 1.157 + /* second 16bit part is the segment selector for the entry code */ 1.158 + desc->d[1] = sel; 1.159 + /* third 16bit part has the privilege level, type, and present bit */ 1.160 + desc->d[2] = ((dpl & 3) << 13) | type | GATE_DEFAULT | GATE_PRESENT; 1.161 + /* last 16bit part is the high 16bits of the entry address */ 1.162 + desc->d[3] = (addr & 0xffff0000) >> 16; 1.163 +} 1.164 + 1.165 +#define IS_TRAP(n) ((n) < 20 && (n) != 2) 1.166 +static void set_intr_entry(int num, void (*handler)(void)) 1.167 +{ 1.168 + int type = IS_TRAP(num) ? GATE_TRAP : GATE_INTR; 1.169 + gate_desc(idt + num, selector(SEGM_KCODE, 0), (uint32_t)handler, 0, type); 1.170 +} 1.171 + 1.172 +static void end_of_irq(int irq) 1.173 +{ 1.174 + if(irq > 7) { 1.175 + outb(OCW2_EOI, PIC2_CMD); 1.176 + } 1.177 + outb(OCW2_EOI, PIC1_CMD); 1.178 +}