diff --git a/src/xenia/debug/protocols/ws/ws_client.cc b/src/xenia/debug/protocols/ws/ws_client.cc index 4795a92d8..52df46335 100644 --- a/src/xenia/debug/protocols/ws/ws_client.cc +++ b/src/xenia/debug/protocols/ws/ws_client.cc @@ -19,7 +19,7 @@ #include #include #include -#include +#include #if XE_PLATFORM(WIN32) // Required for wslay. @@ -219,7 +219,7 @@ int WSClient::PerformHandshake() { if (headers.find("GET /sessions") != std::string::npos) { Emulator* emulator = debug_server_->emulator(); KernelState* kernel_state = emulator->xboxkrnl()->kernel_state(); - XModule* module = kernel_state->GetExecutableModule(); + XUserModule* module = kernel_state->GetExecutableModule(); const xe_xex2_header_t* header = module->xex_header(); char title_id[9]; xesnprintfa(title_id, XECOUNT(title_id), "%.8X", diff --git a/src/xenia/kernel/kernel_module.cc b/src/xenia/kernel/kernel_module.cc deleted file mode 100644 index da4a48a20..000000000 --- a/src/xenia/kernel/kernel_module.cc +++ /dev/null @@ -1,27 +0,0 @@ -/** - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#include - -#include -#include - - -using namespace xe; -using namespace xe::kernel; - - -KernelModule::KernelModule(Emulator* emulator, KernelState* kernel_state) : - emulator_(emulator), kernel_state_(kernel_state), - memory_(emulator->memory()) { - export_resolver_ = emulator->export_resolver(); -} - -KernelModule::~KernelModule() { -} diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index 19dff73d7..e2f338bec 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -10,10 +10,13 @@ #include #include +#include +#include #include #include #include #include +#include using namespace xe; @@ -55,12 +58,22 @@ KernelState* KernelState::shared() { } XModule* KernelState::GetModule(const char* name) { - // TODO(benvanik): implement lookup. Most games seem to look for xam.xex/etc. - XEASSERTALWAYS(); - return NULL; + if (xestrcasecmpa(name, "xam.xex") == 0) { + auto module = emulator_->xam(); + module->Retain(); + return module; + } else if (xestrcasecmpa(name, "xboxkrnl.exe") == 0) { + auto module = emulator_->xboxkrnl(); + module->Retain(); + return module; + } else { + // TODO(benvanik): support user modules/loading/etc. + XEASSERTALWAYS(); + return NULL; + } } -XModule* KernelState::GetExecutableModule() { +XUserModule* KernelState::GetExecutableModule() { if (!executable_module_) { return NULL; } @@ -69,7 +82,7 @@ XModule* KernelState::GetExecutableModule() { return executable_module_; } -void KernelState::SetExecutableModule(XModule* module) { +void KernelState::SetExecutableModule(XUserModule* module) { if (module == executable_module_) { return; } diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index 663cdd5f0..94b6dc673 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -15,14 +15,15 @@ #include #include -#include #include #include +XEDECLARECLASS1(xe, Emulator); XEDECLARECLASS2(xe, cpu, Processor); XEDECLARECLASS2(xe, kernel, XModule); XEDECLARECLASS2(xe, kernel, XThread); +XEDECLARECLASS2(xe, kernel, XUserModule); XEDECLARECLASS3(xe, kernel, fs, FileSystem); @@ -45,8 +46,8 @@ public: ObjectTable* object_table() const { return object_table_; } XModule* GetModule(const char* name); - XModule* GetExecutableModule(); - void SetExecutableModule(XModule* module); + XUserModule* GetExecutableModule(); + void SetExecutableModule(XUserModule* module); void RegisterThread(XThread* thread); void UnregisterThread(XThread* thread); @@ -62,7 +63,7 @@ private: xe_mutex_t* object_mutex_; std::unordered_map threads_by_id_; - XModule* executable_module_; + XUserModule* executable_module_; friend class XObject; }; diff --git a/src/xenia/kernel/objects/sources.gypi b/src/xenia/kernel/objects/sources.gypi index 419534dc4..7e849919a 100644 --- a/src/xenia/kernel/objects/sources.gypi +++ b/src/xenia/kernel/objects/sources.gypi @@ -5,6 +5,8 @@ 'xevent.h', 'xfile.cc', 'xfile.h', + 'xkernel_module.cc', + 'xkernel_module.h', 'xmodule.cc', 'xmodule.h', 'xmutant.cc', @@ -17,5 +19,7 @@ 'xthread.h', 'xtimer.cc', 'xtimer.h', + 'xuser_module.cc', + 'xuser_module.h', ], } diff --git a/src/xenia/kernel/objects/xkernel_module.cc b/src/xenia/kernel/objects/xkernel_module.cc new file mode 100644 index 000000000..506cc0b8e --- /dev/null +++ b/src/xenia/kernel/objects/xkernel_module.cc @@ -0,0 +1,36 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include + + +using namespace xe; +using namespace xe::cpu; +using namespace xe::kernel; + + +XKernelModule::XKernelModule(KernelState* kernel_state, const char* path) : + XModule(kernel_state, path) { + emulator_ = kernel_state->emulator(); + memory_ = emulator_->memory(); + export_resolver_ = kernel_state->emulator()->export_resolver(); +} + +XKernelModule::~XKernelModule() { +} + +void* XKernelModule::GetProcAddressByOrdinal(uint16_t ordinal) { + // TODO(benvanik): check export tables. + XELOGE("GetProcAddressByOrdinal not implemented"); + return NULL; +} diff --git a/src/xenia/kernel/kernel_module.h b/src/xenia/kernel/objects/xkernel_module.h similarity index 65% rename from src/xenia/kernel/kernel_module.h rename to src/xenia/kernel/objects/xkernel_module.h index 36071dd1c..07d3d86b4 100644 --- a/src/xenia/kernel/kernel_module.h +++ b/src/xenia/kernel/objects/xkernel_module.h @@ -7,12 +7,10 @@ ****************************************************************************** */ -#ifndef XENIA_KERNEL_KERNEL_MODULE_H_ -#define XENIA_KERNEL_KERNEL_MODULE_H_ - -#include -#include +#ifndef XENIA_KERNEL_XBOXKRNL_XKERNEL_MODULE_H_ +#define XENIA_KERNEL_XBOXKRNL_XKERNEL_MODULE_H_ +#include XEDECLARECLASS1(xe, Emulator); XEDECLARECLASS1(xe, ExportResolver); @@ -23,17 +21,15 @@ namespace xe { namespace kernel { -class KernelModule { +class XKernelModule : public XModule { public: - KernelModule(Emulator* emulator, KernelState* kernel_state); - virtual ~KernelModule(); + XKernelModule(KernelState* kernel_state, const char* path); + virtual ~XKernelModule(); - Emulator* emulator() const { return emulator_; } - KernelState* kernel_state() const { return kernel_state_; } + virtual void* GetProcAddressByOrdinal(uint16_t ordinal); protected: Emulator* emulator_; - KernelState* kernel_state_; Memory* memory_; ExportResolver* export_resolver_; }; @@ -43,4 +39,4 @@ protected: } // namespace xe -#endif // XENIA_KERNEL_KERNEL_MODULE_H_ +#endif // XENIA_KERNEL_XBOXKRNL_XKERNEL_MODULE_H_ diff --git a/src/xenia/kernel/objects/xmodule.cc b/src/xenia/kernel/objects/xmodule.cc index ebfb79ae8..bee54171d 100644 --- a/src/xenia/kernel/objects/xmodule.cc +++ b/src/xenia/kernel/objects/xmodule.cc @@ -9,23 +9,14 @@ #include -#include -#include -#include - using namespace xe; using namespace xe::cpu; using namespace xe::kernel; -namespace { -} - - XModule::XModule(KernelState* kernel_state, const char* path) : - XObject(kernel_state, kTypeModule), - xex_(NULL) { + XObject(kernel_state, kTypeModule) { XEIGNORE(xestrcpya(path_, XECOUNT(path_), path)); const char* slash = xestrrchra(path, '/'); if (!slash) { @@ -41,301 +32,4 @@ XModule::XModule(KernelState* kernel_state, const char* path) : } XModule::~XModule() { - xe_xex2_release(xex_); -} - -const char* XModule::path() { - return path_; -} - -const char* XModule::name() { - return name_; -} - -xe_xex2_ref XModule::xex() { - return xe_xex2_retain(xex_); -} - -const xe_xex2_header_t* XModule::xex_header() { - return xe_xex2_get_header(xex_); -} - -X_STATUS XModule::LoadFromFile(const char* path) { - // Resolve the file to open. - // TODO(benvanik): make this code shared? - fs::Entry* fs_entry = kernel_state()->file_system()->ResolvePath(path); - if (!fs_entry) { - XELOGE("File not found: %s", path); - return X_STATUS_NO_SUCH_FILE; - } - if (fs_entry->type() != fs::Entry::kTypeFile) { - XELOGE("Invalid file type: %s", path); - return X_STATUS_NO_SUCH_FILE; - } - - // Map into memory. - fs::MemoryMapping* mmap = fs_entry->CreateMemoryMapping(kXEFileModeRead, 0, 0); - if (!mmap) { - return X_STATUS_UNSUCCESSFUL; - } - - // Load the module. - X_STATUS return_code = LoadFromMemory(mmap->address(), mmap->length()); - - // Unmap memory and cleanup. - delete mmap; - delete fs_entry; - - return return_code; -} - -X_STATUS XModule::LoadFromMemory(const void* addr, const size_t length) { - Processor* processor = kernel_state()->processor(); - XenonRuntime* runtime = processor->runtime(); - XexModule* xex_module = NULL; - - // Load the XEX into memory and decrypt. - xe_xex2_options_t xex_options; - xe_zero_struct(&xex_options, sizeof(xex_options)); - xex_ = xe_xex2_load(kernel_state()->memory(), addr, length, xex_options); - XEEXPECTNOTNULL(xex_); - - // Prepare the module for execution. - // Runtime takes ownership. - xex_module = new XexModule(runtime); - XEEXPECTZERO(xex_module->Load(name_, path_, xex_)); - XEEXPECTZERO(runtime->AddModule(xex_module)); - - return X_STATUS_SUCCESS; - -XECLEANUP: - delete xex_module; - return X_STATUS_UNSUCCESSFUL; -} - -X_STATUS XModule::GetSection(const char* name, - uint32_t* out_data, uint32_t* out_size) { - const PESection* section = xe_xex2_get_pe_section(xex_, name); - if (!section) { - return X_STATUS_UNSUCCESSFUL; - } - *out_data = section->address; - *out_size = section->size; - return X_STATUS_SUCCESS; -} - -void* XModule::GetProcAddressByOrdinal(uint16_t ordinal) { - // TODO(benvanik): check export tables. - XELOGE("GetProcAddressByOrdinal not implemented"); - return NULL; -} - -X_STATUS XModule::Launch(uint32_t flags) { - const xe_xex2_header_t* header = xex_header(); - - XELOGI("Launching module..."); - - Dump(); - - // Create a thread to run in. - XThread* thread = new XThread( - kernel_state(), - header->exe_stack_size, - 0, - header->exe_entry_point, NULL, - 0); - - X_STATUS result = thread->Create(); - if (XFAILED(result)) { - XELOGE("Could not create launch thread: %.8X", result); - return result; - } - - // Wait until thread completes. - thread->Wait(0, 0, 0, NULL); - - thread->Release(); - - return X_STATUS_SUCCESS; -} - -void XModule::Dump() { - ExportResolver* export_resolver = - kernel_state_->emulator()->export_resolver(); - const xe_xex2_header_t* header = xe_xex2_get_header(xex_); - - // XEX info. - printf("Module %s:\n\n", path_); - 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); - printf(" Entry Point: %.8X\n", header->exe_entry_point); - printf(" Stack Size: %.8X\n", header->exe_stack_size); - printf(" Heap Size: %.8X\n", header->exe_heap_size); - printf("\n"); - printf(" Execution Info:\n"); - printf(" Media ID: %.8X\n", header->execution_info.media_id); - printf(" Version: %d.%d.%d.%d\n", - header->execution_info.version.major, - header->execution_info.version.minor, - header->execution_info.version.build, - header->execution_info.version.qfe); - printf(" Base Version: %d.%d.%d.%d\n", - header->execution_info.base_version.major, - header->execution_info.base_version.minor, - header->execution_info.base_version.build, - header->execution_info.base_version.qfe); - printf(" Title ID: %.8X\n", header->execution_info.title_id); - printf(" Platform: %.8X\n", header->execution_info.platform); - printf(" Exec Table: %.8X\n", header->execution_info.executable_table); - printf(" Disc Number: %d\n", header->execution_info.disc_number); - printf(" Disc Count: %d\n", header->execution_info.disc_count); - printf(" Savegame ID: %.8X\n", header->execution_info.savegame_id); - printf("\n"); - printf(" Loader Info:\n"); - printf(" Image Flags: %.8X\n", header->loader_info.image_flags); - printf(" Game Regions: %.8X\n", header->loader_info.game_regions); - printf(" Media Flags: %.8X\n", header->loader_info.media_flags); - printf("\n"); - printf(" TLS Info:\n"); - printf(" Slot Count: %d\n", header->tls_info.slot_count); - printf(" Data Size: %db\n", header->tls_info.data_size); - printf(" Address: %.8X, %db\n", header->tls_info.raw_data_address, - header->tls_info.raw_data_size); - 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]; - printf(" %.8X (%.8X, %4db) %.8X = %11d\n", - opt_header->key, opt_header->offset, opt_header->length, - opt_header->value, opt_header->value); - } - printf("\n"); - - // Resources. - printf("Resources:\n"); - printf(" %.8X, %db\n", header->resource_info.address, - header->resource_info.size); - printf(" TODO\n"); - printf("\n"); - - // Section info. - printf("Sections:\n"); - for (size_t n = 0, i = 0; n < header->section_count; n++) { - const xe_xex2_section_t* section = &header->sections[n]; - const char* type = "UNKNOWN"; - switch (section->info.type) { - case XEX_SECTION_CODE: - type = "CODE "; - break; - case XEX_SECTION_DATA: - type = "RWDATA "; - break; - case XEX_SECTION_READONLY_DATA: - type = "RODATA "; - break; - } - const size_t start_address = - header->exe_address + (i * xe_xex2_section_length); - const size_t end_address = - start_address + (section->info.page_count * xe_xex2_section_length); - printf(" %3d %s %3d pages %.8X - %.8X (%d bytes)\n", - (int)n, type, section->info.page_count, (int)start_address, - (int)end_address, section->info.page_count * xe_xex2_section_length); - i += section->info.page_count; - } - printf("\n"); - - // Static libraries. - printf("Static Libraries:\n"); - for (size_t n = 0; n < header->static_library_count; n++) { - const xe_xex2_static_library_t *library = &header->static_libraries[n]; - printf(" %-8s : %d.%d.%d.%d\n", - library->name, library->major, - library->minor, library->build, library->qfe); - } - printf("\n"); - - // Imports. - printf("Imports:\n"); - for (size_t n = 0; n < header->import_library_count; n++) { - const xe_xex2_import_library_t* library = &header->import_libraries[n]; - - xe_xex2_import_info_t* import_infos; - size_t import_info_count; - if (!xe_xex2_get_import_infos(xex_, library, - &import_infos, &import_info_count)) { - printf(" %s - %d imports\n", library->name, (int)import_info_count); - printf(" Version: %d.%d.%d.%d\n", - library->version.major, library->version.minor, - library->version.build, library->version.qfe); - printf(" Min Version: %d.%d.%d.%d\n", - library->min_version.major, library->min_version.minor, - library->min_version.build, library->min_version.qfe); - printf("\n"); - - // Counts. - int known_count = 0; - int unknown_count = 0; - int impl_count = 0; - int unimpl_count = 0; - for (size_t m = 0; m < import_info_count; m++) { - const xe_xex2_import_info_t* info = &import_infos[m]; - KernelExport* kernel_export = - export_resolver->GetExportByOrdinal(library->name, info->ordinal); - if (kernel_export) { - known_count++; - if (kernel_export->is_implemented) { - impl_count++; - } else { - unimpl_count++; - } - } else { - unknown_count++; - unimpl_count++; - } - } - printf(" Total: %4u\n", import_info_count); - printf(" Known: %3d%% (%d known, %d unknown)\n", - (int)(known_count / (float)import_info_count * 100.0f), - known_count, unknown_count); - printf(" Implemented: %3d%% (%d implemented, %d unimplemented)\n", - (int)(impl_count / (float)import_info_count * 100.0f), - impl_count, unimpl_count); - printf("\n"); - - // Listing. - for (size_t m = 0; m < import_info_count; m++) { - const xe_xex2_import_info_t* info = &import_infos[m]; - KernelExport* kernel_export = export_resolver->GetExportByOrdinal( - library->name, info->ordinal); - const char *name = "UNKNOWN"; - bool implemented = false; - if (kernel_export) { - name = kernel_export->name; - implemented = kernel_export->is_implemented; - } - if (kernel_export && kernel_export->type == KernelExport::Variable) { - printf(" V %.8X %.3X (%3d) %s %s\n", - info->value_address, info->ordinal, info->ordinal, - implemented ? " " : "!!", name); - } else if (info->thunk_address) { - printf(" F %.8X %.8X %.3X (%3d) %s %s\n", - info->value_address, info->thunk_address, info->ordinal, - info->ordinal, implemented ? " " : "!!", name); - - } - } - - xe_free(import_infos); - } - - printf("\n"); - } - - // Exports. - printf("Exports:\n"); - printf(" TODO\n"); - printf("\n"); } diff --git a/src/xenia/kernel/objects/xmodule.h b/src/xenia/kernel/objects/xmodule.h index 8b4900470..2c31e5ef6 100644 --- a/src/xenia/kernel/objects/xmodule.h +++ b/src/xenia/kernel/objects/xmodule.h @@ -12,11 +12,7 @@ #include -#include - -#include #include -#include namespace xe { @@ -28,28 +24,14 @@ public: XModule(KernelState* kernel_state, const char* path); virtual ~XModule(); - const char* path(); - const char* name(); - xe_xex2_ref xex(); - const xe_xex2_header_t* xex_header(); + const char* path() const { return path_; } + const char* name() const { return name_; } - X_STATUS LoadFromFile(const char* path); - X_STATUS LoadFromMemory(const void* addr, const size_t length); - - X_STATUS GetSection(const char* name, uint32_t* out_data, uint32_t* out_size); - void* GetProcAddressByOrdinal(uint16_t ordinal); - - X_STATUS Launch(uint32_t flags); - - void Dump(); - -private: - int LoadPE(); + virtual void* GetProcAddressByOrdinal(uint16_t ordinal) = 0; +protected: char name_[256]; char path_[XE_MAX_PATH]; - - xe_xex2_ref xex_; }; diff --git a/src/xenia/kernel/objects/xthread.cc b/src/xenia/kernel/objects/xthread.cc index 4d5d4cfeb..7e7e73ba3 100644 --- a/src/xenia/kernel/objects/xthread.cc +++ b/src/xenia/kernel/objects/xthread.cc @@ -12,7 +12,7 @@ #include #include #include -#include +#include using namespace alloy; @@ -185,7 +185,7 @@ X_STATUS XThread::Create() { // Set native info. SetNativePointer(thread_state_address_); - XModule* module = kernel_state()->GetExecutableModule(); + XUserModule* module = kernel_state()->GetExecutableModule(); // Allocate TLS block. const xe_xex2_header_t* header = module->xex_header(); diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc new file mode 100644 index 000000000..898bcd5f6 --- /dev/null +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -0,0 +1,317 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include + + +using namespace xe; +using namespace xe::cpu; +using namespace xe::kernel; + + +XUserModule::XUserModule(KernelState* kernel_state, const char* path) : + XModule(kernel_state, path), + xex_(NULL) { +} + +XUserModule::~XUserModule() { + xe_xex2_release(xex_); +} + +xe_xex2_ref XUserModule::xex() { + return xe_xex2_retain(xex_); +} + +const xe_xex2_header_t* XUserModule::xex_header() { + return xe_xex2_get_header(xex_); +} + +X_STATUS XUserModule::LoadFromFile(const char* path) { + // Resolve the file to open. + // TODO(benvanik): make this code shared? + fs::Entry* fs_entry = kernel_state()->file_system()->ResolvePath(path); + if (!fs_entry) { + XELOGE("File not found: %s", path); + return X_STATUS_NO_SUCH_FILE; + } + if (fs_entry->type() != fs::Entry::kTypeFile) { + XELOGE("Invalid file type: %s", path); + return X_STATUS_NO_SUCH_FILE; + } + + // Map into memory. + fs::MemoryMapping* mmap = fs_entry->CreateMemoryMapping(kXEFileModeRead, 0, 0); + if (!mmap) { + return X_STATUS_UNSUCCESSFUL; + } + + // Load the module. + X_STATUS return_code = LoadFromMemory(mmap->address(), mmap->length()); + + // Unmap memory and cleanup. + delete mmap; + delete fs_entry; + + return return_code; +} + +X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) { + Processor* processor = kernel_state()->processor(); + XenonRuntime* runtime = processor->runtime(); + XexModule* xex_module = NULL; + + // Load the XEX into memory and decrypt. + xe_xex2_options_t xex_options; + xe_zero_struct(&xex_options, sizeof(xex_options)); + xex_ = xe_xex2_load(kernel_state()->memory(), addr, length, xex_options); + XEEXPECTNOTNULL(xex_); + + // Prepare the module for execution. + // Runtime takes ownership. + xex_module = new XexModule(runtime); + XEEXPECTZERO(xex_module->Load(name_, path_, xex_)); + XEEXPECTZERO(runtime->AddModule(xex_module)); + + return X_STATUS_SUCCESS; + +XECLEANUP: + delete xex_module; + return X_STATUS_UNSUCCESSFUL; +} + +X_STATUS XUserModule::GetSection(const char* name, + uint32_t* out_data, uint32_t* out_size) { + const PESection* section = xe_xex2_get_pe_section(xex_, name); + if (!section) { + return X_STATUS_UNSUCCESSFUL; + } + *out_data = section->address; + *out_size = section->size; + return X_STATUS_SUCCESS; +} + +void* XUserModule::GetProcAddressByOrdinal(uint16_t ordinal) { + // TODO(benvanik): check export tables. + XELOGE("GetProcAddressByOrdinal not implemented"); + return NULL; +} + +X_STATUS XUserModule::Launch(uint32_t flags) { + const xe_xex2_header_t* header = xex_header(); + + XELOGI("Launching module..."); + + Dump(); + + // Create a thread to run in. + XThread* thread = new XThread( + kernel_state(), + header->exe_stack_size, + 0, + header->exe_entry_point, NULL, + 0); + + X_STATUS result = thread->Create(); + if (XFAILED(result)) { + XELOGE("Could not create launch thread: %.8X", result); + return result; + } + + // Wait until thread completes. + thread->Wait(0, 0, 0, NULL); + + thread->Release(); + + return X_STATUS_SUCCESS; +} + +void XUserModule::Dump() { + ExportResolver* export_resolver = + kernel_state_->emulator()->export_resolver(); + const xe_xex2_header_t* header = xe_xex2_get_header(xex_); + + // XEX info. + printf("Module %s:\n\n", path_); + 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); + printf(" Entry Point: %.8X\n", header->exe_entry_point); + printf(" Stack Size: %.8X\n", header->exe_stack_size); + printf(" Heap Size: %.8X\n", header->exe_heap_size); + printf("\n"); + printf(" Execution Info:\n"); + printf(" Media ID: %.8X\n", header->execution_info.media_id); + printf(" Version: %d.%d.%d.%d\n", + header->execution_info.version.major, + header->execution_info.version.minor, + header->execution_info.version.build, + header->execution_info.version.qfe); + printf(" Base Version: %d.%d.%d.%d\n", + header->execution_info.base_version.major, + header->execution_info.base_version.minor, + header->execution_info.base_version.build, + header->execution_info.base_version.qfe); + printf(" Title ID: %.8X\n", header->execution_info.title_id); + printf(" Platform: %.8X\n", header->execution_info.platform); + printf(" Exec Table: %.8X\n", header->execution_info.executable_table); + printf(" Disc Number: %d\n", header->execution_info.disc_number); + printf(" Disc Count: %d\n", header->execution_info.disc_count); + printf(" Savegame ID: %.8X\n", header->execution_info.savegame_id); + printf("\n"); + printf(" Loader Info:\n"); + printf(" Image Flags: %.8X\n", header->loader_info.image_flags); + printf(" Game Regions: %.8X\n", header->loader_info.game_regions); + printf(" Media Flags: %.8X\n", header->loader_info.media_flags); + printf("\n"); + printf(" TLS Info:\n"); + printf(" Slot Count: %d\n", header->tls_info.slot_count); + printf(" Data Size: %db\n", header->tls_info.data_size); + printf(" Address: %.8X, %db\n", header->tls_info.raw_data_address, + header->tls_info.raw_data_size); + 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]; + printf(" %.8X (%.8X, %4db) %.8X = %11d\n", + opt_header->key, opt_header->offset, opt_header->length, + opt_header->value, opt_header->value); + } + printf("\n"); + + // Resources. + printf("Resources:\n"); + printf(" %.8X, %db\n", header->resource_info.address, + header->resource_info.size); + printf(" TODO\n"); + printf("\n"); + + // Section info. + printf("Sections:\n"); + for (size_t n = 0, i = 0; n < header->section_count; n++) { + const xe_xex2_section_t* section = &header->sections[n]; + const char* type = "UNKNOWN"; + switch (section->info.type) { + case XEX_SECTION_CODE: + type = "CODE "; + break; + case XEX_SECTION_DATA: + type = "RWDATA "; + break; + case XEX_SECTION_READONLY_DATA: + type = "RODATA "; + break; + } + const size_t start_address = + header->exe_address + (i * xe_xex2_section_length); + const size_t end_address = + start_address + (section->info.page_count * xe_xex2_section_length); + printf(" %3d %s %3d pages %.8X - %.8X (%d bytes)\n", + (int)n, type, section->info.page_count, (int)start_address, + (int)end_address, section->info.page_count * xe_xex2_section_length); + i += section->info.page_count; + } + printf("\n"); + + // Static libraries. + printf("Static Libraries:\n"); + for (size_t n = 0; n < header->static_library_count; n++) { + const xe_xex2_static_library_t *library = &header->static_libraries[n]; + printf(" %-8s : %d.%d.%d.%d\n", + library->name, library->major, + library->minor, library->build, library->qfe); + } + printf("\n"); + + // Imports. + printf("Imports:\n"); + for (size_t n = 0; n < header->import_library_count; n++) { + const xe_xex2_import_library_t* library = &header->import_libraries[n]; + + xe_xex2_import_info_t* import_infos; + size_t import_info_count; + if (!xe_xex2_get_import_infos(xex_, library, + &import_infos, &import_info_count)) { + printf(" %s - %d imports\n", library->name, (int)import_info_count); + printf(" Version: %d.%d.%d.%d\n", + library->version.major, library->version.minor, + library->version.build, library->version.qfe); + printf(" Min Version: %d.%d.%d.%d\n", + library->min_version.major, library->min_version.minor, + library->min_version.build, library->min_version.qfe); + printf("\n"); + + // Counts. + int known_count = 0; + int unknown_count = 0; + int impl_count = 0; + int unimpl_count = 0; + for (size_t m = 0; m < import_info_count; m++) { + const xe_xex2_import_info_t* info = &import_infos[m]; + KernelExport* kernel_export = + export_resolver->GetExportByOrdinal(library->name, info->ordinal); + if (kernel_export) { + known_count++; + if (kernel_export->is_implemented) { + impl_count++; + } else { + unimpl_count++; + } + } else { + unknown_count++; + unimpl_count++; + } + } + printf(" Total: %4u\n", import_info_count); + printf(" Known: %3d%% (%d known, %d unknown)\n", + (int)(known_count / (float)import_info_count * 100.0f), + known_count, unknown_count); + printf(" Implemented: %3d%% (%d implemented, %d unimplemented)\n", + (int)(impl_count / (float)import_info_count * 100.0f), + impl_count, unimpl_count); + printf("\n"); + + // Listing. + for (size_t m = 0; m < import_info_count; m++) { + const xe_xex2_import_info_t* info = &import_infos[m]; + KernelExport* kernel_export = export_resolver->GetExportByOrdinal( + library->name, info->ordinal); + const char *name = "UNKNOWN"; + bool implemented = false; + if (kernel_export) { + name = kernel_export->name; + implemented = kernel_export->is_implemented; + } + if (kernel_export && kernel_export->type == KernelExport::Variable) { + printf(" V %.8X %.3X (%3d) %s %s\n", + info->value_address, info->ordinal, info->ordinal, + implemented ? " " : "!!", name); + } else if (info->thunk_address) { + printf(" F %.8X %.8X %.3X (%3d) %s %s\n", + info->value_address, info->thunk_address, info->ordinal, + info->ordinal, implemented ? " " : "!!", name); + + } + } + + xe_free(import_infos); + } + + printf("\n"); + } + + // Exports. + printf("Exports:\n"); + printf(" TODO\n"); + printf("\n"); +} diff --git a/src/xenia/kernel/objects/xuser_module.h b/src/xenia/kernel/objects/xuser_module.h new file mode 100644 index 000000000..6f655011a --- /dev/null +++ b/src/xenia/kernel/objects/xuser_module.h @@ -0,0 +1,53 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_XBOXKRNL_XUSER_MODULE_H_ +#define XENIA_KERNEL_XBOXKRNL_XUSER_MODULE_H_ + +#include + +#include +#include +#include + + +namespace xe { +namespace kernel { + + +class XUserModule : public XModule { +public: + XUserModule(KernelState* kernel_state, const char* path); + virtual ~XUserModule(); + + xe_xex2_ref xex(); + const xe_xex2_header_t* xex_header(); + + X_STATUS LoadFromFile(const char* path); + X_STATUS LoadFromMemory(const void* addr, const size_t length); + + X_STATUS GetSection(const char* name, uint32_t* out_data, uint32_t* out_size); + virtual void* GetProcAddressByOrdinal(uint16_t ordinal); + + X_STATUS Launch(uint32_t flags); + + void Dump(); + +private: + int LoadPE(); + + xe_xex2_ref xex_; +}; + + +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_XBOXKRNL_XUSER_MODULE_H_ diff --git a/src/xenia/kernel/sources.gypi b/src/xenia/kernel/sources.gypi index 958140447..a61051028 100644 --- a/src/xenia/kernel/sources.gypi +++ b/src/xenia/kernel/sources.gypi @@ -4,8 +4,6 @@ 'async_request.cc', 'async_request.h', 'kernel.h', - 'kernel_module.cc', - 'kernel_module.h', 'kernel_state.cc', 'kernel_state.h', 'modules.h', diff --git a/src/xenia/kernel/util/shim_utils.h b/src/xenia/kernel/util/shim_utils.h index 9d6108b6c..2d13e91df 100644 --- a/src/xenia/kernel/util/shim_utils.h +++ b/src/xenia/kernel/util/shim_utils.h @@ -15,7 +15,6 @@ #include #include -#include namespace xe { diff --git a/src/xenia/kernel/xam_module.cc b/src/xenia/kernel/xam_module.cc index 2139e702b..32bce4bab 100644 --- a/src/xenia/kernel/xam_module.cc +++ b/src/xenia/kernel/xam_module.cc @@ -20,7 +20,7 @@ using namespace xe::kernel::xam; XamModule::XamModule(Emulator* emulator, KernelState* kernel_state) : - KernelModule(emulator, kernel_state) { + XKernelModule(kernel_state, "xe:\\xam.xex") { // Build the export table used for resolution. #include static KernelExport xam_export_table[] = { diff --git a/src/xenia/kernel/xam_module.h b/src/xenia/kernel/xam_module.h index 4cfd76a7b..52440fc77 100644 --- a/src/xenia/kernel/xam_module.h +++ b/src/xenia/kernel/xam_module.h @@ -14,8 +14,8 @@ #include #include -#include #include +#include // All of the exported functions: #include @@ -25,7 +25,7 @@ namespace xe { namespace kernel { -class XamModule : public KernelModule { +class XamModule : public XKernelModule { public: XamModule(Emulator* emulator, KernelState* kernel_state); virtual ~XamModule(); diff --git a/src/xenia/kernel/xboxkrnl_module.cc b/src/xenia/kernel/xboxkrnl_module.cc index 458f24a3d..c4d1d270d 100644 --- a/src/xenia/kernel/xboxkrnl_module.cc +++ b/src/xenia/kernel/xboxkrnl_module.cc @@ -16,7 +16,7 @@ #include #include #include -#include +#include using namespace xe; @@ -29,7 +29,7 @@ DEFINE_bool(abort_before_entry, false, XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state) : - KernelModule(emulator, kernel_state) { + XKernelModule(kernel_state, "xe:\\xboxkrnl.exe") { // Build the export table used for resolution. #include static KernelExport xboxkrnl_export_table[] = { @@ -144,7 +144,7 @@ XboxkrnlModule::~XboxkrnlModule() { int XboxkrnlModule::LaunchModule(const char* path) { // Create and register the module. We keep it local to this function and // dispose it on exit. - XModule* module = new XModule(kernel_state_, path); + XUserModule* module = new XUserModule(kernel_state_, path); // Load the module into memory from the filesystem. X_STATUS result_code = module->LoadFromFile(path); diff --git a/src/xenia/kernel/xboxkrnl_module.h b/src/xenia/kernel/xboxkrnl_module.h index 4453703f0..357e901b4 100644 --- a/src/xenia/kernel/xboxkrnl_module.h +++ b/src/xenia/kernel/xboxkrnl_module.h @@ -14,8 +14,8 @@ #include #include -#include #include +#include // All of the exported functions: #include @@ -33,7 +33,7 @@ namespace kernel { class KernelState; -class XboxkrnlModule : public KernelModule { +class XboxkrnlModule : public XKernelModule { public: XboxkrnlModule(Emulator* emulator, KernelState* kernel_state); virtual ~XboxkrnlModule(); diff --git a/src/xenia/kernel/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl_modules.cc index 0d780bd36..d88d1a5a0 100644 --- a/src/xenia/kernel/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl_modules.cc @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include @@ -131,7 +131,7 @@ int xeXexCheckExecutablePriviledge(uint32_t privilege) { // Privilege=6 -> 0x00000040 -> XEX_SYSTEM_INSECURE_SOCKETS uint32_t mask = 1 << privilege; - XModule* module = state->GetExecutableModule(); + XUserModule* module = state->GetExecutableModule(); if (!module) { return 0; } @@ -209,6 +209,51 @@ SHIM_CALL XexGetModuleHandle_shim( // } +SHIM_CALL XexLoadImage_shim( + PPCContext* ppc_state, KernelState* 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_flags = SHIM_GET_ARG_32(1); + uint32_t min_version = SHIM_GET_ARG_32(2); + uint32_t handle_ptr = SHIM_GET_ARG_32(3); + + XELOGD( + "XexLoadImage(%s, %.8X, %.8X, %.8X)", + module_name, module_flags, min_version, handle_ptr); + + X_STATUS result = X_STATUS_NO_SUCH_FILE; + + XModule* module = state->GetModule(module_name); + if (module) { + module->RetainHandle(); + SHIM_SET_MEM_32(handle_ptr, module->handle()); + module->Release(); + + result = X_STATUS_SUCCESS; + } else { + result = X_STATUS_NO_SUCH_FILE; + } + + SHIM_SET_RETURN(result); +} + + +SHIM_CALL XexUnloadImage_shim( + PPCContext* ppc_state, KernelState* state) { + uint32_t handle = SHIM_GET_ARG_32(0); + + XELOGD( + "XexUnloadImage(%.8X)", + handle); + + X_STATUS result = X_STATUS_INVALID_HANDLE; + + result = state->object_table()->RemoveHandle(handle); + + SHIM_SET_RETURN(result); +} + + SHIM_CALL XexGetProcedureAddress_shim( PPCContext* ppc_state, KernelState* state) { uint32_t module_handle = SHIM_GET_ARG_32(0); @@ -233,7 +278,7 @@ SHIM_CALL XexGetProcedureAddress_shim( if (XSUCCEEDED(result)) { // TODO(benvanik): implement. May need to create stub functions on the fly. // module->GetProcAddressByOrdinal(ordinal); - result = X_STATUS_INVALID_HANDLE; + result = X_STATUS_NOT_IMPLEMENTED; } if (module) { module->Release(); @@ -279,6 +324,8 @@ void xe::kernel::xboxkrnl::RegisterModuleExports( SHIM_SET_MAPPING("xboxkrnl.exe", XexGetModuleHandle, state); // SHIM_SET_MAPPING("xboxkrnl.exe", XexGetModuleSection, state); + SHIM_SET_MAPPING("xboxkrnl.exe", XexLoadImage, state); + SHIM_SET_MAPPING("xboxkrnl.exe", XexUnloadImage, state); SHIM_SET_MAPPING("xboxkrnl.exe", XexGetProcedureAddress, state); SHIM_SET_MAPPING("xboxkrnl.exe", ExRegisterTitleTerminateNotification, state); diff --git a/src/xenia/kernel/xboxkrnl_rtl.cc b/src/xenia/kernel/xboxkrnl_rtl.cc index bcd8ec70e..d08ea16fd 100644 --- a/src/xenia/kernel/xboxkrnl_rtl.cc +++ b/src/xenia/kernel/xboxkrnl_rtl.cc @@ -11,8 +11,8 @@ #include #include -#include #include +#include #include #include @@ -596,7 +596,7 @@ uint32_t xeRtlImageXexHeaderField(uint32_t xex_header_base_ptr, // The only ImageField I've seen in the wild is // 0x20401 (XEX_HEADER_DEFAULT_HEAP_SIZE), so that's all we'll support. - XModule* module = NULL; + XUserModule* module = NULL; // TODO(benvanik): use xex_header_base to dereference this. // Right now we are only concerned with games making this call on their main