Sorting source tree a bit
[tpg/acess2.git] / KernelLand / Kernel / arch / x86 / proc.asm
diff --git a/KernelLand/Kernel/arch/x86/proc.asm b/KernelLand/Kernel/arch/x86/proc.asm
new file mode 100644 (file)
index 0000000..8da7971
--- /dev/null
@@ -0,0 +1,375 @@
+; AcessOS Microkernel Version
+; Start.asm
+
+[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
+       push DWORD [esp+0x20+12]
+       call MM_Clone
+       add esp, 4
+       ; 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
+; --------------
+[extern Proc_Scheduler]
+[global SchedulerBase]
+SchedulerBase:
+       pusha
+       push ds
+       push es
+       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
+       
+       %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 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
+       
+       popa
+       add esp, 4*2    ; CPU ID + Dummy error code
+       ; No Error code / int num
+       iret
+
+[extern Proc_Clone]
+[extern Threads_Exit]
+[global SpawnTask]
+SpawnTask:
+       ; Call Proc_Clone with Flags=0
+       xor eax, eax
+;      push eax
+       push eax
+       call Proc_Clone
+       add esp, 8      ; Remove arguments from stack
+       
+       test eax, eax
+       jnz .parent
+       
+       ; In child, so now set up stack frame
+       mov ebx, [esp+4]        ; Child Function
+       mov edx, [esp+8]        ; Argument
+       ; 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, tVAddr KernelStack)
+; Calls a user fault handler
+;
+[global Proc_ReturnToUser]
+[extern Proc_GetCurThread]
+Proc_ReturnToUser:
+       push ebp
+       mov ebp, esp
+       ; [EBP+8]: handler to use
+       ; [EBP+12]: parameter
+       ; [EBP+16]: kernel stack top
+       
+       ; Get kernel stack      
+       mov eax, [ebp+16]
+       sub eax, KSTACK_USERSTATE_SIZE
+       
+       ;
+       ; NOTE: This can cause corruption if the signal happens while the user
+       ;       has called a kernel operation.
+       ; 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 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
+       mov ds, ax
+       mov es, ax
+       mov fs, ax
+       mov gs, ax
+       
+       push 0x23       ; SS
+       push edi        ; ESP
+       push 0x202      ; EFLAGS (IP and Rsvd)
+       push 0x1B       ; CS
+       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
+       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
+User_Syscall_Exit:
+       xor eax, eax
+       mov ebx, [esp+4]
+       int 0xAC
+
+; vim: ft=nasm ts=8

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