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

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