Index: sys/amd64/cloudabi64/cloudabi64_sysvec.c =================================================================== --- sys/amd64/cloudabi64/cloudabi64_sysvec.c +++ sys/amd64/cloudabi64/cloudabi64_sysvec.c @@ -27,6 +27,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include #include @@ -47,6 +48,45 @@ extern struct sysent cloudabi64_sysent[]; static int +cloudabi64_fixup_tcb(register_t **stack_base, struct image_params *imgp) +{ + int error; + register_t tcbptr; + + /* Place auxiliary vector and TCB on the stack. */ + error = cloudabi64_fixup(stack_base, imgp); + if (error != 0) + return (error); + + /* + * On x86-64, the TCB is referred to by %fs:0. Take some space + * from the top of the stack to store a single element array, + * containing a pointer to the TCB. %fs will point to this. + */ + tcbptr = (register_t)*stack_base; + return (copyout(&tcbptr, --*stack_base, sizeof(tcbptr))); +} + +static void +cloudabi64_proc_setregs(struct thread *td, struct image_params *imgp, + unsigned long stack) +{ + struct trapframe *regs; + + exec_setregs(td, imgp, stack); + + /* + * The stack now contains a pointer to the TCB, the TCB itself, + * and the auxiliary vector. Let %rdx point to the auxiliary + * vector, and set %fs to the pointer to the TCB. + */ + regs = td->td_frame; + regs->tf_rdi = stack + sizeof(register_t) + + roundup(sizeof(cloudabi64_tcb_t), sizeof(register_t)); + (void)cpu_set_user_tls(td, (void *)stack); +} + +static int cloudabi64_fetch_syscall_args(struct thread *td, struct syscall_args *sa) { struct trapframe *frame = td->td_frame; @@ -109,16 +149,29 @@ frame->tf_rdx = td->td_tid; } -void +int cloudabi64_thread_setregs(struct thread *td, - const cloudabi64_threadattr_t *attr) + const cloudabi64_threadattr_t *attr, uint64_t tcb) { struct trapframe *frame; stack_t stack; + uint64_t tcbptr; + int error; + + /* + * On x86-64, the TCB is referred to by %fs:0. Take some space + * from the top of the stack to store a single element array, + * containing a pointer to the TCB. %fs will point to this. + */ + tcbptr = rounddown(attr->stack + attr->stack_size - sizeof(tcbptr), + _Alignof(tcbptr)); + error = copyout(&tcb, (void *)tcbptr, sizeof(tcb)); + if (error != 0) + return (error); /* Perform standard register initialization. */ stack.ss_sp = (void *)attr->stack; - stack.ss_size = attr->stack_size; + stack.ss_size = tcbptr - attr->stack; cpu_set_upcall_kse(td, (void *)attr->entry_point, NULL, &stack); /* @@ -129,12 +182,14 @@ frame = td->td_frame; frame->tf_rdi = td->td_tid; frame->tf_rsi = attr->argument; + + return (cpu_set_user_tls(td, (void *)tcbptr)); } static struct sysentvec cloudabi64_elf_sysvec = { .sv_size = CLOUDABI64_SYS_MAXSYSCALL, .sv_table = cloudabi64_sysent, - .sv_fixup = cloudabi64_fixup, + .sv_fixup = cloudabi64_fixup_tcb, .sv_name = "CloudABI ELF64", .sv_coredump = elf64_coredump, .sv_pagesize = PAGE_SIZE, @@ -143,6 +198,7 @@ .sv_usrstack = USRSTACK, .sv_stackprot = VM_PROT_READ | VM_PROT_WRITE, .sv_copyout_strings = cloudabi64_copyout_strings, + .sv_setregs = cloudabi64_proc_setregs, .sv_flags = SV_ABI_CLOUDABI | SV_CAPSICUM | SV_LP64, .sv_set_syscall_retval = cloudabi64_set_syscall_retval, .sv_fetch_syscall_args = cloudabi64_fetch_syscall_args, Index: sys/arm64/cloudabi64/cloudabi64_sysvec.c =================================================================== --- sys/arm64/cloudabi64/cloudabi64_sysvec.c +++ sys/arm64/cloudabi64/cloudabi64_sysvec.c @@ -27,6 +27,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include #include @@ -46,6 +47,25 @@ extern const char *cloudabi64_syscallnames[]; extern struct sysent cloudabi64_sysent[]; +static void +cloudabi64_proc_setregs(struct thread *td, struct image_params *imgp, + unsigned long stack) +{ + struct trapframe *regs; + + exec_setregs(td, imgp, stack); + + /* + * The stack now contains a pointer to the TCB and the auxiliary + * vector. Let x0 point to the auxiliary vector, and set + * tpidr_el0 to the TCB. + */ + regs = td->td_frame; + regs->tf_x[0] = td->td_retval[0] = + stack + roundup(sizeof(cloudabi64_tcb_t), sizeof(register_t)); + (void)cpu_set_user_tls(td, (void *)stack); +} + static int cloudabi64_fetch_syscall_args(struct thread *td, struct syscall_args *sa) { @@ -110,9 +130,9 @@ } } -void +int cloudabi64_thread_setregs(struct thread *td, - const cloudabi64_threadattr_t *attr) + const cloudabi64_threadattr_t *attr, uint64_t tcb) { struct trapframe *frame; stack_t stack; @@ -130,6 +150,9 @@ frame = td->td_frame; frame->tf_x[0] = td->td_tid; frame->tf_x[1] = attr->argument; + + /* Set up TLS. */ + return (cpu_set_user_tls(td, (void *)tcb)); } static struct sysentvec cloudabi64_elf_sysvec = { @@ -144,6 +167,7 @@ .sv_usrstack = USRSTACK, .sv_stackprot = VM_PROT_READ | VM_PROT_WRITE, .sv_copyout_strings = cloudabi64_copyout_strings, + .sv_setregs = cloudabi64_proc_setregs, .sv_flags = SV_ABI_CLOUDABI | SV_CAPSICUM | SV_LP64, .sv_set_syscall_retval = cloudabi64_set_syscall_retval, .sv_fetch_syscall_args = cloudabi64_fetch_syscall_args, Index: sys/compat/cloudabi64/cloudabi64_module.c =================================================================== --- sys/compat/cloudabi64/cloudabi64_module.c +++ sys/compat/cloudabi64/cloudabi64_module.c @@ -112,7 +112,13 @@ { .a_type = CLOUDABI_AT_NULL }, }; *stack_base -= howmany(sizeof(auxv), sizeof(register_t)); - return (copyout(auxv, *stack_base, sizeof(auxv))); + error = copyout(auxv, *stack_base, sizeof(auxv)); + if (error != 0) + return (error); + + /* Reserve space for storing the TCB. */ + *stack_base -= howmany(sizeof(cloudabi64_tcb_t), sizeof(register_t)); + return (0); } static int Index: sys/compat/cloudabi64/cloudabi64_thread.c =================================================================== --- sys/compat/cloudabi64/cloudabi64_thread.c +++ sys/compat/cloudabi64/cloudabi64_thread.c @@ -37,6 +37,7 @@ struct thread_create_args { cloudabi64_threadattr_t attr; + uint64_t tcb; lwpid_t tid; }; @@ -49,8 +50,7 @@ args->tid = td->td_tid; /* Set up initial register contents. */ - cloudabi64_thread_setregs(td, &args->attr); - return (0); + return (cloudabi64_thread_setregs(td, &args->attr, args->tcb)); } int @@ -63,6 +63,12 @@ error = copyin(uap->attr, &args.attr, sizeof(args.attr)); if (error != 0) return (error); + + /* Remove some space on the top of the stack for the TCB. */ + args.tcb = rounddown(args.attr.stack + args.attr.stack_size - + sizeof(cloudabi64_tcb_t), _Alignof(cloudabi64_tcb_t)); + args.attr.stack_size = args.tcb - args.attr.stack; + error = thread_create(td, NULL, initialize_thread, &args); if (error != 0) return (error); Index: sys/compat/cloudabi64/cloudabi64_util.h =================================================================== --- sys/compat/cloudabi64/cloudabi64_util.h +++ sys/compat/cloudabi64/cloudabi64_util.h @@ -42,7 +42,7 @@ register_t *cloudabi64_copyout_strings(struct image_params *); int cloudabi64_fixup(register_t **, struct image_params *); -void cloudabi64_thread_setregs(struct thread *, - const cloudabi64_threadattr_t *); +int cloudabi64_thread_setregs(struct thread *, + const cloudabi64_threadattr_t *, uint64_t); #endif Index: sys/contrib/cloudabi/cloudabi64_types.h =================================================================== --- sys/contrib/cloudabi/cloudabi64_types.h +++ sys/contrib/cloudabi/cloudabi64_types.h @@ -192,6 +192,13 @@ _Static_assert(sizeof(cloudabi64_subscription_t) == 56, "Incorrect layout"); _Static_assert(_Alignof(cloudabi64_subscription_t) == 8, "Incorrect layout"); +typedef struct { + _Alignas(8) uint64_t parent; +} cloudabi64_tcb_t; +_Static_assert(offsetof(cloudabi64_tcb_t, parent) == 0, "Incorrect layout"); +_Static_assert(sizeof(cloudabi64_tcb_t) == 8, "Incorrect layout"); +_Static_assert(_Alignof(cloudabi64_tcb_t) == 8, "Incorrect layout"); + typedef void cloudabi64_threadentry_t(cloudabi_tid_t tid, uint64_t aux); typedef struct {