summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-04-28 17:28:02 -0400
committerFreya Murphy <freya@freyacat.org>2025-04-28 17:28:02 -0400
commitd28c5ba100cbc8a4ea6e4f4da16f5c8319a02a72 (patch)
treece096652da2f8f9889bb377b80f6aafc9bf05788
parentclone pgdir (diff)
downloadcomus-d28c5ba100cbc8a4ea6e4f4da16f5c8319a02a72.tar.gz
comus-d28c5ba100cbc8a4ea6e4f4da16f5c8319a02a72.tar.bz2
comus-d28c5ba100cbc8a4ea6e4f4da16f5c8319a02a72.zip
fork syscall
Diffstat (limited to '')
-rw-r--r--kernel/include/comus/user.h5
-rw-r--r--kernel/syscall.c18
-rw-r--r--kernel/user.c31
-rw-r--r--user/fork.c20
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;
+}