I didn't see brendans tutorial but I predict that you already have a scheduler which will select the next thread to run.
You should save/restore all the registers and segments, if you have paging this gets more complicated, you will have to map your kernel in the user's address space.
I never made a 32 Bit OS, but I will see if this helps.
This is a simple Interrupt Handler that saves thread state, calls the Scheduler Function and context switches to the next thread.
If it works, then you can optimize this code with lots of ideas.
Code: Select all
; The Stack is formatted as below:
; EIP, CS, EFLAGS, ESP, SS
SwitchTaskISR:
push edi
mov edi, [CurrentThread]
; Save EDI
pop dword [CurrentThread + EDI]
; Save EIP, CS, EFLAGS, ESP, SS, DS, FS, GS, ES
pop dword [edi + EIP]
pop dword [edi + CS]
pop dword [edi + EFLAGS]
pop dword [edi + ESP]
pop dword [edi + SS]
mov [edi + DS], ds
mov [edi + FS], fs
mov [edi + GS], gs
mov [edi + ES], es
; Save the registers
mov [edi + EAX], eax
mov [edi + EBX], ebx
mov [edi + ECX], ecx
mov [edi + EDX], edx
mov [edi + ESI], esi
mov [edi + EBP], ebp
call Schedule ; Current thread in EAX
mov [CurrentThread], eax
; Build the Stack Frame (These registers will be restored when you do an iret
push dword [eax + SS]
push dword [eax + ESP]
push dword [eax + EFLAGS]
push dword [eax + CS]
push dword [eax + EIP]
; If you use paging (you can also do a cmp to see if they have the same page tables)
mov ebx, [eax + CR3]
mov cr3, ebx
; Restore the registers of the task
.....
; Context Switch
iretd
As far as I know, in 32 Bit you can use the TSS and save/load your task with one instruction.