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