Stack task switching

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
User avatar
Jeko
Member
Member
Posts: 500
Joined: Fri Mar 17, 2006 12:00 am
Location: Napoli, Italy

Stack task switching

Post by Jeko »

I'm using a stack task switching. But it not work!
I post the code:
This is the interrupt handler of the pit:

Code: Select all

asm(".globl pit_ISR	\n"
    "pit_ISR:		\n"
    "cli		\n"
    "pusha		\n"
    "movl %esp, %eax	\n"
    "pushl %eax		\n"
    "call pit_handler	\n"
    "popl %eax		\n"
    "mov %eax, %esp	\n"
    "popa		\n"
    "sti		\n"
    "iret		\n");
This is the scheduler

Code: Select all

void task1(void);
void task2(void);
void task3(void);
void task4(void);

void switch_task(unsigned int stack)
{
      asm("mov %0, %%esp /*reimposto lo stack*/	\n" "popa /*ripristino tutti i registri*/	\n" "sti  /*riabilito gli interrupt*/	\n" "iret /*esco dall'interrupt     */   \n": :"a"(stack));
}

void *make_tss(void (*func) (), void (*end_func) ())
{
	struct TSS *mytss = (struct TSS *) ((unsigned int) malloc(0x5000) + 0x5000 - 100);
	mytss->eip = (unsigned int) func;
	mytss->cs = 8;
	mytss->eflags = 0x202;
	mytss->fine = (unsigned int)end_func;
	return mytss;
}

void del_tss(void *tss)
{
	free(tss);
	return;
}


struct task_descriptor tasks[1000];
unsigned int current_task = 0;
unsigned int num_task = 1;
int active = 0;
unsigned int tasktask=2;

volatile unsigned int tick;

unsigned int find_next_task()
{
	do
		if(++tasktask >= num_task)
			tasktask=0;
	while(tasks[tasktask].stato != ESECUZIONE);
	return tasktask;
}

void scheduler(unsigned int * stack)
{
	if (!active)
		return;
	unsigned int one_task;
	tasks[current_task].esp = *stack;
	one_task = find_next_task();
	switch (tasks[one_task].stato)
	{
		case ESECUZIONE:
			current_task = one_task;
			*stack = tasks[current_task].esp;
			//switch_task(*stack);
		break;

		case ADDORMENTATO:
			if (tasks[one_task].dormo.tick)
			{
				if ((tasks[one_task].dormo.tick + tasks[one_task].dormo.secondi) <= tick)
				{
					tasks[one_task].stato = ESECUZIONE;
					current_task = one_task;
					*stack = tasks[current_task].esp;
					//switch_task(*stack);
				}
				else
				{
					scheduler(stack);
				}
			}
			else
			{
				scheduler(stack);
			}
		break;

		case MORTO:
			del_tss(tasks[one_task].tss);
			scheduler(stack);
		break;
	}
}

void attiva_scheduler()
{
	active = 1;
}

void disattiva_scheduler()
{
	active = 0;
}

void init_scheduler()
{
	active = 1;
	current_task = 0;
	add_task(task1, "Task 1");
	add_task(task2, "Task 2");
	add_task(task3, "Task 3");
	add_task(task4, "Task 4");
	return;
}

unsigned int add_task(void (*func) (), char *nome)
{
	asm("cli");
	//kout << endl <<  num_task << " task creato" << endl;
	tasks[num_task].tss = (void *)make_tss(func, suicide);
	tasks[num_task].esp = (unsigned int) tasks[num_task].tss;
	//imposto il nome del task
	strncpy(tasks[num_task].nome, nome, 50);
	//ne imposto lo stato
	tasks[num_task].stato = ESECUZIONE;
	tasks[num_task].process_id = num_task;
	++num_task;
	asm("sti");
	return num_task - 1;
}

unsigned int get_current_task()
{
	return current_task;
}

void kill(unsigned int id)
{
	tasks[id].stato = MORTO;
	while (1);
}

char *get_task_name(unsigned int id, char *nome)
{
	strcpy(nome, tasks[id].nome);
	return nome;
}


void suicide()
{
	kill(get_current_task());
}

void sleep(unsigned int centesimi)
{
	asm("cli");
	tasks[get_current_task()].stato = ADDORMENTATO;
	tasks[get_current_task()].dormo.tick = tick;
	tasks[get_current_task()].dormo.secondi = centesimi;
	asm("sti");
	while (tick == tasks[get_current_task()].dormo.tick);
}

void addormenta(unsigned int pid)
{
	asm("cli");
	tasks[pid].stato = ADDORMENTATO;
	tasks[pid].dormo.tick = 0;
	if (pid == get_current_task()) {
		unsigned int mytick = tick;
		asm("sti");
		while (tick == mytick);
	}
	else
	{
		asm("sti");
	}
}

