diff --git a/kernel/cpu/isr.c b/kernel/cpu/isr.c index b72e1e0..0ee7022 100644 --- a/kernel/cpu/isr.c +++ b/kernel/cpu/isr.c @@ -10,6 +10,7 @@ #include #include #include +#include #define PIC_END_OF_INTERRUPT 0x20 @@ -142,6 +143,9 @@ void irq_handler(isr_registers_t r) { if (r.int_no >= 40) port_byte_out(PORT_PIC_SLAVE_COMMAND, PIC_END_OF_INTERRUPT); /* slave */ port_byte_out(PORT_PIC_MASTER_COMMAND, PIC_END_OF_INTERRUPT); /* master */ + if (r.int_no >= IRQ0 && r.int_no < IRQ15) { + task_notify_irq(r.int_no - IRQ0); + } /* Handle the interrupt in a more modular way */ if (interrupt_handlers[r.int_no] != NULL) { isr_t handler = interrupt_handlers[r.int_no]; diff --git a/kernel/cpu/syscall_handler.c b/kernel/cpu/syscall_handler.c index 3e09acb..3fc0bbb 100644 --- a/kernel/cpu/syscall_handler.c +++ b/kernel/cpu/syscall_handler.c @@ -14,6 +14,8 @@ void syscall_handle(isr_registers_t *registers) { case SYSCALL_YIELD_JOB: task_switch_next(); break; + case SYSCALL_YIELD_IRQ: + task_wait_irq(registers->ebx); default: break; } diff --git a/kernel/drivers/keyboard.c b/kernel/drivers/keyboard.c index 7ab3477..73cc35e 100644 --- a/kernel/drivers/keyboard.c +++ b/kernel/drivers/keyboard.c @@ -8,6 +8,7 @@ #include #include #include +#include const char scancode_map_lowercase[] = { @@ -63,7 +64,8 @@ char getc() { KeyEvent *get_next_event() { KeyEvent *target = malloc(sizeof(KeyEvent)); if (!ring_buffer_get(keyboard_event_buffer, target)) { - k_wait_for_interrupt(); + syscall_yield_irq(1 << 1); +// k_wait_for_interrupt(); free(target); return NULL; } diff --git a/kernel/kernel.c b/kernel/kernel.c index 0665a8b..26baaaa 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -78,6 +78,7 @@ void noreturn kmain(multiboot_info_t *multiboot_info) { printf("Booted successfully v%d.%d.%d\n", version_major, version_minor, version_patch); + task_init(); task_spawn(main_loop, NULL); syscall_start_scheduler(); } diff --git a/kernel/libk/syscall.c b/kernel/libk/syscall.c index ba32da2..d701114 100644 --- a/kernel/libk/syscall.c +++ b/kernel/libk/syscall.c @@ -12,11 +12,21 @@ void syscall1(uint32_t arg1) { : "a"(arg1)); } -void syscall_yield_job() { - syscall1(SYSCALL_YIELD_JOB); +void syscall2(uint32_t arg1, uint32_t arg2) { + __asm__("int $0x80" + : + : "a"(arg1), "b"(arg2)); } void noreturn syscall_start_scheduler() { syscall1(SYSCALL_START_SCHEDULER); while (1) { __asm__("hlt"); }; -} \ No newline at end of file +} + +void syscall_yield_job() { + syscall1(SYSCALL_YIELD_JOB); +} + +void syscall_yield_irq(uint16_t irq) { + syscall2(SYSCALL_YIELD_IRQ, irq ); +} diff --git a/kernel/libk/syscall.h b/kernel/libk/syscall.h index 3fd5c32..87eefa8 100644 --- a/kernel/libk/syscall.h +++ b/kernel/libk/syscall.h @@ -4,14 +4,17 @@ #ifndef NEW_KERNEL_SYSCALL_H #define NEW_KERNEL_SYSCALL_H - +#include #include #define SYSCALL_START_SCHEDULER 0x01 #define SYSCALL_YIELD_JOB 0x02 - -void syscall_yield_job(); +#define SYSCALL_YIELD_IRQ 0x03 void noreturn syscall_start_scheduler(); +void syscall_yield_job(); + +void syscall_yield_irq(uint16_t irq); + #endif //NEW_KERNEL_SYSCALL_H diff --git a/kernel/tasks/task.c b/kernel/tasks/task.c index 0a90a6e..6c6b377 100644 --- a/kernel/tasks/task.c +++ b/kernel/tasks/task.c @@ -13,15 +13,24 @@ #define stack_end(task) ((task)->stack + ((task)->stack_page_count * PAGE_SIZE)) +#define TASK_STATE_UNKNOWN (0) +#define TASK_STATE_RUNNABLE (1 << 0) +#define TASK_STATE_RUNNING (1 << 1) +#define TASK_STATE_WAIT_IRQ (1 << 2) + +#define TASK_STATE_ERROR (1 << 7) + + typedef struct task { bool present: 1; - uint8_t wait_irq: 4; + uint8_t state; + uint16_t wait_irq; uint32_t tid; struct task *next; - void* stack; + void *stack; uint32_t stack_page_count; task_registers_t *task_registers; @@ -37,15 +46,20 @@ typedef struct { bool task_locked = false; +task_t *idle_task = NULL; task_t *first_task = NULL; task_t *last_task = NULL; task_t *current_task = NULL; uint32_t last_tid = 0; -extern switch_task(task_registers_t**, task_registers_t*); +extern switch_task(task_registers_t +**, task_registers_t*); + extern cdecl noreturn void __task_entry_point(); + extern noreturn void __task_entry_point_inner(); + // explicit cdecl calling convention void cdecl noreturn task_entry_point(task_entrypoint entrypoint, void *entry_data) { entrypoint(entry_data); @@ -61,6 +75,28 @@ void task_lock_free() { task_locked = false; } +void noreturn task_idle(void *data) { + while (true) __asm__("hlt"); +} + +void task_notify_irq(uint8_t irq_no) { + uint16_t irq__bit = 1 << irq_no; + task_t *t = first_task; + while (t != NULL) { + if (t->state == TASK_STATE_WAIT_IRQ && (t->wait_irq & irq__bit) != 0) { + t->wait_irq = 0; + t->state = TASK_STATE_RUNNABLE; + } + t = t->next; + } +} + +void task_wait_irq(uint16_t irq_bits) { + current_task->wait_irq = irq_bits; + current_task->state = TASK_STATE_WAIT_IRQ; + task_switch_next(); +} + void task_switch_next_inner(task_t *next_task) { if (task_locked) { return; // don't switch while the task is locked @@ -70,6 +106,10 @@ void task_switch_next_inner(task_t *next_task) { } task_t *previous_task = current_task; current_task = next_task; + if (previous_task->state == TASK_STATE_RUNNING) { + previous_task->state = TASK_STATE_RUNNABLE; + } + current_task->state = TASK_STATE_RUNNING; // switch task switch_task(previous_task == NULL ? NULL : &previous_task->task_registers, current_task->task_registers); } @@ -78,34 +118,53 @@ void task_start_first() { task_switch_next_inner(first_task); } +task_t *task_first_runnable() { + task_t *next_task = current_task; + bool looped = false; + if (next_task == idle_task || next_task->next == NULL) { + looped = true; + next_task = first_task; + } else { + next_task = current_task->next; + } + do { + if (!looped && next_task == NULL) { + looped = true; + next_task = first_task; + } + if (next_task == NULL) { + break; + } + if (next_task->state == TASK_STATE_RUNNABLE) { + return next_task; + } + next_task = next_task->next; + } while (next_task != current_task); + if (current_task->state == TASK_STATE_RUNNING) + return current_task; + return idle_task; +} + void task_switch_next() { if (current_task == NULL) { return; } - task_switch_next_inner(current_task->next == NULL ? first_task : current_task->next); + task_switch_next_inner(task_first_runnable()); } -uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) { +task_t *task_create(task_entrypoint entrypoint, void *entry_data) { task_t *new_task = malloc(sizeof(task_t)); memset((uint8_t *) new_task, 0, sizeof(task_t)); new_task->tid = last_tid++; + new_task->state = TASK_STATE_RUNNABLE; new_task->stack = pmm_get_pages(16); new_task->stack_page_count = 16; // todo check for null - - if (first_task == NULL) { - // first task - first_task = new_task; - } else { - last_task->next = new_task; - } - last_task = new_task; - // prepare stack // cdecl format - task_stack_start* stack = (task_stack_start *) (stack_end(new_task) - sizeof(task_stack_start)); + task_stack_start *stack = (task_stack_start *) (stack_end(new_task) - sizeof(task_stack_start)); memset((uint8_t *) stack, 0, sizeof(task_stack_start)); // setup isr return frame stack->isr_registers.cs = 0x08; // todo proper gdt setup @@ -124,6 +183,23 @@ uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) { new_task->task_registers = &stack->task_registers; new_task->present = true; + return new_task; + +} + +void task_init() { + idle_task = task_create(task_idle, NULL); +} + +uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) { + task_t *new_task = task_create(entrypoint, entry_data); + if (first_task == NULL) { + // first task + first_task = new_task; + } else { + last_task->next = new_task; + } + last_task = new_task; return new_task->tid; } diff --git a/kernel/tasks/task.h b/kernel/tasks/task.h index 2774097..fad684d 100644 --- a/kernel/tasks/task.h +++ b/kernel/tasks/task.h @@ -9,6 +9,12 @@ typedef void (*task_entrypoint)(void *entry_data); +void task_notify_irq(uint8_t irq_no); + +void task_wait_irq(uint16_t irq_bits); + +void task_init(); + void task_start_first(); void task_switch_next();