diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index ef8c85584..0a36f8662 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -796,6 +796,9 @@ void Settings::SyncToEmulator() // register data location setting g_EmuShared->SetStorageLocation(GetDataLocation().c_str()); + + // reset title mount path + g_EmuShared->SetTitleMountPath(""); } void verifyDebugFilePath(DebugMode& debug_mode, std::string& file_path) diff --git a/src/core/kernel/exports/EmuKrnlHal.cpp b/src/core/kernel/exports/EmuKrnlHal.cpp index 6380e232a..0efa22fe5 100644 --- a/src/core/kernel/exports/EmuKrnlHal.cpp +++ b/src/core/kernel/exports/EmuKrnlHal.cpp @@ -44,8 +44,6 @@ #include "devices\SMCDevice.h" // For SMC_COMMAND_SCRATCH #include "common/util/strConverter.hpp" // for utf16_to_ascii #include "core\kernel\memory-manager\VMManager.h" -#include "common/util/cliConfig.hpp" -#include "common/CxbxDebugger.h" #include // for std::replace #include @@ -565,49 +563,7 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi // Some titles (Xbox Dashboard and retail/demo discs) use ";" as a current directory path seperator // This process is handled during initialization. No special handling here required. - cli_config::SetLoad(XbePath); - - bool Debugging{ false }; - g_EmuShared->GetDebuggingFlag(&Debugging); - - if (Debugging) - { - std::string cliCommands; - if (!cli_config::GenCMD(cliCommands)) - { - CxbxKrnlCleanup("Could not launch %s", XbePath.c_str()); - } - - CxbxDebugger::ReportNewTarget(cliCommands.c_str()); - - // The debugger will execute this process - } - else - { - if (!CxbxExec(false, nullptr, false)) - { - CxbxKrnlCleanup("Could not launch %s", XbePath.c_str()); - } - } - - // This is a requirement to have shared memory buffers remain alive and transfer to new emulation process. - unsigned int retryAttempt = 0; - unsigned int curProcID = 0; - unsigned int oldProcID = GetCurrentProcessId(); - while(true) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - g_EmuShared->GetKrnlProcID(&curProcID); - // Break when new emulation process has take over. - if (curProcID != oldProcID) { - break; - } - retryAttempt++; - // Terminate after 5 seconds of failure. - if (retryAttempt >= (5 * (1000 / 100))) { - PopupError(nullptr, "Could not reboot; New emulation process did not take over."); - break; - } - } + CxbxLaunchNewXbe(XbePath); } } @@ -624,10 +580,7 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi g_VMManager.SavePersistentMemory(); - cli_config::SetLoad(szFilePath_Xbe); - if (!CxbxExec(false, nullptr, false)) { - CxbxKrnlCleanup("Could not launch %s", szFilePath_Xbe); - } + CxbxLaunchNewXbe(szFilePath_Xbe); break; } diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 391f76a10..382437d4b 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -1398,25 +1398,26 @@ __declspec(noreturn) void CxbxKrnlInit CxbxResolveHostToFullPath(relative_path, "xbe's directory"); CxbxBasePathHandle = CreateFile(CxbxBasePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - // Titles may assume they are running from CdRom0/Mbfs : - std::string_view titleDevice = g_bIsChihiro ? DriveMbfs : DeviceCdrom0; int CxbxTitleDeviceDriveIndex = -1; bool isEmuDisk = _strnicmp(relative_path.c_str(), CxbxBasePath.c_str(), CxbxBasePath.size() - 1) == 0; - if (BootFlags == BOOT_NONE) { - // Remember our first initialize mount path for CdRom0/Mbfs. + // Check if title mounth path is already set. This may occur from early boot of Chihiro title. + char title_mount_path[sizeof(szFilePath_Xbe)]; + const char* tmp_buffer = title_mount_path; + g_EmuShared->GetTitleMountPath(title_mount_path); + + if (tmp_buffer[0] == '\0' && BootFlags == BOOT_NONE) { + // Remember our first initialize mount path for CdRom0 and Mbfs. if (!isEmuDisk) { g_EmuShared->SetTitleMountPath(relative_path.c_str()); - CxbxTitleDeviceDriveIndex = CxbxRegisterDeviceHostPath(titleDevice, relative_path); - } - else { - g_EmuShared->SetTitleMountPath(""); + tmp_buffer = relative_path.c_str(); } } - else { - char szBuffer[sizeof(szFilePath_Xbe)]; - g_EmuShared->GetTitleMountPath(szBuffer); - if (szBuffer[0] != '\0') { - CxbxTitleDeviceDriveIndex = CxbxRegisterDeviceHostPath(titleDevice, szBuffer); + + // TODO: Find a place to make permanent placement for DeviceCdrom0 that does not have disc loaded. + if (tmp_buffer[0] != '\0') { + CxbxTitleDeviceDriveIndex = CxbxRegisterDeviceHostPath(DeviceCdrom0, tmp_buffer); + if (g_bIsChihiro) { + CxbxRegisterDeviceHostPath(DriveMbfs, tmp_buffer); } } @@ -1462,9 +1463,9 @@ __declspec(noreturn) void CxbxKrnlInit XboxDevice* xbeLoc = CxbxDeviceByHostPath(xbePath.string()); fileName = xbeLoc->XboxDevicePath; } - // Otherwise it might be from titleDevice source. + // Otherwise it might be from CdRom0 device. else { - fileName = titleDevice; + fileName = DeviceCdrom0; } // Strip out the path, leaving only the XBE file name to append. diff --git a/src/core/kernel/support/EmuFile.cpp b/src/core/kernel/support/EmuFile.cpp index 84f297f94..358168265 100644 --- a/src/core/kernel/support/EmuFile.cpp +++ b/src/core/kernel/support/EmuFile.cpp @@ -40,6 +40,9 @@ #include "core\kernel\init\CxbxKrnl.h" #include "Logging.h" #include "common/util/strConverter.hpp" // utf16_to_ascii +#include "common/util/cliConfig.hpp" +#include "common/CxbxDebugger.h" +#include "EmuShared.h" #include @@ -402,7 +405,8 @@ NTSTATUS CxbxConvertFilePath( std::string RelativePath = RelativeXboxPath; std::string XboxFullPath; std::string HostPath; - EmuNtSymbolicLinkObject* NtSymbolicLinkObject = NULL; + EmuNtSymbolicLinkObject* NtSymbolicLinkObject = nullptr; + EmuDirPath find_path; // Always trim '\??\' off : if (RelativePath.compare(0, DrivePrefix.length(), DrivePrefix.c_str()) == 0) @@ -442,8 +446,9 @@ NTSTATUS CxbxConvertFilePath( } else { // TODO : How should we handle accesses to the serial: (?semi-)volume? - if (RelativePath.compare(0, 7, "serial:") == 0) + if (RelativePath.compare(0, 7, "serial:") == 0) { return STATUS_UNRECOGNIZED_VOLUME; + } // TODO: CDROM0: need access to raw file handle which doesn't exist in file system. // Similar concept with serial: and perhaps mediaboards. @@ -454,51 +459,52 @@ NTSTATUS CxbxConvertFilePath( }*/ // The path seems to be a device path, look it up : - NtSymbolicLinkObject = FindNtSymbolicLinkObjectByDevice(RelativePath); + FindEmuDirPathByDevice(RelativePath, find_path); // Fixup RelativePath path here - if (NtSymbolicLinkObject != NULL) - RelativePath.erase(0, NtSymbolicLinkObject->XboxSymbolicLinkPath.length()); // Remove '\Device\Harddisk0\Partition2' + if (!find_path.HostDirPath.empty()) { + RelativePath.erase(0, find_path.XboxDirPath.length()); // Remove '\Device\Harddisk0\Partition2' + } } - if (NtSymbolicLinkObject == NULL) { - // Check if the path accesses a partition from Harddisk0 : - if (_strnicmp(RelativePath.c_str(), DeviceHarddisk0PartitionPrefix.c_str(), DeviceHarddisk0PartitionPrefix.length()) == 0) { - XboxFullPath = RelativePath; - // Remove Harddisk0 prefix, in the hope that the remaining path might work : - RelativePath.erase(0, DeviceHarddisk0.length() + 1); - // And set Root to the folder containing the partition-folders : - *RootDirectory = CxbxBasePathHandle; - HostPath = CxbxBasePath; - } - // NOTE: RootDirectory cannot be ignored. - // Any special handling for it should be done below. - else if (*RootDirectory == nullptr) { - // Assume relative to Xbe path - NtSymbolicLinkObject = FindNtSymbolicLinkObjectByRootHandle(g_hCurDir); - } - else if (*RootDirectory == ObDosDevicesDirectory()) { - // This is a special handle that tells the API that this is a DOS device - // We can safely remove it and forward to the Xbe directory. - // Test case GTA3 - NtSymbolicLinkObject = FindNtSymbolicLinkObjectByRootHandle(g_hCurDir); - } - else if (*RootDirectory == ObWin32NamedObjectsDirectory()) { - // NOTE: A handle of -4 on the Xbox signifies the path should be in the BaseNamedObjects namespace. - // This handle doesn't exist on Windows, so we prefix the name instead. (note from LukeUsher) - // Handle special root directory constants - *RootDirectory = NULL; - - if (OriginalPath.size() == 0){ - RelativePath = "\\BaseNamedObjects"; - } else { - RelativePath = "\\BaseNamedObjects\\" + OriginalPath; - } - } - // else {} // NOTE: Allow RootDirectory handle to take control of relative path. - // Test-case: Turok Evolution + if (NtSymbolicLinkObject != nullptr || !find_path.HostDirPath.empty()) { + /// If found, then we can skip misc checks below. } + // Check if the path accesses a partition from Harddisk0 : + else if (_strnicmp(RelativePath.c_str(), DeviceHarddisk0PartitionPrefix.c_str(), DeviceHarddisk0PartitionPrefix.length()) == 0) { + XboxFullPath = RelativePath; + // Remove Harddisk0 prefix, in the hope that the remaining path might work : + RelativePath.erase(0, DeviceHarddisk0.length() + 1); + // And set Root to the folder containing the partition-folders : + *RootDirectory = CxbxBasePathHandle; + HostPath = CxbxBasePath; + } + // NOTE: RootDirectory cannot be ignored. + // Any special handling for it should be done below. + else if (*RootDirectory == nullptr) { + NtSymbolicLinkObject = FindNtSymbolicLinkObjectByRootHandle(g_hCurDir); + } + else if (*RootDirectory == ObDosDevicesDirectory()) { + // This is a special handle that tells the API that this is a DOS device + // We can safely remove it and forward to the Xbe directory. + // Test case GTA3 + NtSymbolicLinkObject = FindNtSymbolicLinkObjectByRootHandle(g_hCurDir); + } + else if (*RootDirectory == ObWin32NamedObjectsDirectory()) { + // NOTE: A handle of -4 on the Xbox signifies the path should be in the BaseNamedObjects namespace. + // This handle doesn't exist on Windows, so we prefix the name instead. (note from LukeUsher) + // Handle special root directory constants + *RootDirectory = NULL; - if (NtSymbolicLinkObject != NULL) { + if (OriginalPath.size() == 0){ + RelativePath = "\\BaseNamedObjects"; + } else { + RelativePath = "\\BaseNamedObjects\\" + OriginalPath; + } + } + // else {} // NOTE: Allow RootDirectory handle to take control of relative path. + // Test-case: Turok Evolution + + if (NtSymbolicLinkObject != nullptr) { HostPath = NtSymbolicLinkObject->HostSymbolicLinkPath; XboxFullPath = NtSymbolicLinkObject->XboxSymbolicLinkPath; @@ -506,6 +512,11 @@ NTSTATUS CxbxConvertFilePath( // If accessing a partition as a directly, set the root directory handle and keep relative path as is *RootDirectory = NtSymbolicLinkObject->RootDirectoryHandle; } + else if (!find_path.HostDirPath.empty()) { + HostPath = find_path.HostDirPath; + XboxFullPath = find_path.XboxDirPath; + *RootDirectory = find_path.HostDirHandle; + } } else { *RootDirectory = CxbxBasePathHandle; HostPath = CxbxBasePath; @@ -679,6 +690,7 @@ int CxbxRegisterDeviceHostPath(const std::string_view XboxDevicePath, std::strin } if (succeeded) { + newDevice.HostRootHandle = CreateFile(newDevice.HostDevicePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); Devices.push_back(newDevice); return static_cast(Devices.size()) - 1; } @@ -833,16 +845,18 @@ EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByName(std::string SymbolicLink } -EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByDevice(std::string DeviceName) +void FindEmuDirPathByDevice(std::string DeviceName, EmuDirPath& hybrid_path) { - for (char DriveLetter = 'A'; DriveLetter <= 'Z'; DriveLetter++) - { - EmuNtSymbolicLinkObject* result = NtSymbolicLinkObjects[DriveLetter - 'A']; - if ((result != NULL) && _strnicmp(DeviceName.c_str(), result->XboxSymbolicLinkPath.c_str(), result->XboxSymbolicLinkPath.length()) == 0) - return result; + for (auto device = Devices.begin(); device != Devices.end(); device++) { + if (_strnicmp(DeviceName.c_str(), device->XboxDevicePath.c_str(), device->XboxDevicePath.length()) == 0) { + hybrid_path.XboxDirPath = device->XboxDevicePath; + hybrid_path.HostDirPath = device->HostDevicePath; + hybrid_path.HostDirHandle = device->HostRootHandle; + return; + } } - return NULL; + hybrid_path.HostDirPath = ""; } @@ -1142,6 +1156,52 @@ NTSTATUS NTToXboxFileInformation return result; } +void CxbxLaunchNewXbe(const std::string& XbePath) { + cli_config::SetLoad(XbePath); + + bool Debugging{ false }; + g_EmuShared->GetDebuggingFlag(&Debugging); + + if (Debugging) + { + std::string cliCommands; + if (!cli_config::GenCMD(cliCommands)) + { + CxbxKrnlCleanup("Could not launch %s", XbePath.c_str()); + } + + CxbxDebugger::ReportNewTarget(cliCommands.c_str()); + + // The debugger will execute this process + } + else + { + if (!CxbxExec(false, nullptr, false)) + { + CxbxKrnlCleanup("Could not launch %s", XbePath.c_str()); + } + } + + // This is a requirement to have shared memory buffers remain alive and transfer to new emulation process. + unsigned int retryAttempt = 0; + unsigned int curProcID = 0; + unsigned int oldProcID = GetCurrentProcessId(); + while (true) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + g_EmuShared->GetKrnlProcID(&curProcID); + // Break when new emulation process has take over. + if (curProcID != oldProcID) { + break; + } + retryAttempt++; + // Terminate after 5 seconds of failure. + if (retryAttempt >= (5 * (1000 / 100))) { + PopupError(nullptr, "Could not reboot; New emulation process did not take over."); + break; + } + } +} + // TODO: FS_INFORMATION_CLASS and its related structs most likely need to be converted too // TODO : Move to a better suited file diff --git a/src/core/kernel/support/EmuFile.h b/src/core/kernel/support/EmuFile.h index c1249ac91..8d1a5654b 100644 --- a/src/core/kernel/support/EmuFile.h +++ b/src/core/kernel/support/EmuFile.h @@ -216,18 +216,24 @@ struct XboxDevice { HANDLE HostRootHandle; }; +struct EmuDirPath { + std::string_view XboxDirPath; + std::string_view HostDirPath; + HANDLE HostDirHandle; +}; + CHAR* NtStatusToString(IN NTSTATUS Status); int CxbxRegisterDeviceHostPath(std::string_view XboxFullPath, std::string HostDevicePath, bool IsFile = false); int CxbxDeviceIndexByDevicePath(const char *XboxDevicePath); -XboxDevice *CxbxDeviceByDevicePath(const std::string_view XboxDevicePath); +XboxDevice* CxbxDeviceByDevicePath(const std::string_view XboxDevicePath); XboxDevice* CxbxDeviceByHostPath(const std::string_view HostPath); std::string CxbxConvertXboxToHostPath(const std::string_view XboxDevicePath); char SymbolicLinkToDriveLetter(std::string aSymbolicLinkName); EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByDriveLetter(const char DriveLetter); EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByName(std::string SymbolicLinkName); -EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByDevice(std::string DeviceName); +void FindEmuDirPathByDevice(std::string DeviceName, EmuDirPath& hybrid_path); EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByRootHandle(HANDLE Handle); void CleanupSymbolicLinks(); @@ -322,4 +328,6 @@ void NTAPI CxbxIoApcDispatcher xbox::ulong_xt Reserved ); +void CxbxLaunchNewXbe(const std::string& XbePath); + #endif