void sveglia(unsigned int pid)
{
	tasks[pid].stato = ESECUZIONE;
}

void task1()
{
	printf("CIAO");
	while(1);
}

void task2()
{
	char asssd = getch();
	printf(asssd);
	while(1);
}

void task3()
{
	printf("HALO");
	while(1);
}

void task4()
{

	printf("Who Ming");
	while(1);
}

This is the task_descriptor struct:

Code: Select all

#define ESECUZIONE 1
#define ADDORMENTATO 2
#define MORTO 3

struct sleep_t
{
	unsigned int tick;
	unsigned int secondi;
};

struct task_descriptor
{
	unsigned int esp;
	void *tss;
	char nome[50];
	unsigned int process_id;
	int stato;
	struct sleep_t dormo;
};
This is the struct that is in the register esp

Code: Select all

struct TSS
{
	unsigned int edi;	//+0
	unsigned int esi;	//+1
	unsigned int ebp;	//+2
	unsigned int null;	//+3
	unsigned int ecx;	//+4
	unsigned int edx;	//+5
	unsigned int ebx;	//+6
	unsigned int eax;	//+7
	unsigned int eip;	//+8
	unsigned int cs;	//+9
	unsigned int eflags;	//+10
	unsigned int fine;
};
When I try the kernel, the task switching not work! Where is the error?[/code]
Last edited by Jeko on Sun Apr 09, 2006 11:00 pm, edited 1 time in total.
digo_rp
Member
Member
Posts: 233
Joined: Sun Jun 05, 2005 11:00 pm

Re: Stack task switching

Post by digo_rp »

you just need one TSS if you want to have protection, to use stack based taskswitching is simple, on your scheduler " in C " you just change the TSS.SS0 and TSS.ESP0 to the next task to be switched... and IRQ0_handler " in asm "you use something like that

"In asm"
_irq00:
pushad
push gs
push fs
push ds
push es

mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

mov al, 0x20
out 0x20, al

mov [_OldTaskESP], esp

call _timer_handler

mov esp, [_NewTaskESP]

; mov eax, [_Task_CR3]
; mov cr3, eax

mov eax, cr0
or eax, 0x8 ; Set TS flag to use x87.fxsave with
mov cr0, eax ; device not available

pop es
pop ds
pop fs
pop gs
popad
iretd

"in C My scheduler"

void timer_handler(void) {
tcount++;
loop_exit = 0;

process[current_task].ustack = OldTaskESP;

while (!loop_exit) {
current_task++;

if (current_task > num_of_tasks) current_task = 0;

if (process[current_task].status == 2) {
Task_TSS.esp0 = process[current_task].kstack;
// Task_CR3 = process[current_task].cr3;
NewTaskESP = process[current_task].ustack;
loop_exit = 1;
}
}
loop_exit = 0;
}

"my Add_task"
short add_task(char *str, dword cs, dword entry, dword ds, dword eflags, byte taskpriv) {
num_of_tasks++;
memset(process[num_of_tasks].stack, 0, stack_size);
memset(process[num_of_tasks].name, 0, 20);
insertstr(process[num_of_tasks].name, str);
process[num_of_tasks].v86 = 0;
process[num_of_tasks].eflags = eflags;
process[num_of_tasks].id = num_of_tasks;
process[num_of_tasks].priv = taskpriv;
process[num_of_tasks].status = 2;
process[num_of_tasks].task_sel = 0x28;
process[num_of_tasks].kstack = (dword)&pl0_stack[num_of_tasks][stack_size];
stacksetup = (dword)&process[num_of_tasks].stack+stack_size;
*stacksetup-- = ds;
*stacksetup-- = (dword)&process[num_of_tasks].stack+stack_size;
*stacksetup-- = eflags;
*stacksetup-- = cs;
*stacksetup-- = entry;
*stacksetup-- = 0; /* EAX */
*stacksetup-- = 0; /* ECX */
*stacksetup-- = 0; /* EDX */
*stacksetup-- = 0; /* EBX */
*stacksetup-- = 0; /* EBP */
*stacksetup-- = 0; /* ESI */
*stacksetup-- = 0; /* EDI */
*stacksetup-- = ds; /* GS */
*stacksetup-- = ds; /* FS */
*stacksetup-- = ds; /* DS */
*stacksetup-- = ds; /* ES */
process[num_of_tasks].ustack = (dword)stacksetup;
multitasking = 1;
tr_atual = 0x28;
return(num_of_tasks);
}
Post Reply