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

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