Idling in kernel & nested interrupts (x86)
Posted: Thu Aug 27, 2009 3:00 pm
Hi!
I'm trying to implement an idle-"thread" which doesn't need much resources and let my OS react quickly on interrupts. Therefore I thought the best way would be not to have a real thread/process for idling but implement the thread-switch as follows:
So the CPU will halt until an interrupt arrives. This interrupt would of course be nested, because we were already handling an interrupt. So the CPU doesn't switch the privilege level and continues using the current stack. Lets say we should switch to a different thread/process now. That means we call thread_switch(...) which saves the current thread (idle) and resumes the new one. The save is not really necessary since we'll never resume idle but shouldn't hurt. thread_resume() restores the registers and exchanges the page-directory so that we get the kernel-stack of the resumed task back. That means if this thread now leaves the interrupt-handling and restores the registers (including segment-registers, eflags and so on) we are *not* leaving a nested interrupt but continuing a user-process.
So far, so good. As far as I understand this, it should be working. But it doesn't. I'm trying to debug this for more than 2 days now and getting more and more frustrated because I really don't have a clue what is wrong with this approach or my implementation of it :/
I know that as soon as I'm switching from idle to a different thread/process (or later, I were unable to figured that out yet), at some point of time the user-process gets the wrong stack-pointer and segment-registers (it gets the values from kernel-mode). That means, just handling an interrupt during idle and after that continue idling, works fine.
My questions are:
Am I missing something? Does this approach even work?
Do I need a separate TSS for the idle-task (I've read this somewhere)? If yes, why? ATM I have one TSS for all because I do the task-switching in software.
Thanks!
hrniels
I'm trying to implement an idle-"thread" which doesn't need much resources and let my OS react quickly on interrupts. Therefore I thought the best way would be not to have a real thread/process for idling but implement the thread-switch as follows:
Code: Select all
void thread_switch(tTid tid) {
if(thread_save(...))
return;
if(tid == idleThread) {
enable_interrupts();
while(1)
asm("hlt");
}
thread_resume(...);
}
So far, so good. As far as I understand this, it should be working. But it doesn't. I'm trying to debug this for more than 2 days now and getting more and more frustrated because I really don't have a clue what is wrong with this approach or my implementation of it :/
I know that as soon as I'm switching from idle to a different thread/process (or later, I were unable to figured that out yet), at some point of time the user-process gets the wrong stack-pointer and segment-registers (it gets the values from kernel-mode). That means, just handling an interrupt during idle and after that continue idling, works fine.
My questions are:
Am I missing something? Does this approach even work?
Do I need a separate TSS for the idle-task (I've read this somewhere)? If yes, why? ATM I have one TSS for all because I do the task-switching in software.
Thanks!
hrniels