+ ; Remap PIC
+ push rdx ; Save RDX
+ mov dx, 0x20
+ mov al, 0x11
+ out dx, al ; Init Command
+ mov dx, 0x21
+ mov al, 0xF0
+ out dx, al ; Offset (Start of IDT Range)
+ mov al, 0x04
+ out dx, al ; IRQ connected to Slave (00000100b) = IRQ2
+ mov al, 0x01
+ out dx, al ; Set Mode
+ mov al, 0x00
+ out dx, al ; Set Mode
+
+ mov dx, 0xA0
+ mov al, 0x11
+ out dx, al ; Init Command
+ mov dx, 0xA1
+ mov al, 0xF8
+ out dx, al ; Offset (Start of IDT Range)
+ mov al, 0x02
+ out dx, al ; IRQ Line connected to master
+ mov al, 0x01
+ out dx, al ; Set Mode
+ mov dl, 0x00
+ out dx, al ; Set Mode
+ pop rdx
+
+
+ ; Install IDT
+ mov rax, gIDTPtr
+ lidt [rax]
+
+ ; Re-install GDT (in higher address space)
+ mov rax, gGDTPtr
+ mov rcx, gGDT
+ mov QWORD [rax+2], rcx
+ lgdt [rax]
+
+ ; Start interrupts
+ sti
+
+ ; Initialise System Calls (SYSCALL/SYSRET)
+ ; Set IA32_EFER.SCE
+ mov ecx, 0xC0000080
+ rdmsr
+ or eax, 1
+ wrmsr
+ ; Set IA32_LSTAR (RIP of handler)
+ mov ecx, 0xC0000082 ; IA32_LSTAR
+ mov eax, SyscallStub - 0xFFFFFFFF00000000
+ mov edx, 0xFFFFFFFF
+ wrmsr
+ ; Set IA32_FMASK (flags mask)
+ mov ecx, 0xC0000084
+ rdmsr
+ mov eax, 0x202
+ wrmsr
+ ; Set IA32_STAR (Kernel/User CS)
+ mov ecx, 0xC0000081
+ rdmsr
+ mov edx, 0x8 | (0x18 << 16) ; Kernel CS (and Kernel DS/SS - 8), User CS
+ wrmsr
+
+ ret
+
+; int IRQ_AddHandler(int IRQ, void (*Handler)(int IRQ))
+; Return Values:
+; 0 on Success
+; -1 on an invalid IRQ Number
+; -2 when no slots are avaliable
+[global IRQ_AddHandler]
+IRQ_AddHandler:
+ ; RDI - IRQ Number
+ ; RSI - Callback
+
+ ; Check for RDI >= 16
+ cmp rdi, 16
+ jb .numOK
+ xor rax, rax
+ dec rax
+ jmp .ret
+.numOK:
+
+ ; Get handler base into RAX
+ lea rax, [rdi*4]
+ mov rcx, gaIRQ_Handlers
+ lea rax, [rcx+rax*8]
+
+ ; Find a free callback slot
+ %rep NUM_IRQ_CALLBACKS
+ mov rdx, [rax]
+ test rdx, rdx
+ jz .assign
+ add rax, 8
+ %endrep
+ ; None found, return -2
+ xor rax, rax
+ dec rax
+ dec rax
+ jmp .ret
+
+ ; Assign the IRQ Callback
+.assign:
+ ; A little bit of debug
+ push rdi
+ push rsi
+ push rax
+ sub rsp, 8
+ mov rcx, rdi ; IRQ Number
+ mov rdx, rsi ; Callback
+ mov rsi, rax ; Pointer
+ mov rdi, csIRQ_Assigned
+ call Log
+ add rsp, 8
+ pop rax
+ pop rsi
+ pop rdi
+
+ ; Assign and return
+ mov [rax], rsi
+ xor rax, rax
+
+.ret:
+ ret
+
+[section .rodata]
+csIRQ_Assigned:
+ db "IRQ %p := %p (IRQ %i)",0
+csIRQ_Fired:
+ db "IRQ %i fired",0
+[section .text]