diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index 1a6a8e733..ca00c5bff 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -78,6 +78,18 @@ bool XexModule::GetOptHeader(const xex2_header* header, xe_xex2_header_keys key, return false; } +bool XexModule::GetOptHeader(xe_xex2_header_keys key, void** out_ptr) const { + return XexModule::GetOptHeader(xex_header_, key, out_ptr); +} + +uint32_t XexModule::GetProcAddress(uint16_t ordinal) const { + return xe_xex2_lookup_export(xex_, ordinal); +} + +uint32_t XexModule::GetProcAddress(const char* name) const { + return xe_xex2_lookup_export(xex_, name); +} + bool XexModule::ApplyPatch(XexModule* module) { auto header = reinterpret_cast(module->xex_header()); if (!(header->module_flags & diff --git a/src/xenia/cpu/xex_module.h b/src/xenia/cpu/xex_module.h index 54e23d41e..f15c03bd9 100644 --- a/src/xenia/cpu/xex_module.h +++ b/src/xenia/cpu/xex_module.h @@ -40,6 +40,10 @@ class XexModule : public xe::cpu::Module { // not a pointer! static bool GetOptHeader(const xex2_header* header, xe_xex2_header_keys key, void** out_ptr); + bool GetOptHeader(xe_xex2_header_keys key, void** out_ptr) const; + + uint32_t GetProcAddress(uint16_t ordinal) const; + uint32_t GetProcAddress(const char* name) const; bool ApplyPatch(XexModule* module); bool Load(const std::string& name, const std::string& path, diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index 86994216f..a3544b4ad 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -120,7 +120,16 @@ KernelState* KernelState::shared() { return shared_kernel_state_; } uint32_t KernelState::title_id() const { assert_not_null(executable_module_); - return executable_module_->xex_header()->execution_info.title_id; + + xex2_opt_execution_info* exec_info = 0; + executable_module_->GetOptHeader(XEX_HEADER_EXECUTION_INFO, + (void**)&exec_info); + + if (exec_info) { + return exec_info->title_id; + } + + return 0; } uint32_t KernelState::process_type() const { @@ -192,13 +201,14 @@ void KernelState::SetExecutableModule(object_ref module) { return; } - auto header = executable_module_->xex_header(); - if (header) { + xex2_opt_tls_info* tls_header = nullptr; + executable_module_->GetOptHeader(XEX_HEADER_TLS_INFO, (void**)&tls_header); + if (tls_header) { auto pib = memory_->TranslateVirtual( process_info_block_address_); - pib->tls_data_size = header->tls_info.data_size; - pib->tls_raw_data_size = header->tls_info.raw_data_size; - pib->tls_slot_size = header->tls_info.slot_count * 4; + pib->tls_data_size = tls_header->data_size; + pib->tls_raw_data_size = tls_header->raw_data_size; + pib->tls_slot_size = tls_header->slot_count * 4; } // Setup the kernel's XexExecutableModuleHandle field. @@ -275,8 +285,7 @@ object_ref KernelState::LoadUserModule(const char* raw_name) { module->Dump(); - auto xex_header = module->xex_header(); - if (xex_header->exe_entry_point) { + if (module->entry_point()) { // Call DllMain(DLL_PROCESS_ATTACH): // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx uint64_t args[] = { @@ -285,7 +294,7 @@ object_ref KernelState::LoadUserModule(const char* raw_name) { 0, // 0 because always dynamic }; auto thread_state = XThread::GetCurrentThread()->thread_state(); - processor()->Execute(thread_state, xex_header->exe_entry_point, args, + processor()->Execute(thread_state, module->entry_point(), args, xe::countof(args)); } @@ -323,14 +332,13 @@ void KernelState::OnThreadExecute(XThread* thread) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx auto thread_state = thread->thread_state(); for (auto user_module : user_modules_) { - auto xex_header = user_module->xex_header(); - if (xex_header->exe_entry_point) { + if (user_module->entry_point()) { uint64_t args[] = { user_module->handle(), 2, // DLL_THREAD_ATTACH 0, // 0 because always dynamic }; - processor()->Execute(thread_state, xex_header->exe_entry_point, args, + processor()->Execute(thread_state, user_module->entry_point(), args, xe::countof(args)); } } @@ -346,14 +354,13 @@ void KernelState::OnThreadExit(XThread* thread) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx auto thread_state = thread->thread_state(); for (auto user_module : user_modules_) { - auto xex_header = user_module->xex_header(); - if (xex_header->exe_entry_point) { + if (user_module->entry_point()) { uint64_t args[] = { user_module->handle(), 3, // DLL_THREAD_DETACH 0, // 0 because always dynamic }; - processor()->Execute(thread_state, xex_header->exe_entry_point, args, + processor()->Execute(thread_state, user_module->entry_point(), args, xe::countof(args)); } } diff --git a/src/xenia/kernel/objects/xthread.cc b/src/xenia/kernel/objects/xthread.cc index 5815ba212..471ba3c6b 100644 --- a/src/xenia/kernel/objects/xthread.cc +++ b/src/xenia/kernel/objects/xthread.cc @@ -164,14 +164,18 @@ X_STATUS XThread::Create() { // Allocate TLS block. // Games will specify a certain number of 4b slots that each thread will get. + xex2_opt_tls_info* tls_header = nullptr; + if (module) { + module->GetOptHeader(XEX_HEADER_TLS_INFO, (void**)&tls_header); + } + const uint32_t kDefaultTlsSlotCount = 32; uint32_t tls_slots = 0; uint32_t tls_extended_size = 0; - if (module && module->xex_header()) { - const xe_xex2_header_t* header = module->xex_header(); - tls_slots = header->tls_info.slot_count ? header->tls_info.slot_count - : kDefaultTlsSlotCount; - tls_extended_size = header->tls_info.data_size; + if (tls_header) { + tls_slots = + tls_header->slot_count ? tls_header->slot_count : kDefaultTlsSlotCount; + tls_extended_size = tls_header->data_size; } else { tls_slots = kDefaultTlsSlotCount; } @@ -192,10 +196,9 @@ X_STATUS XThread::Create() { memory()->Fill(tls_address_, tls_total_size, 0); if (tls_extended_size) { // If game has extended data, copy in the default values. - const xe_xex2_header_t* header = module->xex_header(); - assert_not_zero(header->tls_info.raw_data_address); - memory()->Copy(tls_address_, header->tls_info.raw_data_address, - header->tls_info.raw_data_size); + assert_not_zero(tls_header->raw_data_address); + memory()->Copy(tls_address_, tls_header->raw_data_address, + tls_header->raw_data_size); } // Allocate thread state block from heap. @@ -583,8 +586,11 @@ void XThread::DeliverAPCs(void* data) { // kernel_routine(apc_address, &normal_routine, &normal_context, // &system_arg1, &system_arg2) uint64_t kernel_args[] = { - apc_ptr, thread->scratch_address_ + 0, thread->scratch_address_ + 4, - thread->scratch_address_ + 8, thread->scratch_address_ + 12, + apc_ptr, + thread->scratch_address_ + 0, + thread->scratch_address_ + 4, + thread->scratch_address_ + 8, + thread->scratch_address_ + 12, }; processor->Execute(thread->thread_state(), apc->kernel_routine, kernel_args, xe::countof(kernel_args)); diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index 6da97cd48..8a7b958d6 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -22,13 +22,9 @@ namespace kernel { using namespace xe::cpu; XUserModule::XUserModule(KernelState* kernel_state, const char* path) - : XModule(kernel_state, ModuleType::kUserModule, path), xex_(nullptr) {} + : XModule(kernel_state, ModuleType::kUserModule, path) {} -XUserModule::~XUserModule() { xe_xex2_dealloc(xex_); } - -const xe_xex2_header_t* XUserModule::xex_header() { - return xe_xex2_get_header(xex_); -} +XUserModule::~XUserModule() {} X_STATUS XUserModule::LoadFromFile(std::string path) { X_STATUS result = X_STATUS_UNSUCCESSFUL; @@ -86,7 +82,6 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) { if (!xex_module->Load(name_, path_, addr, length)) { return X_STATUS_UNSUCCESSFUL; } - xex_ = xex_module->xex(); processor_module_ = xex_module.get(); if (!processor->AddModule(std::move(xex_module))) { return X_STATUS_UNSUCCESSFUL; @@ -106,34 +101,60 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) { ldr_data->dll_base = 0; // GetProcAddress will read this. ldr_data->xex_header_base = guest_xex_header_; + // Cache some commonly used headers... + this->xex_module()->GetOptHeader(XEX_HEADER_ENTRY_POINT, + (void**)&entry_point_); + this->xex_module()->GetOptHeader(XEX_HEADER_DEFAULT_STACK_SIZE, + (void**)&stack_size_); + OnLoad(); return X_STATUS_SUCCESS; } uint32_t XUserModule::GetProcAddressByOrdinal(uint16_t ordinal) { - return xe_xex2_lookup_export(xex_, ordinal); + return xex_module()->GetProcAddress(ordinal); } uint32_t XUserModule::GetProcAddressByName(const char* name) { - return xe_xex2_lookup_export(xex_, name); + return xex_module()->GetProcAddress(name); } X_STATUS XUserModule::GetSection(const char* name, uint32_t* out_section_data, uint32_t* out_section_size) { - auto header = xe_xex2_get_header(xex_); - for (size_t n = 0; n < header->resource_info_count; n++) { - auto& res = header->resource_infos[n]; + xex2_opt_resource_info* resource_header = nullptr; + if (!XexModule::GetOptHeader(xex_header(), XEX_HEADER_RESOURCE_INFO, + (void**)&resource_header)) { + // No resources. + return X_STATUS_UNSUCCESSFUL; + } + + uint32_t count = (resource_header->size - 4) / 16; + for (uint32_t i = 0; i < count; i++) { + auto& res = resource_header->resources[i]; if (strcmp(name, res.name) == 0) { // Found! *out_section_data = res.address; *out_section_size = res.size; + return X_STATUS_SUCCESS; } } + return X_STATUS_UNSUCCESSFUL; } +X_STATUS XUserModule::GetOptHeader(xe_xex2_header_keys key, void** out_ptr) { + assert_not_null(out_ptr); + + bool ret = xex_module()->GetOptHeader(key, out_ptr); + if (!ret) { + return X_STATUS_NOT_FOUND; + } + + return X_STATUS_SUCCESS; +} + X_STATUS XUserModule::GetOptHeader(xe_xex2_header_keys key, uint32_t* out_header_guest_ptr) { auto header = xex_module()->xex_header(); @@ -180,16 +201,21 @@ X_STATUS XUserModule::GetOptHeader(uint8_t* membase, const xex2_header* header, } X_STATUS XUserModule::Launch(uint32_t flags) { - const xe_xex2_header_t* header = xex_header(); - XELOGI("Launching module..."); - Dump(); + // Grab some important variables... + auto header = xex_header(); + uint32_t exe_stack_size = 0; + uint32_t exe_entry_point = 0; + XexModule::GetOptHeader(xex_header(), XEX_HEADER_DEFAULT_STACK_SIZE, + (void**)&exe_stack_size); + XexModule::GetOptHeader(xex_header(), XEX_HEADER_ENTRY_POINT, + (void**)&exe_entry_point); + // Create a thread to run in. - auto thread = - object_ref(new XThread(kernel_state(), header->exe_stack_size, 0, - header->exe_entry_point, 0, 0)); + auto thread = object_ref( + new XThread(kernel_state(), exe_stack_size, 0, exe_entry_point, 0, 0)); X_STATUS result = thread->Create(); if (XFAILED(result)) { @@ -206,11 +232,14 @@ X_STATUS XUserModule::Launch(uint32_t flags) { void XUserModule::Dump() { xe::cpu::ExportResolver* export_resolver = kernel_state_->emulator()->export_resolver(); - const xe_xex2_header_t* header = xe_xex2_get_header(xex_); + auto header = xex_header(); + + // TODO: Need to loop through the optional headers one-by-one. // XEX info. printf("Module %s:\n\n", path_.c_str()); printf(" Module Flags: %.8X\n", header->module_flags); + /* printf(" System Flags: %.8X\n", header->system_flags); printf("\n"); printf(" Address: %.8X\n", header->exe_address); @@ -249,7 +278,7 @@ void XUserModule::Dump() { printf("\n"); printf(" Headers:\n"); for (size_t n = 0; n < header->header_count; n++) { - const xe_xex2_opt_header_t* opt_header = &header->headers[n]; + const xex2_opt_header* opt_header = &header->headers[n]; printf(" %.8X (%.8X, %4db) %.8X = %11d\n", opt_header->key, opt_header->offset, opt_header->length, opt_header->value, opt_header->value); @@ -440,6 +469,7 @@ void XUserModule::Dump() { printf("\n"); } + */ } } // namespace kernel diff --git a/src/xenia/kernel/objects/xuser_module.h b/src/xenia/kernel/objects/xuser_module.h index 54ed496fe..588c7d875 100644 --- a/src/xenia/kernel/objects/xuser_module.h +++ b/src/xenia/kernel/objects/xuser_module.h @@ -13,15 +13,12 @@ #include #include "xenia/cpu/export_resolver.h" +#include "xenia/cpu/xex_module.h" #include "xenia/kernel/objects/xmodule.h" -#include "xenia/kernel/util/xex2.h" +#include "xenia/kernel/util/xex2_info.h" #include "xenia/xbox.h" namespace xe { -namespace cpu { -class XexModule; -} // namespace cpu - namespace kernel { class XUserModule : public XModule { @@ -29,11 +26,15 @@ class XUserModule : public XModule { XUserModule(KernelState* kernel_state, const char* path); ~XUserModule() override; - const xe_xex2_header_t* xex_header(); const xe::cpu::XexModule* xex_module() const { return reinterpret_cast(processor_module_); } + const xex2_header* xex_header() const { return xex_module()->xex_header(); } + + uint32_t entry_point() const { return entry_point_; } + uint32_t stack_size() const { return stack_size_; } + X_STATUS LoadFromFile(std::string path); X_STATUS LoadFromMemory(const void* addr, const size_t length); @@ -42,6 +43,8 @@ class XUserModule : public XModule { X_STATUS GetSection(const char* name, uint32_t* out_section_data, uint32_t* out_section_size) override; + X_STATUS GetOptHeader(xe_xex2_header_keys key, void** out_ptr); + X_STATUS GetOptHeader(xe_xex2_header_keys key, uint32_t* out_header_guest_ptr); static X_STATUS GetOptHeader(uint8_t* membase, const xex2_header* header, @@ -53,8 +56,10 @@ class XUserModule : public XModule { void Dump(); private: - xe_xex2_ref xex_; uint32_t guest_xex_header_; + + uint32_t entry_point_; + uint32_t stack_size_; }; } // namespace kernel diff --git a/src/xenia/kernel/util/xex2_info.h b/src/xenia/kernel/util/xex2_info.h index 7a3ecd0b1..afd1ea087 100644 --- a/src/xenia/kernel/util/xex2_info.h +++ b/src/xenia/kernel/util/xex2_info.h @@ -480,6 +480,26 @@ union xex2_version { }; }; +struct xex2_opt_tls_info { + xe::be slot_count; // 0x0 + xe::be raw_data_address; // 0x4 + xe::be data_size; // 0x8 + xe::be raw_data_size; // 0xC +}; +static_assert_size(xex2_opt_tls_info, 0x10); + +struct xex2_resource { + char name[8]; // 0x0 + xe::be address; // 0x8 + xe::be size; // 0xC +}; +static_assert_size(xex2_resource, 0x10); + +struct xex2_opt_resource_info { + xe::be size; // 0x0 Resource count is (size - 4) / 16 + xex2_resource resources[1]; // 0x4 +}; + struct xex2_opt_delta_patch_descriptor { xe::be size; // 0x0 xex2_version target_version; // 0x4 diff --git a/src/xenia/kernel/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl_modules.cc index e31afa7ec..9b1889e08 100644 --- a/src/xenia/kernel/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl_modules.cc @@ -142,10 +142,10 @@ SHIM_CALL XexCheckExecutablePrivilege_shim(PPCContext* ppc_context, return; } - auto header = module->xex_header(); - uint32_t result = (header->system_flags & mask) > 0; + uint32_t flags = 0; + module->GetOptHeader(XEX_HEADER_SYSTEM_FLAGS, (void **)&flags); - SHIM_SET_RETURN_32(result); + SHIM_SET_RETURN_32((flags & mask) > 0); } SHIM_CALL XexGetModuleHandle_shim(PPCContext* ppc_context, diff --git a/src/xenia/kernel/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl_threading.cc index 1eee343d7..d24aa08f4 100644 --- a/src/xenia/kernel/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl_threading.cc @@ -109,8 +109,7 @@ SHIM_CALL ExCreateThread_shim(PPCContext* ppc_context, // Inherit default stack size if (stack_size == 0) { - stack_size = - kernel_state->GetExecutableModule()->xex_header()->exe_stack_size; + stack_size = kernel_state->GetExecutableModule()->stack_size(); } // Stack must be aligned to 16kb pages