aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/uapi/proc.c2
-rw-r--r--common/vmem.c38
-rw-r--r--include/apos/unaligned.h248
-rw-r--r--include/apos/vmem.h212
-rw-r--r--include/libfdt_env.h32
5 files changed, 480 insertions, 52 deletions
diff --git a/common/uapi/proc.c b/common/uapi/proc.c
index 2c1fe77..b2fc4f0 100644
--- a/common/uapi/proc.c
+++ b/common/uapi/proc.c
@@ -47,7 +47,7 @@ SYSCALL_DEFINE2(exec)(sys_arg_t bin, sys_arg_t interp){
}
/* free everything except regions to be kept */
- clear_uvmem(r, false);
+ clear_uvmem(r);
/* restore to normal */
clear_bit(b->flags, MR_KEEP);
diff --git a/common/vmem.c b/common/vmem.c
index f446b65..9761e3e 100644
--- a/common/vmem.c
+++ b/common/vmem.c
@@ -25,17 +25,27 @@ static stat_t __free_mapped_region(struct tcb *t, struct mem_region *m)
return status;
}
-stat_t clear_uvmem(struct tcb *t, bool force)
+stat_t clear_uvmem(struct tcb *t)
{
struct mem_region *m = find_first_region(&t->sp_r);
while (m) {
- /* if force is not set, free only regions that are not marked to
- * be kept and are owned.
- *
- * if force is set, free all owned regions.
- */
- if (is_region_owned(m) && (force || !is_region_kept(m)))
+ if (is_region_owned(m) && !is_region_kept(m))
__free_mapped_region(t, m);
+
+ m = m->next;
+ }
+
+ return OK;
+}
+
+stat_t purge_uvmem(struct tcb *t)
+{
+ struct mem_region *m = find_first_region(&t->sp_r);
+ while (m) {
+ if (is_region_owned(m))
+ __free_mapped_region(t, m);
+
+ m = m->next;
}
return OK;
@@ -44,7 +54,7 @@ stat_t clear_uvmem(struct tcb *t, bool force)
stat_t destroy_uvmem(struct tcb *t)
{
/* force clear all regions */
- clear_uvmem(t, true);
+ purge_uvmem(t);
/* destroy region tree itself */
return destroy_region(&t->sp_r);
}
@@ -123,17 +133,17 @@ vm_t ref_shared_uvmem(struct tcb *t1, struct tcb *t2, vm_t va, vmflags_t flags)
}
/** \todo assume tcb is root tcb? */
-stat_t free_uvmem(struct tcb *t, vm_t va)
+stat_t free_uvmem(struct tcb *r, vm_t va)
{
- struct mem_region *m = find_used_region(&t->sp_r, va);
+ struct mem_region *m = find_used_region(&r->sp_r, va);
if (!m)
return -1;
- free_region(&t->sp_r, va);
+ free_region(&r->sp_r, va);
- stat_t status = __free_mapped_region(t, m);
- if (is_rpc(t) && status == INFO_SEFF)
- return clone_rpc_maps(t);
+ stat_t status = __free_mapped_region(r, m);
+ if (is_rpc(r) && status == INFO_SEFF)
+ return clone_rpc_maps(r);
return status;
}
diff --git a/include/apos/unaligned.h b/include/apos/unaligned.h
index 85d67b0..332c992 100644
--- a/include/apos/unaligned.h
+++ b/include/apos/unaligned.h
@@ -9,64 +9,244 @@
#include <apos/types.h>
#include <apos/attrs.h>
-#define get_unaligned(ptr) \
- _Generic(*(ptr), uint8_t \
- : __get_unaligned_uint8_t, uint16_t \
- : __get_unaligned_uint16_t, uint32_t \
- : __get_unaligned_uint32_t, uint64_t \
- : __get_unaligned_uint64_t, int8_t \
- : __get_unaligned_int8_t, int16_t \
- : __get_unaligned_int16_t, int32_t \
- : __get_unaligned_int32_t, int64_t \
- : __get_unaligned_int64_t)((void *)ptr)
+/**
+ * Get unaligned value. Type of value is deduced from pointer type.
+ *
+ * @param ptr Pointer to possibly unaligned value to read.
+ * @return Value pointed to by \c ptr.
+ */
+#define get_unaligned(ptr) \
+ _Generic(*(ptr), \
+ uint8_t: get_unaligned_uint8_t, \
+ uint16_t: get_unaligned_uint16_t, \
+ uint32_t: get_unaligned_uint32_t, \
+ uint64_t: get_unaligned_uint64_t, \
+ \
+ int8_t: get_unaligned_int8_t, \
+ int16_t: get_unaligned_int16_t, \
+ int32_t: get_unaligned_int32_t, \
+ int64_t: get_unaligned_int64_t)((void *)ptr)
-#define put_unaligned(val, ptr) \
- _Generic(*(ptr), uint8_t \
- : __put_unaligned_uint8_t, uint16_t \
- : __put_unaligned_uint16_t, uint32_t \
- : __put_unaligned_uint32_t, uint64_t \
- : __put_unaligned_uint64_t, int8_t \
- : __put_unaligned_int8_t, int16_t \
- : __put_unaligned_int16_t, int32_t \
- : __put_unaligned_int32_t, int64_t \
- : __put_unaligned_int64_t)(val, (void *)ptr)
+/**
+ * Put unaligned value. Type of value is deduced from pointer type.
+ *
+ * @param val Value to write to memory.
+ * @param ptr Pointer to possibly unaligned address.
+ */
+#define put_unaligned(val, ptr) \
+ _Generic(*(ptr), \
+ uint8_t: put_unaligned_uint8_t, \
+ uint16_t: put_unaligned_uint16_t, \
+ uint32_t: put_unaligned_uint32_t, \
+ uint64_t: put_unaligned_uint64_t, \
+ \
+ int8_t: put_unaligned_int8_t, \
+ int16_t: put_unaligned_int16_t, \
+ int32_t: put_unaligned_int32_t, \
+ int64_t: put_unaligned_int64_t)(val, (void *)ptr)
-#define DEFINE_GET(type) \
- static inline type __get_unaligned_##type(void *ptr) \
- { \
- const struct __packed { \
- type x; \
- } *__pptr = ptr; \
- return __pptr->x; \
+/**
+ * Helper macro for defining an unaligned value reader.
+ *
+ * @param type Type of value reader to define.
+ */
+#define DEFINE_GET(type) \
+ static inline type get_unaligned_##type(void *ptr) \
+ { \
+ const struct __packed { \
+ type x; \
+ } *__pptr = ptr; \
+ return __pptr->x; \
}
+/**
+ * Read possibly unaligned \ref uint8_t.
+ *
+ * Technically speaking a byte can't be unaligned, but this is just here for
+ * cohesion.
+ *
+ * @warning Prefer using \ref get_unaligned().
+ *
+ * @param ptr Pointer to \ref uint8_t to read.
+ * @return Value pointed to by \c ptr.
+ */
DEFINE_GET(uint8_t);
+
+/**
+ * Read possibly unaligned \ref uint16_t.
+ *
+ * @warning Prefer using \ref get_unaligned().
+ *
+ * @param ptr Pointer to \ref uint16_t to read.
+ * @return Value pointed to by \c ptr.
+ */
DEFINE_GET(uint16_t);
+
+/**
+ * Read possibly unaligned \ref uint32_t.
+ *
+ * @warning Prefer using \ref get_unaligned().
+ *
+ * @param ptr Pointer to \ref uint32_t to read.
+ * @return Value pointed to by \c ptr.
+ */
DEFINE_GET(uint32_t);
+
+/**
+ * Read possibly unaligned \ref uint64_t.
+ *
+ * @warning Prefer using \ref get_unaligned().
+ *
+ * @param ptr Pointer to \ref uint64_t to read.
+ * @return Value pointed to by \c ptr.
+ */
DEFINE_GET(uint64_t);
+
+/**
+ * Read possibly unaligned \ref int8_t.
+ *
+ * Technically speaking a byte can't be unaligned, but this is just here for
+ * cohesion.
+ *
+ * @warning Prefer using \ref get_unaligned().
+ *
+ * @param ptr Pointer to \ref int8_t to read.
+ * @return Value pointed to by \c ptr.
+ */
DEFINE_GET(int8_t);
+
+/**
+ * Read possibly unaligned \ref int16_t.
+ *
+ * @warning Prefer using \ref get_unaligned().
+ *
+ * @param ptr Pointer to \ref int16_t to read.
+ * @return Value pointed to by \c ptr.
+ */
DEFINE_GET(int16_t);
+
+/**
+ * Read possibly unaligned \ref int32_t.
+ *
+ * @warning Prefer using \ref get_unaligned().
+ *
+ * @param ptr Pointer to \ref int32_t to read.
+ * @return Value pointed to by \c ptr.
+ */
DEFINE_GET(int32_t);
+
+/**
+ * Read possibly unaligned \ref int64_t.
+ *
+ * @warning Prefer using \ref get_unaligned().
+ *
+ * @param ptr Pointer to \ref int64_t to read.
+ * @return Value pointed to by \c ptr.
+ */
DEFINE_GET(int64_t);
#undef DEFINE_GET
-#define DEFINE_PUT(type) \
- static inline void __put_unaligned_##type(type val, void *ptr) \
- { \
- struct __packed { \
- type x; \
- } *__pptr = ptr; \
- __pptr->x = val; \
+/**
+ * Helper macro for defining an unaligned writer.
+ *
+ * @param type Type of value to write.
+ */
+#define DEFINE_PUT(type) \
+ static inline void put_unaligned_##type(type val, void *ptr) \
+ { \
+ struct __packed { \
+ type x; \
+ } *__pptr = ptr; \
+ __pptr->x = val; \
}
+/**
+ * Write possibly unaligned \ref uint8_t.
+ *
+ * Technically speaking a byte can't be unaligned, but this is just here for
+ * cohesion.
+ *
+ * @warning Prefer using \ref put_unaligned().
+ *
+ * @param val Value to write.
+ * @param ptr Address to write to.
+ */
DEFINE_PUT(uint8_t);
+
+/**
+ * Write possibly unaligned \ref uint16_t.
+ *
+ * @warning Prefer using \ref put_unaligned().
+ *
+ * @param val Value to write.
+ * @param ptr Address to write to.
+ */
DEFINE_PUT(uint16_t);
+
+/**
+ * Write possibly unaligned \ref uint32_t.
+ *
+ * @warning Prefer using \ref put_unaligned().
+ *
+ * @param val Value to write.
+ * @param ptr Address to write to.
+ */
DEFINE_PUT(uint32_t);
+
+/**
+ * Write possibly unaligned \ref uint64_t.
+ *
+ * @warning Prefer using \ref put_unaligned().
+ *
+ * @param val Value to write.
+ * @param ptr Address to write to.
+ */
DEFINE_PUT(uint64_t);
+
+/**
+ * Write possibly unaligned \ref int8_t.
+ *
+ * Technically speaking a byte can't be unaligned, but this is just here for
+ * cohesion.
+ *
+ * @warning Prefer using \ref put_unaligned().
+ *
+ * @param val Value to write.
+ * @param ptr Address to write to.
+ */
DEFINE_PUT(int8_t);
+
+/**
+ * Write possibly unaligned \ref int16_t.
+ *
+ * @warning Prefer using \ref put_unaligned().
+ *
+ * @param val Value to write.
+ * @param ptr Address to write to.
+ */
DEFINE_PUT(int16_t);
+
+/**
+ * Write possibly unaligned \ref int32_t.
+ *
+ * @warning Prefer using \ref put_unaligned().
+ *
+ * @param val Value to write.
+ * @param ptr Address to write to.
+ */
DEFINE_PUT(int32_t);
+
+/**
+ * Write possibly unaligned \ref int64_t.
+ *
+ * @warning Prefer using \ref put_unaligned().
+ *
+ * @param val Value to write.
+ * @param ptr Address to write to.
+ */
DEFINE_PUT(int64_t);
+#undef DEFINE_PUT
+
#endif /* APOS_UNALIGNED_H */
diff --git a/include/apos/vmem.h b/include/apos/vmem.h
index 96158be..c02d968 100644
--- a/include/apos/vmem.h
+++ b/include/apos/vmem.h
@@ -11,39 +11,245 @@
#include <apos/pmem.h>
#include <apos/sp_tree.h>
+/**
+ * Allocate user virtual memory.
+ *
+ * Virtual memory start address is chosen according to best fit with regard to
+ * size.
+ *
+ * @param r 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.
+ */
vm_t alloc_uvmem(struct tcb *r, size_t size, vmflags_t flags);
+
+/**
+ * Allocate fixed user virtual memory.
+ *
+ * Virtual memory start address is chosen so that \c start is within the
+ * allocation and the allocation after \c start is at least \c size bytes large.
+ * It is unspecified how many bytes are between the start of the allocation and
+ * \c start.
+ *
+ * @param r Process to allocate memory in.
+ * @param start Address that should be in allocation.
+ * @param size Minimum size of allocation.
+ * @param flags Flags of allocation.
+ * @return Start of allocation when succesful, \c NULL otherwise.
+ */
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 size Minimum size of allocation.
+ * @param flags Flags of allocation.
+ * @return Start of allocation when succesful, \c NULL otherwise.
+ */
vm_t alloc_shared_uvmem(struct tcb *r, size_t size, vmflags_t flags);
+
+/**
+ * Reference shared user virtual memory.
+ *
+ * Only callable by clients.
+ *
+ * @param r1 Process in which shared memory resides.
+ * @param r2 Process to reference shared memory in.
+ * @param va Virtual address of shared memory in \c r1.
+ * @param flags Flags of reference in \c r2.
+ * @return Start of reference in \c r2 when succesful, \c NULL otherwise.
+ */
vm_t ref_shared_uvmem(struct tcb *r1, struct tcb *r2, vm_t va, vmflags_t flags);
-stat_t clear_uvmem(struct tcb *r, bool force);
-stat_t free_uvmem(struct tcb *r, vm_t a);
+/**
+ * Free all user virtual memory allocations not marked with \ref MR_KEEP.
+ *
+ * @param r Process in which to clear user virtual memory.
+ * @return \ref OK.
+ */
+stat_t clear_uvmem(struct tcb *r);
+
+/**
+ * Free all user virtual memory allocations, even if marked with \ref MR_KEEP.
+ *
+ * @param r Process in which to clear user virtual memory.
+ * @return \ref OK.
+ */
+stat_t purge_uvmem(struct tcb *r);
+
+/**
+ * Free one user virtual memory allocation.
+ *
+ * @param r Process in which to clear user virtual memory.
+ * @param va Start of user virtual memory allocation to free.
+ * @return \ref OK.
+ */
+stat_t free_uvmem(struct tcb *r, vm_t va);
+/**
+ * Initialize user virtual memory instance.
+ *
+ * This assumes the user virtual memory is contiguous, with no holes between \c
+ * base and \c top.
+ *
+ * @param r Process in which to initialize user virtual memory.
+ * @param base Start of user virtual memory.
+ * @param top Top of user virtual memory.
+ * @return \see init_region().
+ */
stat_t init_uvmem(struct tcb *r, vm_t base, vm_t top);
+
+/**
+ * Destroy user virtual memory instance.
+ *
+ * @param r Process in which to destroy user virtual memory.
+ * @return \see destroy_region().
+ */
stat_t destroy_uvmem(struct tcb *r);
+/**
+ * User virtual memory worker callback for \ref map_fill_region().
+ *
+ * \c data is a pointer to \ref stat_t, which is set to \ref INFO_SEFF if all
+ * threads in process should sync their memory mappings. This occurs when the
+ * top level page table is modified.
+ *
+ * @param b Virtual memory to work in.
+ * @param offset Hint for \ref alloc_page().
+ * @param vaddr Current virtual address.
+ * @param flags Flags of region.
+ * @param order Suggested page order.
+ * @param data Pointer to \ref stat_t.
+ * @return \c OK when suggested order if acceptable, \c INFO_TRGN if suggested
+ * order not acceptable. Error otherwise.
+ * again
+ */
stat_t alloc_uvmem_wrapper(struct vmem *b, pm_t *offset, vm_t vaddr,
vmflags_t flags, enum mm_order order, void *data);
+
+/**
+ * Shared user virtual memory worker callback for \ref map_fill_region().
+ *
+ * @param b Virtual memory to work in.
+ * @param offset Hint for \ref alloc_page().
+ * @param vaddr Current virtual address.
+ * @param flags Flags of region.
+ * @param order Suggested page order.
+ * @param data Pointer to \ref stat_t.
+ * @return \see alloc_uvmem_wrapper().
+ *
+ * \see alloc_uvmem_wrapper().
+ */
stat_t alloc_shared_wrapper(struct vmem *b, pm_t *offset, vm_t vaddr,
vmflags_t flags, enum mm_order order, void *data);
+
+/**
+ * User virtual memory COW cloning worker callback for \ref map_fill_region().
+ *
+ * Currently unused, but intention is to set up COW clone of some other virtual
+ * memory region, likely passed through \c data?
+ *
+ * @param b Virtual memory to work in.
+ * @param offset Hint for \ref alloc_page().
+ * @param vaddr Current virtual address.
+ * @param flags Flags of region.
+ * @param order Suggested page order.
+ * @param data Pointer to \ref vmem to clone from.
+ * @return \see alloc_uvmem_wrapper().
+ *
+ * \see alloc_uvmem_wraper().
+ * \todo Implement.
+ */
stat_t clone_allocd_wrapper(struct vmem *b, pm_t *offset, vm_t vaddr,
vmflags_t flags, enum mm_order order, void *data);
+
+/**
+ * User virtual memory freeing worker callback for \ref map_fill_region().
+ *
+ * @param b Virtual memory to work in.
+ * @param offset Hint for \ref alloc_page().
+ * @param vaddr Current virtual address.
+ * @param flags Flags of region.
+ * @param order Suggested page order.
+ * @param data Pointer to \ref stat_t.
+ * @return \see alloc_uvmem_wrapper().
+ *
+ * \see alloc_uvmem_wrapper().
+ */
stat_t free_uvmem_wrapper(struct vmem *b, pm_t *offset, vm_t vaddr,
vmflags_t flags, enum mm_order order, void *data);
+/**
+ * Convenience wrapper for \ref map_fill_region() when mapping an allocated
+ * region.
+ *
+ * @param b Virtual memory to work in.
+ * @param start Start of virtual memory region to map.
+ * @param bytes Size of virtual memory region.
+ * @param flags Flags of virtual memory region.
+ * @param data Pointer to \c stat_t.
+ * @return \see map_fill_region().
+ */
#define map_allocd_region(b, start, bytes, flags, data) \
map_fill_region(b, &alloc_uvmem_wrapper, 0, start, bytes, flags, data)
+/**
+ * Convenience wrapper for \ref map_fill_region() when mapping a shared region.
+ *
+ * @param b Virtual memory to work in.
+ * @param start Start of virtual memory region to map.
+ * @param bytes Size of virtual memory region.
+ * @param flags Flags of virtual memory region.
+ * @param data Pointer to \c stat_t.
+ * @return \see map_fill_region().
+ */
#define map_shared_region(b, start, bytes, flags, data) \
map_fill_region(b, &alloc_shared_wrapper, 0, start, bytes, flags, data)
+/**
+ * Convenience wrapper for \ref map_fill_region() when COW cloning a region.
+ *
+ * @param b Virtual memory to work in.
+ * @param start Start of virtual memory region to map.
+ * @param bytes Size of virtual memory region.
+ * @param flags Flags of virtual memory region.
+ * @param data Pointer to \c vmem to clone.
+ * @return \see map_fill_region().
+ */
#define clone_allocd_region(b, start, bytes, flags, data) \
map_fill_region(b, &clone_allocd_wrapper, 0, start, bytes, flags, data)
+/**
+ * Convenience wrapper for \ref map_fill_region() when freeing region.
+ *
+ * @param b Virtual memory to work in.
+ * @param start Start of virtual memory region to unmap.
+ * @param bytes Size of virtual memory region.
+ * @param flags Flags of virtual memory region. Technically unused?
+ * @param data Pointer to \c stat_t.
+ * @return \see map_fill_region().
+ */
#define unmap_freed_region(b, start, bytes, flags, data) \
map_fill_region(b, &free_uvmem_wrapper, 0, start, bytes, flags, data)
+/**
+ * Extract virtual memory flags (MR_XXX).
+ *
+ * @param x Flags to extract virtual memory region flags from.
+ * @return Virtual memory region flags.
+ */
#define vm_flags(x) ((x) & ~0xff)
-#define vp_flags(x) ((x)&0xff)
+
+/**
+ * Extract physical memory page flags (VM_XXX).
+ *
+ * @param x Flags to extract physical memory page flags from.
+ * @return Physical memory page flags.
+ */
+#define vp_flags(x) ((x) & 0xff)
#endif /* APOS_VMEM_H */
diff --git a/include/libfdt_env.h b/include/libfdt_env.h
index 7d00910..589100b 100644
--- a/include/libfdt_env.h
+++ b/include/libfdt_env.h
@@ -11,13 +11,45 @@
#include <apos/string.h>
#include <apos/bits.h>
+/** 16bit integer. */
typedef int16_t fdt16_t;
+
+/** 32bit integer. */
typedef int32_t fdt32_t;
+
+/** 64bit integer. */
typedef int64_t fdt64_t;
+/**
+ * Convert FDT 32bit integer to cpu endianness.
+ *
+ * @param x Integer to convert.
+ * @return Value of \c x in cpu endianness.
+ */
#define fdt32_to_cpu(x) be32_to_cpu(x)
+
+/**
+ * Convert 32bit cpu endian integer to FDT endianness.
+ *
+ * @param x Integer to convert.
+ * @return Value of \c x in FDT endianness.
+ */
#define cpu_to_fdt32(x) cpu_to_be32(x)
+
+/**
+ * Convert FDT 64bit integer to cpu endianness.
+ *
+ * @param x Integer to convert.
+ * @return Value of \c x in cpu endianness.
+ */
#define fdt64_to_cpu(x) be64_to_cpu(x)
+
+/**
+ * Convert 64bit cpu endian integer to FDT endianness.
+ *
+ * @param x Integer to convert.
+ * @return Value of \c x in FDT endianness.
+ */
#define cpu_to_fdt64(x) cpu_to_be64(x)
#endif /* LIBFDT_ENV_H */