; ; ; [BITS 64] [extern Log] [extern gGDTPtr] [extern gGDT] %define NUM_IRQ_CALLBACKS 4 MM_LOCALAPIC equ 0xFFFFFD0000000000 %macro PUSH_GPR 0 mov [rsp-0x60], rsp mov [rsp-0x08], r15 mov [rsp-0x10], r14 mov [rsp-0x18], r13 mov [rsp-0x20], r12 mov [rsp-0x28], r11 mov [rsp-0x30], r10 mov [rsp-0x38], r9 mov [rsp-0x40], r8 mov [rsp-0x48], rdi mov [rsp-0x50], rsi mov [rsp-0x58], rbp mov [rsp-0x68], rbx mov [rsp-0x70], rdx mov [rsp-0x78], rcx mov [rsp-0x80], rax sub rsp, 0x80 %endmacro %macro POP_GPR 0 add rsp, 0x80 mov r15, [rsp-0x08] mov r14, [rsp-0x10] mov r13, [rsp-0x18] mov r12, [rsp-0x20] mov r11, [rsp-0x28] mov r10, [rsp-0x30] mov r9, [rsp-0x38] mov r8, [rsp-0x40] mov rdi, [rsp-0x48] mov rsi, [rsp-0x50] mov rbp, [rsp-0x58] ;mov rsp, [rsp-0x60] mov rbx, [rsp-0x68] mov rdx, [rsp-0x70] mov rcx, [rsp-0x78] mov rax, [rsp-0x80] %endmacro [section .text] [global Desctab_Init] Desctab_Init: ; Save to make following instructions smaller mov rdi, gIDT ; Set an IDT entry to a callback %macro SETIDT 2 mov rax, %2 mov WORD [rdi + %1*16], ax shr rax, 16 mov WORD [rdi + %1*16 + 6], ax shr rax, 16 mov DWORD [rdi + %1*16 + 8], eax ; Enable mov ax, WORD [rdi + %1*16 + 4] or ax, 0x8000 mov WORD [rdi + %1*16 + 4], ax %endmacro ; Install error handlers %macro SETISR 1 SETIDT %1, Isr%1 %endmacro %assign i 0 %rep 32 SETISR i %assign i i+1 %endrep ; Install IRQs SETIDT 0xF0, SchedulerIRQ SETIDT 0xF1, Irq1 SETIDT 0xF2, Irq2 SETIDT 0xF3, Irq3 SETIDT 0xF4, Irq4 SETIDT 0xF5, Irq5 SETIDT 0xF6, Irq6 SETIDT 0xF7, Irq7 SETIDT 0xF8, Irq8 SETIDT 0xF9, Irq9 SETIDT 0xFA, Irq10 SETIDT 0xFB, Irq11 SETIDT 0xFC, Irq12 SETIDT 0xFD, Irq13 SETIDT 0xFE, Irq14 SETIDT 0xFF, Irq15 ; 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 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 cmp rdi, 16 jb .numOK xor rax, rax dec rax jmp .ret .numOK: mov rax, rdi shr rax, 3+2 mov rcx, gaIRQ_Handlers add rax, rcx ; 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 mov [rax], rsi xor rax, rax .ret: ret [section .rodata] csIRQ_Assigned: db "IRQ %p := %p (IRQ %i)",0 [section .text] %macro ISR_NOERRNO 1 Isr%1: push QWORD 0 push QWORD %1 jmp ErrorCommon %endmacro %macro ISR_ERRNO 1 Isr%1: push QWORD %1 jmp ErrorCommon %endmacro ISR_NOERRNO 0; 0: Divide By Zero Exception ISR_NOERRNO 1; 1: Debug Exception ISR_NOERRNO 2; 2: Non Maskable Interrupt Exception ISR_NOERRNO 3; 3: Int 3 Exception ISR_NOERRNO 4; 4: INTO Exception ISR_NOERRNO 5; 5: Out of Bounds Exception ISR_NOERRNO 6; 6: Invalid Opcode Exception ISR_NOERRNO 7; 7: Coprocessor Not Available Exception ISR_ERRNO 8; 8: Double Fault Exception (With Error Code!) ISR_NOERRNO 9; 9: Coprocessor Segment Overrun Exception ISR_ERRNO 10; 10: Bad TSS Exception (With Error Code!) ISR_ERRNO 11; 11: Segment Not Present Exception (With Error Code!) ISR_ERRNO 12; 12: Stack Fault Exception (With Error Code!) ISR_ERRNO 13; 13: General Protection Fault Exception (With Error Code!) ISR_ERRNO 14; 14: Page Fault Exception (With Error Code!) ISR_NOERRNO 15; 15: Reserved Exception ISR_NOERRNO 16; 16: Floating Point Exception ISR_NOERRNO 17; 17: Alignment Check Exception ISR_NOERRNO 18; 18: Machine Check Exception ISR_NOERRNO 19; 19: Reserved ISR_NOERRNO 20; 20: Reserved ISR_NOERRNO 21; 21: Reserved ISR_NOERRNO 22; 22: Reserved ISR_NOERRNO 23; 23: Reserved ISR_NOERRNO 24; 24: Reserved ISR_NOERRNO 25; 25: Reserved ISR_NOERRNO 26; 26: Reserved ISR_NOERRNO 27; 27: Reserved ISR_NOERRNO 28; 28: Reserved ISR_NOERRNO 29; 29: Reserved ISR_NOERRNO 30; 30: Reserved ISR_NOERRNO 31; 31: Reserved [extern Error_Handler] [global ErrorCommon] ErrorCommon: PUSH_GPR push gs push fs ;PUSH_FPU ;PUSH_XMM mov rdi, rsp xchg bx, bx call Error_Handler ;POP_XMM ;POP_FPU pop fs pop gs POP_GPR add rsp, 2*8 iretq %macro DEFIRQ 1 Irq%1: push 0 push %1 jmp IrqCommon %endmacro %assign i 0 %rep 16 DEFIRQ i %assign i i+1 %endrep [global IrqCommon] IrqCommon: PUSH_GPR mov rbx, [rsp+16*8] ; Calculate address shr rbx, 3+2 ; *8*4 mov rax, gaIRQ_Handlers add rbx, rax ; Check all callbacks %assign i 0 %rep NUM_IRQ_CALLBACKS ; Get callback address mov rax, [rbx] test rax, rax ; Check if it exists jz .skip.%[i] ; Set RDI to IRQ number mov rdi, [rsp+16*8] ; Get IRQ number call rax ; Call .skip.%[i]: add rbx, 8 ; Next! %assign i i+1 %endrep ; ACK mov rdi, [rsp+16*8] ; Get IRQ number cmp rdi, 8 mov al, 0x20 jb .skipAckSecondary mov dx, 0x00A0 out dx, al .skipAckSecondary: mov dx, 0x0020 out dx, al POP_GPR add rsp, 8*2 ;xchg bx, bx iretq [extern Proc_Scheduler] [global SchedulerIRQ] SchedulerIRQ: PUSH_GPR ;PUSH_FPU ;PUSH_XMM ; Save Thread Pointer mov rax, dr0 push rax ; Get the CPU Number mov rdi, dr1 ; Call the Scheduler call Proc_Scheduler ; Restore Thread Pointer pop rax mov dr0, rax ; Send EOI (To either the APIC or the PIC) %if USE_MP test ebx, ebx jnz .sendEOI %endif ; PIC mov al, 0x20 out 0x20, al ; ACK IRQ %if USE_MP jmp .ret ; APIC .sendEOI: mov eax, DWORD [gpMP_LocalAPIC] mov DWORD [eax+0x0B0], 0 %endif .ret: ;POP_XMM ;POP_FPU POP_GPR iretq [section .data] gIDT: ; 64-bit Interrupt Gate, CS = 0x8, IST0 (Disabled) times 256 dd 0x00080000, 0x00000E00, 0, 0 gIDTPtr: dw 256*16-1 dq gIDT gaIRQ_Handlers: times 16*NUM_IRQ_CALLBACKS dq 0