; ; ; [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 ; 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 [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 push gs push fs mov rbx, [rsp+(16+2)*8] ; Get interrupt number (16 GPRS + 2 SRs) ; xchg bx, bx ; Bochs Magic break (NOTE: will clear the high-bits of RBX) shl rbx, 2 ; *8*4 mov rax, gaIRQ_Handlers lea rbx, [rax+rbx*8] ; Check all callbacks sub rsp, 8 ; Shadow of argument %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+2+1)*8] ; Get IRQ number call rax ; Call .skip.%[i]: add rbx, 8 ; Next! %assign i i+1 %endrep add rsp, 8 ; ACK mov al, 0x20 mov rdi, [rsp+16*8] ; Get IRQ number cmp rdi, 8 jb .skipAckSecondary mov dx, 0x00A0 out dx, al .skipAckSecondary: mov dx, 0x0020 out dx, al pop fs pop gs POP_GPR add rsp, 8*2 ;xchg bx, bx iretq [extern Proc_Scheduler] [global SchedulerIRQ] ; ; NOTE: Proc_Scheduler makes assumptions about the stack state when called ; SchedulerIRQ: push 0 ; Error code push 0 ; IRQNum PUSH_GPR push gs push fs ;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 fs pop gs POP_GPR add rsp, 2*8 ; Dummy error code and IRQ num iretq [extern ci_offsetof_tThread_KernelStack] [extern SyscallHandler] [global SyscallStub] SyscallStub: mov rbp, dr0 mov ebx, [rel ci_offsetof_tThread_KernelStack] mov rbp, [rbp+rbx] ; Get kernel stack xchg rbp, rsp ; Swap stacks push rbp ; Save User RSP push rcx ; RIP push r11 ; RFLAGS ; RDI ; RSI ; RDX ; R10 (RCX for non syscall) ; R8 ; R9 sub rsp, (6+2)*8 mov [rsp+0x00], rax ; Number ; mov [rsp+0x08], rax ; Errno (don't care really) mov [rsp+0x10], rdi ; Arg1 mov [rsp+0x18], rsi ; Arg2 mov [rsp+0x20], rdx ; Arg3 mov [rsp+0x28], r10 ; Arg4 mov [rsp+0x30], r8 ; Arg5 mov [rsp+0x38], r9 ; Arg6 mov rdi, rsp sub rsp, 8 call SyscallHandler add rsp, 8 mov ebx, [rsp+8] ; Get errno mov rax, [rsp+0] ; Get return add rsp, (6+2)*8 pop r11 pop rcx pop rsp ; Change back to user stack sysret [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