diff options
author | Freya Murphy <freya@freyacat.org> | 2025-04-28 17:28:02 -0400 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2025-04-28 17:28:02 -0400 |
commit | d28c5ba100cbc8a4ea6e4f4da16f5c8319a02a72 (patch) | |
tree | ce096652da2f8f9889bb377b80f6aafc9bf05788 | |
parent | clone pgdir (diff) | |
download | comus-d28c5ba100cbc8a4ea6e4f4da16f5c8319a02a72.tar.gz comus-d28c5ba100cbc8a4ea6e4f4da16f5c8319a02a72.tar.bz2 comus-d28c5ba100cbc8a4ea6e4f4da16f5c8319a02a72.zip |
fork syscall
Diffstat (limited to '')
-rw-r--r-- | kernel/include/comus/user.h | 5 | ||||
-rw-r--r-- | kernel/syscall.c | 18 | ||||
-rw-r--r-- | kernel/user.c | 31 | ||||
-rw-r--r-- | user/fork.c | 20 |
4 files changed, 72 insertions, 2 deletions
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 @@ -18,6 +18,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 */ void user_cleanup(struct pcb *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 <comus/user.h> #include <comus/cpu.h> #include <comus/syscalls.h> #include <comus/drivers/acpi.h> @@ -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 <unistd.h> +#include <stdio.h> + +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; +} |