Kernel/x86 - Added SSE/FPU state saving, not fully tested
[tpg/acess2.git] / Kernel / arch / x86 / proc.asm
1 ; AcessOS Microkernel Version
2 ; Start.asm
3
4 [bits 32]
5
6 %define SAVEFLAG_FPU    0x1
7
8 KERNEL_BASE     equ 0xC0000000
9
10 KSTACK_USERSTATE_SIZE   equ     (4+8+1+5)*4     ; SRegs, GPRegs, CPU, IRET
11
12 [section .text]
13
14 [global NewTaskHeader]
15 NewTaskHeader:
16         mov eax, [esp]
17         mov dr0, eax
18
19         mov eax, [esp+4]
20         add esp, 12     ; Thread, Function, Arg Count
21         call eax
22         
23         push eax        ; Ret val
24         push 0          ; 0 = This Thread
25         call Threads_Exit
26
27 [extern MM_Clone]
28 [global Proc_CloneInt]
29 Proc_CloneInt:
30         pusha
31         ; Save RSP
32         mov eax, [esp+0x20+4]
33         mov [eax], esp
34         call MM_Clone
35         ; Save CR3
36         mov esi, [esp+0x20+8]
37         mov [esi], eax
38         ; Undo the pusha
39         add esp, 0x20
40         mov eax, .newTask
41         ret
42 .newTask:
43         popa
44         xor eax, eax
45         ret
46
47 [global SwitchTasks]
48 ; + 4 = New RSP
49 ; + 8 = Old RSP save loc
50 ; +12 = New RIP
51 ; +16 = Old RIP save loc
52 ; +20 = CR3
53 SwitchTasks:
54         pusha
55         
56         ; Old IP
57         mov eax, [esp+0x20+16]
58         mov DWORD [eax], .restore
59         ; Old SP
60         mov eax, [esp+0x20+8]
61         mov [eax], esp
62
63         mov ecx, [esp+0x20+12]  ; New IP
64         mov eax, [esp+0x20+20]  ; New CR3
65         mov esp, [esp+0x20+ 4]  ; New SP
66         
67         test eax, eax
68         jz .setState
69         mov cr3, eax
70         invlpg [esp]
71         invlpg [esp+0x1000]
72 .setState:
73         jmp ecx
74
75 .restore:
76
77         popa
78         xor eax, eax
79         ret
80
81 [global Proc_InitialiseSSE]
82 Proc_InitialiseSSE:
83         mov eax, cr4
84         or eax, (1 << 9)|(1 << 10)      ; Set OSFXSR and OSXMMEXCPT
85         mov cr4, eax
86         mov eax, cr0
87         and ax, ~(1 << 2)       ; Clear EM
88         or eax, (1 << 1)        ; Set MP
89         mov eax, cr0
90         ret
91 [global Proc_DisableSSE]
92 Proc_DisableSSE:
93         mov eax, cr0
94         or ax, 1 << 3   ; Set TS
95         mov cr0, eax
96         ret
97 [global Proc_EnableSSE]
98 Proc_EnableSSE:
99         mov eax, cr0
100         and ax, ~(1 << 3)       ; Clear TS
101         mov cr0, eax
102         ret
103
104 [global Proc_SaveSSE]
105 Proc_SaveSSE:
106         mov eax, [esp+4]
107         fxsave [eax]
108         ret
109 [global Proc_RestoreSSE]
110 Proc_RestoreSSE:
111         mov eax, [esp+4]
112         fxrstor [eax]
113         ret
114
115 %if USE_MP
116 [extern giMP_TimerCount]
117 [extern gpMP_LocalAPIC]
118 [extern Isr240.jmp]
119 [global SetAPICTimerCount]
120 SetAPICTimerCount:
121         pusha
122         push ds
123         push es
124         push fs
125         push gs
126         
127         mov ax, 0x10
128         mov ds, ax
129         mov es, ax
130         mov fs, ax
131         mov gs, ax
132         
133         mov eax, [gpMP_LocalAPIC]
134         mov ecx, [eax+0x320]
135         test ecx, 0x00010000
136         jz .setTime
137         mov DWORD [eax+0x380], 0xFFFFFFFF       ; Set Initial Count
138         mov DWORD [eax+0x320], 0x000000F0       ; Enable the timer on IVT#0xEF (One Shot)
139         jmp .ret
140
141 .setTime:       
142         ; Get Timer Count
143         mov ecx, 0xFFFFFFFF
144         sub ecx, [eax+0x390]
145         mov DWORD [giMP_TimerCount], ecx
146         ; Disable APIC Timer
147         mov DWORD [eax+0x320], 0x000100EF
148         mov DWORD [eax+0x380], 0
149
150         ; Update Timer IRQ to the IRQ code
151         mov eax, SchedulerBase
152         sub eax, Isr240.jmp+5
153         mov DWORD [Isr240.jmp+1], eax
154
155         ;xchg bx, bx    ; MAGIC BREAK
156 .ret:
157         mov dx, 0x20
158         mov al, 0x20
159         out dx, al              ; ACK IRQ
160         pop gs
161         pop fs
162         pop es
163         pop ds
164         popa
165         add esp, 4      ; CPU ID
166         ; No Error code / int num
167         iret
168 %endif
169 ; --------------
170 ; Task Scheduler
171 ; --------------
172 [extern Proc_Scheduler]
173 [global SchedulerBase]
174 SchedulerBase:
175         pusha
176         push ds
177         push es
178         push fs
179         push gs
180         
181         pushf
182         and BYTE [esp+1], 0xFE  ; Clear Trap Flag
183         popf
184         
185         mov eax, dr0
186         push eax        ; Debug Register 0, Current Thread
187         
188         mov ax, 0x10
189         mov ds, ax
190         mov es, ax
191         mov fs, ax
192         mov gs, ax
193         
194         %if USE_MP
195         call GetCPUNum
196         mov ebx, eax
197         push eax        ; Push as argument
198         %else
199         push 0
200         %endif
201         
202         call Proc_Scheduler
203 [global scheduler_return]
204 scheduler_return:       ; Used by some hackery in Proc_DumpThreadCPUState
205         
206         add esp, 4      ; Remove CPU Number (thread is poped later)
207
208         %if USE_MP
209         test ebx, ebx
210         jnz .sendEOI
211         %endif
212         
213         mov al, 0x20
214         out 0x20, al            ; ACK IRQ
215         %if USE_MP
216         jmp .ret
217         
218 .sendEOI:
219         mov eax, DWORD [gpMP_LocalAPIC]
220         mov DWORD [eax+0x0B0], 0
221         %endif
222 .ret:
223         pop eax ; Debug Register 0, Current Thread
224         mov dr0, eax
225
226         pop gs
227         pop fs
228         pop es
229         pop ds
230         
231         popa
232         add esp, 4*2    ; CPU ID + Dummy error code
233         ; No Error code / int num
234         iret
235
236 [extern Proc_Clone]
237 [extern Threads_Exit]
238 [global SpawnTask]
239 SpawnTask:
240         ; Call Proc_Clone with Flags=0
241         xor eax, eax
242 ;       push eax
243         push eax
244         call Proc_Clone
245         add esp, 8      ; Remove arguments from stack
246         
247         test eax, eax
248         jnz .parent
249         
250         ; In child, so now set up stack frame
251         mov ebx, [esp+4]        ; Child Function
252         mov edx, [esp+8]        ; Argument
253         ; Child Function
254         push edx        ; Argument
255         call ebx        ; Function
256         ; Kill thread once done
257         push eax        ; Exit Code
258         push   0        ; Kill this thread
259         call Threads_Exit       ; Kill Thread
260         
261 .parent:
262         ret
263
264 ; void Proc_ReturnToUser(void *Method, Uint Parameter)
265 ; Calls a user fault handler
266 ;
267 [global Proc_ReturnToUser]
268 [extern Proc_GetCurThread]
269 Proc_ReturnToUser:
270         push ebp
271         mov ebp, esp
272         ; [EBP+8]: handler to use
273         ; [EBP+12]: parameter
274         ; [EBP+16]: kernel stack top
275         
276         ;call Proc_GetCurThread
277         
278         ; EAX is the current thread
279         ;mov ebx, eax
280         ;mov eax, [ebx+12*4]    ; Get Kernel Stack
281         mov eax, [ebp+16]       ; Get Kernel Stack
282         sub eax, KSTACK_USERSTATE_SIZE
283         
284         ;
285         ; NOTE: This can cause corruption if the signal happens while the user
286         ;       has called a kernel operation.
287         ; Good thing this can only be called on a user fault.
288         ;
289         
290         ; Validate user ESP
291         ; - Page Table
292         mov edx, [eax+KSTACK_USERSTATE_SIZE-12] ; User ESP is at top of kstack - 3*4
293         mov ecx, edx
294         shr ecx, 22
295         test BYTE [0xFC3F0000+ecx*4], 1
296         jnz .justKillIt
297         ; - Page
298         mov ecx, edx
299         shr ecx, 12
300         test BYTE [0xFC000000+ecx*4], 1
301         jnz .justKillIt
302         ; Adjust
303         sub edx, 8
304         ; - Page Table
305         mov ecx, edx
306         shr ecx, 22
307         test BYTE [0xFC3F0000+ecx*4], 1
308         jnz .justKillIt
309         ; - Page
310         mov ecx, edx
311         shr ecx, 12
312         test BYTE [0xFC000000+ecx*4], 1
313         jnz .justKillIt
314         
315         ; Get and alter User SP
316         mov edi, edx
317         mov edx, [ebp+12]       ; Get parameter
318         mov [edi+4], edx        ; save to user stack
319         mov [edi], DWORD User_Syscall_RetAndExit        ; Return Address
320         
321         ; Restore Segment Registers
322         mov ax, 0x23
323         mov ds, ax
324         mov es, ax
325         mov fs, ax
326         mov gs, ax
327         
328         push 0x23       ; SS
329         push edi        ; ESP
330         push 0x202      ; EFLAGS (IP and Rsvd)
331         push 0x1B       ; CS
332         mov eax, [ebp+8]        ; Method to call
333         push eax        ; EIP
334         
335         iret
336         
337         ; Just kill the bleeding thing
338         ; (I know it calls int 0xAC in kernel mode, but meh)
339 .justKillIt:
340         xor eax, eax
341         xor ebx, ebx
342         dec ebx ; EBX = -1
343         int 0xAC
344
345 [global GetCPUNum]
346 GetCPUNum:      ; TODO: Store in debug registers
347 ;       xor eax, eax
348 ;       str ax
349 ;       sub ax, 0x30
350 ;       shr ax, 3       ; ax /= 8
351         mov eax, dr1
352         ret
353
354 [extern GetEIP]
355 [global GetEIP_Sched]
356 [global GetEIP_Sched_ret]
357 GetEIP_Sched_ret equ GetEIP_Sched.ret
358 GetEIP_Sched:
359         call GetEIP
360 GetEIP_Sched.ret:
361         ret
362
363 ; Usermode code exported by the kernel
364 [section .usertext]
365 ; Export a place for the user to jump to to call a syscall
366 ; - Allows the kernel to change the method easily
367 User_Syscall:
368         xchg bx, bx     ; MAGIC BREAKPOINT
369         int 0xAC
370
371 ; A place to return to and exit
372 User_Syscall_RetAndExit:
373         push eax
374         call User_Syscall_Exit
375 User_Syscall_Exit:
376         xor eax, eax
377         mov ebx, [esp+4]
378         int 0xAC

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