From 9ca1a0731f3074265bbbc0402b4021ba2685b994 Mon Sep 17 00:00:00 2001 From: Itamar Date: Sat, 10 Oct 2020 12:17:07 +0300 Subject: [PATCH] Kernel: Support TLS allocation from userspace This adds an allocate_tls syscall through which a userspace process can request the allocation of a TLS region with a given size. This will be used by the dynamic loader to allocate TLS for the main executable & its libraries. --- Kernel/API/Syscall.h | 3 ++- Kernel/Process.h | 1 + Kernel/Syscalls/mmap.cpp | 43 ++++++++++++++++++++++++++++++++++++++++ Libraries/LibC/mman.cpp | 10 ++++++++++ Libraries/LibC/mman.h | 1 + 5 files changed, 57 insertions(+), 1 deletion(-) diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index 897d05d64d0..0555851d7e0 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -194,7 +194,8 @@ namespace Kernel { S(sysconf) \ S(set_process_name) \ S(disown) \ - S(adjtime) + S(adjtime) \ + S(allocate_tls) namespace Syscall { diff --git a/Kernel/Process.h b/Kernel/Process.h index f21a79be016..3e36c61d0eb 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -372,6 +372,7 @@ public: int sys$recvfd(int sockfd); long sys$sysconf(int name); int sys$disown(ProcessID); + void* sys$allocate_tls(size_t); template int get_sock_or_peer_name(const Params&); diff --git a/Kernel/Syscalls/mmap.cpp b/Kernel/Syscalls/mmap.cpp index 74dbe31edf1..36aa2a1b670 100644 --- a/Kernel/Syscalls/mmap.cpp +++ b/Kernel/Syscalls/mmap.cpp @@ -24,6 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -417,4 +418,46 @@ int Process::sys$munmap(void* addr, size_t size) return -EINVAL; } +void* Process::sys$allocate_tls(size_t size) +{ + REQUIRE_PROMISE(stdio); + + dbg() << "allocate TLS: " << size; + + if (!size) + return (void*)-EINVAL; + + if (!m_master_tls_region.is_null()) + return (void*)-EEXIST; + + if (thread_count() != 1) + return (void*)-EFAULT; + + Thread* main_thread = nullptr; + for_each_thread([&main_thread](auto& thread) { + main_thread = &thread; + return IterationDecision::Break; + }); + ASSERT(main_thread); + + auto tls_region = allocate_region({}, size, String(), PROT_READ | PROT_WRITE); + if (!tls_region) + return (void*)-EFAULT; + + m_master_tls_region = tls_region->make_weak_ptr(); + dbg() << "master_tls_region: " << m_master_tls_region->vaddr(); + m_master_tls_size = size; + m_master_tls_alignment = PAGE_SIZE; + + auto tsr_result = main_thread->make_thread_specific_region({}); + if (tsr_result.is_error()) + return (void*)-EFAULT; + + auto& tls_descriptor = Processor::current().get_gdt_entry(GDT_SELECTOR_TLS); + tls_descriptor.set_base(main_thread->thread_specific_data().as_ptr()); + tls_descriptor.set_limit(main_thread->thread_specific_region_size()); + + return m_master_tls_region.unsafe_ptr()->vaddr().as_ptr(); +} + } diff --git a/Libraries/LibC/mman.cpp b/Libraries/LibC/mman.cpp index 5a0074fd68c..9dd97d6a1e0 100644 --- a/Libraries/LibC/mman.cpp +++ b/Libraries/LibC/mman.cpp @@ -87,4 +87,14 @@ int minherit(void* address, size_t size, int inherit) int rc = syscall(SC_minherit, address, size, inherit); __RETURN_WITH_ERRNO(rc, rc, -1); } + +void* allocate_tls(size_t size) +{ + int rc = syscall(SC_allocate_tls, size); + if (rc < 0 && -rc < EMAXERRNO) { + errno = -rc; + return MAP_FAILED; + } + return (void*)rc; +} } diff --git a/Libraries/LibC/mman.h b/Libraries/LibC/mman.h index 38c3069278c..1df98de8219 100644 --- a/Libraries/LibC/mman.h +++ b/Libraries/LibC/mman.h @@ -61,5 +61,6 @@ int mprotect(void*, size_t, int prot); int set_mmap_name(void*, size_t, const char*); int madvise(void*, size_t, int advice); int minherit(void*, size_t, int inherit); +void* allocate_tls(size_t); __END_DECLS