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

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