From 39ed0640f0e33b8a48ba82334de219e9fe4ed0e6 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 7 Mar 2024 22:47:49 -0500 Subject: kernel: sched: Add support for user threads Signed-off-by: Ian Moffett --- Makefile.in | 12 +++- sys/include/arch/amd64/frame.h | 7 ++ sys/include/sys/proc.h | 2 + sys/kern/kern_sched.c | 153 +++++++++++++++++++++++++++++++++++++---- usr.sbin/init/init | Bin 944 -> 0 bytes 5 files changed, 157 insertions(+), 17 deletions(-) delete mode 100755 usr.sbin/init/init diff --git a/Makefile.in b/Makefile.in index daa0cf9..5e99728 100644 --- a/Makefile.in +++ b/Makefile.in @@ -69,16 +69,22 @@ override KERNEL_ASMOBJECTS = $(KERNEL_ASMFILES:.S=.S.o) override KERNEL_HEADER_DEPS = $(KERNEL_CFILES:.c=.d) .PHONY: all -all: base init lib base/usr/lib/ld.so base/boot/hyra-kernel +all: base lib userland base/usr/lib/ld.so base/boot/hyra-kernel rm -f sys/include/machine rm -rf iso_root -base/boot/init: usr.sbin/init/ +base/usr/sbin/init: cd usr.sbin/; make CC=$(CC) LD=$(LD) - cp usr.sbin/init/init base/boot/ + mv usr.sbin/init/init base/usr/sbin/ + +# TODO: Make this more flexible +.PHONY: userland +userland: base/usr/sbin/init base: mkdir -p base/usr/lib/ + mkdir -p base/usr/sbin/ + mkdir -p base/boot/ lib: lib/mlibc base/usr/lib/ld.so diff --git a/sys/include/arch/amd64/frame.h b/sys/include/arch/amd64/frame.h index a2e1a05..298a836 100644 --- a/sys/include/arch/amd64/frame.h +++ b/sys/include/arch/amd64/frame.h @@ -67,5 +67,12 @@ struct trapframe { (FRAME)->rsp = SP; \ (FRAME)->ss = 0x10; \ +#define init_frame_user(FRAME, IP, SP) \ + (FRAME)->rip = IP; \ + (FRAME)->cs = 0x18 | 3; \ + (FRAME)->rflags = 0x202; \ + (FRAME)->rsp = SP; \ + (FRAME)->ss = 0x20 | 3; \ + #endif /* !defined(__ASSEMBLER__) */ #endif /* !_AMD64_FRAME_H_ */ diff --git a/sys/include/sys/proc.h b/sys/include/sys/proc.h index f45e4c6..0d3b45e 100644 --- a/sys/include/sys/proc.h +++ b/sys/include/sys/proc.h @@ -34,6 +34,7 @@ #include #include #include +#include /* * A task running on the CPU e.g., a process or @@ -43,6 +44,7 @@ struct proc { pid_t pid; struct cpu_info *cpu; struct trapframe *tf; + struct vas addrsp; TAILQ_ENTRY(proc) link; }; diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c index 266ce39..9231ea2 100644 --- a/sys/kern/kern_sched.c +++ b/sys/kern/kern_sched.c @@ -34,10 +34,20 @@ #include #include #include +#include +#include +#include #include +#include +#include +#include +#include #include #include +#define STACK_PAGES 8 +#define STACK_SIZE (STACK_PAGES*vm_get_page_size()) + /* * Thread ready queue - all threads ready to be * scheduled should be added to this queue. @@ -119,12 +129,99 @@ sched_enter(void) } } +static uintptr_t +sched_init_stack(void *stack_top, char *argvp[], char *envp[], struct auxval auxv) +{ + uintptr_t *sp = stack_top; + size_t envp_len, argv_len, len; + uintptr_t old_sp = 0; + uintptr_t ret; + + for (envp_len = 0; envp[envp_len] != NULL; ++envp_len) { + len = strlen(envp[envp_len]); + sp = (void *)((uintptr_t)sp - len - 1); + memcpy(sp, envp[envp_len], len); + } + + for (argv_len = 0; argvp[argv_len] != NULL; ++argv_len) { + len = strlen(argvp[argv_len]); + sp = (void *)((uintptr_t)sp - len - 1); + memcpy(sp, argvp[envp_len], len); + } + + sp = (uint64_t *)(((uintptr_t)sp / 16) * 16); + if (((argv_len + envp_len + 1) & 1) != 0) { + sp--; + } + + *--sp = 0; + *--sp = 0; + *--sp = auxv.at_entry; + *--sp = AT_ENTRY; + *--sp = auxv.at_phent; + *--sp = AT_PHENT; + *--sp = auxv.at_phnum; + *--sp = AT_PHNUM; + *--sp = auxv.at_phdr; + *--sp = AT_PHDR; + + old_sp = (uintptr_t)sp; + + /* End of envp */ + *--sp = 0; + sp -= envp_len; + for (int i = 0; i < envp_len; ++i) { + old_sp -= strlen(envp[i]) + 1; + sp[i] = old_sp; + } + + /* End of argvp */ + *--sp = 0; + sp -= argv_len; + for (int i = 0; i < argv_len; ++i) { + old_sp -= strlen(argvp[i]) + 1; + sp[i] = old_sp; + } + + /* Argc */ + *--sp = argv_len; + + ret = (uintptr_t)stack_top; + ret -= (ret - (uintptr_t)sp); + return ret; +} + +static uintptr_t +sched_create_stack(struct vas vas, bool user) +{ + int status; + uintptr_t user_stack; + const vm_prot_t USER_STACK_PROT = PROT_WRITE | PROT_USER; + + if (!user) { + return (uintptr_t)dynalloc(STACK_SIZE); + } + + user_stack = vm_alloc_pageframe(STACK_PAGES); + + status = vm_map_create(vas, user_stack, user_stack, USER_STACK_PROT, + STACK_SIZE); + + if (status != 0) { + return 0; + } + + memset(PHYS_TO_VIRT(user_stack), 0, STACK_SIZE); + return user_stack; +} + static struct proc * -sched_create_td(uintptr_t rip) +sched_create_td(uintptr_t rip, char *argvp[], char *envp[], struct auxval auxv, + struct vas vas, bool is_user) { - const size_t STACK_SIZE = 0x100000; /* 1 MiB */ struct proc *td; - void *stack; + uintptr_t stack, sp; + void *stack_virt; struct trapframe *tf; tf = dynalloc(sizeof(struct trapframe)); @@ -132,29 +229,37 @@ sched_create_td(uintptr_t rip) return NULL; } - stack = dynalloc(STACK_SIZE); - if (stack == NULL) { + stack = sched_create_stack(vas, is_user); + if (stack == 0) { dynfree(tf); return NULL; } + stack_virt = (is_user) ? PHYS_TO_VIRT(stack) : (void *)stack; + td = dynalloc(sizeof(struct proc)); if (td == NULL) { + /* TODO: Free stack */ dynfree(tf); - dynfree(stack); return NULL; } memset(tf, 0, sizeof(struct trapframe)); - memset(stack, 0, STACK_SIZE); + sp = sched_init_stack((void *)((uintptr_t)stack_virt + STACK_SIZE), + argvp, envp, auxv); /* Setup process itself */ td->pid = 0; /* Don't assign PID until enqueued */ td->cpu = NULL; /* Not yet assigned a core */ td->tf = tf; + td->addrsp = vas; /* Setup trapframe */ - init_frame(tf, rip, (uintptr_t)stack + STACK_SIZE - 1); + if (!is_user) { + init_frame(tf, rip, sp); + } else { + init_frame_user(tf, rip, VIRT_TO_PHYS(sp)); + } return td; } @@ -193,20 +298,40 @@ sched_context_switch(struct trapframe *tf) sched_enqueue_td(td); } + pmap_switch_vas(vm_get_ctx(), next_td->addrsp); sched_oneshot(); } void sched_init(void) { + struct proc *init; + struct auxval auxv = {0}; + struct vas vas = pmap_create_vas(vm_get_ctx()); + const char *init_bin; + + int status; + char *ld_path; + char *argv[] = {"/boot/init", NULL}; + char *envp[] = {NULL}; + TAILQ_INIT(&td_queue); - /* - * TODO: Create init with sched_create_td() - * and enqueue with sched_enqueue_td() - */ - (void)sched_create_td; - (void)sched_enqueue_td; + if ((init_bin = initramfs_open("/boot/init")) == NULL) { + panic("Could not open /boot/init\n"); + } + + status = loader_load(vas, init_bin, &auxv, 0, &ld_path); + if (status != 0) { + panic("Could not load init\n"); + } + + init = sched_create_td((uintptr_t)auxv.at_entry, argv, envp, auxv, vas, true); + if (init == NULL) { + panic("Failed to create thread for init\n"); + } + + sched_enqueue_td(init); } /* diff --git a/usr.sbin/init/init b/usr.sbin/init/init deleted file mode 100755 index 8b83844..0000000 Binary files a/usr.sbin/init/init and /dev/null differ -- cgit v1.2.3