diff --git a/kernel/arch/i386/interrupts.nim b/kernel/arch/i386/interrupts.nim new file mode 100644 index 0000000..25d6082 --- /dev/null +++ b/kernel/arch/i386/interrupts.nim @@ -0,0 +1,171 @@ +import macros, serial +type + IDTEntry{.packed.} = object + base_low: uint16 + kernel_selector: uint16 + zero: uint8 + flags: uint8 + base_high: uint16 + IDTPointer{.packed.} = object + limit: uint16 + base: uint32 + IDT{.packed.} = object + descriptor: IDTPointer + entries: array[0..255, IDTEntry] + Registers{.packed.} = object + ds: uint32 # Data segment selector + edi, esi, ebp, esp, ebx, edx, ecx, eax: uint32 # Pushed by pusha. + int_no, err_code: uint32 # Interrupt number and error code (if applicable) + eip, cs, eflags, useresp, ss: uint32 # Pushed by the processor automatically. + +var + idt: IDT + idtAddr: uint32 = cast[uint32](idt.addr) + +{.push stackTrace:off.} +proc idtFlush(){.inline,asmNoStackFrame.} = + asm """ + lidt [`idtAddr`] + ret + """ +{.pop.} + +proc isrHandler(registers: Registers){.exportc.} = + serial.write("Recieved interrupt:") + serial.write(registers.int_no) + serial.write("\L") + +proc isrCommon() = + asm """ + pusha + movw %ax, %ds + push %eax + movw $0x10, %ax + movw %ds, %ax + movw %es, %ax + movw %fs, %ax + movw %gs, %ax + call `isrHandler` + pop %eax + movw %ds, %ax + movw %es, %ax + movw %fs, %ax + movw %gs, %ax + popa + add $8, %esp + sti + iret + """ + +macro generateISR(code: static[uint8], isError: static[bool]): typed = + result = nnkStmtList.newTree( + nnkProcDef.newTree( + newIdentNode("isr" & $code), + newEmptyNode(), + newEmptyNode(), + nnkFormalParams.newTree( + newEmptyNode() + ), + newEmptyNode(), + newEmptyNode(), + nnkStmtList.newTree( + nnkAsmStmt.newTree( + newEmptyNode(), + newLit("cli\x0A" & (if isError: "" else: "push 0\x0A") & "push " & $code & "\x0A") + ), + nnkCall.newTree( + newIdentNode("isrCommon") + ) + ) + ) + ) + +proc idtSetGate(num: uint8, base: uint32, sel: uint16, flags: uint8) = + idt.entries[num].base_low = uint16(base and 0xFFFF) + idt.entries[num].base_high = uint16((base shr 16) and 0xFFFF) + idt.entries[num].zero = 0 + idt.entries[num].flags = flags + idt.entries[num].kernel_selector = sel + +# Would like to generate these in a loop, but apparently +# Error: type mismatch: got +# but expected one of: +# macro generateISR(code: static[uint8]; isError: static[bool]): typed +# first type mismatch at position: 1 +# required type: static[uint8] +# but expression 'uint8(i)' is of type: uint8 + +static: + generateISR(0, false) + generateISR(1, false) + generateISR(2, false) + generateISR(3, false) + generateISR(4, false) + generateISR(5, false) + generateISR(6, false) + generateISR(7, false) + generateISR(8, true) + generateISR(9, false) + generateISR(10, true) + generateISR(11, true) + generateISR(12, true) + generateISR(13, true) + generateISR(14, true) + generateISR(15, false) + generateISR(16, false) + generateISR(17, false) + generateISR(18, false) + generateISR(19, false) + generateISR(20, false) + generateISR(21, false) + generateISR(22, false) + generateISR(23, false) + generateISR(24, false) + generateISR(25, false) + generateISR(26, false) + generateISR(27, false) + generateISR(28, false) + generateISR(29, false) + generateISR(30, false) + generateISR(31, false) + +let + selector: uint16 = 0x08 + flags: uint8 = 0x8E + +proc idtInstall*() = + idt.descriptor.limit = uint16(sizeof(IDTEntry) * idt.entries.len) - 1 + idt.descriptor.base = cast[uint32](idt.entries.addr) + idtSetGate(0, cast[uint32](isr0) ,selector, flags) + idtSetGate(1, cast[uint32](isr1) ,selector, flags) + idtSetGate(2, cast[uint32](isr2) ,selector, flags) + idtSetGate(3, cast[uint32](isr3) ,selector, flags) + idtSetGate(4, cast[uint32](isr4) ,selector, flags) + idtSetGate(5, cast[uint32](isr5) ,selector, flags) + idtSetGate(6, cast[uint32](isr6) ,selector, flags) + idtSetGate(7, cast[uint32](isr7) ,selector, flags) + idtSetGate(8, cast[uint32](isr8) ,selector, flags) + idtSetGate(9, cast[uint32](isr9) ,selector, flags) + idtSetGate(10, cast[uint32](isr10) ,selector, flags) + idtSetGate(11, cast[uint32](isr11) ,selector, flags) + idtSetGate(12, cast[uint32](isr12) ,selector, flags) + idtSetGate(13, cast[uint32](isr13) ,selector, flags) + idtSetGate(14, cast[uint32](isr14) ,selector, flags) + idtSetGate(15, cast[uint32](isr15) ,selector, flags) + idtSetGate(16, cast[uint32](isr16) ,selector, flags) + idtSetGate(17, cast[uint32](isr17) ,selector, flags) + idtSetGate(18, cast[uint32](isr18) ,selector, flags) + idtSetGate(19, cast[uint32](isr19) ,selector, flags) + idtSetGate(20, cast[uint32](isr20) ,selector, flags) + idtSetGate(21, cast[uint32](isr21) ,selector, flags) + idtSetGate(22, cast[uint32](isr22) ,selector, flags) + idtSetGate(23, cast[uint32](isr23) ,selector, flags) + idtSetGate(24, cast[uint32](isr24) ,selector, flags) + idtSetGate(25, cast[uint32](isr25) ,selector, flags) + idtSetGate(26, cast[uint32](isr26) ,selector, flags) + idtSetGate(27, cast[uint32](isr27) ,selector, flags) + idtSetGate(28, cast[uint32](isr28) ,selector, flags) + idtSetGate(29, cast[uint32](isr29) ,selector, flags) + idtSetGate(30, cast[uint32](isr30) ,selector, flags) + idtSetGate(31, cast[uint32](isr31) ,selector, flags) + idtFlush() \ No newline at end of file diff --git a/kernel/kernel.nim b/kernel/kernel.nim index 3d1b75e..ea28069 100644 --- a/kernel/kernel.nim +++ b/kernel/kernel.nim @@ -2,7 +2,7 @@ {.passL: "-ffreestanding -target i386 -nostdlib -T arch/i386/linker.ld".} {.passC: "-ffreestanding -nostdlib --target=i386-pc-none-elf -march=i386".} -import tty, gdt, serial +import tty, gdt, interrupts, serial type MemoryPointer{.unchecked.} = ptr array[0, char] @@ -23,6 +23,8 @@ proc kernelMain() {.exportc: "kernel_main"}= serial.write("Booting OS\L") gdt.gdtInstall() serial.write("GDT installed\L") + interrupts.idtInstall() + serial.write("IDT installed\L") terminalInitialize() terminalWrite("Hello World!\L") terminalWrite("MAX_INT:") @@ -32,3 +34,6 @@ proc kernelMain() {.exportc: "kernel_main"}= for i in 0..22: terminalWrite(i) terminalWrite('\L') + asm """ + int $0x3 + """