Files
my-kern/kernel/tasks/task.c

132 lines
3.2 KiB
C

//
// Created by rick on 22-02-21.
//
#include "task.h"
#include <cpu/cpu.h>
#include <stdbool.h>
#include <libc/libc.h>
#include <mem/malloc.h>
#include <mem/pmm.h>
#include <attributes.h>
#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) {
}