Having some trouble 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.
Pyrofan1
Member
Member
Posts: 234
Joined: Sun Apr 29, 2007 1:13 am

Having some trouble with my multitasking system

Post by Pyrofan1 »

Okay, so today i tried to make a multitasking system. When i tried it out nothing happened and what i mean by that is the computer freezes completely. There is no evidence of interrupts firing at all. I have looked over my code several times and i don't see any missing sti or misplaced cli.

Here is my structure

Code: Select all

struct PROCESS
{
	char *name;
	unsigned int eax;
	unsigned int ebx;
	unsigned int ecx;
	unsigned int edx;
	unsigned int esi;
	unsigned int edi;
	unsigned int cr0;
	unsigned int cr3;
	unsigned int eip;
	unsigned int esp;
	unsigned int ebp;
	unsigned short pid;
	unsigned char status;
	unsigned int suspend;
	unsigned char access;
};
here is how i initiate tasking

Code: Select all

start_task(&printl,"Printl",USER);
Printf("Starting tasks\t");
init_tasking(&idle_task);
Printf("Done\n");
my idle_task and printl functions

Code: Select all

void idle_task(void)
{
	for(;;);
}

void printl(void)
{
	for(;;)
	{
		asm("mov $0, %eax"); //system calls to print 'A'
		asm("mov $65, %ebx");
		asm("int $0x80");
		asm("mov $3, %eax"); //system calls to suspend task for 5 seconds
		asm("mov $5000, %ebx");
		asm("int $0x80");
	}
}
and i've attached my tasking code
Attachments
task.h
(2.95 KiB) Downloaded 102 times
User avatar
t0xic
Member
Member
Posts: 216
Joined: Sat May 05, 2007 3:16 pm
Location: VA
Contact:

Post by t0xic »

Well, first off you can't do this:

Code: Select all

tasks[0].name="Idle process";
You need to use strcpy or the likes.

For the rest of this, look here: http://code.google.com/p/onyxkernel/wik ... ltitasking (shameless plug)
or here: http://www.osdever.net/tutorials/multitasking.php

Hope that helps,
Michael
Pyrofan1
Member
Member
Posts: 234
Joined: Sun Apr 29, 2007 1:13 am

Post by Pyrofan1 »

After reading those links i realized that i wasn't properly changing the values in the stack to so when it popped all the registers the proper values weren't there. My problem now is that it Red Screens and tells me that eip=3 which obviously isn't right. I'm wondering why it's doing this because i thought that

Code: Select all

&some_function
would return the memory address of that function.
User avatar
t0xic
Member
Member
Posts: 216
Joined: Sat May 05, 2007 3:16 pm
Location: VA
Contact:

Post by t0xic »

Try:

Code: Select all

tasks[0].eip = (unsigned int) ((void*)some_function);
.

You shouldn't need that eip value though, just setup a stack instead. I would convert to either of the code examples I showed you, as they work great for me.
Pyrofan1
Member
Member
Posts: 234
Joined: Sun Apr 29, 2007 1:13 am

Post by Pyrofan1 »

Tried that code, same deal.
You shouldn't need that eip value though, just setup a stack instead
what do you mean by that?
User avatar
t0xic
Member
Member
Posts: 216
Joined: Sat May 05, 2007 3:16 pm
Location: VA
Contact:

Post by t0xic »

did you read/look over either of the pages with code that I posted? You setup a stack with register values, including eip on it, and when you want to switch tasks, you just change ESP to the stack of the task you set up.
Pyrofan1
Member
Member
Posts: 234
Joined: Sun Apr 29, 2007 1:13 am

Post by Pyrofan1 »

But that's pretty much what i'm doing already. When the timer interrupt fires and the switch_task function gets call, it changes the values that have been pushed onto the stack then when the code gets to iret as we all know the eip register gets popped off. The only difference is that the values are on the kernel stack.
User avatar
t0xic
Member
Member
Posts: 216
Joined: Sat May 05, 2007 3:16 pm
Location: VA
Contact:

Post by t0xic »

I don't see any stacks or irets in the code you posted?

edit: just saw this line:

Code: Select all

tasks[c].esp=kmalloc(0);
tasks[c].ebp=tasks[0].esp;
You need a stack! That is where you must push the values onto.
Pyrofan1
Member
Member
Posts: 234
Joined: Sun Apr 29, 2007 1:13 am

Post by Pyrofan1 »

Okay, i changed my code so that the registers are pushed onto each processes stack. And I still get an invalid opcode exception with eip=3
my process structure

