Page 1 of 1

Stack task switching

Posted: Sun Apr 09, 2006 11:00 pm
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]

Re: Stack task switching

Posted: Sun Apr 09, 2006 11:00 pm
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);
}