From c228c0fa73ad7ac7164565ca9b83fd9d77ef3ac0 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sat, 27 Jun 2015 21:32:16 -0500 Subject: [PATCH 1/9] Add some native xex2 structs and handling functions --- src/xenia/kernel/util/xex2.cc | 34 +++++++++++++++++-- src/xenia/kernel/util/xex2.h | 9 ++++++ src/xenia/kernel/util/xex2_info.h | 54 +++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 3 deletions(-) diff --git a/src/xenia/kernel/util/xex2.cc b/src/xenia/kernel/util/xex2.cc index ab8d594e4..3eccb68cf 100644 --- a/src/xenia/kernel/util/xex2.cc +++ b/src/xenia/kernel/util/xex2.cc @@ -27,6 +27,34 @@ #include "xenia/base/memory.h" #include "xenia/base/platform.h" +namespace xe { +namespace kernel { +template +T* xex2_get_opt_header(const xex2_header* header, uint32_t key) { + for (int i = 0; i < header->header_count; i++) { + const xex2_opt_header* opt_header = header->headers[i]; + if (opt_header->key != key) { + continue; + } + + if ((opt_header->key & 0xFF) == 0x01) { + // Data is stored in the opt header + return (T*)&opt_header->value; + } else { + // Data stored at offset. + return (T*)((uint8_t*)&header->headers[0] + opt_header->offset); + } + } + + return nullptr; +} + +uint32_t xex2_get_header_size(const xex2_header* header) { + return header->exe_offset; +} +} // namespace kernel +} // namespace xe + // TODO(benvanik): remove. #define XEEXPECTZERO(expr) \ if ((expr) != 0) { \ @@ -126,7 +154,7 @@ int xe_xex2_read_header(const uint8_t *addr, const size_t length, xe_xex2_loader_info_t *ldr; header->xex2 = xe::load_and_swap(p + 0x00); - if (header->xex2 != 0x58455832) { + if (header->xex2 != 'XEX2') { return 1; } @@ -356,8 +384,8 @@ int xe_xex2_read_header(const uint8_t *addr, const size_t length, uint32_t window_size = xe::load_and_swap(pp + 0x08); uint32_t window_bits = 0; for (size_t m = 0; m < 32; m++, window_bits++) { - window_size <<= 1; - if (window_size == 0x80000000) { + window_size >>= 1; + if (window_size == 0x00000000) { break; } } diff --git a/src/xenia/kernel/util/xex2.h b/src/xenia/kernel/util/xex2.h index c2c808c6e..536781ceb 100644 --- a/src/xenia/kernel/util/xex2.h +++ b/src/xenia/kernel/util/xex2.h @@ -13,6 +13,15 @@ #include "xenia/kernel/util/xex2_info.h" #include "xenia/memory.h" +namespace xe { +namespace kernel { +template +T* xex2_get_opt_header(const xex2_header* header, uint32_t key); + +uint32_t xex2_get_header_size(const xex2_header* header); +} // namespace kernel +} // namespace xe + typedef struct { int reserved; } xe_xex2_options_t; struct xe_xex2; diff --git a/src/xenia/kernel/util/xex2_info.h b/src/xenia/kernel/util/xex2_info.h index f3a467f46..fa1281935 100644 --- a/src/xenia/kernel/util/xex2_info.h +++ b/src/xenia/kernel/util/xex2_info.h @@ -12,6 +12,8 @@ #include +#include "xenia/base/byte_order.h" + typedef enum { XEX_HEADER_RESOURCE_INFO = 0x000002FF, XEX_HEADER_FILE_FORMAT_INFO = 0x000003FF, @@ -467,4 +469,56 @@ typedef struct { xe_xex2_section_t* sections; } xe_xex2_header_t; +namespace xe { +namespace kernel { +union xex2_version { + uint32_t value; + struct { + uint32_t major : 4; + uint32_t minor : 4; + uint32_t build : 16; + uint32_t qfe : 8; + }; +}; + +struct xex2_opt_execution_info { + xe::be media_id; // 0x0 + xe::be version; // 0x4 + xe::be base_version; // 0x8 + xe::be title_id; // 0xC + uint8_t platform; // 0x10 + uint8_t executable_table; // 0x11 + uint8_t disc_number; // 0x12 + uint8_t disc_count; // 0x13 + xe::be savegame_id; // 0x14 +}; + +struct xex2_opt_header { + xe::be key; // 0x0 + + union { + xe::be value; // 0x4 + xe::be offset; // 0x8 + }; +}; + +struct xex2_header { + xe::be magic; // 0x0 'XEX2' + xe::be module_flags; // 0x4 + xe::be exe_offset; // 0x8 + xe::be reserved; // 0xC + xe::be certificate_offset; // 0x10 + xe::be header_count; // 0x14 + + xex2_opt_header headers[1]; // 0x18 +}; + +struct xex2_loader_info { + xe::be header_size; + xe::be image_size; + +}; +} // namespace kernel +} // namespace xe + #endif // XENIA_KERNEL_XEX2_INFO_H_ From 1289e7ad2228220d0eee61ed8db5ebcdf646db1f Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sat, 27 Jun 2015 21:47:47 -0500 Subject: [PATCH 2/9] xe::be basic arithmetic operators --- src/xenia/base/byte_order.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/xenia/base/byte_order.h b/src/xenia/base/byte_order.h index 5aed576f7..0f1078317 100644 --- a/src/xenia/base/byte_order.h +++ b/src/xenia/base/byte_order.h @@ -83,6 +83,14 @@ struct be { be(const T &src) : value(xe::byte_swap(src)) {} be(const be &other) { value = other.value; } operator T() const { return xe::byte_swap(value); } + + be& operator+=(int a) { *this = *this + a; return *this; } + be& operator-=(int a) { *this = *this - a; return *this; } + be& operator++() { *this += 1; return *this; } // ++a + be operator++(int) { *this += 1; return (*this - 1); } // a++ + be& operator--() { *this -= 1; return *this; } // --a + be operator--(int) { *this -= 1; return (*this + 1); } // a-- + T value; }; From 7372dd4d8d5520a5461ac994000a18847df26d90 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sat, 27 Jun 2015 22:00:58 -0500 Subject: [PATCH 3/9] Use HMODULE instead of handles for xex modules --- src/xenia/kernel/objects/xmodule.cc | 30 ++++++++++- src/xenia/kernel/objects/xmodule.h | 42 +++++++++++++++ src/xenia/kernel/objects/xuser_module.cc | 29 ++++++----- src/xenia/kernel/objects/xuser_module.h | 1 + src/xenia/kernel/xboxkrnl_modules.cc | 65 +++++++++++++++--------- 5 files changed, 126 insertions(+), 41 deletions(-) diff --git a/src/xenia/kernel/objects/xmodule.cc b/src/xenia/kernel/objects/xmodule.cc index db2dd1e87..28d5e1d3d 100644 --- a/src/xenia/kernel/objects/xmodule.cc +++ b/src/xenia/kernel/objects/xmodule.cc @@ -20,7 +20,8 @@ XModule::XModule(KernelState* kernel_state, ModuleType module_type, : XObject(kernel_state, kTypeModule), module_type_(module_type), path_(path), - processor_module_(nullptr) { + processor_module_(nullptr), + hmodule_ptr_(0) { auto last_slash = path.find_last_of('/'); if (last_slash == path.npos) { last_slash = path.find_last_of('\\'); @@ -34,9 +35,22 @@ XModule::XModule(KernelState* kernel_state, ModuleType module_type, if (dot != name_.npos) { name_ = name_.substr(0, dot); } + + // Loader data (HMODULE) + hmodule_ptr_ = memory()->SystemHeapAlloc(sizeof(X_LDR_DATA_TABLE_ENTRY)); + + // Hijack the checksum field to store our kernel object handle. + auto ldr_data = + memory()->TranslateVirtual(hmodule_ptr_); + ldr_data->checksum = handle(); } -XModule::~XModule() { kernel_state_->UnregisterModule(this); } +XModule::~XModule() { + kernel_state_->UnregisterModule(this); + + // Destroy the loader data. + memory()->SystemHeapFree(hmodule_ptr_); +} bool XModule::Matches(const std::string& name) const { if (strcasecmp(xe::find_name_from_path(path_).c_str(), name.c_str()) == 0) { @@ -58,5 +72,17 @@ X_STATUS XModule::GetSection(const char* name, uint32_t* out_section_data, return X_STATUS_UNSUCCESSFUL; } +object_ref XModule::GetFromHModule(KernelState* kernel_state, + void* hmodule) { + // Grab the object from our stashed kernel handle + return kernel_state->object_table()->LookupObject( + GetHandleFromHModule(hmodule)); +} + +uint32_t XModule::GetHandleFromHModule(void* hmodule) { + auto ldr_data = reinterpret_cast(hmodule); + return ldr_data->checksum; +} + } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/objects/xmodule.h b/src/xenia/kernel/objects/xmodule.h index 5c62c2d50..b6cc047a2 100644 --- a/src/xenia/kernel/objects/xmodule.h +++ b/src/xenia/kernel/objects/xmodule.h @@ -19,6 +19,42 @@ namespace xe { namespace kernel { +// http://www.nirsoft.net/kernel_struct/vista/LDR_DATA_TABLE_ENTRY.html +// HMODULE points to this struct! +struct X_LDR_DATA_TABLE_ENTRY { + X_LIST_ENTRY in_load_order_links; // 0x0 + X_LIST_ENTRY in_memory_order_links; // 0x8 + X_LIST_ENTRY in_initialization_order_links; // 0x10 + + xe::be dll_base; // 0x18 + xe::be image_base; // 0x1C + xe::be image_size; // 0x20 + + X_UNICODE_STRING full_dll_name; // 0x24 + X_UNICODE_STRING base_dll_name; // 0x2C + + xe::be flags; // 0x34 + xe::be full_image_size; // 0x38 + xe::be entry_point; // 0x3C + xe::be load_count; // 0x40 + xe::be module_index; // 0x42 + xe::be dll_base_original; // 0x44 + xe::be checksum; // 0x48 hijacked to hold kernel handle + xe::be load_flags; // 0x4C + xe::be time_date_stamp; // 0x50 + xe::be loaded_imports; // 0x54 + xe::be xex_header_base; // 0x58 + + union { + X_ANSI_STRING load_file_name; // 0x5C + + struct { + xe::be closure_root; // 0x5C + xe::be traversal_parent; // 0x60 + }; + }; +}; + class XModule : public XObject { public: enum class ModuleType { @@ -37,12 +73,16 @@ class XModule : public XObject { bool Matches(const std::string& name) const; xe::cpu::Module* processor_module() const { return processor_module_; } + uint32_t hmodule_ptr() const { return hmodule_ptr_; } virtual uint32_t GetProcAddressByOrdinal(uint16_t ordinal) = 0; virtual uint32_t GetProcAddressByName(const char* name) = 0; virtual X_STATUS GetSection(const char* name, uint32_t* out_section_data, uint32_t* out_section_size); + static object_ref GetFromHModule(KernelState* kernel_state, void* hmodule); + static uint32_t GetHandleFromHModule(void* hmodule); + protected: void OnLoad(); @@ -51,6 +91,8 @@ class XModule : public XObject { std::string path_; xe::cpu::Module* processor_module_; + + uint32_t hmodule_ptr_; // This points to LDR_DATA_TABLE_ENTRY. }; } // namespace kernel diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index a8b533e2b..e52d2d319 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -101,20 +101,21 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) { return X_STATUS_UNSUCCESSFUL; } - // Store execution info for later use. - // TODO(benvanik): just put entire xex header in memory somewhere? - execution_info_ptr_ = memory()->SystemHeapAlloc(24); - auto eip = memory()->TranslateVirtual(execution_info_ptr_); - const auto& ex = xe_xex2_get_header(xex_)->execution_info; - xe::store_and_swap(eip + 0x00, ex.media_id); - xe::store_and_swap(eip + 0x04, ex.version.value); - xe::store_and_swap(eip + 0x08, ex.base_version.value); - xe::store_and_swap(eip + 0x0C, ex.title_id); - xe::store_and_swap(eip + 0x10, ex.platform); - xe::store_and_swap(eip + 0x11, ex.executable_table); - xe::store_and_swap(eip + 0x12, ex.disc_number); - xe::store_and_swap(eip + 0x13, ex.disc_count); - xe::store_and_swap(eip + 0x14, ex.savegame_id); + // Copy the xex2 header into guest memory + const xex2_header* header = reinterpret_cast(addr); + uint32_t header_size = xex2_get_header_size(header); + + xex_header_ = memory()->SystemHeapAlloc(header_size); + + uint8_t* xex_header_ptr = memory()->TranslateVirtual(xex_header_); + std::memcpy(xex_header_ptr, header, header_size); + + // Setup the loader data entry + auto ldr_data = + memory()->TranslateVirtual(hmodule_ptr_); + + ldr_data->dll_base = 0; // GetProcAddress will read this. + ldr_data->xex_header_base = xex_header_; // Prepare the module for execution. // Runtime takes ownership. diff --git a/src/xenia/kernel/objects/xuser_module.h b/src/xenia/kernel/objects/xuser_module.h index 3ea84b315..c312433e1 100644 --- a/src/xenia/kernel/objects/xuser_module.h +++ b/src/xenia/kernel/objects/xuser_module.h @@ -44,6 +44,7 @@ class XUserModule : public XModule { private: xe_xex2_ref xex_; + uint32_t xex_header_; uint32_t execution_info_ptr_; }; diff --git a/src/xenia/kernel/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl_modules.cc index ad9c1786d..ac03cce32 100644 --- a/src/xenia/kernel/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl_modules.cc @@ -153,9 +153,9 @@ SHIM_CALL XexGetModuleHandle_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t module_name_ptr = SHIM_GET_ARG_32(0); const char* module_name = (const char*)SHIM_MEM_ADDR(module_name_ptr); - uint32_t module_handle_ptr = SHIM_GET_ARG_32(1); + uint32_t hmodule_ptr = SHIM_GET_ARG_32(1); - XELOGD("XexGetModuleHandle(%s, %.8X)", module_name, module_handle_ptr); + XELOGD("XexGetModuleHandle(%s, %.8X)", module_name, hmodule_ptr); object_ref module; if (!module_name) { @@ -164,31 +164,31 @@ SHIM_CALL XexGetModuleHandle_shim(PPCContext* ppc_context, module = kernel_state->GetModule(module_name); } if (!module) { - SHIM_SET_MEM_32(module_handle_ptr, 0); + SHIM_SET_MEM_32(hmodule_ptr, 0); SHIM_SET_RETURN_32(X_ERROR_NOT_FOUND); return; } // NOTE: we don't retain the handle for return. - SHIM_SET_MEM_32(module_handle_ptr, module->handle()); + SHIM_SET_MEM_32(hmodule_ptr, module->hmodule_ptr()); SHIM_SET_RETURN_32(X_ERROR_SUCCESS); } SHIM_CALL XexGetModuleSection_shim(PPCContext* ppc_context, KernelState* kernel_state) { - uint32_t handle = SHIM_GET_ARG_32(0); + uint32_t hmodule = SHIM_GET_ARG_32(0); uint32_t name_ptr = SHIM_GET_ARG_32(1); const char* name = (const char*)SHIM_MEM_ADDR(name_ptr); uint32_t data_ptr = SHIM_GET_ARG_32(2); uint32_t size_ptr = SHIM_GET_ARG_32(3); - XELOGD("XexGetModuleSection(%.8X, %s, %.8X, %.8X)", handle, name, data_ptr, + XELOGD("XexGetModuleSection(%.8X, %s, %.8X, %.8X)", hmodule, name, data_ptr, size_ptr); X_STATUS result = X_STATUS_SUCCESS; - auto module = kernel_state->object_table()->LookupObject(handle); + auto module = XModule::GetFromHModule(kernel_state, SHIM_MEM_ADDR(hmodule)); if (module) { uint32_t section_data = 0; uint32_t section_size = 0; @@ -210,49 +210,64 @@ SHIM_CALL XexLoadImage_shim(PPCContext* ppc_context, const char* module_name = (const char*)SHIM_MEM_ADDR(module_name_ptr); uint32_t module_flags = SHIM_GET_ARG_32(1); uint32_t min_version = SHIM_GET_ARG_32(2); - uint32_t handle_ptr = SHIM_GET_ARG_32(3); + uint32_t hmodule_ptr = SHIM_GET_ARG_32(3); XELOGD("XexLoadImage(%s, %.8X, %.8X, %.8X)", module_name, module_flags, - min_version, handle_ptr); + min_version, hmodule_ptr); X_STATUS result = X_STATUS_NO_SUCH_FILE; - X_HANDLE module_handle = X_INVALID_HANDLE_VALUE; + uint32_t hmodule = 0; auto module = kernel_state->GetModule(module_name); if (module) { - // Existing module found, just add a reference and obtain a handle. - result = - kernel_state->object_table()->AddHandle(module.get(), &module_handle); + // Existing module found. + hmodule = module->hmodule_ptr(); } else { // Not found; attempt to load as a user module. auto user_module = kernel_state->LoadUserModule(module_name); if (user_module) { user_module->RetainHandle(); - module_handle = user_module->handle(); + hmodule = user_module->hmodule_ptr(); result = X_STATUS_SUCCESS; } } - SHIM_SET_MEM_32(handle_ptr, module_handle); + + // Increment the module's load count. + auto ldr_data = + kernel_memory()->TranslateVirtual(hmodule); + ldr_data->load_count++; + + SHIM_SET_MEM_32(hmodule_ptr, hmodule); SHIM_SET_RETURN_32(result); } SHIM_CALL XexUnloadImage_shim(PPCContext* ppc_context, KernelState* kernel_state) { - uint32_t module_handle = SHIM_GET_ARG_32(0); + uint32_t hmodule = SHIM_GET_ARG_32(0); - XELOGD("XexUnloadImage(%.8X)", module_handle); + XELOGD("XexUnloadImage(%.8X)", hmodule); - X_STATUS result = X_STATUS_INVALID_HANDLE; + auto module = XModule::GetFromHModule(kernel_state, SHIM_MEM_ADDR(hmodule)); + if (!module) { + SHIM_SET_RETURN_32(X_STATUS_INVALID_HANDLE); + return; + } - result = kernel_state->object_table()->RemoveHandle(module_handle); + auto ldr_data = + kernel_state->memory()->TranslateVirtual( + hmodule); + if (ldr_data->load_count-- <= 0) { + // No more references, free it. + kernel_state->object_table()->RemoveHandle(module->handle()); + } - SHIM_SET_RETURN_32(result); + SHIM_SET_RETURN_32(X_STATUS_SUCCESS); } SHIM_CALL XexGetProcedureAddress_shim(PPCContext* ppc_context, KernelState* kernel_state) { - uint32_t module_handle = SHIM_GET_ARG_32(0); + uint32_t hmodule = SHIM_GET_ARG_32(0); uint32_t ordinal = SHIM_GET_ARG_32(1); uint32_t out_function_ptr = SHIM_GET_ARG_32(2); @@ -263,20 +278,20 @@ SHIM_CALL XexGetProcedureAddress_shim(PPCContext* ppc_context, auto string_name = reinterpret_cast(SHIM_MEM_ADDR(ordinal)); if (is_string_name) { - XELOGD("XexGetProcedureAddress(%.8X, %.8X(%s), %.8X)", module_handle, + XELOGD("XexGetProcedureAddress(%.8X, %.8X(%s), %.8X)", hmodule, ordinal, string_name, out_function_ptr); } else { - XELOGD("XexGetProcedureAddress(%.8X, %.8X, %.8X)", module_handle, ordinal, + XELOGD("XexGetProcedureAddress(%.8X, %.8X, %.8X)", hmodule, ordinal, out_function_ptr); } X_STATUS result = X_STATUS_INVALID_HANDLE; object_ref module; - if (!module_handle) { + if (!hmodule) { module = kernel_state->GetExecutableModule(); } else { - module = kernel_state->object_table()->LookupObject(module_handle); + module = XModule::GetFromHModule(kernel_state, SHIM_MEM_ADDR(hmodule)); } if (module) { uint32_t ptr; From 169cb65d967f1c8f86d8d9cc66011d047cab6bf1 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sat, 27 Jun 2015 22:08:52 -0500 Subject: [PATCH 4/9] Remove unused execution_info_ptr --- src/xenia/kernel/objects/xuser_module.h | 3 --- src/xenia/kernel/util/xex2.cc | 20 -------------------- src/xenia/kernel/util/xex2.h | 21 +++++++++++++++++++-- src/xenia/kernel/xboxkrnl_rtl.cc | 6 ------ 4 files changed, 19 insertions(+), 31 deletions(-) diff --git a/src/xenia/kernel/objects/xuser_module.h b/src/xenia/kernel/objects/xuser_module.h index c312433e1..03ad4c389 100644 --- a/src/xenia/kernel/objects/xuser_module.h +++ b/src/xenia/kernel/objects/xuser_module.h @@ -28,8 +28,6 @@ class XUserModule : public XModule { xe_xex2_ref xex(); const xe_xex2_header_t* xex_header(); - uint32_t execution_info_ptr() const { return execution_info_ptr_; } - X_STATUS LoadFromFile(std::string path); X_STATUS LoadFromMemory(const void* addr, const size_t length); @@ -45,7 +43,6 @@ class XUserModule : public XModule { private: xe_xex2_ref xex_; uint32_t xex_header_; - uint32_t execution_info_ptr_; }; } // namespace kernel diff --git a/src/xenia/kernel/util/xex2.cc b/src/xenia/kernel/util/xex2.cc index 3eccb68cf..36f17fb4b 100644 --- a/src/xenia/kernel/util/xex2.cc +++ b/src/xenia/kernel/util/xex2.cc @@ -29,26 +29,6 @@ namespace xe { namespace kernel { -template -T* xex2_get_opt_header(const xex2_header* header, uint32_t key) { - for (int i = 0; i < header->header_count; i++) { - const xex2_opt_header* opt_header = header->headers[i]; - if (opt_header->key != key) { - continue; - } - - if ((opt_header->key & 0xFF) == 0x01) { - // Data is stored in the opt header - return (T*)&opt_header->value; - } else { - // Data stored at offset. - return (T*)((uint8_t*)&header->headers[0] + opt_header->offset); - } - } - - return nullptr; -} - uint32_t xex2_get_header_size(const xex2_header* header) { return header->exe_offset; } diff --git a/src/xenia/kernel/util/xex2.h b/src/xenia/kernel/util/xex2.h index 536781ceb..82380daee 100644 --- a/src/xenia/kernel/util/xex2.h +++ b/src/xenia/kernel/util/xex2.h @@ -15,8 +15,25 @@ namespace xe { namespace kernel { -template -T* xex2_get_opt_header(const xex2_header* header, uint32_t key); +template +T* xex2_get_opt_header(const xex2_header* header, uint32_t key) { + for (uint32_t i = 0; i < header->header_count; i++) { + const xex2_opt_header& opt_header = header->headers[i]; + if (opt_header.key != key) { + continue; + } + + if ((opt_header.key & 0xFF) == 0x01) { + // Data is stored in the opt header + return (T*)&opt_header.value; + } else { + // Data stored at offset. + return (T*)((uint8_t*)&header->headers[0] + opt_header.offset); + } + } + + return nullptr; +} uint32_t xex2_get_header_size(const xex2_header* header); } // namespace kernel diff --git a/src/xenia/kernel/xboxkrnl_rtl.cc b/src/xenia/kernel/xboxkrnl_rtl.cc index 1045506e9..993344ec3 100644 --- a/src/xenia/kernel/xboxkrnl_rtl.cc +++ b/src/xenia/kernel/xboxkrnl_rtl.cc @@ -409,12 +409,6 @@ SHIM_CALL RtlImageXexHeaderField_shim(PPCContext* ppc_context, assert_true(xex_header_base == 0x80101100); auto module = kernel_state->GetExecutableModule(); - // Special case. - if (image_field == XEX_HEADER_EXECUTION_INFO) { - SHIM_SET_RETURN_32(module->execution_info_ptr()); - return; - } - const xe_xex2_header_t* xex_header = module->xex_header(); for (size_t n = 0; n < xex_header->header_count; n++) { if (xex_header->headers[n].key == image_field) { From cdbf73624160931dc03d3af01b9e5cc1954a2182 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sat, 27 Jun 2015 22:39:11 -0500 Subject: [PATCH 5/9] X_UNICODE_STRING --- src/xenia/xbox.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index 8479c307e..66ed575f7 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -288,6 +288,28 @@ struct X_ANSI_STRING { } }; +struct X_UNICODE_STRING { + xe::be length; + xe::be maximum_length; + xe::be pointer; + + void reset() { + length = 0; + maximum_length = 0; + pointer = 0; + } + + std::wstring to_string(uint8_t* membase) const { + if (!length) { + return L""; + } + + return std::wstring(reinterpret_cast(membase + pointer), + length); + } +}; +static_assert_size(X_UNICODE_STRING, 8); + // http://pastebin.com/SMypYikG typedef uint32_t XNotificationID; From 8a6c620fe7bfe743d5c3fd1c7465d07fc52280b6 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sat, 27 Jun 2015 22:41:09 -0500 Subject: [PATCH 6/9] XUserModule::GetOptHeader --- src/xenia/kernel/objects/xuser_module.cc | 29 +++++++++++++++++------- src/xenia/kernel/objects/xuser_module.h | 1 + src/xenia/kernel/util/xex2.cc | 21 ++++++++++++++++- src/xenia/kernel/util/xex2.h | 24 +++----------------- src/xenia/kernel/xam_info.cc | 11 +++++++-- 5 files changed, 54 insertions(+), 32 deletions(-) diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index e52d2d319..b4de37959 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -22,14 +22,9 @@ namespace kernel { using namespace xe::cpu; XUserModule::XUserModule(KernelState* kernel_state, const char* path) - : XModule(kernel_state, ModuleType::kUserModule, path), - xex_(nullptr), - execution_info_ptr_(0) {} + : XModule(kernel_state, ModuleType::kUserModule, path), xex_(nullptr) {} -XUserModule::~XUserModule() { - kernel_state()->memory()->SystemHeapFree(execution_info_ptr_); - xe_xex2_dealloc(xex_); -} +XUserModule::~XUserModule() { xe_xex2_dealloc(xex_); } xe_xex2_ref XUserModule::xex() { return xex_; } @@ -114,7 +109,7 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) { auto ldr_data = memory()->TranslateVirtual(hmodule_ptr_); - ldr_data->dll_base = 0; // GetProcAddress will read this. + ldr_data->dll_base = 0; // GetProcAddress will read this. ldr_data->xex_header_base = xex_header_; // Prepare the module for execution. @@ -156,6 +151,24 @@ X_STATUS XUserModule::GetSection(const char* name, uint32_t* out_section_data, return X_STATUS_UNSUCCESSFUL; } +X_STATUS XUserModule::GetOptHeader(xe_xex2_header_keys key, + uint32_t* out_header_guest_ptr) { + assert_not_null(out_header_guest_ptr); + + auto header = memory()->TranslateVirtual(xex_header_); + if (!header) { + return X_STATUS_UNSUCCESSFUL; + } + + auto ptr = xex2_get_opt_header(header, key); + if (!ptr) { + return X_STATUS_NOT_FOUND; + } + + *out_header_guest_ptr = (uint32_t)(ptr - memory()->virtual_membase()); + return X_STATUS_SUCCESS; +} + X_STATUS XUserModule::Launch(uint32_t flags) { const xe_xex2_header_t* header = xex_header(); diff --git a/src/xenia/kernel/objects/xuser_module.h b/src/xenia/kernel/objects/xuser_module.h index 03ad4c389..3026a02a7 100644 --- a/src/xenia/kernel/objects/xuser_module.h +++ b/src/xenia/kernel/objects/xuser_module.h @@ -35,6 +35,7 @@ class XUserModule : public XModule { uint32_t GetProcAddressByName(const char* name) override; 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, uint32_t* out_header_guest_ptr); X_STATUS Launch(uint32_t flags); diff --git a/src/xenia/kernel/util/xex2.cc b/src/xenia/kernel/util/xex2.cc index 36f17fb4b..2eea304be 100644 --- a/src/xenia/kernel/util/xex2.cc +++ b/src/xenia/kernel/util/xex2.cc @@ -29,7 +29,26 @@ namespace xe { namespace kernel { -uint32_t xex2_get_header_size(const xex2_header* header) { +uint8_t* xex2_get_opt_header(const xex2_header* header, uint32_t key) { + for (uint32_t i = 0; i < header->header_count; i++) { + const xex2_opt_header& opt_header = header->headers[i]; + if (opt_header.key != key) { + continue; + } + + if ((opt_header.key & 0xFF) == 0x01) { + // Data is stored in the opt header + return (uint8_t*)&opt_header.value; + } else { + // Data stored at offset. + return ((uint8_t*)&header->headers[0] + opt_header.offset); + } + } + + return nullptr; +} + +uint32_t xex2_get_header_size(const xex2_header *header) { return header->exe_offset; } } // namespace kernel diff --git a/src/xenia/kernel/util/xex2.h b/src/xenia/kernel/util/xex2.h index 82380daee..87999ae98 100644 --- a/src/xenia/kernel/util/xex2.h +++ b/src/xenia/kernel/util/xex2.h @@ -15,29 +15,11 @@ namespace xe { namespace kernel { -template -T* xex2_get_opt_header(const xex2_header* header, uint32_t key) { - for (uint32_t i = 0; i < header->header_count; i++) { - const xex2_opt_header& opt_header = header->headers[i]; - if (opt_header.key != key) { - continue; - } - - if ((opt_header.key & 0xFF) == 0x01) { - // Data is stored in the opt header - return (T*)&opt_header.value; - } else { - // Data stored at offset. - return (T*)((uint8_t*)&header->headers[0] + opt_header.offset); - } - } - - return nullptr; -} +uint8_t* xex2_get_opt_header(const xex2_header* header, uint32_t key); uint32_t xex2_get_header_size(const xex2_header* header); -} // namespace kernel -} // namespace xe +} // namespace kernel +} // namespace xe typedef struct { int reserved; } xe_xex2_options_t; diff --git a/src/xenia/kernel/xam_info.cc b/src/xenia/kernel/xam_info.cc index 7121d056e..e2cc7de17 100644 --- a/src/xenia/kernel/xam_info.cc +++ b/src/xenia/kernel/xam_info.cc @@ -77,9 +77,16 @@ SHIM_CALL XamGetExecutionId_shim(PPCContext* ppc_context, auto module = kernel_state->GetExecutableModule(); assert_not_null(module); - SHIM_SET_MEM_32(info_ptr, module->execution_info_ptr()); + uint32_t guest_hdr_ptr; + X_STATUS result = module->GetOptHeader(XEX_HEADER_EXECUTION_INFO, &guest_hdr_ptr); - SHIM_SET_RETURN_32(0); + if (XFAILED(result)) { + SHIM_SET_RETURN_32(result); + return; + } + + SHIM_SET_MEM_32(info_ptr, guest_hdr_ptr); + SHIM_SET_RETURN_32(X_STATUS_SUCCESS); } SHIM_CALL XamLoaderSetLaunchData_shim(PPCContext* ppc_context, From 944b39c51d8fedc5b6ef41f3b30c4e396bebc9d6 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sat, 27 Jun 2015 22:43:33 -0500 Subject: [PATCH 7/9] Apply some lint n' stuff --- src/xenia/base/byte_order.h | 30 ++++++++++++++++++++++------ src/xenia/kernel/objects/xmodule.h | 5 +++-- src/xenia/kernel/util/xex2_info.h | 5 ++--- src/xenia/kernel/xboxkrnl_modules.cc | 4 ++-- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/xenia/base/byte_order.h b/src/xenia/base/byte_order.h index 0f1078317..ef875145e 100644 --- a/src/xenia/base/byte_order.h +++ b/src/xenia/base/byte_order.h @@ -84,12 +84,30 @@ struct be { be(const be &other) { value = other.value; } operator T() const { return xe::byte_swap(value); } - be& operator+=(int a) { *this = *this + a; return *this; } - be& operator-=(int a) { *this = *this - a; return *this; } - be& operator++() { *this += 1; return *this; } // ++a - be operator++(int) { *this += 1; return (*this - 1); } // a++ - be& operator--() { *this -= 1; return *this; } // --a - be operator--(int) { *this -= 1; return (*this + 1); } // a-- + be &operator+=(int a) { + *this = *this + a; + return *this; + } + be &operator-=(int a) { + *this = *this - a; + return *this; + } + be &operator++() { + *this += 1; + return *this; + } // ++a + be operator++(int) { + *this += 1; + return (*this - 1); + } // a++ + be &operator--() { + *this -= 1; + return *this; + } // --a + be operator--(int) { + *this -= 1; + return (*this + 1); + } // a-- T value; }; diff --git a/src/xenia/kernel/objects/xmodule.h b/src/xenia/kernel/objects/xmodule.h index b6cc047a2..d6951b63b 100644 --- a/src/xenia/kernel/objects/xmodule.h +++ b/src/xenia/kernel/objects/xmodule.h @@ -80,7 +80,8 @@ class XModule : public XObject { virtual X_STATUS GetSection(const char* name, uint32_t* out_section_data, uint32_t* out_section_size); - static object_ref GetFromHModule(KernelState* kernel_state, void* hmodule); + static object_ref GetFromHModule(KernelState* kernel_state, + void* hmodule); static uint32_t GetHandleFromHModule(void* hmodule); protected: @@ -92,7 +93,7 @@ class XModule : public XObject { xe::cpu::Module* processor_module_; - uint32_t hmodule_ptr_; // This points to LDR_DATA_TABLE_ENTRY. + uint32_t hmodule_ptr_; // This points to LDR_DATA_TABLE_ENTRY. }; } // namespace kernel diff --git a/src/xenia/kernel/util/xex2_info.h b/src/xenia/kernel/util/xex2_info.h index fa1281935..4d0a5409f 100644 --- a/src/xenia/kernel/util/xex2_info.h +++ b/src/xenia/kernel/util/xex2_info.h @@ -516,9 +516,8 @@ struct xex2_header { struct xex2_loader_info { xe::be header_size; xe::be image_size; - }; -} // namespace kernel -} // namespace xe +} // namespace kernel +} // namespace xe #endif // XENIA_KERNEL_XEX2_INFO_H_ diff --git a/src/xenia/kernel/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl_modules.cc index ac03cce32..468cb8c71 100644 --- a/src/xenia/kernel/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl_modules.cc @@ -278,8 +278,8 @@ SHIM_CALL XexGetProcedureAddress_shim(PPCContext* ppc_context, auto string_name = reinterpret_cast(SHIM_MEM_ADDR(ordinal)); if (is_string_name) { - XELOGD("XexGetProcedureAddress(%.8X, %.8X(%s), %.8X)", hmodule, - ordinal, string_name, out_function_ptr); + XELOGD("XexGetProcedureAddress(%.8X, %.8X(%s), %.8X)", hmodule, ordinal, + string_name, out_function_ptr); } else { XELOGD("XexGetProcedureAddress(%.8X, %.8X, %.8X)", hmodule, ordinal, out_function_ptr); From bb900ba9db8dac4b944fa18710e6638b0fa0e003 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sat, 27 Jun 2015 23:17:56 -0500 Subject: [PATCH 8/9] XexExecutableModuleHandle export now points to the executing HMODULE --- src/xenia/kernel/kernel_state.cc | 12 +++++++ src/xenia/kernel/xboxkrnl_module.cc | 8 ----- src/xenia/kernel/xboxkrnl_rtl.cc | 49 +++++++---------------------- 3 files changed, 23 insertions(+), 46 deletions(-) diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index 3a56e8a88..019b890d5 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -68,6 +68,7 @@ KernelState::KernelState(Emulator* emulator) shared_kernel_state_ = this; process_info_block_address_ = memory_->SystemHeapAlloc(0x60); + auto pib = memory_->TranslateVirtual(process_info_block_address_); // TODO(benvanik): figure out what this list is. @@ -188,6 +189,17 @@ void KernelState::SetExecutableModule(object_ref module) { pib->tls_raw_data_size = header->tls_info.raw_data_size; pib->tls_slot_size = header->tls_info.slot_count * 4; } + + // Setup the kernel's XexExecutableModuleHandle field + auto exp = processor()->export_resolver()->GetExportByOrdinal( + "xboxkrnl.exe", ordinals::XexExecutableModuleHandle); + + if (exp) { + auto variable_ptr = + memory()->TranslateVirtual*>(exp->variable_ptr); + + *variable_ptr = module->hmodule_ptr(); + } } void KernelState::LoadKernelModule(object_ref kernel_module) { diff --git a/src/xenia/kernel/xboxkrnl_module.cc b/src/xenia/kernel/xboxkrnl_module.cc index 047f3da32..016da3eb9 100644 --- a/src/xenia/kernel/xboxkrnl_module.cc +++ b/src/xenia/kernel/xboxkrnl_module.cc @@ -89,17 +89,9 @@ XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state) // 0x80101058 <- pointer to xex header // 0x80101100 <- xex header base uint32_t ppXexExecutableModuleHandle = memory_->SystemHeapAlloc(4); - auto lppXexExecutableModuleHandle = - memory_->TranslateVirtual(ppXexExecutableModuleHandle); export_resolver_->SetVariableMapping("xboxkrnl.exe", ordinals::XexExecutableModuleHandle, ppXexExecutableModuleHandle); - uint32_t pXexExecutableModuleHandle = memory_->SystemHeapAlloc(256); - auto lpXexExecutableModuleHandle = - memory_->TranslateVirtual(pXexExecutableModuleHandle); - xe::store_and_swap(lppXexExecutableModuleHandle, - pXexExecutableModuleHandle); - xe::store_and_swap(lpXexExecutableModuleHandle + 0x58, 0x80101100); // ExLoadedCommandLine (char*) // The name of the xex. Not sure this is ever really used on real devices. diff --git a/src/xenia/kernel/xboxkrnl_rtl.cc b/src/xenia/kernel/xboxkrnl_rtl.cc index 993344ec3..0ff82a422 100644 --- a/src/xenia/kernel/xboxkrnl_rtl.cc +++ b/src/xenia/kernel/xboxkrnl_rtl.cc @@ -385,49 +385,22 @@ SHIM_CALL RtlImageXexHeaderField_shim(PPCContext* ppc_context, uint32_t xex_header_base = SHIM_GET_ARG_32(0); uint32_t image_field = SHIM_GET_ARG_32(1); - // NOTE: this is totally faked! - // We set the XexExecutableModuleHandle pointer to a block that has at offset - // 0x58 a pointer to our XexHeaderBase. If the value passed doesn't match - // then die. - // The only ImageField I've seen in the wild is - // 0x20401 (XEX_HEADER_DEFAULT_HEAP_SIZE), so that's all we'll support. - XELOGD("RtlImageXexHeaderField(%.8X, %.8X)", xex_header_base, image_field); - // PVOID - // PVOID XexHeaderBase - // DWORD ImageField - - // NOTE: this is totally faked! - // We set the XexExecutableModuleHandle pointer to a block that has at offset - // 0x58 a pointer to our XexHeaderBase. If the value passed doesn't match - // then die. - - // TODO(benvanik): use xex_header_base to dereference this. - // Right now we are only concerned with games making this call on their main - // module, so this hack is fine. - assert_true(xex_header_base == 0x80101100); - auto module = kernel_state->GetExecutableModule(); - - const xe_xex2_header_t* xex_header = module->xex_header(); - for (size_t n = 0; n < xex_header->header_count; n++) { - if (xex_header->headers[n].key == image_field) { - uint32_t value = xex_header->headers[n].value; - SHIM_SET_RETURN_32(value); - return; - } + auto header = + kernel_memory()->TranslateVirtual(xex_header_base); + if (!header) { + SHIM_SET_RETURN_32(X_STATUS_UNSUCCESSFUL); + return; } - // Some games seem to expect 0xC0000225 for not-found results, while - // others will explode if it's not zero. Maybe there are default headers? - switch (image_field) { - case 0x20401: // XEX_HEADER_DEFAULT_HEAP_SIZE - SHIM_SET_RETURN_32(0); - break; - default: - SHIM_SET_RETURN_32(X_STATUS_NOT_FOUND); - break; + uint8_t* hdr = xex2_get_opt_header(header, image_field); + if (!hdr) { + SHIM_SET_RETURN_32(X_STATUS_NOT_FOUND); + return; } + + SHIM_SET_RETURN_32((uint32_t)(hdr - kernel_memory()->virtual_membase())); } // Unfortunately the Windows RTL_CRITICAL_SECTION object is bigger than the one From c47c0b335411a7852b5482149642fef864f751cb Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 28 Jun 2015 12:26:51 -0500 Subject: [PATCH 9/9] Uhh, lint --- src/xenia/kernel/objects/xuser_module.h | 3 ++- src/xenia/kernel/util/xex2.cc | 8 ++++---- src/xenia/kernel/xam_info.cc | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/xenia/kernel/objects/xuser_module.h b/src/xenia/kernel/objects/xuser_module.h index 3026a02a7..74dc1c47b 100644 --- a/src/xenia/kernel/objects/xuser_module.h +++ b/src/xenia/kernel/objects/xuser_module.h @@ -35,7 +35,8 @@ class XUserModule : public XModule { uint32_t GetProcAddressByName(const char* name) override; 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, uint32_t* out_header_guest_ptr); + X_STATUS GetOptHeader(xe_xex2_header_keys key, + uint32_t* out_header_guest_ptr); X_STATUS Launch(uint32_t flags); diff --git a/src/xenia/kernel/util/xex2.cc b/src/xenia/kernel/util/xex2.cc index 2eea304be..5d64f15c6 100644 --- a/src/xenia/kernel/util/xex2.cc +++ b/src/xenia/kernel/util/xex2.cc @@ -29,19 +29,19 @@ namespace xe { namespace kernel { -uint8_t* xex2_get_opt_header(const xex2_header* header, uint32_t key) { +uint8_t *xex2_get_opt_header(const xex2_header *header, uint32_t key) { for (uint32_t i = 0; i < header->header_count; i++) { - const xex2_opt_header& opt_header = header->headers[i]; + const xex2_opt_header &opt_header = header->headers[i]; if (opt_header.key != key) { continue; } if ((opt_header.key & 0xFF) == 0x01) { // Data is stored in the opt header - return (uint8_t*)&opt_header.value; + return (uint8_t *)&opt_header.value; } else { // Data stored at offset. - return ((uint8_t*)&header->headers[0] + opt_header.offset); + return ((uint8_t *)&header->headers[0] + opt_header.offset); } } diff --git a/src/xenia/kernel/xam_info.cc b/src/xenia/kernel/xam_info.cc index e2cc7de17..d503ea7d1 100644 --- a/src/xenia/kernel/xam_info.cc +++ b/src/xenia/kernel/xam_info.cc @@ -78,7 +78,8 @@ SHIM_CALL XamGetExecutionId_shim(PPCContext* ppc_context, assert_not_null(module); uint32_t guest_hdr_ptr; - X_STATUS result = module->GetOptHeader(XEX_HEADER_EXECUTION_INFO, &guest_hdr_ptr); + X_STATUS result = + module->GetOptHeader(XEX_HEADER_EXECUTION_INFO, &guest_hdr_ptr); if (XFAILED(result)) { SHIM_SET_RETURN_32(result);