Merge pull request #2210 from RadWolfie/fix-chihiro-support

Few fixes toward title mount path and prepped for chihiro work
This commit is contained in:
Luke Usher 2021-05-21 17:56:57 +01:00 committed by GitHub
commit df22c8baed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 158 additions and 135 deletions

View File

@ -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)

View File

@ -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 <algorithm> // for std::replace
#include <locale>
@ -539,7 +537,6 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi
std::string TitlePath = xbox::LaunchDataPage->Header.szLaunchPath;
char szWorkingDirectoy[xbox::max_path];
// If the title path starts with a semicolon, remove it
if (TitlePath.length() > 0 && TitlePath[0] == ';') {
@ -553,12 +550,6 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi
std::string& XbePath = CxbxConvertXboxToHostPath(TitlePath);
// Determine Working Directory
{
strncpy_s(szWorkingDirectoy, XbePath.c_str(), MAX_PATH);
PathRemoveFileSpec(szWorkingDirectoy);
}
// Relaunch Cxbx, to load another Xbe
{
int QuickReboot;
@ -572,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);
}
}
@ -631,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;
}

View File

@ -1398,25 +1398,27 @@ __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;
int CxbxCdrom0DeviceIndex = -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* p_default_mount_path = title_mount_path;
g_EmuShared->GetTitleMountPath(title_mount_path);
if (p_default_mount_path[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("");
p_default_mount_path = 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 (p_default_mount_path[0] != '\0') {
CxbxCdrom0DeviceIndex = CxbxRegisterDeviceHostPath(DeviceCdrom0, p_default_mount_path);
// Since Chihiro also map Mbfs to the same path as Cdrom0, we'll map it the same way.
if (g_bIsChihiro) {
(void)CxbxRegisterDeviceHostPath(DriveMbfs, p_default_mount_path);
}
}
@ -1444,12 +1446,9 @@ __declspec(noreturn) void CxbxKrnlInit
#else
// HACK: It is a hack to override XDK's default mount to CdRom0 which may not exist when launch to dashboard directly.
// Otherwise, titles may launch to dashboard, more specifically xbox live title, and back.
if (CxbxTitleDeviceDriveIndex == -1 || lastFind != std::string::npos) {
if (CxbxCdrom0DeviceIndex == -1 || lastFind != std::string::npos) {
#endif
CxbxCreateSymbolicLink(DriveD, relative_path);
// Arrange that the Xbe path can reside outside the partitions, and put it to g_hCurDir :
EmuNtSymbolicLinkObject* xbePathSymbolicLinkObject = FindNtSymbolicLinkObjectByDriveLetter(CxbxAutoMountDriveLetter);
g_hCurDir = xbePathSymbolicLinkObject->RootDirectoryHandle;
}
}
@ -1462,9 +1461,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.

View File

@ -42,8 +42,6 @@ CRITICAL_SECTION dbgCritical;
#endif
// Global Variable(s)
HANDLE g_hCurDir = NULL;
CHAR *g_strCurDrive= NULL;
volatile thread_local bool g_bEmuException = false;
static thread_local bool bOverrideEmuException;
volatile bool g_bEmuSuspended = false;

View File

@ -63,9 +63,6 @@ extern volatile bool g_bEmuSuspended;
// global exception patching address
extern void * funcExclude[2048];
// partition emulation directory handles
extern HANDLE g_hCurDir;
extern CHAR *g_strCurDrive;
extern HWND g_hEmuWindow;
#define GET_FRONT_WINDOW_HANDLE ((CxbxKrnl_hEmuParent != nullptr) ? CxbxKrnl_hEmuParent : g_hEmuWindow)

View File

@ -40,9 +40,15 @@
#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 <filesystem>
// partition emulation directory handles
HANDLE g_hCurDir_hack = NULL; // HACK: We should not be depending on this variable. Instead, we should fix/implement Ob/Io objects such as IoCreateDevice.
// Default Xbox Partition Table
#define PE_PARTFLAGS_IN_USE 0x80000000
#define XBOX_SWAPPART1_LBA_START 0x400
@ -402,7 +408,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)
@ -429,7 +436,7 @@ NTSTATUS CxbxConvertFilePath(
else if (RelativePath[0] == '$') {
if (RelativePath.compare(0, 5, "$HOME") == 0) // "xbmp" needs this
{
NtSymbolicLinkObject = FindNtSymbolicLinkObjectByRootHandle(g_hCurDir);
NtSymbolicLinkObject = FindNtSymbolicLinkObjectByRootHandle(g_hCurDir_hack);
RelativePath.erase(0, 5); // Remove '$HOME'
}
else
@ -437,13 +444,14 @@ NTSTATUS CxbxConvertFilePath(
}
// Check if the path starts with a relative path indicator :
else if (RelativePath[0] == '.') {// "4x4 Evo 2" needs this
NtSymbolicLinkObject = FindNtSymbolicLinkObjectByRootHandle(g_hCurDir);
NtSymbolicLinkObject = FindNtSymbolicLinkObjectByRootHandle(g_hCurDir_hack);
RelativePath.erase(0, 1); // Remove the '.'
}
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 +462,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_hack);
}
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_hack);
}
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 +515,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 +693,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<int>(Devices.size()) - 1;
}
@ -703,8 +718,13 @@ xbox::ntstatus_xt CxbxCreateSymbolicLink(std::string SymbolicLinkName, std::stri
SymbolicLinkObject = new EmuNtSymbolicLinkObject();
result = SymbolicLinkObject->Init(SymbolicLinkName, FullPath);
if (result != xbox::status_success)
if (result != xbox::status_success) {
SymbolicLinkObject->NtClose();
}
// TODO: Remove whole else if statement below, see g_hCurDir_hack's comment for remark.
else if (SymbolicLinkObject->DriveLetter == CxbxAutoMountDriveLetter) {
g_hCurDir_hack = SymbolicLinkObject->RootDirectoryHandle;
}
return result;
}
@ -795,6 +815,10 @@ NTSTATUS EmuNtSymbolicLinkObject::Init(std::string aSymbolicLinkName, std::strin
if (DriveLetter >= 'A' && DriveLetter <= 'Z') {
NtSymbolicLinkObjects[DriveLetter - 'A'] = NULL;
NtDll::NtClose(RootDirectoryHandle);
// TODO: Remove whole if statement below, see g_hCurDir_hack's comment for remark.
if (DriveLetter == CxbxAutoMountDriveLetter) {
g_hCurDir_hack = NULL;
}
}
}
@ -833,16 +857,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 +1168,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

View File

@ -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