// // Created by rick on 22-02-21. // #include "task.h" #include #include #include #include #include #include #define stack_end(task) ((task)->stack + ((task)->stack_page_count * PAGE_SIZE)) typedef struct task { bool present: 1; uint8_t wait_irq: 4; uint32_t tid; struct task *next; void* stack; uint32_t stack_page_count; task_registers_t *task_registers; } task_t; typedef struct { task_registers_t task_registers; isr_registers_t isr_registers; task_entrypoint entrypoint; void *entry_data; char alignment[4]; } packed task_stack_start; bool task_locked = false; 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 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); // task_end_self(); while (true); // halt } void task_lock_acquire() { task_locked = true; } void task_lock_free() { task_locked = false; } void task_switch_next_inner(task_t *next_task) { if (task_locked) { return; // don't switch while the task is locked } if (next_task == current_task) { return; } task_t *previous_task = current_task; current_task = next_task; // switch task switch_task(previous_task == NULL ? NULL : &previous_task->task_registers, current_task->task_registers); } void task_start_first() { task_switch_next_inner(first_task); } void task_switch_next() { if (current_task == NULL) { return; } task_switch_next_inner(current_task->next == NULL ? first_task : current_task->next); } uint32_t task_spawn(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->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)); memset((uint8_t *) stack, 0, sizeof(task_stack_start)); // setup isr return frame stack->isr_registers.cs = 0x08; // todo proper gdt setup stack->isr_registers.ds = 0x10; // todo // stack->isr_registers.ss = 0x10; // todo stack->isr_registers.eip = (uint32_t) __task_entry_point_inner; stack->isr_registers.eflags = 0x200; // setup task switch frame stack->task_registers.eip = (uint32_t) __task_entry_point; stack->task_registers.ebp = (uint32_t) stack_end(new_task); // setup entrypoint stack->entrypoint = entrypoint; stack->entry_data = entry_data; new_task->task_registers = &stack->task_registers; new_task->present = true; return new_task->tid; } void task_end(uint32_t pid) { }