27ba9137829b8fe507856972fde87aa61db922ea
[tpg/acess2.git] / Kernel / arch / x86_64 / desctab.asm
1 ;
2 ;
3 ;
4 %include "arch/x86_64/include/common.inc.asm"
5 [BITS 64]
6
7 [extern Log]
8 [extern gGDTPtr]
9 [extern gGDT]
10
11 %define NUM_IRQ_CALLBACKS       4
12
13 MM_LOCALAPIC    equ     0xFFFFFD0000000000
14
15 [section .text]
16 [global Desctab_Init]
17 Desctab_Init:   
18         ; Save to make following instructions smaller
19         mov rdi, gIDT
20         
21         ; Set an IDT entry to a callback
22         %macro SETIDT 2
23         mov rax, %2
24         mov WORD [rdi + %1*16], ax
25         shr rax, 16
26         mov WORD [rdi + %1*16 + 6], ax
27         shr rax, 16
28         mov DWORD [rdi + %1*16 + 8], eax
29         ; Enable
30         mov ax, WORD [rdi + %1*16 + 4]
31         or  ax, 0x8000
32         mov WORD [rdi + %1*16 + 4], ax
33         %endmacro
34         
35         ; Install error handlers
36         %macro SETISR 1
37         SETIDT %1, Isr%1
38         %endmacro
39         
40         %assign i 0
41         %rep 32
42         SETISR i
43         %assign i i+1
44         %endrep
45         
46         ; Install IRQs
47         SETIDT  0xF0, SchedulerIRQ
48         SETIDT  0xF1, Irq1
49         SETIDT  0xF2, Irq2
50         SETIDT  0xF3, Irq3
51         SETIDT  0xF4, Irq4
52         SETIDT  0xF5, Irq5
53         SETIDT  0xF6, Irq6
54         SETIDT  0xF7, Irq7
55         SETIDT  0xF8, Irq8
56         SETIDT  0xF9, Irq9
57         SETIDT  0xFA, Irq10
58         SETIDT  0xFB, Irq11
59         SETIDT  0xFC, Irq12
60         SETIDT  0xFD, Irq13
61         SETIDT  0xFE, Irq14
62         SETIDT  0xFF, Irq15
63
64         ; Remap PIC
65         push rdx        ; Save RDX
66         mov dx, 0x20
67         mov al, 0x11
68         out dx, al      ;       Init Command
69         mov dx, 0x21
70         mov al, 0xF0
71         out dx, al      ;       Offset (Start of IDT Range)
72         mov al, 0x04
73         out dx, al      ;       IRQ connected to Slave (00000100b) = IRQ2
74         mov al, 0x01
75         out dx, al      ;       Set Mode
76         mov al, 0x00
77         out dx, al      ;       Set Mode
78         
79         mov dx, 0xA0
80         mov al, 0x11
81         out dx, al      ;       Init Command
82         mov dx, 0xA1
83         mov al, 0xF8
84         out dx, al      ;       Offset (Start of IDT Range)
85         mov al, 0x02
86         out dx, al      ;       IRQ Line connected to master
87         mov al, 0x01
88         out dx, al      ;       Set Mode
89         mov dl, 0x00
90         out dx, al      ;       Set Mode
91         pop rdx
92         
93         
94         ; Install IDT
95         mov rax, gIDTPtr
96         lidt [rax]
97         
98         ; Re-install GDT (in higher address space)
99         mov rax, gGDTPtr
100         mov rcx, gGDT
101         mov QWORD [rax+2], rcx
102         lgdt [rax]
103         
104         ; Start interrupts
105         sti
106
107         ; Initialise System Calls (SYSCALL/SYSRET)
108         ; Set IA32_EFER.SCE
109         mov ecx, 0xC0000080
110         rdmsr
111         or eax, 1
112         wrmsr
113         ; Set IA32_LSTAR (RIP of handler)
114         mov ecx, 0xC0000082     ; IA32_LSTAR
115         mov eax, SyscallStub - 0xFFFFFFFF00000000
116         mov edx, 0xFFFFFFFF
117         wrmsr
118         ; Set IA32_FMASK (flags mask)
119         mov ecx, 0xC0000084
120         rdmsr
121         mov eax, 0x202
122         wrmsr
123         ; Set IA32_STAR (Kernel/User CS)
124         mov ecx, 0xC0000081
125         rdmsr
126         mov edx, 0x8 | (0x18 << 16)     ; Kernel CS (and Kernel DS/SS - 8), User CS
127         wrmsr
128         
129         ret
130
131 ; int IRQ_AddHandler(int IRQ, void (*Handler)(int IRQ), void *Ptr)
132 ; Return Values:
133 ;  0 on Success
134 ; -1 on an invalid IRQ Number
135 ; -2 when no slots are avaliable
136 [global IRQ_AddHandler]
137 IRQ_AddHandler:
138         ; RDI - IRQ Number
139         ; RSI - Callback
140         ; RDX - Ptr
141         
142         ; Check for RDI >= 16
143         cmp rdi, 16
144         jb .numOK
145         xor rax, rax
146         dec rax
147         jmp .ret
148 .numOK:
149
150         ; Get handler base into RAX
151         lea rax, [rdi*4]
152         mov rcx, gaIRQ_Handlers
153         lea rax, [rcx+rax*8]
154         
155         ; Find a free callback slot
156         %rep NUM_IRQ_CALLBACKS
157         mov rcx, [rax]
158         test rcx, rcx
159         jz .assign
160         add rax, 8
161         %endrep
162         ; None found, return -2
163         xor rax, rax
164         dec rax
165         dec rax
166         jmp .ret
167         
168         ; Assign the IRQ Callback
169 .assign:
170         ; A little bit of debug
171         push rdi
172         push rsi
173         push rax
174         push rdx
175         sub rsp, 8
176         mov rcx, rdi    ; IRQ Number
177         mov rdx, rsi    ; Callback
178         mov rsi, rax    ; Pointer
179         mov rdi, csIRQ_Assigned
180         call Log
181         add rsp, 8
182         pop rdx
183         pop rax
184         pop rsi
185         pop rdi
186
187         ; Assign and return
188         mov [rax], rsi
189         add rax, gaIRQ_DataPtrs - gaIRQ_Handlers
190         mov [rax], rdx
191         xor rax, rax
192
193 .ret:
194         ret
195         
196 [section .rodata]
197 csIRQ_Assigned:
198         db      "IRQ %p := %p (IRQ %i)",0
199 csIRQ_Fired:
200         db      "IRQ %i fired",0
201 [section .text]
202
203 %macro ISR_NOERRNO      1
204 Isr%1:
205         push    QWORD 0
206         push    QWORD %1
207         jmp     ErrorCommon
208 %endmacro
209 %macro ISR_ERRNO        1
210 Isr%1:
211         push    QWORD %1
212         jmp     ErrorCommon
213 %endmacro
214
215 ISR_NOERRNO     0;  0: Divide By Zero Exception
216 ISR_NOERRNO     1;  1: Debug Exception
217 ISR_NOERRNO     2;  2: Non Maskable Interrupt Exception
218 ISR_NOERRNO     3;  3: Int 3 Exception
219 ISR_NOERRNO     4;  4: INTO Exception
220 ISR_NOERRNO     5;  5: Out of Bounds Exception
221 ISR_NOERRNO     6;  6: Invalid Opcode Exception
222 ISR_NOERRNO     7;  7: Coprocessor Not Available Exception
223 ISR_ERRNO       8;  8: Double Fault Exception (With Error Code!)
224 ISR_NOERRNO     9;  9: Coprocessor Segment Overrun Exception
225 ISR_ERRNO       10; 10: Bad TSS Exception (With Error Code!)
226 ISR_ERRNO       11; 11: Segment Not Present Exception (With Error Code!)
227 ISR_ERRNO       12; 12: Stack Fault Exception (With Error Code!)
228 ISR_ERRNO       13; 13: General Protection Fault Exception (With Error Code!)
229 ISR_ERRNO       14; 14: Page Fault Exception (With Error Code!)
230 ISR_NOERRNO     15; 15: Reserved Exception
231 ISR_NOERRNO     16; 16: Floating Point Exception
232 ISR_NOERRNO     17; 17: Alignment Check Exception
233 ISR_NOERRNO     18; 18: Machine Check Exception
234 ISR_NOERRNO     19; 19: Reserved
235 ISR_NOERRNO     20; 20: Reserved
236 ISR_NOERRNO     21; 21: Reserved
237 ISR_NOERRNO     22; 22: Reserved
238 ISR_NOERRNO     23; 23: Reserved
239 ISR_NOERRNO     24; 24: Reserved
240 ISR_NOERRNO     25; 25: Reserved
241 ISR_NOERRNO     26; 26: Reserved
242 ISR_NOERRNO     27; 27: Reserved
243 ISR_NOERRNO     28; 28: Reserved
244 ISR_NOERRNO     29; 29: Reserved
245 ISR_NOERRNO     30; 30: Reserved
246 ISR_NOERRNO     31; 31: Reserved
247
248 [extern Error_Handler]
249 [global ErrorCommon]
250 ErrorCommon:
251         PUSH_GPR
252         push gs
253         push fs
254         ;PUSH_FPU
255         ;PUSH_XMM
256         
257         mov rdi, rsp
258         xchg bx, bx
259         call Error_Handler
260         
261         ;POP_XMM
262         ;POP_FPU
263         pop fs
264         pop gs
265         POP_GPR
266         add rsp, 2*8
267         iretq
268
269 %macro DEFIRQ   1
270 Irq%1:
271         push    0
272         push    %1
273         jmp     IrqCommon
274 %endmacro
275
276 %assign i 0
277 %rep 16
278 DEFIRQ  i
279 %assign i i+1
280 %endrep
281
282 [global IrqCommon]
283 IrqCommon:
284         PUSH_GPR
285         push gs
286         push fs
287
288 ;       mov rdi, csIRQ_Fired
289 ;       mov rsi, [rsp+(16+2)*8]
290 ;       call Log
291         
292         mov ebx, [rsp+(16+2)*8] ; Get interrupt number (16 GPRS + 2 SRs)
293 ;       xchg bx, bx     ; Bochs Magic break (NOTE: will clear the high-bits of RBX)
294         shl ebx, 2      ; *4
295         mov rax, gaIRQ_Handlers
296         lea rbx, [rax+rbx*8]
297         
298         ; Check all callbacks
299         sub rsp, 8      ; Shadow of argument
300         %assign i 0
301         %rep NUM_IRQ_CALLBACKS
302         ; Get callback address
303         mov rax, [rbx]
304         test rax, rax   ; Check if it exists
305         jz .skip.%[i]
306         ; Set RDI to IRQ number
307         mov rdi, [rsp+(16+2+1)*8]       ; Get IRQ number
308         mov rsi, [rbx-gaIRQ_Handlers+gaIRQ_DataPtrs]
309         call rax        ; Call
310 .skip.%[i]:
311         add rbx, 8      ; Next!
312         %assign i i+1
313         %endrep
314         add rsp, 8
315         
316         ; ACK
317         mov al, 0x20
318         mov rdi, [rsp+(16+2)*8] ; Get IRQ number
319         cmp rdi, 8
320         jb .skipAckSecondary
321         out 0xA0, al
322 .skipAckSecondary:
323         out 0x20, al
324         
325         pop fs
326         pop gs
327         POP_GPR
328         add rsp, 8*2
329         iretq
330
331 [extern Proc_Scheduler]
332 [global SchedulerIRQ]
333 ;
334 ; NOTE: Proc_Scheduler makes assumptions about the stack state when called 
335 ;
336 SchedulerIRQ:
337         push 0  ; Error code
338         push 0  ; IRQNum
339         PUSH_GPR
340         push gs
341         push fs
342         ;PUSH_FPU
343         ;PUSH_XMM
344         
345         ; Save Thread Pointer
346         mov rax, dr0
347         push rax
348         
349         mov rdi, dr1    ; Get the CPU Number
350         mov rsi, rsp    ; Save stack pointer
351         mov rdx, SchedulerIRQ.restoreState
352         ; Call the Scheduler
353         call Proc_Scheduler
354 .restoreState:
355         
356         ; Restore Thread Pointer
357         pop rax
358         mov dr0, rax
359         
360         ; Send EOI (To either the APIC or the PIC)
361         %if USE_MP
362         test ebx, ebx
363         jnz .sendEOI
364         %endif
365         ; PIC
366         mov al, 0x20
367         out 0x20, al            ; ACK IRQ
368         %if USE_MP
369         jmp .ret
370         ; APIC
371 .sendEOI:
372         mov eax, DWORD [gpMP_LocalAPIC]
373         mov DWORD [eax+0x0B0], 0
374         %endif
375 .ret:
376         
377         ;POP_XMM
378         ;POP_FPU
379         pop fs
380         pop gs
381         POP_GPR
382         add rsp, 2*8    ; Dummy error code and IRQ num
383 ;       xchg bx, bx
384         iretq
385
386 [extern ci_offsetof_tThread_KernelStack]
387 [extern SyscallHandler]
388 [global SyscallStub]
389 SyscallStub:
390         mov rbp, dr0
391         mov ebx, [rel ci_offsetof_tThread_KernelStack]
392         mov rbp, [rbp+rbx]      ; Get kernel stack
393         xchg rbp, rsp   ; Swap stacks
394
395         push rbp        ; Save User RSP
396         push rcx        ; RIP
397         push r11        ; RFLAGS
398
399         ; RDI
400         ; RSI
401         ; RDX
402         ; R10 (RCX for non syscall)
403         ; R8
404         ; R9
405         sub rsp, (6+2)*8
406         mov [rsp+0x00], rax     ; Number
407 ;       mov [rsp+0x08], rax     ; Errno (don't care really)
408         mov [rsp+0x10], rdi     ; Arg1
409         mov [rsp+0x18], rsi     ; Arg2
410         mov [rsp+0x20], rdx     ; Arg3
411         mov [rsp+0x28], r10     ; Arg4
412         mov [rsp+0x30], r8      ; Arg5
413         mov [rsp+0x38], r9      ; Arg6
414         
415         mov rdi, rsp
416         sub rsp, 8
417         call SyscallHandler
418         add rsp, 8
419         mov ebx, [rsp+8]        ; Get errno
420         mov rax, [rsp+0]        ; Get return
421         add rsp, (6+2)*8
422
423         pop r11
424         pop rcx
425         pop rsp         ; Change back to user stack
426         ; TODO: Determine if user is 64 or 32 bit
427
428 ;       xchg bx, bx     
429         db 0x48 ; REX, nasm doesn't have a sysretq opcode
430         sysret
431
432 [section .data]
433 gIDT:
434         ; 64-bit Interrupt Gate, CS = 0x8, IST0 (Disabled)
435         times 256       dd      0x00080000, 0x00000E00, 0, 0
436 gIDTPtr:
437         dw      256*16-1
438         dq      gIDT
439
440 gaIRQ_Handlers:
441         times   16*NUM_IRQ_CALLBACKS    dq      0
442 gaIRQ_DataPtrs:
443         times   16*NUM_IRQ_CALLBACKS    dq      0

UCC git Repository :: git.ucc.asn.au