All pastes #96876 Raw Edit

Task Switcher

public text v1 · immutable
#96876 ·published 2006-07-23 07:46 UTC
rendered paste body
; **********************************************************

;	Name: Task Switcher
;	Autor: Toaster Burger
;	Version: 1.00
;	Date: 26.11.2005
;	last Update: 26.11.2005
;	see document: ToasterOS.pdf

; **********************************************************

[bits 32]
CPU 386

%define	Type_System
%include "interface.asm"

%define	Handle_Size	6

org Task_Switcher


jmp dword Enable_Scheduler

jmp dword Create_Task
jmp dword Delete_Task
jmp dword Destroy_Task

jmp dword Check_Task_Handle

jmp dword Dispatcher

jmp dword Finite

jmp dword Create_Task_System

jmp dword Switch_Task

jmp dword Get_Current_Process








Enable_Scheduler:					; enable (start) the Scheduler

; API Enable_Scheduler

Enter_System_Environment


; command CPUID available (test bit 21 of eflags to set) ?
pushfd
or [esp],dword 1000000000000000000000b
popfd
pushfd
pop eax
test eax,1000000000000000000000b
jz No_FPU_MMX_SSE2_support

; check if the FPU, MMX, SSE (re)store command is available
mov eax,1
CPU PentiumPro
cpuid
CPU 386
test edx,1000000000000000000000000b
jz No_FPU_MMX_SSE2_support
jmp Write_Task_Table


No_FPU_MMX_SSE2_support:
; if here the fxsave/fxrstor opcodes are not supported, so delete them
mov [Store_FPU_MMX_SSE_state],dword 90909090h
mov [Store_FPU_MMX_SSE_state+4],word 9090h
mov [Store_FPU_MMX_SSE_state+6],byte 90h
mov [Restore_FPU_MMX_SSE_state],dword 90909090h
mov [Restore_FPU_MMX_SSE_state+4],word 9090h
mov [Restore_FPU_MMX_SSE_state+6],byte 90h


Write_Task_Table:
mov [Current_Task],dword Task_Table
xor ecx,ecx						; loop counter = 65536
xor eax,eax
mov edi,Task_Table

rep stosw						; erase all words
rep stosd						; erase all dwords

Leave_System_Environment

ret







Create_Task_System:

; API Create_Task_System, Handle, Process, Stack, Address, Data, Size

