having a problem with my multitasking system

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Pyrofan1
Member
Member
Posts: 234
Joined: Sun Apr 29, 2007 1:13 am

having a problem with my multitasking system

Post by Pyrofan1 »

so after reading about TSS for about an hour and then deciding that it was too complex for me, i decided to make my own simple multitasking system
here is task.h

Code: Select all


#include "types.h"
#include "error.h"

#define MAX_TASKS 10

struct TASK tasks[MAX_TASKS];
int current_task=0;
int running_task=0;

void new_task(void *function)
{
	if(current_task==10)
	{
		kerror(ERROR_NO_TASK_SPACE);
	}
	else
	{
		tasks[current_task].eip=(unsigned int)&function;
		asm("mov %%eax, %0"::"g"(tasks[current_task].eax));
		asm("mov %%ebx, %0"::"g"(tasks[current_task].ebx));
		asm("mov %%ecx, %0"::"g"(tasks[current_task].ecx));
		asm("mov %%edx, %0"::"g"(tasks[current_task].edx));
		asm("mov %%esp, %0"::"g"(tasks[current_task].esp));
		asm("mov %%esi, %0"::"g"(tasks[current_task].esi));
		asm("mov %%edi, %0"::"g"(tasks[current_task].edi));
		asm("mov %%ss, %0"::"g"(tasks[current_task].ss));
		asm("mov %%es, %0"::"g"(tasks[current_task].es));
		asm("mov %%gs, %0"::"g"(tasks[current_task].gs));
		asm("mov %%fs, %0"::"g"(tasks[current_task].fs));
		asm("mov %%cs, %0"::"g"(tasks[current_task].cs));
		asm("mov %%ds, %0"::"g"(tasks[current_task].ds));
		asm("pushfl");
		asm("pop %eax");
		asm("mov %%eax, %0"::"g"(tasks[current_task].eflags));

		if(current_task==0)
		{
			tasks[current_task].esp+=(sizeof(long)*100);
		}
		else
		{		
			tasks[current_task].esp+=(sizeof(long)*100)+tasks[current_task-1].esp;
		}
		current_task++;
	}
}

void switch_task(void)
{
	if(running_task==10) running_task=-1;
	running_task++;

	if(tasks[running_task].eip!=0)
	{
		asm("push %0":"=g"(tasks[running_task].eflags));
		asm("popfl");
		asm("mov %0, %%eax":"=g"(tasks[running_task].eax));
		asm("mov %0, %%ebx":"=g"(tasks[running_task].ebx));
		asm("mov %0, %%ecx":"=g"(tasks[running_task].ecx));
		asm("mov %0, %%edx":"=g"(tasks[running_task].edx));
		asm("mov %0, %%edi":"=g"(tasks[running_task].edi));
		asm("mov %0, %%esi":"=g"(tasks[running_task].esi));
		asm("mov %0, %%esp":"=g"(tasks[running_task].esp));
		asm("mov %0, %%ebp":"=g"(tasks[running_task].ebp));
		asm("mov %0, %%ss":"=g"(tasks[running_task].ss));
		asm("mov %0, %%gs":"=g"(tasks[running_task].gs));
		asm("mov %0, %%fs":"=g"(tasks[running_task].fs));
		asm("mov %0, %%cs":"=g"(tasks[running_task].cs));
		asm("mov %0, %%ds":"=g"(tasks[running_task].ds));
		asm("jmp %0":"=g"(tasks[running_task].eip));
	}
}
my TASK structure

Code: Select all

struct TASK
{
	unsigned int gs;
	unsigned int fs;
	unsigned int ds;
	unsigned int ss;
	unsigned int cs;
	unsigned int es;
	unsigned int edi;
	unsigned int esi;
	unsigned int ebp;
	unsigned int esp;
	unsigned int ebx;
	unsigned int edx;
	unsigned int ecx;
	unsigned int eax;
	unsigned int eflags;
	unsigned int eip;
};
here's my main

Code: Select all

void _main(void* mbd,unsigned int magic)
{
	idt_install();
	gdt_install();

	clrscr(BLACK,BLACK);
	set_color(WHITE,BLACK);
	set_echo(1);

	Put("Welcome to PyroS\n");
	init_tasks();
}
my init_tasks function

Code: Select all

void main_loop(void)
{
	for(;;);
}

void init_tasks(void)
{
	new_task((void*)main_loop);
}	
now when i run my OS i get an Invalid opcode exception, but don't see anything in the code that would cause this.
User avatar
ucosty
Member
Member
Posts: 271
Joined: Tue Aug 08, 2006 7:43 am
Location: Sydney, Australia

Post by ucosty »

My best guess is that you are messing up the stack in the new_task function.

In any case this method of task switching is pretty limited and you would be much better of figuring out how to set up a single tss and use proper software switching. It is very easy to get working. The TSS for the most part is set and forget.
The cake is a lie | rackbits.com
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

