diff --git a/src/Common/Xbe.cpp b/src/Common/Xbe.cpp index a0760647b..9c9f633ff 100644 --- a/src/Common/Xbe.cpp +++ b/src/Common/Xbe.cpp @@ -144,7 +144,7 @@ Xbe::Xbe(const char *x_szFilename) char Dir[_MAX_DIR]; char Filename[_MAX_FNAME]; _splitpath(x_szFilename, nullptr, Dir, Filename, nullptr); - if (stricmp(Filename, "default") != 0) { + if (_stricmp(Filename, "default") != 0) { strcpy(m_szAsciiTitle, Filename); } else { @@ -187,18 +187,18 @@ Xbe::Xbe(const char *x_szFilename) { printf("Xbe::Xbe: Reading Section Names...\n"); - m_szSectionName = new char[m_Header.dwSections][9]; + m_szSectionName = new char[m_Header.dwSections][10]; for(uint32 v=0;vm_Header.dwBaseAddr, &CxbxKrnl_Xbe->m_Header, sizeof(Xbe::Header)); - // Copy over the certificate memcpy((void*)(CxbxKrnl_Xbe->m_Header.dwBaseAddr + sizeof(Xbe::Header)), CxbxKrnl_Xbe->m_HeaderEx, CxbxKrnl_Xbe->m_ExSize); - // Copy over the library versions - memcpy((void*)CxbxKrnl_Xbe->m_Header.dwLibraryVersionsAddr, CxbxKrnl_Xbe->m_LibraryVersion, CxbxKrnl_Xbe->m_Header.dwLibraryVersions * sizeof(DWORD)); - // TODO : Actually, instead of copying from CxbxKrnl_Xbe, we should load the entire Xbe directly into memory, like Dxbx does - see _ReadXbeBlock() - // Verify no section would load outside virtual_memory_placeholder (which would overwrite Cxbx code) + // Load all sections marked as preload using the in-memory copy of the xbe header + xboxkrnl::PXBEIMAGE_SECTION sectionHeaders = (xboxkrnl::PXBEIMAGE_SECTION)CxbxKrnl_Xbe->m_Header.dwSectionHeadersAddr; for (uint32 i = 0; i < CxbxKrnl_Xbe->m_Header.dwSections; i++) { - xbaddr section_end = CxbxKrnl_Xbe->m_SectionHeader[i].dwVirtualAddr + CxbxKrnl_Xbe->m_SectionHeader[i].dwSizeofRaw; - if (section_end >= XBE_MAX_VA) - { - CxbxPopupMessage("Couldn't load XBE section - please report this!"); - return; // TODO : Halt(0); + if ((sectionHeaders[i].Flags & XBEIMAGE_SECTION_PRELOAD) != 0) { + NTSTATUS result = xboxkrnl::XeLoadSection(§ionHeaders[i]); + if (FAILED(result)) { + CxbxKrnlCleanup("Failed to preload XBE section: %s", CxbxKrnl_Xbe->m_szSectionName[i]); + } } } - // Load all sections to their requested Virtual Address : - for (uint32 i = 0; i < CxbxKrnl_Xbe->m_Header.dwSections; i++) { - memcpy((void*)CxbxKrnl_Xbe->m_SectionHeader[i].dwVirtualAddr, CxbxKrnl_Xbe->m_bzSection[i], CxbxKrnl_Xbe->m_SectionHeader[i].dwSizeofRaw); - } - // We need to remember a few XbeHeader fields, so we can switch between a valid ExeHeader and XbeHeader : StoreXbeImageHeader(); diff --git a/src/CxbxKrnl/CxbxKrnl.h b/src/CxbxKrnl/CxbxKrnl.h index 782df0404..8aecdd125 100644 --- a/src/CxbxKrnl/CxbxKrnl.h +++ b/src/CxbxKrnl/CxbxKrnl.h @@ -35,7 +35,6 @@ #define CXBXKRNL_H #include "Cxbx.h" - #include "Common/Xbe.h" #undef FIELD_OFFSET // prevent macro redefinition warnings diff --git a/src/CxbxKrnl/EmuFile.cpp b/src/CxbxKrnl/EmuFile.cpp index ad0980fda..ab1b28a8a 100644 --- a/src/CxbxKrnl/EmuFile.cpp +++ b/src/CxbxKrnl/EmuFile.cpp @@ -193,7 +193,8 @@ NTSTATUS CxbxConvertFilePath( std::string RelativeXboxPath, OUT std::wstring &RelativeHostPath, OUT NtDll::HANDLE *RootDirectory, - std::string aFileAPIName) + std::string aFileAPIName, + bool partitionHeader) { std::string OriginalPath = RelativeXboxPath; std::string RelativePath = RelativeXboxPath; @@ -278,7 +279,15 @@ NTSTATUS CxbxConvertFilePath( } XboxFullPath = NtSymbolicLinkObject->XboxSymbolicLinkPath; - *RootDirectory = NtSymbolicLinkObject->RootDirectoryHandle; + + // If directly accessing a partition header, redirect to the partitionX.bin file + if (partitionHeader) { + RelativePath = DrivePrefix + HostPath.substr(0, HostPath.length()) + ".bin"; + } else { + // If accessing a partition as a directly, set the root directory handle and keep relative path as is + *RootDirectory = NtSymbolicLinkObject->RootDirectoryHandle; + } + } // Check for special case : Partition0 @@ -317,7 +326,8 @@ NTSTATUS CxbxConvertFilePath( NTSTATUS CxbxObjectAttributesToNT( xboxkrnl::POBJECT_ATTRIBUTES ObjectAttributes, OUT NativeObjectAttributes& nativeObjectAttributes, - const std::string aFileAPIName) + const std::string aFileAPIName, + bool partitionHeader) { if (ObjectAttributes == NULL) { @@ -346,7 +356,7 @@ NTSTATUS CxbxObjectAttributesToNT( if (aFileAPIName.size() > 0) { // Then interpret the ObjectName as a filename, and update it to host relative : - NTSTATUS result = CxbxConvertFilePath(ObjectName, /*OUT*/RelativeHostPath, /*OUT*/&RootDirectory, aFileAPIName); + NTSTATUS result = CxbxConvertFilePath(ObjectName, /*OUT*/RelativeHostPath, /*OUT*/&RootDirectory, aFileAPIName, partitionHeader); if (FAILED(result)) return result; } @@ -400,6 +410,18 @@ int CxbxRegisterDeviceHostPath(std::string XboxDevicePath, std::string HostDevic } else { + // All HDD partitions have a .bin file to allow direct file io on the partition info + if (_strnicmp(XboxDevicePath.c_str(), DeviceHarddisk0PartitionPrefix.c_str(), DeviceHarddisk0PartitionPrefix.length()) == 0) { + std::string partitionHeaderPath = (HostDevicePath + ".bin").c_str(); + if (!PathFileExists(partitionHeaderPath.c_str())) { + HANDLE hf = CreateFile(partitionHeaderPath.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); + + SetFilePointer(hf, 512 * 1024, 0, FILE_BEGIN); + SetEndOfFile(hf); + CloseHandle(hf); + } + } + int status = SHCreateDirectoryEx(NULL, HostDevicePath.c_str(), NULL); if (status == STATUS_SUCCESS || status == ERROR_ALREADY_EXISTS) { diff --git a/src/CxbxKrnl/EmuFile.h b/src/CxbxKrnl/EmuFile.h index 33a0000d6..576f28a96 100644 --- a/src/CxbxKrnl/EmuFile.h +++ b/src/CxbxKrnl/EmuFile.h @@ -165,8 +165,8 @@ struct NativeObjectAttributes { NtDll::POBJECT_ATTRIBUTES NtObjAttrPtr; }; -NTSTATUS CxbxObjectAttributesToNT(xboxkrnl::POBJECT_ATTRIBUTES ObjectAttributes, NativeObjectAttributes& nativeObjectAttributes, std::string aFileAPIName = ""); -NTSTATUS CxbxConvertFilePath(std::string RelativeXboxPath, OUT std::wstring &RelativeHostPath, OUT NtDll::HANDLE *RootDirectory, std::string aFileAPIName = ""); +NTSTATUS CxbxObjectAttributesToNT(xboxkrnl::POBJECT_ATTRIBUTES ObjectAttributes, NativeObjectAttributes& nativeObjectAttributes, std::string aFileAPIName = "", bool partitionHeader = false); +NTSTATUS CxbxConvertFilePath(std::string RelativeXboxPath, OUT std::wstring &RelativeHostPath, OUT NtDll::HANDLE *RootDirectory, std::string aFileAPIName = "", bool partitionHeader = false); // ****************************************************************** // * Wrapper of a handle object diff --git a/src/CxbxKrnl/EmuKrnlIo.cpp b/src/CxbxKrnl/EmuKrnlIo.cpp index 75959e5e8..785d58b6d 100644 --- a/src/CxbxKrnl/EmuKrnlIo.cpp +++ b/src/CxbxKrnl/EmuKrnlIo.cpp @@ -259,7 +259,23 @@ XBSYSAPI EXPORTNUM(66) xboxkrnl::NTSTATUS NTAPI xboxkrnl::IoCreateFile NativeObjectAttributes nativeObjectAttributes; - NTSTATUS ret = CxbxObjectAttributesToNT(ObjectAttributes, /*OUT*/nativeObjectAttributes, "IoCreateFile"); + // If we are NOT accessing a directory, and we match a partition path, we need to redirect to a partition.bin file + bool isDirectPartitionAccess = false; + std::string objectName = std::string(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length); + if ((CreateOptions & FILE_DIRECTORY_FILE) == 0 && _strnicmp(objectName.c_str(), DeviceHarddisk0PartitionPrefix.c_str(), DeviceHarddisk0PartitionPrefix.length()) == 0) { + isDirectPartitionAccess = true; + } + + NTSTATUS ret = CxbxObjectAttributesToNT(ObjectAttributes, /*OUT*/nativeObjectAttributes, "IoCreateFile", isDirectPartitionAccess); + + // When a Synchronous CreateOption is specified, DesiredAccess must have SYNCHRONIZE set + if ((CreateOptions & FILE_SYNCHRONOUS_IO_NONALERT) != 0 || + (CreateOptions & FILE_SYNCHRONOUS_IO_ALERT) != 0) { + DesiredAccess |= SYNCHRONIZE; + } + + // Force ShareAccess to all + ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; if (!FAILED(ret)) // redirect to NtCreateFile diff --git a/src/CxbxKrnl/EmuKrnlXe.cpp b/src/CxbxKrnl/EmuKrnlXe.cpp index f1d0da046..6c5bdda52 100644 --- a/src/CxbxKrnl/EmuKrnlXe.cpp +++ b/src/CxbxKrnl/EmuKrnlXe.cpp @@ -43,6 +43,7 @@ namespace xboxkrnl #include // For XeImageFileName, etc. }; +#include "CxbxKrnl.h" // For CxbxKrnl_Xbe #include "Logging.h" // For LOG_FUNC() #include "EmuKrnlLogging.h" #include "Emu.h" // For EmuWarning() @@ -76,12 +77,24 @@ XBSYSAPI EXPORTNUM(327) xboxkrnl::NTSTATUS NTAPI xboxkrnl::XeLoadSection LOG_FUNC_ARG(Section) LOG_FUNC_END; - NTSTATUS ret = STATUS_SUCCESS; + NTSTATUS ret = STATUS_INVALID_HANDLE; - if (Section->SectionReferenceCount++ == 0) { - LOG_INCOMPLETE(); // TODO : Load section - probably lock this too + void* sectionData = CxbxKrnl_Xbe->FindSection((char*)std::string(Section->SectionName, 9).c_str()); + if (sectionData != nullptr) { + // If the reference count was zero, load the section + if (Section->SectionReferenceCount == 0) { + // Clear the memory the section requires + memset(Section->VirtualAddress, 0, Section->VirtualSize); + // Copy the section data + memcpy(Section->VirtualAddress, sectionData, Section->FileSize); + } + + // Increment the reference count + Section->SectionReferenceCount++; + + ret = STATUS_SUCCESS; } - + RETURN(ret); } @@ -101,15 +114,20 @@ XBSYSAPI EXPORTNUM(328) xboxkrnl::NTSTATUS NTAPI xboxkrnl::XeUnloadSection LOG_FUNC_ARG(Section) LOG_FUNC_END; - NTSTATUS ret = STATUS_SUCCESS; + NTSTATUS ret = STATUS_INVALID_PARAMETER; + // If the section was loaded, process it if (Section->SectionReferenceCount > 0) { - if (--Section->SectionReferenceCount == 0) { - LOG_INCOMPLETE(); // TODO : Unload section - probably lock this too + // Decrement the reference count + Section->SectionReferenceCount -= 1; + + // Free the section if necessary + if (Section->SectionReferenceCount == 0) { + memset(Section->VirtualAddress, 0, Section->VirtualSize); } + + ret = STATUS_SUCCESS; } - else - ret = STATUS_INVALID_PARAMETER; RETURN(ret); }