diff --git a/include/uk/plat/memory.h b/include/uk/plat/memory.h index ccd93eb3bf52de7210e564eb0925f9ba5e032d7d..0d08bb73902e59801d97e0e2523444e054003db0 100644 --- a/include/uk/plat/memory.h +++ b/include/uk/plat/memory.h @@ -272,6 +272,8 @@ int ukplat_mem_init(void); * @param auxsp_len * The custom length of the auxiliary stack. If 0, then * CONFIG_UKPLAT_AUXSP_PAGE_ORDER is used instead as the default length. + * @param auxstack + * Pointer to the allocated auxiliary stack, used to store the start address. * * @return * Pointer to the allocated auxiliary stack @@ -280,7 +282,8 @@ static inline __uptr ukplat_auxsp_alloc(struct uk_alloc __maybe_unused *a, #if CONFIG_LIBUKVMEM struct uk_vas __maybe_unused *vas, #endif /* CONFIG_LIBUKVMEM */ - __sz auxsp_len) + __sz auxsp_len, + __uptr * auxstack) { __vaddr_t auxsp; @@ -331,6 +334,9 @@ static inline __uptr ukplat_auxsp_alloc(struct uk_alloc __maybe_unused *a, } #endif /* !CONFIG_LIBUKVMEM */ + if (auxstack) + *auxstack = auxsp; + /* If auxsp resulted from the previous allocations is ECTX aligned * and auxsp_len is ECTX aligned, then the function call below will * result in an ECTX aligned stack pointer. @@ -338,6 +344,48 @@ static inline __uptr ukplat_auxsp_alloc(struct uk_alloc __maybe_unused *a, return (__uptr)ukarch_gen_sp((__uptr)auxsp, auxsp_len); } +/* Free an auxiliary stack that created by ukplat_auxsp_alloc. + * The size is that given by (1 << CONFIG_AUXSP_PAGE_ORDER) * PAGE_SIZE. + * + * @param a + * The allocator to use for the auxiliary stack + * @param vas + * The virtual address space to use for the mapping of the auxiliary stack. + * This should be used in conjunction with CONFIG_LIBUKVMEM to ensure that + * accesses to the auxiliary stack do not generate page faults in more + * fragile system states. + * @param auxstack + * Pointer to the allocated auxiliary stack, used to store the start address. + * @param auxstack_len + * The custom length of the auxiliary stack. If 0, then + * CONFIG_UKPLAT_AUXSP_PAGE_ORDER is used instead as the default length. + */ +static inline void ukplat_auxsp_free(struct uk_alloc __maybe_unused *a, +#if CONFIG_LIBUKVMEM + struct uk_vas __maybe_unused *vas, +#endif /* CONFIG_LIBUKVMEM */ + __uptr auxstack, + __sz auxstack_len) +{ +#if CONFIG_LIBUKVMEM + int rc; + + /* Compitable with the behavior provided by ukplat_auxsp_alloc */ + if (!auxstack_len) + auxstack_len = + ALIGN_UP(PAGE_SIZE * (1 << CONFIG_UKPLAT_AUXSP_PAGE_ORDER), + UKARCH_ECTX_ALIGN); + + rc = uk_vma_unmap(vas, auxstack, auxstack_len, 0); + if (rc) { + uk_pr_err("Failed to unmap auxiliary stack\n"); + return; + } +#else /* !CONFIG_LIBUKVMEM */ + uk_free(a, auxstack); +#endif /* !CONFIG_LIBUKVMEM */ +} + #ifdef __cplusplus } #endif diff --git a/lib/uksched/include/uk/thread.h b/lib/uksched/include/uk/thread.h index 844d516e13f93dc98acd115793b729ba2a56f76e..0356d86ac724970e3b0428f223d280a106895762 100644 --- a/lib/uksched/include/uk/thread.h +++ b/lib/uksched/include/uk/thread.h @@ -81,6 +81,7 @@ struct uk_thread { struct uk_alloc *uktls_a; void *auxstack; struct uk_alloc *auxstack_a; + __sz auxstack_len; } _mem; /**< Associated allocs (internal!) */ uk_thread_gc_t _gc_fn; /**< Extra gc function (internal!) */ void *_gc_argp; /**< Argument for gc fn (internal!) */ diff --git a/lib/uksched/thread.c b/lib/uksched/thread.c index c86c8441cfa3344b708fa13e84da866b529b73ec..cd5c544cab5e682ab2e654dd8bd415d1d6f4db38 100644 --- a/lib/uksched/thread.c +++ b/lib/uksched/thread.c @@ -250,13 +250,22 @@ static void _uk_thread_struct_init(struct uk_thread *t, t->prio = prio; #endif - if (!auxsp) + if (!auxsp) { + /* These seems to be compatible code block, we should store + * necessary staff to free aux stack when release thread. + */ + __uptr auxstack = 0x0; auxsp = ukplat_auxsp_alloc(uk_alloc_get_default(), #if CONFIG_LIBUKVMEM uk_vas_get_active(), -#endif /* CONFIG_LIBUKVMEM */ - 0); /* Default auxsp size */ - +#endif /* CONFIG_LIBUKVMEM */ + 0, /* Default auxsp size */ + &auxstack); + if (auxsp && auxstack) { + t->_mem.auxstack = (void *)auxstack; + t->_mem.auxstack_a = uk_alloc_get_default(); + } + } t->auxsp = auxsp; if (tlsp && is_uktls) { @@ -392,7 +401,8 @@ static int _uk_thread_struct_init_alloc(struct uk_thread *t, { void *stack = NULL; void *tls = NULL; - void *auxstack = 0x0; + __uptr auxstack = 0x0; + __uptr auxsp = 0x0; uintptr_t tlsp = 0x0; int rc; @@ -405,12 +415,12 @@ static int _uk_thread_struct_init_alloc(struct uk_thread *t, } if (a_auxstack && auxstack_len) { - auxstack = (void *)ukplat_auxsp_alloc(a_auxstack, + auxsp = ukplat_auxsp_alloc(a_auxstack, #if CONFIG_LIBUKVMEM - uk_vas_get_active(), + uk_vas_get_active(), #endif /* CONFIG_LIBUKVMEM */ - auxstack_len); - if (unlikely(!auxstack)) { + auxstack_len, &auxstack); + if (unlikely(!auxsp || !auxstack)) { rc = -ENOMEM; goto err_free_stack; } @@ -447,8 +457,8 @@ static int _uk_thread_struct_init_alloc(struct uk_thread *t, tlsp = ukarch_tls_tlsp(tls); } - _uk_thread_struct_init(t, (__uptr)auxstack, tlsp, !(!tlsp), ectx, name, - prio, priv, dtor); + _uk_thread_struct_init(t, auxsp, tlsp, !(!tlsp), ectx, name, prio, priv, + dtor); /* Set uk_thread fields related to stack and TLS */ if (stack) { @@ -456,9 +466,10 @@ static int _uk_thread_struct_init_alloc(struct uk_thread *t, t->_mem.stack_a = a_stack; } - if (auxstack) { - t->_mem.auxstack = auxstack; + if (auxsp && auxstack) { + t->_mem.auxstack = (void *)auxstack; t->_mem.auxstack_a = a_auxstack; + t->_mem.auxstack_len = auxstack_len; } if (tls) { @@ -510,9 +521,14 @@ void _uk_thread_struct_free_alloc(struct uk_thread *t) t->_mem.stack = NULL; } if (t->auxsp) { - uk_free(t->_mem.auxstack_a, t->_mem.auxstack); + ukplat_auxsp_free(t->_mem.auxstack_a, +#if CONFIG_LIBUKVMEM + uk_vas_get_active(), +#endif /* CONFIG_LIBUKVMEM */ + t->_mem.auxstack, t->_mem.auxstack_len); t->_mem.auxstack_a = NULL; t->_mem.auxstack = NULL; + t->_mem.auxstack_len = 0; } } @@ -1036,6 +1052,7 @@ void uk_thread_release(struct uk_thread *t) void *stack; void *auxstack; void *tls; + __sz auxstack_len; UK_ASSERT(t); UK_ASSERT(t != uk_thread_current()); @@ -1052,6 +1069,7 @@ void uk_thread_release(struct uk_thread *t) stack = t->_mem.stack; auxstack_a = t->_mem.auxstack_a; auxstack = t->_mem.auxstack; + auxstack_len = t->_mem.auxstack_len; tls_a = t->_mem.uktls_a; tls = t->_mem.uktls; @@ -1068,7 +1086,11 @@ void uk_thread_release(struct uk_thread *t) if (stack_a && stack) uk_free(stack_a, stack); if (auxstack_a && auxstack) - uk_free(auxstack_a, auxstack); + ukplat_auxsp_free(auxstack_a, +#if CONFIG_LIBUKVMEM + uk_vas_get_active(), +#endif /* CONFIG_LIBUKVMEM */ + auxstack, auxstack_len); if (a) uk_free(a, t); }