diff --git a/src/xenia/kernel/objects/xthread.cc b/src/xenia/kernel/objects/xthread.cc index fe4dd7f04..41d51830e 100644 --- a/src/xenia/kernel/objects/xthread.cc +++ b/src/xenia/kernel/objects/xthread.cc @@ -106,18 +106,17 @@ uint32_t XThread::GetCurrentThreadHandle() { return thread->handle(); } -uint32_t XThread::GetCurrentThreadId(const uint8_t* pcr) { - return xe::load_and_swap(pcr + 0x2D8 + 0x14C); +uint32_t XThread::GetCurrentThreadId() { + XThread* thread = XThread::GetCurrentThread(); + return thread->guest_object()->thread_id; } uint32_t XThread::last_error() { - uint8_t* p = memory()->TranslateVirtual(thread_state_address_); - return xe::load_and_swap(p + 0x160); + return guest_object()->last_error; } void XThread::set_last_error(uint32_t error_code) { - uint8_t* p = memory()->TranslateVirtual(thread_state_address_); - xe::store_and_swap(p + 0x160, error_code); + guest_object()->last_error = error_code; } void XThread::set_name(const std::string& name) { @@ -129,9 +128,15 @@ void XThread::set_name(const std::string& name) { } } +uint8_t next_cpu = 0; uint8_t GetFakeCpuNumber(uint8_t proc_mask) { if (!proc_mask) { - return 0; // is this reasonable? + next_cpu++; + if (next_cpu > 6) { + next_cpu = 0; + } + + return next_cpu; // is this reasonable? } assert_false(proc_mask & 0xC0); @@ -143,15 +148,12 @@ uint8_t GetFakeCpuNumber(uint8_t proc_mask) { X_STATUS XThread::Create() { // Thread kernel object // This call will also setup the native pointer for us. - auto guest_object = CreateNative(sizeof(X_KTHREAD)); - if (!guest_object) { + auto guest_thread = CreateNative(); + if (!guest_thread) { XELOGW("Unable to allocate thread object"); return X_STATUS_NO_MEMORY; } - guest_object->header.type = 6; - StashNative(&guest_object->header, this); - auto module = kernel_state()->GetExecutableModule(); // Allocate thread scratch. @@ -210,8 +212,7 @@ X_STATUS XThread::Create() { // 0x160: last error // So, at offset 0x100 we have a 4b pointer to offset 200, then have the // structure. - pcr_address_ = memory()->SystemHeapAlloc(0x2D8 + 0xAB0); - thread_state_address_ = pcr_address_ + 0x2D8; + pcr_address_ = memory()->SystemHeapAlloc(0x2D8); if (!pcr_address_) { XELOGW("Unable to allocate thread state block"); return X_STATUS_NO_MEMORY; @@ -232,27 +233,11 @@ X_STATUS XThread::Create() { uint8_t proc_mask = static_cast(creation_params_.creation_flags >> 24); - // Processor Control Region - struct XPCR { - xe::be tls_ptr; // 0x0 - char unk_04[0x2C]; // 0x4 - xe::be pcr_ptr; // 0x30 - char unk_34[0x3C]; // 0x34 - xe::be stack_base_ptr; // 0x70 Stack base address (high addr) - xe::be stack_end_ptr; // 0x74 Stack end (low addr) - char unk_78[0x88]; // 0x78 - xe::be teb_ptr; // 0x100 - char unk_104[0x8]; // 0x104 - xe::be current_cpu; // 0x10C - char unk_10D[0x43]; // 0x10D - xe::be dpc_active; // 0x150 - }; - - XPCR* pcr = memory()->TranslateVirtual(pcr_address_); + X_KPCR* pcr = memory()->TranslateVirtual(pcr_address_); pcr->tls_ptr = tls_address_; pcr->pcr_ptr = pcr_address_; - pcr->teb_ptr = thread_state_address_; + pcr->current_thread = guest_object(); pcr->stack_base_ptr = thread_state_->stack_address() + thread_state_->stack_size(); @@ -262,19 +247,16 @@ X_STATUS XThread::Create() { pcr->dpc_active = 0; // DPC active bool? // Setup the thread state block (last error/etc). - // TODO: This is actually a KTHREAD object. Use the one from CreateNative - // instead. - uint8_t* p = memory()->TranslateVirtual(thread_state_address_); - xe::store_and_swap(p + 0x000, 6); - xe::store_and_swap(p + 0x008, thread_state_address_ + 0x008); - xe::store_and_swap(p + 0x00C, thread_state_address_ + 0x008); - xe::store_and_swap(p + 0x010, thread_state_address_ + 0x010); - xe::store_and_swap(p + 0x014, thread_state_address_ + 0x010); + uint8_t* p = memory()->TranslateVirtual(guest_object()); + guest_thread->header.type = 6; - xe::store_and_swap(p + 0x040, thread_state_address_ + 0x018 + 8); - xe::store_and_swap(p + 0x044, thread_state_address_ + 0x018 + 8); - xe::store_and_swap(p + 0x048, thread_state_address_); - xe::store_and_swap(p + 0x04C, thread_state_address_ + 0x018); + xe::store_and_swap(p + 0x010, guest_object() + 0x010); + xe::store_and_swap(p + 0x014, guest_object() + 0x010); + + xe::store_and_swap(p + 0x040, guest_object() + 0x018 + 8); + xe::store_and_swap(p + 0x044, guest_object() + 0x018 + 8); + xe::store_and_swap(p + 0x048, guest_object()); + xe::store_and_swap(p + 0x04C, guest_object() + 0x018); xe::store_and_swap(p + 0x054, 0x102); xe::store_and_swap(p + 0x056, 1); @@ -283,27 +265,27 @@ X_STATUS XThread::Create() { xe::store_and_swap(p + 0x060, thread_state_->stack_address()); xe::store_and_swap(p + 0x068, tls_address_); xe::store_and_swap(p + 0x06C, 0); - xe::store_and_swap(p + 0x074, thread_state_address_ + 0x074); - xe::store_and_swap(p + 0x078, thread_state_address_ + 0x074); - xe::store_and_swap(p + 0x07C, thread_state_address_ + 0x07C); - xe::store_and_swap(p + 0x080, thread_state_address_ + 0x07C); + xe::store_and_swap(p + 0x074, guest_object() + 0x074); + xe::store_and_swap(p + 0x078, guest_object() + 0x074); + xe::store_and_swap(p + 0x07C, guest_object() + 0x07C); + xe::store_and_swap(p + 0x080, guest_object() + 0x07C); xe::store_and_swap(p + 0x084, kernel_state_->process_info_block_address()); xe::store_and_swap(p + 0x08B, 1); - // D4 = APC - // FC = semaphore (ptr, 0, 2) - // A88 = APC - // 18 = timer + // 0xD4 = APC + // 0xFC = semaphore (ptr, 0, 2) + // 0xA88 = APC + // 0x18 = timer xe::store_and_swap(p + 0x09C, 0xFDFFD7FF); xe::store_and_swap( p + 0x0D0, thread_state_->stack_address() + thread_state_->stack_size()); xe::store_and_swap(p + 0x130, Clock::QueryGuestSystemTime()); - xe::store_and_swap(p + 0x144, thread_state_address_ + 0x144); - xe::store_and_swap(p + 0x148, thread_state_address_ + 0x144); + xe::store_and_swap(p + 0x144, guest_object() + 0x144); + xe::store_and_swap(p + 0x148, guest_object() + 0x144); xe::store_and_swap(p + 0x14C, thread_id_); xe::store_and_swap(p + 0x150, creation_params_.start_address); - xe::store_and_swap(p + 0x154, thread_state_address_ + 0x154); - xe::store_and_swap(p + 0x158, thread_state_address_ + 0x154); + xe::store_and_swap(p + 0x154, guest_object() + 0x154); + xe::store_and_swap(p + 0x158, guest_object() + 0x154); xe::store_and_swap(p + 0x160, 0); // last error xe::store_and_swap(p + 0x16C, creation_params_.creation_flags); xe::store_and_swap(p + 0x17C, 1); @@ -331,6 +313,7 @@ X_STATUS XThread::Create() { // Release the self-reference to the thread. Release(); }); + if (!thread_) { // TODO(benvanik): translate error? XELOGE("CreateThread failed"); @@ -520,7 +503,8 @@ void XThread::DeliverAPCs() { LockApc(); } - XELOGD("Completed delivery of APC to %.8X", uint32_t(apc->normal_routine)); + XELOGD("Completed delivery of APC to %.8X (%.8X, %.8X, %.8X)", + normal_routine, normal_context, arg1, arg2); // If special, free it. if (needs_freeing) { @@ -614,6 +598,8 @@ void XThread::SetActiveCpu(uint32_t cpu_index) { } X_STATUS XThread::Resume(uint32_t* out_suspend_count) { + --guest_object()->suspend_count; + if (thread_->Resume(out_suspend_count)) { return X_STATUS_SUCCESS; } else { @@ -622,6 +608,8 @@ X_STATUS XThread::Resume(uint32_t* out_suspend_count) { } X_STATUS XThread::Suspend(uint32_t* out_suspend_count) { + ++guest_object()->suspend_count; + if (thread_->Suspend(out_suspend_count)) { return X_STATUS_SUCCESS; } else { diff --git a/src/xenia/kernel/objects/xthread.h b/src/xenia/kernel/objects/xthread.h index d67195f29..3c2b564d3 100644 --- a/src/xenia/kernel/objects/xthread.h +++ b/src/xenia/kernel/objects/xthread.h @@ -65,13 +65,35 @@ struct XAPC { } }; -// http://www.nirsoft.net/kernel_struct/vista/KTHREAD.html +// Processor Control Region +struct X_KPCR { + xe::be tls_ptr; // 0x0 + char unk_04[0x2C]; // 0x4 + xe::be pcr_ptr; // 0x30 + char unk_34[0x3C]; // 0x34 + xe::be stack_base_ptr; // 0x70 Stack base address (high addr) + xe::be stack_end_ptr; // 0x74 Stack end (low addr) + char unk_78[0x88]; // 0x78 + xe::be current_thread; // 0x100 + char unk_104[0x8]; // 0x104 + xe::be current_cpu; // 0x10C + char unk_10D[0x43]; // 0x10D + xe::be dpc_active; // 0x150 +}; + struct X_KTHREAD { - X_DISPATCH_HEADER header; // 0x0 - char unk_04[0xAA0]; // 0x4 + X_DISPATCH_HEADER header; // 0x0 + char unk_10[0xAC]; // 0x10 + uint8_t suspend_count; // 0xBC + char unk_BD[0x8F]; // 0xBD + xe::be thread_id; // 0x14C + char unk_150[0x10]; // 0x150 + xe::be last_error; // 0x160 + char unk_164[0x94C]; // 0x164 // This struct is actually quite long... so uh, not filling this out! }; +static_assert_size(X_KTHREAD, 0xAB0); class XThread : public XObject { public: @@ -83,11 +105,10 @@ class XThread : public XObject { static bool IsInThread(XThread* other); static XThread* GetCurrentThread(); static uint32_t GetCurrentThreadHandle(); - static uint32_t GetCurrentThreadId(const uint8_t* pcr); + static uint32_t GetCurrentThreadId(); uint32_t tls_ptr() const { return tls_address_; } uint32_t pcr_ptr() const { return pcr_address_; } - uint32_t thread_state_ptr() const { return thread_state_address_; } bool guest_thread() const { return guest_thread_; } bool running() const { return running_; } @@ -149,9 +170,8 @@ class XThread : public XObject { uint32_t scratch_size_ = 0; uint32_t tls_address_ = 0; uint32_t pcr_address_ = 0; - uint32_t thread_state_address_ = 0; cpu::ThreadState* thread_state_ = nullptr; - bool guest_thread_ = false; // Launched into guest code. + bool guest_thread_ = false; // Launched into guest code? bool running_ = false; std::string name_; @@ -159,7 +179,7 @@ class XThread : public XObject { int32_t priority_ = 0; uint32_t affinity_ = 0; - std::atomic irql_; + std::atomic irql_ = 0; xe::mutex apc_lock_; NativeList* apc_list_ = nullptr; };