Merge pull request #768 from LukeUsher/xbe-loading

Xbe loading & FileSystem Tweaks
This commit is contained in:
PatrickvL 2017-10-18 20:33:32 +02:00 committed by GitHub
commit e305ff48bb
8 changed files with 93 additions and 40 deletions

View File

@ -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;v<m_Header.dwSections;v++)
{
printf("Xbe::Xbe: Reading Section Name 0x%.04X...", v);
uint08 *sn = GetAddr(m_SectionHeader[v].dwSectionNameAddr);
memset(m_szSectionName[v], 0, 9);
memset(m_szSectionName[v], 0, 10);
if(sn != 0)
{
for(int b=0;b<8;b++)
for(int b=0;b<9;b++)
{
m_szSectionName[v][b] = sn[b];

View File

@ -222,8 +222,8 @@ class Xbe : public Error
#include "AlignPosfix1.h"
*m_TLS;
// Xbe section names, each 8 bytes max and null terminated
char (*m_szSectionName)[9];
// Xbe section names, stored null terminated
char (*m_szSectionName)[10];
// Xbe sections
uint08 **m_bzSection;
@ -360,4 +360,11 @@ const uint32 XBEIMAGE_MEDIA_TYPE_NONSECURE_HARD_DISK = 0x40000000;
const uint32 XBEIMAGE_MEDIA_TYPE_NONSECURE_MODE = 0x80000000;
const uint32 XBEIMAGE_MEDIA_TYPE_MEDIA_MASK = 0x00FFFFFF;
// section type flags for Xbe
const uint32 XBEIMAGE_SECTION_WRITEABLE = 0x00000001;
const uint32 XBEIMAGE_SECTION_PRELOAD = 0x00000002;
const uint32 XBEIMAGE_SECTION_EXECUTABLE = 0x00000004;
const uint32 XBEIMAGE_SECTION_INSERTFILE = 0x00000008;
const uint32 XBEIMAGE_SECTION_HEAD_PAGE_READONLY = 0x00000010;
const uint32 XBEIMAGE_SECTION_TAIL_PAGE_READONLY = 0x00000020;
#endif

View File

@ -177,7 +177,6 @@ void CxbxLaunchXbe(void(*Entry)())
__try
{
Entry();
}
__except (EmuException(GetExceptionInformation()))
{
@ -503,29 +502,21 @@ void CxbxKrnlMain(int argc, char* argv[])
// Determine memory size accordingly :
SIZE_T memorySize = (g_bIsChihiro ? CHIHIRO_MEMORY_SIZE : XBOX_MEMORY_SIZE);
// Copy over loaded Xbe Header to specified base address
// Copy over loaded Xbe Headers to specified base address
memcpy((void*)CxbxKrnl_Xbe->m_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(&sectionHeaders[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();

View File

@ -35,7 +35,6 @@
#define CXBXKRNL_H
#include "Cxbx.h"
#include "Common/Xbe.h"
#undef FIELD_OFFSET // prevent macro redefinition warnings

View File

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

View File

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

View File

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

View File

@ -43,6 +43,7 @@ namespace xboxkrnl
#include <xboxkrnl/xboxkrnl.h> // 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);
}