; Handle = Process Handle (of the caller's one)
; Process = Process Handle of the Process to start the Task
; Stack = start stack (esp) of the new task (the value stack is from high to low)
; Address = start address (eip) of the new task
; Size = bytes to copy from Data (source) to the new Tasks stack (destination)

; NOTES:
; The Data is bytewise copied to the stack from low to high, and the new Task's 
; stack pointer will point BEFORE the data.
; This function adds to the data the Task Handle, so esp+0 points to the Handle
; and esp+4 to the user sepcific data.
; The caller won't get the Handle.

Enter_System_Environment


; set the correct Stack Pointer
mov eax,[Param6]
sub [Param3],eax



; search a free Task Handle
mov esi,Task_Table
xor ecx,ecx						; loop counter = 65536
Enter_Multitasking MT_Task_Switcher			; coordinate Multitasking access (enter)

Search_free_System_Task:
add esi,02h

lodsd
or eax,eax
jz Task_System_found
loop Search_free_System_Task

; if here, there is no free Task Handle
Leave_Multitasking MT_Task_Switcher			; coordinate Multitasking access (leave)
stc
mov eax,No_free_Task
jmp Create_Task_System_Exit


Task_System_found:					; if comes here, a free Task Handle is found
Leave_Multitasking MT_Task_Switcher			; coordinate Multitasking access (leave)
lea edi,[esi-06h]

; store the Process Handle
mov ax,[Param2]
stosw

; store the Stack Pointer
mov eax,[Param3]
sub eax,12+(4*5)+32+108
stosd



; set the stack for the new process on the current stack
; push following values in the correct direction: 
;     gs, fs, es, ds, ad, FPU, iret, Handle (4, 4, 4, 4, 32, 108, 12, 4)

sub esp,12+(4*5)+32+108
mov edi,esp
mov ebx,esp

; set gs, fs, es, ds
xor eax,eax
stosd
stosd
mov eax,Data_Selector
stosd
stosd

; set edi, esi, ebp & esp (all points to the start of stack)
mov eax,[Param3]
stosd
stosd
stosd
stosd

; xor eax, ebx, ecx & edx
xor eax,eax
stosd
stosd
stosd
stosd

; FPU registers (use current)
fsave [edi]
add edi,108

; store the iret (eip, cs, flags)
mov eax,[Param4]
stosd
mov eax,Code_Selector
stosd
mov eax,User_EFLAG
stosd

; store the Task Handle
xor eax,eax
sub eax,ecx						; 65536 - loop counter
stosd


; check whether the data is to copy (or not)
cmp [Param6],dword 0
je Copy_System_finished

; copy the data
API Copy_Process_Data, [Param1], [Param2], [Param5], [Param3], [Param6]
jc Create_Task_System_Exit

Copy_System_finished:


; copy the (system) stack
sub [Param3],dword (12+(4*5)+32+108)
API Copy_Process_Data, [Param1], [Param2], ebx, [Param3], (12+(4*5)+32+108)



; reset the stack (delete temporary other process stack)
add esp,12+(4*5)+32+108


Create_Task_System_Exit:
Leave_System_Environment

ret







Create_Task:

; API Create_Task, Handle, Process, Stack, Address, Data, Size

; Handle = Process Handle (of the caller's one)
; Process = Process Handle of the Process to start the Task
; Stack = start stack (esp) of the new task (the value stack is from high to low)
; Address = start address (eip) of the new task
; Size = bytes to copy from Data (source) to the new Tasks stack (destination)

; NOTES:
; The Data is bytewise copied to the stack from low to high, and the new Task's 
; stack pointer will point BEFORE the data.
; This function adds to the data the Task Handle, so esp+0 points to the Handle
; and esp+4 to the user sepcific data.
; The caller won't get the Handle.

Enter_System_Environment


; set the correct Stack Pointer
mov eax,[Param6]
sub [Param3],eax



; search a free Task Handle
mov esi,Task_Table
xor ecx,ecx						; loop counter = 65536
Enter_Multitasking MT_Task_Switcher			; coordinate Multitasking access (enter)

Search_free_Task:
add esi,02h

lodsd
or eax,eax
jz Task_found
loop Search_free_Task

; if here, there is no free Task Handle
Leave_Multitasking MT_Task_Switcher			; coordinate Multitasking access (leave)
stc
mov eax,No_free_Task
jmp Create_Task_Exit


Task_found:						; if comes here, a free Task Handle is found
Leave_Multitasking MT_Task_Switcher			; coordinate Multitasking access (leave)
lea edi,[esi-06h]

; store the Process Handle
mov ax,[Param2]
stosw

; store the Stack Pointer
mov eax,[Param3]
sub eax,12+(4*5)+32+108
stosd



; set the stack for the new process on the current stack
; push following values in the correct direction: 
;     gs, fs, es, ds, ad, FPU, iret, Handle (4, 4, 4, 4, 32, 108, 12, 4)

sub esp,12+(4*5)+32+108
mov edi,esp
mov ebx,esp

; set gs, fs, es, ds
xor eax,eax
stosd
stosd
mov eax,Data_Selector_User
stosd
stosd

; set edi, esi, ebp & esp (all points to the start of stack)
mov eax,[Param3]
stosd
stosd
stosd
stosd

; xor eax, ebx, ecx & edx
xor eax,eax
stosd
stosd
stosd
stosd

; FPU registers (use current)
fsave [edi]
add edi,108

; store the iret (eip, cs, flags)
mov eax,[Param4]
stosd
mov eax,Code_Selector_User
stosd
mov eax,User_EFLAG
stosd

; store the Task Handle
sub eax,ecx						; 65536 - loop counter
stosd


; check whether the data is to copy (or not)
cmp [Param6],dword 0
je Copy_finished

; copy the data
API Copy_Process_Data, [Param1], [Param2], [Param5], [Param3], [Param6]
jc Create_Task_Exit

Copy_finished:


; copy the (system) stack
sub [Param3],dword (12+(4*5)+32+108)
API Copy_Process_Data, [Param1], [Param2], ebx, [Param3], (12+(4*5)+32+108)



; reset the stack (delete temporary other process stack)
add esp,12+(4*5)+32+108


Create_Task_Exit:
Leave_System_Environment

ret






Delete_Task:

; API Delete_Task, Handle

; Handle = Handle of the Task to delete; returned (on the stack) by Create_Task

Enter_System_Environment

; edi = address of the Handle
imul edi,[Param1],Handle_Size
add edi,Task_Table

xor eax,eax
stosw
stosd

Leave_System_Environment

ret







Destroy_Task:

; API Destroy_Task, Task_ID

; (undocumented)

Enter_System_Environment

mov esi,Task_Table
xor ecx,ecx						; loop counter = 65536
mov bx,[Param1]

Destroy_free_Task:
lodsw
cmp ax,bx
jne Destroy_free_Task_nt

mov [esi-2],word 0
mov [esi],dword 0

Destroy_free_Task_nt:
add esi,04h
loop Destroy_free_Task

Leave_System_Environment

ret







Finite:

; (undocumented)


; test register content ???
;   - esp

; test if current cr3 register/handle is in Task Table ???

Enter_MT	dispatcher_state

jmp Scheduler







Dispatcher:

Enter_MT	dispatcher_state


; 1. store the current Task's state

sub esp,108
fsave [esp]
pushad
mpush ds, es, fs, gs

; store special FPU, MMX and SSE state or do nop
Store_FPU_MMX_SSE_state:
CPU PentiumPro
fxsave [FPU_MMX_SSE2_State]
CPU 386

; store the stack
mov ebx,[Current_Task]
mov [ebx+2],esp


; 2. execute the (internal) Scheduler
Scheduler:
add [Current_Task],dword Handle_Size
cmp [Current_Task],dword Task_Table_End
jl Scheduler_Next

mov [Current_Task],dword Task_Table

Scheduler_Next:
mov ebx,[Current_Task]
mov eax,[ebx+2]
or eax,eax
jz Scheduler

; restore the stack
mov esp,[ebx+2]


; 3. restore the new Task's state
movzx ecx,word [ebx]
API Get_CR3, ecx
mov cr3,eax

; restore special FPU, MMX and SSE state or do nop
Restore_FPU_MMX_SSE_state:
CPU PentiumPro
fxrstor [FPU_MMX_SSE2_State]
CPU 386

mpop ds, es, fs, gs
popad
frstor [esp]
add esp,108


Leave_MT	dispatcher_state

ret







Switch_Task:

; (undocumented)

Enter_System


; set the return stack
pushfd
push cs
push Switch_Task_ret

; switch the task
call Dispatcher

iret


Switch_Task_ret:
Leave_System

ret







Check_Task_Handle:

; API Check_Task_Handle, Handle, Process_Handle

; Handle = Handle of the Task to check of validity; returned (on the stack) by Create_Task
; Process Handle = Process Handle of the Task (have to be the same as by Create_Task)

Enter_System_Environment

; ebx = address of the Handle
imul ebx,[Param1],Handle_Size
add edi,Task_Table

; check the boundarys
cmp [Param1],dword Task_Table_End
jnc Check_Task_Handle_Invalid

; check if the Task_Handle(current).Process_Handle is euqal to the as parameter's one
mov ax,[ebx]
cmp ax,[Param2]
jne Check_Task_Handle_Invalid

; esp = 0 ?
cmp [ebx+2],TPointer NULL
je Check_Task_Handle_Invalid

; Process Handle valid?
API Check_Process_Handle, TProcessHandle [Param2]
jc Check_Task_Handle_Exit

xor eax,eax
clc
jmp Check_Task_Handle_Exit


Check_Task_Handle_Invalid:
stc
mov eax,Invalid_Handle


Check_Task_Handle_Exit:
Leave_System_Environment

ret







Get_Current_Process:

; (undocumented)

Enter_System

mov esi,[Current_Task]
movzx eax,word [esi]

Leave_System

ret







; Current_Task is a direct pointer to the current Task into the Task Table
Current_Task		dd	0
FPU_MMX_SSE		dd	"no"
dispatcher_state	db	0






; the Task Table contains information about the Tasks, the descriptor format:

; Process Handle        (word)
; esp                   (dword)
; ------------------------------
; a Task description    6 Bytes