--- /dev/null
+struc idt_entry
+.handler_low: resw 1
+.selector: resw 1
+.ist: resb 1
+.flags: resb 1
+.handler_high: resw 1
+.handler_highest: resd 1
+.reserved: resd 1
+endstruc
+
+align 16
+
+global set_idt_entry:function
+
+;void set_idt_entry(
+; struct idt_entry *entry, rdi
+; uintptr_t handler, rsi
+; uint16_t selector, rdx
+; uint8_t flags, rcx
+; uint8_t ist r8
+
+set_idt_entry:
+ mov [rdi + idt_entry.flags], cl
+ mov [rdi + idt_entry.ist], r8b
+ mov [rdi + idt_entry.selector], dx
+ mov [rdi + idt_entry.handler_low], si
+ shr rsi, 16
+ mov [rdi + idt_entry.handler_high], si
+ shr rsi, 16
+ mov [rdi + idt_entry.handler_highest], esi
+ mov [rdi + idt_entry.reserved], dword 0x0
+
+global load_idt:function
+
+load_idt:
+; size_t limit = sizeof(struct idt_entry) * length - 1;
+ shl rsi, 4
+ sub rsi, 1
+
+ sub rsp, 10
+ mov [rsp], si
+ mov [rsp + 2], rdi
+ lidt [rsp]
+ add rsp, 10
+ ret
+
+section .text
+
+extern interrupt_handler
+extern global_errno
+extern printk
+
+%macro makeisr 2
+global isr%1:function
+isr%1:
+ push %2 ; err_code
+ push %1 ; int_no
+ jmp interrupt_handler_prepare
+%endmacro
+
+%macro makeisr 1
+global isr%1:function
+isr%1:
+ ; error code pushed by processor
+ push %1 ; int_no
+ jmp interrupt_handler_prepare
+%endmacro
+
+%macro makeirq 2
+global irq%1:function
+irq%1:
+ push 0 ; err_code
+ push %2 ; int_no
+ jmp interrupt_handler_prepare
+%endmacro
+
+; create isr 0-7, which need an error code pushed
+%assign i 0
+%rep 8
+
+makeisr i,0
+
+%assign i i+1
+%endrep
+
+makeisr 8
+makeisr 9,0
+makeisr 10
+makeisr 11
+makeisr 12
+makeisr 13
+makeisr 14
+
+; make isr 15-31
+%assign i 15
+%rep 17
+makeisr i,0
+%assign i i+1
+%endrep
+
+; make irqs
+%assign i 32
+%assign j 0
+%rep 16
+makeirq j,i
+%assign i i+1
+%assign j j+1
+%endrep
+
+; make remaining interrupts
+%assign i 48
+%rep 208
+makeisr i,0
+%assign i i+1
+%endrep
+
+interrupt_handler_prepare:
+
+ push r15
+ push r14
+ push r13
+ push r12
+ push r11
+ push r10
+ push r9
+ push r8
+ push rax
+ push rcx
+ push rdx
+ push rbx
+ push rsp
+ push rbp
+ push rsi
+ push rdi
+
+ ; CR2 for page faults, always push for consistent frame
+ mov rbp, cr2
+ push rbp
+
+ mov eax, [qword global_errno]
+ push rax
+
+ mov rdi, rsp ; context stack frame pointer
+ mov rbx, rsp ; rbx is preserved by the abi, so save it
+ and rsp, 0xFFFFFFF0 ; should be sign extended
+ call interrupt_handler
+ mov rsp, rbx ; restore the stack
+
+load_interrupted_registers:
+ ; Restore the previous kernel errno.
+ pop rax
+ mov [qword global_errno], eax
+
+ add rsp, 8 ; remove CR2
+
+ pop rdi
+ pop rsi
+ pop rbp
+ add rsp, 8 ; skip rsp
+ pop rbx
+ pop rdx
+ pop rcx
+ pop rax
+ pop r8
+ pop r9
+ pop r10
+ pop r11
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+
+ ; Remove int_no and err_code
+ add rsp, 16
+
+ iretq
+;.size interrupt_handler_prepare, . - interrupt_handler_prepare
+
+global interrupt_handler_null:function
+
+align 16
+interrupt_handler_null:
+ iretq
+;.size interrupt_handler_null, . - interrupt_handler_null
+
+rfprintf: db 'rflags : %llx', 10, 0
+csprintf: db 'cs : %hx', 10, 0
+ripprintf: db 'rip : %llx', 10, 0
+rspprintf: db 'rsp : %llx', 10, 0
+ssprintf: db 'ss : %hx', 10, 0
+csvprintf: db 'gdt : %016llx', 10, 0
+
+global interrupts_enabled:function
+interrupts_enabled:
+ pushf
+ pop rax
+ shr rax, 9
+ and rax, 0x1
+ ret
+
+global enable_interrupts:function
+enable_interrupts:
+ sti
+ ret
+
+global disable_interrupts:function
+disable_interrupts:
+ cli
+ ret
+