X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Farch%2Fx86%2Fproc.asm;h=00ea9e1e6012f0a76630b7273633fa897835a5f2;hb=6d5880d56afb2c6a900e480c891fb40e05457ea3;hp=b1843c782c33570f0371e5bc3c6396c7d49a9c5c;hpb=b98fbd4e9c71447d81fc9bd643fb174c76346e0f;p=tpg%2Facess2.git diff --git a/Kernel/arch/x86/proc.asm b/Kernel/arch/x86/proc.asm index b1843c78..00ea9e1e 100644 --- a/Kernel/arch/x86/proc.asm +++ b/Kernel/arch/x86/proc.asm @@ -3,11 +3,170 @@ [bits 32] +%define SAVEFLAG_FPU 0x1 + KERNEL_BASE equ 0xC0000000 KSTACK_USERSTATE_SIZE equ (4+8+1+5)*4 ; SRegs, GPRegs, CPU, IRET [section .text] + +[global NewTaskHeader] +NewTaskHeader: + mov eax, [esp] + mov dr0, eax + + mov eax, [esp+4] + add esp, 12 ; Thread, Function, Arg Count + call eax + + push eax ; Ret val + push 0 ; 0 = This Thread + call Threads_Exit + +[extern MM_Clone] +[global Proc_CloneInt] +Proc_CloneInt: + pusha + ; Save RSP + mov eax, [esp+0x20+4] + mov [eax], esp + call MM_Clone + ; Save CR3 + mov esi, [esp+0x20+8] + mov [esi], eax + ; Undo the pusha + add esp, 0x20 + mov eax, .newTask + ret +.newTask: + popa + xor eax, eax + ret + +[global SwitchTasks] +; + 4 = New RSP +; + 8 = Old RSP save loc +; +12 = New RIP +; +16 = Old RIP save loc +; +20 = CR3 +SwitchTasks: + pusha + + ; Old IP + mov eax, [esp+0x20+16] + test eax, eax + jz .nosave + mov DWORD [eax], .restore + ; Old SP + mov eax, [esp+0x20+8] + mov [eax], esp + +.nosave: + mov ecx, [esp+0x20+12] ; New IP + mov eax, [esp+0x20+20] ; New CR3 + mov esp, [esp+0x20+ 4] ; New SP + + test eax, eax + jz .setState + mov cr3, eax + invlpg [esp] + invlpg [esp+0x1000] +.setState: + jmp ecx + +.restore: + popa + xor eax, eax + ret + +[global Proc_InitialiseSSE] +Proc_InitialiseSSE: + mov eax, cr4 + or eax, (1 << 9)|(1 << 10) ; Set OSFXSR and OSXMMEXCPT + mov cr4, eax + mov eax, cr0 + and ax, ~(1 << 2) ; Clear EM + or eax, (1 << 1) ; Set MP + mov eax, cr0 + ret +[global Proc_DisableSSE] +Proc_DisableSSE: + mov eax, cr0 + or ax, 1 << 3 ; Set TS + mov cr0, eax + ret +[global Proc_EnableSSE] +Proc_EnableSSE: + mov eax, cr0 + and ax, ~(1 << 3) ; Clear TS + mov cr0, eax + ret + +[global Proc_SaveSSE] +Proc_SaveSSE: + mov eax, [esp+4] + fxsave [eax] + ret +[global Proc_RestoreSSE] +Proc_RestoreSSE: + mov eax, [esp+4] + fxrstor [eax] + ret + +%if USE_MP +[extern giMP_TimerCount] +[extern gpMP_LocalAPIC] +[extern Isr240.jmp] +[global SetAPICTimerCount] +SetAPICTimerCount: + pusha + push ds + push es + push fs + push gs + + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + mov eax, [gpMP_LocalAPIC] + mov ecx, [eax+0x320] + test ecx, 0x00010000 + jz .setTime + mov DWORD [eax+0x380], 0xFFFFFFFF ; Set Initial Count + mov DWORD [eax+0x320], 0x000000F0 ; Enable the timer on IVT#0xEF (One Shot) + jmp .ret + +.setTime: + ; Get Timer Count + mov ecx, 0xFFFFFFFF + sub ecx, [eax+0x390] + mov DWORD [giMP_TimerCount], ecx + ; Disable APIC Timer + mov DWORD [eax+0x320], 0x000100EF + mov DWORD [eax+0x380], 0 + + ; Update Timer IRQ to the IRQ code + mov eax, SchedulerBase + sub eax, Isr240.jmp+5 + mov DWORD [Isr240.jmp+1], eax + + ;xchg bx, bx ; MAGIC BREAK +.ret: + mov dx, 0x20 + mov al, 0x20 + out dx, al ; ACK IRQ + pop gs + pop fs + pop es + pop ds + popa + add esp, 8 ; CPU ID / Error Code + iret +%endif ; -------------- ; Task Scheduler ; -------------- @@ -20,29 +179,58 @@ SchedulerBase: push fs push gs + pushf + and BYTE [esp+1], 0xFE ; Clear Trap Flag + popf + + mov eax, dr0 + push eax ; Debug Register 0, Current Thread + mov ax, 0x10 mov ds, ax mov es, ax mov fs, ax mov gs, ax - mov eax, [esp+12*4] ; CPU Number - push eax ; Pus as argument + %if USE_MP + call GetCPUNum + mov ebx, eax + push eax ; Push as argument + %else + push 0 + %endif call Proc_Scheduler +[global scheduler_return] +scheduler_return: ; Used by some hackery in Proc_DumpThreadCPUState - add esp, 4 ; Remove Argument + add esp, 4 ; Remove CPU Number (thread is poped later) + + %if USE_MP + test ebx, ebx + jnz .sendEOI + %endif + + mov al, 0x20 + out 0x20, al ; ACK IRQ + %if USE_MP + jmp .ret +.sendEOI: + mov eax, DWORD [gpMP_LocalAPIC] + mov DWORD [eax+0x0B0], 0 + %endif +.ret: + pop eax ; Debug Register 0, Current Thread + mov dr0, eax + pop gs pop fs pop es pop ds - - mov dx, 0x20 - mov al, 0x20 - out dx, al ; ACK IRQ + popa - add esp, 4 ; CPU ID + add esp, 4*2 ; CPU ID + Dummy error code ; No Error code / int num iret @@ -52,7 +240,7 @@ SchedulerBase: SpawnTask: ; Call Proc_Clone with Flags=0 xor eax, eax - push eax +; push eax push eax call Proc_Clone add esp, 8 ; Remove arguments from stack @@ -63,29 +251,36 @@ SpawnTask: ; In child, so now set up stack frame mov ebx, [esp+4] ; Child Function mov edx, [esp+8] ; Argument - ; Child + ; Child Function push edx ; Argument call ebx ; Function + ; Kill thread once done + push eax ; Exit Code + push 0 ; Kill this thread call Threads_Exit ; Kill Thread .parent: ret -; +; void Proc_ReturnToUser(void *Method, Uint Parameter) ; Calls a user fault handler ; -[global Proc_AlterUserReturnAddr] +[global Proc_ReturnToUser] [extern Proc_GetCurThread] -Proc_AlterUserReturnAddr: - ; EBP is the handler to use +Proc_ReturnToUser: + push ebp + mov ebp, esp + ; [EBP+8]: handler to use + ; [EBP+12]: parameter + ; [EBP+16]: kernel stack top - call Proc_GetCurThread - xchg bx, bx + ;call Proc_GetCurThread ; EAX is the current thread - mov ebx, eax - mov eax, [ebx+40] ; Get Kernel Stack - sub eax, KSTACK_USERSTATE_SIZE + ;mov ebx, eax + ;mov eax, [ebx+12*4] ; Get Kernel Stack + mov eax, [ebp+16] ; Get Kernel Stack + sub eax, KSTACK_USERSTATE_SIZE ; ; NOTE: This can cause corruption if the signal happens while the user @@ -93,12 +288,36 @@ Proc_AlterUserReturnAddr: ; Good thing this can only be called on a user fault. ; + ; Validate user ESP + ; - Page Table + mov edx, [eax+KSTACK_USERSTATE_SIZE-12] ; User ESP is at top of kstack - 3*4 + mov ecx, edx + shr ecx, 22 + test BYTE [0xFC3F0000+ecx*4], 1 + jnz .justKillIt + ; - Page + mov ecx, edx + shr ecx, 12 + test BYTE [0xFC000000+ecx*4], 1 + jnz .justKillIt + ; Adjust + sub edx, 8 + ; - Page Table + mov ecx, edx + shr ecx, 22 + test BYTE [0xFC3F0000+ecx*4], 1 + jnz .justKillIt + ; - Page + mov ecx, edx + shr ecx, 12 + test BYTE [0xFC000000+ecx*4], 1 + jnz .justKillIt + ; Get and alter User SP - mov ecx, [eax+KSTACK_USERSTATE_SIZE-12] - mov edx, [ebx+60] ; Get Signal Number - mov [ecx-4], edx - mov [ecx-8], DWORD User_Syscall_RetAndExit - sub ecx, 8 + mov edi, edx + mov edx, [ebp+12] ; Get parameter + mov [edi+4], edx ; save to user stack + mov [edi], DWORD User_Syscall_RetAndExit ; Return Address ; Restore Segment Registers mov ax, 0x23 @@ -108,15 +327,49 @@ Proc_AlterUserReturnAddr: mov gs, ax push 0x23 ; SS - push ecx ; ESP + push edi ; ESP push 0x202 ; EFLAGS (IP and Rsvd) push 0x1B ; CS - push ebp ; EIP + mov eax, [ebp+8] ; Method to call + push eax ; EIP iret + + ; Just kill the bleeding thing + ; (I know it calls int 0xAC in kernel mode, but meh) +.justKillIt: + xor eax, eax + xor ebx, ebx + dec ebx ; EBX = -1 + int 0xAC +[global GetCPUNum] +GetCPUNum: ; TODO: Store in debug registers +; xor eax, eax +; str ax +; sub ax, 0x30 +; shr ax, 3 ; ax /= 8 + mov eax, dr1 + ret +[extern GetEIP] +[global GetEIP_Sched] +[global GetEIP_Sched_ret] +GetEIP_Sched_ret equ GetEIP_Sched.ret +GetEIP_Sched: + call GetEIP +GetEIP_Sched.ret: + ret + +; Usermode code exported by the kernel [section .usertext] +; Export a place for the user to jump to to call a syscall +; - Allows the kernel to change the method easily +User_Syscall: + xchg bx, bx ; MAGIC BREAKPOINT + int 0xAC + +; A place to return to and exit User_Syscall_RetAndExit: push eax call User_Syscall_Exit @@ -124,3 +377,5 @@ User_Syscall_Exit: xor eax, eax mov ebx, [esp+4] int 0xAC + +; vim: ft=nasm ts=8