I really don't know a lot about multitasking, as I haven't yet reached that point of my kernel, but I can see a major flaw in your code: you jump to the task while you're still inside the interrupt handler.
I will explain myself:
Code: Select all
IRQ0:
cli
pusha and other pushes
call _schedule <<-------- C function schedule
{
account_for_passed_ticks;
find_next_thread();
switch_to(tread->gdt); <<---------- ASM proc switch_to
ljmp *(%esp) <<--- jump to the procedure
ret
}
other pops and popa
sti
iret
And the flaws are...
- No really a flaw, but you're mixing intel syntax (proc IRQ0) with AT&T (switch_to)... What for? Use nasm or gas, but not both (well, do what you want, just an opinion)
- You're using the hardware task switching method. Again, do what you want, but even if hardware task management is far easier for the OSdever, it 1) is way slower than a good designed software management, and 2) won't work for AMD64 processors, so it is not "future compatible"
- And the real flaw: you're jumping to the task while still inside the IRQ0 handler, as this language-mixed, call-nested view shows. So, when you jump to the next thread, INTERRUPTS ARE STILL DISABLED (execution has not yet arrived to STI). So, even when the task switch succeeds (that I don't know), the next clock interrupt will never arrive and the scheduler won't be called again.
So what can you do with the real flaw? Well, you could, for example, modify the return information in the stack of IRQ0.
This works for software task management, but I don't know if it will for the hardware, TSS-based version. Basically, the idea is this: the CS:EIP in force when the interrupt was detected is stored in the stack, and used by IRET to return to it. Just replace it with the address you want to jump to.
Assuming that information was stored just before calling the handler (that I don't know, look for it at the intel/amd manuals), the code would be like this:
Code: Select all
IRQ0:
cli
push %ebp
mov %esp, %ebp <<---- return address would be at 4(%ebp)
pusha and other pushes
<<-- save current thread info from the stack to the thread table
call _schedule <<---- C functions return value is at %EAX
mov %eax, 4(%ebp) <<-- modify return address
<<-- if the task will change, load the new state from the thread table to the stack
other pops and popa
pop %ebp
sti
iret <<-- this will return to the modified return address
void* schedule()
{
account_for_ticks;
nextThread = GetNextThread();
return nextThread->eip;
}
This code is 100% na?ve, does not account for changes in the code segment of apps, has probably more errors than your code, and a lot of etceteras, but I think (correct me please, OSdevers of the forum) these are the basics of multitasking
[edit]aargh! i always go crazy with the stack direction T_T[/edit]