From 106b52a55cb197a5796f805a9e6d04f93a4ecaf8 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Wed, 23 Oct 2024 19:39:54 -0700 Subject: [PATCH] kernel: Fix new pthreads code on macOS. --- src/core/libraries/kernel/threads.h | 1 + .../libraries/kernel/threads/event_flag.cpp | 1 + src/core/libraries/kernel/threads/mutex.cpp | 1 + src/core/libraries/kernel/threads/pthread.h | 1 + .../libraries/kernel/threads/semaphore.cpp | 1 + src/core/libraries/kernel/time.cpp | 3 + src/core/libraries/kernel/time.h | 3 +- src/core/libraries/network/net_ctl_obj.cpp | 1 + src/core/tls.cpp | 65 +++++++++++-------- 9 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/core/libraries/kernel/threads.h b/src/core/libraries/kernel/threads.h index 4ad9644eec..a022b3a012 100644 --- a/src/core/libraries/kernel/threads.h +++ b/src/core/libraries/kernel/threads.h @@ -4,6 +4,7 @@ #pragma once #include +#include "common/polyfill_thread.h" #include "core/libraries/kernel/threads/pthread.h" namespace Core::Loader { diff --git a/src/core/libraries/kernel/threads/event_flag.cpp b/src/core/libraries/kernel/threads/event_flag.cpp index 5b17a4104d..134bd54911 100644 --- a/src/core/libraries/kernel/threads/event_flag.cpp +++ b/src/core/libraries/kernel/threads/event_flag.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "common/assert.h" #include "common/logging/log.h" diff --git a/src/core/libraries/kernel/threads/mutex.cpp b/src/core/libraries/kernel/threads/mutex.cpp index 884e39100f..e5563742e8 100644 --- a/src/core/libraries/kernel/threads/mutex.cpp +++ b/src/core/libraries/kernel/threads/mutex.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include "common/assert.h" #include "common/scope_exit.h" #include "common/types.h" diff --git a/src/core/libraries/kernel/threads/pthread.h b/src/core/libraries/kernel/threads/pthread.h index 323c288bd0..6fa78062e6 100644 --- a/src/core/libraries/kernel/threads/pthread.h +++ b/src/core/libraries/kernel/threads/pthread.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/src/core/libraries/kernel/threads/semaphore.cpp b/src/core/libraries/kernel/threads/semaphore.cpp index 33414eb5cb..2ce51da1e6 100644 --- a/src/core/libraries/kernel/threads/semaphore.cpp +++ b/src/core/libraries/kernel/threads/semaphore.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "common/assert.h" #include "common/logging/log.h" #include "core/libraries/error_codes.h" diff --git a/src/core/libraries/kernel/time.cpp b/src/core/libraries/kernel/time.cpp index 4a4407f857..021fb929c0 100644 --- a/src/core/libraries/kernel/time.cpp +++ b/src/core/libraries/kernel/time.cpp @@ -16,6 +16,9 @@ #include "common/ntapi.h" #else +#if __APPLE__ +#include +#endif #include #include #include diff --git a/src/core/libraries/kernel/time.h b/src/core/libraries/kernel/time.h index 84f68c85f6..508ef21524 100644 --- a/src/core/libraries/kernel/time.h +++ b/src/core/libraries/kernel/time.h @@ -33,7 +33,8 @@ struct OrbisKernelTimespec { std::chrono::system_clock::time_point TimePoint() const noexcept { using namespace std::chrono; - const auto duration = seconds{tv_sec} + nanoseconds{tv_nsec}; + const auto duration = + duration_cast(seconds{tv_sec} + nanoseconds{tv_nsec}); return system_clock::time_point{duration}; } }; diff --git a/src/core/libraries/network/net_ctl_obj.cpp b/src/core/libraries/network/net_ctl_obj.cpp index 8d1c7ad9d5..ad944cd9c4 100644 --- a/src/core/libraries/network/net_ctl_obj.cpp +++ b/src/core/libraries/network/net_ctl_obj.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include "core/libraries/network/net_ctl_codes.h" #include "core/libraries/network/net_ctl_obj.h" #include "core/tls.h" diff --git a/src/core/tls.cpp b/src/core/tls.cpp index 7f556b3a15..f5f997f032 100644 --- a/src/core/tls.cpp +++ b/src/core/tls.cpp @@ -54,8 +54,13 @@ Tcb* GetTcbBase() { // Reserve space in the 32-bit address range for allocating TCB pages. asm(".zerofill TCB_SPACE,TCB_SPACE,__guest_system,0x3FC000"); -static constexpr u64 ldt_region_base = 0x4000; -static constexpr u64 ldt_region_size = 0x3FC000; +struct LdtPage { + void* tcb; + u16 index; +}; + +static constexpr uintptr_t ldt_region_base = 0x4000; +static constexpr size_t ldt_region_size = 0x3FC000; static constexpr u16 ldt_block_size = 0x1000; static constexpr u16 ldt_index_base = 8; static constexpr u16 ldt_index_total = (ldt_region_size - ldt_region_base) / ldt_block_size; @@ -63,11 +68,13 @@ static constexpr u16 ldt_index_total = (ldt_region_size - ldt_region_base) / ldt static boost::icl::interval_set free_ldts{}; static std::mutex free_ldts_lock; static std::once_flag ldt_region_init_flag; +static pthread_key_t ldt_page_slot = 0; + +static void FreeLdtPage(void* raw) { + const auto* ldt_page = static_cast(raw); -static u16 GetLdtIndex() { - sel_t selector; - asm volatile("mov %%fs, %0" : "=r"(selector)); - return selector.index; + std::unique_lock lock{free_ldts_lock}; + free_ldts += ldt_page->index; } static void InitLdtRegion() { @@ -78,11 +85,20 @@ static void InitLdtRegion() { free_ldts += boost::icl::interval::right_open(ldt_index_base, ldt_index_base + ldt_index_total); + ASSERT_MSG(pthread_key_create(&ldt_page_slot, FreeLdtPage) == 0, + "Failed to create LDT index thread key: {}", errno); } -static void** SetupThreadLdt() { +void SetTcbBase(void* image_address) { std::call_once(ldt_region_init_flag, InitLdtRegion); + auto* ldt_page = static_cast(pthread_getspecific(ldt_page_slot)); + if (ldt_page != nullptr) { + // Update TCB pointer in existing page. + ldt_page->tcb = image_address; + return; + } + // Allocate a new LDT index for the current thread. u16 ldt_index; { @@ -91,10 +107,12 @@ static void** SetupThreadLdt() { ldt_index = first(*free_ldts.begin()); free_ldts -= ldt_index; } - const u64 addr = ldt_region_base + (ldt_index - ldt_index_base) * ldt_block_size; + + const uintptr_t addr = ldt_region_base + (ldt_index - ldt_index_base) * ldt_block_size; // Create an LDT entry for the TCB. - const ldt_entry ldt{.data{ + ldt_entry ldt{}; + ldt.data = { .base00 = static_cast(addr), .base16 = static_cast(addr >> 16), .base24 = static_cast(addr >> 24), @@ -105,34 +123,27 @@ static void** SetupThreadLdt() { .present = 1, // Segment present .stksz = DESC_DATA_32B, .granular = DESC_GRAN_BYTE, - }}; + }; int ret = i386_set_ldt(ldt_index, &ldt, 1); ASSERT_MSG(ret == ldt_index, - "Failed to set LDT for TLS area: expected {}, but syscall returned {}", ldt_index, - ret); + "Failed to set LDT {} at {:#x} for TLS area: syscall returned {}, errno {}", + ldt_index, addr, ret, errno); // Set the FS segment to the created LDT. - const sel_t sel{ + const sel_t new_selector{ .rpl = USER_PRIV, .ti = SEL_LDT, .index = ldt_index, }; - asm volatile("mov %0, %%fs" ::"r"(sel)); + asm volatile("mov %0, %%fs" ::"r"(new_selector)); - return reinterpret_cast(addr); -} + // Store the TCB base pointer and index in the created LDT area. + ldt_page = reinterpret_cast(addr); + ldt_page->tcb = image_address; + ldt_page->index = ldt_index; -static void FreeThreadLdt() { - std::unique_lock lock{free_ldts_lock}; - free_ldts += GetLdtIndex(); -} - -void SetTcbBase(void* image_address) { - if (image_address != nullptr) { - *SetupThreadLdt() = image_address; - } else { - FreeThreadLdt(); - } + ASSERT_MSG(pthread_setspecific(ldt_page_slot, ldt_page) == 0, + "Failed to store thread LDT page pointer: {}", errno); } Tcb* GetTcbBase() {