diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-07-09 17:35:56 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-07-09 17:35:56 +0300 |
| commit | 298636079d912d0936f8156a609fe74b839c547b (patch) | |
| tree | e0c22ce0e7b7c8a29e3937616076e8fb327fde8b | |
| parent | e134202611a50b358c147c92bfb8a7f443030b8b (diff) | |
| download | kmi-298636079d912d0936f8156a609fe74b839c547b.tar.gz kmi-298636079d912d0936f8156a609fe74b839c547b.zip | |
allow mapping null page
+ User has to 'free' the 0 page before it becomes accessible to mapping.
Probably worth noting that this is likely VERY niche and mainly
concerns stuff like certain kinds of emulators that I'm still
eons from implementing, but still.
Unbacked pages can also be useful for some kinds of notifications,
like 'if someone writes to this page, please report it to me with this
ID' or whatever, I remember seeing some discussion about it somewhere
but that's also not really relevant for the moment.
Most significantly, at least with the current design,
after the null page is freed it becomes available for use to regular req_mem()
calls, so users should probably using locks around memory requests.
That's probably a good idea anyway as internally the kernal has to
lock the virtual memory, and without a scheduler it might cause
threads to spin for a while in the kernel which is rather bad.
| -rw-r--r-- | arch/riscv64/conf/init.c | 2 | ||||
| -rw-r--r-- | arch/riscv64/config.h | 5 | ||||
| -rw-r--r-- | include/arch/vmem.h | 15 | ||||
| -rw-r--r-- | include/kmi/atomic.h | 2 | ||||
| -rw-r--r-- | include/kmi/mem.h | 17 | ||||
| -rw-r--r-- | include/kmi/syscalls.h | 7 | ||||
| -rw-r--r-- | include/kmi/types.h | 6 | ||||
| -rw-r--r-- | include/kmi/uapi.h | 72 | ||||
| -rw-r--r-- | include/kmi/unaligned.h | 32 | ||||
| -rw-r--r-- | include/kmi/utils.h | 66 | ||||
| -rw-r--r-- | include/kmi/vmem.h | 10 | ||||
| -rw-r--r-- | src/debug.c | 4 | ||||
| -rw-r--r-- | src/tcb.c | 36 | ||||
| -rw-r--r-- | src/uapi/conf.c | 12 | ||||
| -rw-r--r-- | src/uapi/mem.c | 36 | ||||
| -rw-r--r-- | src/vmem.c | 131 |
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. @@ -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); } @@ -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; |
