Page 1 of 1
Task Switching
Posted: Wed Jun 28, 2006 4:32 pm
by Bob the Avenger
I'm attempting to impliment multitasking (well only multithreading at its current level) in my kernel using stack swtiching, but I'm having a proglem with it. I've managed to narrow it down to my addTask() function. Not all the values are added to the stack correctly and none of the combinations I've tried have worked.
My stump does this:
Code: Select all
# error code and interrupt number already pushed
pusha
pushl %ds
pushl %es
pushl %fs
pushl %gs
movw $0x10,%ax
movw %ax,%ds
movw %ax,%es
movw %ax,%fs
movw %ax,%gs
movw %ax,%ss
movl %esp,%eax
pushl %eax
movl $irqHandler, %eax
call *%eax # replace the old stack esp with the new one
popl %eax
movl %eax,%esp
popl %gs
popl %fs
popl %es
popl %ds
popa
addl $8,%esp
iret
and this is how the values are added to the stack in addTask()
Code: Select all
/* stacksetup = stacktop */
*stacksetup-- = 0x10; // gs
*stacksetup-- = 0x10; // fs
*stacksetup-- = 0x10; // es
*stacksetup-- = 0x10; // ds
*stacksetup-- = 0; // eax
*stacksetup-- = 0; // ecx
*stacksetup-- = 0; // edx
*stacksetup-- = 0; // ebx
*stacksetup-- = 0; // esp
*stacksetup-- = 0; // ebp
*stacksetup-- = 0; // esi
*stacksetup-- = 0; // edi
*stacksetup-- = 0x10; // ss
*stacksetup-- = 0x0202; // eflags
*stacksetup-- = 0x08; // cs
*stacksetup = entry; // eip
When the new stack is loaded, eip is loaded with value 0x0D and eflags is loaded with 0x00010046. I've tried looking at different tutorials and working out the order the values are poped off the stack, but i haven't managed to fix this. Thanks for any help in adavance
Re:Task Switching
Posted: Wed Jun 28, 2006 5:31 pm
by bluecode
You mixed it up a "little" bit
The stack is growing downwards
What I do is the following (s points to 0 e.g., when you want the last page in the virtual address space to be the stack):
Code: Select all
unsigned int *s = reinterpret_cast<unsigned int*>(kernelStack);
*--s = 0x202;//eflags
*--s = 0x10;//CS
*--s = entryPoint;//EIP
*--s = 0; //EAX
*--s = 0; //ECX
*--s = 0; //EDX
*--s = 0; //EBX
*--s = 0; //EBP
*--s = 0; //ESI
*--s = 0; //EDI
*--s = DS;
*--s = ES;
*--s = FS;
*--s = GS
There actually is no ESP in the pusha/popa. And there is no ss on the stack when you don't do priviledge level changes.
Re:Task Switching
Posted: Thu Jun 29, 2006 4:58 am
by Bob the Avenger
Thanks, I think it's like your sig, i was confused on a higher level. I know that the stack grows downwards, but somehow when working out the order of values on the stack, that got mangled and reversed in my head. Thanks for the help, i'll try using that set-up asap.
Re:Task Switching
Posted: Fri Jun 30, 2006 5:19 am
by Bob the Avenger
Hmm, now my task-switch is messed up. The task switch code i am using currently is:
Code: Select all
void taskHandler(regs *r){
clockHandler(r);
/* can/do we need to make a switch */
if(numTasks < 2) return;
/* save old stack */
queue[next++].esp = (dword)r;
/* is next too big? */
if(next >= (numTasks - 1)) next = 0;
/* load new stack */
r = (regs *)queue[next].esp;
}
i have also tried using asm to adjust 'r' in the stack with both the 'movl' and using 'push' and 'pop' instructions with no luck.
TaskHandler() is being called by this:
Code: Select all
void irqHandler(regs *r){
void (*handler)(regs *r);
/* does a handler exist? */
handler = irqRoutines[r->intNo - 32];
if (handler){
handler(r);
}
/* do we need to signal chip2? */
if (r->intNo >= 40){
outportb(0xA0, 0x20);
/* signal chip1 */
outportb(0x20, 0x20);
}
If thats any help. Thanks in advance.
Re:Task Switching
Posted: Fri Jun 30, 2006 6:18 am
by bluecode
Sorry, but I have to correct myself (there was a dword missing)
Code: Select all
unsigned int *s = reinterpret_cast<unsigned int*>(kernelStack);
*--s = 0x202;//eflags
*--s = 0x10;//CS
*--s = entryPoint;//EIP
*--s = 0; //EAX
*--s = 0; //ECX
*--s = 0; //EDX
*--s = 0; //EBX
*--s = 0; //ESP <----- (it's ignored when executing popa)
*--s = 0; //EBP
*--s = 0; //ESI
*--s = 0; //EDI
*--s = DS;
*--s = ES;
*--s = FS;
*--s = GS
So there is an ESP in popa/pusha
sorry about that :-\
Re:Task Switching
Posted: Fri Jun 30, 2006 6:27 am
by Bob the Avenger
Thanks and dont worry about forgetting esp. by the way, I've added 2 empty values between eip and eax because i have a stub before that which pushes an interrupt number and error code, if the interrupt itself doesnt push them. So there needed to be 2 values between what the interrupt causes to be pushed and the pusha.
The problem with it does seem to be in my task-switching code though. I'm thinking of renaming this version of my kernel 666 because its driving me mad.
Edit: No matter if I have set the stack up right it is not working because no switch takes place. That value in loaded into esp is the same value as before the task switching function is called.
Re:Task Switching
Posted: Mon Jul 03, 2006 10:17 pm
by proxy
Code: Select all
# error code and interrupt number already pushed
pusha
pushl %ds
pushl %es
pushl %fs
pushl %gs
movw $0x10,%ax
movw %ax,%ds
movw %ax,%es
movw %ax,%fs
movw %ax,%gs
movw %ax,%ss
movl %esp,%eax
pushl %eax
movl $irqHandler, %eax
call *%eax # replace the old stack esp with the new one
popl %eax
movl %eax,%esp
popl %gs
popl %fs
popl %es
popl %ds
popa
addl $8,%esp
iret
i think i see the problem here, you "call *%eax" which i assume is a function expected to return the new stack...then you immidiately "pop %eax"! and just before a "mov %eax, %esp"...so you are assigning esp to some valuye off the stack, not what the function returned...
I think if you just remove the pop it'll work fine.
proxy
Re:Task Switching
Posted: Tue Jul 04, 2006 2:44 pm
by Bob the Avenger
Yer, well the idea is that a pointer to the stack top gets passed to my task switching function in the arguments, then the taskswitching function changes the value in that bit of the stack to the new esp, so the new esp get popped into eax and then mov'd into esp. No values.
Sorry my code is probably really unclear about that.
Anyway the problem is, the value for the esp, somehow, doesn't get changed (thats shown in the C i posted before)
Re:Task Switching
Posted: Tue Jul 04, 2006 9:59 pm
by proxy
ok, that's fine, but then you have another problem:
you pass r like this:
but then assign to it like this:
well that wont work, because you are passing a copy of the pointer, I would try passing like this: "regs **r" and do "*r = (regs *)queue[next].esp;"
see if that works (and it definitely should)
proxy
Re:Task Switching
Posted: Wed Jul 05, 2006 11:38 am
by Bob the Avenger
Thanks, i'll try that now, although I think your right about its working, because thats what i've told people when they've been editing arguments which are pointers
Re:Task Switching
Posted: Wed Jul 05, 2006 1:45 pm
by Bob the Avenger
Thanks, it does work, now for the minor problem that something thinks my task-switch function is in some very weird memory and page faults when i try to install it in the irq handler. Except, this occurs AFTER i've done all the installing of irqs ???
AND the regs dump, which occurs BEFORE the custom isr handler is called, dupms regs which i would expect AFTER the custom isr handler is called ???
Re:Task Switching
Posted: Wed Jul 12, 2006 5:48 am
by Bob the Avenger
I'm making progress, but after 3 stack swaps, the stack becomes mangled. the correct value of 0x10 is pop'd into gs, 0 is pop'd into es and fs and pop ds causes a GPF. Here is the code i'm using:
Code: Select all
irq0:
cli
pushl $0
pushl $32
jmp irqCommonStub
irqCommonStub:
pusha
pushl %ds
pushl %es
pushl %fs
pushl %gs
movw $0x10,%ax
movw %ax,%ds
movw %ax,%es
movw %ax,%fs
movw %ax,%gs
movw %ax,%ss
movl %esp,%eax
movl %eax,stack(,1)
movl $sysStack, %esp
pushl %eax
movl $irqHandler, %eax
call *%eax
popl %eax
movl stack(,1),%eax
movl %eax,%esp
popl %gs
popl %fs
popl %es
popl %ds
popa
addl $8,%esp
iret
Code: Select all
void irqHandler(regs *r){
void (*handler)(regs *r);
/* does a handler exist? */
handler = irqRoutines[r->intNo - 32];
if (handler){
handler(r);
}
/* do we need to signal chip2? */
if (r->intNo >= 40){
outportb(0xA0, 0x20);
/* signal chip1 */
outportb(0x20, 0x20);
}
void taskHandler(regs *r){
clockHandler(r);
#ifdef DEBUG
/* Output error string to screen. */
printf("PID: %u\n"
"Regs Dump: \n"
" eax: 0x%X ebx: 0x%X ecx: 0x%X edx: 0x%X esp: 0x%X\n"
" ebp: 0x%X esi: 0x%X edi: 0x%X eip: 0x%X eflags: 0x%X\n"
" cs: 0x%X ds: 0x%X es: 0x%X fs: 0x%X gs: 0x%X ss: 0x%X\n",
queue[next].pid, r->eax, r->ebx, r->ecx, r->edx, r->esp, r->ebp,
r->esi, r->edi, r->eip, r->eflags, r->cs, r->ds, r->es, r->fs, r->gs,
r->ss);
#endif /* DEBUG */
/* can/do we need to make a switch */
if(numTasks < 2) return;
/* save old stack */
if(i != 0) queue[next].esp = stack;
printf("Stack: %X\n", stack);
next++;
/* is next too big? */
if(next > (numTasks - 1)) next = 0;
/* load new stack */
stack = queue[next].esp;
printf("Stack: %X\n", stack);
i++;
/* halt after 4 switches to examine regs dump */
if(i == 4) for(;;);
}
Thanks in advance for any help you can give me
Re:Task Switching
Posted: Wed Jul 12, 2006 10:43 pm
by Cody
Hi, Bob
I am just a beginner to OS implementation and by accident I am reading the same tutorial these days.
I have a simple question and I wonder whether you can tell me:
What's the "stacktop" in your first post? Is that the top of the system kernel stack? And is that part of code only used for adding tasks? I read your latest sample code carefully and seems they are nowhere to be found.
Thanks in advance for any of your help!
Best regards,
Cody
Re:Task Switching
Posted: Thu Jul 13, 2006 4:14 am
by Bob the Avenger
its the 'esp' of the stack i am creating for the task, the "*stacksetup-- = ...;" simulate pushes