Kernel - Fixing and breaking SMP related stuff
[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, 8      ; CPU ID / Error Code
166         iret
167 %endif
168 ; --------------
169 ; Task Scheduler
170 ; --------------
171 [extern Proc_Scheduler]
172 [global SchedulerBase]
173 SchedulerBase:
174         pusha
175         push ds
176         push es
177         push fs
178         push gs
179         
180         pushf
181         and BYTE [esp+1], 0xFE  ; Clear Trap Flag
182         popf
183         
184         mov eax, dr0
185         push eax        ; Debug Register 0, Current Thread
186         
187         mov ax, 0x10
188         mov ds, ax
189         mov es, ax
190         mov fs, ax
191         mov gs, ax
192         
193         %if USE_MP
194         call GetCPUNum
195         mov ebx, eax
196         push eax        ; Push as argument
197         %else
198         push 0
199         %endif
200         
201         call Proc_Scheduler
202 [global scheduler_return]
203 scheduler_return:       ; Used by some hackery in Proc_DumpThreadCPUState
204         
205         add esp, 4      ; Remove CPU Number (thread is poped later)
206
207         %if USE_MP
208         test ebx, ebx
209         jnz .sendEOI
210         %endif
211         
212         mov al, 0x20
213         out 0x20, al            ; ACK IRQ
214         %if USE_MP
215         jmp .ret
216         
217 .sendEOI:
218         mov eax, DWORD [gpMP_LocalAPIC]
219         mov DWORD [eax+0x0B0], 0
220         %endif
221 .ret:
222         pop eax ; Debug Register 0, Current Thread
223         mov dr0, eax
224
225         pop gs
226         pop fs
227         pop es
228         pop ds
229         
230         popa
231         add esp, 4*2    ; CPU ID + Dummy error code
232         ; No Error code / int num
233         iret
234
235 [extern Proc_Clone]
236 [extern Threads_Exit]
237 [global SpawnTask]
238 SpawnTask:
239         ; Call Proc_Clone with Flags=0
240         xor eax, eax
241 ;       push eax
242         push eax
243         call Proc_Clone
244         add esp, 8      ; Remove arguments from stack
245         
246         test eax, eax
247         jnz .parent
248         
249         ; In child, so now set up stack frame
250         mov ebx, [esp+4]        ; Child Function
251         mov edx, [esp+8]        ; Argument
252         ; Child Function
253         push edx        ; Argument
254         call ebx        ; Function
255         ; Kill thread once done
256         push eax        ; Exit Code
257         push   0        ; Kill this thread
258         call Threads_Exit       ; Kill Thread
259         
260 .parent:
261         ret
262
263 ; void Proc_ReturnToUser(void *Method, Uint Parameter)
264 ; Calls a user fault handler
265 ;
266 [global Proc_ReturnToUser]
267 [extern Proc_GetCurThread]
268 Proc_ReturnToUser:
269         push ebp
270         mov ebp, esp
271         ; [EBP+8]: handler to use
272         ; [EBP+12]: parameter
273         ; [EBP+16]: kernel stack top
274         
275         ;call Proc_GetCurThread
276         
277         ; EAX is the current thread
278         ;mov ebx, eax
279         ;mov eax, [ebx+12*4]    ; Get Kernel Stack
280         mov eax, [ebp+16]       ; Get Kernel Stack
281         sub eax, KSTACK_USERSTATE_SIZE
282         
283         ;
284         ; NOTE: This can cause corruption if the signal happens while the user
285         ;       has called a kernel operation.
286         ; Good thing this can only be called on a user fault.
287         ;
288         
289         ; Validate user ESP
290         ; - Page Table
291         mov edx, [eax+KSTACK_USERSTATE_SIZE-12] ; User ESP is at top of kstack - 3*4
292         mov ecx, edx
293         shr ecx, 22
294         test BYTE [0xFC3F0000+ecx*4], 1
295         jnz .justKillIt
296         ; - Page
297         mov ecx, edx
298         shr ecx, 12
299         test BYTE [0xFC000000+ecx*4], 1
300         jnz .justKillIt
301         ; Adjust
302         sub edx, 8
303         ; - Page Table
304         mov ecx, edx
305         shr ecx, 22
306         test BYTE [0xFC3F0000+ecx*4], 1
307         jnz .justKillIt
308         ; - Page
309         mov ecx, edx
310         shr ecx, 12
311         test BYTE [0xFC000000+ecx*4], 1
312         jnz .justKillIt
313         
314         ; Get and alter User SP
315         mov edi, edx
316         mov edx, [ebp+12]       ; Get parameter
317         mov [edi+4], edx        ; save to user stack
318         mov [edi], DWORD User_Syscall_RetAndExit        ; Return Address
319         
320         ; Restore Segment Registers
321         mov ax, 0x23
322         mov ds, ax
323         mov es, ax
324         mov fs, ax
325         mov gs, ax
326         
327         push 0x23       ; SS
328         push edi        ; ESP
329         push 0x202      ; EFLAGS (IP and Rsvd)
330         push 0x1B       ; CS
331         mov eax, [ebp+8]        ; Method to call
332         push eax        ; EIP
333         
334         iret
335         
336         ; Just kill the bleeding thing
337         ; (I know it calls int 0xAC in kernel mode, but meh)
338 .justKillIt:
339         xor eax, eax
340         xor ebx, ebx
341         dec ebx ; EBX = -1
342         int 0xAC
343
344 [global GetCPUNum]
345 GetCPUNum:      ; TODO: Store in debug registers
346 ;       xor eax, eax
347 ;       str ax
348 ;       sub ax, 0x30
349 ;       shr ax, 3       ; ax /= 8
350         mov eax, dr1
351         ret
352
353 [extern GetEIP]
354 [global GetEIP_Sched]
355 [global GetEIP_Sched_ret]
356 GetEIP_Sched_ret equ GetEIP_Sched.ret
357 GetEIP_Sched:
358         call GetEIP
359 GetEIP_Sched.ret:
360         ret
361
362 ; Usermode code exported by the kernel
363 [section .usertext]
364 ; Export a place for the user to jump to to call a syscall
365 ; - Allows the kernel to change the method easily
366 User_Syscall:
367         xchg bx, bx     ; MAGIC BREAKPOINT
368         int 0xAC
369
370 ; A place to return to and exit
371 User_Syscall_RetAndExit:
372         push eax
373         call User_Syscall_Exit
374 User_Syscall_Exit:
375         xor eax, eax
376         mov ebx, [esp+4]
377         int 0xAC
378
379 ; vim: ft=nasm, ts=8

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