diff --git a/src/xenia/kernel/objects/xthread.cc b/src/xenia/kernel/objects/xthread.cc index 1bd3e06ee..33bc26691 100644 --- a/src/xenia/kernel/objects/xthread.cc +++ b/src/xenia/kernel/objects/xthread.cc @@ -155,25 +155,6 @@ X_STATUS XThread::Create() { return X_STATUS_NO_MEMORY; } - // Allocate thread state block from heap. - // This is set as r13 for user code and some special inlined Win32 calls - // (like GetLastError/etc) will poke it directly. - // We try to use it as our primary store of data just to keep things all - // consistent. - // 0x000: pointer to tls data - // 0x100: pointer to self? - // 0x14C: thread id - // 0x150: if >0 then error states don't get set - // 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; - if (!pcr_address_) { - XELOGW("Unable to allocate thread state block"); - return X_STATUS_NO_MEMORY; - } - auto module = kernel_state()->GetExecutableModule(); // Allocate thread scratch. @@ -217,6 +198,31 @@ X_STATUS XThread::Create() { header->tls_info.raw_data_size); } + // Allocate thread state block from heap. + // http://www.microsoft.com/msj/archive/s2ce.aspx + // This is set as r13 for user code and some special inlined Win32 calls + // (like GetLastError/etc) will poke it directly. + // We try to use it as our primary store of data just to keep things all + // consistent. + // 0x000: pointer to tls data + // 0x100: pointer to TEB(?) + // 0x10C: Current CPU(?) + // 0x150: if >0 then error states don't get set (DPC active bool?) + // TEB: + // 0x14C: thread id + // 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; + if (!pcr_address_) { + XELOGW("Unable to allocate thread state block"); + return X_STATUS_NO_MEMORY; + } + + // Zero everything + memory()->Zero(pcr_address_, 0x2D8 + 0xAB0); + // Allocate processor thread state. // This is thread safe. thread_state_ = new ThreadState(kernel_state()->processor(), thread_id_, @@ -232,29 +238,56 @@ X_STATUS XThread::Create() { uint8_t proc_mask = static_cast(creation_params_.creation_flags >> 24); - uint8_t* pcr = memory()->TranslateVirtual(pcr_address_); - std::memset(pcr, 0x0, 0x2D8 + 0xAB0); // Zero the PCR - xe::store_and_swap(pcr + 0x000, tls_address_); - xe::store_and_swap(pcr + 0x030, pcr_address_); - xe::store_and_swap(pcr + 0x070, thread_state_->stack_address() + - thread_state_->stack_size()); - xe::store_and_swap(pcr + 0x074, thread_state_->stack_address()); - xe::store_and_swap(pcr + 0x100, thread_state_address_); - xe::store_and_swap(pcr + 0x10C, - GetFakeCpuNumber(proc_mask)); // Current CPU(?) - xe::store_and_swap(pcr + 0x150, 0); // DPC active bool? + // 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 + }; - // Setup the thread state block (last error/etc). + XPCR* pcr = memory()->TranslateVirtual(pcr_address_); + + pcr->tls_ptr = tls_address_; + pcr->pcr_ptr = pcr_address_; + pcr->teb_ptr = thread_state_address_; + + pcr->stack_base_ptr = + thread_state_->stack_address() + thread_state_->stack_size(); + pcr->stack_end_ptr = thread_state_->stack_address(); + + pcr->current_cpu = GetFakeCpuNumber(proc_mask); // Current CPU(?) + pcr->dpc_active = 0; // DPC active bool? + + // Thread state block + struct XTEB { + xe::be unk_00; // 0x0 + xe::be unk_04; // 0x4 + X_LIST_ENTRY unk_08; // 0x8 + X_LIST_ENTRY unk_10; // 0x10 + }; + + // Setup the thread state block (last error/etc) 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); + 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 + 0x054, 0x102); xe::store_and_swap(p + 0x056, 1); xe::store_and_swap( @@ -313,6 +346,8 @@ X_STATUS XThread::Exit(int exit_code) { // NOTE: unless PlatformExit fails, expect it to never return! current_thread_tls = nullptr; xe::Profiler::ThreadExit(); + kernel_state()->OnThreadExit(this); + Release(); X_STATUS return_code = PlatformExit(exit_code); if (XFAILED(return_code)) { @@ -443,6 +478,8 @@ void XThread::Execute() { // have time to initialize shared structures AFTER CreateThread (RR). xe::threading::Sleep(std::chrono::milliseconds::duration(100)); + int exit_code = 0; + // If a XapiThreadStartup value is present, we use that as a trampoline. // Otherwise, we are a raw thread. if (creation_params_.xapi_thread_startup) { @@ -454,16 +491,14 @@ void XThread::Execute() { } else { // Run user code. uint64_t args[] = {creation_params_.start_context}; - int exit_code = (int)kernel_state()->processor()->Execute( + exit_code = (int)kernel_state()->processor()->Execute( thread_state_, creation_params_.start_address, args, xe::countof(args)); // If we got here it means the execute completed without an exit being // called. // Treat the return code as an implicit exit code. - Exit(exit_code); } - // Let the kernel know we are exiting. - kernel_state()->OnThreadExit(this); + Exit(exit_code); } void XThread::EnterCriticalRegion() { @@ -736,9 +771,6 @@ void XHostThread::Execute() { int ret = host_fn_(); - // Let the kernel know we are exiting. - kernel_state()->OnThreadExit(this); - // Exit. Exit(ret); } diff --git a/src/xenia/kernel/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl_threading.cc index 80bb922bd..6e6c5767e 100644 --- a/src/xenia/kernel/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl_threading.cc @@ -41,14 +41,14 @@ namespace kernel { // RtlGetLastError: // lwz r11, 0x150(r13) -// if (r11 != 0) { +// if (r11 == 0) { // lwz r11, 0x100(r13) // stw r3, 0x160(r11) // } // RtlSetLastError: // lwz r11, 0x150(r13) -// if (r11 != 0) { +// if (r11 == 0) { // lwz r11, 0x100(r13) // stw r3, 0x160(r11) // } @@ -56,7 +56,7 @@ namespace kernel { // RtlSetLastNTError: // r3 = RtlNtStatusToDosError(r3) // lwz r11, 0x150(r13) -// if (r11 != 0) { +// if (r11 == 0) { // lwz r11, 0x100(r13) // stw r3, 0x160(r11) // } diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index 07e6c71a1..a74cc7ddc 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -292,7 +292,7 @@ class X_ANSI_STRING { }; // static_assert_size(X_ANSI_STRING, 8); -// Values seem to be all over the place - GUIDs? +// http://pastebin.com/SMypYikG typedef uint32_t XNotificationID; // http://ffplay360.googlecode.com/svn/trunk/Common/XTLOnPC.h @@ -374,6 +374,12 @@ struct X_INPUT_KEYSTROKE { }; static_assert_size(X_INPUT_KEYSTROKE, 8); +struct X_LIST_ENTRY { + be flink_ptr; // next entry / head + be blink_ptr; // previous entry / head +}; +static_assert_size(X_LIST_ENTRY, 8); + #pragma pack(pop) } // namespace xe