From a7cf67cd71fc5ee2f029a278d58f3a3b1941e3db Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Mon, 27 Dec 2021 02:02:34 +0100 Subject: [PATCH] Allow ObIniSystem to succeed --- CMakeLists.txt | 2 + .../DSOUND/DirectSound/XFileMediaObject.cpp | 2 +- src/core/hle/XAPI/Xapi.cpp | 2 +- src/core/kernel/common/ob.h | 19 +- src/core/kernel/common/types.h | 1 + src/core/kernel/exports/EmuKrnlNt.cpp | 151 ++++++----- src/core/kernel/exports/EmuKrnlOb.cpp | 251 +++++++++++++----- src/core/kernel/init/CxbxKrnl.cpp | 3 +- src/core/kernel/support/EmuFile.cpp | 6 +- src/core/kernel/support/EmuNtDll.h | 12 - src/core/kernel/support/NativeHandle.cpp | 64 +++++ src/core/kernel/support/NativeHandle.h | 34 +++ 12 files changed, 394 insertions(+), 153 deletions(-) create mode 100644 src/core/kernel/support/NativeHandle.cpp create mode 100644 src/core/kernel/support/NativeHandle.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c1d1c732..9cab41ffb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -190,6 +190,7 @@ file (GLOB CXBXR_HEADER_EMU "${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuFile.h" "${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuFS.h" "${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuNtDll.h" + "${CXBXR_ROOT_DIR}/src/core/kernel/support/NativeHandle.h" "${CXBXR_ROOT_DIR}/src/core/kernel/support/PatchRdtsc.hpp" "${CXBXR_ROOT_DIR}/src/devices/ADM1032Device.h" "${CXBXR_ROOT_DIR}/src/devices/EEPROMDevice.h" @@ -371,6 +372,7 @@ file (GLOB CXBXR_SOURCE_EMU "${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuFile.cpp" "${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuFS.cpp" "${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuNtDll.cpp" + "${CXBXR_ROOT_DIR}/src/core/kernel/support/NativeHandle.cpp" "${CXBXR_ROOT_DIR}/src/core/kernel/support/PatchRdtsc.cpp" "${CXBXR_ROOT_DIR}/src/devices/ADM1032Device.cpp" "${CXBXR_ROOT_DIR}/src/devices/EEPROMDevice.cpp" diff --git a/src/core/hle/DSOUND/DirectSound/XFileMediaObject.cpp b/src/core/hle/DSOUND/DirectSound/XFileMediaObject.cpp index 72e1766af..9862a9aeb 100644 --- a/src/core/hle/DSOUND/DirectSound/XFileMediaObject.cpp +++ b/src/core/hle/DSOUND/DirectSound/XFileMediaObject.cpp @@ -133,7 +133,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(XAudioDownloadEffectsImage) ANSI_STRING file_name; IO_STATUS_BLOCK io_status_block; RtlInitAnsiString(&file_name, pszImageName); - XB_InitializeObjectAttributes(&obj, &file_name, obj_case_insensitive, ObDosDevicesDirectory()); + X_InitializeObjectAttributes(&obj, &file_name, OBJ_CASE_INSENSITIVE, ObDosDevicesDirectory()); HANDLE hFile; ntstatus_xt NtStatusCreateFile = NtCreateFile( diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index 9721537d0..f9997f7eb 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -1629,7 +1629,7 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XReadMUMetaData) std::string mu_path_str(DrivePrefix + lett + ":"); ANSI_STRING mu_path; RtlInitAnsiString(&mu_path, mu_path_str.data()); - XB_InitializeObjectAttributes(&obj, &mu_path, obj_case_insensitive, ObDosDevicesDirectory()); + X_InitializeObjectAttributes(&obj, &mu_path, OBJ_CASE_INSENSITIVE, ObDosDevicesDirectory()); HANDLE handle; IO_STATUS_BLOCK io_status_block; diff --git a/src/core/kernel/common/ob.h b/src/core/kernel/common/ob.h index d6b60b526..5d39f6dc8 100644 --- a/src/core/kernel/common/ob.h +++ b/src/core/kernel/common/ob.h @@ -35,8 +35,6 @@ typedef struct _OBJECT_HEADER_NAME_INFO { OBJECT_STRING Name; } OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO; -inline constexpr dword_xt obj_case_insensitive = 0x40; - #define ObDosDevicesDirectory() ((HANDLE)-3) #define ObWin32NamedObjectsDirectory() ((HANDLE)-4) @@ -54,6 +52,15 @@ inline constexpr dword_xt obj_case_insensitive = 0x40; #define OB_FLAG_PERMANENT_OBJECT 0x02 #define OB_FLAG_ATTACHED_OBJECT 0x04 +#define OBJ_INHERIT 0x00000002L +#define OBJ_PERMANENT 0x00000010L +#define OBJ_EXCLUSIVE 0x00000020L +#define OBJ_CASE_INSENSITIVE 0x00000040L +#define OBJ_OPENIF 0x00000080L +#define OBJ_OPENLINK 0x00000100L +#define OBJ_KERNEL_HANDLE 0x00000200L +#define OBJ_VALID_ATTRIBUTES 0x000003F2L + #define OBJECT_TO_OBJECT_HEADER(Object) CONTAINING_RECORD(Object, OBJECT_HEADER, Body) #define OBJECT_TO_OBJECT_HEADER_NAME_INFO(Object) ((POBJECT_HEADER_NAME_INFO)OBJECT_TO_OBJECT_HEADER(Object) - 1) #define OBJECT_HEADER_NAME_INFO_TO_OBJECT_HEADER(ObjectHeaderNameInfo) ((POBJECT_HEADER)((POBJECT_HEADER_NAME_INFO)(ObjectHeaderNameInfo)+1)) @@ -75,7 +82,8 @@ ntstatus_xt ObpReferenceObjectByName( OUT PVOID *ReturnedObject ); -#define XB_InitializeObjectAttributes(p, n, a, r){\ +// Avoid a conflict with the InitializeObjectAttributes macro imported by the windows headers +#define X_InitializeObjectAttributes(p, n, a, r){\ (p)->RootDirectory = r; \ (p)->Attributes = a; \ (p)->ObjectName = n; \ @@ -86,7 +94,10 @@ boolean_xt ObpExtendObjectHandleTable(); void_xt ObDissectName(OBJECT_STRING Path, POBJECT_STRING FirstName, POBJECT_STRING RemainingName); PVOID ObpGetObjectHandleContents(HANDLE Handle); PVOID ObpGetObjectHandleReference(HANDLE Handle); -ulong_xt FASTCALL ObpComputeHashIndex(IN POBJECT_STRING ElementName); +ulong_xt FASTCALL ObpComputeHashIndex(POBJECT_STRING ElementName); +PVOID ObpDestroyObjectHandle(HANDLE Handle); +void_xt ObpDetachNamedObject(PVOID Object, KIRQL OldIrql); +ntstatus_xt ObpClose(HANDLE Handle); boolean_xt ObpLookupElementNameInDirectory( IN POBJECT_DIRECTORY Directory, diff --git a/src/core/kernel/common/types.h b/src/core/kernel/common/types.h index 717799939..b053d70b9 100644 --- a/src/core/kernel/common/types.h +++ b/src/core/kernel/common/types.h @@ -103,6 +103,7 @@ typedef void* LPSECURITY_ATTRIBUTES; #define X_STATUS_MEMORY_NOT_ALLOCATED 0xC00000A0L #define X_STATUS_NOT_COMMITTED 0xC000002DL #define X_STATUS_UNRECOGNIZED_VOLUME 0xC000014FL +#define X_STATUS_OBJECT_PATH_NOT_FOUND 0xC000003AL // ****************************************************************** // * Registry value types diff --git a/src/core/kernel/exports/EmuKrnlNt.cpp b/src/core/kernel/exports/EmuKrnlNt.cpp index 223a05585..5d2ca5319 100644 --- a/src/core/kernel/exports/EmuKrnlNt.cpp +++ b/src/core/kernel/exports/EmuKrnlNt.cpp @@ -44,6 +44,7 @@ namespace NtDll #include "core\kernel\support\Emu.h" // For EmuLog(LOG_LEVEL::WARNING, ) #include "core\kernel\support\EmuFile.h" // For EmuNtSymbolicLinkObject, NtStatusToString(), etc. #include "core\kernel\memory-manager\VMManager.h" // For g_VMManager +#include "core\kernel\support\NativeHandle.h" #include "CxbxDebugger.h" #pragma warning(disable:4005) // Ignore redefined status values @@ -142,32 +143,43 @@ XBSYSAPI EXPORTNUM(187) xbox::ntstatus_xt NTAPI xbox::NtClose NTSTATUS ret = X_STATUS_SUCCESS; - if (EmuHandle::IsEmuHandle(Handle)) - { + if (EmuHandle::IsEmuHandle(Handle)) { + // EmuHandles are only created for symbolic links with NtOpenSymbolicLinkObject, and ob handles are currently not created + // for those, so we can skip the call to ObpClose for now // delete 'special' handles auto iEmuHandle = (EmuHandle*)Handle; ret = iEmuHandle->NtClose(); - - LOG_UNIMPLEMENTED(); // TODO : Base this on the Ob* functions } - else - { + else { + // Handle everything else if (CxbxDebugger::CanReport()) { CxbxDebugger::ReportFileClosed(Handle); } + if (const auto &nativeHandle = GetNativeHandle(Handle)) { + // This was a handle created by Ob + if (ntstatus_xt status = ObpClose(Handle) != X_STATUS_SUCCESS) { + RETURN(status); + } + + RemoveXboxHandle(Handle); + Handle = *nativeHandle; + } + + // Now also close the native handle // Prevent exceptions when using invalid NTHandle DWORD flags = 0; if (GetHandleInformation(Handle, &flags) != 0) { + // This was a native handle, call NtDll::NtClose ret = NtDll::NtClose(Handle); // Delete duplicate threads created by our implementation of NtQueueApcThread() - if( GetHandleInformation( g_DuplicateHandles[Handle], &flags ) != 0 ) + if (GetHandleInformation(g_DuplicateHandles[Handle], &flags) != 0) { - EmuLog(LOG_LEVEL::DEBUG, "Closing duplicate handle..." ); + EmuLog(LOG_LEVEL::DEBUG, "Closing duplicate handle..."); - CloseHandle( g_DuplicateHandles[Handle] ); + CloseHandle(g_DuplicateHandles[Handle]); g_DuplicateHandles.erase(Handle); } } @@ -190,29 +202,19 @@ XBSYSAPI EXPORTNUM(188) xbox::ntstatus_xt NTAPI xbox::NtCreateDirectoryObject LOG_FUNC_ARG(ObjectAttributes) LOG_FUNC_END; - NativeObjectAttributes nativeObjectAttributes; - NTSTATUS ret = CxbxObjectAttributesToNT( - ObjectAttributes, - nativeObjectAttributes, - "NtCreateDirectoryObject"); + POBJECT_DIRECTORY directoryObject; + ntstatus_xt status = ObCreateObject(&ObDirectoryObjectType, ObjectAttributes, sizeof(OBJECT_DIRECTORY), reinterpret_cast(&directoryObject)); - if (ret == X_STATUS_SUCCESS) - { - // TODO : Is this the correct ACCESS_MASK? : - const ACCESS_MASK DesiredAccess = DIRECTORY_CREATE_OBJECT; + if (X_NT_SUCCESS(status)) { + std::memset(directoryObject, 0, sizeof(OBJECT_DIRECTORY)); + status = ObInsertObject(directoryObject, ObjectAttributes, 0, DirectoryHandle); - ret = NtDll::NtCreateDirectoryObject( - /*OUT*/DirectoryHandle, - DesiredAccess, - nativeObjectAttributes.NtObjAttrPtr); + if (X_NT_SUCCESS(status)) { + RegisterXboxHandle(*DirectoryHandle, NULL); // we don't need to create a native handle for a directory object + } } - if (FAILED(ret)) - EmuLog(LOG_LEVEL::WARNING, "NtCreateDirectoryObject Failed!"); - else - EmuLog(LOG_LEVEL::DEBUG, "NtCreateDirectoryObject DirectoryHandle = 0x%.8X", *DirectoryHandle); - - RETURN(ret); + RETURN(status); } // ****************************************************************** @@ -707,50 +709,71 @@ XBSYSAPI EXPORTNUM(197) xbox::ntstatus_xt NTAPI xbox::NtDuplicateObject LOG_FUNC_ARG(Options) LOG_FUNC_END; - NTSTATUS result = X_STATUS_SUCCESS; - -#ifdef CXBX_KERNEL_REWORK_ENABLED - PVOID Object; - - result = ObReferenceObjectByHandle(SourceHandle, /*ObjectType=*/nullptr, &Object); - if (X_NT_SUCCESS(result)) { - if (ObpIsFlagSet(Options, DUPLICATE_CLOSE_SOURCE)) - NtClose(SourceHandle); - - result = ObOpenObjectByPointer(Object, OBJECT_TO_OBJECT_HEADER(Object)->Type, /*OUT*/TargetHandle); - ObfDereferenceObject(Object); - } - else - *TargetHandle = NULL; -#else + ntstatus_xt status; if (EmuHandle::IsEmuHandle(SourceHandle)) { auto iEmuHandle = (EmuHandle*)SourceHandle; - result = iEmuHandle->NtDuplicateObject(TargetHandle, Options); + status = iEmuHandle->NtDuplicateObject(TargetHandle, Options); } - else - { + else { // On the xbox, the duplicated handle always has the same access rigths of the source handle const ACCESS_MASK DesiredAccess = 0; const ULONG Attributes = 0; - Options |= (DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS); + dword_xt nativeOptions = (Options | DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS); - // redirect to Win2k/XP - result = NtDll::NtDuplicateObject( - /*SourceProcessHandle=*/g_CurrentProcessHandle, - SourceHandle, - /*TargetProcessHandle=*/g_CurrentProcessHandle, - TargetHandle, - DesiredAccess, - Attributes, - Options); + if (const auto &nativeHandle = GetNativeHandle(SourceHandle)) { + // This was a handle created by Ob + PVOID Object; + status = ObReferenceObjectByHandle(SourceHandle, /*ObjectType=*/nullptr, &Object); + if (X_NT_SUCCESS(status)) { + if (ObpIsFlagSet(Options, DUPLICATE_CLOSE_SOURCE)) { + NtClose(SourceHandle); + } + + status = ObOpenObjectByPointer(Object, OBJECT_TO_OBJECT_HEADER(Object)->Type, /*OUT*/TargetHandle); + if (!X_NT_SUCCESS(status)) { + *TargetHandle = NULL; + RETURN(status); + } + + ObfDereferenceObject(Object); + + // If nativeHandle is NULL, then skip NtDll::NtDuplicateObject. This happens when SourceHandle is an xbox handle with a corresponding + // NULL native handle (e.g. directory objects hit this case) + if (*nativeHandle != NULL) { + ::HANDLE dupHandle; + status = NtDll::NtDuplicateObject( + /*SourceProcessHandle=*/g_CurrentProcessHandle, + *nativeHandle, + /*TargetProcessHandle=*/g_CurrentProcessHandle, + &dupHandle, + DesiredAccess, + Attributes, + nativeOptions); + RegisterXboxHandle(*TargetHandle, dupHandle); + } + else { + RegisterXboxHandle(*TargetHandle, NULL); + } + } + } + else { + status = NtDll::NtDuplicateObject( + /*SourceProcessHandle=*/g_CurrentProcessHandle, + SourceHandle, + /*TargetProcessHandle=*/g_CurrentProcessHandle, + TargetHandle, + DesiredAccess, + Attributes, + nativeOptions); + } + + if (!X_NT_SUCCESS(status)) { + CxbxrKrnlAbort("NtDll::NtDuplicateObject failed to duplicate the handle 0x%.8X!", SourceHandle); + } } - if (result != X_STATUS_SUCCESS) - EmuLog(LOG_LEVEL::WARNING, "Object was not duplicated!"); -#endif - - RETURN(result); + RETURN(status); } // ****************************************************************** @@ -894,7 +917,9 @@ XBSYSAPI EXPORTNUM(201) xbox::ntstatus_xt NTAPI xbox::NtOpenDirectoryObject { LOG_FORWARD("ObOpenObjectByName"); - return ObOpenObjectByName(ObjectAttributes, &ObDirectoryObjectType, NULL, DirectoryHandle); + xbox::ntstatus_xt status = ObOpenObjectByName(ObjectAttributes, &ObDirectoryObjectType, NULL, DirectoryHandle); + RegisterXboxHandle(*DirectoryHandle, NULL); // we don't need to create a native handle for a directory object + return status; } // ****************************************************************** diff --git a/src/core/kernel/exports/EmuKrnlOb.cpp b/src/core/kernel/exports/EmuKrnlOb.cpp index 0912173ad..473c4f373 100644 --- a/src/core/kernel/exports/EmuKrnlOb.cpp +++ b/src/core/kernel/exports/EmuKrnlOb.cpp @@ -31,7 +31,6 @@ // TODO: What needs proper implement from Ob functions' side: (use CXBX_KERNEL_REWORK_ENABLED defined to evaluate what needs fixing) // ObpDeleteSymbolicLink - internal function which would need a call to ObDereferenceObject with LinkTargetObject pass down. // Plus it require proper IoCreateSymbolicLink implement as well, not emulated implement method. -// ObpDefaultObject - Find out how to initialize this. Then connect the dots from TODO message. // OBJECT_DIRECTORY interface (root, dos, device, and named object, you can find global varables about 30 lines below) // etc (add more above this line) @@ -42,6 +41,7 @@ #include "core\kernel\init\CxbxKrnl.h" // For CxbxrKrnlAbort #include "EmuKrnl.h" // For OBJECT_TO_OBJECT_HEADER() #include "core\kernel\support\EmuFile.h" // For EmuNtSymbolicLinkObject, NtStatusToString(), etc. +#include "core\kernel\support\NativeHandle.h" #include #pragma warning(disable:4005) // Ignore redefined status values @@ -64,6 +64,7 @@ xbox::POBJECT_DIRECTORY ObpDosDevicesDirectoryObject; xbox::POBJECT_DIRECTORY ObpWin32NamedObjectsDirectoryObject; xbox::POBJECT_DIRECTORY ObpRootDirectoryObject; xbox::POBJECT_DIRECTORY ObpIoDevicesDirectoryObject; +xbox::KEVENT ObpDefaultObject; XBSYSAPI EXPORTNUM(245) xbox::OBJECT_HANDLE_TABLE xbox::ObpObjectHandleTable = { @@ -71,6 +72,9 @@ XBSYSAPI EXPORTNUM(245) xbox::OBJECT_HANDLE_TABLE xbox::ObpObjectHandleTable = { xbox::PVOID ObpDosDevicesDriveLetterMap['Z' - 'A' + 1]; +// This mutex is necessary to guard access to the global ob variables above +std::recursive_mutex g_ObMtx; + xbox::boolean_xt xbox::ObpCreatePermanentDirectoryObject( IN POBJECT_STRING DirectoryName OPTIONAL, OUT POBJECT_DIRECTORY *DirectoryObject @@ -82,23 +86,23 @@ xbox::boolean_xt xbox::ObpCreatePermanentDirectoryObject( LOG_FUNC_END; OBJECT_ATTRIBUTES ObjectAttributes; - XB_InitializeObjectAttributes(&ObjectAttributes, DirectoryName, OBJ_PERMANENT, NULL); + X_InitializeObjectAttributes(&ObjectAttributes, DirectoryName, OBJ_PERMANENT, NULL); HANDLE Handle; - NTSTATUS status = NtCreateDirectoryObject(&Handle, &ObjectAttributes); + NTSTATUS result = NtCreateDirectoryObject(&Handle, &ObjectAttributes); - if (!X_NT_SUCCESS(status)) { + if (!X_NT_SUCCESS(result)) { RETURN(FALSE); } - status = ObReferenceObjectByHandle(Handle, &ObDirectoryObjectType, (PVOID *)DirectoryObject); + result = ObReferenceObjectByHandle(Handle, &ObDirectoryObjectType, (PVOID *)DirectoryObject); - if (!X_NT_SUCCESS(status)) { + if (!X_NT_SUCCESS(result)) { RETURN(FALSE); } NtClose(Handle); - + RETURN(TRUE); } @@ -111,10 +115,12 @@ xbox::ntstatus_xt xbox::ObpReferenceObjectByName( OUT PVOID *ReturnedObject ) { - NTSTATUS status; + NTSTATUS result; *ReturnedObject = NULL; KIRQL OldIrql = KeRaiseIrqlToDpcLevel(); + // Raising the irql to dpc level doesn't prevent thread switching, so acquire a lock + std::unique_lock lck(g_ObMtx); OBJECT_STRING RemainingName; if (ObjectName != NULL) { @@ -135,14 +141,14 @@ xbox::ntstatus_xt xbox::ObpReferenceObjectByName( FoundObject = (POBJECT_DIRECTORY)ObpGetObjectHandleContents(RootDirectoryHandle); if (FoundObject == NULL) { - status = X_STATUS_INVALID_HANDLE; + result = X_STATUS_INVALID_HANDLE; goto CleanupAndExit; } } if ((RemainingName.Length != 0) && (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) { - status = X_STATUS_OBJECT_NAME_INVALID; + result = X_STATUS_OBJECT_NAME_INVALID; goto CleanupAndExit; } @@ -153,7 +159,7 @@ xbox::ntstatus_xt xbox::ObpReferenceObjectByName( if ((RemainingName.Length == 0) || (RemainingName.Buffer[0] != OBJ_NAME_PATH_SEPARATOR)) { - status = X_STATUS_OBJECT_NAME_INVALID; + result = X_STATUS_OBJECT_NAME_INVALID; goto CleanupAndExit; } @@ -171,7 +177,7 @@ xbox::ntstatus_xt xbox::ObpReferenceObjectByName( if (RemainingName.Length != 0) { if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) { - status = X_STATUS_OBJECT_NAME_INVALID; + result = X_STATUS_OBJECT_NAME_INVALID; goto CleanupAndExit; } } else { @@ -182,7 +188,7 @@ xbox::ntstatus_xt xbox::ObpReferenceObjectByName( if (!ObpLookupElementNameInDirectory(Directory, &ElementName, ResolveSymbolicLink, &FoundObject)) { - status = (RemainingName.Length != 0) ? STATUS_OBJECT_PATH_NOT_FOUND : X_STATUS_OBJECT_NAME_NOT_FOUND; + result = (RemainingName.Length != 0) ? STATUS_OBJECT_PATH_NOT_FOUND : X_STATUS_OBJECT_NAME_NOT_FOUND; goto CleanupAndExit; } @@ -195,19 +201,19 @@ OpenRootDirectory: } if ((ObjectType != NULL) && (ObjectType != ObjectHeader->Type)) { - status = STATUS_OBJECT_TYPE_MISMATCH; + result = STATUS_OBJECT_TYPE_MISMATCH; goto CleanupAndExit; } ObjectHeader->PointerCount++; *ReturnedObject = FoundObject; - status = X_STATUS_SUCCESS; + result = X_STATUS_SUCCESS; goto CleanupAndExit; } if (ObjectHeader->Type != &ObDirectoryObjectType) { if (ObjectHeader->Type->ParseProcedure == NULL) { - status = STATUS_OBJECT_PATH_NOT_FOUND; + result = STATUS_OBJECT_PATH_NOT_FOUND; goto CleanupAndExit; } @@ -222,25 +228,25 @@ InvokeParseProcedure: } PVOID ParsedObject = NULL; - status = ObjectHeader->Type->ParseProcedure(FoundObject, ObjectType, Attributes, ObjectName, &RemainingName, ParseContext, &ParsedObject); + result = ObjectHeader->Type->ParseProcedure(FoundObject, ObjectType, Attributes, ObjectName, &RemainingName, ParseContext, &ParsedObject); ObfDereferenceObject(FoundObject); - if (X_NT_SUCCESS(status)) { + if (X_NT_SUCCESS(result)) { if ((ObjectType == NULL) || (ObjectType == OBJECT_TO_OBJECT_HEADER(ParsedObject)->Type)) { *ReturnedObject = ParsedObject; - status = X_STATUS_SUCCESS; + result = X_STATUS_SUCCESS; } else { ObfDereferenceObject(ParsedObject); - status = STATUS_OBJECT_TYPE_MISMATCH; + result = STATUS_OBJECT_TYPE_MISMATCH; } } - return status; + return result; } } CleanupAndExit: KfLowerIrql(OldIrql); - return status; + return result; } xbox::boolean_xt xbox::ObInitSystem() @@ -250,7 +256,11 @@ xbox::boolean_xt xbox::ObInitSystem() ObpObjectHandleTable.NextHandleNeedingPool = 0; ObpObjectHandleTable.RootTable = NULL; - RtlZeroMemory(ObpDosDevicesDriveLetterMap, sizeof(ObpDosDevicesDriveLetterMap)); + std::memset(ObpDosDevicesDriveLetterMap, 0, sizeof(ObpDosDevicesDriveLetterMap)); + + ObpDefaultObject.Header.Absolute = FALSE; + ObpDefaultObject.Header.Inserted = FALSE; + KeInitializeEvent(&ObpDefaultObject, SynchronizationEvent, TRUE); if (!ObpCreatePermanentDirectoryObject(NULL, &ObpRootDirectoryObject)) { return FALSE; @@ -389,17 +399,20 @@ xbox::void_xt xbox::ObDissectName(OBJECT_STRING Path, POBJECT_STRING FirstName, return; } -static inline xbox::HANDLE ObpGetHandleByObjectThenDereferenceInline(const xbox::PVOID Object, xbox::ntstatus_xt& result) { - xbox::HANDLE newHandle = nullptr; +static inline xbox::HANDLE ObpGetHandleByObjectThenDereferenceInline(const xbox::PVOID Object, xbox::ntstatus_xt& result) +{ + xbox::HANDLE newHandle = NULL; if (X_NT_SUCCESS(result)) { xbox::KIRQL oldIrql = xbox::KeRaiseIrqlToDpcLevel(); + // Raising the irql to dpc level doesn't prevent thread switching, so acquire a lock + std::unique_lock lck(g_ObMtx); newHandle = xbox::ObpCreateObjectHandle(Object); xbox::KfLowerIrql(oldIrql); - if (newHandle == nullptr) { + if (newHandle == NULL) { xbox::ObfDereferenceObject(Object); result = X_STATUS_INSUFFICIENT_RESOURCES; } @@ -498,7 +511,7 @@ XBSYSAPI EXPORTNUM(240) xbox::OBJECT_TYPE xbox::ObDirectoryObjectType = NULL, NULL, NULL, - NULL, // TODO : &xbox::ObpDefaultObject, + &ObpDefaultObject, 'eriD' // = first four characters of "Directory" in reverse }; @@ -552,6 +565,8 @@ xbox::PVOID xbox::ObpGetObjectHandleReference(HANDLE Handle) PVOID *HandleContents; Handle = ObpMaskOffApplicationBits(Handle); KIRQL OldIrql = KeRaiseIrqlToDpcLevel(); + // Raising the irql to dpc level doesn't prevent thread switching, so acquire a lock + std::unique_lock lck(g_ObMtx); if (HandleToUlong(Handle) < HandleToUlong(ObpObjectHandleTable.NextHandleNeedingPool)) { HandleContents = ObpGetHandleContentsPointer(Handle); @@ -613,6 +628,116 @@ xbox::boolean_xt xbox::ObpLookupElementNameInDirectory( return FALSE; } +xbox::PVOID xbox::ObpDestroyObjectHandle( + IN HANDLE Handle +) +{ + Handle = ObpMaskOffApplicationBits(Handle); + + if (HandleToUlong(Handle) < HandleToUlong(ObpObjectHandleTable.NextHandleNeedingPool)) { + PVOID *HandleContents = ObpGetHandleContentsPointer(Handle); + PVOID Object = *HandleContents; + + if (Object != NULL && !ObpIsFreeHandleLink(Object)) { + *HandleContents = (PVOID)ObpObjectHandleTable.FirstFreeTableEntry; + ObpObjectHandleTable.FirstFreeTableEntry = ObpEncodeFreeHandleLink(Handle); + ObpObjectHandleTable.HandleCount--; + + return Object; + } + } + + return NULL; +} + +xbox::void_xt xbox::ObpDetachNamedObject( + IN PVOID Object, + IN KIRQL OldIrql +) +{ + POBJECT_HEADER_NAME_INFO ObjectHeaderNameInfo = OBJECT_TO_OBJECT_HEADER_NAME_INFO(Object); + POBJECT_DIRECTORY Directory = ObjectHeaderNameInfo->Directory; + + if ((Directory == ObpDosDevicesDirectoryObject) && + (ObjectHeaderNameInfo->Name.Length == sizeof(char_xt) * 2) && + (ObjectHeaderNameInfo->Name.Buffer[1] == (char_xt)':')) { + + char_xt DriveLetter = ObjectHeaderNameInfo->Name.Buffer[0]; + if (DriveLetter >= 'a' && DriveLetter <= 'z') { + ObpDosDevicesDriveLetterMap[DriveLetter - 'a'] = NULL; + } + else if (DriveLetter >= 'A' && DriveLetter <= 'Z') { + ObpDosDevicesDriveLetterMap[DriveLetter - 'A'] = NULL; + } + } + + ulong_xt HashIndex = ObpComputeHashIndex(&ObjectHeaderNameInfo->Name); + POBJECT_HEADER_NAME_INFO LastObjectHeaderNameInfo = NULL; + POBJECT_HEADER_NAME_INFO CurrentObjectHeaderNameInfo = Directory->HashBuckets[HashIndex]; + + while (CurrentObjectHeaderNameInfo != ObjectHeaderNameInfo) { + LastObjectHeaderNameInfo = CurrentObjectHeaderNameInfo; + CurrentObjectHeaderNameInfo = CurrentObjectHeaderNameInfo->ChainLink; + } + + if (LastObjectHeaderNameInfo == NULL) { + Directory->HashBuckets[HashIndex] = CurrentObjectHeaderNameInfo->ChainLink; + } + else { + LastObjectHeaderNameInfo->ChainLink = CurrentObjectHeaderNameInfo->ChainLink; + } + + ObjectHeaderNameInfo->ChainLink = NULL; + ObjectHeaderNameInfo->Directory = NULL; + + KfLowerIrql(OldIrql); + g_ObMtx.unlock(); + + ObfDereferenceObject(Directory); + ObfDereferenceObject(Object); +} + +xbox::ntstatus_xt xbox::ObpClose( + IN HANDLE Handle +) +{ + KIRQL OldIrql = KeRaiseIrqlToDpcLevel(); + // Raising the irql to dpc level doesn't prevent thread switching, so acquire a lock + std::unique_lock lck(g_ObMtx); + + PVOID Object = ObpDestroyObjectHandle(Handle); + if (Object != NULL) { + POBJECT_HEADER ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); + ulong_xt HandleCount = ObjectHeader->HandleCount; + ObjectHeader->HandleCount--; + + if (ObjectHeader->Type->CloseProcedure != NULL) { + KfLowerIrql(OldIrql); + lck.unlock(); + ObjectHeader->Type->CloseProcedure(Object, HandleCount); + OldIrql = KeRaiseIrqlToDpcLevel(); + lck.lock(); + } + + if ((ObjectHeader->HandleCount == 0) && + ObpIsFlagSet(ObjectHeader->Flags, OB_FLAG_ATTACHED_OBJECT) && + ObpIsFlagClear(ObjectHeader->Flags, OB_FLAG_PERMANENT_OBJECT)) { + ObpDetachNamedObject(Object, OldIrql); + } + else { + KfLowerIrql(OldIrql); + lck.unlock(); + } + + ObfDereferenceObject(Object); + return X_STATUS_SUCCESS; + } + else { + KfLowerIrql(OldIrql); + return X_STATUS_INVALID_HANDLE; + } +} + // ****************************************************************** // * 0x00F1 - ObInsertObject() // ****************************************************************** @@ -631,10 +756,12 @@ XBSYSAPI EXPORTNUM(241) xbox::ntstatus_xt NTAPI xbox::ObInsertObject LOG_FUNC_ARG_OUT(ReturnedHandle) LOG_FUNC_END; - NTSTATUS status; + NTSTATUS result; POBJECT_DIRECTORY Directory; KIRQL OldIrql = KeRaiseIrqlToDpcLevel(); + // Raising the irql to dpc level doesn't prevent thread switching, so acquire a lock + std::unique_lock lck(g_ObMtx); HANDLE Handle = NULL; PVOID InsertObject = Object; @@ -644,7 +771,7 @@ XBSYSAPI EXPORTNUM(241) xbox::ntstatus_xt NTAPI xbox::ObInsertObject if (RootDirectoryHandle != NULL) { if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) { - status = STATUS_OBJECT_NAME_INVALID; + result = STATUS_OBJECT_NAME_INVALID; goto CleanupAndExit; } @@ -656,18 +783,18 @@ XBSYSAPI EXPORTNUM(241) xbox::ntstatus_xt NTAPI xbox::ObInsertObject Directory = (POBJECT_DIRECTORY)ObpGetObjectHandleContents(RootDirectoryHandle); if (Directory == NULL) { - status = STATUS_INVALID_HANDLE; + result = STATUS_INVALID_HANDLE; goto CleanupAndExit; } if (OBJECT_TO_OBJECT_HEADER(Directory)->Type != &ObDirectoryObjectType) { - status = STATUS_OBJECT_TYPE_MISMATCH; + result = STATUS_OBJECT_TYPE_MISMATCH; goto CleanupAndExit; } } } else { if (RemainingName.Buffer[0] != OBJ_NAME_PATH_SEPARATOR) { - status = STATUS_OBJECT_NAME_INVALID; + result = STATUS_OBJECT_NAME_INVALID; goto CleanupAndExit; } @@ -686,25 +813,25 @@ XBSYSAPI EXPORTNUM(241) xbox::ntstatus_xt NTAPI xbox::ObInsertObject Directory = NULL; break; } else { - status = STATUS_OBJECT_TYPE_MISMATCH; + result = STATUS_OBJECT_TYPE_MISMATCH; goto CleanupAndExit; } } else { - status = X_STATUS_OBJECT_NAME_COLLISION; + result = X_STATUS_OBJECT_NAME_COLLISION; goto CleanupAndExit; } } if (OBJECT_TO_OBJECT_HEADER(FoundObject)->Type != &ObDirectoryObjectType) { - status = STATUS_OBJECT_PATH_NOT_FOUND; + result = STATUS_OBJECT_PATH_NOT_FOUND; goto CleanupAndExit; } Directory = (POBJECT_DIRECTORY)FoundObject; } else { if (RemainingName.Length != 0) { - status = STATUS_OBJECT_PATH_NOT_FOUND; + result = STATUS_OBJECT_PATH_NOT_FOUND; goto CleanupAndExit; } @@ -718,7 +845,7 @@ XBSYSAPI EXPORTNUM(241) xbox::ntstatus_xt NTAPI xbox::ObInsertObject Handle = ObpCreateObjectHandle(InsertObject); if (Handle == NULL) { - status = X_STATUS_INSUFFICIENT_RESOURCES; + result = X_STATUS_INSUFFICIENT_RESOURCES; goto CleanupAndExit; } @@ -758,14 +885,14 @@ XBSYSAPI EXPORTNUM(241) xbox::ntstatus_xt NTAPI xbox::ObInsertObject ObjectHeader->Flags |= OB_FLAG_PERMANENT_OBJECT; } - status = (Object == InsertObject) ? X_STATUS_SUCCESS : STATUS_OBJECT_NAME_EXISTS; + result = (Object == InsertObject) ? X_STATUS_SUCCESS : STATUS_OBJECT_NAME_EXISTS; CleanupAndExit: KfLowerIrql(OldIrql); ObfDereferenceObject(Object); *ReturnedHandle = Handle; - RETURN(status); + RETURN(result); } // ****************************************************************** @@ -800,21 +927,20 @@ XBSYSAPI EXPORTNUM(243) xbox::ntstatus_xt NTAPI xbox::ObOpenObjectByName LOG_FUNC_ARG_OUT(Handle) LOG_FUNC_END; -#ifdef CXBX_KERNEL_REWORK_ENABLED - PVOID Object; - ntstatus_xt result = ObpReferenceObjectByName(ObjectAttributes->RootDirectory, ObjectAttributes->ObjectName, - ObjectAttributes->Attributes, ObjectType, ParseContext, &Object); + ntstatus_xt result = X_STATUS_OBJECT_PATH_NOT_FOUND; - *Handle = ObpGetHandleByObjectThenDereferenceInline(Object, result); -#else - - ntstatus_xt result = STATUS_OBJECT_PATH_NOT_FOUND; - - // Use this place for any interface implementation since - // it is origin of creating new handle. In other case, "ObpCreateObjectHandle" handle it directly. - // But global variables with POBJECT_DIRECTORY are not initialized properly. - // Along with IoCreateSymbolicLink for ObSymbolicLinkObjectType linkage in order to work. - if (ObjectType == &ObSymbolicLinkObjectType) { + if (const auto &nativeHandle = GetNativeHandle(Handle)) { + // This was a handle created by Ob + PVOID Object; + result = ObpReferenceObjectByName(ObjectAttributes->RootDirectory, ObjectAttributes->ObjectName, + ObjectAttributes->Attributes, ObjectType, ParseContext, &Object); + *Handle = ObpGetHandleByObjectThenDereferenceInline(Object, result); + } + else if (ObjectType == &ObSymbolicLinkObjectType) { + // Use this place for any interface implementation since + // it is origin of creating new handle. In other case, "ObpCreateObjectHandle" handle it directly. + // But global variables with POBJECT_DIRECTORY are not initialized properly. + // Along with IoCreateSymbolicLink for ObSymbolicLinkObjectType linkage in order to work. EmuNtSymbolicLinkObject* symbolicLinkObject = FindNtSymbolicLinkObjectByName(PSTRING_to_string(ObjectAttributes->ObjectName)); @@ -837,7 +963,6 @@ XBSYSAPI EXPORTNUM(243) xbox::ntstatus_xt NTAPI xbox::ObOpenObjectByName assert(false); result = X_STATUS_SUCCESS; } -#endif RETURN(result); } @@ -858,17 +983,9 @@ XBSYSAPI EXPORTNUM(244) xbox::ntstatus_xt NTAPI xbox::ObOpenObjectByPointer LOG_FUNC_ARG_OUT(Handle) LOG_FUNC_END; -#ifdef CXBX_KERNEL_REWORK_ENABLED ntstatus_xt result = ObReferenceObjectByPointer(Object, ObjectType); - *Handle = ObpGetHandleByObjectThenDereferenceInline(Object, result); RETURN(result); -#else - LOG_UNIMPLEMENTED(); - assert(false); - - RETURN(X_STATUS_SUCCESS); -#endif } // ****************************************************************** @@ -893,7 +1010,7 @@ XBSYSAPI EXPORTNUM(246) xbox::ntstatus_xt NTAPI xbox::ObReferenceObjectByHandle LOG_FUNC_ARG_OUT(ReturnedObject) LOG_FUNC_END; - NTSTATUS status; + NTSTATUS result; PVOID Object; POBJECT_HEADER ObjectHeader; @@ -905,7 +1022,7 @@ XBSYSAPI EXPORTNUM(246) xbox::ntstatus_xt NTAPI xbox::ObReferenceObjectByHandle *ReturnedObject = Object; return X_STATUS_SUCCESS; } else { - status = STATUS_OBJECT_TYPE_MISMATCH; + result = STATUS_OBJECT_TYPE_MISMATCH; } } else { Object = ObpGetObjectHandleReference(Handle); @@ -918,7 +1035,7 @@ XBSYSAPI EXPORTNUM(246) xbox::ntstatus_xt NTAPI xbox::ObReferenceObjectByHandle return X_STATUS_SUCCESS; } else { ObfDereferenceObject(Object); - status = STATUS_OBJECT_TYPE_MISMATCH; + result = STATUS_OBJECT_TYPE_MISMATCH; } } else { // HACK: Since we forward to NtDll::NtCreateEvent, this *might* be a Windows handle instead of our own @@ -931,13 +1048,13 @@ XBSYSAPI EXPORTNUM(246) xbox::ntstatus_xt NTAPI xbox::ObReferenceObjectByHandle return X_STATUS_SUCCESS; } - status = STATUS_INVALID_HANDLE; + result = STATUS_INVALID_HANDLE; } } *ReturnedObject = NULL; - RETURN(status); + RETURN(result); } // ****************************************************************** diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index ca7ef6e65..b3efd3601 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -1491,8 +1491,7 @@ static void CxbxrKrnlInitHacks() InitXboxThread(); g_AffinityPolicy->SetAffinityXbox(); if (!xbox::ObInitSystem()) { - // TODO: Replace EmuLogEx to CxbxrKrnlAbortEx when ObInitSystem's calls are properly implement. - EmuLogEx(LOG_PREFIX_INIT, LOG_LEVEL::WARNING, "Unable to intialize xbox::ObInitSystem."); + CxbxrKrnlAbortEx(LOG_PREFIX_INIT, "Unable to intialize ObInitSystem."); } xbox::KiInitSystem(); diff --git a/src/core/kernel/support/EmuFile.cpp b/src/core/kernel/support/EmuFile.cpp index b7b057e47..fd34e81af 100644 --- a/src/core/kernel/support/EmuFile.cpp +++ b/src/core/kernel/support/EmuFile.cpp @@ -698,7 +698,7 @@ NTSTATUS CxbxConvertFilePath( // Convert the relative path to unicode RelativeHostPath = string_to_wstring(RelativePath); - return X_STATUS_SUCCESS; + return STATUS_SUCCESS; } NTSTATUS CxbxObjectAttributesToNT( @@ -711,7 +711,7 @@ NTSTATUS CxbxObjectAttributesToNT( { // When the pointer is nil, make sure we pass nil to Windows too : nativeObjectAttributes.NtObjAttrPtr = nullptr; - return X_STATUS_SUCCESS; + return STATUS_SUCCESS; } // Pick up the ObjectName, and let's see what to make of it : @@ -743,7 +743,7 @@ NTSTATUS CxbxObjectAttributesToNT( // ObjectAttributes are given, so make sure the pointer we're going to pass to Windows is assigned : nativeObjectAttributes.NtObjAttrPtr = &nativeObjectAttributes.NtObjAttr; - return X_STATUS_SUCCESS; + return STATUS_SUCCESS; } int CxbxDeviceIndexByDevicePath(const char *XboxDevicePath) diff --git a/src/core/kernel/support/EmuNtDll.h b/src/core/kernel/support/EmuNtDll.h index 6b6ec3b29..a66840d42 100644 --- a/src/core/kernel/support/EmuNtDll.h +++ b/src/core/kernel/support/EmuNtDll.h @@ -293,18 +293,6 @@ typedef struct _RTL_CRITICAL_SECTION } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION; -// ****************************************************************** -// * Valid values for the Attributes field -// ****************************************************************** -#define OBJ_INHERIT 0x00000002L -#define OBJ_PERMANENT 0x00000010L -#define OBJ_EXCLUSIVE 0x00000020L -#define OBJ_CASE_INSENSITIVE 0x00000040L -#define OBJ_OPENIF 0x00000080L -#define OBJ_OPENLINK 0x00000100L -#define OBJ_KERNEL_HANDLE 0x00000200L -#define OBJ_VALID_ATTRIBUTES 0x000003F2L - // ****************************************************************** // * UNICODE_STRING // ****************************************************************** diff --git a/src/core/kernel/support/NativeHandle.cpp b/src/core/kernel/support/NativeHandle.cpp new file mode 100644 index 000000000..43b744c6f --- /dev/null +++ b/src/core/kernel/support/NativeHandle.cpp @@ -0,0 +1,64 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * 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) 2021 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +#include +#include +#include +#include "Windows.h" +#include "assert.h" +#include "NativeHandle.h" + + +std::unordered_map g_RegisteredHandles; +std::shared_mutex g_MapMtx; + +void RegisterXboxHandle(xbox::HANDLE xhandle, HANDLE nhandle) +{ + std::unique_lock lck(g_MapMtx); + [[maybe_unused]] const auto &ret = g_RegisteredHandles.emplace(xhandle, nhandle); + // Even when duplicating xbox handles with NtDuplicateObject, the duplicate will still be different then the source handle + assert(ret.second == true); +} + +void RemoveXboxHandle(xbox::HANDLE xhandle) +{ + std::unique_lock lck(g_MapMtx); + [[maybe_unused]] auto ret = g_RegisteredHandles.erase(xhandle); + assert(ret == 1); +} + +std::optional GetNativeHandle(xbox::HANDLE xhandle) +{ + std::shared_lock lck(g_MapMtx); + auto &it = g_RegisteredHandles.find(xhandle); + if (it == g_RegisteredHandles.end()) { + return std::nullopt; + } + else { + return it->second; + } +} diff --git a/src/core/kernel/support/NativeHandle.h b/src/core/kernel/support/NativeHandle.h new file mode 100644 index 000000000..3ba46f9b8 --- /dev/null +++ b/src/core/kernel/support/NativeHandle.h @@ -0,0 +1,34 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * 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) 2021 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +#pragma once + +#include + +void RegisterXboxHandle(xbox::HANDLE xhandle, HANDLE nhandle); +void RemoveXboxHandle(xbox::HANDLE xhandle); +std::optional GetNativeHandle(xbox::HANDLE xhandle);