From 8d4582a7a429d903d4002a7a9677f483ad0934d5 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 13:27:48 -0500 Subject: [PATCH 01/24] Fix a couple of API bugs dealing with modules --- src/xenia/kernel/xboxkrnl_modules.cc | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl_modules.cc index 6f95ef3a1..ab195b5b5 100644 --- a/src/xenia/kernel/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl_modules.cc @@ -221,6 +221,7 @@ SHIM_CALL XexLoadImage_shim(PPCContext* ppc_context, if (module) { // Existing module found. hmodule = module->hmodule_ptr(); + result = X_STATUS_SUCCESS; } else { // Not found; attempt to load as a user module. auto user_module = kernel_state->LoadUserModule(module_name); @@ -232,9 +233,11 @@ SHIM_CALL XexLoadImage_shim(PPCContext* ppc_context, } // Increment the module's load count. - auto ldr_data = - kernel_memory()->TranslateVirtual(hmodule); - ldr_data->load_count++; + if (hmodule) { + auto ldr_data = + kernel_memory()->TranslateVirtual(hmodule); + ldr_data->load_count++; + } SHIM_SET_MEM_32(hmodule_ptr, hmodule); @@ -253,12 +256,15 @@ SHIM_CALL XexUnloadImage_shim(PPCContext* ppc_context, return; } - 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()); + // Can't unload kernel modules from user code. + if (module->module_type() != XModule::ModuleType::kKernelModule) { + 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(X_STATUS_SUCCESS); From fbfdfc891457788437cbe97decb77cbce132ee9e Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 13:31:13 -0500 Subject: [PATCH 02/24] Don't call DllMain on non-DLLs Gracefully handle the kernel dispatch thread already running --- src/xenia/kernel/kernel_state.cc | 44 +++++++++++++----------- src/xenia/kernel/objects/xuser_module.cc | 1 + src/xenia/kernel/objects/xuser_module.h | 2 ++ 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index 5c1f32ea8..256bb3cdd 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -223,26 +223,27 @@ void KernelState::SetExecutableModule(object_ref module) { // Spin up deferred dispatch worker. // TODO(benvanik): move someplace more appropriate (out of ctor, but around // here). - assert_false(dispatch_thread_running_); - dispatch_thread_running_ = true; - dispatch_thread_ = - object_ref(new XHostThread(this, 128 * 1024, 0, [this]() { - while (dispatch_thread_running_) { - std::unique_lock lock(dispatch_mutex_); - if (dispatch_queue_.empty()) { - dispatch_cond_.wait(lock); - if (!dispatch_thread_running_) { - break; + if (!dispatch_thread_running_) { + dispatch_thread_running_ = true; + dispatch_thread_ = + object_ref(new XHostThread(this, 128 * 1024, 0, [this]() { + while (dispatch_thread_running_) { + std::unique_lock lock(dispatch_mutex_); + if (dispatch_queue_.empty()) { + dispatch_cond_.wait(lock); + if (!dispatch_thread_running_) { + break; + } } + auto fn = std::move(dispatch_queue_.front()); + dispatch_queue_.pop_front(); + fn(); } - auto fn = std::move(dispatch_queue_.front()); - dispatch_queue_.pop_front(); - fn(); - } - return 0; - })); - dispatch_thread_->set_name("Kernel Dispatch Thread"); - dispatch_thread_->Create(); + return 0; + })); + dispatch_thread_->set_name("Kernel Dispatch Thread"); + dispatch_thread_->Create(); + } } void KernelState::LoadKernelModule(object_ref kernel_module) { @@ -255,6 +256,7 @@ object_ref KernelState::LoadUserModule(const char* raw_name) { std::string name = xe::find_name_from_path(raw_name); std::string path(raw_name); if (name == raw_name) { + assert_not_null(executable_module_); path = xe::join_paths(xe::find_base_path(executable_module_->path()), name); } @@ -284,7 +286,7 @@ object_ref KernelState::LoadUserModule(const char* raw_name) { module->Dump(); - if (module->entry_point()) { + if (module->dll_module() && module->entry_point()) { // Call DllMain(DLL_PROCESS_ATTACH): // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx uint64_t args[] = { @@ -331,7 +333,7 @@ void KernelState::OnThreadExecute(XThread* thread) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx auto thread_state = thread->thread_state(); for (auto user_module : user_modules_) { - if (user_module->entry_point()) { + if (user_module->dll_module() && user_module->entry_point()) { uint64_t args[] = { user_module->handle(), 2, // DLL_THREAD_ATTACH @@ -353,7 +355,7 @@ void KernelState::OnThreadExit(XThread* thread) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx auto thread_state = thread->thread_state(); for (auto user_module : user_modules_) { - if (user_module->entry_point()) { + if (user_module->dll_module() && user_module->entry_point()) { uint64_t args[] = { user_module->handle(), 3, // DLL_THREAD_DETACH diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index b0fd110b9..4b30c7a20 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -104,6 +104,7 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) { // Cache some commonly used headers... this->xex_module()->GetOptHeader(XEX_HEADER_ENTRY_POINT, &entry_point_); this->xex_module()->GetOptHeader(XEX_HEADER_DEFAULT_STACK_SIZE, &stack_size_); + dll_module_ = !!(header->module_flags & XEX_MODULE_DLL_MODULE); OnLoad(); diff --git a/src/xenia/kernel/objects/xuser_module.h b/src/xenia/kernel/objects/xuser_module.h index e8896fede..3f3da1ac3 100644 --- a/src/xenia/kernel/objects/xuser_module.h +++ b/src/xenia/kernel/objects/xuser_module.h @@ -32,6 +32,7 @@ class XUserModule : public XModule { const xex2_header* xex_header() const { return xex_module()->xex_header(); } uint32_t guest_xex_header() const { return guest_xex_header_; } + bool dll_module() const { return dll_module_; } uint32_t entry_point() const { return entry_point_; } uint32_t stack_size() const { return stack_size_; } @@ -67,6 +68,7 @@ class XUserModule : public XModule { private: uint32_t guest_xex_header_; + bool dll_module_; uint32_t entry_point_; uint32_t stack_size_; }; From 6bb5b002e0a66dfc7e7bcc1bc1234455b4e4e687 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 13:31:51 -0500 Subject: [PATCH 03/24] Gracefully handle debugger accept thread already running --- src/xenia/debug/debugger.cc | 122 +++++++++++++++++++----------------- src/xenia/debug/debugger.h | 1 + 2 files changed, 64 insertions(+), 59 deletions(-) diff --git a/src/xenia/debug/debugger.cc b/src/xenia/debug/debugger.cc index e8b887e47..44c033337 100644 --- a/src/xenia/debug/debugger.cc +++ b/src/xenia/debug/debugger.cc @@ -58,7 +58,8 @@ Breakpoint::~Breakpoint() = default; Debugger::Debugger(Emulator* emulator) : emulator_(emulator), listen_socket_(INVALID_SOCKET), - client_socket_(INVALID_SOCKET) { + client_socket_(INVALID_SOCKET), + accept_thread_running_(false) { WSADATA wsa_data; WSAStartup(MAKEWORD(2, 2), &wsa_data); } @@ -134,67 +135,70 @@ void SendResponse(SOCKET client_socket, flatbuffers::FlatBufferBuilder& fbb, } void Debugger::PreLaunch() { - accept_thread_ = std::thread([this]() { - xe::threading::set_name("Debugger Server"); + if (!accept_thread_running_) { + accept_thread_running_ = true; + accept_thread_ = std::thread([this]() { + xe::threading::set_name("Debugger Server"); - while (listen_socket_ != INVALID_SOCKET) { - sockaddr_in6 client_addr; - int client_count = sizeof(client_addr); - SOCKET client_socket_id = - accept(listen_socket_, reinterpret_cast(&client_addr), - &client_count); - if (client_socket_id == INVALID_SOCKET) { - XELOGE("Failed to accept socket"); - continue; - } - - // Only one debugger at a time. - if (client_socket_ != INVALID_SOCKET) { - XELOGW("Ignoring debugger connection as one is already connected"); - closesocket(client_socket_id); - continue; - } - - // Setup recv thread. - client_socket_ = client_socket_id; - receive_thread_ = std::thread([this]() { - xe::threading::set_name("Debugger Connection"); - - while (client_socket_ != INVALID_SOCKET) { - // Read length prefix. - uint32_t length = 0; - int r = recv(client_socket_, reinterpret_cast(&length), 4, - MSG_WAITALL); - if (r != 4) { - // Failed? - XELOGE("Failed to recv debug data length - dead connection?"); - if (FLAGS_exit_with_debugger) { - exit(1); - } - break; - } - - // Read body. - std::vector body(length); - r = recv(client_socket_, reinterpret_cast(body.data()), length, - MSG_WAITALL); - if (r != length) { - // Failed? - XELOGE("Failed to recv debug data body - dead connection?"); - if (FLAGS_exit_with_debugger) { - exit(1); - } - break; - } - - // Read message contents and dispatch. - OnMessage(std::move(body)); + while (listen_socket_ != INVALID_SOCKET) { + sockaddr_in6 client_addr; + int client_count = sizeof(client_addr); + SOCKET client_socket_id = + accept(listen_socket_, reinterpret_cast(&client_addr), + &client_count); + if (client_socket_id == INVALID_SOCKET) { + XELOGE("Failed to accept socket"); + continue; } - }); - // This will WaitForClient if it was waiting. - } - }); + // Only one debugger at a time. + if (client_socket_ != INVALID_SOCKET) { + XELOGW("Ignoring debugger connection as one is already connected"); + closesocket(client_socket_id); + continue; + } + + // Setup recv thread. + client_socket_ = client_socket_id; + receive_thread_ = std::thread([this]() { + xe::threading::set_name("Debugger Connection"); + + while (client_socket_ != INVALID_SOCKET) { + // Read length prefix. + uint32_t length = 0; + int r = recv(client_socket_, reinterpret_cast(&length), 4, + MSG_WAITALL); + if (r != 4) { + // Failed? + XELOGE("Failed to recv debug data length - dead connection?"); + if (FLAGS_exit_with_debugger) { + exit(1); + } + break; + } + + // Read body. + std::vector body(length); + r = recv(client_socket_, reinterpret_cast(body.data()), + length, MSG_WAITALL); + if (r != length) { + // Failed? + XELOGE("Failed to recv debug data body - dead connection?"); + if (FLAGS_exit_with_debugger) { + exit(1); + } + break; + } + + // Read message contents and dispatch. + OnMessage(std::move(body)); + } + }); + + // This will WaitForClient if it was waiting. + } + }); + } if (FLAGS_wait_for_debugger) { // Wait for the first client. diff --git a/src/xenia/debug/debugger.h b/src/xenia/debug/debugger.h index 9bb446679..08b3d4266 100644 --- a/src/xenia/debug/debugger.h +++ b/src/xenia/debug/debugger.h @@ -111,6 +111,7 @@ class Debugger { Emulator* emulator_; uintptr_t listen_socket_; + bool accept_thread_running_; std::thread accept_thread_; xe::threading::Fence accept_fence_; uintptr_t client_socket_; From 4fdebd530f338d36d83b36653d6fbbb86d042a31 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 13:37:10 -0500 Subject: [PATCH 04/24] XThread bool guest thread --- src/xenia/kernel/objects/xthread.cc | 8 +++++--- src/xenia/kernel/objects/xthread.h | 4 +++- src/xenia/kernel/objects/xuser_module.cc | 2 +- src/xenia/kernel/xboxkrnl_threading.cc | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/xenia/kernel/objects/xthread.cc b/src/xenia/kernel/objects/xthread.cc index 494086b85..46ef3707b 100644 --- a/src/xenia/kernel/objects/xthread.cc +++ b/src/xenia/kernel/objects/xthread.cc @@ -41,7 +41,8 @@ xe::mutex critical_region_; XThread::XThread(KernelState* kernel_state, uint32_t stack_size, uint32_t xapi_thread_startup, uint32_t start_address, - uint32_t start_context, uint32_t creation_flags) + uint32_t start_context, uint32_t creation_flags, + bool guest_thread) : XObject(kernel_state, kTypeThread), thread_id_(++next_xthread_id), thread_handle_(0), @@ -50,7 +51,8 @@ XThread::XThread(KernelState* kernel_state, uint32_t stack_size, thread_state_(0), priority_(0), affinity_(0), - irql_(0) { + irql_(0), + guest_thread_(guest_thread) { creation_params_.stack_size = stack_size; creation_params_.xapi_thread_startup = xapi_thread_startup; creation_params_.start_address = start_address; @@ -758,7 +760,7 @@ void* XThread::GetWaitHandle() { return event_->GetWaitHandle(); } XHostThread::XHostThread(KernelState* kernel_state, uint32_t stack_size, uint32_t creation_flags, std::function host_fn) - : XThread(kernel_state, stack_size, 0, 0, 0, creation_flags), + : XThread(kernel_state, stack_size, 0, 0, 0, creation_flags, false), host_fn_(host_fn) {} void XHostThread::Execute() { diff --git a/src/xenia/kernel/objects/xthread.h b/src/xenia/kernel/objects/xthread.h index 03516833f..70e2a8ed2 100644 --- a/src/xenia/kernel/objects/xthread.h +++ b/src/xenia/kernel/objects/xthread.h @@ -81,7 +81,7 @@ class XThread : public XObject { public: XThread(KernelState* kernel_state, uint32_t stack_size, uint32_t xapi_thread_startup, uint32_t start_address, - uint32_t start_context, uint32_t creation_flags); + uint32_t start_context, uint32_t creation_flags, bool guest_thread); virtual ~XThread(); static bool IsInThread(XThread* other); @@ -92,6 +92,7 @@ class XThread : public XObject { uint32_t tls_ptr() const { return tls_address_; } uint32_t pcr_ptr() const { return pcr_address_; } uint32_t thread_state_ptr() const { return thread_state_address_; } + bool guest_thread() const { return guest_thread_; } cpu::ThreadState* thread_state() const { return thread_state_; } uint32_t thread_id() const { return thread_id_; } @@ -156,6 +157,7 @@ class XThread : public XObject { uint32_t pcr_address_; uint32_t thread_state_address_; cpu::ThreadState* thread_state_; + bool guest_thread_; // Launched into guest code? std::string name_; diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index 4b30c7a20..f4fbdee69 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -206,7 +206,7 @@ X_STATUS XUserModule::Launch(uint32_t flags) { // Create a thread to run in. auto thread = object_ref( - new XThread(kernel_state(), stack_size_, 0, entry_point_, 0, 0)); + new XThread(kernel_state(), stack_size_, 0, entry_point_, 0, 0, true)); X_STATUS result = thread->Create(); if (XFAILED(result)) { diff --git a/src/xenia/kernel/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl_threading.cc index d24aa08f4..9d91891b8 100644 --- a/src/xenia/kernel/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl_threading.cc @@ -117,7 +117,7 @@ SHIM_CALL ExCreateThread_shim(PPCContext* ppc_context, auto thread = object_ref( new XThread(kernel_state, stack_size, xapi_thread_startup, start_address, - start_context, creation_flags)); + start_context, creation_flags, true)); X_STATUS result = thread->Create(); if (XFAILED(result)) { From 8210ada448aa70bbde8aee398c9d4c4d8109dcd6 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 13:47:53 -0500 Subject: [PATCH 05/24] XModule OnUnload --- src/xenia/kernel/objects/xmodule.cc | 2 ++ src/xenia/kernel/objects/xmodule.h | 1 + 2 files changed, 3 insertions(+) diff --git a/src/xenia/kernel/objects/xmodule.cc b/src/xenia/kernel/objects/xmodule.cc index 28d5e1d3d..183fa86fe 100644 --- a/src/xenia/kernel/objects/xmodule.cc +++ b/src/xenia/kernel/objects/xmodule.cc @@ -67,6 +67,8 @@ bool XModule::Matches(const std::string& name) const { void XModule::OnLoad() { kernel_state_->RegisterModule(this); } +void XModule::OnUnload() { kernel_state_->UnregisterModule(this); } + X_STATUS XModule::GetSection(const char* name, uint32_t* out_section_data, uint32_t* out_section_size) { return X_STATUS_UNSUCCESSFUL; diff --git a/src/xenia/kernel/objects/xmodule.h b/src/xenia/kernel/objects/xmodule.h index d6951b63b..6573b9d1f 100644 --- a/src/xenia/kernel/objects/xmodule.h +++ b/src/xenia/kernel/objects/xmodule.h @@ -86,6 +86,7 @@ class XModule : public XObject { protected: void OnLoad(); + void OnUnload(); ModuleType module_type_; std::string name_; From 7f53b1d630e39dbd6075d3a416437ae7d634521c Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 14:03:00 -0500 Subject: [PATCH 06/24] Allow unloading of user modules --- src/xenia/cpu/xex_module.cc | 25 +++++++++++++++++++++++- src/xenia/cpu/xex_module.h | 1 + src/xenia/kernel/objects/xuser_module.cc | 11 ++++++++++- src/xenia/kernel/objects/xuser_module.h | 4 ++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index af6f6e588..f3f36951b 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -41,11 +41,19 @@ XexModule::XexModule(Processor* processor, KernelState* kernel_state) processor_(processor), kernel_state_(kernel_state), xex_(nullptr), + xex_header_(nullptr), base_address_(0), low_address_(0), high_address_(0) {} -XexModule::~XexModule() { xe_xex2_dealloc(xex_); } +XexModule::~XexModule() { + xe_xex2_dealloc(xex_); + + if (xex_header_) { + delete[] xex_header_; + xex_header_ = nullptr; + } +} bool XexModule::GetOptHeader(const xex2_header* header, xe_xex2_header_keys key, void** out_ptr) { @@ -287,6 +295,21 @@ bool XexModule::Load(const std::string& name, const std::string& path, return true; } +bool XexModule::Unload() { + // Just deallocate the memory occupied by the exe + uint32_t exe_address = 0; + GetOptHeader(XEX_HEADER_IMAGE_BASE_ADDRESS, &exe_address); + assert_not_zero(exe_address); + + memory()->LookupHeap(exe_address)->Release(exe_address); + + assert_not_null(xex_header_); // Unloading a module that wasn't loaded? + delete[] xex_header_; + xex_header_ = nullptr; + + return true; +} + bool XexModule::SetupLibraryImports(const char* name, const xex2_import_library* library) { ExportResolver* kernel_resolver = nullptr; diff --git a/src/xenia/cpu/xex_module.h b/src/xenia/cpu/xex_module.h index f4723a6cb..692e0e4fe 100644 --- a/src/xenia/cpu/xex_module.h +++ b/src/xenia/cpu/xex_module.h @@ -68,6 +68,7 @@ class XexModule : public xe::cpu::Module { bool Load(const std::string& name, const std::string& path, const void* xex_addr, size_t xex_length); bool Load(const std::string& name, const std::string& path, xe_xex2_ref xex); + bool Unload(); const std::string& name() const override { return name_; } diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index f4fbdee69..ab2094b6d 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -24,7 +24,7 @@ using namespace xe::cpu; XUserModule::XUserModule(KernelState* kernel_state, const char* path) : XModule(kernel_state, ModuleType::kUserModule, path) {} -XUserModule::~XUserModule() {} +XUserModule::~XUserModule() { Unload(); } X_STATUS XUserModule::LoadFromFile(std::string path) { X_STATUS result = X_STATUS_UNSUCCESSFUL; @@ -111,6 +111,15 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) { return X_STATUS_SUCCESS; } +X_STATUS XUserModule::Unload() { + if (!xex_module()->Unload()) { + return X_STATUS_UNSUCCESSFUL; + } + + OnUnload(); + return X_STATUS_SUCCESS; +} + uint32_t XUserModule::GetProcAddressByOrdinal(uint16_t ordinal) { return xex_module()->GetProcAddress(ordinal); } diff --git a/src/xenia/kernel/objects/xuser_module.h b/src/xenia/kernel/objects/xuser_module.h index 3f3da1ac3..dc9a168dd 100644 --- a/src/xenia/kernel/objects/xuser_module.h +++ b/src/xenia/kernel/objects/xuser_module.h @@ -29,6 +29,9 @@ class XUserModule : public XModule { const xe::cpu::XexModule* xex_module() const { return reinterpret_cast(processor_module_); } + xe::cpu::XexModule* xex_module() { + return reinterpret_cast(processor_module_); + } const xex2_header* xex_header() const { return xex_module()->xex_header(); } uint32_t guest_xex_header() const { return guest_xex_header_; } @@ -39,6 +42,7 @@ class XUserModule : public XModule { X_STATUS LoadFromFile(std::string path); X_STATUS LoadFromMemory(const void* addr, const size_t length); + X_STATUS Unload(); uint32_t GetProcAddressByOrdinal(uint16_t ordinal) override; uint32_t GetProcAddressByName(const char* name) override; From 778acac9292685e416e60a24995b49700329320b Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 14:44:43 -0500 Subject: [PATCH 07/24] XThread Terminate --- src/xenia/kernel/objects/xthread.cc | 30 +++++++++++++++++++++++++++++ src/xenia/kernel/objects/xthread.h | 2 ++ 2 files changed, 32 insertions(+) diff --git a/src/xenia/kernel/objects/xthread.cc b/src/xenia/kernel/objects/xthread.cc index 46ef3707b..ff746a70f 100644 --- a/src/xenia/kernel/objects/xthread.cc +++ b/src/xenia/kernel/objects/xthread.cc @@ -337,6 +337,8 @@ X_STATUS XThread::Create() { } X_STATUS XThread::Exit(int exit_code) { + assert_true(XThread::GetCurrentThread() == this); + // TODO(benvanik): set exit code in thread state block // TODO(benvanik); dispatch events? waiters? etc? @@ -359,6 +361,21 @@ X_STATUS XThread::Exit(int exit_code) { return X_STATUS_SUCCESS; } +X_STATUS XThread::Terminate(int exit_code) { + if (event_) { + event_->Set(0, false); + } + // TODO: Inform the profiler that this thread is exiting. + + Release(); + X_STATUS status = PlatformTerminate(exit_code); + if (XFAILED(status)) { + return status; + } + + return X_STATUS_SUCCESS; +} + #if XE_PLATFORM_WIN32 static uint32_t __stdcall XThreadStartCallbackWin32(void* param) { @@ -406,6 +423,14 @@ X_STATUS XThread::PlatformExit(int exit_code) { return X_STATUS_SUCCESS; } +X_STATUS XThread::PlatformTerminate(int exit_code) { + if (!TerminateThread(thread_handle_, exit_code)) { + return X_STATUS_UNSUCCESSFUL; + } + + return X_STATUS_SUCCESS; +} + #else static void* XThreadStartCallbackPthreads(void* param) { @@ -465,6 +490,11 @@ X_STATUS XThread::PlatformExit(int exit_code) { return X_STATUS_SUCCESS; } +X_STATUS XThread::PlatformTerminate(int exit_code) { + // TODO! + assert_always(); +} + #endif // WIN32 void XThread::Execute() { diff --git a/src/xenia/kernel/objects/xthread.h b/src/xenia/kernel/objects/xthread.h index 70e2a8ed2..4f0023679 100644 --- a/src/xenia/kernel/objects/xthread.h +++ b/src/xenia/kernel/objects/xthread.h @@ -103,6 +103,7 @@ class XThread : public XObject { X_STATUS Create(); X_STATUS Exit(int exit_code); + X_STATUS Terminate(int exit_code); virtual void Execute(); @@ -137,6 +138,7 @@ class XThread : public XObject { X_STATUS PlatformCreate(); void PlatformDestroy(); X_STATUS PlatformExit(int exit_code); + X_STATUS PlatformTerminate(int exit_code); static void DeliverAPCs(void* data); void RundownAPCs(); From 567bb525f83c5ec1865b17593aa73a62ebc31170 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 15:41:47 -0500 Subject: [PATCH 08/24] Fix incorrectly getting the exe address --- src/xenia/cpu/xex_module.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index f3f36951b..e800829a0 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -297,11 +297,11 @@ bool XexModule::Load(const std::string& name, const std::string& path, bool XexModule::Unload() { // Just deallocate the memory occupied by the exe - uint32_t exe_address = 0; + xe::be* exe_address = 0; GetOptHeader(XEX_HEADER_IMAGE_BASE_ADDRESS, &exe_address); assert_not_zero(exe_address); - memory()->LookupHeap(exe_address)->Release(exe_address); + memory()->LookupHeap(*exe_address)->Release(*exe_address); assert_not_null(xex_header_); // Unloading a module that wasn't loaded? delete[] xex_header_; From 5ccea06e7fb8cee492466172be8b64ae8580db84 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 15:42:30 -0500 Subject: [PATCH 09/24] KernelState::TerminateTitle --- src/xenia/kernel/kernel_state.cc | 43 ++++++++++++++++++++++++++++++++ src/xenia/kernel/kernel_state.h | 3 +++ 2 files changed, 46 insertions(+) diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index 256bb3cdd..15f10e818 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -302,6 +302,49 @@ object_ref KernelState::LoadUserModule(const char* raw_name) { return module; } +void KernelState::TerminateTitle(bool from_guest_thread) { + std::lock_guard lock(object_mutex_); + + // First: Kill all guest threads. + for (auto it = threads_by_id_.begin(); it != threads_by_id_.end();) { + if (it->second->guest_thread()) { + auto thread = it->second; + + if (from_guest_thread && XThread::IsInThread(thread)) { + // Don't terminate ourselves. + continue; + } + + if (it->second->running()) { + thread->Terminate(0); + } + + // Erase it from the thread list. + it = threads_by_id_.erase(it); + } else { + ++it; + } + } + + // Second: Unload all user modules (including the executable) + for (int i = 0; i < user_modules_.size(); i++) { + X_STATUS status = user_modules_[i]->Unload(); + assert_true(XSUCCEEDED(status)); + + object_table_->RemoveHandle(user_modules_[i]->handle()); + } + user_modules_.clear(); + + if (from_guest_thread) { + // Now commit suicide (using Terminate, because we can't call into guest + // code anymore) + // Also, manually invoke the lock guard's destructor, because Terminate + // does not return. + lock.~lock_guard(); + XThread::GetCurrentThread()->Terminate(0); + } +} + void KernelState::RegisterThread(XThread* thread) { std::lock_guard lock(object_mutex_); threads_by_id_[thread->thread_id()] = thread; diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index 8b448ea5f..e625d7809 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -122,6 +122,9 @@ class KernelState { } object_ref LoadUserModule(const char* name); + // Terminates a title: Unloads all modules, and kills all guest threads. + void TerminateTitle(bool from_guest_thread = false); + void RegisterThread(XThread* thread); void UnregisterThread(XThread* thread); void OnThreadExecute(XThread* thread); From 57e89e72b1073b19b5a4ae8f5fa79fd45b856308 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 15:43:09 -0500 Subject: [PATCH 10/24] Use the actual thread handle as a wait handle, add bool XThread::running --- src/xenia/kernel/objects/xthread.cc | 20 +++++++------------- src/xenia/kernel/objects/xthread.h | 4 ++-- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/xenia/kernel/objects/xthread.cc b/src/xenia/kernel/objects/xthread.cc index ff746a70f..538f82324 100644 --- a/src/xenia/kernel/objects/xthread.cc +++ b/src/xenia/kernel/objects/xthread.cc @@ -52,7 +52,8 @@ XThread::XThread(KernelState* kernel_state, uint32_t stack_size, priority_(0), affinity_(0), irql_(0), - guest_thread_(guest_thread) { + guest_thread_(guest_thread), + running_(false) { creation_params_.stack_size = stack_size; creation_params_.xapi_thread_startup = xapi_thread_startup; creation_params_.start_address = start_address; @@ -69,9 +70,6 @@ XThread::XThread(KernelState* kernel_state, uint32_t stack_size, apc_list_ = new NativeList(kernel_state->memory()); - event_ = object_ref(new XEvent(kernel_state)); - event_->Initialize(true, false); - char thread_name[32]; snprintf(thread_name, xe::countof(thread_name), "XThread%04X", handle()); set_name(thread_name); @@ -86,8 +84,6 @@ XThread::~XThread() { delete apc_list_; - event_.reset(); - PlatformDestroy(); if (thread_state_) { @@ -342,9 +338,6 @@ X_STATUS XThread::Exit(int exit_code) { // TODO(benvanik): set exit code in thread state block // TODO(benvanik); dispatch events? waiters? etc? - if (event_) { - event_->Set(0, false); - } RundownAPCs(); kernel_state()->OnThreadExit(this); @@ -353,6 +346,7 @@ X_STATUS XThread::Exit(int exit_code) { current_thread_tls = nullptr; xe::Profiler::ThreadExit(); + running_ = false; Release(); X_STATUS return_code = PlatformExit(exit_code); if (XFAILED(return_code)) { @@ -362,11 +356,9 @@ X_STATUS XThread::Exit(int exit_code) { } X_STATUS XThread::Terminate(int exit_code) { - if (event_) { - event_->Set(0, false); - } // TODO: Inform the profiler that this thread is exiting. + running_ = false; Release(); X_STATUS status = PlatformTerminate(exit_code); if (XFAILED(status)) { @@ -501,6 +493,7 @@ void XThread::Execute() { XELOGKERNEL("XThread::Execute thid %d (handle=%.8X, '%s', native=%.8X)", thread_id_, handle(), name_.c_str(), xe::threading::current_thread_id()); + running_ = true; // Let the kernel know we are starting. kernel_state()->OnThreadExecute(this); @@ -530,6 +523,7 @@ void XThread::Execute() { // Treat the return code as an implicit exit code. } + running_ = false; Exit(exit_code); } @@ -786,7 +780,7 @@ X_STATUS XThread::Delay(uint32_t processor_mode, uint32_t alertable, } } -void* XThread::GetWaitHandle() { return event_->GetWaitHandle(); } +void* XThread::GetWaitHandle() { return thread_handle_; } XHostThread::XHostThread(KernelState* kernel_state, uint32_t stack_size, uint32_t creation_flags, std::function host_fn) diff --git a/src/xenia/kernel/objects/xthread.h b/src/xenia/kernel/objects/xthread.h index 4f0023679..a9914fb52 100644 --- a/src/xenia/kernel/objects/xthread.h +++ b/src/xenia/kernel/objects/xthread.h @@ -93,6 +93,7 @@ class XThread : public XObject { uint32_t pcr_ptr() const { return pcr_address_; } uint32_t thread_state_ptr() const { return thread_state_address_; } bool guest_thread() const { return guest_thread_; } + bool running() const { return running_; } cpu::ThreadState* thread_state() const { return thread_state_; } uint32_t thread_id() const { return thread_id_; } @@ -160,6 +161,7 @@ class XThread : public XObject { uint32_t thread_state_address_; cpu::ThreadState* thread_state_; bool guest_thread_; // Launched into guest code? + bool running_; std::string name_; @@ -169,8 +171,6 @@ class XThread : public XObject { std::atomic irql_; xe::mutex apc_lock_; NativeList* apc_list_; - - object_ref event_; }; class XHostThread : public XThread { From d6686fc34598c28af9267744636ecb0760b30706 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 15:44:02 -0500 Subject: [PATCH 11/24] Load default.xex as a regular module and call TerminateTitle when the main thread exits. --- src/xenia/kernel/xboxkrnl_module.cc | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl_module.cc b/src/xenia/kernel/xboxkrnl_module.cc index 016da3eb9..6af08be9e 100644 --- a/src/xenia/kernel/xboxkrnl_module.cc +++ b/src/xenia/kernel/xboxkrnl_module.cc @@ -177,14 +177,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. - auto module = object_ref(new XUserModule(kernel_state_, path)); - - // Load the module into memory from the filesystem. - X_STATUS result_code = module->LoadFromFile(path); - if (XFAILED(result_code)) { - XELOGE("Failed to load module %s: %.8X", path, result_code); - return 1; - } + auto module = kernel_state_->LoadUserModule(path); // Set as the main module, while running. kernel_state_->SetExecutableModule(module); @@ -196,7 +189,10 @@ int XboxkrnlModule::LaunchModule(const char* path) { // Launch the module. // NOTE: this won't return until the module exits. - result_code = module->Launch(0); + X_STATUS result_code = module->Launch(0); + + // Main thread exited. Terminate the title. + kernel_state_->TerminateTitle(); kernel_state_->SetExecutableModule(NULL); if (XFAILED(result_code)) { XELOGE("Failed to launch module %s: %.8X", path, result_code); From 39d6e9a20f2200bc908fef6b82b53a42f6c15519 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 15:44:46 -0500 Subject: [PATCH 12/24] Implement XamLoaderLaunchTitle and other loader functions. --- src/xenia/emulator.cc | 21 ++++++- src/xenia/kernel/xam_info.cc | 110 ++++++++++++++++++++++----------- src/xenia/kernel/xam_module.cc | 3 +- src/xenia/kernel/xam_module.h | 18 ++++++ 4 files changed, 113 insertions(+), 39 deletions(-) diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index 93fdd4ee8..8ea87f50d 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -274,10 +274,29 @@ X_STATUS Emulator::LaunchStfsContainer(std::wstring path) { X_STATUS Emulator::CompleteLaunch(const std::wstring& path, const std::string& module_path) { + // Allow xam to request module loads. + auto xam_module = kernel_state_->GetModule("xam.xex"); + auto xam = kernel::object_ref( + reinterpret_cast(xam_module.release())); + auto xboxkrnl_module = kernel_state_->GetModule("xboxkrnl.exe"); auto xboxkrnl = kernel::object_ref( reinterpret_cast(xboxkrnl_module.release())); - int result = xboxkrnl->LaunchModule(module_path.c_str()); + + int result = 0; + auto next_module = module_path; + while (next_module != "") { + XELOGI("Launching module %s", next_module.c_str()); + result = xboxkrnl->LaunchModule(next_module.c_str()); + + // Check xam and see if they want us to load another module. + auto& loader_data = xam->loader_data(); + next_module = loader_data.launch_path; + + // And blank out the launch path to avoid an infinite loop. + loader_data.launch_path = ""; + } + if (result == 0) { return X_STATUS_SUCCESS; } else { diff --git a/src/xenia/kernel/xam_info.cc b/src/xenia/kernel/xam_info.cc index 980e565d4..8fbacd9ad 100644 --- a/src/xenia/kernel/xam_info.cc +++ b/src/xenia/kernel/xam_info.cc @@ -11,8 +11,10 @@ #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/objects/xenumerator.h" #include "xenia/kernel/objects/xuser_module.h" +#include "xenia/kernel/objects/xthread.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/util/xex2.h" +#include "xenia/kernel/xam_module.h" #include "xenia/kernel/xam_private.h" #include "xenia/xbox.h" @@ -90,53 +92,93 @@ SHIM_CALL XamGetExecutionId_shim(PPCContext* ppc_context, SHIM_SET_RETURN_32(X_STATUS_SUCCESS); } -SHIM_CALL XamLoaderSetLaunchData_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t data_ptr = SHIM_GET_ARG_32(0); - uint32_t data_size = SHIM_GET_ARG_32(1); +dword_result_t XamLoaderSetLaunchData(lpvoid_t data, dword_t size) { + auto xam_module = kernel_state()->GetModule("xam.xex"); + auto xam = kernel::object_ref( + reinterpret_cast(xam_module.release())); - XELOGD("XamLoaderSetLaunchData(%.8X, %d)", data_ptr, data_size); + auto& loader_data = xam->loader_data(); + if (loader_data.launch_data_ptr) { + kernel_memory()->SystemHeapFree(loader_data.launch_data_ptr); + } - // Unknown return value. - SHIM_SET_RETURN_32(0); + loader_data.launch_data_ptr = kernel_memory()->SystemHeapAlloc(size); + loader_data.launch_data_size = size; + + std::memcpy(kernel_memory()->TranslateVirtual(loader_data.launch_data_ptr), + data, size); + + // FIXME: Unknown return value. + return 0; } +DECLARE_XAM_EXPORT(XamLoaderSetLaunchData, ExportTag::kSketchy); -SHIM_CALL XamLoaderGetLaunchDataSize_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t size_ptr = SHIM_GET_ARG_32(0); +dword_result_t XamLoaderGetLaunchDataSize(lpdword_t size_ptr) { + auto xam_module = kernel_state()->GetModule("xam.xex"); + auto xam = kernel::object_ref( + reinterpret_cast(xam_module.release())); - XELOGD("XamLoaderGetLaunchDataSize(%.8X)", size_ptr); + *size_ptr = xam->loader_data().launch_data_size; - SHIM_SET_MEM_32(size_ptr, 0); - - SHIM_SET_RETURN_32(1); + // FIXME: What do we return? + return 1; } +DECLARE_XAM_EXPORT(XamLoaderGetLaunchDataSize, ExportTag::kSketchy); -SHIM_CALL XamLoaderGetLaunchData_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t buffer_ptr = SHIM_GET_ARG_32(0); - uint32_t buffer_size = SHIM_GET_ARG_32(1); +dword_result_t XamLoaderGetLaunchData(lpvoid_t buffer_ptr, dword_t buffer_size) { + auto xam_module = kernel_state()->GetModule("xam.xex"); + auto xam = kernel::object_ref( + reinterpret_cast(xam_module.release())); - XELOGD("XamLoaderGetLaunchData(%.8X, %d)", buffer_ptr, buffer_size); + auto& loader_data = xam->loader_data(); + if (loader_data.launch_data_ptr) { + uint8_t* loader_buffer_ptr = + kernel_memory()->TranslateVirtual(loader_data.launch_data_ptr); - SHIM_SET_RETURN_32(0); + uint32_t copy_size = + std::min(loader_data.launch_data_size, (uint32_t)buffer_size); + + std::memcpy(buffer_ptr, loader_buffer_ptr, copy_size); + } + + // FIXME: Unknown return value. + return 0; } +DECLARE_XAM_EXPORT(XamLoaderGetLaunchData, ExportTag::kSketchy); -SHIM_CALL XamLoaderLaunchTitle_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t name_ptr = SHIM_GET_ARG_32(0); - const char* name = (const char*)SHIM_MEM_ADDR(name_ptr); - uint32_t flags = SHIM_GET_ARG_32(1); +void XamLoaderLaunchTitle(lpstring_t raw_name, dword_t flags) { + auto xam_module = kernel_state()->GetModule("xam.xex"); + auto xam = kernel::object_ref( + reinterpret_cast(xam_module.release())); - XELOGD("XamLoaderLaunchTitle(%.8X(%s), %.8X)", name_ptr, name, flags); - assert_always(); + auto& loader_data = xam->loader_data(); + loader_data.launch_flags = flags; + + // Translate the launch path to a full path. + if (raw_name) { + std::string name = xe::find_name_from_path(std::string(raw_name)); + std::string path(raw_name); + if (name == std::string(raw_name)) { + path = xe::join_paths( + xe::find_base_path(kernel_state()->GetExecutableModule()->path()), + name); + } + + loader_data.launch_path = path; + } else { + assert_always("Game requested exit to dashboard via XamLoaderLaunchTitle"); + } + + // This function does not return. + XThread::GetCurrentThread()->Exit(0); } +DECLARE_XAM_EXPORT(XamLoaderLaunchTitle, ExportTag::kSketchy); -SHIM_CALL XamLoaderTerminateTitle_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - XELOGD("XamLoaderTerminateTitle()"); - assert_always(); +void XamLoaderTerminateTitle() { + // This function does not return. + XThread::GetCurrentThread()->Exit(0); } +DECLARE_XAM_EXPORT(XamLoaderTerminateTitle, ExportTag::kSketchy); SHIM_CALL XamAlloc_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t unk = SHIM_GET_ARG_32(0); @@ -223,12 +265,6 @@ void xe::kernel::xam::RegisterInfoExports( SHIM_SET_MAPPING("xam.xex", XamGetExecutionId, state); - SHIM_SET_MAPPING("xam.xex", XamLoaderSetLaunchData, state); - SHIM_SET_MAPPING("xam.xex", XamLoaderGetLaunchDataSize, state); - SHIM_SET_MAPPING("xam.xex", XamLoaderGetLaunchData, state); - SHIM_SET_MAPPING("xam.xex", XamLoaderLaunchTitle, state); - SHIM_SET_MAPPING("xam.xex", XamLoaderTerminateTitle, state); - SHIM_SET_MAPPING("xam.xex", XamAlloc, state); SHIM_SET_MAPPING("xam.xex", XamFree, state); diff --git a/src/xenia/kernel/xam_module.cc b/src/xenia/kernel/xam_module.cc index df3455eeb..254f88d09 100644 --- a/src/xenia/kernel/xam_module.cc +++ b/src/xenia/kernel/xam_module.cc @@ -17,7 +17,8 @@ namespace xe { namespace kernel { XamModule::XamModule(Emulator* emulator, KernelState* kernel_state) - : XKernelModule(kernel_state, "xe:\\xam.xex") { + : XKernelModule(kernel_state, "xe:\\xam.xex") + , loader_data_() { RegisterExportTable(export_resolver_); // Register all exported functions. diff --git a/src/xenia/kernel/xam_module.h b/src/xenia/kernel/xam_module.h index 370ee472f..ab8093491 100644 --- a/src/xenia/kernel/xam_module.h +++ b/src/xenia/kernel/xam_module.h @@ -24,7 +24,25 @@ class XamModule : public XKernelModule { static void RegisterExportTable(xe::cpu::ExportResolver* export_resolver); + struct LoaderData { + LoaderData() { + launch_data_ptr = 0; + launch_data_size = 0; + launch_flags = 0; + launch_path = ""; + } + + uint32_t launch_data_ptr; + uint32_t launch_data_size; + uint32_t launch_flags; + std::string launch_path; // Full path to next xex + }; + + const LoaderData& loader_data() const { return loader_data_; } + LoaderData& loader_data() { return loader_data_; } + private: + LoaderData loader_data_; }; } // namespace kernel From ff72a252601436a4d78f80063415bbef198392f9 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 15:54:30 -0500 Subject: [PATCH 13/24] Remove dump on module launch (already dumped on load!) --- src/xenia/kernel/objects/xuser_module.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index ab2094b6d..9209c2172 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -211,7 +211,6 @@ X_STATUS XUserModule::GetOptHeader(uint8_t* membase, const xex2_header* header, X_STATUS XUserModule::Launch(uint32_t flags) { XELOGI("Launching module..."); - Dump(); // Create a thread to run in. auto thread = object_ref( From 82986c6eec0503203604f2df96bbba813265a4f7 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 16:22:45 -0500 Subject: [PATCH 14/24] Use TerminateTitle rather than relying on XamLoader* being called from the main thread. --- src/xenia/kernel/kernel_state.cc | 3 +++ src/xenia/kernel/xam_info.cc | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index 15f10e818..ed71209da 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -312,6 +312,7 @@ void KernelState::TerminateTitle(bool from_guest_thread) { if (from_guest_thread && XThread::IsInThread(thread)) { // Don't terminate ourselves. + ++it; continue; } @@ -336,6 +337,8 @@ void KernelState::TerminateTitle(bool from_guest_thread) { user_modules_.clear(); if (from_guest_thread) { + threads_by_id_.erase(XThread::GetCurrentThread()->thread_id()); + // Now commit suicide (using Terminate, because we can't call into guest // code anymore) // Also, manually invoke the lock guard's destructor, because Terminate diff --git a/src/xenia/kernel/xam_info.cc b/src/xenia/kernel/xam_info.cc index 8fbacd9ad..1042417df 100644 --- a/src/xenia/kernel/xam_info.cc +++ b/src/xenia/kernel/xam_info.cc @@ -170,13 +170,13 @@ void XamLoaderLaunchTitle(lpstring_t raw_name, dword_t flags) { } // This function does not return. - XThread::GetCurrentThread()->Exit(0); + kernel_state()->TerminateTitle(true); } DECLARE_XAM_EXPORT(XamLoaderLaunchTitle, ExportTag::kSketchy); void XamLoaderTerminateTitle() { // This function does not return. - XThread::GetCurrentThread()->Exit(0); + kernel_state()->TerminateTitle(true); } DECLARE_XAM_EXPORT(XamLoaderTerminateTitle, ExportTag::kSketchy); From 4e6b036b3c8061d9a1381287c13381390148d521 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 16:28:11 -0500 Subject: [PATCH 15/24] Formatting. --- src/xenia/cpu/xex_module.cc | 2 +- src/xenia/kernel/objects/xthread.h | 2 +- src/xenia/kernel/xam_info.cc | 5 +++-- src/xenia/kernel/xam_module.cc | 3 +-- src/xenia/kernel/xam_module.h | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index e800829a0..3dbfbe143 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -303,7 +303,7 @@ bool XexModule::Unload() { memory()->LookupHeap(*exe_address)->Release(*exe_address); - assert_not_null(xex_header_); // Unloading a module that wasn't loaded? + assert_not_null(xex_header_); // Unloading a module that wasn't loaded? delete[] xex_header_; xex_header_ = nullptr; diff --git a/src/xenia/kernel/objects/xthread.h b/src/xenia/kernel/objects/xthread.h index a9914fb52..8793381e7 100644 --- a/src/xenia/kernel/objects/xthread.h +++ b/src/xenia/kernel/objects/xthread.h @@ -160,7 +160,7 @@ class XThread : public XObject { uint32_t pcr_address_; uint32_t thread_state_address_; cpu::ThreadState* thread_state_; - bool guest_thread_; // Launched into guest code? + bool guest_thread_; // Launched into guest code? bool running_; std::string name_; diff --git a/src/xenia/kernel/xam_info.cc b/src/xenia/kernel/xam_info.cc index 1042417df..6c51687f7 100644 --- a/src/xenia/kernel/xam_info.cc +++ b/src/xenia/kernel/xam_info.cc @@ -125,7 +125,8 @@ dword_result_t XamLoaderGetLaunchDataSize(lpdword_t size_ptr) { } DECLARE_XAM_EXPORT(XamLoaderGetLaunchDataSize, ExportTag::kSketchy); -dword_result_t XamLoaderGetLaunchData(lpvoid_t buffer_ptr, dword_t buffer_size) { +dword_result_t XamLoaderGetLaunchData(lpvoid_t buffer_ptr, + dword_t buffer_size) { auto xam_module = kernel_state()->GetModule("xam.xex"); auto xam = kernel::object_ref( reinterpret_cast(xam_module.release())); @@ -153,7 +154,7 @@ void XamLoaderLaunchTitle(lpstring_t raw_name, dword_t flags) { auto& loader_data = xam->loader_data(); loader_data.launch_flags = flags; - + // Translate the launch path to a full path. if (raw_name) { std::string name = xe::find_name_from_path(std::string(raw_name)); diff --git a/src/xenia/kernel/xam_module.cc b/src/xenia/kernel/xam_module.cc index 254f88d09..79199217d 100644 --- a/src/xenia/kernel/xam_module.cc +++ b/src/xenia/kernel/xam_module.cc @@ -17,8 +17,7 @@ namespace xe { namespace kernel { XamModule::XamModule(Emulator* emulator, KernelState* kernel_state) - : XKernelModule(kernel_state, "xe:\\xam.xex") - , loader_data_() { + : XKernelModule(kernel_state, "xe:\\xam.xex"), loader_data_() { RegisterExportTable(export_resolver_); // Register all exported functions. diff --git a/src/xenia/kernel/xam_module.h b/src/xenia/kernel/xam_module.h index ab8093491..2e0627ded 100644 --- a/src/xenia/kernel/xam_module.h +++ b/src/xenia/kernel/xam_module.h @@ -35,14 +35,14 @@ class XamModule : public XKernelModule { uint32_t launch_data_ptr; uint32_t launch_data_size; uint32_t launch_flags; - std::string launch_path; // Full path to next xex + std::string launch_path; // Full path to next xex }; const LoaderData& loader_data() const { return loader_data_; } LoaderData& loader_data() { return loader_data_; } private: - LoaderData loader_data_; + LoaderData loader_data_; }; } // namespace kernel From fd136c1f9f26cdd8f71c451d7b3798aef38558e7 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 17:05:58 -0500 Subject: [PATCH 16/24] Swap to default initializers. --- src/xenia/kernel/xam_module.h | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/xenia/kernel/xam_module.h b/src/xenia/kernel/xam_module.h index 2e0627ded..50897457e 100644 --- a/src/xenia/kernel/xam_module.h +++ b/src/xenia/kernel/xam_module.h @@ -25,16 +25,9 @@ class XamModule : public XKernelModule { static void RegisterExportTable(xe::cpu::ExportResolver* export_resolver); struct LoaderData { - LoaderData() { - launch_data_ptr = 0; - launch_data_size = 0; - launch_flags = 0; - launch_path = ""; - } - - uint32_t launch_data_ptr; - uint32_t launch_data_size; - uint32_t launch_flags; + uint32_t launch_data_ptr = 0; + uint32_t launch_data_size = 0; + uint32_t launch_flags = 0; std::string launch_path; // Full path to next xex }; From 8adbc2cd0c1af2619a2c8a5586f9ec17dd3606d8 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 17:14:42 -0500 Subject: [PATCH 17/24] Return 0 for success --- src/xenia/kernel/xam_info.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/xenia/kernel/xam_info.cc b/src/xenia/kernel/xam_info.cc index 6c51687f7..5bd13f619 100644 --- a/src/xenia/kernel/xam_info.cc +++ b/src/xenia/kernel/xam_info.cc @@ -120,8 +120,7 @@ dword_result_t XamLoaderGetLaunchDataSize(lpdword_t size_ptr) { *size_ptr = xam->loader_data().launch_data_size; - // FIXME: What do we return? - return 1; + return 0; } DECLARE_XAM_EXPORT(XamLoaderGetLaunchDataSize, ExportTag::kSketchy); @@ -142,7 +141,6 @@ dword_result_t XamLoaderGetLaunchData(lpvoid_t buffer_ptr, std::memcpy(buffer_ptr, loader_buffer_ptr, copy_size); } - // FIXME: Unknown return value. return 0; } DECLARE_XAM_EXPORT(XamLoaderGetLaunchData, ExportTag::kSketchy); From 870aa092bb2ebc3a06977ebd59e37ba25e642c42 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 17:27:25 -0500 Subject: [PATCH 18/24] KernelState::GetKernelModule --- src/xenia/emulator.cc | 10 +++------- src/xenia/kernel/kernel_state.cc | 12 ++++++++++++ src/xenia/kernel/kernel_state.h | 10 +++++++++- src/xenia/kernel/xam_info.cc | 16 ++++------------ 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index 8ea87f50d..2ce75b66e 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -275,13 +275,9 @@ X_STATUS Emulator::LaunchStfsContainer(std::wstring path) { X_STATUS Emulator::CompleteLaunch(const std::wstring& path, const std::string& module_path) { // Allow xam to request module loads. - auto xam_module = kernel_state_->GetModule("xam.xex"); - auto xam = kernel::object_ref( - reinterpret_cast(xam_module.release())); - - auto xboxkrnl_module = kernel_state_->GetModule("xboxkrnl.exe"); - auto xboxkrnl = kernel::object_ref( - reinterpret_cast(xboxkrnl_module.release())); + auto xam = kernel_state()->GetKernelModule("xam.xex"); + auto xboxkrnl = + kernel_state()->GetKernelModule("xboxkrnl.exe"); int result = 0; auto next_module = module_path; diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index ed71209da..b90571b06 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -161,6 +161,18 @@ bool KernelState::IsKernelModule(const char* name) { return false; } +object_ref KernelState::GetKernelModule(const char* name) { + assert_true(IsKernelModule(name)); + + for (auto kernel_module : kernel_modules_) { + if (kernel_module->Matches(name)) { + return retain_object(kernel_module.get()); + } + } + + return nullptr; +} + object_ref KernelState::GetModule(const char* name) { if (!name) { // NULL name = self. diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index e625d7809..28e074698 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -112,15 +112,23 @@ class KernelState { void UnregisterModule(XModule* module); bool IsKernelModule(const char* name); object_ref GetModule(const char* name); + object_ref GetExecutableModule(); void SetExecutableModule(object_ref module); + object_ref LoadUserModule(const char* name); + + object_ref GetKernelModule(const char* name); template object_ref LoadKernelModule() { auto kernel_module = object_ref(new T(emulator_, this)); LoadKernelModule(kernel_module); return kernel_module; } - object_ref LoadUserModule(const char* name); + template + object_ref GetKernelModule(const char* name) { + auto module = GetKernelModule(name); + return object_ref(reinterpret_cast(module.release())); + } // Terminates a title: Unloads all modules, and kills all guest threads. void TerminateTitle(bool from_guest_thread = false); diff --git a/src/xenia/kernel/xam_info.cc b/src/xenia/kernel/xam_info.cc index 5bd13f619..ee095bb5a 100644 --- a/src/xenia/kernel/xam_info.cc +++ b/src/xenia/kernel/xam_info.cc @@ -93,9 +93,7 @@ SHIM_CALL XamGetExecutionId_shim(PPCContext* ppc_context, } dword_result_t XamLoaderSetLaunchData(lpvoid_t data, dword_t size) { - auto xam_module = kernel_state()->GetModule("xam.xex"); - auto xam = kernel::object_ref( - reinterpret_cast(xam_module.release())); + auto xam = kernel_state()->GetKernelModule("xam.xex"); auto& loader_data = xam->loader_data(); if (loader_data.launch_data_ptr) { @@ -114,9 +112,7 @@ dword_result_t XamLoaderSetLaunchData(lpvoid_t data, dword_t size) { DECLARE_XAM_EXPORT(XamLoaderSetLaunchData, ExportTag::kSketchy); dword_result_t XamLoaderGetLaunchDataSize(lpdword_t size_ptr) { - auto xam_module = kernel_state()->GetModule("xam.xex"); - auto xam = kernel::object_ref( - reinterpret_cast(xam_module.release())); + auto xam = kernel_state()->GetKernelModule("xam.xex"); *size_ptr = xam->loader_data().launch_data_size; @@ -126,9 +122,7 @@ DECLARE_XAM_EXPORT(XamLoaderGetLaunchDataSize, ExportTag::kSketchy); dword_result_t XamLoaderGetLaunchData(lpvoid_t buffer_ptr, dword_t buffer_size) { - auto xam_module = kernel_state()->GetModule("xam.xex"); - auto xam = kernel::object_ref( - reinterpret_cast(xam_module.release())); + auto xam = kernel_state()->GetKernelModule("xam.xex"); auto& loader_data = xam->loader_data(); if (loader_data.launch_data_ptr) { @@ -146,9 +140,7 @@ dword_result_t XamLoaderGetLaunchData(lpvoid_t buffer_ptr, DECLARE_XAM_EXPORT(XamLoaderGetLaunchData, ExportTag::kSketchy); void XamLoaderLaunchTitle(lpstring_t raw_name, dword_t flags) { - auto xam_module = kernel_state()->GetModule("xam.xex"); - auto xam = kernel::object_ref( - reinterpret_cast(xam_module.release())); + auto xam = kernel_state()->GetKernelModule("xam.xex"); auto& loader_data = xam->loader_data(); loader_data.launch_flags = flags; From 6ddd0b470037893f8465ca6f6df99471d778215e Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sun, 5 Jul 2015 21:32:26 -0500 Subject: [PATCH 19/24] Rewrite InterlockedPopEntrySList --- src/xenia/kernel/xboxkrnl_threading.cc | 29 ++++++++++---------------- src/xenia/xbox.h | 25 +++++++++++++++++++--- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl_threading.cc index 9d91891b8..4769b8df3 100644 --- a/src/xenia/kernel/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl_threading.cc @@ -1348,38 +1348,31 @@ SHIM_CALL KeRemoveQueueDpc_shim(PPCContext* ppc_context, xe::mutex global_list_mutex_; -// http://www.nirsoft.net/kernel_struct/vista/SLIST_HEADER.html -struct SLIST_HEADER { - xe::be next; - xe::be depth; - xe::be sequence; -}; - -pointer_result_t InterlockedPopEntrySList(pointer_t plist_ptr) { +pointer_result_t InterlockedPopEntrySList(pointer_t plist_ptr) { std::lock_guard lock(global_list_mutex_); - uint32_t first = plist_ptr->next; - if (first == 0) { + if (plist_ptr->next.next == 0) { // List empty! return 0; } - // Get the second element. - uint8_t* p = kernel_memory()->TranslateVirtual(first); - auto second = xe::load_and_swap(p); + // Get the first element. + auto result = kernel_memory()->TranslateVirtual( + plist_ptr->next.next); - plist_ptr->next = second; + uint32_t popped = plist_ptr->next.next; + plist_ptr->next.next = result->next; // Return the one we popped - return first; + return popped; } DECLARE_XBOXKRNL_EXPORT(InterlockedPopEntrySList, ExportTag::kImplemented); -pointer_result_t InterlockedFlushSList(pointer_t plist_ptr) { +pointer_result_t InterlockedFlushSList(pointer_t plist_ptr) { std::lock_guard lock(global_list_mutex_); - uint32_t next = plist_ptr->next; - plist_ptr->next = 0; + uint32_t next = plist_ptr->next.next; + plist_ptr->next.next = 0; return next; } diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index 671bc4c9f..5c24c965a 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -280,9 +280,9 @@ struct X_ANSI_STRING { }; struct X_UNICODE_STRING { - xe::be length; - xe::be maximum_length; - xe::be pointer; + xe::be length; // 0x0 + xe::be maximum_length; // 0x2 + xe::be pointer; // 0x4 void reset() { length = 0; @@ -322,9 +322,28 @@ static_assert_size(X_VIDEO_MODE, 48); struct X_LIST_ENTRY { be flink_ptr; // next entry / head be blink_ptr; // previous entry / head + + // Assumes X_LIST_ENTRY is within guest memory! + void initialize(uint8_t* virtual_membase) { + flink_ptr = (uint32_t)((uint8_t*)this - virtual_membase); + blink_ptr = (uint32_t)((uint8_t*)this - virtual_membase); + } }; static_assert_size(X_LIST_ENTRY, 8); +struct X_SINGLE_LIST_ENTRY { + be next; // 0x0 pointer to next entry +}; +static_assert_size(X_SINGLE_LIST_ENTRY, 4); + +// http://www.nirsoft.net/kernel_struct/vista/SLIST_HEADER.html +struct X_SLIST_HEADER { + X_SINGLE_LIST_ENTRY next; // 0x0 + be depth; // 0x4 + be sequence; // 0x6 +}; +static_assert_size(X_SLIST_HEADER, 8); + #pragma pack(pop) } // namespace xe From 93f24d2047c564390b3eb1eab4b2ff8326e3238c Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 6 Jul 2015 10:40:35 -0500 Subject: [PATCH 20/24] XexModule keep track of whether it's loaded into memory or not --- src/xenia/cpu/xex_module.cc | 11 ++++++++++- src/xenia/cpu/xex_module.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index 3dbfbe143..beafe98af 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -44,7 +44,8 @@ XexModule::XexModule(Processor* processor, KernelState* kernel_state) xex_header_(nullptr), base_address_(0), low_address_(0), - high_address_(0) {} + high_address_(0), + loaded_(false) {} XexModule::~XexModule() { xe_xex2_dealloc(xex_); @@ -215,7 +216,10 @@ bool XexModule::Load(const std::string& name, const std::string& path, bool XexModule::Load(const std::string& name, const std::string& path, xe_xex2_ref xex) { + assert_false(loaded_); + loaded_ = true; xex_ = xex; + auto header = xex_header_; auto old_header = xe_xex2_get_header(xex_); @@ -296,6 +300,11 @@ bool XexModule::Load(const std::string& name, const std::string& path, } bool XexModule::Unload() { + if (!loaded_) { + return true; + } + loaded_ = false; + // Just deallocate the memory occupied by the exe xe::be* exe_address = 0; GetOptHeader(XEX_HEADER_IMAGE_BASE_ADDRESS, &exe_address); diff --git a/src/xenia/cpu/xex_module.h b/src/xenia/cpu/xex_module.h index 692e0e4fe..aa088a14e 100644 --- a/src/xenia/cpu/xex_module.h +++ b/src/xenia/cpu/xex_module.h @@ -33,6 +33,7 @@ class XexModule : public xe::cpu::Module { virtual ~XexModule(); xe_xex2_ref xex() const { return xex_; } + bool loaded() const { return loaded_; } const xex2_header* xex_header() const { return xex_header_; } const xex2_security_info* xex_security_info() const { return GetSecurityInfo(xex_header_); @@ -86,6 +87,7 @@ class XexModule : public xe::cpu::Module { std::string path_; xe_xex2_ref xex_; xex2_header* xex_header_; + bool loaded_; // Loaded into memory? uint32_t base_address_; uint32_t low_address_; From 88465de41e242c4ca0bc55b1334ae041e7202a52 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 6 Jul 2015 10:41:14 -0500 Subject: [PATCH 21/24] FscGetCacheElementCount stub --- src/xenia/kernel/xboxkrnl_io.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xenia/kernel/xboxkrnl_io.cc b/src/xenia/kernel/xboxkrnl_io.cc index 9e8795b69..05b58019e 100644 --- a/src/xenia/kernel/xboxkrnl_io.cc +++ b/src/xenia/kernel/xboxkrnl_io.cc @@ -824,6 +824,11 @@ SHIM_CALL NtFlushBuffersFile_shim(PPCContext* ppc_context, SHIM_SET_RETURN_32(result); } +dword_result_t FscGetCacheElementCount(dword_t r3) { + return 0; +} +DECLARE_XBOXKRNL_EXPORT(FscGetCacheElementCount, ExportTag::kStub); + SHIM_CALL FscSetCacheElementCount_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t unk_0 = SHIM_GET_ARG_32(0); From 0388d17a72ea7f39f608159a29863567620b5487 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 6 Jul 2015 10:41:41 -0500 Subject: [PATCH 22/24] Formatting --- src/xenia/cpu/xex_module.h | 2 +- src/xenia/kernel/xboxkrnl_io.cc | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/xenia/cpu/xex_module.h b/src/xenia/cpu/xex_module.h index aa088a14e..a8e3a8602 100644 --- a/src/xenia/cpu/xex_module.h +++ b/src/xenia/cpu/xex_module.h @@ -87,7 +87,7 @@ class XexModule : public xe::cpu::Module { std::string path_; xe_xex2_ref xex_; xex2_header* xex_header_; - bool loaded_; // Loaded into memory? + bool loaded_; // Loaded into memory? uint32_t base_address_; uint32_t low_address_; diff --git a/src/xenia/kernel/xboxkrnl_io.cc b/src/xenia/kernel/xboxkrnl_io.cc index 05b58019e..8ca2b0665 100644 --- a/src/xenia/kernel/xboxkrnl_io.cc +++ b/src/xenia/kernel/xboxkrnl_io.cc @@ -824,9 +824,7 @@ SHIM_CALL NtFlushBuffersFile_shim(PPCContext* ppc_context, SHIM_SET_RETURN_32(result); } -dword_result_t FscGetCacheElementCount(dword_t r3) { - return 0; -} +dword_result_t FscGetCacheElementCount(dword_t r3) { return 0; } DECLARE_XBOXKRNL_EXPORT(FscGetCacheElementCount, ExportTag::kStub); SHIM_CALL FscSetCacheElementCount_shim(PPCContext* ppc_context, From b2241e3feffae3a666d822724b1f49365b137d0d Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 6 Jul 2015 19:19:32 -0500 Subject: [PATCH 23/24] Avoid calling OnUnload twice. --- src/xenia/kernel/objects/xuser_module.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index 9209c2172..037611d37 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -112,12 +112,17 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) { } X_STATUS XUserModule::Unload() { - if (!xex_module()->Unload()) { - return X_STATUS_UNSUCCESSFUL; + if (!xex_module()->loaded()) { + // Quick abort. + return X_STATUS_SUCCESS; } - OnUnload(); - return X_STATUS_SUCCESS; + if (xex_module()->Unload()) { + OnUnload(); + return X_STATUS_SUCCESS; + } + + return X_STATUS_UNSUCCESSFUL; } uint32_t XUserModule::GetProcAddressByOrdinal(uint16_t ordinal) { From f9977a25af23451dbfa94411c0a93ffc58deb14d Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 6 Jul 2015 19:45:10 -0500 Subject: [PATCH 24/24] Use std::vector to hold the xex header instead of new/delete --- src/xenia/cpu/xex_module.cc | 23 ++++++----------------- src/xenia/cpu/xex_module.h | 10 ++++++---- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index beafe98af..d73553a3f 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -41,20 +41,12 @@ XexModule::XexModule(Processor* processor, KernelState* kernel_state) processor_(processor), kernel_state_(kernel_state), xex_(nullptr), - xex_header_(nullptr), base_address_(0), low_address_(0), high_address_(0), loaded_(false) {} -XexModule::~XexModule() { - xe_xex2_dealloc(xex_); - - if (xex_header_) { - delete[] xex_header_; - xex_header_ = nullptr; - } -} +XexModule::~XexModule() { xe_xex2_dealloc(xex_); } bool XexModule::GetOptHeader(const xex2_header* header, xe_xex2_header_keys key, void** out_ptr) { @@ -89,7 +81,7 @@ bool XexModule::GetOptHeader(const xex2_header* header, xe_xex2_header_keys key, } bool XexModule::GetOptHeader(xe_xex2_header_keys key, void** out_ptr) const { - return XexModule::GetOptHeader(xex_header_, key, out_ptr); + return XexModule::GetOptHeader(xex_header(), key, out_ptr); } const xex2_security_info* XexModule::GetSecurityInfo( @@ -207,9 +199,9 @@ bool XexModule::Load(const std::string& name, const std::string& path, // Make a copy of the xex header. auto src_header = reinterpret_cast(xex_addr); - xex_header_ = (xex2_header*)new char[src_header->header_size]; + xex_header_mem_.resize(src_header->header_size); - std::memcpy(xex_header_, src_header, src_header->header_size); + std::memcpy(xex_header_mem_.data(), src_header, src_header->header_size); return Load(name, path, xex_); } @@ -220,7 +212,7 @@ bool XexModule::Load(const std::string& name, const std::string& path, loaded_ = true; xex_ = xex; - auto header = xex_header_; + auto header = xex_header(); auto old_header = xe_xex2_get_header(xex_); // Setup debug info. @@ -311,10 +303,7 @@ bool XexModule::Unload() { assert_not_zero(exe_address); memory()->LookupHeap(*exe_address)->Release(*exe_address); - - assert_not_null(xex_header_); // Unloading a module that wasn't loaded? - delete[] xex_header_; - xex_header_ = nullptr; + xex_header_mem_.resize(0); return true; } diff --git a/src/xenia/cpu/xex_module.h b/src/xenia/cpu/xex_module.h index a8e3a8602..b4fc3c4db 100644 --- a/src/xenia/cpu/xex_module.h +++ b/src/xenia/cpu/xex_module.h @@ -34,9 +34,11 @@ class XexModule : public xe::cpu::Module { xe_xex2_ref xex() const { return xex_; } bool loaded() const { return loaded_; } - const xex2_header* xex_header() const { return xex_header_; } + const xex2_header* xex_header() const { + return reinterpret_cast(xex_header_mem_.data()); + } const xex2_security_info* xex_security_info() const { - return GetSecurityInfo(xex_header_); + return GetSecurityInfo(xex_header()); } // Gets an optional header. Returns NULL if not found. @@ -86,8 +88,8 @@ class XexModule : public xe::cpu::Module { std::string name_; std::string path_; xe_xex2_ref xex_; - xex2_header* xex_header_; - bool loaded_; // Loaded into memory? + std::vector xex_header_mem_; // Holds the xex header + bool loaded_; // Loaded into memory? uint32_t base_address_; uint32_t low_address_;