;
[BITS 64]
+[extern Log]
+[extern gGDTPtr]
+[extern gGDT]
+
%define NUM_IRQ_CALLBACKS 4
MM_LOCALAPIC equ 0xFFFFFD0000000000
; Set an IDT entry to a callback
%macro SETIDT 2
mov rax, %2
- mov WORD [rdi + %1*16], ax
+ mov WORD [rdi + %1*16], ax
shr rax, 16
- mov WORD [rdi + %1*16 + 6], ax
+ 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
+ mov ax, WORD [rdi + %1*16 + 4]
+ or ax, 0x8000
+ mov WORD [rdi + %1*16 + 4], ax
%endmacro
; Install error handlers
%endrep
; Install IRQs
- SETIDT 0xF0, Irq0
+ SETIDT 0xF0, SchedulerIRQ
SETIDT 0xF1, Irq1
SETIDT 0xF2, Irq2
SETIDT 0xF3, Irq3
mov dx, 0x20
mov al, 0x11
out dx, al ; Init Command
- mov dx, 0x21
+ mov dx, 0x21
mov al, 0xF0
out dx, al ; Offset (Start of IDT Range)
- mov al, 0x04
+ mov al, 0x04
out dx, al ; IRQ connected to Slave (00000100b) = IRQ2
- mov al, 0x01
+ mov al, 0x01
out dx, al ; Set Mode
- mov al, 0x00
+ mov al, 0x00
out dx, al ; Set Mode
mov dx, 0xA0
mov al, 0x11
out dx, al ; Init Command
- mov dx, 0xA1
+ mov dx, 0xA1
mov al, 0xF8
out dx, al ; Offset (Start of IDT Range)
- mov al, 0x02
+ mov al, 0x02
out dx, al ; IRQ Line connected to master
- mov al, 0x01
+ mov al, 0x01
out dx, al ; Set Mode
- mov dl, 0x00
+ mov dl, 0x00
out dx, al ; Set Mode
pop rdx
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
; RDI - IRQ Number
; RSI - Callback
+ ; Check for RDI >= 16
cmp rdi, 16
jb .numOK
xor rax, rax
jmp .ret
.numOK:
- mov rax, rdi
- shr rax, 3+2
+ ; Get handler base into RAX
+ lea rax, [rdi*4]
mov rcx, gaIRQ_Handlers
- add rax, rcx
+ lea rax, [rcx+rax*8]
; Find a free callback slot
%rep NUM_IRQ_CALLBACKS
; 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:
[global IrqCommon]
IrqCommon:
PUSH_GPR
+ push gs
+ push fs
- mov rbx, [rsp+16*8] ; Calculate address
- shr rbx, 3+2 ; *8*4
+ 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
- add rbx, rax
+ lea rbx, [rax+rbx*8]
; Check all callbacks
+ sub rsp, 8 ; Shadow of argument
%assign i 0
%rep NUM_IRQ_CALLBACKS
; Get callback address
test rax, rax ; Check if it exists
jz .skip.%[i]
; Set RDI to IRQ number
- mov rdi, [rsp+16*8] ; Get 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
- mov al, 0x20
jb .skipAckSecondary
mov dx, 0x00A0
out dx, al
mov dx, 0x0020
out dx, al
+ pop fs
+ pop gs
POP_GPR
add rsp, 8*2
;xchg bx, bx
[extern Proc_Scheduler]
[global SchedulerIRQ]
+;
+; NOTE: Proc_Scheduler makes assumptions about the stack state when called
+;
SchedulerIRQ:
- ; TODO: Find Current CPU
+ push 0 ; Error code
+ push 0 ; IRQNum
PUSH_GPR
+ push gs
+ push fs
;PUSH_FPU
;PUSH_XMM
- xor rsi, rsi
- mov rdi, MM_LOCALAPIC+0x20
- mov esi, [rdi]
+ ; 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, 8*2
+ 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)