From 551d8169ea20686829f19a6f424c5e37cb82ca86 Mon Sep 17 00:00:00 2001 From: Dragos Iulian Argint Date: Mon, 15 Aug 2022 01:07:58 +0300 Subject: [PATCH] Add custom TLS related functions as glue code The functions related to the TLS layout (like copying content) are implemented in the unikraft core libraries. To use them, we need to add glue source code. Signed-off-by: Dragos Iulian Argint Reviewed-by: Florin Postolache Reviewed-by: Simon Kuenzer Reviewed-by: Cezar Craciunoiu Reviewed-by: Razvan Deaconescu Reviewed-by: Robert Kuban Approved-by: Simon Kuenzer Tested-by: Unikraft CI GitHub-Closes: #9 --- __uk_init_tls.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 __uk_init_tls.c diff --git a/__uk_init_tls.c b/__uk_init_tls.c new file mode 100644 index 0000000..1cf3dce --- /dev/null +++ b/__uk_init_tls.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Authors: Dragos Iulian Argint + * + * Copyright (c) 2022, University POLITEHNICA of Bucharest. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include "pthread_impl.h" +#include "libc.h" +#include "atomic.h" +#include "syscall.h" + +#include +#include + +/* + * This glue code source is meant to replace `__libc_start_main()` + * and tls related stuff. + * If the pthread API is used, musl will allocate the TLS and will + * provide a pointer to it in the `clone()` syscall. Musl will allocate + * in fact a contiguous region which will have the following layout (Please + * refer to the `pthread_create.c` file): + * map ----------------------------------------------------------------- + * ^ + * | + * | 4096 GUARD PAGE + * | + * v + * map + guard --------------------------------------------------------- + * ^ + * | + * | + * | STACK + * | + * | + * | + * v + * stack --------------------------------------------------------------- + * ^ ^ + * | | TLS SPACE + * | v + * new ->|------------------------------------------------ + * | ^ + * | | + * | | + * | | 280 pthread structure + * | | + * v v + * tsd ----------------------------------------------------------------- + * ^ + * | 1024 + * v + * map + size ---------------------------------------------------------- + */ + + +void *__uk_copy_tls(unsigned char *mem) +{ + pthread_t td; + void *tls_area; + + mem -= (uintptr_t)mem & (libc.tls_align-1); + tls_area = mem; + ukarch_tls_area_init(tls_area); + + td = (pthread_t) ukarch_tls_tlsp(tls_area); + td->dtv = td->dtv_copy = tls_area; + + return td; +} + +/* + * This function is only called for the main thread + */ +static int __uk_init_tp(void *p) +{ + pthread_t td = p; + + td->self = td; + /* + * Set the `$fs` register for the current thread. + * In the original code of musl this will use an `arch_prtcl` + * syscall to fill the `$fs` register. + */ + ukplat_tlsp_set((unsigned long) TP_ADJ(p)); + libc.can_do_threads = 1; + /* + * The original musl code will invoke here a `SYS_set_tid_address` + * syscall, to set the tid user space address in the Kernel. + * FIXME: Currently this does not return the tid assigned for the caller, + * it returns an error code (-95) because probably there is no tid assigned + * at this stage. It is not a really big problem right now. + */ + td->tid = uk_syscall_r_set_tid_address(&td->tid); + td->locale = &libc.global_locale; + td->robust_list.head = &td->robust_list.head; + return 0; +} + +/* + * This fucntion is only called for the main thread. + */ +static void __uk_init_tls(void *tls_area) +{ + libc.tls_size = ukarch_tls_area_size(); + libc.tls_align = ukarch_tls_area_align(); + + /* Failure to initialize thread pointer is always fatal. */ + if (__uk_init_tp(tls_area) < 0) + UK_CRASH("Failed to initialize the main thread\n"); +} + +static void __uk_init_libc(void) +{ + libc.auxv = 0; + __hwcap = 0; + __sysinfo = 0; + libc.page_size = __PAGE_SIZE; +} + +static const size_t __uk_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX; + +/* + * This callback will only be called for threads that are NOT + * created with the pthread API but we still want them to be + * compatible with Musl. + */ +int uk_thread_uktcb_init(struct uk_thread *thread, void *tcb) +{ + struct pthread *td = (struct pthread *) tcb; + + uk_pr_debug("%s uk_thread %p, tcb %p\n", __func__, thread, tcb); + + td->stack = thread->_mem.stack; + td->stack_size = __STACK_SIZE; + td->self = td; + td->tsd = (void *)uk_memalign( + uk_alloc_get_default(), + __PAGE_SIZE, + __uk_tsd_size); + td->locale = &libc.global_locale; + + return 0; +} + +/* This callback will only be called for threads that are NOT + * created with the pthread API + */ +void uk_thread_tcb_fini(struct uk_thread *thread, void *tcb) +{ + struct pthread *td = (struct pthread *) tcb; + + uk_pr_debug("%s uk_thread %p, tcb %p\n", __func__, thread, tcb); + uk_free(uk_alloc_get_default(), td->tsd); +} + +/* + * This callback is called for every thread, but we only use it + * to initialize the `libc` global variable and the main thread. + */ +void ukarch_tls_tcb_init(void *tcb) +{ + uk_pr_debug("%s tcb %p\n", __func__, tcb); + + /* + * The first thread (main) will fill the `libc` global variable. + * This includes `tls_size`, `tls_align`. After this the + * `__uk_init_tls()` function is called which will initialise + * the `struct pthread` structure for the main thread. + * After this sequence of calls `libc.can_do_threads` is set to 1. + */ + if (!libc.can_do_threads) { + __uk_init_libc(); + __uk_init_tls(tcb); + } +} -- 2.39.5