Merge pull request #275 from DrChat/thread_cleanup

Cleanup some XThread code
This commit is contained in:
Ben Vanik 2015-06-22 21:43:02 -07:00
commit 54b94ac22f
3 changed files with 80 additions and 42 deletions

View File

@ -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<uint8_t>(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<uint32_t>(pcr + 0x000, tls_address_);
xe::store_and_swap<uint32_t>(pcr + 0x030, pcr_address_);
xe::store_and_swap<uint32_t>(pcr + 0x070, thread_state_->stack_address() +
thread_state_->stack_size());
xe::store_and_swap<uint32_t>(pcr + 0x074, thread_state_->stack_address());
xe::store_and_swap<uint32_t>(pcr + 0x100, thread_state_address_);
xe::store_and_swap<uint8_t>(pcr + 0x10C,
GetFakeCpuNumber(proc_mask)); // Current CPU(?)
xe::store_and_swap<uint32_t>(pcr + 0x150, 0); // DPC active bool?
// Processor Control Region
struct XPCR {
xe::be<uint32_t> tls_ptr; // 0x0
char unk_04[0x2C]; // 0x4
xe::be<uint32_t> pcr_ptr; // 0x30
char unk_34[0x3C]; // 0x34
xe::be<uint32_t> stack_base_ptr; // 0x70 Stack base address (high addr)
xe::be<uint32_t> stack_end_ptr; // 0x74 Stack end (low addr)
char unk_78[0x88]; // 0x78
xe::be<uint32_t> teb_ptr; // 0x100
char unk_104[0x8]; // 0x104
xe::be<uint8_t> current_cpu; // 0x10C
char unk_10D[0x43]; // 0x10D
xe::be<uint32_t> dpc_active; // 0x150
};
// Setup the thread state block (last error/etc).
XPCR* pcr = memory()->TranslateVirtual<XPCR*>(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<uint32_t> unk_00; // 0x0
xe::be<uint32_t> 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<uint32_t>(p + 0x000, 6);
xe::store_and_swap<uint32_t>(p + 0x008, thread_state_address_ + 0x008);
xe::store_and_swap<uint32_t>(p + 0x00C, thread_state_address_ + 0x008);
xe::store_and_swap<uint32_t>(p + 0x010, thread_state_address_ + 0x010);
xe::store_and_swap<uint32_t>(p + 0x014, thread_state_address_ + 0x010);
xe::store_and_swap<uint32_t>(p + 0x040, thread_state_address_ + 0x018 + 8);
xe::store_and_swap<uint32_t>(p + 0x044, thread_state_address_ + 0x018 + 8);
xe::store_and_swap<uint32_t>(p + 0x048, thread_state_address_);
xe::store_and_swap<uint32_t>(p + 0x04C, thread_state_address_ + 0x018);
xe::store_and_swap<uint16_t>(p + 0x054, 0x102);
xe::store_and_swap<uint16_t>(p + 0x056, 1);
xe::store_and_swap<uint32_t>(
@ -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);
}

View File

@ -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)
// }

View File

@ -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<uint32_t> flink_ptr; // next entry / head
be<uint32_t> blink_ptr; // previous entry / head
};
static_assert_size(X_LIST_ENTRY, 8);
#pragma pack(pop)
} // namespace xe