Store thread TLS in guest memory rather than using host APIs

This commit is contained in:
Dr. Chat
2015-12-27 13:16:08 -06:00
committed by Ben Vanik
parent c5ac4185ac
commit eee0bb070c
5 changed files with 95 additions and 52 deletions

View File

@@ -281,7 +281,7 @@ X_STATUS XThread::Create() {
module->GetOptHeader(XEX_HEADER_TLS_INFO, &tls_header);
}
const uint32_t kDefaultTlsSlotCount = 32;
const uint32_t kDefaultTlsSlotCount = 1024;
uint32_t tls_slots = kDefaultTlsSlotCount;
uint32_t tls_extended_size = 0;
if (tls_header && tls_header->slot_count) {
@@ -293,16 +293,16 @@ X_STATUS XThread::Create() {
// HACK: we're currently not using the extra memory allocated for TLS slots
// and instead relying on native TLS slots, so don't allocate anything for
// the slots.
uint32_t tls_slot_size = 0; // tls_slots * 4;
uint32_t tls_total_size = tls_slot_size + tls_extended_size;
tls_address_ = memory()->SystemHeapAlloc(tls_total_size);
uint32_t tls_slot_size = tls_slots * 4;
tls_total_size_ = tls_slot_size + tls_extended_size;
tls_address_ = memory()->SystemHeapAlloc(tls_total_size_);
if (!tls_address_) {
XELOGW("Unable to allocate thread local storage block");
return X_STATUS_NO_MEMORY;
}
// Zero all of TLS.
memory()->Fill(tls_address_, tls_total_size, 0);
memory()->Fill(tls_address_, tls_total_size_, 0);
if (tls_extended_size) {
// If game has extended data, copy in the default values.
assert_not_zero(tls_header->raw_data_address);
@@ -441,7 +441,6 @@ X_STATUS XThread::Exit(int exit_code) {
running_ = false;
Release();
ReleaseHandle();
// NOTE: this does not return!
xe::threading::Thread::Exit(exit_code);
@@ -462,7 +461,6 @@ X_STATUS XThread::Terminate(int exit_code) {
running_ = false;
Release();
ReleaseHandle();
thread_->Terminate(exit_code);
return X_STATUS_SUCCESS;
@@ -479,7 +477,7 @@ void XThread::Execute() {
// All threads get a mandatory sleep. This is to deal with some buggy
// games that are assuming the 360 is so slow to create threads that they
// have time to initialize shared structures AFTER CreateThread (RR).
xe::threading::Sleep(std::chrono::milliseconds(100));
xe::threading::Sleep(std::chrono::milliseconds(10));
int exit_code = 0;
@@ -708,6 +706,26 @@ void XThread::SetActiveCpu(uint32_t cpu_index) {
xe::store_and_swap<uint8_t>(pcr + 0x10C, cpu_index);
}
bool XThread::GetTLSValue(uint32_t slot, uint32_t* value_out) {
if (slot * 4 > tls_total_size_) {
return false;
}
auto mem = memory()->TranslateVirtual(tls_address_ + slot * 4);
*value_out = xe::load_and_swap<uint32_t>(mem);
return true;
}
bool XThread::SetTLSValue(uint32_t slot, uint32_t value) {
if (slot * 4 >= tls_total_size_) {
return false;
}
auto mem = memory()->TranslateVirtual(tls_address_ + slot * 4);
xe::store_and_swap<uint32_t>(mem, value);
return true;
}
uint32_t XThread::suspend_count() {
return guest_object<X_KTHREAD>()->suspend_count;
}
@@ -1021,6 +1039,7 @@ struct ThreadSavedState {
uint32_t apc_head;
uint32_t tls_address;
uint32_t tls_total_size;
uint32_t pcr_address;
uint32_t stack_base; // High address
uint32_t stack_limit; // Low address
@@ -1076,6 +1095,7 @@ bool XThread::Save(ByteStream* stream) {
state.is_running = running_;
state.apc_head = apc_list_.head();
state.tls_address = tls_address_;
state.tls_total_size = tls_total_size_;
state.pcr_address = pcr_address_;
state.stack_base = stack_base_;
state.stack_limit = stack_limit_;
@@ -1140,6 +1160,7 @@ object_ref<XThread> XThread::Restore(KernelState* kernel_state,
thread->main_thread_ = state.is_main_thread;
thread->apc_list_.set_head(state.apc_head);
thread->tls_address_ = state.tls_address;
thread->tls_total_size_ = state.tls_total_size;
thread->pcr_address_ = state.pcr_address;
thread->stack_base_ = state.stack_base;
thread->stack_limit_ = state.stack_limit;