Code: Select all

struct REGS
{
    	unsigned int gs, fs, es, ds;      /* pushed the segs last */
    	unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;  /* pushed by 'pusha' */
    	unsigned int int_no, err_code;    /* our 'push byte #' and ecodes do this */
    	unsigned int eip, cs, eflags, useresp, ss;   /* pushed by the processor automatically */ 
}__attribute__((packed));


struct PROCESS
{
	char *name;
	struct REGS *r;
	unsigned int *esp;
	unsigned short pid;
	unsigned char status;
	unsigned int suspend;
	unsigned char access;
};
and i've attached my code.
Attachments
task.h
(4.2 KiB) Downloaded 99 times
User avatar
t0xic
Member
Member
Posts: 216
Joined: Sat May 05, 2007 3:16 pm
Location: VA
Contact:

Post by t0xic »

esp should not be a pointer, and your stack should expand down, i.e:

Code: Select all

void CreateTask(int id, unsigned char name[32], void (*thread)())
{
        asm volatile("cli");
        unsigned int *stack;
        task_t *task = (task_t*) kmalloc(sizeof(task_t));
        task->stack = kmalloc_a(0x1000) + 0x1000;       // Allocate 4 kilobytes of space

        stack = (unsigned int*)task->stack;

        // Expand down stack
        // processor data
        *--stack = 0x202;       // EFLAGS
        *--stack = 0x08;        // CS
        *--stack = (unsigned int) thread;       // EIP

        // pusha
        *--stack = 0;           // EDI
        *--stack = 0;           // ESI
        *--stack = 0;           // EBP
        *--stack = 0;           // NULL
        *--stack = 0;           // EBX
        *--stack = 0;           // EDX
        *--stack = 0;           // ECX
        *--stack = 0;           // EAX

        // data segments
        *--stack = 0x10;        // DS
        *--stack = 0x10;        // ES
        *--stack = 0x10;        // FS
        *--stack = 0x10;        // GS

        task->state = 1;
        task->stack = (unsigned int) stack;
        task->thread = thread;
        strncpy(task->name, name, strlen(name));

        tasks[id] = *task;

        asm volatile("sti");
        
}
edit: STILL!!! :? :? :?

Code: Select all

tasks[0].name="Idle process";
tasks[0].esp=kmalloc(0);
change the kmalloc(0) to kmalloc(4096). And use strcpy();.
Pyrofan1
Member
Member
Posts: 234
Joined: Sun Apr 29, 2007 1:13 am

Post by Pyrofan1 »

Okay, i changed it to your advice, but now it just freezes again
change the kmalloc(0) to kmalloc(4096)
I should have mentioned that my kmalloc function, by default allocates 4096 bytes :oops:
And use strcpy();.
taken care of
Attachments
task.h
(4.02 KiB) Downloaded 64 times
User avatar
t0xic
Member
Member
Posts: 216
Joined: Sat May 05, 2007 3:16 pm
Location: VA
Contact:

Post by t0xic »

The best way to do this is to set up the scheduler (switch_task, or whatever) as an interrupt handler, so that you can iret to a task, just like in my example.

edit: sorry for being frustrated. didn't know that your kmalloc() alloc'ed 4096. :oops:
Pyrofan1
Member
Member
Posts: 234
Joined: Sun Apr 29, 2007 1:13 am

Post by Pyrofan1 »

The best way to do this is to set up the scheduler (switch_task, or whatever) as an interrupt handler
well, the way i set it up is that it is called by the PIT int handler like this

Code: Select all

void timer_handler(struct REGS *r)
{
	ticks++;
	update_cursor();
	update_time();
	switch_tasks((struct REGS*)r);
}
User avatar
t0xic
Member
Member
Posts: 216
Joined: Sat May 05, 2007 3:16 pm
Location: VA
Contact:

Post by t0xic »

My scheduler is the interrupt handler, and the scheduler calls the timer, not the other way around.

edit:

your switch_tasks function shouldn't be changing the values of registers.
Thats the purpose of the having a stack. Just pop the values off of the stack. look at the working examples I have posted.
User avatar
proxy
Member
Member
Posts: 108
Joined: Wed Jan 19, 2005 12:00 am
Contact:

Post by proxy »

t0xic: there is nothing wrong:

Code: Select all

tasks[0].name="Idle process"; 
the type of name is char * and "Idle process" is a string constant which should be in the .rodata section. It is perfectly legal (while not smart from a future planning perspective) to make a char * point to a string constant like that.

proxy
Post Reply