diff --git a/import/OpenXDK/include/xboxkrnl/nt.h b/import/OpenXDK/include/xboxkrnl/nt.h index fefd00eea..429f05684 100644 --- a/import/OpenXDK/include/xboxkrnl/nt.h +++ b/import/OpenXDK/include/xboxkrnl/nt.h @@ -46,7 +46,11 @@ XBSYSAPI EXPORTNUM(187) NTSTATUS NTAPI NtClose IN HANDLE Handle ); -XBSYSAPI VOID *NtCreateDirectoryObject; +XBSYSAPI EXPORTNUM(188) NTSTATUS NTAPI NtCreateDirectoryObject +( + OUT PHANDLE DirectoryHandle, + IN POBJECT_ATTRIBUTES ObjectAttributes +); // ****************************************************************** // * NtCreateEvent @@ -59,6 +63,8 @@ XBSYSAPI EXPORTNUM(189) NTSTATUS NTAPI NtCreateEvent IN BOOLEAN InitialState ); + + // ****************************************************************** // * NtCreateFile // ****************************************************************** diff --git a/src/CxbxKrnl/CxbxKrnl.cpp b/src/CxbxKrnl/CxbxKrnl.cpp index f5d7319b3..8940026ca 100644 --- a/src/CxbxKrnl/CxbxKrnl.cpp +++ b/src/CxbxKrnl/CxbxKrnl.cpp @@ -43,6 +43,7 @@ namespace xboxkrnl #include "CxbxKrnl.h" #include "Emu.h" +#include "EmuFile.h" #include "EmuFS.h" #include "EmuShared.h" #include "HLEIntercept.h" @@ -68,6 +69,9 @@ extern CXBXKRNL_API HWND CxbxKrnl_hEmuParent = NULL; /*! thread handles */ static HANDLE g_hThreads[MAXIMUM_XBOX_THREADS] = { 0 }; +std::string CxbxBasePath; +HANDLE CxbxBasePathHandle; + static uint32 funcAddr[]= { 0x001396D1, // -> 0x00139709 (Size : 56 bytes) @@ -159,6 +163,53 @@ extern "C" CXBXKRNL_API bool CxbxKrnlVerifyVersion(const char *szVersion) return true; } + +void CxbxLaunchXbe(void(*Entry)()) +{ + // + // Xbe entry point + // + + __try + { + EmuSwapFS(); // XBox FS + + // _USE_XGMATH Disabled in mesh :[ + // halo : dword_0_2E2D18 + // halo : 1744F0 (bink) + //_asm int 3; + + /* + for(int v=0;vdwCertificateAddr, &((uint08*)pXbeHeader)[pXbeHeader->dwCertificateAddr - 0x00010000], sizeof(Xbe::Certificate)); } - // - // initialize current directory - // + // Initialize devices : - { - char szBuffer[260]; + char szBuffer[260]; + SHGetSpecialFolderPath(NULL, szBuffer, CSIDL_APPDATA, TRUE); + strcat(szBuffer, "\\Cxbx\\"); - g_EmuShared->GetXbePath(szBuffer); + std::string basePath(szBuffer); + CxbxBasePath = basePath + "\\EmuDisk\\"; - if(szBuffer && *szBuffer) - SetCurrentDirectory(szBuffer); - else - GetCurrentDirectory(260, szBuffer); + memset(szBuffer, 0, 260); + GetCurrentDirectory(260, szBuffer); + if (szBuffer[strlen(szBuffer)] != '\\') + szBuffer[strlen(szBuffer)+1] = '\\'; - g_strCurDrive = _strdup(szBuffer); + std::string xbePath(szBuffer); + + CxbxBasePathHandle = CreateFile(CxbxBasePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - g_hCurDir = CreateFile(szBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + memset(szBuffer, 0, 260); + sprintf(szBuffer, "%08X", ((Xbe::Certificate*)pXbeHeader->dwCertificateAddr)->dwTitleId); - if(g_hCurDir == INVALID_HANDLE_VALUE) - CxbxKrnlCleanup("Could not map D:\\\n"); + std::string titleId(szBuffer); - DbgPrintf("EmuMain (0x%X): CurDir := %s\n", GetCurrentThreadId(), szBuffer); - } + // Games may assume they are running from CdRom : + CxbxRegisterDeviceNativePath(DeviceCdrom0, xbePath); - // - // initialize EmuDisk - // + // Partition 0 contains configuration data, and is accessed as a native file, instead as a folder : + CxbxRegisterDeviceNativePath(DeviceHarddisk0Partition0, CxbxBasePath + "Partition0_ConfigData.bin", true); /*IsFile=*/ + // The first two partitions are for Data and Shell files, respectively : + CxbxRegisterDeviceNativePath(DeviceHarddisk0Partition1, CxbxBasePath + "Partition1"); + CxbxRegisterDeviceNativePath(DeviceHarddisk0Partition2, CxbxBasePath + "Partition2"); + // The following partitions are for caching purposes - for now we allocate up to 7 (as xbmp needs that many) : + CxbxRegisterDeviceNativePath(DeviceHarddisk0Partition3, CxbxBasePath + "Partition3"); + CxbxRegisterDeviceNativePath(DeviceHarddisk0Partition4, CxbxBasePath + "Partition4"); + CxbxRegisterDeviceNativePath(DeviceHarddisk0Partition5, CxbxBasePath + "Partition5"); + CxbxRegisterDeviceNativePath(DeviceHarddisk0Partition6, CxbxBasePath + "Partition6"); + CxbxRegisterDeviceNativePath(DeviceHarddisk0Partition7, CxbxBasePath + "Partition7"); + - { - char szBuffer[260]; + DbgPrintf("EmuMain : Creating default symbolic links.\n"); - SHGetSpecialFolderPath(NULL, szBuffer, CSIDL_APPDATA, TRUE); + // Create default symbolic links : + { + // Arrange that the Xbe path can reside outside the partitions, and put it to g_hCurDir : + CxbxCreateSymbolicLink(DriveC, (xbePath)); + g_hCurDir = ((EmuNtSymbolicLinkObject*)FindNtSymbolicLinkObjectByVolumeLetter(CxbxDefaultXbeVolumeLetter))->RootDirectoryHandle; + // TODO -oDxbx: Make sure this path is set in g_EmuXbePath (xboxkrnl_XeImageFileName) too. + /* + CxbxCreateSymbolicLink(DriveD, DeviceCdrom0); // CdRom goes to D: + CxbxCreateSymbolicLink(DriveE, DeviceHarddisk0Partition1); // Partition1 goes to E: (Data files, savegames, etc.) + CxbxCreateSymbolicLink(DriveF, DeviceHarddisk0Partition2); // Partition2 goes to F: (Shell files, dashboard, etc.) + CxbxCreateSymbolicLink(DriveT, DeviceHarddisk0Partition1 + "\\TDATA\\" + titleId + "\\"); // Partition1\Title data goes to T: + CxbxCreateSymbolicLink(DriveU, DeviceHarddisk0Partition1 + "\\UDATA\\" + titleId + "\\"); // Partition1\User data goes to U: + CxbxCreateSymbolicLink(DriveX, DeviceHarddisk0Partition3); // Partition3 goes to X: + CxbxCreateSymbolicLink(DriveY, DeviceHarddisk0Partition4); // Partition4 goes to Y: */ - strcat(szBuffer, "\\Cxbx\\"); - - CreateDirectory(szBuffer, NULL); - - sint32 spot = -1; - - for(int v=0;v<260;v++) - { - if(szBuffer[v] == '\\') { spot = v; } - else if(szBuffer[v] == '\0') { break; } - } - - if(spot != -1) { szBuffer[spot] = '\0'; } - - Xbe::Certificate *pCertificate = (Xbe::Certificate*)pXbeHeader->dwCertificateAddr; - - // - // create EmuDisk directory - // - - strcpy(&szBuffer[spot], "\\EmuDisk"); - - CreateDirectory(szBuffer, NULL); - - // - // create T:\ directory - // - - { - strcpy(&szBuffer[spot], "\\EmuDisk\\T"); - - CreateDirectory(szBuffer, NULL); - - sprintf(&szBuffer[spot+10], "\\%08x", pCertificate->dwTitleId); - - CreateDirectory(szBuffer, NULL); - - g_strTDrive = _strdup(szBuffer); - - g_hTDrive = CreateFile(szBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - - if(g_hTDrive == INVALID_HANDLE_VALUE) - CxbxKrnlCleanup("Could not map T:\\\n"); - - DbgPrintf("EmuMain (0x%X): T Data := %s\n", GetCurrentThreadId(), szBuffer); - } - - // - // create U:\ directory - // - - { - strcpy(&szBuffer[spot], "\\EmuDisk\\U"); - - CreateDirectory(szBuffer, NULL); - - sprintf(&szBuffer[spot+10], "\\%08x", pCertificate->dwTitleId); - - CreateDirectory(szBuffer, NULL); - - g_strUDrive = _strdup(szBuffer); - - g_hUDrive = CreateFile(szBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - - if(g_hUDrive == INVALID_HANDLE_VALUE) - CxbxKrnlCleanup("Could not map U:\\\n"); - - DbgPrintf("EmuMain (0x%X): U Data := %s\n", GetCurrentThreadId(), szBuffer); - } - - // - // create Z:\ directory - // - - { - strcpy(&szBuffer[spot], "\\EmuDisk\\Z"); - - CreateDirectory(szBuffer, NULL); - - //* is it necessary to make this directory title unique? - sprintf(&szBuffer[spot+10], "\\%08x", pCertificate->dwTitleId); - - CreateDirectory(szBuffer, NULL); - //*/ - - g_strZDrive = _strdup(szBuffer); - - g_hZDrive = CreateFile(szBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - - if(g_hUDrive == INVALID_HANDLE_VALUE) - CxbxKrnlCleanup("Could not map Z:\\\n"); - - DbgPrintf("EmuMain (0x%X): Z Data := %s\n", GetCurrentThreadId(), szBuffer); - } - } + // Mount the Utility drive (Z:) conditionally : + if (CxbxKrnl_XbeHeader->dwInitFlags.bMountUtilityDrive) + CxbxMountUtilityDrive(CxbxKrnl_XbeHeader->dwInitFlags.bFormatUtilityDrive);/*fFormatClean=*/ + } // // duplicate handle in order to retain Suspend/Resume thread rights from a remote thread @@ -429,47 +416,7 @@ extern "C" CXBXKRNL_API void CxbxKrnlInit DbgPrintf("EmuMain (0x%X): Initial thread starting.\n", GetCurrentThreadId()); - // - // Xbe entry point - // - - __try - { - EmuSwapFS(); // XBox FS - - // _USE_XGMATH Disabled in mesh :[ - // halo : dword_0_2E2D18 - // halo : 1744F0 (bink) - //_asm int 3; - - /* - for(int v=0;vWin32->CxbxKrnl->EmuFile.cpp -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2002-2003 Aaron Robinson -// * -// * All rights reserved -// * -// ****************************************************************** -#define _CXBXKRNL_INTERNAL -#define _XBOXKRNL_DEFEXTRN_ - -#include "EmuFile.h" - -// Array of EmuHandles in the system -EmuHandle EmuHandle::Handles[EMU_MAX_HANDLES]; - -// Pointer to first free handle in array, or NULL if none -volatile EmuHandle *EmuHandle::FirstFree; - -// Pointer to last free handle in array, or NULL if none -volatile EmuHandle *EmuHandle::LastFree; - -// Lock on the handle system -CRITICAL_SECTION EmuHandle::HandleLock; - -// ****************************************************************** -// * Initialize the handle database -// ****************************************************************** -bool EmuHandle::Initialize() -{ - size_t x; - - // Initialize the critical section - InitializeCriticalSection(&HandleLock); - - // Mark all handles as free. We also set up the linked list of - // free handles here. - for (x = 0; x < EMU_MAX_HANDLES; x++) - { - Handles[x].m_Type = EMUHANDLE_TYPE_EMPTY; - Handles[x].m_NextFree = &Handles[x + 1]; - } - - // The last entry should have a NULL next entry - Handles[EMU_MAX_HANDLES - 1].m_NextFree = NULL; - - // Set up the head and tail pointers - FirstFree = &Handles[0]; - LastFree = &Handles[EMU_MAX_HANDLES]; - - return true; -} - -// ****************************************************************** -// * func: EmuHandle::Lock -// * Locks the handle database -// ****************************************************************** -inline void EmuHandle::Lock(void) -{ - EnterCriticalSection(&HandleLock); -} - -// ****************************************************************** -// * func: EmuHandle::Unlock -// * Unlocks the handle database -// ****************************************************************** -inline void EmuHandle::Unlock(void) -{ - LeaveCriticalSection(&HandleLock); -} - -// ****************************************************************** -// * func: EmuHandle::Allocate -// * Allocates a new handle -// ****************************************************************** -EmuHandle volatile *EmuHandle::Allocate(void) -{ - volatile EmuHandle *Handle; - - // Lock the database - Lock(); - - // Get the first free entry - Handle = FirstFree; - - // Remove it from the list - FirstFree = Handle->m_NextFree; - - // If it was the last handle, clear LastFree - if (!Handle->m_NextFree) - LastFree = NULL; - - // Initialize the handle's fields - Handle->m_Type = EMUHANDLE_TYPE_ALLOCATED; - Handle->m_Object = NULL; - - // Unlock the database - Unlock(); - - return Handle; -} +// ****************************************************************** +// * +// * .,-::::: .,:: .::::::::. .,:: .: +// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;; +// * [[[ '[[,,[[' [[[__[[\. '[[,,[[' +// * $$$ Y$$$P $$""""Y$$ Y$$$P +// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo, +// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm, +// * +// * Cxbx->Win32->CxbxKrnl->EmuFile.cpp +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2002-2003 Aaron Robinson +// * +// * All rights reserved +// * +// ****************************************************************** +#define _CXBXKRNL_INTERNAL +#define _XBOXKRNL_DEFEXTRN_ + +#include "EmuFile.h" +#include +#include +#include +#include +#include "CxbxKrnl.h" + +std::string DriveSerial = "\\??\\serial:"; +std::string DriveCdRom0 = "\\??\\CdRom0:"; // CD-ROM device +std::string DriveMbfs = "\\??\\mbfs:"; // media board's file system area device +std::string DriveMbcom = "\\??\\mbcom:"; // media board's communication area device +std::string DriveMbrom = "\\??\\mbrom:"; // media board's boot ROM device +std::string DriveC = "\\??\\C:"; // C: is HDD0 +std::string DriveD = "\\??\\D:"; // D: is DVD Player +std::string DriveE = "\\??\\E:"; +std::string DriveF = "\\??\\F:"; +std::string DriveT = "\\??\\T:"; // T: is Title persistent data region +std::string DriveU = "\\??\\U:"; // U: is User persistent data region +std::string DriveV = "\\??\\V:"; +std::string DriveW = "\\??\\W:"; +std::string DriveX = "\\??\\X:"; +std::string DriveY = "\\??\\Y:"; // Y: is Dashboard volume (contains "xboxdash.xbe" and "XDASH" folder + contents) +std::string DriveZ = "\\??\\Z:"; // Z: is Title utility data region +std::string DeviceCdrom0 = "\\Device\\CdRom0"; +std::string DeviceHarddisk0 = "\\Device\\Harddisk0"; +std::string DeviceHarddisk0Partition0 = "\\Device\\Harddisk0\\partition0"; // Contains raw config sectors (like XBOX_REFURB_INFO) + entire hard disk +std::string DeviceHarddisk0Partition1 = "\\Device\\Harddisk0\\partition1"; // Data partition. Contains TDATA and UDATA folders. +std::string DeviceHarddisk0Partition2 = "\\Device\\Harddisk0\\partition2"; // Shell partition. Contains Dashboard (cpxdash.xbe, evoxdash.xbe or xboxdash.xbe) +std::string DeviceHarddisk0Partition3 = "\\Device\\Harddisk0\\partition3"; // First cache partition. Contains cache data (from here up to largest number) +std::string DeviceHarddisk0Partition4 = "\\Device\\Harddisk0\\partition4"; +std::string DeviceHarddisk0Partition5 = "\\Device\\Harddisk0\\partition5"; +std::string DeviceHarddisk0Partition6 = "\\Device\\Harddisk0\\partition6"; +std::string DeviceHarddisk0Partition7 = "\\Device\\Harddisk0\\partition7"; +std::string DeviceHarddisk0Partition8 = "\\Device\\Harddisk0\\partition8"; +std::string DeviceHarddisk0Partition9 = "\\Device\\Harddisk0\\partition9"; +std::string DeviceHarddisk0Partition10 = "\\Device\\Harddisk0\\partition10"; +std::string DeviceHarddisk0Partition11 = "\\Device\\Harddisk0\\partition11"; +std::string DeviceHarddisk0Partition12 = "\\Device\\Harddisk0\\partition12"; +std::string DeviceHarddisk0Partition13 = "\\Device\\Harddisk0\\partition13"; +std::string DeviceHarddisk0Partition14 = "\\Device\\Harddisk0\\partition14"; +std::string DeviceHarddisk0Partition15 = "\\Device\\Harddisk0\\partition15"; +std::string DeviceHarddisk0Partition16 = "\\Device\\Harddisk0\\partition16"; +std::string DeviceHarddisk0Partition17 = "\\Device\\Harddisk0\\partition17"; +std::string DeviceHarddisk0Partition18 = "\\Device\\Harddisk0\\partition18"; +std::string DeviceHarddisk0Partition19 = "\\Device\\Harddisk0\\partition19"; +std::string DeviceHarddisk0Partition20 = "\\Device\\Harddisk0\\partition20"; // 20 = Largest possible partition number +char CxbxDefaultXbeVolumeLetter = 'C'; + +// Array of EmuHandles in the system +EmuHandle EmuHandle::Handles[EMU_MAX_HANDLES]; + +// Pointer to first free handle in array, or NULL if none +volatile EmuHandle *EmuHandle::FirstFree; + +// Pointer to last free handle in array, or NULL if none +volatile EmuHandle *EmuHandle::LastFree; + +// Lock on the handle system +CRITICAL_SECTION EmuHandle::HandleLock; + +EmuNtSymbolicLinkObject* NtSymbolicLinkObjects[26]; + +struct XboxDevice { + std::string XboxFullPath; + std::string NativePath; + HANDLE NativeRootHandle; +}; +std::vector Devices; + +bool CxbxRegisterDeviceNativePath(std::string XboxFullPath, std::string NativePath, bool IsFile) +{ + bool result = false; + int i = 0; + if (IsFile) { + result = true; // Actually, this is the Config sectors partition (partition0) registered as a file + } + else + { + int status = SHCreateDirectoryEx(NULL, NativePath.c_str(), NULL); + result = status == STATUS_SUCCESS || ERROR_ALREADY_EXISTS; + } + if (result) + { + XboxDevice newDevice; + newDevice.XboxFullPath = XboxFullPath; + newDevice.NativePath = NativePath; + Devices.push_back(newDevice); + } + return result; +} + + +NTSTATUS CxbxCreateSymbolicLink(std::string SymbolicLinkName, std::string FullPath) +{ + NTSTATUS result = 0; + EmuNtSymbolicLinkObject* SymbolicLinkObject = FindNtSymbolicLinkObjectByName(SymbolicLinkName); + + if ((SymbolicLinkObject != NULL)) { + // In that case, close it : + SymbolicLinkObject->NtClose(); + } + + // Now (re)create a symbolic link object, and initialize it with the new definition : + SymbolicLinkObject = new EmuNtSymbolicLinkObject(); + result = SymbolicLinkObject->Init(SymbolicLinkName, FullPath); + + if (result != STATUS_SUCCESS) + SymbolicLinkObject->NtClose(); + + return result; +} + +// ****************************************************************** +// * Initialize the handle database +// ****************************************************************** +bool EmuHandle::Initialize() +{ + size_t x; + + // Initialize the critical section + InitializeCriticalSection(&HandleLock); + + // Mark all handles as free. We also set up the linked list of + // free handles here. + for (x = 0; x < EMU_MAX_HANDLES; x++) + { + Handles[x].m_Type = EMUHANDLE_TYPE_EMPTY; + Handles[x].m_NextFree = &Handles[x + 1]; + } + + // The last entry should have a NULL next entry + Handles[EMU_MAX_HANDLES - 1].m_NextFree = NULL; + + // Set up the head and tail pointers + FirstFree = &Handles[0]; + LastFree = &Handles[EMU_MAX_HANDLES]; + + return true; +} + +// ****************************************************************** +// * func: EmuHandle::Lock +// * Locks the handle database +// ****************************************************************** +inline void EmuHandle::Lock(void) +{ + EnterCriticalSection(&HandleLock); +} + +// ****************************************************************** +// * func: EmuHandle::Unlock +// * Unlocks the handle database +// ****************************************************************** +inline void EmuHandle::Unlock(void) +{ + LeaveCriticalSection(&HandleLock); +} + +// ****************************************************************** +// * func: EmuHandle::Allocate +// * Allocates a new handle +// ****************************************************************** +EmuHandle volatile *EmuHandle::Allocate(void) +{ + volatile EmuHandle *Handle; + + // Lock the database + Lock(); + + // Get the first free entry + Handle = FirstFree; + + // Remove it from the list + FirstFree = Handle->m_NextFree; + + // If it was the last handle, clear LastFree + if (!Handle->m_NextFree) + LastFree = NULL; + + // Initialize the handle's fields + Handle->m_Type = EMUHANDLE_TYPE_ALLOCATED; + Handle->m_Object = NULL; + + // Unlock the database + Unlock(); + + return Handle; +} + +NTSTATUS EmuNtSymbolicLinkObject::Init(std::string aSymbolicLinkName, std::string aFullPath) +{ + NTSTATUS result = 0; + bool IsNativePath = false; + int i = 0; + std::string ExtraPath; + int DeviceIndex = 0; + result = STATUS_OBJECT_NAME_INVALID; + DriveLetter = SymbolicLinkToDriveLetter(aSymbolicLinkName); + if (DriveLetter > 'A' && DriveLetter < 'Z') + { + result = STATUS_OBJECT_NAME_COLLISION; + if (FindNtSymbolicLinkObjectByVolumeLetter(DriveLetter) == NULL) + { + // Look up the partition in the list of pre-registered devices : + result = STATUS_DEVICE_DOES_NOT_EXIST; // TODO : Is this the correct error? + + // Make a distinction between Xbox paths (starting with '\Device'...) and Native paths : + std::string deviceString = "\\Device"; + IsNativePath = aFullPath.compare(0, deviceString.length(), deviceString) != 0; + if (IsNativePath) + DeviceIndex = 0; + else + { + DeviceIndex = -1; + for (int i = 0; i < Devices.size(); i++) { + int compare = aFullPath.compare(Devices[i].XboxFullPath); + if (aFullPath.compare(0, Devices[i].XboxFullPath.length(), Devices[i].XboxFullPath) == 0) + { + DeviceIndex = i; + break; + } + } + } + if (DeviceIndex >= 0) + { + result = STATUS_SUCCESS; + SymbolicLinkName = aSymbolicLinkName; + XboxFullPath = aFullPath; // TODO : What path do we remember in IsNativePath mode? + if (IsNativePath) + { + NativePath = ""; + ExtraPath = aFullPath; + } + else + { + NativePath = Devices[DeviceIndex].NativePath; + // Handle the case where a sub folder of the partition is mounted (instead of it's root) : + ExtraPath = aFullPath.substr(Devices[DeviceIndex].XboxFullPath.length(), std::string::npos); + } + if (!ExtraPath.empty()) + NativePath = NativePath + ExtraPath; + + SHCreateDirectoryEx(NULL, NativePath.c_str(), NULL); + + RootDirectoryHandle = CreateFile(NativePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (RootDirectoryHandle == INVALID_HANDLE_VALUE) + { + result = STATUS_DEVICE_DOES_NOT_EXIST; // TODO : Is this the correct error? + CxbxKrnlCleanup((std::string("Could not map ") + NativePath).c_str()); + } + else + { + NtSymbolicLinkObjects[DriveLetter - 'A'] = this; + DbgPrintf("EmuMain : Linked \"%s\" to \"%s\" (residing at \"%s\")\n", aSymbolicLinkName.c_str(), aFullPath.c_str(), NativePath.c_str()); + } + } + } + } + return result; +} + +void EmuNtSymbolicLinkObject::Free() +{ + return; +} + +bool CxbxMountUtilityDrive(bool formatClean) +{ + Xbe::Certificate* pCertificate; + std::string TitleStr; + NTSTATUS status; + + // TODO -oDxbx : Select the oldest cache partition somehow. + // For now, select partition6 as 'Utility data' drive, and link it to Z: + pCertificate = (Xbe::Certificate*)CxbxKrnl_XbeHeader->dwCertificateAddr; + + char szBuffer[255]; + sprintf(szBuffer, "%08X", ((Xbe::Certificate*)CxbxKrnl_XbeHeader->dwCertificateAddr)->dwTitleId); + TitleStr = szBuffer; + status = CxbxCreateSymbolicLink(DriveZ, DeviceHarddisk0Partition6 + "\\Cxbx_ZDATA_" + TitleStr + "\\"); + + // Dxbx note : The ZDATA convention is not actually what the Xbox does, but for now + // allows us to skip the partition-selection and formatting of the Utility drive, + // by creating a unique subfolder per title. + + // TODO -oDxbx : Implement 'formatting' (cleaning) of the Utility drive + + return status == STATUS_SUCCESS; +} + +char SymbolicLinkToDriveLetter(std::string SymbolicLinkName) +{ + char result = '\0'; + // SymbolicLinkName must look like this : "\??\D:" + if ((SymbolicLinkName.size() == 6) && (SymbolicLinkName[0] == '\\') && (SymbolicLinkName[1] == '?') && (SymbolicLinkName[2] == '?') && (SymbolicLinkName[3] == '\\') && (SymbolicLinkName[5] == ':')) + { + result = SymbolicLinkName[4]; + switch (result) + { + case /*# 'A' .. 'Z' */ 'A': + case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': + case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': + case 'V': case 'W': case 'X': case 'Y': case 'Z': + return result; + break; + case /*# 'a' .. 'z' */ 'a': + case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': + case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': + case 'v': case 'w': case 'x': case 'y': case 'z': + { + result = (int(result) + int('A') - int('a')); + return result; + } + break; + } + } + result = '\x00'; + return result; +} + +EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByVolumeLetter(const char VolumeLetter) +{ + EmuNtSymbolicLinkObject* result = NULL; + switch (VolumeLetter) + { + case /*# 'A' .. 'Z' */ 'A': + case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': + case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': + case 'V': case 'W': case 'X': case 'Y': case 'Z': + result = NtSymbolicLinkObjects[VolumeLetter - 65]; + break; + case /*# 'a' .. 'z' */ 'a': + case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': + case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': + case 'v': case 'w': case 'x': case 'y': case 'z': + result = NtSymbolicLinkObjects[VolumeLetter + 'A' - 'a' - 65]; + break; + default: + result = NULL; + } + return result; +} + +EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByName(std::string SymbolicLinkName) +{ + EmuNtSymbolicLinkObject* result = NULL; + result = FindNtSymbolicLinkObjectByVolumeLetter(SymbolicLinkToDriveLetter(SymbolicLinkName)); + return result; +} + + +EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByDevice(std::string DeviceName) + +{ + EmuNtSymbolicLinkObject* result = NULL; + char VolumeLetter = '\0'; + for (int stop = 'Z', VolumeLetter = 'A'; VolumeLetter <= stop; VolumeLetter++) + { + result = NtSymbolicLinkObjects[VolumeLetter - 65]; + if ((result != NULL) && DeviceName.compare(0, result->XboxFullPath.length(), result->XboxFullPath) == 0) + return result; + } + result = NULL; + return result; +} + + +EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByRootHandle(const HANDLE Handle) +{ + EmuNtSymbolicLinkObject* result = NULL; + char VolumeLetter = '\0'; + for (int stop = 'Z', VolumeLetter = 'A'; VolumeLetter <= stop; VolumeLetter++) + { + result = NtSymbolicLinkObjects[VolumeLetter - 65]; + if ((result != NULL) && (Handle == result->RootDirectoryHandle)) + return result; + } + result = NULL; + return result; +} + +NTSTATUS EmuNtObject::NtClose() +{ + NTSTATUS result = 0; + RefCount--; + if (RefCount <= 0) + Free(); + result = STATUS_SUCCESS; + return result; +} + +EmuNtObject* EmuNtObject::NtDuplicateObject(DWORD Options) +{ + EmuNtObject* result = NULL; + RefCount++; + result = this; + return result; +} \ No newline at end of file diff --git a/src/CxbxKrnl/EmuFile.h b/src/CxbxKrnl/EmuFile.h index 1ff6808d2..686bd0236 100644 --- a/src/CxbxKrnl/EmuFile.h +++ b/src/CxbxKrnl/EmuFile.h @@ -43,6 +43,7 @@ namespace xboxkrnl }; #include +#include // ****************************************************************** // * prevent name collisions @@ -54,11 +55,56 @@ namespace NtDll #include "Emu.h" +extern std::string DriveSerial; +extern std::string DriveCdRom0; +extern std::string DriveMbfs; +extern std::string DriveMbcom; +extern std::string DriveMbrom; +extern std::string DriveC; +extern std::string DriveD; +extern std::string DriveE; +extern std::string DriveF; +extern std::string DriveT; +extern std::string DriveU; +extern std::string DriveV; +extern std::string DriveW; +extern std::string DriveX; +extern std::string DriveY; +extern std::string DriveZ; +extern std::string DeviceCdrom0; +extern std::string DeviceHarddisk0; +extern std::string DeviceHarddisk0Partition0; +extern std::string DeviceHarddisk0Partition1; +extern std::string DeviceHarddisk0Partition2; +extern std::string DeviceHarddisk0Partition3; +extern std::string DeviceHarddisk0Partition4; +extern std::string DeviceHarddisk0Partition5; +extern std::string DeviceHarddisk0Partition6; +extern std::string DeviceHarddisk0Partition7; +extern std::string DeviceHarddisk0Partition8; +extern std::string DeviceHarddisk0Partition9; +extern std::string DeviceHarddisk0Partition10; +extern std::string DeviceHarddisk0Partition11; +extern std::string DeviceHarddisk0Partition12; +extern std::string DeviceHarddisk0Partition13; +extern std::string DeviceHarddisk0Partition14; +extern std::string DeviceHarddisk0Partition15; +extern std::string DeviceHarddisk0Partition16; +extern std::string DeviceHarddisk0Partition17; +extern std::string DeviceHarddisk0Partition18; +extern std::string DeviceHarddisk0Partition19; +extern std::string DeviceHarddisk0Partition20; +extern char CxbxDefaultXbeVolumeLetter; + +extern std::string CxbxBasePath; +extern HANDLE CxbxBasePathHandle; + // ****************************************************************** // * Maximum number of open handles in the system // ****************************************************************** #define EMU_MAX_HANDLES 1024 + // ****************************************************************** // * Wrapper of a handle object // ****************************************************************** @@ -134,14 +180,14 @@ class EmuNtObject { public: // Decrements the reference count of this object (never override) - void NtClose(void); + NTSTATUS NtClose(void); // These functions mimic the Nt* calls // Increments the reference count of this object // For file handles, a whole new EmuFile structure is returned. // For other objects (the default implementation), "this" is returned. - virtual EmuNtObject *NtDuplicateObject(void); + EmuNtObject *NtDuplicateObject(DWORD options); protected: // Object name (Unicode, because we handle after-conversion strings) @@ -152,10 +198,7 @@ class EmuNtObject // Called by close() when the reference count reaches zero virtual void Free(void) = 0; - // Constructor - EmuNtObject(void); - // Destructor - virtual ~EmuNtObject() = 0; + private: // Reference count @@ -177,6 +220,20 @@ class EmuNtFile : public EmuNtObject //EmuNtVolume *Volume; }; +// ****************************************************************** +// * Emulated symbolic link handle +// ****************************************************************** +class EmuNtSymbolicLinkObject : public EmuNtObject { +public: + char DriveLetter; + std::string SymbolicLinkName; + std::string XboxFullPath; + std::string NativePath; + HANDLE RootDirectoryHandle; + NTSTATUS Init(std::string aSymbolicLinkName, std::string aFullPath); + void Free(); +}; + // ****************************************************************** // * is hFile a 'special' emulated handle? // ****************************************************************** @@ -203,4 +260,15 @@ static inline HANDLE PtrToEmuHandle(EmuHandle *pEmuHandle) return (HANDLE)((uint32)pEmuHandle + 0x80000000); } +char SymbolicLinkToDriveLetter(std::string aSymbolicLinkName); +EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByVolumeLetter(const char VolumeLetter); +EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByName(std::string SymbolicLinkName); +EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByDevice(std::string DeviceName); +EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByRootHandle(HANDLE Handle); +void CleanupSymbolicLinks(); +bool CxbxRegisterDeviceNativePath(std::string XboxFullPath, std::string NativePath, bool IsFile = false); +HANDLE CxbxGetDeviceNativeRootHandle(std::string XboxFullPath); +NTSTATUS CxbxCreateSymbolicLink(std::string SymbolicLinkName, std::string FullPath); +bool CxbxMountUtilityDrive(bool formatClean); + #endif diff --git a/src/CxbxKrnl/EmuKrnl.cpp b/src/CxbxKrnl/EmuKrnl.cpp index 67f031337..59fcdaf04 100644 --- a/src/CxbxKrnl/EmuKrnl.cpp +++ b/src/CxbxKrnl/EmuKrnl.cpp @@ -86,6 +86,15 @@ struct INTERNAL_CRITICAL_SECTION NtDll::_RTL_CRITICAL_SECTION NativeCriticalSection; }; +struct NativeObjectAttributes { + wchar_t wszObjectName[160]; + NtDll::UNICODE_STRING NtUnicodeString; + NtDll::OBJECT_ATTRIBUTES NtObjAttr; + // This is what should be passed on to Windows + // after CxbxObjectAttributesToNT() has been called : + NtDll::POBJECT_ATTRIBUTES NtObjAttrPtr; +}; + #define MAX_XBOX_CRITICAL_SECTIONS 1024 INTERNAL_CRITICAL_SECTION GlobalCriticalSections[MAX_XBOX_CRITICAL_SECTIONS] = {0}; @@ -1153,6 +1162,135 @@ callComplete: } #pragma warning(pop) + +NTSTATUS CxbxObjectAttributesToNT(xboxkrnl::POBJECT_ATTRIBUTES ObjectAttributes, NativeObjectAttributes& nativeObjectAttributes, std::string aFileAPIName = "") +{ + NTSTATUS result = 0; + std::string OriginalPath; + std::string RelativePath; + std::string XboxFullPath; + std::string NativePath; + EmuNtSymbolicLinkObject* NtSymbolicLinkObject = NULL; + result = STATUS_SUCCESS; + if (ObjectAttributes == NULL) + { + // When the pointer is nil, make sure we pass nil to Windows too : + nativeObjectAttributes.NtObjAttrPtr = NULL; + return result; + } + + // ObjectAttributes are given, so make sure the pointer we're going to pass to Windows is assigned : + nativeObjectAttributes.NtObjAttrPtr = &nativeObjectAttributes.NtObjAttr; + RelativePath = std::string(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length); + OriginalPath = RelativePath; + + // Always trim '\??\' off : + if ((RelativePath.length() >= 4) && (RelativePath[0] == '\\') && (RelativePath[1] == '?') && (RelativePath[2] == '?') && (RelativePath[3] == '\\')) + RelativePath.erase(0, 4); + + // Check if we where called from a File-handling API : + if (!aFileAPIName.empty()) + { + NtSymbolicLinkObject = NULL; + // Check if the path starts with a volume indicator : + if ((RelativePath.length() >= 2) && (RelativePath[1] == ':')) + { + // Look up the symbolic link information using the drive letter : + NtSymbolicLinkObject = FindNtSymbolicLinkObjectByVolumeLetter(RelativePath[0]); + RelativePath.erase(0, 2); // Remove 'C:' + + // If the remaining path starts with a ':', remove it (to prevent errors) : + if ((RelativePath.length() > 0) && (RelativePath[0] == ':')) + RelativePath.erase(0, 1); // xbmp needs this, as it accesses 'e::\' + } + // Check if the path starts with a macro indicator : + else + if (RelativePath.compare(0, 1, "$") == 0) + { + if (RelativePath.compare(0, 5, "$HOME") == 0) // "xbmp" needs this + { + NtSymbolicLinkObject = FindNtSymbolicLinkObjectByRootHandle(g_hCurDir); + RelativePath.erase(0, 5); // Remove '$HOME' + } + else + CxbxKrnlCleanup(("Unsupported path macro : " + OriginalPath).c_str()); + } + // Check if the path starts with a relative path indicator : + else + if (RelativePath.compare(0, 1, ".") == 0) // "4x4 Evo 2" needs this + { + NtSymbolicLinkObject = FindNtSymbolicLinkObjectByRootHandle(g_hCurDir); + RelativePath.erase(0, 1); // Remove the '.' + } + else + { + // The path seems to be a device path, look it up : + NtSymbolicLinkObject = FindNtSymbolicLinkObjectByDevice(RelativePath); + // Fixup RelativePath path here + if ((NtSymbolicLinkObject != NULL)) + RelativePath.erase(0, NtSymbolicLinkObject->XboxFullPath.length()); // Remove '\Device\Harddisk0\Partition2' + } + if ((NtSymbolicLinkObject != NULL)) + { + // If the remaining path starts with a '\', remove it (to prevent working in a native root) : + if ((RelativePath.length() > 0) && (RelativePath[0] == '\\')) + RelativePath.erase(0, 1); + XboxFullPath = NtSymbolicLinkObject->XboxFullPath; + NativePath = NtSymbolicLinkObject->NativePath; + ObjectAttributes->RootDirectory = NtSymbolicLinkObject->RootDirectoryHandle; + } + else + { + // No symbolic link - as last resort, check if the path accesses a partition from Harddisk0 : + if (RelativePath.compare(0, (DeviceHarddisk0 + "\\partition").length(), DeviceHarddisk0 + "\\partition") != 0) + { + result = STATUS_UNRECOGNIZED_VOLUME; // TODO : Is this the correct error? + EmuWarning((("Path not available : ") + OriginalPath).c_str()); + return result; + } + 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 : + ObjectAttributes->RootDirectory = CxbxBasePathHandle; + NativePath = CxbxBasePath; + } + + // Check for special case : Partition0 + if (XboxFullPath.compare(DeviceHarddisk0Partition0) == 0) + { + CxbxKrnlCleanup("Partition0 access not implemented yet! Tell PatrickvL what title triggers this."); + // TODO : Redirect raw sector-access to the 'Partition0_ConfigData.bin' file + // (This file probably needs to be pre-initialized somehow too). + } + + DbgPrintf("EmuKrnl : %s Corrected path...", aFileAPIName.c_str()); + DbgPrintf(" Org:\"%s\"", OriginalPath.c_str()); + if (NativePath.compare(CxbxBasePath) == 0) + { + DbgPrintf(" New:\"$CxbxPath\\EmuDisk%s%s\"", (NativePath.substr(CxbxBasePath.length(), std::string::npos)).c_str(), RelativePath.c_str()); + } + else + DbgPrintf(" New:\"$XbePath\\%s\"", RelativePath.c_str()); + + } + else + { + // For non-file API calls, prefix with '\??\' again : + RelativePath = "\\??\\" + RelativePath; + ObjectAttributes->RootDirectory = 0; + } + + // Convert Ansi to Unicode : + mbstowcs(nativeObjectAttributes.wszObjectName, RelativePath.c_str(), 160); + NtDll::RtlInitUnicodeString(&nativeObjectAttributes.NtUnicodeString, nativeObjectAttributes.wszObjectName); + + // Initialize the NT ObjectAttributes : + InitializeObjectAttributes(&nativeObjectAttributes.NtObjAttr, &nativeObjectAttributes.NtUnicodeString, ObjectAttributes->Attributes, ObjectAttributes->RootDirectory, NULL); + return result; +} + + using namespace xboxkrnl; // ****************************************************************** @@ -1729,8 +1867,7 @@ XBSYSAPI EXPORTNUM(67) xboxkrnl::NTSTATUS NTAPI xboxkrnl::IoCreateSymbolicLink GetCurrentThreadId(), SymbolicLinkName, SymbolicLinkName->Buffer, DeviceName, DeviceName->Buffer); - // TODO: Actually um...implement this function - NTSTATUS ret = STATUS_OBJECT_NAME_COLLISION; + NTSTATUS ret = CxbxCreateSymbolicLink(SymbolicLinkName->Buffer, DeviceName->Buffer); EmuSwapFS(); // Xbox FS @@ -1753,8 +1890,12 @@ XBSYSAPI EXPORTNUM(69) xboxkrnl::NTSTATUS NTAPI xboxkrnl::IoDeleteSymbolicLink ");\n", GetCurrentThreadId(), SymbolicLinkName, SymbolicLinkName->Buffer); - // TODO: Actually um...implement this function - NTSTATUS ret = STATUS_OBJECT_NAME_NOT_FOUND; + EmuNtSymbolicLinkObject* symbolicLink = FindNtSymbolicLinkObjectByName(SymbolicLinkName->Buffer); + + NTSTATUS ret = STATUS_OBJECT_NAME_NOT_FOUND; + + if ((symbolicLink != NULL)) + ret = symbolicLink->NtClose(); EmuSwapFS(); // Xbox FS @@ -2726,6 +2867,49 @@ XBSYSAPI EXPORTNUM(187) xboxkrnl::NTSTATUS NTAPI xboxkrnl::NtClose return ret; } +// ****************************************************************** +// * 0x00BC - NtCreateDirectoryObject +// ****************************************************************** +XBSYSAPI EXPORTNUM(189) xboxkrnl::NTSTATUS NTAPI xboxkrnl::NtCreateDirectoryObject +( + OUT PHANDLE DirectoryHandle, + IN POBJECT_ATTRIBUTES ObjectAttributes +) +{ + EmuSwapFS(); // Win2k/XP FS + + DbgPrintf("EmuKrnl (0x%X): NtCreateDirectoryObject\n" + "(\n" + " DirectoryHandle : 0x%.08X\n" + " ObjectAttributes : 0x%.08X (\"%s\")\n" + ");\n", + GetCurrentThreadId(), DirectoryHandle, ObjectAttributes); + + NTSTATUS ret = 0; + + NativeObjectAttributes nativeObjectAttributes; + ACCESS_MASK DesiredAccess = 0; + + ret = CxbxObjectAttributesToNT(ObjectAttributes, nativeObjectAttributes, "NtCreateDirectoryObject"); + if (ret == STATUS_SUCCESS) + { + // TODO -oDxbx : Is this the correct ACCESS_MASK? : + DesiredAccess = DIRECTORY_CREATE_OBJECT; + + ret = /*# JwaNative::*/ NtDll::NtCreateDirectoryObject(DirectoryHandle, DesiredAccess, nativeObjectAttributes.NtObjAttrPtr); + } + + if (FAILED(ret)) + EmuWarning("NtCreateDirectoryObject Failed!"); + + DbgPrintf("EmuKrnl (0x%X): NtCreateDirectoryObject DirectoryHandle = 0x%.08X\n", GetCurrentThreadId(), *DirectoryHandle); + + EmuSwapFS(); // Xbox FS + + return ret; +} + + // ****************************************************************** // * 0x00BD - NtCreateEvent // ****************************************************************** @@ -2739,38 +2923,30 @@ XBSYSAPI EXPORTNUM(189) xboxkrnl::NTSTATUS NTAPI xboxkrnl::NtCreateEvent { EmuSwapFS(); // Win2k/XP FS - char *szBuffer = (ObjectAttributes != 0) ? ObjectAttributes->ObjectName->Buffer : 0; - DbgPrintf("EmuKrnl (0x%X): NtCreateEvent\n" "(\n" " EventHandle : 0x%.08X\n" - " ObjectAttributes : 0x%.08X (\"%s\")\n" + " ObjectAttributes : 0x%.08X\n" " EventType : 0x%.08X\n" " InitialState : 0x%.08X\n" ");\n", - GetCurrentThreadId(), EventHandle, ObjectAttributes, szBuffer, - EventType, InitialState); + GetCurrentThreadId(), EventHandle, ObjectAttributes, EventType, InitialState); - wchar_t wszObjectName[160]; + NativeObjectAttributes nativeObjectAttributes; + ACCESS_MASK DesiredAccess = 0; - NtDll::UNICODE_STRING NtUnicodeString; - NtDll::OBJECT_ATTRIBUTES NtObjAttr; + // initialize object attributes + NTSTATUS ret = CxbxObjectAttributesToNT(ObjectAttributes, nativeObjectAttributes); /*var*/ + if (ret == STATUS_SUCCESS) + { + // TODO -oDxbx : Is this the correct ACCESS_MASK? : + DesiredAccess = EVENT_ALL_ACCESS; - // initialize object attributes - if(szBuffer != 0) - { - mbstowcs(wszObjectName, "\\??\\", 4); - mbstowcs(wszObjectName+4, szBuffer, 160); - - NtDll::RtlInitUnicodeString(&NtUnicodeString, wszObjectName); - - InitializeObjectAttributes(&NtObjAttr, &NtUnicodeString, ObjectAttributes->Attributes, ObjectAttributes->RootDirectory, NULL); - } - - NtObjAttr.RootDirectory = 0; - - // redirect to NtCreateEvent - NTSTATUS ret = NtDll::NtCreateEvent(EventHandle, EVENT_ALL_ACCESS, (szBuffer != 0) ? &NtObjAttr : 0, (NtDll::EVENT_TYPE)EventType, InitialState); + // redirect to Win2k/XP + ret = NtDll::NtCreateEvent(EventHandle, DesiredAccess, nativeObjectAttributes.NtObjAttrPtr, (NtDll::EVENT_TYPE)EventType, InitialState); + // TODO : Instead of the above, we should consider using the Ke*Event APIs, but + // that would require us to create the event's kernel object with the Ob* api's too! + } if(FAILED(ret)) EmuWarning("NtCreateEvent Failed!"); @@ -2815,170 +2991,12 @@ XBSYSAPI EXPORTNUM(190) xboxkrnl::NTSTATUS NTAPI xboxkrnl::NtCreateFile GetCurrentThreadId(), FileHandle, DesiredAccess, ObjectAttributes, ObjectAttributes->ObjectName->Buffer, IoStatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions); - char ReplaceChar = '\0'; - int ReplaceIndex = -1; - - char *szBuffer = ObjectAttributes->ObjectName->Buffer; - - if(szBuffer == (char*) 0xFFFFFFFF) - szBuffer = NULL; - - if(szBuffer != NULL) - { - //printf("Orig : %s\n", szBuffer); - - // trim this off - if(szBuffer[0] == '\\' && szBuffer[1] == '?' && szBuffer[2] == '?' && szBuffer[3] == '\\') - { - szBuffer += 4; - } - - // D:\ should map to current directory - if( (szBuffer[0] == 'D' || szBuffer[0] == 'd') && szBuffer[1] == ':' && szBuffer[2] == '\\') - { - szBuffer += 3; - - ObjectAttributes->RootDirectory = g_hCurDir; - - DbgPrintf("EmuKrnl (0x%X): NtCreateFile Corrected path...\n", GetCurrentThreadId()); - DbgPrintf(" Org:\"%s\"\n", ObjectAttributes->ObjectName->Buffer); - DbgPrintf(" New:\"$XbePath\\%s\"\n", szBuffer); - } - // Going to map Y:\ to current directory as well (dashboard test, 3944) - else if( (szBuffer[0] == 'Y' || szBuffer[0] == 'y') && szBuffer[1] == ':' && szBuffer[2] == '\\') - { - szBuffer += 3; - - ObjectAttributes->RootDirectory = g_hCurDir; - - DbgPrintf("EmuKrnl (0x%X): NtCreateFile Corrected path...\n", GetCurrentThreadId()); - DbgPrintf(" Org:\"%s\"\n", ObjectAttributes->ObjectName->Buffer); - DbgPrintf(" New:\"$XbePath\\%s\"\n", szBuffer); - } - else if( (szBuffer[0] == 'T' || szBuffer[0] == 't') && szBuffer[1] == ':' && szBuffer[2] == '\\') - { - szBuffer += 3; - - ObjectAttributes->RootDirectory = g_hTDrive; - - DbgPrintf("EmuKrnl (0x%X): NtCreateFile Corrected path...\n", GetCurrentThreadId()); - DbgPrintf(" Org:\"%s\"\n", ObjectAttributes->ObjectName->Buffer); - DbgPrintf(" New:\"$CxbxPath\\EmuDisk\\T\\%s\"\n", szBuffer); - } - else if( (szBuffer[0] == 'U' || szBuffer[0] == 'u') && szBuffer[1] == ':' && szBuffer[2] == '\\') - { - szBuffer += 3; - - ObjectAttributes->RootDirectory = g_hUDrive; - - DbgPrintf("EmuKrnl (0x%X): NtCreateFile Corrected path...\n", GetCurrentThreadId()); - DbgPrintf(" Org:\"%s\"\n", ObjectAttributes->ObjectName->Buffer); - DbgPrintf(" New:\"$CxbxPath\\EmuDisk\\U\\%s\"\n", szBuffer); - } - else if( (szBuffer[0] == 'Z' || szBuffer[0] == 'z') && szBuffer[1] == ':' && szBuffer[2] == '\\') - { - szBuffer += 3; - - ObjectAttributes->RootDirectory = g_hZDrive; - - DbgPrintf("EmuKrnl (0x%X): NtCreateFile Corrected path...\n", GetCurrentThreadId()); - DbgPrintf(" Org:\"%s\"\n", ObjectAttributes->ObjectName->Buffer); - DbgPrintf(" New:\"$CxbxPath\\EmuDisk\\Z\\%s\"\n", szBuffer); - } - - // Ignore wildcards. Xapi FindFirstFile uses the same path buffer for - // NtOpenFile and NtQueryDirectoryFile. Wildcards are only parsed by - // the latter. - { - for(int v=0;szBuffer[v] != '\0';v++) - { - // FIXME: Fallback to parent directory if wildcard is found. - if(szBuffer[v] == '*') - { - ReplaceIndex = v; - break; - } - } - } - - // Note: Hack: Not thread safe (if problems occur, create a temp buffer) - if(ReplaceIndex != -1) - { - ReplaceChar = szBuffer[ReplaceIndex]; - szBuffer[ReplaceIndex] = '\0'; - } - - //printf("Aftr : %s\n", szBuffer); - } - - wchar_t wszObjectName[160]; - - NtDll::UNICODE_STRING NtUnicodeString; - NtDll::OBJECT_ATTRIBUTES NtObjAttr; - - // initialize object attributes - if(szBuffer != NULL) - { - mbstowcs(wszObjectName, szBuffer, 160); - } - else - { - wszObjectName[0] = L'\0'; - } - - NtDll::RtlInitUnicodeString(&NtUnicodeString, wszObjectName); - - InitializeObjectAttributes(&NtObjAttr, &NtUnicodeString, ObjectAttributes->Attributes, ObjectAttributes->RootDirectory, NULL); + NativeObjectAttributes nativeObjectAttributes; + NTSTATUS ret = CxbxObjectAttributesToNT(ObjectAttributes, nativeObjectAttributes, "NtCreateFile"); /*var*/ // redirect to NtCreateFile - NTSTATUS ret = NtDll::NtCreateFile - ( - FileHandle, DesiredAccess, &NtObjAttr, (NtDll::IO_STATUS_BLOCK*)IoStatusBlock, - (NtDll::LARGE_INTEGER*)AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, NULL, 0 - ); - - // If we're trying to open a regular file as a directory, fallback to - // parent directory. This behavior is required by Xapi FindFirstFile. - if(ret == STATUS_NOT_A_DIRECTORY) - { - DbgPrintf("EmuKrnl (0x%X): NtCreateFile fallback to parent directory\n", GetCurrentThreadId()); - - // Restore original buffer. - if(ReplaceIndex != -1) - { - szBuffer[ReplaceIndex] = ReplaceChar; - } - - // Strip filename from path. - int CurIndex = strlen(szBuffer); - while(CurIndex--) - { - if(szBuffer[CurIndex] == '\\') - { - ReplaceIndex = CurIndex; - break; - } - } - if(CurIndex == -1) - { - ReplaceIndex = 0; - } - - // Modify buffer again. - ReplaceChar = szBuffer[ReplaceIndex]; - szBuffer[ReplaceIndex] = '\0'; - DbgPrintf(" New:\"$CurRoot\\%s\"\n", szBuffer); - - mbstowcs(wszObjectName, szBuffer, 160); - NtDll::RtlInitUnicodeString(&NtUnicodeString, wszObjectName); - - ret = NtDll::NtCreateFile - ( - FileHandle, DesiredAccess, &NtObjAttr, (NtDll::IO_STATUS_BLOCK*)IoStatusBlock, - (NtDll::LARGE_INTEGER*)AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, NULL, 0 - ); - } - + ret = NtDll::NtCreateFile(FileHandle, DesiredAccess | GENERIC_READ, nativeObjectAttributes.NtObjAttrPtr, NtDll::PIO_STATUS_BLOCK(IoStatusBlock), NtDll::PLARGE_INTEGER(AllocationSize), FileAttributes, ShareAccess, CreateDisposition, CreateOptions, NULL, 0); + if(FAILED(ret)) { DbgPrintf("EmuKrnl (0x%X): NtCreateFile Failed! (0x%.08X)\n", GetCurrentThreadId(), ret); @@ -2988,12 +3006,7 @@ XBSYSAPI EXPORTNUM(190) xboxkrnl::NTSTATUS NTAPI xboxkrnl::NtCreateFile DbgPrintf("EmuKrnl (0x%X): NtCreateFile = 0x%.08X\n", GetCurrentThreadId(), *FileHandle); } - // restore original buffer - if(ReplaceIndex != -1) - { - szBuffer[ReplaceIndex] = ReplaceChar; - } - + // NOTE: We can map this to IoCreateFile once implemented (if ever necessary) // xboxkrnl::IoCreateFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, 0); @@ -4604,6 +4617,8 @@ XBSYSAPI EXPORTNUM(308) xboxkrnl::NTSTATUS NTAPI xboxkrnl::RtlUnicodeStringToAns return ret; } + + // ****************************************************************** // * 0x0142 - XboxHardwareInfo // ****************************************************************** diff --git a/src/CxbxKrnl/EmuNtDll.cpp b/src/CxbxKrnl/EmuNtDll.cpp index 9ff8792ee..7efcca090 100644 --- a/src/CxbxKrnl/EmuNtDll.cpp +++ b/src/CxbxKrnl/EmuNtDll.cpp @@ -87,6 +87,7 @@ NtDll::FPTR_NtCreateMutant NtDll::NtCreateMutant = NtDll::FPTR_NtReleaseMutant NtDll::NtReleaseMutant = (NtDll::FPTR_NtReleaseMutant)GetProcAddress(hNtDll, "NtReleaseMutant"); NtDll::FPTR_NtCreateSemaphore NtDll::NtCreateSemaphore = (NtDll::FPTR_NtCreateSemaphore)GetProcAddress(hNtDll, "NtCreateSemaphore"); NtDll::FPTR_NtReleaseSemaphore NtDll::NtReleaseSemaphore = (NtDll::FPTR_NtReleaseSemaphore)GetProcAddress(hNtDll, "NtReleaseSemaphore"); +NtDll::FPTR_NtCreateDirectoryObject NtDll::NtCreateDirectoryObject = (NtDll::FPTR_NtCreateDirectoryObject)GetProcAddress(hNtDll, "NtCreateDirectoryObject"); NtDll::FPTR_NtCreateFile NtDll::NtCreateFile = (NtDll::FPTR_NtCreateFile)GetProcAddress(hNtDll, "NtCreateFile"); NtDll::FPTR_NtReadFile NtDll::NtReadFile = (NtDll::FPTR_NtReadFile)GetProcAddress(hNtDll, "NtReadFile"); NtDll::FPTR_NtWriteFile NtDll::NtWriteFile = (NtDll::FPTR_NtWriteFile)GetProcAddress(hNtDll, "NtWriteFile"); diff --git a/src/CxbxKrnl/EmuNtDll.h b/src/CxbxKrnl/EmuNtDll.h index 659892440..0822aefcb 100644 --- a/src/CxbxKrnl/EmuNtDll.h +++ b/src/CxbxKrnl/EmuNtDll.h @@ -116,6 +116,12 @@ typedef unsigned __int64 ULONGLONG; #define NT_SUCCESS(Status) ((NTSTATUS) (Status) >= 0) +#define DIRECTORY_QUERY 1 +#define DIRECTORY_TRAVERSE 2 +#define DIRECTORY_CREATE_OBJECT 4 +#define DIRECTORY_CREATE_SUBDIRECTORY 8 + + // ****************************************************************** // * calling conventions // ****************************************************************** @@ -881,6 +887,17 @@ typedef NTSTATUS (NTAPI *FPTR_NtCreateFile) IN ULONG EaLength ); +// ****************************************************************** +// * NtCreateDirectoryObject +// ****************************************************************** +typedef NTSTATUS(NTAPI *FPTR_NtCreateDirectoryObject) +( + OUT PHANDLE DirectoryHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + + // ****************************************************************** // * NtClearEvent // ****************************************************************** @@ -1119,6 +1136,7 @@ extern FPTR_NtCreateMutant NtCreateMutant; extern FPTR_NtReleaseMutant NtReleaseMutant; extern FPTR_NtCreateSemaphore NtCreateSemaphore; extern FPTR_NtReleaseSemaphore NtReleaseSemaphore; +extern FPTR_NtCreateDirectoryObject NtCreateDirectoryObject; extern FPTR_NtCreateFile NtCreateFile; extern FPTR_NtReadFile NtReadFile; extern FPTR_NtWriteFile NtWriteFile; diff --git a/src/CxbxKrnl/HLEIntercept.cpp b/src/CxbxKrnl/HLEIntercept.cpp index fb9cafb9b..3d253e4c5 100644 --- a/src/CxbxKrnl/HLEIntercept.cpp +++ b/src/CxbxKrnl/HLEIntercept.cpp @@ -68,9 +68,9 @@ void EmuHLEIntercept(Xbe::LibraryVersion *pLibraryVersion, Xbe::Header *pXbeHead { DbgPrintf("HLE: Detected Microsoft XDK application...\n"); - uint32 dwLibraryVersions = pXbeHeader->dwLibraryVersions; - - + uint32 dwLibraryVersions = pXbeHeader->dwLibraryVersions; + + // Find D3D Library Version, this is used within the HLE functions to account for minor differences between XDK revisions for (uint32 v = 0;v < dwLibraryVersions;v++) { uint16 MajorVersion = pLibraryVersion[v].wMajorVersion; @@ -92,9 +92,14 @@ void EmuHLEIntercept(Xbe::LibraryVersion *pLibraryVersion, Xbe::Header *pXbeHead // Save D3D8 build version g_BuildVersion = BuildVersion; g_OrigBuildVersion = OrigBuildVersion; + break; } } + + // Load StoredPatternTrie + // Perform symbol matching + // Install wrappers } DbgPrintf("\n"); diff --git a/src/CxbxKrnl/KernelThunk.cpp b/src/CxbxKrnl/KernelThunk.cpp index cca181db8..9f40f666a 100644 --- a/src/CxbxKrnl/KernelThunk.cpp +++ b/src/CxbxKrnl/KernelThunk.cpp @@ -245,7 +245,7 @@ extern "C" CXBXKRNL_API uint32 CxbxKrnl_KernelThunkTable[367] = (uint32)PANIC(0x00B9), // 0x00B9 (185) NtCancelTimer (uint32)&xboxkrnl::NtClearEvent, // 0x00BA (186) (uint32)&xboxkrnl::NtClose, // 0x00BB (187) - (uint32)PANIC(0x00BC), // 0x00BC (188) NtCreateDirectoryObject + (uint32)&xboxkrnl::NtCreateDirectoryObject, // 0x00BC (188) NtCreateDirectoryObject (uint32)&xboxkrnl::NtCreateEvent, // 0x00BD (189) (uint32)&xboxkrnl::NtCreateFile, // 0x00BE (190) (uint32)PANIC(0x00BF), // 0x00BF (191) NtCreateIoCompletion