/* * @author xamidev * @brief Process linked list implementation * @license GPL-3.0-only */ #include #include "process.h" #include "mem/heap/kheap.h" #include "kernel.h" #include "string/string.h" #include "mem/gdt/gdt.h" #include "config.h" #include "io/serial/serial.h" #include "io/term/flanterm.h" extern struct flanterm_context* ft_ctx; struct process_t* processes_list; struct process_t* current_process; extern uint64_t *kernel_pml4; size_t next_free_pid = 0; void process_init() { processes_list = NULL; current_process = NULL; } // Only for debug void process_display_list(struct process_t* processes_list) { int process_view_id = 0; struct process_t* tmp = processes_list; while (tmp != NULL) { DEBUG("{%d: %p} -> ", process_view_id, tmp); tmp = tmp->next; process_view_id++; } DEBUG("NULL"); } struct process_t* process_create(char* name, void(*function)(void*), void* arg) { /* CLEAR_INTERRUPTS; */ struct process_t* proc = (struct process_t*)kmalloc(sizeof(struct process_t)); struct cpu_status_t* ctx = (struct cpu_status_t*)kmalloc(sizeof(struct cpu_status_t)); // No more memory? if (!proc) return NULL; if (!ctx) return NULL; strncpy(proc->name, name, PROCESS_NAME_MAX); proc->pid = next_free_pid++; proc->status = READY; uint64_t* stack_top = (uint64_t*)kalloc_stack(); // push return address to the stack so when "ret" hits we jmp to exit instead of idk what // stack grows DOWNWARDS!! *(--stack_top) = (uint64_t)process_exit; proc->context = ctx; proc->context->iret_ss = KERNEL_DATA_SEGMENT; // process will live in kernel mode proc->context->iret_rsp = (uint64_t)stack_top; proc->context->iret_flags = 0x202; //bit 2 and 9 set (Interrupt Flag) proc->context->iret_cs = KERNEL_CODE_SEGMENT; proc->context->iret_rip = (uint64_t)function; // beginning of executable code proc->context->rdi = (uint64_t)arg; // 1st arg is in rdi (as per x64 calling convention) proc->context->rbp = 0; // Kernel PML4 as it already maps code/stack (when switching to userland we'll have to change that) proc->root_page_table = kernel_pml4; proc->next = 0; process_add(&processes_list, proc); /* SET_INTERRUPTS; */ return proc; } void process_add(struct process_t** processes_list, struct process_t* process) { if (!process) return; process->next = NULL; if (*processes_list == NULL) { // List is empty *processes_list = process; return; } struct process_t* tmp = *processes_list; while (tmp->next != NULL) { tmp = tmp->next; } // We're at last process before NULL tmp->next = process; // process->next = NULL; } void process_delete(struct process_t** processes_list, struct process_t* process) { if (!processes_list || !*processes_list || !process) return; if (*processes_list == process) { // process to delete is at head *processes_list = process->next; process->next = NULL; kfree(process); return; } struct process_t* tmp = *processes_list; while (tmp->next && tmp->next != process) { tmp = tmp->next; } if (tmp->next == NULL) { // Didn't find the process return; } // We're at process before the one we want to delete tmp->next = process->next; process->next = NULL; kfree(process); } struct process_t* process_get_next(struct process_t* process) { if (!process) return NULL; return process->next; } // Will be used to clean up resources (if any, when we implement it) // Just mark as DEAD then idle. Scheduler will delete process at next timer interrupt % quantum. void process_exit() { DEBUG("Exiting from process '%s'", current_process->name); CLEAR_INTERRUPTS; if (current_process) { current_process->status = DEAD; } SET_INTERRUPTS; //outb(0x20, 0x20); for (;;) { asm("hlt"); } }