aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/riscv64/conf/init.c2
-rw-r--r--arch/riscv64/config.h5
-rw-r--r--include/arch/vmem.h15
-rw-r--r--include/kmi/atomic.h2
-rw-r--r--include/kmi/mem.h17
-rw-r--r--include/kmi/syscalls.h7
-rw-r--r--include/kmi/types.h6
-rw-r--r--include/kmi/uapi.h72
-rw-r--r--include/kmi/unaligned.h32
-rw-r--r--include/kmi/utils.h66
-rw-r--r--include/kmi/vmem.h10
-rw-r--r--src/debug.c4
-rw-r--r--src/tcb.c36
-rw-r--r--src/uapi/conf.c12
-rw-r--r--src/uapi/mem.c36
-rw-r--r--src/vmem.c131
16 files changed, 260 insertions, 193 deletions
diff --git a/arch/riscv64/conf/init.c b/arch/riscv64/conf/init.c
index c4e8064..03fdc64 100644
--- a/arch/riscv64/conf/init.c
+++ b/arch/riscv64/conf/init.c
@@ -273,7 +273,7 @@ static void sys_sleep()
#define CSR_TIME "0xc01"
#define csr_read(csr, \
- res) __asm__ volatile ("csrr %0, " csr : "=r" (res) :: "memory")
+ res) __asm__ volatile ("csrr %0, " csr : "=r" (res) :: "memory")
#define CSR_CYCLE "0xc00"
diff --git a/arch/riscv64/config.h b/arch/riscv64/config.h
index 952c0ca..d686ed9 100644
--- a/arch/riscv64/config.h
+++ b/arch/riscv64/config.h
@@ -51,8 +51,9 @@
*/
#define CSTACK_PAGE 248UL
-/** User virtual memory space start. */
-#define UVMEM_START (SZ_4K)
+/** User virtual memory space start. Should essentially always be the start of
+ * the NULL page, which is marked reserved in the address space by \ref init_uvmem().*/
+#define UVMEM_START (0)
/** User virtual memory space end. */
#define UVMEM_END (SZ_256G - SZ_8G)
diff --git a/include/arch/vmem.h b/include/arch/vmem.h
index a19f555..1674e95 100644
--- a/include/arch/vmem.h
+++ b/include/arch/vmem.h
@@ -24,9 +24,6 @@
/**
* Map one virtual page to physical page.
*
- * If \ref INFO_SEFF is returned, the caller is responsible for synchronizing
- * all other threads that are in the same virtual address space.
- *
* The caller is responsible for checking that both virtual and physical page of
* the correct order are available.
*
@@ -35,7 +32,8 @@
* @param vaddr Virtual address to map page to.
* @param flags Page flags.
* @param order Order of page.
- * @return \ref INFO_SEFF when top level table modified, \ref OK otherwise.
+ * @return \ref OK when succesful, possibly \ref ERR_OOMEM if we don't have
+ * enough pages to create the mapping.
*/
stat_t map_vpage(struct vmem *branch, pm_t paddr, vm_t vaddr, vmflags_t flags,
enum mm_order order);
@@ -56,8 +54,7 @@ stat_t unmap_vpage(struct vmem *branch, vm_t vaddr);
* @param branch Branch in which to work.
* @param vaddr Virtual address of page.
* @param flags Flags to set.
- * @return \ref ERR_NF if no page could be found at \p vaddr,
- * \ref INFO_SEFF if modification has side effects, otherwise \ref OK.
+ * @return \ref ERR_NF if no page could be found at \p vaddr, otherwise \ref OK.
*/
stat_t set_vpage_flags(struct vmem *branch, vm_t vaddr, vmflags_t flags);
@@ -68,7 +65,7 @@ stat_t set_vpage_flags(struct vmem *branch, vm_t vaddr, vmflags_t flags);
* @param vaddr Virtual address of page.
* @param flags Flags to clear.
* @return \ref ERR_NF if no page could be found at \p vaddr,
- * \ref INFO_SEFF if modification has side effects, otherwise \ref OK.
+ * otherwise \ref OK.
*/
stat_t clear_vpage_flags(struct vmem *branch, vm_t vaddr, vmflags_t flags);
@@ -82,9 +79,7 @@ stat_t clear_vpage_flags(struct vmem *branch, vm_t vaddr, vmflags_t flags);
* @param vaddr Virtual address of map to modify.
* @param paddr Physical address to map to.
* @param flags Flags to set.
- * @return \ref ERR_NF if no virtual page is found at \c vaddr.
- * \ref INFO_SEFF if modding takes place in top page table but otherwise
- * succesful, \ref OK otherwise.
+ * @return \ref ERR_NF if no virtual page is found at \c vaddr, \ref OK otherwise.
*/
stat_t mod_vpage(struct vmem *branch, vm_t vaddr, pm_t paddr, vmflags_t flags);
diff --git a/include/kmi/atomic.h b/include/kmi/atomic.h
index 88ffdfa..76d50e4 100644
--- a/include/kmi/atomic.h
+++ b/include/kmi/atomic.h
@@ -404,7 +404,7 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t;
*/
#define atomic_compare_exchange_weak(obj, val, des) \
atomic_compare_exchange_weak_explicit(obj, val, des, __ATOMIC_SEQ_CST, \
- __ATOMIC_SEQ_CST)
+ __ATOMIC_SEQ_CST)
/**
* Explicit atomic in-place addition.
diff --git a/include/kmi/mem.h b/include/kmi/mem.h
index 6c62d31..8c66eb5 100644
--- a/include/kmi/mem.h
+++ b/include/kmi/mem.h
@@ -177,12 +177,17 @@ size_t page_shift();
/** Memory region is used. */
#define MR_USED (1 << (ARCH_VP_FLAGS + 0))
+
/** Don't free memory on clear. */
#define MR_KEEP (1 << (ARCH_VP_FLAGS + 1))
+
/** Memory region in shared, but owned. Note: regions that are shared but no
* owned don't use this flag, they just set the tid field for the region. */
#define MR_SHARED (1 << (ARCH_VP_FLAGS + 2))
+/** Memory region is private but not backed by memory. */
+#define MR_NONBACKED (1 << (ARCH_VP_FLAGS + 3))
+
/** @} */
/**
@@ -243,4 +248,16 @@ pm_t get_load_addr();
/** Base page order. */
#define BASE_PAGE (MM_O0)
+/**
+ * Check if value is in range of error codes.
+ * The absolute top page of a virtual address space is -BASE_PAGE_SIZE, which
+ * will NEVER be used, so we can use it as a baseline. This allows quite a few
+ * error codes to be added in the future if need be.
+ * Although I guess the errors could be defined as positive and then just add a
+ * minus sign to every use to turn them negative? Dunno.
+ *
+ * @param x Value to check.
+ */
+#define ERR_CODE(x) ((vm_t)(x) > (vm_t)-BASE_PAGE_SIZE)
+
#endif /* KMI_MEM_H */
diff --git a/include/kmi/syscalls.h b/include/kmi/syscalls.h
index b6cde34..1efd0d4 100644
--- a/include/kmi/syscalls.h
+++ b/include/kmi/syscalls.h
@@ -235,6 +235,13 @@ enum conf_param {
* \c R.
*/
CONF_RAM_SIZE,
+
+ /**
+ * Size of page of some order.
+ * Uses `d0` to signify which order to request.
+ * \c R
+ */
+ CONF_PAGE_SIZE,
};
/**
diff --git a/include/kmi/types.h b/include/kmi/types.h
index 2b1492f..1da5248 100644
--- a/include/kmi/types.h
+++ b/include/kmi/types.h
@@ -489,12 +489,6 @@ enum status_codes {
ERR_NF = -1,
/** OK. */
OK = 0,
- /** Try again. */
- INFO_TRGN = 1,
- /** Side effects. */
- INFO_SEFF = 2,
- /** Continue. */
- INFO_CONT = 3,
};
#include <arch/types.h> /* arch-specific type definitions (pm_t/vm_t etc) */
diff --git a/include/kmi/uapi.h b/include/kmi/uapi.h
index 8047632..65a4d93 100644
--- a/include/kmi/uapi.h
+++ b/include/kmi/uapi.h
@@ -50,11 +50,11 @@ typedef void (*sys_t)(struct tcb *t, long, long, long, long, long);
*/
#define SYSCALL_DECLARE0(name) \
void sys_##name(struct tcb *t, \
- sys_arg_t a, \
- sys_arg_t b, \
- sys_arg_t c, \
- sys_arg_t d, \
- sys_arg_t e);
+ sys_arg_t a, \
+ sys_arg_t b, \
+ sys_arg_t c, \
+ sys_arg_t d, \
+ sys_arg_t e);
/**
* Helper macro for declaring syscalls with one argument.
@@ -64,8 +64,8 @@ typedef void (*sys_t)(struct tcb *t, long, long, long, long, long);
*/
#define SYSCALL_DECLARE1(name, a) \
void sys_##name(struct tcb *t, sys_arg_t a, sys_arg_t b, \
- sys_arg_t c, \
- sys_arg_t d, sys_arg_t e);
+ sys_arg_t c, \
+ sys_arg_t d, sys_arg_t e);
/**
* Helper macro for declaring syscalls with two arguments.
@@ -76,8 +76,8 @@ typedef void (*sys_t)(struct tcb *t, long, long, long, long, long);
*/
#define SYSCALL_DECLARE2(name, a, b) \
void sys_##name(struct tcb *t, sys_arg_t a, sys_arg_t b, \
- sys_arg_t c, \
- sys_arg_t d, sys_arg_t e);
+ sys_arg_t c, \
+ sys_arg_t d, sys_arg_t e);
/**
* Helper macro for declaring syscalls with three arguments.
@@ -89,8 +89,8 @@ typedef void (*sys_t)(struct tcb *t, long, long, long, long, long);
*/
#define SYSCALL_DECLARE3(name, a, b, c) \
void sys_##name(struct tcb *t, sys_arg_t a, sys_arg_t b, \
- sys_arg_t c, \
- sys_arg_t d, sys_arg_t e);
+ sys_arg_t c, \
+ sys_arg_t d, sys_arg_t e);
/**
* Helper macro for declaring syscalls with four arguments.
@@ -103,8 +103,8 @@ typedef void (*sys_t)(struct tcb *t, long, long, long, long, long);
*/
#define SYSCALL_DECLARE4(name, a, b, c, d) \
void sys_##name(struct tcb *t, sys_arg_t a, sys_arg_t b, \
- sys_arg_t c, \
- sys_arg_t d, sys_arg_t e);
+ sys_arg_t c, \
+ sys_arg_t d, sys_arg_t e);
/**
* Helper macro for declaring syscalls with five arguments.
@@ -118,8 +118,8 @@ typedef void (*sys_t)(struct tcb *t, long, long, long, long, long);
*/
#define SYSCALL_DECLARE5(name, a, b, c, d, e) \
void sys_##name(struct tcb *t, sys_arg_t a, sys_arg_t b, \
- sys_arg_t c, \
- sys_arg_t d, sys_arg_t e);
+ sys_arg_t c, \
+ sys_arg_t d, sys_arg_t e);
/**
* Helper macro for defining syscall with zero arguments.
@@ -135,8 +135,8 @@ typedef void (*sys_t)(struct tcb *t, long, long, long, long, long);
#define SYSCALL_DEFINE0(name) \
static inline void __##name(struct tcb *t); \
void __noinline sys_##name(struct tcb *t, sys_arg_t a, sys_arg_t b, \
- sys_arg_t c, \
- sys_arg_t d, sys_arg_t e) \
+ sys_arg_t c, \
+ sys_arg_t d, sys_arg_t e) \
{ \
UNUSED(a); \
UNUSED(b); \
@@ -155,8 +155,8 @@ typedef void (*sys_t)(struct tcb *t, long, long, long, long, long);
#define SYSCALL_DEFINE1(name) \
static inline void __##name(struct tcb *, sys_arg_t); \
void __noinline sys_##name(struct tcb *t, sys_arg_t a, sys_arg_t b, \
- sys_arg_t c, \
- sys_arg_t d, sys_arg_t e) \
+ sys_arg_t c, \
+ sys_arg_t d, sys_arg_t e) \
{ \
UNUSED(b); \
UNUSED(c); \
@@ -173,10 +173,10 @@ typedef void (*sys_t)(struct tcb *t, long, long, long, long, long);
*/
#define SYSCALL_DEFINE2(name) \
static inline void __##name(struct tcb *, sys_arg_t, \
- sys_arg_t); \
+ sys_arg_t); \
void __noinline sys_##name(struct tcb *t, sys_arg_t a, sys_arg_t b, \
- sys_arg_t c, \
- sys_arg_t d, sys_arg_t e) \
+ sys_arg_t c, \
+ sys_arg_t d, sys_arg_t e) \
{ \
UNUSED(c); \
UNUSED(d); \
@@ -192,11 +192,11 @@ typedef void (*sys_t)(struct tcb *t, long, long, long, long, long);
*/
#define SYSCALL_DEFINE3(name) \
static inline void __##name(struct tcb *, sys_arg_t, \
- sys_arg_t, \
- sys_arg_t); \
+ sys_arg_t, \
+ sys_arg_t); \
void __noinline sys_##name(struct tcb *t, sys_arg_t a, sys_arg_t b, \
- sys_arg_t c, \
- sys_arg_t d, sys_arg_t e) \
+ sys_arg_t c, \
+ sys_arg_t d, sys_arg_t e) \
{ \
UNUSED(d); \
UNUSED(e); \
@@ -211,11 +211,11 @@ typedef void (*sys_t)(struct tcb *t, long, long, long, long, long);
*/
#define SYSCALL_DEFINE4(name) \
static inline void __##name(struct tcb *, sys_arg_t, \
- sys_arg_t, sys_arg_t, \
- sys_arg_t); \
+ sys_arg_t, sys_arg_t, \
+ sys_arg_t); \
void __noinline sys_##name(struct tcb *t, sys_arg_t a, sys_arg_t b, \
- sys_arg_t c, \
- sys_arg_t d, sys_arg_t e) \
+ sys_arg_t c, \
+ sys_arg_t d, sys_arg_t e) \
{ \
UNUSED(e); \
__##name(t, a, b, c, d); \
@@ -229,11 +229,11 @@ typedef void (*sys_t)(struct tcb *t, long, long, long, long, long);
*/
#define SYSCALL_DEFINE5(name) \
static inline void __##name(struct tcb *, sys_arg_t, \
- sys_arg_t, sys_arg_t, \
- sys_arg_t, sys_arg_t); \
+ sys_arg_t, sys_arg_t, \
+ sys_arg_t, sys_arg_t); \
void __noinline sys_##name(struct tcb *t, sys_arg_t a, sys_arg_t b, \
- sys_arg_t c, \
- sys_arg_t d, sys_arg_t e) \
+ sys_arg_t c, \
+ sys_arg_t d, sys_arg_t e) \
{ \
__##name(t, a, b, c, d, e); \
} \
@@ -706,14 +706,14 @@ SYSCALL_DECLARE2(conf_set, param, val);
*
* @param t Current tcb.
* @param param Parameter to get.
- * @param b Unused.
+ * @param d0 Optional data argument to parameter.
* @param c Unused.
* @param d Unused.
* @param e Unused.
*
* Returns \ref OK.
*/
-SYSCALL_DECLARE1(conf_get, param);
+SYSCALL_DECLARE2(conf_get, param, d0);
/**
* Set capabilities.
diff --git a/include/kmi/unaligned.h b/include/kmi/unaligned.h
index 89f5894..fac5146 100644
--- a/include/kmi/unaligned.h
+++ b/include/kmi/unaligned.h
@@ -20,15 +20,15 @@
*/
#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, \
+ 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)
+ 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)
/**
* Put unaligned value. Type of value is deduced from pointer type.
@@ -38,15 +38,15 @@
*/
#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, \
+ 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)
+ 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)
/**
* Helper macro for defining an unaligned value reader.
diff --git a/include/kmi/utils.h b/include/kmi/utils.h
index a37f4bb..62d32da 100644
--- a/include/kmi/utils.h
+++ b/include/kmi/utils.h
@@ -251,18 +251,18 @@
*/
#define align_down(x, y) \
_Generic((x), signed char \
- : align_down_c, signed short \
- : align_down_s, signed int \
- : align_down_i, signed long \
- : align_down_l, signed long long \
- : align_down_ll, \
+ : align_down_c, signed short \
+ : align_down_s, signed int \
+ : align_down_i, signed long \
+ : align_down_l, signed long long \
+ : align_down_ll, \
\
- unsigned char \
- : align_down_uc, unsigned short \
- : align_down_us, unsigned int \
- : align_down_ui, unsigned long \
- : align_down_ul, unsigned long long \
- : align_down_ull)((x), (y))
+ unsigned char \
+ : align_down_uc, unsigned short \
+ : align_down_us, unsigned int \
+ : align_down_ui, unsigned long \
+ : align_down_ul, unsigned long long \
+ : align_down_ull)((x), (y))
/**
* Helper macro for defining type specific aligning.
@@ -385,18 +385,18 @@ DEFINE_ALIGN_DOWN(ull, unsigned long long);
*/
#define align_up(x, y) \
_Generic((x), signed char \
- : align_up_c, signed short \
- : align_up_s, signed int \
- : align_up_i, signed long \
- : align_up_l, signed long long \
- : align_up_ll, \
+ : align_up_c, signed short \
+ : align_up_s, signed int \
+ : align_up_i, signed long \
+ : align_up_l, signed long long \
+ : align_up_ll, \
\
- unsigned char \
- : align_up_uc, unsigned short \
- : align_up_us, unsigned int \
- : align_up_ui, unsigned long \
- : align_up_ul, unsigned long long \
- : align_up_ull)((x), (y))
+ unsigned char \
+ : align_up_uc, unsigned short \
+ : align_up_us, unsigned int \
+ : align_up_ui, unsigned long \
+ : align_up_ul, unsigned long long \
+ : align_up_ull)((x), (y))
/**
* Helper macro for defining type specific aligning.
@@ -515,18 +515,18 @@ DEFINE_ALIGN_UP(ull, unsigned long long);
*/
#define is_aligned(x, y) \
_Generic((x), signed char \
- : is_aligned_c, signed short \
- : is_aligned_s, signed int \
- : is_aligned_i, signed long \
- : is_aligned_l, signed long long \
- : is_aligned_ll, \
+ : is_aligned_c, signed short \
+ : is_aligned_s, signed int \
+ : is_aligned_i, signed long \
+ : is_aligned_l, signed long long \
+ : is_aligned_ll, \
\
- unsigned char \
- : is_aligned_uc, unsigned short \
- : is_aligned_us, unsigned int \
- : is_aligned_ui, unsigned long \
- : is_aligned_ul, unsigned long long \
- : is_aligned_ll)((x), (y))
+ unsigned char \
+ : is_aligned_uc, unsigned short \
+ : is_aligned_us, unsigned int \
+ : is_aligned_ui, unsigned long \
+ : is_aligned_ul, unsigned long long \
+ : is_aligned_ll)((x), (y))
/**
* Helper macro for defining type specific alignment checks.
diff --git a/include/kmi/vmem.h b/include/kmi/vmem.h
index dd968ca..eb46da5 100644
--- a/include/kmi/vmem.h
+++ b/include/kmi/vmem.h
@@ -98,17 +98,17 @@ 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.
+ * This assumes the user virtual memory is contiguous, with no holes between
+ * \ref UVMEM_START and \ref UVMEM_END. One base page at the start of the region
+ * is reserved for use as a NULL page, which can be freed by the user to
+ * 'accept' that it's dangerous to not have a NULL page.
*
* Requires that \p t already has a vmem allocated.
*
* @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);
+stat_t init_uvmem(struct tcb *r);
/**
* Destroy user virtual memory instance.
diff --git a/src/debug.c b/src/debug.c
index d87588d..950f73b 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -455,7 +455,7 @@ static size_t __print_sign(ssize_t value, size_t flags)
* @return \see __integral_val().
*/
#define __integral_len(value, base, flags) __integral_val((value), (base), \
- (flags), false)
+ (flags), false)
/**
* Print integral value as string.
@@ -466,7 +466,7 @@ static size_t __print_sign(ssize_t value, size_t flags)
* @return \see __integral_val().
*/
#define __integral_print(value, base, flags) __integral_val((value), (base), \
- (flags), true)
+ (flags), true)
/**
* Print integral value.
diff --git a/src/tcb.c b/src/tcb.c
index 053ea6f..48f1d3b 100644
--- a/src/tcb.c
+++ b/src/tcb.c
@@ -123,11 +123,14 @@ struct tcb *create_thread(struct tcb *p)
assert(tcbs);
vm_t bottom = alloc_page(KERNEL_STACK_PAGE_ORDER);
+ if (!bottom)
+ return NULL;
+
/* move tcb to top of kernel stack, keeping alignment in check
* (hopefully) */
/** \todo check alignment */
- bottom = bottom + order_size(MM_O0) - sizeof(struct tcb);
- struct tcb *t = (struct tcb *)align_down(bottom, sizeof(long));
+ vm_t top = bottom + order_size(MM_O0) - sizeof(struct tcb);
+ struct tcb *t = (struct tcb *)align_down(top, sizeof(long));
memset(t, 0, sizeof(struct tcb));
id_t tid = __alloc_tid(t);
@@ -141,9 +144,19 @@ struct tcb *create_thread(struct tcb *p)
* structure, this works on riscv but in the event that other
* systems don't we can easily turn this into a clone_uvmem. */
t->proc.vmem = p->proc.vmem;
- } else {
- t->proc.vmem = create_vmem();
- init_uvmem(t, UVMEM_START, UVMEM_END);
+ }
+ else {
+ if (!(t->proc.vmem = create_vmem())) {
+ free_page(MM_O0, bottom);
+ return NULL;
+ }
+
+ if (init_uvmem(t)) {
+ destroy_vmem(t->proc.vmem);
+ free_page(MM_O0, bottom);
+ return NULL;
+ }
+
t->pid = t->tid;
t->rid = t->tid;
p = t;
@@ -151,7 +164,16 @@ struct tcb *create_thread(struct tcb *p)
t->eid = t->pid;
t->rid = p->rid;
- t->rpc.vmem = create_vmem();
+
+ if (!(t->rpc.vmem = create_vmem())) {
+ if (likely(p))
+ return NULL;
+
+ destroy_vmem(t->proc.vmem);
+ free_page(MM_O0, bottom);
+ return NULL;
+ }
+
setup_rpc_stack(t);
reference_proc(p);
@@ -191,7 +213,7 @@ struct tcb *create_proc(struct tcb *p)
/* create a new thread outside the current process */
struct tcb *n = create_thread(NULL);
if (!n)
- return 0;
+ return NULL;
if (p)
__copy_proc(p, n); /* we have a parent process i.e. fork */
diff --git a/src/uapi/conf.c b/src/uapi/conf.c
index 3a45d30..c8ec964 100644
--- a/src/uapi/conf.c
+++ b/src/uapi/conf.c
@@ -42,9 +42,10 @@ size_t rpc_stack_size()
*
* @param t Current tcb.
* @param param Parameter to read.
+ * @param d0 Optional data argument for parameter.
* @return \ref OK and parameter value.
*/
-SYSCALL_DEFINE1(conf_get)(struct tcb *t, sys_arg_t param)
+SYSCALL_DEFINE2(conf_get)(struct tcb *t, sys_arg_t param, sys_arg_t d0)
{
/* anyone can read any current parameter, I don't think they should be
* hidden. */
@@ -66,6 +67,15 @@ SYSCALL_DEFINE1(conf_get)(struct tcb *t, sys_arg_t param)
val = get_ram_size();
break;
+ case CONF_PAGE_SIZE:
+ if (d0 < 0 || d0 > max_order()) {
+ val = 0;
+ break;
+ }
+
+ val = order_size(d0);
+ break;
+
default:
return_args1(t, ERR_NF);
}
diff --git a/src/uapi/mem.c b/src/uapi/mem.c
index 49370fc..b4b2df8 100644
--- a/src/uapi/mem.c
+++ b/src/uapi/mem.c
@@ -24,10 +24,10 @@
SYSCALL_DEFINE2(req_mem)(struct tcb *t, sys_arg_t size, sys_arg_t flags)
{
struct tcb *r = get_cproc(t);
- vm_t start = 0;
flags = sanitize_uvflags(flags);
- if (!(start = alloc_uvmem(r, size, flags)))
- return_args1(t, ERR_OOMEM);
+ vm_t start = alloc_uvmem(r, size, flags);
+ if (ERR_CODE(start))
+ return_args1(t, start);
return_args2(t, OK, start);
}
@@ -47,10 +47,10 @@ SYSCALL_DEFINE3(req_fixmem)(struct tcb *t, sys_arg_t fixed, sys_arg_t size,
sys_arg_t flags)
{
struct tcb *r = get_cproc(t);
- vm_t start = 0;
flags = sanitize_uvflags(flags);
- if (!(start = alloc_fixed_uvmem(r, fixed, size, flags)))
- return_args1(t, ERR_OOMEM);
+ vm_t start = alloc_fixed_uvmem(r, fixed, size, flags);
+ if (ERR_CODE(start))
+ return_args1(t, start);
return_args2(t, OK, start);
}
@@ -97,10 +97,10 @@ SYSCALL_DEFINE3(req_pmem)(struct tcb *t, sys_arg_t paddr, sys_arg_t size,
* that keeps track of used regions outside of RAM. We'll see.
*/
struct tcb *r = get_cproc(t);
- vm_t start = 0;
flags = sanitize_uvflags(flags);
- if (!(start = alloc_devmem(r, paddr, size, flags)))
- return_args1(t, ERR_OOMEM);
+ vm_t start = alloc_devmem(r, paddr, size, flags);
+ if (ERR_CODE(start))
+ return_args1(t, start);
return_args2(t, OK, start);
}
@@ -127,8 +127,9 @@ SYSCALL_DEFINE2(req_page)(struct tcb *t, sys_arg_t size, sys_arg_t flags)
vm_t start = 0;
size_t asize = 0;
flags = sanitize_uvflags(flags);
- if (!(start = alloc_uvpage(r, size, flags, &addr, &asize)))
- return_args1(t, ERR_OOMEM);
+ start = alloc_uvpage(r, size, flags, &addr, &asize);
+ if (ERR_CODE(start))
+ return_args1(t, start);
return_args4(t, OK, start, addr, asize);
}
@@ -148,10 +149,10 @@ SYSCALL_DEFINE2(req_sharedmem)(struct tcb *t, sys_arg_t size, sys_arg_t flags)
if (!has_cap(c->caps, CAP_SHARED))
return_args1(t, ERR_PERM);
- vm_t start = 0;
flags = sanitize_uvflags(flags);
- if (!(start = alloc_shared_uvmem(c, size, flags)))
- return_args1(t, ERR_OOMEM);
+ vm_t start = alloc_shared_uvmem(c, size, flags);
+ if (ERR_CODE(start))
+ return_args1(t, start);
return_args3(t, OK, start, size);
}
@@ -178,10 +179,11 @@ SYSCALL_DEFINE3(ref_sharedmem)(struct tcb *t, sys_arg_t tid, sys_arg_t addr,
if (!r || zombie(r))
return_args1(t, ERR_INVAL);
- vm_t start = 0; size_t size = 0;
+ size_t size = 0;
flags = sanitize_uvflags(flags);
- if (!(start = ref_shared_uvmem(r, c, addr, flags)))
- return_args1(t, ERR_OOMEM);
+ vm_t start = ref_shared_uvmem(r, c, addr, flags);
+ if (ERR_CODE(start))
+ return_args1(t, start);
return_args3(t, OK, start, size);
}
diff --git a/src/vmem.c b/src/vmem.c
index 261ef42..52e7bd2 100644
--- a/src/vmem.c
+++ b/src/vmem.c
@@ -14,11 +14,23 @@
#include <kmi/vmem.h>
#include <arch/vmem.h>
-stat_t init_uvmem(struct tcb *t, vm_t base, vm_t top)
+stat_t init_uvmem(struct tcb *t)
{
t->uvmem.owner = t->tid;
t->uvmem.vmem = t->proc.vmem;
- return init_region(&t->uvmem.region, base, top);
+
+ stat_t ret = OK;
+ if ((ret = init_region(&t->uvmem.region, UVMEM_START, UVMEM_END)))
+ return ret;
+
+ /* if a user really wants to use the first page for something, they'll
+ * have to free it first, 'accepting' that no null-page is dangerous. */
+ size_t size = 0;
+ vm_t v = alloc_fixed_region(&t->uvmem.region,
+ UVMEM_START, BASE_PAGE_SIZE, &size,
+ MR_NONBACKED);
+ assert(v == UVMEM_START && size == BASE_PAGE_SIZE);
+ return OK;
}
/**
@@ -40,6 +52,12 @@ static stat_t __copy_mapped_region(struct tcb *d, struct tcb *s,
size_t size = end - start;
vm_t v = alloc_fixed_region(&d->uvmem.region, start, size, &size,
m->flags);
+ if (ERR_CODE(v))
+ return v;
+
+ if (is_set(m->flags, MR_NONBACKED))
+ return v;
+
assert(v == start);
/* note that we use uvmem.vmem instead of proc.vmem, this is just to
@@ -76,6 +94,8 @@ static stat_t __copy_shared_region(struct tcb *d, struct mem_region *m)
size_t size = end - start;
vm_t v = alloc_fixed_region(&d->uvmem.region, start, size, &size,
m->flags);
+ if (ERR_CODE(v))
+ return v;
assert(v == start);
stat_t res = clone_region(d->uvmem.vmem, s->uvmem.vmem, start, v, size,
@@ -107,8 +127,11 @@ static vm_t __clone_shared_region(struct tcb *d, struct tcb *s,
reference_proc(s);
size_t size = end - start;
- vm_t v = alloc_shared_region(&d->uvmem.region, size, &size, m->flags,
- s->rid);
+ vm_t v = alloc_shared_region(&d->uvmem.region, size, &size,
+ MR_NONBACKED | m->flags, s->rid);
+ if (ERR_CODE(v))
+ return v;
+
stat_t res = clone_region(d->uvmem.vmem, s->uvmem.vmem, start, v, size,
flags);
if (res == OK)
@@ -118,7 +141,7 @@ static vm_t __clone_shared_region(struct tcb *d, struct tcb *s,
unreference_proc(s);
free_region(&d->uvmem.region, v);
unmap_fixed_region(d->uvmem.vmem, v, size);
- return NULL;
+ return res;
}
/**
@@ -127,44 +150,23 @@ static vm_t __clone_shared_region(struct tcb *d, struct tcb *s,
* @param t Current thread.
* @param m Memory region to free.
*/
-static void __free_private_mapping(struct tcb *t, struct mem_region *m)
+static void __free_mapping(struct tcb *t, struct mem_region *m)
{
+ struct tcb *owner = get_tcb(m->pid);
+ if (owner)
+ unreference_proc(owner);
+
+ if (is_set(m->flags, MR_NONBACKED))
+ return;
+
pm_t start = __addr(m->start);
pm_t end = __addr(m->end);
size_t size = end - start;
- unmap_region(t->proc.vmem, start, size);
-}
-
-/**
- * Unmap shared region and free associated physical pages if they're not being
- * used by the other process.
- *
- * @param t Current thread.
- * @param m Memory region to free.
- */
-static void __free_shared_mapping(struct tcb *t, struct mem_region *m)
-{
- vm_t start = __addr(m->start);
- vm_t end = __addr(m->end);
- unreference_proc(get_tcb(m->pid));
-
- size_t bytes = end - start;
- unmap_fixed_region(t->proc.vmem, start, bytes);
-}
-
-/**
- * Convenience function for freeing mapped regions.
- *
- * @param t Thread to work in.
- * @param m Memory region to free.
- */
-static void __free_mapping(struct tcb *t, struct mem_region *m)
-{
- if (m->pid != 0)
- return __free_shared_mapping(t, m);
-
- return __free_private_mapping(t, m);
+ if (m->pid)
+ unmap_fixed_region(t->proc.vmem, start, size);
+ else
+ unmap_region(t->proc.vmem, start, size);
}
void clear_uvmem(struct tcb *t)
@@ -174,13 +176,11 @@ void clear_uvmem(struct tcb *t)
struct mem_region *m = find_closest_used_region(&t->uvmem.region, 0);
for (; m; m = m->next) {
- if (is_region_kept(m)) {
+ if (is_region_kept(m))
continue;
- }
- if (!is_set(m->flags, MR_USED)) {
+ if (!is_set(m->flags, MR_USED))
continue;
- }
__free_mapping(t, m);
free_known_region(&t->uvmem.region, m);
@@ -243,10 +243,14 @@ vm_t alloc_uvmem(struct tcb *t, size_t size, vmflags_t flags)
assert(t && is_proc(t));
const vm_t v = alloc_region(&t->uvmem.region, size, &size, flags);
- if (map_region(t->proc.vmem, v, size, max_order(), flags)) {
+ if (ERR_CODE(v))
+ return v;
+
+ stat_t ret = OK;
+ if ((ret = map_region(t->proc.vmem, v, size, max_order(), flags))) {
unmap_region(t->proc.vmem, v, size);
free_region(&t->uvmem.region, v);
- return NULL;
+ return ret;
}
return v;
@@ -258,10 +262,14 @@ vm_t alloc_fixed_uvmem(struct tcb *t, vm_t start, size_t size, vmflags_t flags)
const vm_t v = alloc_fixed_region(&t->uvmem.region, start, size, &size,
flags);
- if (map_region(t->proc.vmem, v, size, max_order(), flags)) {
+ if (ERR_CODE(v))
+ return v;
+
+ stat_t ret = OK;
+ if ((ret = map_region(t->proc.vmem, v, size, max_order(), flags))) {
unmap_region(t->proc.vmem, v, size);
free_region(&t->uvmem.region, v);
- return NULL;
+ return ret;
}
return v;
@@ -269,14 +277,20 @@ vm_t alloc_fixed_uvmem(struct tcb *t, vm_t start, size_t size, vmflags_t flags)
vm_t map_fixed_uvmem(struct tcb *t, pm_t start, size_t size, vmflags_t flags)
{
+ assert(is_aligned(start, BASE_PAGE_SIZE));
+
const vm_t v = alloc_region(&t->uvmem.region, size, &size, flags);
- if (map_fixed_region(t->proc.vmem, v, start, size, flags)) {
+ if (ERR_CODE(v))
+ return v;
+
+ stat_t ret = OK;
+ if ((ret = map_fixed_region(t->proc.vmem, v, start, size, flags))) {
unmap_region(t->proc.vmem, v, size);
free_region(&t->uvmem.region, v);
- return NULL;
+ return ret;
}
- return v + (start % BASE_PAGE_SIZE);
+ return v;
}
vm_t alloc_uvpage(struct tcb *t, size_t size, vmflags_t flags, pm_t *startp,
@@ -286,19 +300,20 @@ vm_t alloc_uvpage(struct tcb *t, size_t size, vmflags_t flags, pm_t *startp,
size = order_size(order);
const vm_t v = alloc_region(&t->uvmem.region, size, &size, flags);
- if (!v)
- return 0;
+ if (ERR_CODE(v))
+ return v;
pm_t start = alloc_page(order);
if (!start) {
free_region(&t->uvmem.region, size);
- return 0;
+ return ERR_OOMEM;
}
- if (map_fixed_region(t->proc.vmem, v, start, size, flags)) {
+ stat_t ret = OK;
+ if ((ret = map_fixed_region(t->proc.vmem, v, start, size, flags))) {
unmap_region(t->proc.vmem, v, size);
free_region(&t->uvmem.region, v);
- return NULL;
+ return ret;
}
*startp = (pm_t)__pa(start);
@@ -313,11 +328,15 @@ vm_t alloc_shared_uvmem(struct tcb *s, size_t size, vmflags_t flags)
assert(s && is_proc(s));
const vm_t v = alloc_region(&s->uvmem.region, size, &size,
MR_SHARED | flags);
+ if (ERR_CODE(v))
+ return v;
+
/* use base pages to make clone more likely to succeed */
- if (map_region(s->proc.vmem, v, size, BASE_PAGE, flags)) {
+ stat_t ret = OK;
+ if ((ret = map_region(s->proc.vmem, v, size, BASE_PAGE, flags))) {
unmap_region(s->proc.vmem, v, size);
free_region(&s->uvmem.region, v);
- return NULL;
+ return ret;
}
return v;