asm("mov %0, %%eax":"=g"(tasks[running_task].eax));
asm("mov %0, %%ebx":"=g"(tasks[running_task].ebx));
asm("mov %0, %%ecx":"=g"(tasks[running_task].ecx));
asm("mov %0, %%edx":"=g"(tasks[running_task].edx));
asm("mov %0, %%edi":"=g"(tasks[running_task].edi));
asm("mov %0, %%esi":"=g"(tasks[running_task].esi));
asm("mov %0, %%esp":"=g"(tasks[running_task].esp));
asm("mov %0, %%ebp":"=g"(tasks[running_task].ebp));
asm("mov %0, %%ss":"=g"(tasks[running_task].ss));
asm("mov %0, %%gs":"=g"(tasks[running_task].gs));
asm("mov %0, %%fs":"=g"(tasks[running_task].fs));
asm("mov %0, %%cs":"=g"(tasks[running_task].cs));
asm("mov %0, %%ds":"=g"(tasks[running_task].ds));
You are suggesting gcc to pick a register, then move it into another. the result is that at least one of the registers will not have the correct contents as it is overwritten by subsequent MOVs.

In fact, register clobbering and will never allow to store a full state directly to tasks[running_task] without using special measures. The best way to do software multitasking is by using stack switching. Nevertheless, a TSS is practically all normal cases required.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Pyrofan1
Member
Member
Posts: 234
Joined: Sun Apr 29, 2007 1:13 am

Post by Pyrofan1 »

okay, scene now i have to use a TSS, i have some questions about it. The intel manuals seem to imply that each task needs to have a LDT is this true? and also the TSS holds spaces for stacks at different privilege levels, what if i don't have any privilege levels in my OS.
User avatar
ucosty
Member
Member
Posts: 271
Joined: Tue Aug 08, 2006 7:43 am
Location: Sydney, Australia

Post by ucosty »

You don't need any LDT's. The TSS does hold the ring 0 tss for when your os needs to do high ring -> ring 0 transitions. If you are already in ring 0 it will be ignored.
The cake is a lie | rackbits.com
blackcatcoder
Member
Member
Posts: 132
Joined: Wed Nov 03, 2004 12:00 am
Location: Austria
Contact:

Post by blackcatcoder »

if you're gonna to implement the TSS you should also think of implementing GDT IDT and so on and trap gates ........ so first do GDT and IDT with the apropriate Gates, LDT is not necessary at all you just can leave it 0.
User avatar
Dandee Yuyo
Member
Member
Posts: 47
Joined: Fri Nov 09, 2007 6:46 pm
Location: Argentina

Post by Dandee Yuyo »

You might not only be ruining the process task but scratching some other registers aswell... :roll: I would suggest to write that code completely in ASM and debug it line by line.

Good luck! :wink:
NaN - Not a Nerd
Working on: Physical Memory Management with a 5-lod mipmap XD
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Post by jal »

Pyrofan1 wrote:okay, scene now i have to use a TSS, i have some questions about it. The intel manuals seem to imply that each task needs to have a LDT is this true? and also the TSS holds spaces for stacks at different privilege levels, what if i don't have any privilege levels in my OS.
Please note that using a TSS is by no means the only or standard way of doing things. Many developers here would advise against it, as it is slow and very Intel specific.


JAL
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

jal: On the x86 you HAVE to use a TSS if you want a stack switch on interrupt (use a kernel stack much?). What we tend to do is only use one TSS as opposed to one for each process.
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Post by jal »

JamesM wrote:jal: On the x86 you HAVE to use a TSS if you want a stack switch on interrupt (use a kernel stack much?). What we tend to do is only use one TSS as opposed to one for each process.
Yeah, but you don't need to use a TSS if you want to switch the stack manually, iirc, and that's faster than using a TSS.


JAL
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Post by AJ »

If you want to run ring 3 tasks, yes you do. Otherwise, the processor cannot switch back to a ring 0 stack when an interrupt happens. You will need one TSS for each core.

Cheers,
Adam
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

jal wrote:
JamesM wrote:jal: On the x86 you HAVE to use a TSS if you want a stack switch on interrupt (use a kernel stack much?). What we tend to do is only use one TSS as opposed to one for each process.
Yeah, but you don't need to use a TSS if you want to switch the stack manually, iirc, and that's faster than using a TSS.


JAL
Have you implemented tasking, perchance?
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Post by jal »

AJ wrote:If you want to run ring 3 tasks, yes you do. Otherwise, the processor cannot switch back to a ring 0 stack when an interrupt happens. You will need one TSS for each core.
Ok, I stand corrected. I must have confused the matter with something else.


JAL
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Post by jal »

JamesM wrote:Have you implemented tasking, perchance?
I haven't, and I misrecalled something someone told me recently. It was indeed that one only needs one TSS, that being enough (as opposed to using a TSS for each task), not that you need no TSS at all. Appologies again if I caused confusion.


JAL
Post Reply