Hi,
GLneo wrote:
i think your right, i have been looking at very diferent tutorials and tried to put them togheter
, i would like to use both a CPL=3 stack and a CPL=0 stack per task, how is THAT done?,
That's done with the examples I've been posting, sort of.
Specifically, the SS0 and ESP0 fields in the TSS must be updated every task switch to point to the new taskl's kernel stack, and the CPU itself handles all stack switching (except for within the task switch code).
If you want to use C for your kernel, I'd also recommend the elegant method of parameter passing posted by Colonel Kernel. Also, I'd still do the thread switch code itself in a seperate routine.
Combining all of this gives something like:
Code:
;IRQ 0 assembly stub. Must be called with interrupts disabled (i.e. use
; an "interrupt gate" in the IDT and not a "trap gate").
IRQhandler00:
<push DS, ES, FS, GS if necessary>
pusha
<reload DS and ES (and maybe FS, GS) with values the kernel expects, if necessary>
push esp ;Push the only parameter to the C function (the address of CPU state on the stack)
call _Timer_IRQ_handler ;Call the C function (which must send the EOI)
add esp,4 ;Remove the C function's parameters from the stack
cmp eax,esp ;Did the C function request a task switch?
je .skipSwitch ; no
call do_task_switch ; yes, call the assembly code that handles task switches
.skipSwitch:
popa
<pop DS, ES, FS, GS if necessary>
iretd
Code:
;Kernel API assembly stub. Must be called with interrupts enabled (which is
; what you'd expect when CPL=3 code was running anyway).
kernelAPIentry:
<push DS, ES, FS, GS if necessary>
pusha
<reload DS and ES (and maybe FS, GS) with values the kernel expects, if necessary>
push esp ;Push the only parameter to the C function (the address of CPU state on the stack)
call _kernel_API_entry_point ;Call the C function
add esp,4 ;Remove the C function's parameters from the stack
cmp eax,esp ;Did the C function request a task switch?
je .skipSwitch ; no, skip the task switch
cli ;Disable interrupts for the task switch code
call do_task_switch ;Call the assembly code that handles task switches
sti ;Restore interrupts
.skipSwitch:
popa
<pop DS, ES, FS, GS if necessary>
iretd
Code:
;Do a task switch. This code must be called with interrupts disabled.
;All general registers trashed (shouldn't matter as they're always saved
;before calling this code, and restored after this code runs.
;
;Input
; eax Must contain the top of stack for the task being switched to
do_task_switch:
mov ebx,[currentTaskStructure]
mov [ebx+TASK_STRUCT.currentESP],esp
<work out how much CPU time the last task used and update "[ebx + TASK_STRUCT.timeUsed]">
<convert EAX into address of task structure and put it in ESI>
mov ebx,[esi+TASK_STRUCT.kernelStackTop]
mov [address_of_system_TSS + TSS.ESP0], ebx
mov ebx,[esi+TASK_STRUCT.pageDirectory]
mov ecx,cr3
cmp ecx,ebx ;Does address space need to be changed?
je .skipCR3 ; no, skip it
mov cr3,ebx ; yes, update CR3
<do something about FPU/MMX/SSE/SSE2 state saving here>
mov esp,eax ;Switch stacks
ret
[continued]