I were trying to start with my first device driver but firstly, of course, I have to implement scheduler. I have scheduling algorithm which works as it should (I'm not completely sure but...). The only problem for me is Context switching.
I was following the [wiki]Brendan's Multi-tasking Tutorial[/wiki] and I cant make context switch work properly. Now my code looks like this
Code: Select all
section .text
global switch_context
switch_context:
push ebx
push esi
push edi
push ebp
mov edi,[now_executed] ;edi = address of the previous task's "thread control block"
mov [edi + TCB.esp],esp ;Save ESP for previous task's kernel stack in the thread's TCB
;Load next task's state
mov esi,[esp+(4+1)*4] ;esi = address of the next task's "thread control block" (parameter passed on stack)
mov [now_executed],esi ;Current task's TCB is the next task TCB
mov esp,[esi + TCB.esp] ;Load ESP for next task's kernel stack from the thread's TCB
mov eax,[esi + TCB.pgd] ;eax = address of page directory for next task
mov ebx,[esi + TCB.esp0] ;ebx = address for the top of the next task's kernel stack
mov [TSS + TSS_struc.esp0],ebx ;Adjust the ESP0 field in the TSS (used by CPU for for CPL=3 -> CPL=0 privilege level changes)
mov ecx,cr3 ;ecx = previous task's virtual address space
cmp eax,ecx ;Does the virtual address space need to being changed?
je .doneVAS ; no, virtual address space is the same, so don't reload it and cause TLB flushes
mov cr3,eax ; yes, load the next task's virtual address space
.doneVAS:
pop ebp
pop edi
pop esi
pop ebx
ret ;Load next task's EIP from its kernel stack
Code: Select all
switch_context(&(task));
Code: Select all
void prepare_task(task_struct_t task, uint32_t eip) {
uint32_t esp;
asm volatile (
"movl %%esp, %0"
: "=r"(esp)
);
asm volatile (
"mov %0, %%esp\n"
"pushl %1\n"
"push %%ebp\n"
"push %%edi\n"
"push %%esi\n"
"push %%ebx\n"
"movl %2, %%esp\n"
:
: "r"(task.esp), "r"(eip), "r"(esp)
);
}