diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc index 42292895b..29b064841 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc @@ -222,13 +222,23 @@ void KeSetCurrentStackPointers(lpvoid_t stack_ptr, } DECLARE_XBOXKRNL_EXPORT1(KeSetCurrentStackPointers, kThreading, kImplemented); -dword_result_t KeSetAffinityThread(lpvoid_t thread_ptr, dword_t affinity) { - auto thread = XObject::GetNativeObject(kernel_state(), thread_ptr); - if (thread) { - thread->SetAffinity(affinity); +dword_result_t KeSetAffinityThread(lpvoid_t thread_ptr, dword_t affinity, + lpdword_t previous_affinity_ptr) { + // Xbox 360 uses additional parameter (in comparation to NT equivalent) + // which is used only for returning previous thread affinity. (Based on code + // dissasembly) + if (!affinity) { + return X_STATUS_INVALID_PARAMETER; } - return (uint32_t)affinity; + auto thread = XObject::GetNativeObject(kernel_state(), thread_ptr); + if (thread) { + if (previous_affinity_ptr) { + *previous_affinity_ptr = 1 << thread->active_cpu(); + } + thread->SetAffinity(affinity); + } + return X_STATUS_SUCCESS; } DECLARE_XBOXKRNL_EXPORT1(KeSetAffinityThread, kThreading, kImplemented); diff --git a/src/xenia/kernel/xthread.cc b/src/xenia/kernel/xthread.cc index 458d7a592..1e4753053 100644 --- a/src/xenia/kernel/xthread.cc +++ b/src/xenia/kernel/xthread.cc @@ -205,6 +205,7 @@ void XThread::InitializeGuestObject() { // 0xA88 = APC // 0x18 = timer xe::store_and_swap(p + 0x09C, 0xFDFFD7FF); + xe::store_and_swap(p + 0xBF, 0); xe::store_and_swap(p + 0x0D0, stack_base_); xe::store_and_swap(p + 0x130, Clock::QueryGuestSystemTime()); xe::store_and_swap(p + 0x144, guest_object() + 0x144); @@ -346,6 +347,9 @@ X_STATUS XThread::Create() { // Exports use this to get the kernel. thread_state_->context()->kernel_state = kernel_state_; + // Initialize the KTHREAD object. + InitializeGuestObject(); + X_KPCR* pcr = memory()->TranslateVirtual(pcr_address_); pcr->tls_ptr = tls_static_address_; @@ -355,14 +359,12 @@ X_STATUS XThread::Create() { pcr->stack_base_ptr = stack_base_; pcr->stack_end_ptr = stack_limit_; + pcr->dpc_active = 0; // DPC active bool? + uint8_t proc_mask = static_cast(creation_params_.creation_flags >> 24); - - pcr->current_cpu = GetFakeCpuNumber(proc_mask); // Current CPU(?) - pcr->dpc_active = 0; // DPC active bool? - - // Initialize the KTHREAD object. - InitializeGuestObject(); + // Assign cpu core used by thread on guest side + SetAffinity(1 << GetFakeCpuNumber(proc_mask)); // Always retain when starting - the thread owns itself until exited. RetainHandle(); @@ -714,7 +716,7 @@ void XThread::SetAffinity(uint32_t affinity) { XELOGW("Too few processors - scheduling will be wonky"); } SetActiveCpu(GetFakeCpuNumber(affinity)); - affinity_ = affinity; + if (!cvars::ignore_thread_affinities) { thread_->set_affinity_mask(affinity); } @@ -729,6 +731,12 @@ void XThread::SetActiveCpu(uint32_t cpu_index) { assert_true(cpu_index < 6); uint8_t* pcr = memory()->TranslateVirtual(pcr_address_); xe::store_and_swap(pcr + 0x10C, cpu_index); + + if (is_guest_thread()) { + X_KTHREAD* thread_object = + memory()->TranslateVirtual(guest_object()); + thread_object->current_cpu = cpu_index; + } } bool XThread::GetTLSValue(uint32_t slot, uint32_t* value_out) { diff --git a/src/xenia/kernel/xthread.h b/src/xenia/kernel/xthread.h index 2b6518703..de813bb49 100644 --- a/src/xenia/kernel/xthread.h +++ b/src/xenia/kernel/xthread.h @@ -88,7 +88,8 @@ struct X_KTHREAD { char unk_10[0xAC]; // 0x10 uint8_t suspend_count; // 0xBC uint8_t unk_BD; // 0xBD - uint16_t unk_BE; // 0xBE + uint8_t unk_BE; // 0xBE + uint8_t current_cpu; // 0xBF char unk_C0[0x70]; // 0xC0 xe::be create_time; // 0x130 xe::be exit_time; // 0x138 @@ -165,7 +166,6 @@ class XThread : public XObject, public cpu::Thread { int32_t priority() const { return priority_; } int32_t QueryPriority(); void SetPriority(int32_t increment); - uint32_t affinity() const { return affinity_; } void SetAffinity(uint32_t affinity); uint32_t active_cpu() const; void SetActiveCpu(uint32_t cpu_index); @@ -220,7 +220,6 @@ class XThread : public XObject, public cpu::Thread { bool running_ = false; int32_t priority_ = 0; - uint32_t affinity_ = 0; xe::global_critical_region global_critical_region_; std::atomic irql_ = {0};