diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index 4fed0907c..a20cbf40d 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -11,6 +11,10 @@ #include +#include "third_party/crypto/TinySHA1.hpp" +#include "third_party/crypto/rijndael-alg-fst.c" +#include "third_party/crypto/rijndael-alg-fst.h" +#include "third_party/pe/pe_image.h" #include "xenia/base/byte_order.h" #include "xenia/base/logging.h" #include "xenia/base/math.h" @@ -20,13 +24,9 @@ #include "xenia/cpu/lzx.h" #include "xenia/cpu/processor.h" #include "xenia/kernel/kernel_state.h" +#include "xenia/kernel/user_module.h" #include "xenia/kernel/xmodule.h" -#include "third_party/crypto/TinySHA1.hpp" -#include "third_party/crypto/rijndael-alg-fst.c" -#include "third_party/crypto/rijndael-alg-fst.h" -#include "third_party/pe/pe_image.h" - static const uint8_t xe_xex2_retail_key[16] = { 0x20, 0xB1, 0x85, 0xA5, 0x9D, 0x28, 0xFD, 0xC3, 0x40, 0x58, 0x3F, 0xBB, 0x08, 0x96, 0xBF, 0x91}; @@ -484,8 +484,6 @@ int XexModule::ReadImage(const void* xex_addr, size_t xex_length, return 0; } - memory()->LookupHeap(base_address_)->Reset(); - aes_decrypt_buffer( use_dev_key ? xe_xex2_devkit_key : xe_xex2_retail_key, reinterpret_cast(xex_security_info()->aes_key), 16, @@ -1095,6 +1093,11 @@ bool XexModule::SetupLibraryImports(const char* name, auto user_module = kernel_state_->GetModule(name); + if (!kernel_resolver && !user_module) { + // Library module hasn't been loaded in, ask kernel to load it: + user_module = kernel_state_->LoadUserModule(name); + } + std::string libbasename = name; auto dot = libbasename.find_last_of('.'); if (dot != libbasename.npos) { diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index 5c55e9f88..7b7397b89 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -233,35 +233,54 @@ object_ref KernelState::LaunchModule(object_ref module) { return nullptr; } - SetExecutableModule(module); - XELOGI("KernelState: Launching module..."); + XELOGI("KernelState: Launching module %s...", module->path().c_str()); // Create a thread to run in. // We start suspended so we can run the debugger prep. - auto thread = object_ref( - new XThread(kernel_state(), module->stack_size(), 0, - module->entry_point(), 0, X_CREATE_SUSPENDED, true, true)); + xe::kernel::object_ref thread = nullptr; - // We know this is the 'main thread'. + if (!module->is_dll_module()) { + // Not a DLL module, run entrypoint as normal + thread = object_ref(new XThread( + kernel_state(), module->stack_size(), XThread::StartupType::Normal, 0, + module->entry_point(), 0, X_CREATE_SUSPENDED, true, true)); + } else { + // Run entrypoint as DllMain, using module handle as start context + thread = object_ref( + new XThread(kernel_state(), module->stack_size(), + XThread::StartupType::DllMain, 0, module->entry_point(), + module->handle(), X_CREATE_SUSPENDED, true, true)); + } + + // We know this is the 'main thread', or ' thread' char thread_name[32]; - std::snprintf(thread_name, xe::countof(thread_name), "Main XThread%08X", + std::snprintf(thread_name, xe::countof(thread_name), "%s XThread%08X", + module->is_dll_module() ? module->name().c_str() : "Main", thread->handle()); thread->set_name(thread_name); X_STATUS result = thread->Create(); if (XFAILED(result)) { - XELOGE("Could not create launch thread: %.8X", result); + XELOGE("Could not create launch thread for %s: %.8X", + module->path().c_str(), result); return nullptr; } // Waits for a debugger client, if desired. - emulator()->processor()->PreLaunch(); + if (!module->is_dll_module()) { + emulator()->processor()->PreLaunch(); + } // Resume the thread now. // If the debugger has requested a suspend this will just decrement the // suspend count without resuming it until the debugger wants. thread->Resume(); + // If this is a DLL, wait for DllMain to complete before continuing + if (module->is_dll_module()) { + thread->Wait(0, 0, false, 0); + } + return thread; } @@ -378,6 +397,9 @@ object_ref KernelState::LoadUserModule(const char* raw_name, module = object_ref(new UserModule(this)); X_STATUS status = module->LoadFromFile(path); if (XFAILED(status)) { + if (executable_module_.get() == module.get()) { + executable_module_.reset(); + } object_table()->ReleaseHandle(module->handle()); return nullptr; } @@ -391,16 +413,22 @@ object_ref KernelState::LoadUserModule(const char* raw_name, module->Dump(); if (module->is_dll_module() && module->entry_point() && call_entry) { - // Call DllMain(DLL_PROCESS_ATTACH): - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx - uint64_t args[] = { - module->handle(), - 1, // DLL_PROCESS_ATTACH - 0, // 0 because always dynamic - }; - auto thread_state = XThread::GetCurrentThread()->thread_state(); - processor()->Execute(thread_state, module->entry_point(), args, - xe::countof(args)); + // If we're not in a thread, use LaunchModule to run DllMain for us + // Otherwise we can just execute it in the current thread instead + if (!XThread::IsInThread()) { + LaunchModule(module); + } else { + // Call DllMain(DLL_PROCESS_ATTACH): + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx + uint64_t args[] = { + module->handle(), + 1, // DLL_PROCESS_ATTACH + 0, // 0 because always dynamic + }; + auto thread_state = XThread::GetCurrentThread()->thread_state(); + processor()->Execute(thread_state, module->entry_point(), args, + xe::countof(args)); + } } return module; diff --git a/src/xenia/kernel/user_module.cc b/src/xenia/kernel/user_module.cc index f567ed502..525af2881 100644 --- a/src/xenia/kernel/user_module.cc +++ b/src/xenia/kernel/user_module.cc @@ -244,9 +244,9 @@ X_STATUS UserModule::LoadXexContinue() { return X_STATUS_SUCCESS; } - // Finish XexModule load (PE sections/imports/symbols...) - if (!xex_module()->LoadContinue()) { - return X_STATUS_UNSUCCESSFUL; + // Notify kernel that we have an executable if we haven't got one already + if (!kernel_state_->GetExecutableModule()) { + kernel_state_->SetExecutableModule(object_ref(this)); } // Copy the xex2 header into guest memory. @@ -272,6 +272,11 @@ X_STATUS UserModule::LoadXexContinue() { ldr_data->image_base = this->xex_module()->base_address(); ldr_data->entry_point = entry_point_; + // Finish XexModule load (PE sections/imports/symbols...) + if (!xex_module()->LoadContinue()) { + return X_STATUS_UNSUCCESSFUL; + } + OnLoad(); return X_STATUS_SUCCESS; diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc index b12325dcd..70aba9a66 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc @@ -122,9 +122,11 @@ dword_result_t ExCreateThread(lpdword_t handle_ptr, dword_t stack_size, std::max((uint32_t)0x4000, ((actual_stack_size + 0xFFF) & 0xFFFFF000)); auto thread = object_ref( - new XThread(kernel_state(), actual_stack_size, xapi_thread_startup, - start_address.guest_address(), start_context.guest_address(), - creation_flags, true)); + new XThread(kernel_state(), actual_stack_size, + xapi_thread_startup ? XThread::StartupType::XapiThreadStartup + : XThread::StartupType::Normal, + xapi_thread_startup, start_address.guest_address(), + start_context.guest_address(), creation_flags, true)); X_STATUS result = thread->Create(); if (XFAILED(result)) { diff --git a/src/xenia/kernel/xthread.cc b/src/xenia/kernel/xthread.cc index 593096c23..6ea139ec8 100644 --- a/src/xenia/kernel/xthread.cc +++ b/src/xenia/kernel/xthread.cc @@ -50,15 +50,16 @@ XThread::XThread(KernelState* kernel_state) : XObject(kernel_state, kType), guest_thread_(true) {} 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, - bool guest_thread, bool main_thread) + StartupType startup_type, uint32_t xapi_thread_startup, + uint32_t start_address, uint32_t start_context, + uint32_t creation_flags, bool guest_thread, bool main_thread) : XObject(kernel_state, kType), thread_id_(++next_xthread_id_), guest_thread_(guest_thread), main_thread_(main_thread), apc_list_(kernel_state->memory()) { creation_params_.stack_size = stack_size; + creation_params_.startup_type = startup_type; creation_params_.xapi_thread_startup = xapi_thread_startup; creation_params_.start_address = start_address; creation_params_.start_context = start_context; @@ -515,12 +516,22 @@ void XThread::Execute() { // If a XapiThreadStartup value is present, we use that as a trampoline. // Otherwise, we are a raw thread. - if (creation_params_.xapi_thread_startup) { + if (creation_params_.startup_type == StartupType::XapiThreadStartup) { uint64_t args[] = {creation_params_.start_address, creation_params_.start_context}; kernel_state()->processor()->Execute(thread_state_, creation_params_.xapi_thread_startup, args, xe::countof(args)); + } else if (creation_params_.startup_type == StartupType::DllMain) { + // Call DllMain(DLL_PROCESS_ATTACH): + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx + uint64_t args[] = { + creation_params_.start_context, + 1, // DLL_PROCESS_ATTACH + 0, // 0 because always dynamic + }; + kernel_state()->processor()->Execute( + thread_state_, creation_params_.start_address, args, xe::countof(args)); } else { // Run user code. uint64_t args[] = {creation_params_.start_context}; @@ -1036,7 +1047,8 @@ object_ref XThread::Restore(KernelState* kernel_state, 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, false), + : XThread(kernel_state, stack_size, XThread::StartupType::Normal, 0, 0, 0, + creation_flags, false), host_fn_(host_fn) { // By default host threads are not debugger suspendable. If the thread runs // any guest code this must be overridden. diff --git a/src/xenia/kernel/xthread.h b/src/xenia/kernel/xthread.h index cfb53967e..b3bfca80d 100644 --- a/src/xenia/kernel/xthread.h +++ b/src/xenia/kernel/xthread.h @@ -106,9 +106,11 @@ static_assert_size(X_KTHREAD, 0xAB0); class XThread : public XObject, public cpu::Thread { public: static const Type kType = kTypeThread; + enum class StartupType { Normal, XapiThreadStartup, DllMain }; struct CreationParams { uint32_t stack_size; + StartupType startup_type; uint32_t xapi_thread_startup; uint32_t start_address; uint32_t start_context; @@ -117,9 +119,9 @@ class XThread : public XObject, public cpu::Thread { XThread(KernelState* kernel_state); 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, bool guest_thread, - bool main_thread = false); + StartupType startup_type, uint32_t xapi_thread_startup, + uint32_t start_address, uint32_t start_context, + uint32_t creation_flags, bool guest_thread, bool main_thread = false); ~XThread() override; static bool IsInThread(XThread* other);