Page 1 of 1

multitasking

Posted: Sun Sep 06, 2009 11:26 pm
by sebopop
hi everyone.

here is my problem, i just can't get task switching right.I m trying to implement software-based task switching, but it just doesn't work, it get stucks on the first task, i m pretty sure it's the interrupt stack frame that's buggy, and i did googled and search the forums, but i m so frustrated and confused, i m just going nowhere. #-o :?:
i set up an idt with a stub for each interrupt with an (eventual) error code and int number

Code: Select all

__declspec(naked) void int_1()
{
	_asm push 0;
	_asm push 1;
	_asm jmp int_stub;
}
then a general stub is called

Code: Select all

__declspec(naked) void int_stub()
{
	__asm
	{
		pushad;
		push ds;
		push es;
		push fs;
		push gs;
		mov ax, KDATA_SEGMENT;
		mov ds, ax;
		mov es, ax;
		mov gs, ax;
		mov ax, KPCR_SEGMENT;
		mov fs, ax;
		mov eax, esp;
		push eax;
		mov eax, int_handler;
		call eax;
		pop eax;
		pop gs;
		pop fs;
		pop es;
		pop ds;
		popad;
		add esp, 8;
		iretd;
	}
}
eventually calling sys_timer and scheduler

Code: Select all

void sys_timer(PREGS regs)
{
	tick_count++;
	vga_count++;
	if(vga_count==16)
	{
		vga_count = 0;
		vga_flip();
	}//*/

	task_scheduler(regs);
}
scheduler just go round robin with 2 tasks right now

Code: Select all

void task_scheduler(PREGS regs)
{
PKTHREAD pcur_thread = task_get_current_thread();
	PKTHREAD pnext_thread = pcur_thread->next;


	PKPCR kpcr = cpu_getkpcr();

	task_save_regs(pcur_thread, regs);
	pcur_thread->quantum = TASK_DEFAULT_QUANTUM;
	task_set_current_thread(pnext_thread);
	task_load_regs(pnext_thread, regs);

	pcur_thread->state = THREAD_STATE::runnable;
	pnext_thread->state = THREAD_STATE::running;
}
context save (context restore just the opposite) :

Code: Select all

void task_save_regs(PKTHREAD pthread, PREGS regs)
{
	pthread->tss.ds = (WORD)regs->ds;
	pthread->tss.es = (WORD)regs->es;
	pthread->tss.fs = (WORD)regs->fs;
	pthread->tss.gs = (WORD)regs->gs;
	pthread->tss.cs = (WORD)regs->cs;
	pthread->tss.ss = (WORD)regs->ss;

	pthread->tss.eax = regs->eax;
	pthread->tss.ecx = regs->ecx;
	pthread->tss.edx = regs->edx;
	pthread->tss.ebx = regs->ebx;
	pthread->tss.esi = regs->esi;
	pthread->tss.edi = regs->edi;
	pthread->tss.esp = regs->esp;
	pthread->tss.ebp = regs->ebp;
	pthread->tss.eip = regs->eip;

	pthread->tss.eflags = regs->eflags;
}
tasks are just vga_putc('A');
so i know it s running at first. tasks are kernel land, set up with stacks (esp, esp0 but the last is not used i guess), int on, no ldt, etc... pit is 1mhz
i know it's stupid, but there's so much to do and to learn, i m just lost. if i forgot to detail anything, just ask.

thanks to anyone bothering reading this, or answering and sorry for eventual bad english (and bad code).

Re: multitasking

Posted: Sun Sep 06, 2009 11:53 pm
by Troy Martin
Interrupt... 1? I think you mean IRQ0, which != ISR0...

Methinks you should post a little more description of your IRQ/task switching system. There's nothing really wrong with what you've posted, it's just a little vague/non-descriptive.

Oh, and it would be a good idea to use slexy or pastebin for long blocks of code. Makes load times less and you don't need as many code blocks, shortening your post.

Re: multitasking

Posted: Mon Sep 07, 2009 12:15 am
by sebopop
thanks for your time.

int 1 was an example, of course i remapped irq 0 to int 32...
maybe it s a reincursive problem, i m not sure...
didn t knew slexy

http://slexy.org/view/s26vK9JNuj

Re: multitasking

Posted: Mon Sep 07, 2009 2:35 am
by Combuster
Your assembly interrupt handler restores all register from the stack (pushad..popad) any changes to the GPRs made between that won't be seen in userland. If you want to change tasks, you'll need to make sure something else gets loaded between the return to userland.

A common construction would be the following:

Code: Select all

/* irq entry and save registers */
mov eax, esp // store the stackframe
push eax 
call int_handler
add esp, 4
mov esp, eax // load the address of the returned stackframe into ESP
/* restore registers and exit irq */

...

stackframe * int_handler(stackframe * s)
{
    /* do something */
    return s; /* or some other stackframe when we want to switch tasks */
}

Re: multitasking

Posted: Tue Sep 08, 2009 12:29 am
by sebopop
thanks, but i still dont get it, the way i do it (task_load_regs) is lame (twice as moves) but should work anyway, no?
i actually dont think its the stack anymore, but i cant put my finger on the problem! #-o

Re: multitasking

Posted: Tue Sep 08, 2009 11:02 am
by Hangin10
EDIT: When you are saving/restoring registers using the pointer to the stack, you're saving/restoring the ESP pushed by PUSHAD, aren't you? You need to be using the REGS pointer for the value of ESP (as it points to the pushed GS rather than the value of ESP before the PUSHAD instruction), and not to the esp member of REGS, as that value will be ignored by POPAD.

It would be alot easier to just leave the state on the kernel stack (as in, you don't need a function to explicitly save/restore the registers, as they should already be on the stack of what you are switching to), then you only have to deal with changing ESP0 before popping the segment registers and GPRs (like Combuster said, I think).

Re: multitasking

Posted: Mon Sep 14, 2009 5:46 pm
by sebopop
got it working.

thanks to you all for your kindness (better late than never...)