12bc99445SSchrodinger ZHU Yifan //===-- Implementation of tls for riscv -----------------------------------===// 22bc99445SSchrodinger ZHU Yifan // 32bc99445SSchrodinger ZHU Yifan // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42bc99445SSchrodinger ZHU Yifan // See https://llvm.org/LICENSE.txt for license information. 52bc99445SSchrodinger ZHU Yifan // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 62bc99445SSchrodinger ZHU Yifan // 72bc99445SSchrodinger ZHU Yifan //===----------------------------------------------------------------------===// 82bc99445SSchrodinger ZHU Yifan 92bc99445SSchrodinger ZHU Yifan #include "src/__support/OSUtil/syscall.h" 10*5ff3ff33SPetr Hosek #include "src/__support/macros/config.h" 112bc99445SSchrodinger ZHU Yifan #include "src/__support/threads/thread.h" 122bc99445SSchrodinger ZHU Yifan #include "src/string/memory_utils/inline_memcpy.h" 132bc99445SSchrodinger ZHU Yifan #include "startup/linux/do_start.h" 142bc99445SSchrodinger ZHU Yifan 152bc99445SSchrodinger ZHU Yifan #include <sys/mman.h> 162bc99445SSchrodinger ZHU Yifan #include <sys/syscall.h> 172bc99445SSchrodinger ZHU Yifan 18*5ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL { 192bc99445SSchrodinger ZHU Yifan 202bc99445SSchrodinger ZHU Yifan #ifdef SYS_mmap2 212bc99445SSchrodinger ZHU Yifan static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap2; 222bc99445SSchrodinger ZHU Yifan #elif SYS_mmap 232bc99445SSchrodinger ZHU Yifan static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap; 242bc99445SSchrodinger ZHU Yifan #else 252bc99445SSchrodinger ZHU Yifan #error "mmap and mmap2 syscalls not available." 262bc99445SSchrodinger ZHU Yifan #endif 272bc99445SSchrodinger ZHU Yifan 282bc99445SSchrodinger ZHU Yifan void init_tls(TLSDescriptor &tls_descriptor) { 292bc99445SSchrodinger ZHU Yifan if (app.tls.size == 0) { 302bc99445SSchrodinger ZHU Yifan tls_descriptor.size = 0; 312bc99445SSchrodinger ZHU Yifan tls_descriptor.tp = 0; 322bc99445SSchrodinger ZHU Yifan return; 332bc99445SSchrodinger ZHU Yifan } 342bc99445SSchrodinger ZHU Yifan 352bc99445SSchrodinger ZHU Yifan // riscv64 follows the variant 1 TLS layout: 362bc99445SSchrodinger ZHU Yifan const uintptr_t size_of_pointers = 2 * sizeof(uintptr_t); 372bc99445SSchrodinger ZHU Yifan uintptr_t padding = 0; 382bc99445SSchrodinger ZHU Yifan const uintptr_t ALIGNMENT_MASK = app.tls.align - 1; 392bc99445SSchrodinger ZHU Yifan uintptr_t diff = size_of_pointers & ALIGNMENT_MASK; 402bc99445SSchrodinger ZHU Yifan if (diff != 0) 412bc99445SSchrodinger ZHU Yifan padding += (ALIGNMENT_MASK - diff) + 1; 422bc99445SSchrodinger ZHU Yifan 432bc99445SSchrodinger ZHU Yifan uintptr_t alloc_size = size_of_pointers + padding + app.tls.size; 442bc99445SSchrodinger ZHU Yifan 452bc99445SSchrodinger ZHU Yifan // We cannot call the mmap function here as the functions set errno on 462bc99445SSchrodinger ZHU Yifan // failure. Since errno is implemented via a thread local variable, we cannot 472bc99445SSchrodinger ZHU Yifan // use errno before TLS is setup. 482bc99445SSchrodinger ZHU Yifan long mmap_ret_val = syscall_impl<long>(MMAP_SYSCALL_NUMBER, nullptr, 492bc99445SSchrodinger ZHU Yifan alloc_size, PROT_READ | PROT_WRITE, 502bc99445SSchrodinger ZHU Yifan MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 512bc99445SSchrodinger ZHU Yifan // We cannot check the return value with MAP_FAILED as that is the return 522bc99445SSchrodinger ZHU Yifan // of the mmap function and not the mmap syscall. 532bc99445SSchrodinger ZHU Yifan if (mmap_ret_val < 0 && static_cast<uintptr_t>(mmap_ret_val) > -app.page_size) 542bc99445SSchrodinger ZHU Yifan syscall_impl<long>(SYS_exit, 1); 552bc99445SSchrodinger ZHU Yifan uintptr_t thread_ptr = uintptr_t(reinterpret_cast<uintptr_t *>(mmap_ret_val)); 562bc99445SSchrodinger ZHU Yifan uintptr_t tls_addr = thread_ptr + size_of_pointers + padding; 572bc99445SSchrodinger ZHU Yifan inline_memcpy(reinterpret_cast<char *>(tls_addr), 582bc99445SSchrodinger ZHU Yifan reinterpret_cast<const char *>(app.tls.address), 592bc99445SSchrodinger ZHU Yifan app.tls.init_size); 602bc99445SSchrodinger ZHU Yifan tls_descriptor.size = alloc_size; 612bc99445SSchrodinger ZHU Yifan tls_descriptor.addr = thread_ptr; 622bc99445SSchrodinger ZHU Yifan tls_descriptor.tp = tls_addr; 632bc99445SSchrodinger ZHU Yifan } 642bc99445SSchrodinger ZHU Yifan 652bc99445SSchrodinger ZHU Yifan void cleanup_tls(uintptr_t addr, uintptr_t size) { 662bc99445SSchrodinger ZHU Yifan if (size == 0) 672bc99445SSchrodinger ZHU Yifan return; 682bc99445SSchrodinger ZHU Yifan syscall_impl<long>(SYS_munmap, addr, size); 692bc99445SSchrodinger ZHU Yifan } 702bc99445SSchrodinger ZHU Yifan 712bc99445SSchrodinger ZHU Yifan bool set_thread_ptr(uintptr_t val) { 722bc99445SSchrodinger ZHU Yifan LIBC_INLINE_ASM("mv tp, %0\n\t" : : "r"(val)); 732bc99445SSchrodinger ZHU Yifan return true; 742bc99445SSchrodinger ZHU Yifan } 75*5ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL 76