diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/l0/context_switch.s | 32 | ||||
-rw-r--r-- | kernel/l0/task.c | 40 |
2 files changed, 52 insertions, 20 deletions
diff --git a/kernel/l0/context_switch.s b/kernel/l0/context_switch.s index 7351997..6738a03 100644 --- a/kernel/l0/context_switch.s +++ b/kernel/l0/context_switch.s @@ -11,10 +11,7 @@ save_context_and_enter_scheduler: mov eax, cr3 push eax - mov ax, ds ; Lower 16-bits of eax = ds. - push eax ; save the data segment descriptor - - mov eax, [esp+48] ; get address of saved_context structure + mov eax, [esp+44] ; get address of saved_context structure mov [eax], esp ; save esp mov dword [eax+4], resume_saved_context ; save eip @@ -23,18 +20,33 @@ save_context_and_enter_scheduler: resume_saved_context: pop eax - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - pop eax mov cr3, eax popa popf ret +[GLOBAL irq0_save_context_and_enter_scheduler] +; meant to be called on IRQ0 +; general registers already saved by IRQ handler stub +; flags already saved by interruption and interruptions disabled +; only saves CR3 +irq0_save_context_and_enter_scheduler: + mov eax, cr3 + push eax + + mov eax, [esp+8] ; get address of saved_context structure + mov [eax], esp ; save esp + mov dword [eax+4], resume_saved_irq0_context ; save eip + + mov esp, kernel_stack_top + jmp run_scheduler + +resume_saved_irq0_context: + pop eax + mov cr3, eax + ret + [GLOBAL resume_context] resume_context: diff --git a/kernel/l0/task.c b/kernel/l0/task.c index f8750e6..e31a85c 100644 --- a/kernel/l0/task.c +++ b/kernel/l0/task.c @@ -7,6 +7,7 @@ #include <paging.h> void save_context_and_enter_scheduler(saved_context_t *ctx); +void irq0_save_context_and_enter_scheduler(saved_context_t *ctx); void resume_context(saved_context_t *ctx); task_t *current_task = 0; @@ -27,6 +28,21 @@ void set_pit_frequency(uint32_t freq) { outb(0x40, h); } +// ============================= // +// HELPER : IF FLAG MANIPULATION // +// ============================= // + +static inline bool disable_interrupts() { + uint32_t eflags; + asm volatile("pushf; pop %0" : "=r"(eflags)); + asm volatile("cli"); + return (eflags & EFLAGS_IF) != 0; +} + +static inline void resume_interrupts(bool st) { + if (st) asm volatile("sti"); +} + // ================== // // THE TASK SCHEDULER // // ================== // @@ -63,10 +79,13 @@ task_t* dequeue_task() { // ================ // void run_scheduler() { + // At this point, interrupts are disabled // This function is expected NEVER TO RETURN + if (current_task != 0 && current_task->state == T_STATE_RUNNING) { enqueue_task(current_task, true); } + current_task = dequeue_task(); if (current_task != 0) { resume_context(¤t_task->ctx); @@ -134,9 +153,13 @@ task_t *new_task(entry_t entry) { return t; } +void irq0_handler(registers_t *regs) { + if (current_task != 0) + irq0_save_context_and_enter_scheduler(¤t_task->ctx); +} void tasking_setup(entry_t cont, void* arg) { set_pit_frequency(TASK_SWITCH_FREQUENCY); - idt_set_irq_handler(IRQ0, yield); + idt_set_irq_handler(IRQ0, irq0_handler); task_t *t = new_task(cont); ASSERT(t != 0); @@ -158,9 +181,7 @@ void yield() { } void* wait_for_result() { - uint32_t eflags; - asm volatile("pushf; pop %0" : "=r"(eflags)); - asm volatile("cli"); + bool st = disable_interrupts(); if (!current_task->has_result) { current_task->state = T_STATE_WAITING; @@ -169,15 +190,14 @@ void* wait_for_result() { ASSERT(current_task->has_result); current_task->has_result = false; - if (eflags & EFLAGS_IF) asm volatile("sti"); + void *result = current_task->result; - return current_task->result; + resume_interrupts(st); + return result; } void resume_with_result(task_t *task, void* data, bool run_at_once) { - uint32_t eflags; - asm volatile("pushf; pop %0" : "=r"(eflags)); - asm volatile("cli"); + bool st = disable_interrupts(); task->has_result = true; task->result = data; @@ -188,7 +208,7 @@ void resume_with_result(task_t *task, void* data, bool run_at_once) { } if (run_at_once) yield(); - if (eflags & EFLAGS_IF) asm volatile("sti"); + resume_interrupts(st); } /* vim: set ts=4 sw=4 tw=0 noet :*/ |