x86 Context Switching
Posted: Fri May 15, 2009 3:49 am
Hi there,
yesterday I got my thread scheduling in the kernel to do something without crashing
I've got some problems with interrupt disabling and enabling when switching the contexts.
I disable them, when entering my scheduling method and want to enable them after the context switch.
And here is the tricky thing: I'm storing the old context and loading a fresh, new one just created. It has an own stack, on this stack is the first return address which points to the entry point etc. All fine.
But after the context switch, I'm jumping straight to the entry point. I've got no chance to enable interrupts afterwards since I'm now in the thread. This means my scheduling timer never fires, so the task runs forever. Not good
Here is how I switch contexts (I took a bit from exlaim and other projects to learn how to do it, thx!):
A context is defined by this structure:
The switching itself is done here:
A context switch is invoked from the c++ code like this:
Also I'm quite confused about three things in this code:
Doesn't I have to save all the registers like eax, edx, the eflags and all the segments? I don't know when I'm interrupted, so I definetly need the eflags. This would also solve my Interrupt problem, since I can pass an interrupt status to the context switch and set the bit on the eflags, right?
The other thing is the return value of context_save. When does it return 0? When a thread just woke up, because it was picked by the scheduler?
The third thing is the return value in eax of context_restore. Do I need this? I think it would be fatal. I need a restored value in eax when continuing the execution of the thread. Nobody know what the code of the thread moved in there before the switch. So what is this code (the two "WTF??"-lines ) for?
It would be nice if somebody could help me!
(And hopefully you understand my english... It still has much of this "german strangeness" in it )
yesterday I got my thread scheduling in the kernel to do something without crashing
I've got some problems with interrupt disabling and enabling when switching the contexts.
I disable them, when entering my scheduling method and want to enable them after the context switch.
And here is the tricky thing: I'm storing the old context and loading a fresh, new one just created. It has an own stack, on this stack is the first return address which points to the entry point etc. All fine.
But after the context switch, I'm jumping straight to the entry point. I've got no chance to enable interrupts afterwards since I'm now in the thread. This means my scheduling timer never fires, so the task runs forever. Not good
Here is how I switch contexts (I took a bit from exlaim and other projects to learn how to do it, thx!):
A context is defined by this structure:
Code: Select all
typedef struct {
Address ip; //EIP (Instruction Pointer)
Address sp; //ESP (Stack Pointer)
unsigned int bp; //EBP (Stack Frame)
unsigned int bx; //EBX
unsigned int edi; //EDI
unsigned int esi; //ESI
Address *kernelStack; //KernelStack
} context_t;
Code: Select all
[BITS 32]
CTX_OFF_EIP equ 0 ;EIP offset
CTX_OFF_ESP equ 4 ;ESP offset
CTX_OFF_EBP equ 8 ;EBP offset
CTX_OFF_EBX equ 12 ;EBX offset
CTX_OFF_EDI equ 16 ;EDI offset
CTX_OFF_ESI equ 20 ;ESI offset
;int context_save(context_t *ctx)
[GLOBAL context_save]
context_save:
mov eax, [esp+4]
;Save old instruction/stack pointers
mov ecx, [esp]
mov [CTX_OFF_EIP+eax],ecx
mov [CTX_OFF_ESP+eax],esp
;Save old callee-save registers
mov [CTX_OFF_EBP+eax],ebp
mov [CTX_OFF_EBX+eax],ebx
mov [CTX_OFF_EDI+eax],edi
mov [CTX_OFF_ESI+eax],esi
xor eax,eax
ret
;int context_restore(context_t *ctx)
[global context_restore]
context_restore:
mov eax, [esp+4]
;Restore new callee-save registers
mov esi, [CTX_OFF_ESI+eax]
mov edi, [CTX_OFF_EDI+eax]
mov ebx, [CTX_OFF_EBX+eax]
mov ebp, [CTX_OFF_EBP+eax]
;Restore new instruction/stack pointers
mov esp, [CTX_OFF_ESP+eax]
mov ecx, [CTX_OFF_EIP+eax]
mov [esp],ecx
;xor eax,eax ;WTF???
;inc eax
ret
Code: Select all
void CPUContext::SwitchTo(CPUContext *old)
{
//TODO: Set kernel stack in TSS for usermode later
if(context_save(old->GetContext()) == 0) {
context_restore(&context);
}
}
Doesn't I have to save all the registers like eax, edx, the eflags and all the segments? I don't know when I'm interrupted, so I definetly need the eflags. This would also solve my Interrupt problem, since I can pass an interrupt status to the context switch and set the bit on the eflags, right?
The other thing is the return value of context_save. When does it return 0? When a thread just woke up, because it was picked by the scheduler?
The third thing is the return value in eax of context_restore. Do I need this? I think it would be fatal. I need a restored value in eax when continuing the execution of the thread. Nobody know what the code of the thread moved in there before the switch. So what is this code (the two "WTF??"-lines ) for?
It would be nice if somebody could help me!
(And hopefully you understand my english... It still has much of this "german strangeness" in it )