kernel: fix chihiro support

This commit is contained in:
RadWolfie 2021-04-25 15:45:06 -05:00
parent 9eadb8d393
commit d8eb26fbda
5 changed files with 140 additions and 115 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>
@ -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;
}

View File

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

View File

@ -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 <filesystem>
@ -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<int>(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

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