I'm trying to implement task switching in my OS. Creating a process and jumping to it seems fine, the problem arises when actually context switching. It seems that after the iret in task_switch, I get a GPF (error code 0), even when there's only one process switching to itself. I've included the relevant code sections below.
Code: Select all
typedef struct task {
int id; //process id
uint32_t esp; //stack pointer
uint32_t stack_top; //top of stack
uint32_t eip; //instruction pointer
uint32_t cr3; //page directory
struct task* next; //next task in linked list
struct task* prev; //previous task
} task_t;
Code: Select all
void tasking_install() {
printf_info("Initializing tasking...");
//init first task (kernel task)
ready_queue = (volatile task_t*)create_process(PRIO_HIGH, (uint32_t)test_1);
current_task = (task_t*)ready_queue;
current_task->next = current_task;
current_task->prev = current_task;
//add_process(create_process(PRIO_MED, (uint32_t)test_2));
//add_process(create_process(PRIO_MED, (uint32_t)test_3));
//create callback to switch tasks
//add_callback((void*)switch_callback, 1, 1, 0);
jumpstart_main_thread();
ASSERT(1, "Failed to start tasking!");
}
static void jumpstart_main_thread() {
asm volatile("mov %%eax, %%esp": :"a"(current_task->esp));
asm volatile("pop %gs");
asm volatile("pop %fs");
asm volatile("pop %es");
asm volatile("pop %ds");
asm volatile("pop %ebp");
asm volatile("pop %edi");
asm volatile("pop %esi");
asm volatile("pop %edx");
asm volatile("pop %ecx");
asm volatile("pop %ebx");
asm volatile("pop %eax");
asm volatile("iret");
}
task_t* create_process(int priority, uint32_t addr) {
task_t* task = (task_t*)kmalloc(sizeof(task_t));
memset(task, 0, sizeof(task_t));
task->id = next_pid++;
task->eip = addr;
task->esp = (uint32_t)kmalloc(KERNEL_STACK_SIZE);
asm volatile("mov %%cr3, %%eax" : "=a"(task->cr3));
uint32_t* stack = (uint32_t*)(task->esp + KERNEL_STACK_SIZE);
task->stack_top = task->esp;
*--stack = 0x00000202; //eflags
*--stack = 0x8; //cs
*--stack = (uint32_t)addr; //eip
*--stack = 0; //eax
*--stack = 0; //ebx
*--stack = 0; //ecx
*--stack = 0; //edx
*--stack = 0; //esi
*--stack = 0; //edi
*--stack = task->esp + KERNEL_STACK_SIZE; //ebp
*--stack = 0x10; //ds
*--stack = 0x10; //fs
*--stack = 0x10; //es
*--stack = 0x10; //gs
task->esp = (uint32_t)stack;
printf_info("Created process (PID %d) with esp %x eip %x", task->id, task->esp, task->eip);
return task;
Code: Select all
void task_switch() {
//if we haven't initialized tasking yet, quit early
//if (!current_task) return;
asm volatile("push %eax");
asm volatile("push %ebx");
asm volatile("push %ecx");
asm volatile("push %edx");
asm volatile("push %esi");
asm volatile("push %edi");
asm volatile("push %ebp");
asm volatile("push %ds");
asm volatile("push %es");
asm volatile("push %fs");
asm volatile("push %gs");
asm volatile("mov %%esp, %%eax":"=a"(current_task->esp));
current_task = current_task->next;
asm volatile("mov %%eax, %%cr3": :"a"(current_task->cr3));
asm volatile("mov %%eax, %%esp": :"a"(current_task->esp));
asm volatile("pop %gs");
asm volatile("pop %fs");
asm volatile("pop %es");
asm volatile("pop %ds");
asm volatile("pop %ebp");
asm volatile("pop %edi");
asm volatile("pop %esi");
asm volatile("pop %edx");
asm volatile("pop %ecx");
asm volatile("pop %ebx");
asm volatile("pop %eax");
asm volatile("iret");
}