From 711da8aeab8d59f217db1f9643a660a4cee963e7 Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Fri, 16 Jan 2026 00:26:37 +0100 Subject: [PATCH] Implement proc_spawn_thread syscall, fix proc_resume and proc_suspend --- include/m/syscall_defs.h | 20 ++++++----- init/init.c | 49 ++++++++++++++++--------- kernel/amd64/mm.c | 15 ++++---- kernel/amd64/proc.c | 78 ++++++++++++++++++++++++++++++++++++++-- kernel/proc/mutex.c | 48 ++++++++++++++++++------- kernel/proc/mutex.h | 3 +- kernel/proc/proc.c | 2 +- kernel/proc/proc.h | 10 ++++++ kernel/sys/proc.h | 2 ++ kernel/syscall/syscall.c | 34 +++++++++++++++++- libmsl/m/proc.c | 7 ++++ libmsl/m/proc.h | 2 ++ 12 files changed, 219 insertions(+), 51 deletions(-) diff --git a/include/m/syscall_defs.h b/include/m/syscall_defs.h index 26a9398..661284b 100644 --- a/include/m/syscall_defs.h +++ b/include/m/syscall_defs.h @@ -1,15 +1,17 @@ #ifndef _M_SYSCALL_DEFS_H #define _M_SYSCALL_DEFS_H -#define SYS_PROC_QUIT 1 -#define SYS_PROC_TEST 2 -#define SYS_PROC_MAP 3 -#define SYS_PROC_UNMAP 4 -#define SYS_PROC_CREATE_RESOURCE_MEM 5 -#define SYS_PROC_DROP_RESOURCE 6 -#define SYS_PROC_CREATE_RESOURCE_MUTEX 7 -#define SYS_PROC_MUTEX_LOCK 8 -#define SYS_PROC_MUTEX_UNLOCK 9 +#define SYS_PROC_QUIT 1 +#define SYS_PROC_TEST 2 +#define SYS_PROC_MAP 3 +#define SYS_PROC_UNMAP 4 +#define SYS_PROC_CREATE_RESOURCE_MEM 5 +#define SYS_PROC_DROP_RESOURCE 6 +#define SYS_PROC_CREATE_RESOURCE_MUTEX 7 +#define SYS_PROC_MUTEX_LOCK 8 +#define SYS_PROC_MUTEX_UNLOCK 9 +#define SYS_PROC_SPAWN_THREAD 10 +#define SYS_PROC_SCHED 11 #define SR_OK 0 #define SR_SYSCALL_NOT_FOUND 1 diff --git a/init/init.c b/init/init.c index b811e5d..288ec10 100644 --- a/init/init.c +++ b/init/init.c @@ -5,24 +5,41 @@ #include char c = 'a'; +int mutex_rid; + +void mythread (void) { + for (;;) { + proc_mutex_lock (mutex_rid); + for (size_t i = 0; i < 3; i++) + proc_test ('b'); + proc_mutex_unlock (mutex_rid); + proc_sched (); + } +} + +void make_thread (void* fn) { + size_t stack_pages = 256; + size_t stack_size = PAGE_SIZE * stack_pages; + + uintptr_t out_paddr; + int mem_rid = proc_create_resource_mem (100, stack_pages, RV_PRIVATE, &out_paddr); + proc_map (out_paddr, PROC_MAP_BASE, stack_pages, PM_PRESENT | PM_RW | PM_USER); + memset ((void*)PROC_MAP_BASE, 0, stack_size); + + uintptr_t vstack_top = PROC_MAP_BASE + stack_size; + proc_spawn_thread (vstack_top, stack_size, fn); +} void app_main (void) { - uintptr_t out_paddr; - int mem_rid = proc_create_resource_mem (100, 16, RV_PRIVATE, &out_paddr); + mutex_rid = proc_create_resource_mutex (200, RV_PRIVATE); - proc_map (out_paddr, PROC_MAP_BASE, 16, PM_PRESENT | PM_RW | PM_USER); + make_thread (&mythread); - memset ((void*)PROC_MAP_BASE, 0, PAGE_SIZE * 16); - - proc_unmap (PROC_MAP_BASE, 16); - - proc_drop_resource (mem_rid); - - proc_test ('a'); - - int mutex_rid = proc_create_resource_mutex (101, RV_PRIVATE); - - proc_mutex_lock (mutex_rid); - proc_test ('b'); - proc_mutex_unlock (mutex_rid); + for (;;) { + proc_mutex_lock (mutex_rid); + for (size_t i = 0; i < 3; i++) + proc_test ('a'); + proc_mutex_unlock (mutex_rid); + proc_sched (); + } } diff --git a/kernel/amd64/mm.c b/kernel/amd64/mm.c index 775a904..0a57e93 100644 --- a/kernel/amd64/mm.c +++ b/kernel/amd64/mm.c @@ -11,12 +11,10 @@ #include #include -/* Present flag */ #define AMD64_PG_PRESENT (1 << 0) -/* Writable flag */ -#define AMD64_PG_RW (1 << 1) -/* User-accessible flag */ -#define AMD64_PG_USER (1 << 2) +#define AMD64_PG_RW (1 << 1) +#define AMD64_PG_USER (1 << 2) +#define AMD64_PG_HUGE (1 << 7) /* Auxilary struct for page directory walking */ struct pg_index { @@ -64,9 +62,12 @@ static uint64_t* amd64_mm_next_table (uint64_t* table, uint64_t entry_idx, bool struct limine_hhdm_response* hhdm = limine_hhdm_request.response; - if (entry & AMD64_PG_PRESENT) + if (entry & AMD64_PG_PRESENT) { + if (entry & AMD64_PG_HUGE) + return NULL; + paddr = entry & ~0xFFFULL; - else { + } else { if (!alloc) return NULL; diff --git a/kernel/amd64/proc.c b/kernel/amd64/proc.c index 6bf6c25..8c6fbe6 100644 --- a/kernel/amd64/proc.c +++ b/kernel/amd64/proc.c @@ -33,6 +33,14 @@ struct proc* proc_from_elf (uint8_t* elf_contents) { return NULL; } + proc->sys_rids = malloc (sizeof (*proc->sys_rids)); + if (proc->sys_rids == NULL) { + free (proc); + return NULL; + } + proc->sys_rids->counter = 0; + proc->sys_rids->refs = 1; + proc->pd->lock = SPIN_LOCK_INIT; proc->pd->refs = 1; proc->pd->cr3_paddr = mm_alloc_user_pd_phys (); @@ -42,9 +50,10 @@ struct proc* proc_from_elf (uint8_t* elf_contents) { return NULL; } + int kstk_rid = atomic_fetch_add (&proc->sys_rids->counter, 1); struct proc_resource_mem_init kstk_mem_init = {.pages = KSTACK_SIZE / PAGE_SIZE}; struct proc_resource* kstk_r = - proc_create_resource (proc, 0, PR_MEM, RV_PRIVATE, (void*)&kstk_mem_init); + proc_create_resource (proc, kstk_rid, PR_MEM, RV_PRIVATE, (void*)&kstk_mem_init); if (kstk_r == NULL) { pmm_free (proc->pd->cr3_paddr, 1); free (proc->pd); @@ -54,9 +63,10 @@ struct proc* proc_from_elf (uint8_t* elf_contents) { proc->pdata.kernel_stack = kstk_r->u.mem.paddr + (uintptr_t)hhdm->offset + KSTACK_SIZE; + int ustk_rid = atomic_fetch_add (&proc->sys_rids->counter, 1); struct proc_resource_mem_init ustk_mem_init = {.pages = USTACK_SIZE / PAGE_SIZE}; struct proc_resource* ustk_r = - proc_create_resource (proc, 1, PR_MEM, RV_PRIVATE, (void*)&ustk_mem_init); + proc_create_resource (proc, ustk_rid, PR_MEM, RV_PRIVATE, (void*)&ustk_mem_init); if (ustk_r == NULL) { kstk_r->ops.cleanup (proc, kstk_r); free (kstk_r); @@ -71,6 +81,8 @@ struct proc* proc_from_elf (uint8_t* elf_contents) { proc_map (proc, proc->pdata.user_stack, PROC_USTACK_TOP - USTACK_SIZE, USTACK_SIZE / PAGE_SIZE, MM_PG_USER | MM_PG_PRESENT | MM_PG_RW); + proc->flags |= PROC_USTK_PREALLOC; + struct elf_aux aux = proc_load_segments (proc, elf_contents); proc->pdata.regs.ss = GDT_UDATA | 0x03; @@ -82,6 +94,63 @@ struct proc* proc_from_elf (uint8_t* elf_contents) { return proc; } +struct proc* proc_spawn_thread (struct proc* proto, uintptr_t vstack_top, size_t stack_size, + uintptr_t entry) { + struct limine_hhdm_response* hhdm = limine_hhdm_request.response; + spin_lock_ctx_t ctxprt; + + struct proc* proc = malloc (sizeof (*proc)); + if (proc == NULL) + return NULL; + + memset (proc, 0, sizeof (*proc)); + + proc->lock = SPIN_LOCK_INIT; + atomic_store (&proc->state, PROC_READY); + proc->pid = atomic_fetch_add (&pids, 1); + + spin_lock (&proto->lock, &ctxprt); + + proc->pd = proto->pd; + proc->mappings = proto->mappings; + atomic_fetch_add (&proto->pd->refs, 1); + + proc->resource_tree = proto->resource_tree; + proc->sys_rids = proto->sys_rids; + atomic_fetch_add (&proc->sys_rids->refs, 1); + + spin_unlock (&proto->lock, &ctxprt); + + uintptr_t vstack_bottom = vstack_top - stack_size; + + uintptr_t pstack_bottom = mm_v2p (proc->pd, vstack_bottom, MM_PD_LOCK); + if (pstack_bottom == 0) { + free (proc); + return NULL; + } + + int kstk_rid = atomic_fetch_add (&proc->sys_rids->counter, 1); + struct proc_resource_mem_init kstk_mem_init = {.pages = KSTACK_SIZE / PAGE_SIZE}; + struct proc_resource* kstk_r = + proc_create_resource (proc, kstk_rid, PR_MEM, RV_PRIVATE, (void*)&kstk_mem_init); + if (kstk_r == NULL) { + free (proc); + return NULL; + } + + proc->pdata.kernel_stack = kstk_r->u.mem.paddr + (uintptr_t)hhdm->offset + KSTACK_SIZE; + + proc->pdata.user_stack = pstack_bottom + stack_size; + + proc->pdata.regs.ss = GDT_UDATA | 0x03; + proc->pdata.regs.rsp = (uint64_t)vstack_top; + proc->pdata.regs.rflags = 0x202; + proc->pdata.regs.cs = GDT_UCODE | 0x03; + proc->pdata.regs.rip = (uint64_t)entry; + + return proc; +} + void proc_cleanup (struct proc* proc) { struct limine_hhdm_response* hhdm = limine_hhdm_request.response; spin_lock_ctx_t ctxprpd; @@ -108,7 +177,10 @@ void proc_cleanup (struct proc* proc) { pmm_free (proc->pdata.kernel_stack - (uintptr_t)hhdm->offset - KSTACK_SIZE, KSTACK_SIZE / PAGE_SIZE); - pmm_free (proc->pdata.user_stack, USTACK_SIZE / PAGE_SIZE); + + if ((proc->flags & PROC_USTK_PREALLOC)) + pmm_free (proc->pdata.user_stack, USTACK_SIZE / PAGE_SIZE); + DEBUG ("PID %d Free stacks\n", proc->pid); free (proc); diff --git a/kernel/proc/mutex.c b/kernel/proc/mutex.c index 17fa672..5403d35 100644 --- a/kernel/proc/mutex.c +++ b/kernel/proc/mutex.c @@ -7,36 +7,58 @@ #include void proc_mutex_lock (struct proc* proc, struct proc_mutex* mutex) { - while (atomic_flag_test_and_set_explicit (&mutex->flag, memory_order_acquire)) - proc_suspend (proc, &mutex->suspension_q); + spin_lock_ctx_t ctxmt; - /* taken */ +try: + spin_lock (&mutex->lock, &ctxmt); - mutex->owner = proc; + if (!mutex->locked || mutex->owner == proc) { + mutex->locked = true; + mutex->owner = proc; + spin_unlock (&mutex->lock, &ctxmt); + return; + } + + spin_unlock (&mutex->lock, &ctxmt); + + proc_suspend (proc, &mutex->suspension_q); + + goto try; } bool proc_mutex_unlock (struct proc* proc, struct proc_mutex* mutex) { - if (mutex->owner != proc) - return false; + spin_lock_ctx_t ctxmt, ctxsq; - atomic_flag_clear_explicit (&mutex->flag, memory_order_release); + spin_lock (&mutex->lock, &ctxmt); + + if (mutex->owner != proc) { + spin_unlock (&mutex->lock, &ctxmt); + return false; + } + + spin_lock (&mutex->suspension_q.lock, &ctxsq); struct proc* resumed_proc; struct rb_node_link* node; rbtree_first (&mutex->suspension_q.proc_tree, node); - while (node) { - struct rb_node_link* next; - rbtree_next (node, next); - + if (node) { resumed_proc = rbtree_entry (node, struct proc, suspension_link); + mutex->owner = resumed_proc; + spin_unlock (&mutex->suspension_q.lock, &ctxsq); + spin_unlock (&mutex->lock, &ctxmt); proc_resume (resumed_proc); - node = next; + return true; } - assert (mutex->suspension_q.proc_tree == NULL); + spin_unlock (&mutex->suspension_q.lock, &ctxsq); + + mutex->locked = false; + mutex->owner = NULL; + + spin_unlock (&mutex->lock, &ctxmt); return true; } diff --git a/kernel/proc/mutex.h b/kernel/proc/mutex.h index 724a2dd..79e1a9b 100644 --- a/kernel/proc/mutex.h +++ b/kernel/proc/mutex.h @@ -8,7 +8,8 @@ struct proc; struct proc_mutex { - atomic_flag flag; + spin_lock_t lock; + bool locked; struct proc_suspension_q suspension_q; struct proc* owner; }; diff --git a/kernel/proc/proc.c b/kernel/proc/proc.c index 39311c2..492f3a8 100644 --- a/kernel/proc/proc.c +++ b/kernel/proc/proc.c @@ -197,7 +197,7 @@ static struct proc* proc_spawn_rd (char* name) { return proc_from_elf (rd_file->content); } -static void proc_register (struct proc* proc, struct cpu* cpu) { +void proc_register (struct proc* proc, struct cpu* cpu) { spin_lock_ctx_t ctxcpu, ctxprtr; proc->cpu = cpu; diff --git a/kernel/proc/proc.h b/kernel/proc/proc.h index 328666c..b35958a 100644 --- a/kernel/proc/proc.h +++ b/kernel/proc/proc.h @@ -25,6 +25,8 @@ #define PROC_RESOURCES_MAX 1024 +#define PROC_USTK_PREALLOC (1 << 0) + struct cpu; struct proc_mapping { @@ -35,6 +37,11 @@ struct proc_mapping { size_t size; }; +struct proc_sys_rids { + atomic_int refs; + atomic_int counter; +}; + struct proc { int pid; struct rb_node_link proc_tree_link; @@ -44,11 +51,13 @@ struct proc { struct list_node_link* mappings; /* pd.lock implicitly protects this field */ struct proc_platformdata pdata; + uint32_t flags; struct pd* pd; spin_lock_t lock; struct cpu* cpu; atomic_int state; struct rb_node_link* resource_tree; + struct proc_sys_rids* sys_rids; struct proc_suspension_q* suspension_q; }; @@ -60,6 +69,7 @@ bool proc_map (struct proc* proc, uintptr_t start_paddr, uintptr_t start_vaddr, uint32_t flags); bool proc_unmap (struct proc* proc, uintptr_t start_vaddr, size_t pages); struct elf_aux proc_load_segments (struct proc* proc, uint8_t* elf); +void proc_register (struct proc* proc, struct cpu* cpu); void proc_init (void); #endif // _KERNEL_PROC_PROC_H diff --git a/kernel/sys/proc.h b/kernel/sys/proc.h index 290db41..2f2b086 100644 --- a/kernel/sys/proc.h +++ b/kernel/sys/proc.h @@ -6,6 +6,8 @@ struct proc; struct proc* proc_from_elf (uint8_t* elf_contents); +struct proc* proc_spawn_thread (struct proc* proto, uintptr_t vstack_top, size_t stack_size, + uintptr_t entry); void proc_cleanup (struct proc* proc); #endif // _KERNEL_SYS_PROC_H diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index affaf82..2060d91 100644 --- a/kernel/syscall/syscall.c +++ b/kernel/syscall/syscall.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #define DEFINE_SYSCALL(name) \ @@ -24,7 +25,7 @@ DEFINE_SYSCALL (sys_proc_quit) { /* int proc_test (void) */ DEFINE_SYSCALL (sys_proc_test) { char c = (char)a1; - DEBUG ("test syscall! %c\n", c); + DEBUG ("test syscall from %d! %c\n", proc->pid, c); return SR_OK; } @@ -163,6 +164,35 @@ DEFINE_SYSCALL (sys_proc_drop_resource) { return SR_OK; } +/* int proc_spawn_thread (uintptr_t vstack_top, size_t stack_size, void* entry) */ +DEFINE_SYSCALL (sys_proc_spawn_thread) { + uintptr_t vstack_top = a1; + size_t stack_size = (size_t)a2; + uintptr_t entry = a3; + + struct cpu* cpu = proc->cpu; + + struct proc* new = proc_spawn_thread (proc, vstack_top, stack_size, entry); + + DEBUG ("new=%p\n", new); + + if (new == NULL) { + return -SR_OOM_ERROR; + } + + int pid = new->pid; + + proc_register (new, cpu); + + return pid; +} + +/* int proc_sched (void) */ +DEFINE_SYSCALL (sys_proc_sched) { + proc_sched (regs); + return SR_OK; +} + static syscall_handler_func_t handler_table[] = { [SYS_PROC_QUIT] = &sys_proc_quit, [SYS_PROC_TEST] = &sys_proc_test, @@ -173,6 +203,8 @@ static syscall_handler_func_t handler_table[] = { [SYS_PROC_CREATE_RESOURCE_MUTEX] = &sys_proc_create_resource_mutex, [SYS_PROC_MUTEX_LOCK] = &sys_proc_mutex_lock, [SYS_PROC_MUTEX_UNLOCK] = &sys_proc_mutex_unlock, + [SYS_PROC_SPAWN_THREAD] = &sys_proc_spawn_thread, + [SYS_PROC_SCHED] = &sys_proc_sched, }; syscall_handler_func_t syscall_find_handler (int syscall_num) { diff --git a/libmsl/m/proc.c b/libmsl/m/proc.c index 3820d6f..61c2ca0 100644 --- a/libmsl/m/proc.c +++ b/libmsl/m/proc.c @@ -35,3 +35,10 @@ int proc_mutex_lock (int mutex_rid) { int proc_mutex_unlock (int mutex_rid) { return syscall (SYS_PROC_MUTEX_UNLOCK, (uintptr_t)mutex_rid, 0, 0, 0, 0, 0); } + +int proc_spawn_thread (uintptr_t vstack_top, size_t stack_size, void* entry) { + return syscall (SYS_PROC_SPAWN_THREAD, vstack_top, (uintptr_t)stack_size, (uintptr_t)entry, 0, 0, + 0); +} + +int proc_sched (void) { return syscall (SYS_PROC_SCHED, 0, 0, 0, 0, 0, 0); } diff --git a/libmsl/m/proc.h b/libmsl/m/proc.h index fce6d13..686fb12 100644 --- a/libmsl/m/proc.h +++ b/libmsl/m/proc.h @@ -25,5 +25,7 @@ int proc_drop_resource (int rid); int proc_create_resource_mutex (int rid, int vis); int proc_mutex_lock (int mutex_rid); int proc_mutex_unlock (int mutex_rid); +int proc_spawn_thread (uintptr_t vstack_top, size_t stack_size, void* entry); +int proc_sched (void); #endif // _LIBMSL_M_PROC_H