forked from xamidev/pepperOS
162 lines
4.0 KiB
C
162 lines
4.0 KiB
C
/*
|
|
* @author xamidev <xamidev@riseup.net>
|
|
* @brief Process linked list implementation
|
|
* @license GPL-3.0-only
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#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");
|
|
}
|
|
} |