struct ukarch_ectx *ectx; /**< Extended context (FPU, VPU, ...) */
uintptr_t tlsp; /**< Current active TLS pointer */
__uptr uktlsp; /**< Unikraft TLS pointer */
+ __uptr auxsp; /**< Unikraft Auxiliary Stack Pointer */
UK_TAILQ_ENTRY(struct uk_thread) queue;
uint32_t flags;
struct uk_alloc *stack_a;
void *uktls;
struct uk_alloc *uktls_a;
+ void *auxstack;
+ struct uk_alloc *auxstack_a;
} _mem; /**< Associated allocs (internal!) */
uk_thread_gc_t _gc_fn; /**< Extra gc function (internal!) */
void *_gc_argp; /**< Argument for gc fn (internal!) */
* UK_THREADF_RUNNABLE is set.
* @param sp
* Stack pointer
+ * @param auxsp
+ * Auxiliary stack pointer
* @param tlsp
* Architecture pointer to TLS. If set to NULL, the thread cannot
* access thread-local variables.
int uk_thread_init_bare(struct uk_thread *t,
uintptr_t ip,
uintptr_t sp,
+ uintptr_t auxsp,
uintptr_t tlsp,
bool is_uktls,
struct ukarch_ectx *ectx,
* Thread entry function (required)
* @param sp
* Architecture stack pointer (stack is required)
+ * @param auxsp
+ * Auxiliary stack pointer
* @param tlsp
* Architecture pointer to TLS. If set to NULL, the thread cannot
* access thread-local variables.
int uk_thread_init_bare_fn0(struct uk_thread *t,
uk_thread_fn0_t fn,
uintptr_t sp,
+ uintptr_t auxsp,
uintptr_t tlsp,
bool is_uktls,
struct ukarch_ectx *ectx,
uk_thread_fn1_t fn,
void *argp,
uintptr_t sp,
+ uintptr_t auxsp,
uintptr_t tlsp,
bool is_uktls,
struct ukarch_ectx *ectx,
uk_thread_fn2_t fn,
void *argp0, void *argp1,
uintptr_t sp,
+ uintptr_t auxsp,
uintptr_t tlsp,
bool is_uktls,
struct ukarch_ectx *ectx,
* @param stack_len
* Size of the thread stack. If set to 0, a default stack size is used
* for the allocation.
+ * @param a_auxstack
+ * Reference to an allocator for allocating an auxiliary stack
+ * @param auxstack_len
+ * Size of the thread auxiliary stack. If set to 0, a default stack size is
+ * used for the allocation.
* @param a_uktls
* Reference to an allocator for allocating (Unikraft) thread local storage.
* In case `custom_ectx` is not set, space for extended CPU context state
uk_thread_fn0_t fn,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool custom_ectx,
struct ukarch_ectx *ectx,
void *argp,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool custom_ectx,
struct ukarch_ectx *ectx,
void *argp0, void *argp1,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool custom_ectx,
struct ukarch_ectx *ectx,
* `UK_THREADF_RUNNABLE` is set.
* @param sp
* Stack pointer
+ * @param auxsp
+ * Auxiliary stack pointer
* @param tlsp
* Architecture pointer to TLS. If set to NULL, the thread cannot
* access thread-local variables
struct uk_thread *uk_thread_create_bare(struct uk_alloc *a,
uintptr_t ip,
uintptr_t sp,
+ uintptr_t auxsp,
uintptr_t tlsp,
bool is_uktls,
bool no_ectx,
* @param stack_len
* Size of the thread stack. If set to 0, a default stack size is used
* for the stack allocation.
+ * @param a_auxstack
+ * Reference to an allocator for allocating an auxiliary stack
+ * @param auxstack_len
+ * Size of the thread auxiliary stack. If set to 0, a default stack size is
+ * used for the allocation.
* @param a_uktls
* Reference to an allocator for allocating (Unikraft) thread local storage.
* If `NULL` is passed, a thread without TLS is allocated.
struct uk_thread *uk_thread_create_container(struct uk_alloc *a,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool no_ectx,
const char *name,
* Reference t o an allocator (required)
* @param sp
* Stack pointer
+ * @param auxsp
+ * Auxiliary stack pointer
* @param tlsp
* Architecture pointer to TLS. If set to NULL, the thread cannot
* access thread-local variables
*/
struct uk_thread *uk_thread_create_container2(struct uk_alloc *a,
uintptr_t sp,
+ uintptr_t auxsp,
uintptr_t tlsp,
bool is_uktls,
bool no_ectx,
* @param stack_len
* Size of the thread stack. If set to 0, a default stack size is used
* for the stack allocation.
+ * @param a_auxstack
+ * Reference to an allocator for allocating an auxiliary stack
+ * @param auxstack_len
+ * Size of the thread auxiliary stack. If set to 0, a default stack size is
+ * used for the allocation.
* @param a_uktls
* Reference to an allocator for allocating (Unikraft) thread local storage.
* If `NULL` is passed, a thread without TLS is allocated.
uk_thread_fn0_t fn,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool no_ectx,
const char *name,
uk_thread_fn1_t fn, void *argp,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool no_ectx,
const char *name,
void *argp0, void *argp1,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool no_ectx,
const char *name,
#include <uk/print.h>
#include <uk/assert.h>
#include <uk/arch/tls.h>
+#include <uk/plat/memory.h>
#if CONFIG_LIBUKSCHED_TCB_INIT && !CONFIG_UKARCH_TLS_HAVE_TCB
#error CONFIG_LIBUKSCHED_TCB_INIT requires that a TLS contains reserved space for a TCB
}
static void _uk_thread_struct_init(struct uk_thread *t,
+ uintptr_t auxsp,
uintptr_t tlsp,
bool is_uktls,
struct ukarch_ectx *ectx,
t->dtor = dtor;
t->exec_time = 0;
+ if (!auxsp)
+ auxsp = ukplat_auxsp_alloc(uk_alloc_get_default(),
+#if CONFIG_LIBUKVMEM
+ uk_vas_get_active(),
+#endif /* CONFIG_LIBUKVMEM */
+ 0); /* Default auxsp size */
+
+ t->auxsp = auxsp;
+
if (tlsp && is_uktls) {
t->flags |= UK_THREADF_UKTLS;
t->uktlsp = tlsp;
int uk_thread_init_bare(struct uk_thread *t,
uintptr_t ip,
uintptr_t sp,
+ uintptr_t auxsp,
uintptr_t tlsp,
bool is_uktls,
struct ukarch_ectx *ectx,
UK_ASSERT(t);
UK_ASSERT(t != uk_thread_current());
- _uk_thread_struct_init(t, tlsp, is_uktls, ectx, name, priv, dtor);
+ _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv,
+ dtor);
ukarch_ctx_init_bare(&t->ctx, sp, ip);
if (ip)
int uk_thread_init_bare_fn0(struct uk_thread *t,
uk_thread_fn0_t fn,
uintptr_t sp,
+ uintptr_t auxsp,
uintptr_t tlsp,
bool is_uktls,
struct ukarch_ectx *ectx,
UK_ASSERT(sp); /* stack pointer is required for ctx_entry */
UK_ASSERT(fn);
- _uk_thread_struct_init(t, tlsp, is_uktls, ectx, name, priv, dtor);
+ _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv,
+ dtor);
ukarch_ctx_init_entry0(&t->ctx, sp, 0,
(ukarch_ctx_entry0) fn);
uk_thread_set_runnable(t);
uk_thread_fn1_t fn,
void *argp,
uintptr_t sp,
+ uintptr_t auxsp,
uintptr_t tlsp,
bool is_uktls,
struct ukarch_ectx *ectx,
UK_ASSERT(sp); /* stack pointer is required for ctx_entry */
UK_ASSERT(fn);
- _uk_thread_struct_init(t, tlsp, is_uktls, ectx, name, priv, dtor);
+ _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv,
+ dtor);
ukarch_ctx_init_entry1(&t->ctx, sp, 0,
(ukarch_ctx_entry1) fn,
(long) argp);
uk_thread_fn2_t fn,
void *argp0, void *argp1,
uintptr_t sp,
+ uintptr_t auxsp,
uintptr_t tlsp,
bool is_uktls,
struct ukarch_ectx *ectx,
UK_ASSERT(sp); /* stack pointer is required for ctx_entry */
UK_ASSERT(fn);
- _uk_thread_struct_init(t, tlsp, is_uktls, ectx, name, priv, dtor);
+ _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv,
+ dtor);
ukarch_ctx_init_entry2(&t->ctx, sp, 0,
(ukarch_ctx_entry2) fn,
(long) argp0, (long) argp1);
static int _uk_thread_struct_init_alloc(struct uk_thread *t,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool custom_ectx,
struct ukarch_ectx *ectx,
{
void *stack = NULL;
void *tls = NULL;
+ void *auxstack = 0x0;
uintptr_t tlsp = 0x0;
int rc;
}
}
+ if (a_auxstack && auxstack_len) {
+ auxstack = (void *)ukplat_auxsp_alloc(a_auxstack,
+#if CONFIG_LIBUKVMEM
+ uk_vas_get_active(),
+#endif /* CONFIG_LIBUKVMEM */
+ auxstack_len);
+ if (unlikely(!auxstack)) {
+ rc = -ENOMEM;
+ goto err_free_stack;
+ }
+ }
+
if (a_uktls) {
if (!custom_ectx) {
/* Allocate TLS and ectx together */
tlsp = ukarch_tls_tlsp(tls);
}
- _uk_thread_struct_init(t, tlsp, !(!tlsp), ectx, name, priv, dtor);
+ _uk_thread_struct_init(t, (__uptr)auxstack, tlsp, !(!tlsp), ectx,
+ name, priv,
+ dtor);
/* Set uk_thread fields related to stack and TLS */
if (stack) {
t->_mem.stack_a = a_stack;
}
+ if (auxstack) {
+ t->_mem.auxstack = auxstack;
+ t->_mem.auxstack_a = a_auxstack;
+ }
+
if (tls) {
ukarch_tls_area_init(tls);
t->_mem.stack_a = NULL;
t->_mem.stack = NULL;
}
+ if (t->auxsp) {
+ uk_free(t->_mem.auxstack_a, t->_mem.auxstack);
+ t->_mem.auxstack_a = NULL;
+ t->_mem.auxstack = NULL;
+ }
}
int uk_thread_init_fn0(struct uk_thread *t,
uk_thread_fn0_t fn,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool custom_ectx,
struct ukarch_ectx *ectx,
UK_ASSERT(t != uk_thread_current());
UK_ASSERT(fn);
- ret = _uk_thread_struct_init_alloc(t, a_stack, stack_len,
+ ret = _uk_thread_struct_init_alloc(t,
+ a_stack, stack_len,
+ a_auxstack, auxstack_len,
a_uktls, custom_ectx, ectx, name,
priv, dtor);
if (ret < 0)
void *argp,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool custom_ectx,
struct ukarch_ectx *ectx,
UK_ASSERT(t != uk_thread_current());
UK_ASSERT(fn);
- ret = _uk_thread_struct_init_alloc(t, a_stack, stack_len,
+ ret = _uk_thread_struct_init_alloc(t,
+ a_stack, stack_len,
+ a_auxstack, auxstack_len,
a_uktls, custom_ectx, ectx, name,
priv, dtor);
if (ret < 0)
void *argp0, void *argp1,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool custom_ectx,
struct ukarch_ectx *ectx,
UK_ASSERT(t != uk_thread_current());
UK_ASSERT(fn);
- ret = _uk_thread_struct_init_alloc(t, a_stack, stack_len,
+ ret = _uk_thread_struct_init_alloc(t,
+ a_stack, stack_len,
+ a_auxstack, auxstack_len,
a_uktls, custom_ectx, ectx, name,
priv, dtor);
if (ret < 0)
struct uk_thread *uk_thread_create_bare(struct uk_alloc *a,
uintptr_t ip,
uintptr_t sp,
+ uintptr_t auxsp,
uintptr_t tlsp,
bool is_uktls,
bool no_ectx,
if (!t)
return NULL;
- uk_thread_init_bare(t, ip, sp, tlsp, is_uktls,
+ uk_thread_init_bare(t, ip, sp, auxsp, tlsp, is_uktls,
(struct ukarch_ectx *) ALIGN_UP((uintptr_t) t
+ sizeof(*t),
ukarch_ectx_align()),
struct uk_thread *uk_thread_create_container(struct uk_alloc *a,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool no_ectx,
const char *name,
ukarch_ectx_align());
stack_len = (!!stack_len) ? stack_len : STACK_SIZE;
+ auxstack_len = (!!auxstack_len) ? auxstack_len :
+ CONFIG_UKPLAT_AUXSP_SIZE;
if (_uk_thread_struct_init_alloc(t,
a_stack, stack_len,
+ a_auxstack, auxstack_len,
a_uktls,
!(!ectx),
ectx,
*/
struct uk_thread *uk_thread_create_container2(struct uk_alloc *a,
uintptr_t sp,
+ uintptr_t auxsp,
uintptr_t tlsp,
bool is_uktls,
bool no_ectx,
+ sizeof(*t),
ukarch_ectx_align());
- _uk_thread_struct_init(t, tlsp, is_uktls, ectx, name, priv, dtor);
+ _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv,
+ dtor);
t->_mem.t_a = a;
/* Minimal context initialization where the stack pointer
uk_thread_fn0_t fn,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool no_ectx,
const char *name,
t = uk_thread_create_container(a,
a_stack, stack_len,
+ a_auxstack, auxstack_len,
a_uktls,
no_ectx, name, priv, dtor);
if (!t)
void *argp,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool no_ectx,
const char *name,
t = uk_thread_create_container(a,
a_stack, stack_len,
+ a_auxstack, auxstack_len,
a_uktls,
no_ectx, name, priv, dtor);
if (!t)
void *argp0, void *argp1,
struct uk_alloc *a_stack,
size_t stack_len,
+ struct uk_alloc *a_auxstack,
+ size_t auxstack_len,
struct uk_alloc *a_uktls,
bool no_ectx,
const char *name,
t = uk_thread_create_container(a,
a_stack, stack_len,
+ a_auxstack, auxstack_len,
a_uktls,
no_ectx, name, priv, dtor);
if (!t)
{
struct uk_alloc *a;
struct uk_alloc *stack_a;
+ struct uk_alloc *auxstack_a;
struct uk_alloc *tls_a;
void *stack;
+ void *auxstack;
void *tls;
UK_ASSERT(t);
*/
a = t->_mem.t_a;
stack_a = t->_mem.stack_a;
- stack = t->_mem.stack;
- tls_a = t->_mem.uktls_a;
- tls = t->_mem.uktls;
+ stack = t->_mem.stack;
+ auxstack_a = t->_mem.auxstack_a;
+ auxstack = t->_mem.auxstack;
+ tls_a = t->_mem.uktls_a;
+ tls = t->_mem.uktls;
#if CONFIG_LIBUKSCHED_TCB_INIT
if (tls_a && tls)
uk_free(tls_a, tls);
if (stack_a && stack)
uk_free(stack_a, stack);
+ if (auxstack_a && auxstack)
+ uk_free(auxstack_a, auxstack);
if (a)
uk_free(a, t);
}