mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-01-01 12:46:01 +00:00
kernel: Fix new pthreads code on macOS. (#1441)
This commit is contained in:
parent
729d7b8ccc
commit
649ffb2079
|
@ -4,6 +4,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include "common/polyfill_thread.h"
|
||||||
#include "core/libraries/kernel/threads/pthread.h"
|
#include "core/libraries/kernel/threads/pthread.h"
|
||||||
|
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <forward_list>
|
#include <forward_list>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <semaphore>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
#include <boost/intrusive/list.hpp>
|
#include <boost/intrusive/list.hpp>
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <semaphore>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
#include "common/ntapi.h"
|
#include "common/ntapi.h"
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
#if __APPLE__
|
||||||
|
#include <date/tz.h>
|
||||||
|
#endif
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
|
@ -33,7 +33,8 @@ struct OrbisKernelTimespec {
|
||||||
|
|
||||||
std::chrono::system_clock::time_point TimePoint() const noexcept {
|
std::chrono::system_clock::time_point TimePoint() const noexcept {
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
const auto duration = seconds{tv_sec} + nanoseconds{tv_nsec};
|
const auto duration =
|
||||||
|
duration_cast<system_clock::duration>(seconds{tv_sec} + nanoseconds{tv_nsec});
|
||||||
return system_clock::time_point{duration};
|
return system_clock::time_point{duration};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include "core/libraries/network/net_ctl_codes.h"
|
#include "core/libraries/network/net_ctl_codes.h"
|
||||||
#include "core/libraries/network/net_ctl_obj.h"
|
#include "core/libraries/network/net_ctl_obj.h"
|
||||||
#include "core/tls.h"
|
#include "core/tls.h"
|
||||||
|
|
|
@ -54,8 +54,13 @@ Tcb* GetTcbBase() {
|
||||||
// Reserve space in the 32-bit address range for allocating TCB pages.
|
// Reserve space in the 32-bit address range for allocating TCB pages.
|
||||||
asm(".zerofill TCB_SPACE,TCB_SPACE,__guest_system,0x3FC000");
|
asm(".zerofill TCB_SPACE,TCB_SPACE,__guest_system,0x3FC000");
|
||||||
|
|
||||||
static constexpr u64 ldt_region_base = 0x4000;
|
struct LdtPage {
|
||||||
static constexpr u64 ldt_region_size = 0x3FC000;
|
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_block_size = 0x1000;
|
||||||
static constexpr u16 ldt_index_base = 8;
|
static constexpr u16 ldt_index_base = 8;
|
||||||
static constexpr u16 ldt_index_total = (ldt_region_size - ldt_region_base) / ldt_block_size;
|
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<u16> free_ldts{};
|
static boost::icl::interval_set<u16> free_ldts{};
|
||||||
static std::mutex free_ldts_lock;
|
static std::mutex free_ldts_lock;
|
||||||
static std::once_flag ldt_region_init_flag;
|
static std::once_flag ldt_region_init_flag;
|
||||||
|
static pthread_key_t ldt_page_slot = 0;
|
||||||
|
|
||||||
static u16 GetLdtIndex() {
|
static void FreeLdtPage(void* raw) {
|
||||||
sel_t selector;
|
const auto* ldt_page = static_cast<LdtPage*>(raw);
|
||||||
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() {
|
static void InitLdtRegion() {
|
||||||
|
@ -78,11 +85,20 @@ static void InitLdtRegion() {
|
||||||
|
|
||||||
free_ldts +=
|
free_ldts +=
|
||||||
boost::icl::interval<u16>::right_open(ldt_index_base, ldt_index_base + ldt_index_total);
|
boost::icl::interval<u16>::right_open(ldt_index_base, ldt_index_base + ldt_index_total);
|
||||||
|
ASSERT_MSG(pthread_key_create(&ldt_page_slot, FreeLdtPage) == 0,
|
||||||
|
"Failed to create thread LDT page key: {}", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void** SetupThreadLdt() {
|
void SetTcbBase(void* image_address) {
|
||||||
std::call_once(ldt_region_init_flag, InitLdtRegion);
|
std::call_once(ldt_region_init_flag, InitLdtRegion);
|
||||||
|
|
||||||
|
auto* ldt_page = static_cast<LdtPage*>(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.
|
// Allocate a new LDT index for the current thread.
|
||||||
u16 ldt_index;
|
u16 ldt_index;
|
||||||
{
|
{
|
||||||
|
@ -91,10 +107,12 @@ static void** SetupThreadLdt() {
|
||||||
ldt_index = first(*free_ldts.begin());
|
ldt_index = first(*free_ldts.begin());
|
||||||
free_ldts -= ldt_index;
|
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.
|
// Create an LDT entry for the TCB.
|
||||||
const ldt_entry ldt{.data{
|
ldt_entry ldt{};
|
||||||
|
ldt.data = {
|
||||||
.base00 = static_cast<u16>(addr),
|
.base00 = static_cast<u16>(addr),
|
||||||
.base16 = static_cast<u8>(addr >> 16),
|
.base16 = static_cast<u8>(addr >> 16),
|
||||||
.base24 = static_cast<u8>(addr >> 24),
|
.base24 = static_cast<u8>(addr >> 24),
|
||||||
|
@ -105,34 +123,27 @@ static void** SetupThreadLdt() {
|
||||||
.present = 1, // Segment present
|
.present = 1, // Segment present
|
||||||
.stksz = DESC_DATA_32B,
|
.stksz = DESC_DATA_32B,
|
||||||
.granular = DESC_GRAN_BYTE,
|
.granular = DESC_GRAN_BYTE,
|
||||||
}};
|
};
|
||||||
int ret = i386_set_ldt(ldt_index, &ldt, 1);
|
int ret = i386_set_ldt(ldt_index, &ldt, 1);
|
||||||
ASSERT_MSG(ret == ldt_index,
|
ASSERT_MSG(ret == ldt_index,
|
||||||
"Failed to set LDT for TLS area: expected {}, but syscall returned {}", ldt_index,
|
"Failed to set LDT {} at {:#x} for TLS area: syscall returned {}, errno {}",
|
||||||
ret);
|
ldt_index, addr, ret, errno);
|
||||||
|
|
||||||
// Set the FS segment to the created LDT.
|
// Set the FS segment to the created LDT.
|
||||||
const sel_t sel{
|
const sel_t new_selector{
|
||||||
.rpl = USER_PRIV,
|
.rpl = USER_PRIV,
|
||||||
.ti = SEL_LDT,
|
.ti = SEL_LDT,
|
||||||
.index = ldt_index,
|
.index = ldt_index,
|
||||||
};
|
};
|
||||||
asm volatile("mov %0, %%fs" ::"r"(sel));
|
asm volatile("mov %0, %%fs" ::"r"(new_selector));
|
||||||
|
|
||||||
return reinterpret_cast<void**>(addr);
|
// Store the TCB base pointer and index in the created LDT area.
|
||||||
}
|
ldt_page = reinterpret_cast<LdtPage*>(addr);
|
||||||
|
ldt_page->tcb = image_address;
|
||||||
|
ldt_page->index = ldt_index;
|
||||||
|
|
||||||
static void FreeThreadLdt() {
|
ASSERT_MSG(pthread_setspecific(ldt_page_slot, ldt_page) == 0,
|
||||||
std::unique_lock lock{free_ldts_lock};
|
"Failed to store thread LDT page pointer: {}", errno);
|
||||||
free_ldts += GetLdtIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetTcbBase(void* image_address) {
|
|
||||||
if (image_address != nullptr) {
|
|
||||||
*SetupThreadLdt() = image_address;
|
|
||||||
} else {
|
|
||||||
FreeThreadLdt();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Tcb* GetTcbBase() {
|
Tcb* GetTcbBase() {
|
||||||
|
|
Loading…
Reference in a new issue