extern intr_handler
PIC1_CMD_PORT equ 0x20
+PIC1_DATA_PORT equ 0x21
PIC2_CMD_PORT equ 0xa0
+PIC2_DATA_PORT equ 0xa1
+
+ICW1_ICW4_NEEDED equ 0x01
+ICW1_INIT equ 0x10
+ICW4_8086 equ 0x01
+
OCW2_EOI equ 0x20
OCW3_ISR equ 0x0b
idtbase dd 0
+ global prog_pic
+prog_pic:
+ ; send ICW1 saying we'll follow with ICW4 later
+ mov al, ICW1_INIT | ICW1_ICW4_NEEDED
+ out PIC1_CMD_PORT, al
+ ; send ICW2 with IRQ remapping
+ mov al, [esp + 4]
+ out PIC1_DATA_PORT, al
+ add al, 8
+ out PIC2_DATA_PORT, al
+ ; send ICW3 to setup the master/slave relationship
+ ; ... set bit3 = 3rd interrupt input has a slave
+ mov al, 4
+ out PIC1_DATA_PORT, al
+ ; ... set slave id to 2
+ mov al, 2
+ OUT PIC2_DATA_PORT, al
+ ; send ICW4 to set 8086 mode (no calls generated)
+ mov al, ICW4_8086
+ out PIC1_DATA_PORT, al
+ out PIC2_DATA_PORT, al
+ ; done, reset the data port to 0
+ xor al, al
+ out PIC1_DATA_PORT, al
+ out PIC2_DATA_PORT, al
+ ret
+
+
+ global end_of_irq
+end_of_irq:
+ mov eax, [esp + 4]
+ cmp eax, 8
+ jb .eoi_master
+ ; cascaded IRQ, send EOI to slave PIC first
+ mov al, OCW2_EOI
+ out PIC2_CMD_PORT, al
+.eoi_master: ; send EOI to master PIC
+ mov al, OCW2_EOI
+ out PIC1_CMD_PORT, al
+ ret
+
+
; special entry point for IRQ7 to catch and disregard spurious interrupts
global intr_entry_irq7_verify
intr_entry_irq7_verify:
%macro intr_entry_err 2
+ global intr_entry_%2
intr_entry_%2:
push dword %1 ; push interrupt number
jmp intr_entry_common
%endmacro
%macro intr_entry_noerr 2
+ global intr_entry_%2
intr_entry_%2:
push dword 0 ; push dummy error code
push dword %1 ; push interrupt number
intr_entry_err 12, stack
intr_entry_err 13, prot
intr_entry_err 14, page
- intr_entry_noerr 15, rsvd
intr_entry_noerr 16, fpu
intr_entry_err 17, align
intr_entry_noerr 18, mce
+#include <stdio.h>
#include "intr.h"
#include "desc.h"
+#include "mem.h"
void set_idt(void *ptr, uint16_t lim);
#define NUM_INTR 256
static struct desc idt[NUM_INTR] __attribute__((aligned(8)));
+static void (*intr_func[NUM_INTR])();
+
+static struct {
+ char *name;
+ int num;
+ void (*entry)();
+} intrtab[] = {
+ {"divide error", 0, intr_entry_div},
+ {"debug exception", 1, intr_entry_debug},
+ {"non-maskable interrupt", 2, intr_entry_nmi},
+ {"breakpoint", 3, intr_entry_bpt},
+ {"overflow", 4, intr_entry_ovf},
+ {"bounds check", 5, intr_entry_bound},
+ {"invalid opcode", 6, intr_entry_ill},
+ {"missing coprocessor", 7, intr_entry_nodev},
+ {"double fault", 8, intr_entry_dbl},
+ {"coprocessor segment overrun", 9, intr_entry_copseg},
+ {"invalid TSS", 10, intr_entry_tss},
+ {"segment not present", 11, intr_entry_segpres},
+ {"stack exception", 12, intr_entry_stack},
+ {"general protection", 13, intr_entry_prot},
+ {"page fault", 14, intr_entry_page},
+ {"floating point error", 16, intr_entry_fpu},
+ {"alignment check", 17, intr_entry_align},
+ {"machine check", 18, intr_entry_mce},
+ {"SIMD floating point error", 19, intr_entry_sse},
+ {"IRQ 0 (timer)", 32, intr_entry_irq0},
+ {"IRQ 1 (keyboard)", 33, intr_entry_irq1},
+ {"IRQ 2 (cascade)", 34, intr_entry_irq2},
+ {"IRQ 3 (UART 1)", 35, intr_entry_irq3},
+ {"IRQ 4 (UART 0)", 36, intr_entry_irq4},
+ {"IRQ 5", 37, intr_entry_irq5},
+ {"IRQ 6 (floppy)", 38, intr_entry_irq6},
+ {"IRQ 7 (parallel)", 39, intr_entry_irq7_verify},
+ {"IRQ 8 (RTC)", 40, intr_entry_irq8},
+ {"IRQ 9", 41, intr_entry_irq9},
+ {"IRQ 10", 42, intr_entry_irq10},
+ {"IRQ 11", 43, intr_entry_irq11},
+ {"IRQ 12 (PS/2 mouse)", 44, intr_entry_irq12},
+ {"IRQ 13 (coproc)", 45, intr_entry_irq13},
+ {"IRQ 14 (ATA 0)", 46, intr_entry_irq14},
+ {"IRQ 15 (ATA 1)", 47, intr_entry_irq15_verify}
+};
void intr_init(void)
{
+ int i, inum, type;
+ uint16_t sel_kcode = selector(SEL_KCODE, 0);
+
+ prog_pic(IRQ_OFFS);
+
+ for(i=0; i<256; i++) {
+ type = i < 32 ? GATE_TRAP : GATE_INTR;
+ desc_intr(idt + i, type, sel_kcode, (uint32_t)intr_entry_default, 0);
+ }
+ for(i=0; i<sizeof intrtab / sizeof *intrtab; i++) {
+ inum = intrtab[i].num;
+ type = inum < 32 ? GATE_TRAP : GATE_INTR;
+ desc_intr(idt + inum, type, sel_kcode, (uint32_t)intrtab[i].entry, 0);
+ }
set_idt(idt, sizeof idt - 1);
}
void intr_handler(int err, int num)
{
-}
+ if(intr_func[num]) {
+ intr_func[num]();
+ } else {
+ printf("unhandled interrupt: %d\n", num);
+ }
+ if(num >= IRQ_OFFS) {
+ end_of_irq(num - IRQ_OFFS);
+ }
+}
void set_gdt(void *addr, uint16_t limit);
-enum {
- SEG_KCODE = 1,
- SEG_KDATA = 2
-};
-
-#define NUM_SEG 3
+#define NUM_SEG 3
static struct desc gdt[NUM_SEG] __attribute__((aligned(8)));
void mem_init(void)
{
desc_seg(gdt, SEG_NULL, 0, 0, 0);
- desc_seg(gdt + SEG_KCODE, SEG_CODE, 0, 0xffffffff, 0);
- desc_seg(gdt + SEG_KDATA, SEG_DATA, 0, 0xffffffff, 0);
+ desc_seg(gdt + SEL_KCODE, SEG_CODE, 0, 0xffffffff, 0);
+ desc_seg(gdt + SEL_KDATA, SEG_DATA, 0, 0xffffffff, 0);
set_gdt(gdt, sizeof gdt - 1);
+
+ setup_selectors(selector(SEL_KCODE, 0), selector(SEL_KDATA, 0));
+}
+
+uint16_t selector(int idx, int rpl)
+{
+ return (idx << 3) | (rpl & 3);
}