diff --git a/src/xenia/base/byte_order.h b/src/xenia/base/byte_order.h index 5aed576f7..ef875145e 100644 --- a/src/xenia/base/byte_order.h +++ b/src/xenia/base/byte_order.h @@ -83,6 +83,32 @@ 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; }; diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index a43189102..d7e581775 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. @@ -190,6 +191,17 @@ void KernelState::SetExecutableModule(object_ref module) { 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/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..d6951b63b 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,17 @@ 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 +92,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 bb50d8cac..d9a47d24b 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_; } @@ -94,20 +89,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. @@ -148,6 +144,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 3ea84b315..74dc1c47b 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); @@ -37,6 +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 Launch(uint32_t flags); @@ -44,7 +44,7 @@ class XUserModule : public XModule { private: xe_xex2_ref xex_; - uint32_t execution_info_ptr_; + uint32_t xex_header_; }; } // namespace kernel diff --git a/src/xenia/kernel/util/xex2.cc b/src/xenia/kernel/util/xex2.cc index 2c816f312..25c5b4fd5 100644 --- a/src/xenia/kernel/util/xex2.cc +++ b/src/xenia/kernel/util/xex2.cc @@ -27,6 +27,33 @@ #include "xenia/base/memory.h" #include "xenia/base/platform.h" +namespace xe { +namespace kernel { +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 +} // namespace xe + // TODO(benvanik): remove. #define XEEXPECTZERO(expr) \ if ((expr) != 0) { \ @@ -126,7 +153,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 +383,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..87999ae98 100644 --- a/src/xenia/kernel/util/xex2.h +++ b/src/xenia/kernel/util/xex2.h @@ -13,6 +13,14 @@ #include "xenia/kernel/util/xex2_info.h" #include "xenia/memory.h" +namespace xe { +namespace kernel { +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 + 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..4d0a5409f 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,55 @@ 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_ diff --git a/src/xenia/kernel/xam_info.cc b/src/xenia/kernel/xam_info.cc index 7121d056e..d503ea7d1 100644 --- a/src/xenia/kernel/xam_info.cc +++ b/src/xenia/kernel/xam_info.cc @@ -77,9 +77,17 @@ 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, 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_modules.cc b/src/xenia/kernel/xboxkrnl_modules.cc index ad9c1786d..468cb8c71 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, - 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)", 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; diff --git a/src/xenia/kernel/xboxkrnl_rtl.cc b/src/xenia/kernel/xboxkrnl_rtl.cc index 1045506e9..0ff82a422 100644 --- a/src/xenia/kernel/xboxkrnl_rtl.cc +++ b/src/xenia/kernel/xboxkrnl_rtl.cc @@ -385,55 +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(); - - // Special case. - if (image_field == XEX_HEADER_EXECUTION_INFO) { - SHIM_SET_RETURN_32(module->execution_info_ptr()); + auto header = + kernel_memory()->TranslateVirtual(xex_header_base); + if (!header) { + SHIM_SET_RETURN_32(X_STATUS_UNSUCCESSFUL); 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) { - uint32_t value = xex_header->headers[n].value; - SHIM_SET_RETURN_32(value); - return; - } + uint8_t* hdr = xex2_get_opt_header(header, image_field); + if (!hdr) { + SHIM_SET_RETURN_32(X_STATUS_NOT_FOUND); + 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; - } + SHIM_SET_RETURN_32((uint32_t)(hdr - kernel_memory()->virtual_membase())); } // Unfortunately the Windows RTL_CRITICAL_SECTION object is bigger than the one 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;