Here is the code that sets up the IDT.
global lngmd_startextern kernel_mainextern gdt.datasection .textbits 64lngmd_start: mov ax, gdt.data mov ss, ax mov ds, ax mov es, ax mov fs, ax mov gs, ax call map_entries lidt [idt.pointer] sti ;call kernel_main ;int 0x00 jmp krnl_hltmap_entries: mov rbx, idt.map_exceptions: mov rdx, 0 mov r8, exception_handler mov rcx, 32 jmp .loop.map_irqs_pic1: mov rdx, 1 mov r8, isr_handler.pic1 mov rcx, 8 jmp .loop.map_irqs_pic2: mov rdx, 2 mov r8, isr_handler.pic2 mov rcx, 8.loop: mov rax, r8 mov word [rbx], ax shr rax, 16 mov word [rbx + 6], ax shr rax, 16 mov dword [rbx + 8], eax add rbx, 16 dec rcx ;jmp krnl_hlt ; This works as intended and halts the kernel, printing "a2" jne .loop jmp krnl_hlt ; this is supposed to print "a2" then halt, but causes an INVALID_OPCODE (0x6 in QEMU debugger) exception. Removing this jump causes the code to hang with no exceptions. test rdx, rdx je .map_irqs_pic1 dec rdx test rdx, rdx je .map_irqs_pic2 retidt:.exception_0: dw 0 dw 0x8 db 0 db 10001110b dw 0 dd 0 dd 0; --------------------------------; exceptions 1 - 30; --------------------------------.exception_31: dw 0 dw 0x8 db 0 db 10001110b dw 0 dd 0 dd 0.irq_0: dw 0 dw 0x8 db 0 db 10001110b dw 0 dd 0 dd 0; --------------------------------; irqs 1 - 14; --------------------------------.irq_15: dw 0 dw 0x8 db 0 db 10001110b dw 0 dd 0 dd 0.pointer: dw $ - idt - 1 dq idtexception_handler: jmp krnl_hltisr_handler:.pic1: mov ax, 0x20 out 0x20, ax iretq.pic2: mov ax, 0x20 out 0xa0, ax iretqkrnl_hlt: mov dword [0xb8000], 0x0c320c61 abbc: hlt nop jmp abbc
I have spent the last 5 hours trying different ways to get this IDT working through many different methods, and I don't normally ask questions, but it seems I've hit a dead end. If I've missed any required info or asked a "bad question", let me know and I will try to make it better.