summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--kernel/include/comus/procs.h5
-rw-r--r--kernel/include/comus/syscalls.h4
-rw-r--r--kernel/syscall.c105
-rw-r--r--user/forkman.c121
-rw-r--r--user/include/unistd.h23
-rw-r--r--user/lib/syscall.S2
7 files changed, 250 insertions, 12 deletions
diff --git a/Makefile b/Makefile
index f5d6020..54fa441 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@ GRUB ?= grub-mkrescue
QEMUOPTS += -cdrom $(BIN)/$(ISO) \
-no-reboot \
- -drive format=raw,file=user/bin/apple \
+ -drive format=raw,file=user/bin/forkman \
-serial mon:stdio \
-m 4G \
-name kern
diff --git a/kernel/include/comus/procs.h b/kernel/include/comus/procs.h
index 7b1a70a..717f27a 100644
--- a/kernel/include/comus/procs.h
+++ b/kernel/include/comus/procs.h
@@ -71,6 +71,11 @@ struct pcb {
uint64_t syscall;
uint64_t wakeup;
uint8_t exit_status;
+
+ // pipe to check for shared memory
+ void* shared_mem;
+ size_t shared_mem_pages;
+ pid_t shared_mem_source;
};
/// ordering of pcb queues
diff --git a/kernel/include/comus/syscalls.h b/kernel/include/comus/syscalls.h
index f714184..f27b879 100644
--- a/kernel/include/comus/syscalls.h
+++ b/kernel/include/comus/syscalls.h
@@ -30,9 +30,11 @@
#define SYS_poweroff 17
#define SYS_drm 18
#define SYS_ticks 19
+#define SYS_allocshared 20
+#define SYS_popsharedmem 21
// UPDATE THIS DEFINITION IF MORE SYSCALLS ARE ADDED!
-#define N_SYSCALLS 20
+#define N_SYSCALLS 22
// interrupt vector entry for system calls
#define VEC_SYSCALL 0x80
diff --git a/kernel/syscall.c b/kernel/syscall.c
index 96d2fcf..2b98ec1 100644
--- a/kernel/syscall.c
+++ b/kernel/syscall.c
@@ -324,17 +324,102 @@ static int sys_ticks(void)
return 0;
}
+static int sys_popsharedmem(void)
+{
+ RET(void *, res_mem);
+ *res_mem = NULL;
+
+ if (pcb->shared_mem == NULL) {
+ return 1;
+ }
+
+ struct pcb *const sharer = pcb_find_pid(pcb->shared_mem_source);
+ if (sharer == NULL) {
+ // process died or something since sharing
+ pcb->shared_mem = NULL;
+ return 1;
+ }
+
+ void *result =
+ mem_mapaddr(pcb->memctx, mem_get_phys(sharer->memctx, pcb->shared_mem),
+ pcb->shared_mem, pcb->shared_mem_pages * PAGE_SIZE,
+ F_WRITEABLE | F_UNPRIVILEGED);
+
+ // if (!result) {
+ // alert the other process that we cannot get its allocation?
+ // mem_free_pages(pcb->memctx, alloced);
+ // return 1;
+ // }
+
+ *res_mem = result;
+
+ pcb->shared_mem = NULL;
+
+ return 0;
+}
+
+static int sys_allocshared(void)
+{
+ ARG1(size_t, num_pages);
+ ARG2(unsigned short, otherpid); // same as pid_t
+ RET(void *, res_mem);
+ *res_mem = NULL;
+ assert(sizeof(unsigned short) == sizeof(pid_t),
+ "out of date sys_memshare syscall, pid_t changed?");
+
+ if (otherpid == pcb->pid || otherpid == 0) {
+ return 1;
+ }
+
+ struct pcb *const otherpcb = pcb_find_pid(otherpid);
+ if (otherpcb == NULL) {
+ // no such target process exists
+ return 1;
+ }
+ if (otherpcb->shared_mem != NULL) {
+ // it has yet to consume the last allocshared given to it
+ return 1;
+ }
+
+ void *alloced =
+ mem_alloc_pages(pcb->memctx, num_pages, F_WRITEABLE | F_UNPRIVILEGED);
+
+ if (!alloced) {
+ return 1;
+ }
+
+ otherpcb->shared_mem = alloced;
+ otherpcb->shared_mem_source = pcb->pid;
+ otherpcb->shared_mem_pages = num_pages;
+
+ *res_mem = alloced;
+
+ return 0;
+}
+
static int (*syscall_tbl[N_SYSCALLS])(void) = {
- [SYS_exit] = sys_exit, [SYS_waitpid] = sys_waitpid,
- [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,
- [SYS_gettime] = sys_gettime, [SYS_getprio] = sys_getprio,
- [SYS_setprio] = sys_setprio, [SYS_kill] = sys_kill,
- [SYS_sleep] = sys_sleep, [SYS_brk] = sys_brk,
- [SYS_sbrk] = sys_sbrk, [SYS_poweroff] = sys_poweroff,
- [SYS_drm] = sys_drm, [SYS_ticks] = sys_ticks,
+ [SYS_exit] = sys_exit,
+ [SYS_waitpid] = sys_waitpid,
+ [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,
+ [SYS_gettime] = sys_gettime,
+ [SYS_getprio] = sys_getprio,
+ [SYS_setprio] = sys_setprio,
+ [SYS_kill] = sys_kill,
+ [SYS_sleep] = sys_sleep,
+ [SYS_brk] = sys_brk,
+ [SYS_sbrk] = sys_sbrk,
+ [SYS_poweroff] = sys_poweroff,
+ [SYS_drm] = sys_drm,
+ [SYS_ticks] = sys_ticks,
+ [SYS_allocshared] = sys_allocshared,
+ [SYS_popsharedmem] = sys_popsharedmem,
};
void syscall_handler(void)
diff --git a/user/forkman.c b/user/forkman.c
new file mode 100644
index 0000000..fb5ae5f
--- /dev/null
+++ b/user/forkman.c
@@ -0,0 +1,121 @@
+/*
+ * FORKMAN: a platformer game with IPC
+ *
+ * This executable will fork. One process is responsible for writing to the
+ * screen and getting user input, the other is responsible for game logic.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#define GAME_WIDTH 480
+#define GAME_HEIGHT 360
+#define SHARED_PAGES 10
+#define PAGE_SIZE 4096
+
+typedef struct {
+ uint32_t *mapped_memory;
+ int width;
+ int height;
+ int bpp;
+ int scale;
+ size_t size;
+} framebuffer;
+
+typedef struct {
+ volatile size_t frame;
+ volatile size_t dummy_counter;
+ volatile int lock;
+ volatile uint8_t mem[PAGE_SIZE * (SHARED_PAGES - 1)];
+} sharedmem;
+
+static int display_server_entry(sharedmem *);
+static int client_entry(sharedmem *);
+
+int main(void)
+{
+ uint8_t *current_break = sbrk(0);
+ if (!current_break) {
+ fprintf(stderr, "sbrk failure\n");
+ return 1;
+ }
+
+ printf("ABOUT TO FORK\n");
+
+ int child = fork();
+ if (child < 0) {
+ fprintf(stderr, "fork failed!\n");
+ return 1;
+ }
+
+ if (child) {
+ printf("FORK GOOD, CHILD IS %d\n", child);
+ sharedmem *shared = allocshared(SHARED_PAGES, child);
+ if (!shared) {
+ fprintf(stderr, "memory share failure\n");
+ return 1;
+ }
+
+ return display_server_entry(shared);
+ } else {
+ printf("FORK GOOD, WE ARE CHILD\n");
+
+ sharedmem *shared;
+
+ while (!(shared = popsharedmem()))
+ sleep(1);
+
+ return client_entry(shared);
+ }
+}
+
+static void set_pixel(framebuffer *fb, size_t x, size_t y,
+ int state) // state is 0 or 1
+{
+ fb->mapped_memory[x + y * fb->width] = state * (0x00010101);
+}
+
+static int display_server_entry(sharedmem *shared)
+{
+ framebuffer fb;
+ if (drm((void **)&fb.mapped_memory, &fb.width, &fb.height, &fb.bpp)) {
+ fprintf(stderr, "Unable to map framebuffer, display server failing\n");
+ return 1;
+ }
+
+ fb.size = (fb.width * fb.height * fb.bpp) / 8;
+
+ size_t last_frame = 1;
+
+ while (1) {
+ if (shared->frame == last_frame) {
+ continue;
+ }
+
+ printf("server writing frame %zu\n", last_frame);
+
+ last_frame += 1;
+ shared->frame = last_frame;
+ }
+
+ return 0;
+}
+
+static int client_entry(sharedmem *shared)
+{
+ size_t last_frame = shared->frame;
+ do {
+ if (last_frame == shared->frame)
+ continue;
+
+ printf("client writing frame %zu\n", last_frame);
+
+ last_frame += 1;
+ shared->frame = last_frame;
+ } while (1);
+
+ return 0;
+}
diff --git a/user/include/unistd.h b/user/include/unistd.h
index cad3a81..27b6d31 100644
--- a/user/include/unistd.h
+++ b/user/include/unistd.h
@@ -187,6 +187,29 @@ extern void *brk(const void *addr);
extern void *sbrk(intptr_t increment);
/**
+ * Allocate a number of pages shared with another PID. Does not map the pages
+ * into the other process's vtable until the other process calls popsharedmem().
+ *
+ * @param num_pages number of pages to allocate
+ * @param other_pid pid of other process
+ * @return pointer to the virtual address which will be accessible by both,
+ * after popsharedmem() is called.
+ */
+extern void* allocshared(size_t num_pages, int other_pid);
+
+/**
+ * Checks if another process has tried to share memory with us, and return it.
+ * No size information is returned, it is only guaranteed that there is at least
+ * one page in the shared allocation. To get around this, the sharer can write
+ * a size number to the start of the first page.
+ *
+ * @return page aligned pointer to the start of the shared pages, or NULL if no
+ * process has tried to share with us, or NULL if we the shared virtual address
+ * space is already occupied in the caller's pagetable.
+ */
+extern void* popsharedmem(void);
+
+/**
* Poweroff the system.
*
* @return 1 on failure
diff --git a/user/lib/syscall.S b/user/lib/syscall.S
index 2ba4dc0..9e050bc 100644
--- a/user/lib/syscall.S
+++ b/user/lib/syscall.S
@@ -27,3 +27,5 @@ SYSCALL sbrk SYS_sbrk
SYSCALL poweroff SYS_poweroff
SYSCALL drm SYS_drm
SYSCALL ticks SYS_ticks
+SYSCALL allocshared SYS_allocshared
+SYSCALL popsharedmem SYS_popsharedmem