PIT stops after taskswitch
Posted: Wed Aug 31, 2016 3:15 am
I have a problem with my preemptive multitasking code. It switches tasks nicely, but after it PIT doesn't fire anymore. This is my multitasking .c and .h code:
multitasking.h:
multitasking.c:
IRQ0 handler:
I see that it runs idle task one time, then it switches to second and then PIT doesn't fire anymore, so nothing can interrupt second task and it displays 'a' all time.
multitasking.h:
Code: Select all
#ifndef MULTITASKING_H
#define MULTITASKING_H
#include <stdint.h>
enum task_priority {
PRIORITY_IDLE = 1, //Only for idle process.
PRIORITY_LOW = 5,
PRIORITY_NORMAL = 10, //Recommended for use by all regular processes.
PRIORITY_HIGH = 20,
PRIORITY_MAXIMAL = 40, //It will slow down all processes with other priorities, but will work maximally fast.
};
/*
* Reserved PIDs:
*
* - 0 is idle process.
* - 1 is init process. This is every process' parent.
*/
struct task
{
struct task *prev;
//We need to check if the process is dead, so on next PIT tick it will be removed from process list.
uint8_t alive; //On new process, it's set to 1.
uint16_t time_out; //Time before task switch
int8_t exit_status; //Contains 0 when the process is alive. kill_process() sets it to provided value, nulls all register data, frees stack memory and makes alive field == 1.
enum task_priority priority;
void *stack; //Stack needs to be separated from kernel and other processes' stack.
uint32_t eax, ebx, ecx, edx, eip, esi, edi, ebp, cr3;
struct task *next;
};
extern struct task *process_list;
extern struct task *running_task;
void init_multitasking();
void switch_task(struct task*);
#endif
Code: Select all
#include <arch/i686/multitasking.h>
#include <arch/i686/regs.h>
#include <memory.h>
#include <stdio.h>
#include <tty_old.h>
#include <stddef.h>
struct task *process_list=NULL;
struct task *running_task;
void insertTaskAfter(struct task* a, struct task* b)
{
b->prev = a;
b->next = a->next;
a->next = b;
b->next->prev = b;
}
//What do you want?
//Arguments. Lots of arguments.
struct task *create_task(void *page_directory,
void *start_address,
enum task_priority priority)
{
struct task *t = malloc(sizeof(struct task));
printf("creating task, structure address=0x%x, code address=0x%x\n", t, start_address);
t->eax = 0;
t->ebx = 0;
t->ecx = 0;
t->edx = 0;
t->esi = 0;
t->edi = 0;
t->stack = malloc(4096) + 4096; //4kb will be enough
t->eip = (uint32_t) start_address;
t->cr3 = (uint32_t) page_directory;
t->priority = priority;
t->alive = 1;
t->exit_status = 0;
t->time_out = priority;
t->next = t; //It will point to start of process list.
//Now we will put it into our process list.
if(process_list)
insertTaskAfter(process_list->prev, t);
else
{
t->prev = t;
process_list = t;
}
//process_list->prev = t;
return t;
}
static uint32_t task_eip_address; //VERY bad code, but everything crashes without this
void __attribute__((noreturn)) switch_task(struct task *task)
{
//We will change stack there, so we want to save EIP to jump.
task_eip_address = task->eip;
asm volatile("mov %0, %%eax;"
"mov %1, %%ebx;"
"mov %2, %%ecx;"
"mov %3, %%edx;"
"mov %4, %%esi;"
"mov %5, %%edi;"
"mov %6, %%ebp;"
"mov %7, %%esp;" :
"=g" (task->eax),
"=g" (task->ebx),
"=g" (task->ecx),
"=g" (task->edx),
"=g" (task->esi),
"=g" (task->edi),
"=g" (task->ebp),
"=g" (task->stack) : : "memory");
asm volatile("jmp *%0" : "=g" (task_eip_address) : : "memory");
//If something happened, halt the system.
while(1);
}
void idle_process()
{
while(1)
asm("sti; hlt");
}
void test_process()
{
while(1)
tty_putchar('a');
}
void test2_process()
{
while(1)
tty_putchar('b');
}
void test3_process()
{
while(1)
//tty_putchar('c');
;
}
void init_multitasking()
{
create_task(0, (void*) idle_process, PRIORITY_IDLE);
create_task(0, (void*) test_process, PRIORITY_NORMAL);
create_task(0, (void*) test2_process, PRIORITY_NORMAL);
create_task(0, (void*) test3_process, PRIORITY_NORMAL);
struct task *t;
for(t = process_list; t->next!=process_list; t=t->next)
printf("struct: 0x%x, code: 0x%x, priority: %d -> ", t, t->eip, t->priority);
printf("struct: 0x%x, code: 0x%x, priority: %d", t, t->eip, t->priority);
running_task = process_list; //Idle process enters the scene! Woo-hoo!
}
Code: Select all
void timer_handler(regs* r)
{
tty_wrstr("Timer interrupt!\n");
timer_ticks++; //Just increment timer_ticks.
if(running_task->time_out) //Yes, it can be zero.
running_task->time_out--;
if(running_task->time_out == 0) //Our task's time is out, so we need to switch task.
{
running_task->time_out = running_task->priority;
//Save current task state and switch to next task.
running_task->eax = r->eax ;
running_task->ebx = r->ebx ;
running_task->ecx = r->ecx ;
running_task->edx = r->edx ;
running_task->esi = r->esi ;
running_task->edi = r->edi ;
running_task->eip = r->eip ;
running_task = running_task->next ;
//Current task state saved. We will call switch_task to actually switch.
printf("Interrupting current task! New EIP is 0x%x\n", running_task->eip);
switch_task(running_task);
}
}