aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2022-12-02 21:12:11 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2022-12-02 21:12:11 +0200
commit10ae2e6ebc7e9776b9f124c9fc530c79f5e84460 (patch)
tree6687cf98db623f8c38c5d5aea234014a27302e10
parent131af4eec38752a27e6e56579fbf76178e022ec1 (diff)
downloadkmi-10ae2e6ebc7e9776b9f124c9fc530c79f5e84460.tar.gz
kmi-10ae2e6ebc7e9776b9f124c9fc530c79f5e84460.zip
initial shared memory working
-rwxr-xr-xarch/riscv64/conf/initbin5088 -> 6072 bytes
-rw-r--r--arch/riscv64/conf/init.c55
-rw-r--r--arch/riscv64/conf/initrdbin5632 -> 6656 bytes
-rw-r--r--common/elf.c3
-rw-r--r--common/mem_regions.c22
-rw-r--r--common/uapi/dispatch.c1
-rw-r--r--common/uapi/mem.c28
-rw-r--r--common/vmem.c44
-rw-r--r--include/apos/mem_regions.h18
-rw-r--r--include/apos/uapi.h16
-rw-r--r--include/apos/vmem.h16
11 files changed, 151 insertions, 52 deletions
diff --git a/arch/riscv64/conf/init b/arch/riscv64/conf/init
index 0d99b80..b24a661 100755
--- a/arch/riscv64/conf/init
+++ b/arch/riscv64/conf/init
Binary files 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
--- a/arch/riscv64/conf/initrd
+++ b/arch/riscv64/conf/initrd
Binary files 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);
- 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);
+ 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 (is_rpc(t) && status == INFO_SEFF)
- clone_rpc_maps(t);
+ if (csize != ssize) {
+ /** @todo cleanup, better errors? */
+ return ERR_INVAL;
+ }
- return w;
+ 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 (cstatus == INFO_SEFF)
+ clone_rpc_maps(c);
+
+ 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;
@@ -125,6 +128,21 @@ 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.
* \note The address returned might not be the address requested, and the caller
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
@@ -374,22 +374,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.
*
* Frees the memory region pointed to.
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.