From d28c5ba100cbc8a4ea6e4f4da16f5c8319a02a72 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 28 Apr 2025 17:28:02 -0400 Subject: fork syscall --- kernel/include/comus/user.h | 5 +++++ kernel/syscall.c | 18 ++++++++++++++++-- kernel/user.c | 31 +++++++++++++++++++++++++++++++ user/fork.c | 20 ++++++++++++++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 user/fork.c diff --git a/kernel/include/comus/user.h b/kernel/include/comus/user.h index 29c978c..f51ada5 100644 --- a/kernel/include/comus/user.h +++ b/kernel/include/comus/user.h @@ -17,6 +17,11 @@ */ int user_load(struct pcb *pcb, struct disk *disk); +/** + * Clone a user process. Used for fork(). + */ +struct pcb *user_clone(struct pcb *pcb); + /** * Clean up all loaded userland data from a pcb */ diff --git a/kernel/syscall.c b/kernel/syscall.c index dd9bc16..2dd6460 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -1,4 +1,4 @@ -#include "lib/kio.h" +#include #include #include #include @@ -44,6 +44,20 @@ static int sys_waitpid(void) dispatch(); } +static int sys_fork(void) +{ + struct pcb *child; + + child = user_clone(pcb); + if (child == NULL) + return -1; + + child->regs.rax = 0; + pcb->regs.rax = child->pid; + schedule(child); + return 0; +} + static int sys_write(void) { ARG1(int, fd); @@ -313,7 +327,7 @@ static int sys_ticks(void) static int (*syscall_tbl[N_SYSCALLS])(void) = { [SYS_exit] = sys_exit, [SYS_waitpid] = sys_waitpid, - [SYS_fork] = NULL, [SYS_exec] = NULL, + [SYS_fork] = sys_fork, [SYS_exec] = NULL, [SYS_open] = NULL, [SYS_close] = NULL, [SYS_read] = NULL, [SYS_write] = sys_write, [SYS_getpid] = sys_getpid, [SYS_getppid] = sys_getppid, diff --git a/kernel/user.c b/kernel/user.c index fc1167d..f9b541c 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -230,6 +230,37 @@ fail: return 1; } +struct pcb *user_clone(struct pcb *pcb) +{ + struct pcb *child; + + if (pcb_alloc(&child)) + return NULL; + + // copy context + memcpy(&child->regs, &pcb->regs, sizeof(struct cpu_regs)); + child->memctx = mem_ctx_clone(pcb->memctx, true); + if (child->memctx == NULL) + return NULL; + + // set metadata + child->parent = pcb; + child->state = PROC_STATE_READY; + child->priority = pcb->priority; + child->ticks = 0; + + // copy heap + child->heap_start = pcb->heap_start; + child->heap_len = pcb->heap_len; + + // copy elf data + memcpy(&child->elf_header, &pcb->elf_header, sizeof(Elf64_Ehdr)); + memcpy(&child->elf_segments, &pcb->elf_segments, sizeof(Elf64_Ehdr)); + child->n_elf_segments = pcb->n_elf_segments; + + return child; +} + void user_cleanup(struct pcb *pcb) { if (pcb == NULL) diff --git a/user/fork.c b/user/fork.c new file mode 100644 index 0000000..d534fcf --- /dev/null +++ b/user/fork.c @@ -0,0 +1,20 @@ +#include +#include + +int main(void) +{ + printf("im going to print some a's and b's. get ready\n"); + + int pid = fork(); + if (pid < 0) { + fprintf(stderr, "fork failed!\n"); + return 1; + } + + for (int i = 0; i < 10; i++) { + putchar(pid == 0 ? 'a' : 'b'); + putchar('\n'); + } + + return 0; +} -- cgit v1.2.3-freya