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

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