diff options
author | Ian McFarlane <i.mcfarlane2002@gmail.com> | 2025-05-02 00:37:08 -0400 |
---|---|---|
committer | Ian McFarlane <i.mcfarlane2002@gmail.com> | 2025-05-02 00:37:08 -0400 |
commit | 74c2b180769ef14ad42fe666207271bf344b11b9 (patch) | |
tree | 1957f4cdccc46b440898032f79350dfb113b19e4 | |
parent | fmt (diff) | |
download | comus-74c2b180769ef14ad42fe666207271bf344b11b9.tar.gz comus-74c2b180769ef14ad42fe666207271bf344b11b9.tar.bz2 comus-74c2b180769ef14ad42fe666207271bf344b11b9.zip |
Add allocshared() and popsharedmem() syscalls
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | kernel/include/comus/procs.h | 5 | ||||
-rw-r--r-- | kernel/include/comus/syscalls.h | 4 | ||||
-rw-r--r-- | kernel/syscall.c | 105 | ||||
-rw-r--r-- | user/forkman.c | 121 | ||||
-rw-r--r-- | user/include/unistd.h | 23 | ||||
-rw-r--r-- | user/lib/syscall.S | 2 |
7 files changed, 250 insertions, 12 deletions
@@ -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 |