8da797110977532a8e0c7f56f6fe8e28a4cac5d9
[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         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         add esp, 0x20
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         %if USE_MP
219         jmp .ret
220         
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         pop gs
230         pop fs
231         pop es
232         pop ds
233         
234         popa
235         add esp, 4*2    ; CPU ID + Dummy error code
236         ; No Error code / int num
237         iret
238
239 [extern Proc_Clone]
240 [extern Threads_Exit]
241 [global SpawnTask]
242 SpawnTask:
243         ; Call Proc_Clone with Flags=0
244         xor eax, eax
245 ;       push eax
246         push eax
247         call Proc_Clone
248         add esp, 8      ; Remove arguments from stack
249         
250         test eax, eax
251         jnz .parent
252         
253         ; In child, so now set up stack frame
254         mov ebx, [esp+4]        ; Child Function
255         mov edx, [esp+8]        ; Argument
256         ; Child Function
257         push edx        ; Argument
258         call ebx        ; Function
259         ; Kill thread once done
260         push eax        ; Exit Code
261         push   0        ; Kill this thread
262         call Threads_Exit       ; Kill Thread
263         
264 .parent:
265         ret
266
267 ; void Proc_ReturnToUser(void *Method, Uint Parameter, tVAddr KernelStack)
268 ; Calls a user fault handler
269 ;
270 [global Proc_ReturnToUser]
271 [extern Proc_GetCurThread]
272 Proc_ReturnToUser:
273         push ebp
274         mov ebp, esp
275         ; [EBP+8]: handler to use
276         ; [EBP+12]: parameter
277         ; [EBP+16]: kernel stack top
278         
279         ; Get kernel stack      
280         mov eax, [ebp+16]
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         mov eax, dr1
347         ret
348
349 [extern GetEIP]
350 [global GetEIP_Sched]
351 [global GetEIP_Sched_ret]
352 GetEIP_Sched_ret equ GetEIP_Sched.ret
353 GetEIP_Sched:
354         call GetEIP
355 GetEIP_Sched.ret:
356         ret
357
358 ; Usermode code exported by the kernel
359 [section .usertext]
360 ; Export a place for the user to jump to to call a syscall
361 ; - Allows the kernel to change the method easily
362 User_Syscall:
363         xchg bx, bx     ; MAGIC BREAKPOINT
364         int 0xAC
365
366 ; A place to return to and exit
367 User_Syscall_RetAndExit:
368         push eax
369         call User_Syscall_Exit
370 User_Syscall_Exit:
371         xor eax, eax
372         mov ebx, [esp+4]
373         int 0xAC
374
375 ; vim: ft=nasm ts=8

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