From 10ae2e6ebc7e9776b9f124c9fc530c79f5e84460 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Fri, 2 Dec 2022 21:12:11 +0200 Subject: initial shared memory working --- arch/riscv64/conf/init | Bin 5088 -> 6072 bytes arch/riscv64/conf/init.c | 55 ++++++++++++++++++++++++++++++++++++++++----- arch/riscv64/conf/initrd | Bin 5632 -> 6656 bytes common/elf.c | 3 ++- common/mem_regions.c | 22 +++++++++++++----- common/uapi/dispatch.c | 1 + common/uapi/mem.c | 28 +++++++++++++++-------- common/vmem.c | 44 ++++++++++++++++++++++++++++-------- include/apos/mem_regions.h | 18 +++++++++++++++ include/apos/uapi.h | 16 ------------- include/apos/vmem.h | 16 ++++++++----- 11 files changed, 151 insertions(+), 52 deletions(-) diff --git a/arch/riscv64/conf/init b/arch/riscv64/conf/init index 0d99b80..b24a661 100755 Binary files a/arch/riscv64/conf/init and b/arch/riscv64/conf/init differ diff --git a/arch/riscv64/conf/init.c b/arch/riscv64/conf/init.c index 4cd4cea..fb7c737 100644 --- a/arch/riscv64/conf/init.c +++ b/arch/riscv64/conf/init.c @@ -25,6 +25,17 @@ struct sys_ret { long a0, a1, a2, a3, a4, a5; }; +char *strcpy(char * restrict dst, const char * restrict src) +{ + const char *s1 = src; + char *s2 = dst; + + while (*s1) + *(s2++) = *(s1++); + + return dst; +} + struct sys_ret ecall(struct sys_ret s) { register long a0 asm ("a0") = s.a0; @@ -165,7 +176,7 @@ static struct ipc_args sys_ipc_req(long tid, long d0, long d1, long d2, long d3) if (r.a0) print_value("ipc_req() failed with error ", r.a0); - return (struct ipc_args){r.a2, r.a3, r.a4, r.a5}; + return (struct ipc_args){r.a1, r.a2, r.a3, r.a4}; } static void sys_ipc_resp(long d0, long d1, long d2, long d3) @@ -206,11 +217,36 @@ static void sys_free_mem(void *p) print_value("sys_free_mem() failed with error ", r.a0); } +static void *sys_req_sharedmem(long tid, unsigned long size, void **cbuf) +{ + struct sys_ret r = {.a0 = SYS_REQ_SHAREDMEM, .a1 = tid, .a2 = size, + .a3 = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 4), + .a4 = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 4)}; + r = ecall(r); + + if (r.a0) + print_value("sys_req_sharedmem() failed with error ", r.a0); + + *cbuf = (void *)r.a2; + return (void *)r.a1; +} + +/* I'm guessing my elf parser doesn't handle data pages correctly yet... */ +static char *rw_buf = 0; +static size_t rw_buf_size = 4096; + void callback(long status, long tid, long d0, long d1, long d2, long d3) { (void)status; - (void)tid; - sys_ipc_resp(d0, d1, d2, d3); + + void *cbuf = 0; + if (d0 == 1) + rw_buf = sys_req_sharedmem(tid, rw_buf_size, &cbuf); + + if (d0 == 2) + puts(rw_buf); + + sys_ipc_resp((long)cbuf, rw_buf_size, 0, 0); } #define CSR_TIME "0xc01" @@ -262,11 +298,10 @@ void _start() print_value("Swaps (both ways) per second", n); puts("Doing ipc requests...\n"); - long d0 = 0, d1 = 0, d2 = 0, d3 = 0; csr_read(CSR_TIME, i); start = i; n = 0; while (i < start + second) { - sys_ipc_req(1, n, d1, d2, d3); + sys_ipc_req(1, 0, 0, 0, 0); csr_read(CSR_TIME, i); n++; } @@ -280,5 +315,15 @@ void _start() sys_free_mem(p); } + puts("Checking shared memory\n"); + struct ipc_args r = sys_ipc_req(1, 1, 0, 0, 0); + rw_buf = (char *)r.a1; + print_value("Shared memory ptr", (uintptr_t)rw_buf); + print_value("Shared memory size", rw_buf_size); + + rw_buf[0] = 0; + strcpy(rw_buf, "Hello from the other side!\n"); + sys_ipc_req(1, 2, 0, 0, 0); + sys_poweroff(0); } diff --git a/arch/riscv64/conf/initrd b/arch/riscv64/conf/initrd index 8d36a5a..35cf825 100644 Binary files a/arch/riscv64/conf/initrd and b/arch/riscv64/conf/initrd differ diff --git a/common/elf.c b/common/elf.c index fcd6e85..f423fc5 100644 --- a/common/elf.c +++ b/common/elf.c @@ -54,7 +54,7 @@ static void __map_exec(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart, * segment fits into it */ /** \todo check if p_memsz is larger than p_filesz, the segment should be * filled with zeroes. */ - /** \todo in general, make this a low more clean. */ + /** \todo in general, make this a lot more clean. */ /* useful bit of info: all segments are sorted in ascending order of p_vaddr */ vm_t runner = phstart; vmflags_t default_flags = VM_V | VM_R | VM_W | VM_X | VM_U; @@ -74,6 +74,7 @@ static void __map_exec(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart, uint8_t uvflags = __elf_to_uvflags(elf_flags); map_allocd_region(t->proc.vmem, start, vsz, default_flags, 0); + memset((void *)start, 0, vsz); vm_t vo = bin + program_header_prop(ei_c, runner, p_offset); vm_t vfz = program_header_prop(ei_c, runner, p_filesz); diff --git a/common/mem_regions.c b/common/mem_regions.c index eee9230..17f3a1e 100644 --- a/common/mem_regions.c +++ b/common/mem_regions.c @@ -323,12 +323,14 @@ struct mem_region *find_first_region(struct mem_region_root *r) * @param m Free memory region to carve used memory region out of. * @param pages Number of base order pages to give used region. * @param align Alignment of used region. In this case, start of used region + * @param pid Process ID to associate with region if shared. 0 if private. * from start of free region. * @param flags Flags of used region. * @return Start address of used region. */ static vm_t __partition_region(struct mem_region_root *r, struct mem_region *m, - size_t pages, size_t align, vmflags_t flags) + size_t pages, size_t align, vmflags_t flags, + id_t pid) { sp_remove(&sp_root(&r->free_regions), &m->sp_n); @@ -364,6 +366,7 @@ static vm_t __partition_region(struct mem_region_root *r, struct mem_region *m, m->end = end; m->start = start; m->flags = flags; + m->pid = pid; mark_region_used(m->flags); __insert_used_region(r, m); return __addr(start); @@ -373,8 +376,9 @@ static vm_t __partition_region(struct mem_region_root *r, struct mem_region *m, * just ignore them for now. Note that alloc_region should only be used when * mmap is called with MAP_ANON, all other situations should be handled in some * fs server */ -vm_t alloc_region(struct mem_region_root *r, size_t size, size_t *actual_size, - vmflags_t flags) +stat_t alloc_shared_region(struct mem_region_root *r, size_t size, + size_t *actual_size, + vmflags_t flags, id_t pid) { size_t asize = align_up(size, BASE_PAGE_SIZE); if (actual_size) @@ -388,7 +392,13 @@ vm_t alloc_region(struct mem_region_root *r, size_t size, size_t *actual_size, if (!m) return 0; - return __partition_region(r, m, pages, align, flags); + return __partition_region(r, m, pages, align, flags, pid); +} + +vm_t alloc_region(struct mem_region_root *r, size_t size, size_t *actual_size, + vmflags_t flags) +{ + return alloc_shared_region(r, size, actual_size, flags, 0); } vm_t alloc_fixed_region(struct mem_region_root *r, vm_t start, size_t size, @@ -406,7 +416,7 @@ vm_t alloc_fixed_region(struct mem_region_root *r, vm_t start, size_t size, return 0; /* locate actual region where start is between the region start and end */ - while (!((m->start <= start) && (start <= m->end))) { + while (!((m->start <= start) && (start < m->end))) { if (start > m->start) m = m->next; else @@ -422,7 +432,7 @@ vm_t alloc_fixed_region(struct mem_region_root *r, vm_t start, size_t size, return 0; /* actually start marking region used */ - return __partition_region(r, m, pages, start - m->start, flags); + return __partition_region(r, m, pages, start - m->start, flags, 0); } /** diff --git a/common/uapi/dispatch.c b/common/uapi/dispatch.c index aa63170..d11e02e 100644 --- a/common/uapi/dispatch.c +++ b/common/uapi/dispatch.c @@ -53,6 +53,7 @@ void handle_syscall(sys_arg_t syscall, sys_arg_t a, sys_arg_t b, case SYS_REQ_MEM: sys_req_mem(t, a, b, c, d, e); break; case SYS_REQ_PMEM: sys_req_pmem(t, a, b, c, d, e); break; case SYS_REQ_FIXMEM: sys_req_fixmem(t, a, b, c, d, e); break; + case SYS_REQ_SHAREDMEM: sys_req_sharedmem(t, a, b, c, d, e); break; case SYS_FREE_MEM: sys_free_mem(t, a, b, c, d, e); break; case SYS_TIMEBASE: sys_timebase(t, a, b, c, d, e); break; case SYS_TICKS: sys_ticks(t, a, b, c, d, e); break; diff --git a/common/uapi/mem.c b/common/uapi/mem.c index 374bcbe..099028e 100644 --- a/common/uapi/mem.c +++ b/common/uapi/mem.c @@ -107,23 +107,33 @@ SYSCALL_DEFINE3(req_pmem)(struct tcb *t, sys_arg_t paddr, sys_arg_t size, * Request shared memory syscall handler. * * @param t Current tcb. + * @param tid Thread to share memory with. * @param size Minimum size of allocation. - * @param flags Flags of allocation. - * @return \ref OK and start of allocation when succesful, - * \ref ERR_OOMEM and \c NULL otherwise. + * @param sflags Flags of allocation for \p t. + * @param cflags Flags of allocation for \p tid. + * @return \ref OK and start of \p t allocation and start of \p tid allocation, + * in that order, \ref ERR_OOMEM otherwise. * * @todo should we also take the thread who should get the other end of the * memory? */ -SYSCALL_DEFINE2(req_sharedmem)(struct tcb *t, sys_arg_t size, sys_arg_t flags) +SYSCALL_DEFINE4(req_sharedmem)(struct tcb *t, sys_arg_t tid, + sys_arg_t size, sys_arg_t sflags, + sys_arg_t cflags) { - /** \todo check that requester is server */ - struct tcb *r = get_cproc(t); - vm_t start = 0; - if (!(start = alloc_shared_uvmem(r, size, flags))) + /** @todo check capability for shared memory */ + struct tcb *u = get_tcb(tid); + if (!u) + return_args(t, SYS_RET1(ERR_INVAL)); + + struct tcb *s = get_cproc(t); + struct tcb *c = get_rproc(u); + + vm_t sstart, cstart; + if (alloc_shared_uvmem(s, c, size, sflags, cflags, &sstart, &cstart)) return_args(t, SYS_RET1(ERR_OOMEM)); - return_args(t, SYS_RET2(OK, start)); + return_args(t, SYS_RET3(OK, sstart, cstart)); } /** \todo add some way to specify who gets to access the shared memory? */ diff --git a/common/vmem.c b/common/vmem.c index a53ce6c..781458a 100644 --- a/common/vmem.c +++ b/common/vmem.c @@ -151,19 +151,45 @@ vm_t alloc_fixed_uvmem(struct tcb *t, vm_t start, size_t size, vmflags_t flags) } /* free_shared_uvmem shouldn't be needed, likely to work with free_uvmem */ -vm_t alloc_shared_uvmem(struct tcb *t, size_t size, vmflags_t flags) +stat_t alloc_shared_uvmem(struct tcb *s, struct tcb *c, + size_t size, vmflags_t sflags, vmflags_t cflags, + vm_t *sstart, vm_t *cstart) { - hard_assert(t && is_proc(t), ERR_INVAL); + hard_assert(sstart, ERR_INVAL); + hard_assert(cstart, ERR_INVAL); + hard_assert(s && is_proc(s), ERR_INVAL); + hard_assert(c && is_proc(c), ERR_INVAL); + + size_t ssize, csize; + vm_t sv = alloc_shared_region(&s->sp_r, size, &ssize, sflags, c->rid); + vm_t cv = alloc_shared_region(&c->sp_r, size, &csize, cflags, s->rid); + + if (csize != ssize) { + /** @todo cleanup, better errors? */ + return ERR_INVAL; + } - stat_t status = OK; - const vm_t v = alloc_region(&t->sp_r, size, &size, - flags | MR_SHARED | MR_OWNED); - const vm_t w = map_shared_region(t->proc.vmem, v, size, flags, &status); + stat_t cstatus = OK, sstatus = OK; + size_t osize = order_size(BASE_PAGE); + size_t pages = ssize / osize; + for (size_t i = 0; i < pages; ++i) { + pm_t p = alloc_page(BASE_PAGE); + sstatus = map_vpage(s->proc.vmem, p, sv + i * osize, sflags, + BASE_PAGE); + cstatus = map_vpage(c->proc.vmem, p, cv + i * osize, cflags, + BASE_PAGE); + } - if (is_rpc(t) && status == INFO_SEFF) - clone_rpc_maps(t); + if (cstatus == INFO_SEFF) + clone_rpc_maps(c); - return w; + if (sstatus == INFO_SEFF) + clone_rpc_maps(s); + + *sstart = sv; + *cstart = cv; + + return OK; } vm_t ref_shared_uvmem(struct tcb *t1, struct tcb *t2, vm_t va, vmflags_t flags) diff --git a/include/apos/mem_regions.h b/include/apos/mem_regions.h index b94d15a..7231dbd 100644 --- a/include/apos/mem_regions.h +++ b/include/apos/mem_regions.h @@ -85,6 +85,9 @@ struct mem_region { * MR_SHARED, MR_OWNED, MR_COW, MR_KEEP. */ vmflags_t flags; + /** In shared regions, mark the other pid that shared the region. */ + id_t pid; + /** End address of memory region. */ vm_t end; @@ -124,6 +127,21 @@ stat_t destroy_region(struct mem_region_root *r); vm_t alloc_region(struct mem_region_root *r, size_t size, size_t *actual_size, vmflags_t flags); +/** + * Allocate memory region and associate it with some other process. + * Will allocate region of at least \c size bytes, with best possible location. + * + * @param r Memory region root. + * @param size Size of region to allocate. + * @param actual_size Size of region that was allocated. + * @param flags Memory flags. + * @param pid Process to associate with region. + * @return Address of allocated region on success, otherwise \c NULL. + */ +stat_t alloc_shared_region(struct mem_region_root *r, size_t size, + size_t *actual_size, + vmflags_t flags, id_t pid); + /** * Allocate fixed memory region. * Will allocate region that is at least \c size bytes, and includes \c start. diff --git a/include/apos/uapi.h b/include/apos/uapi.h index 7bd00bb..dda4391 100644 --- a/include/apos/uapi.h +++ b/include/apos/uapi.h @@ -373,22 +373,6 @@ SYSCALL_DECLARE3(req_fixmem, start, size, flags); */ SYSCALL_DECLARE4(req_sharedmem, tid, size, sflags, cflags); -/** - * Reference shared memory syscall. - * - * \see sys_req_sharedmem(). - * - * @param t Current tcb. - * @param tid Thread ID of owner of shared memory. - * @param va Start address of shared memory. - * @param flags Flags to use for reference. - * @param d Unused. - * @param e Unused. - * - * Returns \ref OK and start of shared memory. - */ -SYSCALL_DECLARE3(ref_sharedmem, tid, va, flags); - /** * Free memory syscall. * diff --git a/include/apos/vmem.h b/include/apos/vmem.h index 1e481fa..38bad16 100644 --- a/include/apos/vmem.h +++ b/include/apos/vmem.h @@ -46,14 +46,18 @@ vm_t alloc_fixed_uvmem(struct tcb *r, vm_t start, size_t size, vmflags_t flags); /** * Allocate shared user virtual memory. * - * Only callable by servers, who are the owners of the shared region. - * - * @param r Process to allocate memory in. + * @param s First process to allocate memory in. + * @param c Second process to allocate memory in. * @param size Minimum size of allocation. - * @param flags Flags of allocation. - * @return Start of allocation when succesful, \c NULL otherwise. + * @param sflags Flags of allocation for \p s. + * @param cflags Flags of allocation for \p c. + * @param sstart Start of allocation for \p s. + * @param cstart Start of allocation for \p c. + * @return Status of allocation. */ -vm_t alloc_shared_uvmem(struct tcb *r, size_t size, vmflags_t flags); +stat_t alloc_shared_uvmem(struct tcb *s, struct tcb *c, size_t size, + vmflags_t sflags, vmflags_t cflags, + vm_t *sstart, vm_t *cstart); /** * Reference shared user virtual memory. -- cgit v1.3