Page 1 of 3
Having some trouble with my multitasking system
Posted: Sat Mar 22, 2008 11:07 pm
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
Posted: Sun Mar 23, 2008 9:11 am
by t0xic
Well, first off you can't do this:
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
Posted: Sun Mar 23, 2008 10:20 am
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
would return the memory address of that function.
Posted: Sun Mar 23, 2008 10:33 am
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.
Posted: Sun Mar 23, 2008 10:47 am
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?
Posted: Sun Mar 23, 2008 11:05 am
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.
Posted: Sun Mar 23, 2008 11:12 am
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.
Posted: Sun Mar 23, 2008 12:01 pm
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.
Posted: Sun Mar 23, 2008 12:23 pm
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.
Posted: Sun Mar 23, 2008 1:48 pm
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();.
Posted: Sun Mar 23, 2008 2:15 pm
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
And use strcpy();.
taken care of
Posted: Sun Mar 23, 2008 4:33 pm
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.

Posted: Sun Mar 23, 2008 5:53 pm
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);
}
Posted: Sun Mar 23, 2008 6:26 pm
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.
Posted: Mon Mar 24, 2008 7:39 pm
by proxy
t0xic: there is nothing wrong:
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