xref: /llvm-project/libc/startup/linux/riscv/tls.cpp (revision 5ff3ff33ff930e4ec49da7910612d8a41eb068cb)
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