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 --- common/elf.c | 3 ++- common/mem_regions.c | 22 ++++++++++++++++------ common/uapi/dispatch.c | 1 + common/uapi/mem.c | 28 +++++++++++++++++++--------- common/vmem.c | 44 +++++++++++++++++++++++++++++++++++--------- 5 files changed, 73 insertions(+), 25 deletions(-) (limited to 'common') 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) -- cgit v1.3