If I don't add some delay to tasks, it page faults after a while, with a strange faulting address like 0, 10, 12, 34, but then I fixed that with adding schedule_noirq(); before printf()s. Is that correct?
And bugs, firstly, if I dump tasks with:
Code: Select all
printf("kernel_idle: %x, %s\ntest1: %x, %s\ntest2: %x, %s\n", task_getpid("kernel_idle"), task_getname(0), task_getpid("test1"), task_getname(1), task_getpid("test2"), task_getname(2));
If i some delay after printf, it works, but os freezes after a short while.
I think something in my implementation messes stack, but I don't know what's causing that
That is irq0 handler:
Code: Select all
.macro IRQ ident byte
.global _irq\ident
.type _irq\ident, @function
_irq\ident:
cli
push $0x00
push $\byte
jmp irq_common
.endm
/* Interrupt Requests */
IRQ 0, 32
IRQ 1, 33
IRQ 2, 34
IRQ 3, 35
IRQ 4, 36
IRQ 5, 37
IRQ 6, 38
IRQ 7, 39
IRQ 8, 40
IRQ 9, 41
IRQ 10, 42
IRQ 11, 43
IRQ 12, 44
IRQ 13, 45
IRQ 14, 46
IRQ 15, 47
.extern irq_handler
.type irq_handler, @function
irq_common:
pusha
/* Save segment registers */
push %ds
push %es
push %fs
push %gs
/* Call interrupt handler */
push %esp
call irq_handler
add $4, %esp
/* Restore segment registers */
pop %gs
pop %fs
pop %es
pop %ds
/* Restore all registers */
popa
/* Cleanup error code and IRQ # */
add $8, %esp
/* pop CS, EIP, EFLAGS, SS and ESP */
iret
Code: Select all
volatile bool tasking = false;
typedef struct task
{
registers_t regs;
uintptr_t page_directory;
char* name;
uint32_t pid;
struct task* next;
} task_t;
task_t* task_idle;
task_t* current_task;
uint32_t last_pid = 1;
task_t* create_task(char* name, void (*func)(), uint32_t flags, uintptr_t page_directory)
{
task_t *task = (task_t*) calloc(1, sizeof(task_t));
task->name = name;
task->regs.cs = 0x08;
task->regs.gs = 0x10;
task->regs.fs = 0x10;
task->regs.es = 0x10;
task->regs.ds = 0x10;
task->regs.ss = 0x10;
task->regs.eflags = flags;
task->regs.eip = (uint32_t) func;
task->regs.useresp = (uint32_t) (malloc(0x1000) + 0x1000);
task->page_directory = page_directory;
task->next = NULL;
return task;
}
uint32_t add_task(task_t* task)
{
task->pid = last_pid++;
task_t* last_task = task_idle;
while (last_task->next != NULL) last_task = last_task->next;
last_task->next = task;
return task->pid;
}
void remove_task(uint32_t pid)
{
if (pid == 0) return;
task_t* task = task_idle;
for (uint32_t i = 0; i < pid - 1; i++) task = task->next;
task_t* temp = task->next;
task->next = temp->next;
free(temp);
}
uint32_t task_getpid(char* name)
{
task_t* task = task_idle;
while (task)
{
if (strcmp(task->name, name) == 0) break;
task = task->next;
}
if (task == NULL) return 0xFFFFFFFF;
return task->pid;
}
char* task_getname(uint32_t pid)
{
task_t* task = task_idle;
while (task)
{
if (task->pid == pid) break;
task = task->next;
}
if (task == NULL) return "(error)";
return task->name;
}
void schedule(registers_t* regs)
{
if (tasking)
{
memcpy(¤t_task->regs, regs, sizeof(registers_t));
if (current_task->next != NULL) current_task = current_task->next;
else current_task = task_idle;
memcpy(regs, ¤t_task->regs, sizeof(registers_t));
}
}
void timer(registers_t* regs)
{
schedule(regs);
}
void schedule_noirq()
{
asm volatile("int $0x20");
return;
}
void idle()
{
for(;;)
{
schedule_noirq();
printf("a");
}
}
void test1()
{
for(;;)
{
schedule_noirq();
printf("b");
}
}
void test2()
{
for(;;)
{
schedule_noirq();
printf("c");
}
}
void init_tasking()
{
uint32_t eflags;
asm volatile("pushfl; movl (%%esp), %%eax; movl %%eax, %0; popfl;":"=m"(eflags)::"%eax");
task_idle = create_task("kernel_idle", &idle, eflags, read_cr3());
current_task = task_idle;
add_task(create_task("test1", &test1, eflags, read_cr3()));
add_task(create_task("test2", &test2, eflags, read_cr3()));
idle();
}
Code: Select all
typedef struct regs
{
unsigned int gs, fs, es, ds;
unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;
unsigned int int_no, err_code;
unsigned int eip, cs, eflags, useresp, ss;
} registers_t;
I also tried changing "task->regs.useresp = (uint32_t) (malloc(0x1000) + 0x1000);" with "task->regs.esp = (uint32_t) (malloc(0x1000) + 0x1000);" but didn't change anything.
Thanks
Notes:
void timer(); is IRQ0 handler, calls schedule in 100Hz.
void schedule_noirq() calls IRQ0 without waiting PIT.
Can writing a separate irq0 handler to keep the stack safe instead of irq_common work?