Implement core Object Manager subsystem
Some checks failed
Builds / ExectOS (i686, debug) (push) Failing after 27s
Builds / ExectOS (amd64, release) (push) Failing after 39s
Builds / ExectOS (i686, release) (push) Failing after 36s
Builds / ExectOS (amd64, debug) (push) Failing after 28s

This commit is contained in:
2026-07-09 08:11:44 +02:00
parent 96502d5db6
commit 195c749396
16 changed files with 3182 additions and 0 deletions

View File

@@ -89,6 +89,13 @@ list(APPEND XTOSKRNL_SOURCE
${XTOSKRNL_SOURCE_DIR}/mm/probe.cc
${XTOSKRNL_SOURCE_DIR}/mm/pte.cc
${XTOSKRNL_SOURCE_DIR}/mm/quota.cc
${XTOSKRNL_SOURCE_DIR}/ob/data.cc
${XTOSKRNL_SOURCE_DIR}/ob/devmap.cc
${XTOSKRNL_SOURCE_DIR}/ob/lifecycl.cc
${XTOSKRNL_SOURCE_DIR}/ob/obdir.cc
${XTOSKRNL_SOURCE_DIR}/ob/obmgr.cc
${XTOSKRNL_SOURCE_DIR}/ob/security.cc
${XTOSKRNL_SOURCE_DIR}/ob/typereg.cc
${XTOSKRNL_SOURCE_DIR}/po/idle.cc
${XTOSKRNL_SOURCE_DIR}/ps/data.cc
${XTOSKRNL_SOURCE_DIR}/ps/process.cc

View File

@@ -19,6 +19,11 @@
#define TAG_MM_OVERFLOW SIGNATURE32('O', 'V', 'F', 'L')
#define TAG_MM_MEMORY_POOL SIGNATURE32('P', 'O', 'O', 'L')
#define TAG_MM_NONE SIGNATURE32('N', 'O', 'N', 'E')
#define TAG_OB_CREATE_INFO SIGNATURE32('O', 'B', 'C', 'I')
#define TAG_OB_DIRECTORY SIGNATURE32('O', 'B', 'D', 'I')
#define TAG_OB_MEMORY_POOL SIGNATURE32('O', 'B', 'J', 'M')
#define TAG_OB_NAME SIGNATURE32('O', 'B', 'N', 'M')
#define TAG_OB_OBJECT_TYPE SIGNATURE32('O', 'B', 'J', 'T')
#define TAG_PS_QUOTA_BLOCK SIGNATURE32('P', 'S', 'Q', 'B')
#define TAG_SE_DESCRIPTOR SIGNATURE32('S', 'E', 'S', 'D')

22
xtoskrnl/includes/ob.hh Normal file
View File

@@ -0,0 +1,22 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/includes/ob.hh
* DESCRIPTION: Object Manager
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#ifndef __XTOSKRNL_OB_HH
#define __XTOSKRNL_OB_HH
#include <xtos.hh>
#include <ob/devmap.hh>
#include <ob/lifecycl.hh>
#include <ob/obdir.hh>
#include <ob/obmgr.hh>
#include <ob/security.hh>
#include <ob/typereg.hh>
#endif /* __XTOSKRNL_OB_HH */

View File

@@ -0,0 +1,31 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/includes/ob/devmap.hh
* DESCRIPTION: Object Manager Device Map
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#ifndef __XTOSKRNL_OB_DEVMAP_HH
#define __XTOSKRNL_OB_DEVMAP_HH
#include <xtos.hh>
/* Object Manager */
namespace OB
{
class DeviceMap
{
private:
STATIC KPUSH_LOCK DeviceMapLock;
STATIC BOOLEAN UniqueDeviceMaps;
public:
STATIC XTAPI POBJECT_DIRECTORY GetGlobalDevicesDirectory(IN POBJECT_DIRECTORY Directory);
STATIC XTAPI BOOLEAN GetUniqueDeviceMaps(VOID);
STATIC XTAPI XTSTATUS InitializeDeviceMap(VOID);
};
}
#endif /* __XTOSKRNL_OB_DEVMAP_HH */

View File

@@ -0,0 +1,86 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/includes/ob/lifecycl.hh
* DESCRIPTION: Object Manager Lifecycle Management
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#ifndef __XTOSKRNL_OB_LIFECYCL_HH
#define __XTOSKRNL_OB_LIFECYCL_HH
#include <xtos.hh>
/* Object Manager */
namespace OB
{
class LifeCycle
{
private:
STATIC PVOID RemoveObjectList;
STATIC WORK_QUEUE_ITEM RemoveObjectWorkItem;
public:
STATIC XTAPI XTSTATUS AllocateObject(IN POBJECT_CREATE_INFORMATION CreateInfo,
IN KPROCESSOR_MODE OwnerProcessorMode,
IN POBJECT_TYPE ObjectType,
IN PUNICODE_STRING ObjectName,
IN ULONG ObjectBodySize,
OUT POBJECT_HEADER *ReturnedObjectHeader);
STATIC XTAPI VOID DeferObjectDeletion(IN POBJECT_HEADER ObjectHeader);
STATIC XTFASTCALL LONG_PTR DereferenceObject(IN PVOID Object);
STATIC XTFASTCALL LONG_PTR DereferenceObject(IN PVOID Object,
IN ULONG Count);
STATIC XTFASTCALL LONG_PTR DereferenceObjectDeferDelete(IN PVOID Object);
STATIC XTFASTCALL VOID DereferenceObjectNameInformation(IN POBJECT_HEADER_NAME_INFO NameInfo);
STATIC XTFASTCALL POBJECT_HEADER_CREATOR_INFO GetObjectCreatorInformation(IN POBJECT_HEADER Header);
STATIC XTFASTCALL POBJECT_HEADER_NAME_INFO GetObjectNameInformation(IN POBJECT_HEADER Header);
STATIC XTAPI VOID InitializeObjectLifeCycle(VOID);
STATIC XTFASTCALL LONG_PTR ReferenceObject(IN PVOID Object);
STATIC XTFASTCALL LONG_PTR ReferenceObject(IN PVOID Object,
IN ULONG Count);
STATIC XTFASTCALL POBJECT_HEADER_NAME_INFO ReferenceObjectNameInformation(IN POBJECT_HEADER ObjectHeader);
private:
STATIC XTFASTCALL PWCH AllocateObjectName(IN ULONG Length,
IN BOOLEAN UseLookaside,
IN OUT PUNICODE_STRING ObjectName);
STATIC XTAPI VOID CalculateOptionalHeaderSize(IN POBJECT_CREATE_INFORMATION CreateInfo,
IN POBJECT_TYPE ObjectType,
IN PUNICODE_STRING ObjectName,
OUT POBJECT_OPTIONAL_HEADER_LAYOUT Layout);
STATIC XTAPI XTSTATUS CaptureObjectCreateInformation(IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE ProcessorMode,
IN KPROCESSOR_MODE OwnerProcessorMode,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN OUT PUNICODE_STRING CapturedObjectName,
IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
IN BOOLEAN UseLookaside);
STATIC XTAPI XTSTATUS CaptureObjectName(IN KPROCESSOR_MODE ProcessorMode,
IN PUNICODE_STRING ObjectName,
IN OUT PUNICODE_STRING CapturedObjectName,
IN BOOLEAN UseLookaside);
STATIC XTAPI XTSTATUS CreateObject(IN KPROCESSOR_MODE ProcessorMode,
IN POBJECT_TYPE ObjectType,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN KPROCESSOR_MODE OwnerProcessorMode,
IN OUT PVOID ParseContext,
IN ULONG ObjectBodySize,
IN ULONG PagedPoolCharge,
IN ULONG NonPagedPoolCharge,
OUT PVOID *Object);
STATIC XTAPI VOID DeleteObject(IN PVOID Object,
IN BOOLEAN CalledOnWorkerThread);
STATIC XTAPI VOID FreeObject(IN PVOID Object);
STATIC XTFASTCALL VOID FreeObjectCreateInformation(IN POBJECT_CREATE_INFORMATION CreateInfo);
STATIC XTFASTCALL VOID FreeObjectName(IN OUT PUNICODE_STRING ObjectName);
STATIC XTAPI PVOID GetObjectAllocationBase(IN POBJECT_HEADER ObjectHeader);
STATIC XTAPI VOID ProcessDeferredDeletionQueue(IN PVOID Parameter);
STATIC XTFASTCALL VOID ReleaseObjectCreateInformation(IN POBJECT_CREATE_INFORMATION CreateInfo);
STATIC XTAPI VOID ReturnObjectQuota(IN POBJECT_HEADER ObjectHeader,
IN POBJECT_TYPE ObjectType);
};
}
#endif /* __XTOSKRNL_OB_LIFECYCL_HH */

View File

@@ -0,0 +1,53 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/includes/ob/obdir.hh
* DESCRIPTION: Object Manager Security API
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#ifndef __XTOSKRNL_OB_OBDIR_HH
#define __XTOSKRNL_OB_OBDIR_HH
#include <xtos.hh>
/* Object Manager */
namespace OB
{
class Directory
{
public:
STATIC XTAPI BOOLEAN DeleteDirectoryEntry(IN POBJECT_LOOKUP_CONTEXT LookupContext);
STATIC XTFASTCALL VOID InitializeLookupContext(OUT POBJECT_LOOKUP_CONTEXT LookupContext);
STATIC XTAPI BOOLEAN InsertDirectoryEntry(IN OUT POBJECT_DIRECTORY Directory,
IN POBJECT_LOOKUP_CONTEXT LookupContext,
IN OUT POBJECT_HEADER ObjectHeader);
STATIC XTFASTCALL VOID LockLookupContext(IN POBJECT_DIRECTORY Directory,
IN POBJECT_LOOKUP_CONTEXT LookupContext);
STATIC XTAPI PVOID LookupDirectoryEntry(IN POBJECT_DIRECTORY Directory,
IN PUNICODE_STRING Name,
IN ULONG Attributes,
IN BOOLEAN SearchGlobalDirectory,
OUT POBJECT_LOOKUP_CONTEXT LookupContext);
STATIC XTFASTCALL VOID ReleaseLookupContext(IN OUT POBJECT_LOOKUP_CONTEXT LookupContext);
private:
STATIC XTFASTCALL VOID AcquireExclusiveDirectoryLock(IN OUT POBJECT_DIRECTORY Directory,
IN OUT POBJECT_LOOKUP_CONTEXT LookupContext);
STATIC XTFASTCALL VOID AcquireSharedDirectoryLock(IN POBJECT_DIRECTORY Directory,
IN POBJECT_LOOKUP_CONTEXT LookupContext);
STATIC XTFASTCALL ULONG ComputeObjectNameHash(IN PCUNICODE_STRING Name);
STATIC XTFASTCALL VOID ReleaseDirectoryLock(IN OUT POBJECT_DIRECTORY Directory,
IN OUT POBJECT_LOOKUP_CONTEXT LookupContext);
STATIC XTFASTCALL VOID ReleaseLookupContextObject(IN OUT POBJECT_LOOKUP_CONTEXT LookupContext);
STATIC XTFASTCALL PVOID SearchDirectory(IN POBJECT_DIRECTORY Directory,
IN PCUNICODE_STRING Name,
IN BOOLEAN CaseInsensitive,
IN ULONG HashIndex,
IN POBJECT_LOOKUP_CONTEXT LookupContext);
};
}
#endif /* __XTOSKRNL_OB_OBDIR_HH */

View File

@@ -0,0 +1,30 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/includes/ob/obmgr.hh
* DESCRIPTION: Object Manager
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#ifndef __XTOSKRNL_OB_OBMGR_HH
#define __XTOSKRNL_OB_OBMGR_HH
#include <xtos.hh>
/* Object Manager */
namespace OB
{
class Manager
{
private:
STATIC GENERAL_LOOKASIDE CreateInfoList;
STATIC GENERAL_LOOKASIDE NameBufferList;
public:
STATIC XTAPI XTSTATUS InitializeObjectManager(VOID);
STATIC XTAPI VOID InitializeSystemLookasideList(VOID);
};
}
#endif /* __XTOSKRNL_OB_OBMGR_HH */

View File

@@ -0,0 +1,32 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/includes/ob/security.hh
* DESCRIPTION: Object Manager Security API
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#ifndef __XTOSKRNL_OB_SECURITY_HH
#define __XTOSKRNL_OB_SECURITY_HH
#include <xtos.hh>
/* Object Manager */
namespace OB
{
class Security
{
public:
STATIC XTAPI XTSTATUS ProcessObjectSecurityDescriptor(IN PVOID Object,
IN SECURITY_OPERATION_CODE OperationCode,
IN PSECURITY_INFORMATION SecurityInformation,
IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN OUT PULONG Length,
IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
IN MMPOOL_TYPE PoolType,
IN PGENERIC_MAPPING GenericMapping);
};
}
#endif /* __XTOSKRNL_OB_SECURITY_HH */

View File

@@ -0,0 +1,44 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/includes/ob/typereg.hh
* DESCRIPTION: Object Manager Type Registry
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#ifndef __XTOSKRNL_OB_TYPEREG_HH
#define __XTOSKRNL_OB_TYPEREG_HH
#include <xtos.hh>
/* Object Manager */
namespace OB
{
class TypeRegistry
{
private:
STATIC KEVENT DefaultEvent;
STATIC POBJECT_TYPE MasterObjectType;
STATIC POBJECT_DIRECTORY ObjectTypeDirectory;
STATIC POBJECT_TYPE ObjectTypesTable[OBJECT_MAX_DEFINED_OBJECT_TYPES];
public:
STATIC XTAPI XTSTATUS CreateObjectType(IN PUNICODE_STRING TypeName,
IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
OUT POBJECT_TYPE *ObjectType);
STATIC XTAPI VOID DeleteObjectType(IN PVOID Object);
STATIC XTAPI XTSTATUS InitializeObjectTypeRegistry(VOID);
private:
STATIC XTAPI ULONG GenerateObjectPoolTag(IN PUNICODE_STRING TypeName);
STATIC XTAPI VOID InitializeObjectType(IN OUT POBJECT_TYPE ObjectType,
IN POBJECT_TYPE_INITIALIZER Initializer,
IN PUNICODE_STRING ObjectName);
STATIC XTAPI XTSTATUS ValidateObjectTypeParameters(IN PUNICODE_STRING TypeName,
IN POBJECT_TYPE_INITIALIZER Initializer);
};
}
#endif /* __XTOSKRNL_OB_TYPEREG_HH */

40
xtoskrnl/ob/data.cc Normal file
View File

@@ -0,0 +1,40 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/ob/data.cc
* DESCRIPTION: Object Manager global and static data
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#include <xtos.hh>
/* Synchronizes shared read and exclusive write access to system device map structures */
KPUSH_LOCK OB::DeviceMap::DeviceMapLock;
/* Indicates whether the system employs unique device maps */
BOOLEAN OB::DeviceMap::UniqueDeviceMaps;
/* System work queue item responsible for scheduling the deferred object deletion */
WORK_QUEUE_ITEM OB::LifeCycle::RemoveObjectWorkItem;
/* Default kernel event utilized by the Object Manager */
KEVENT OB::TypeRegistry::DefaultEvent;
/* Fundamental Type object type */
POBJECT_TYPE OB::TypeRegistry::MasterObjectType;
/* Points to the Object Types directory */
POBJECT_DIRECTORY OB::TypeRegistry::ObjectTypeDirectory;
/* Index-based lookup for all registered object types */
POBJECT_TYPE OB::TypeRegistry::ObjectTypesTable[OBJECT_MAX_DEFINED_OBJECT_TYPES];
/* General lookaside list used for allocation and deallocation of OBJECT_CREATE_INFORMATION structures */
GENERAL_LOOKASIDE OB::Manager::CreateInfoList;
/* General lookaside list used for allocation and deallocation buffers for Unicode object names */
GENERAL_LOOKASIDE OB::Manager::NameBufferList;
/* The list head for tracking objects that have been marked for deferred deletion */
PVOID OB::LifeCycle::RemoveObjectList;

82
xtoskrnl/ob/devmap.cc Normal file
View File

@@ -0,0 +1,82 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/ob/devmap.cc
* DESCRIPTION: Object Manager Device Map
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#include <xtos.hh>
/**
* Retrieves the Global Devices Directory associated with a given directory's device map.
*
* @param Directory
* Supplies a pointer to the object directory to query.
*
* @return Returns a pointer to the global devices directory, or NULLPTR if none exists.
*
* @since XT 1.0
*/
XTAPI
POBJECT_DIRECTORY
OB::DeviceMap::GetGlobalDevicesDirectory(IN POBJECT_DIRECTORY Directory)
{
POBJECT_DIRECTORY GlobalDevicesDirectory;
/* Assume no mapping exists */
GlobalDevicesDirectory = NULLPTR;
/* Acquire the device map lock */
KE::PushLock::AcquireExclusivePushLock(&DeviceMapLock);
/* Check if the directory has an associated device map */
if(Directory->DeviceMap)
{
/* Extract the global devices directory */
GlobalDevicesDirectory = Directory->DeviceMap->GlobalDevicesDirectory;
}
/* Release the device map lock */
KE::PushLock::ReleaseExclusivePushLock(&DeviceMapLock);
/* Return the resolved directory */
return GlobalDevicesDirectory;
}
/**
* Retrieves the current state of the unique device maps configuration.
*
* @return This routine returns TRUE if unique device maps are enabled, or FALSE otherwise.
*
* @since XT 1.0
*/
XTAPI
BOOLEAN
OB::DeviceMap::GetUniqueDeviceMaps(VOID)
{
/* Return the unique device maps flag */
return UniqueDeviceMaps;
}
/**
* Initializes the Object Manager's device map subsystem.
*
* @return This routine returns a status code indicating the success or failure of the operation.
*
* @since XT 1.0
*/
XTAPI
XTSTATUS
OB::DeviceMap::InitializeDeviceMap(VOID)
{
/* Initialize device map lock */
KE::PushLock::InitializePushLock(&DeviceMapLock);
/* Temporarily disable unique device maps */
UniqueDeviceMaps = FALSE;
/* Return success */
return STATUS_SUCCESS;
}

1541
xtoskrnl/ob/lifecycl.cc Normal file

File diff suppressed because it is too large Load Diff

582
xtoskrnl/ob/obdir.cc Normal file
View File

@@ -0,0 +1,582 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/ob/obdir.cc
* DESCRIPTION: Object Manager Directory
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#include <xtos.hh>
/**
* Acquires an exclusive pushlock for the specified object directory.
*
* @param Directory
* Supplies a pointer to the object directory being locked.
*
* @param LookupContext
* Supplies a pointer to the lookup context used to track the lock state.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTFASTCALL
VOID
OB::Directory::AcquireExclusiveDirectoryLock(IN OUT POBJECT_DIRECTORY Directory,
IN OUT POBJECT_LOOKUP_CONTEXT LookupContext)
{
/* Set the initial lock state */
LookupContext->LockStateSignature = OBJECT_LOCK_STATE_WAIT_EXCLUSIVE;
/* Disable kernel APCs */
KE::KThread::EnterCriticalRegion();
/* Acquire the directory lock for exclusive access */
KE::PushLock::AcquireExclusivePushLock(&Directory->Lock);
/* Update the lock state */
LookupContext->LockStateSignature = OBJECT_LOCK_STATE_OWNED_EXCLUSIVE;
}
/**
* Acquires a shared pushlock for the specified object directory.
*
* @param Directory
* Supplies a pointer to the object directory being locked.
*
* @param LookupContext
* Supplies a pointer to the lookup context used to track the lock state.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTFASTCALL
VOID
OB::Directory::AcquireSharedDirectoryLock(IN POBJECT_DIRECTORY Directory,
IN POBJECT_LOOKUP_CONTEXT LookupContext)
{
/* Set the initial lock state */
LookupContext->LockStateSignature = OBJECT_LOCK_WAITSHARED_SIGNATURE;
/* Disable kernel APCs */
KE::KThread::EnterCriticalRegion();
/* Acquire the directory lock for shared access */
KE::PushLock::AcquireSharedPushLock(&Directory->Lock);
/* Update the lock state */
LookupContext->LockStateSignature = OBJECT_LOCK_OWNEDSHARED_SIGNATURE;
}
/**
* Computes the case-insensitive hash index for an object name.
*
* @param Name
* Supplies a pointer to the unicode string containing the object name.
*
* @return This routine returns the computed hash index.
*
* @since XT 1.0
*/
XTFASTCALL
ULONG
OB::Directory::ComputeObjectNameHash(IN PCUNICODE_STRING Name)
{
ULONG CharacterLength, HashIndex;
WCHAR Character;
PWCH Buffer;
/* Initialize the buffer pointer, character count, and starting hash value */
Buffer = Name->Buffer;
CharacterLength = Name->Length / sizeof(WCHAR);
HashIndex = 0;
/* Iterate through each wide character */
while(CharacterLength--)
{
/* Fetch the current character and advance the buffer pointer */
Character = *Buffer++;
/* Apply the NT string hashing polynomial */
HashIndex += (HashIndex << 1) + (HashIndex >> 1);
/* Check if the character is uppercase, numeric, or a symbol */
if(Character < L'a')
{
/* Add the unmodified character */
HashIndex += Character;
}
else if(Character > L'z')
{
/* Convert extended Unicode characters to uppercase */
HashIndex += RTL::Nls::ToUpperUnicodeCharacter(Character);
}
else
{
/* Perform ASCII conversion from lowercase to uppercase */
HashIndex += (Character - (L'a' - L'A'));
}
}
/* Return the final hash value */
return HashIndex % OBJECT_NUMBER_HASH_BUCKETS;
}
/**
* Removes an object directory entry from its hash bucket and frees its memory.
*
* @param LookupContext
* Supplies a pointer to the lookup context containing the directory and hash index.
*
* @return This routine returns TRUE if the entry was successfully unlinked and freed, or FALSE otherwise.
*
* @since XT 1.0
*/
XTAPI
BOOLEAN
OB::Directory::DeleteDirectoryEntry(IN POBJECT_LOOKUP_CONTEXT LookupContext)
{
POBJECT_DIRECTORY_ENTRY DirectoryEntry, *HashBucket;
POBJECT_DIRECTORY Directory;
/* Extract the directory from the lookup context */
Directory = LookupContext->Directory;
/* Verify that the directory pointer is valid */
if(Directory)
{
/* Resolve the head of the collision chain */
HashBucket = (POBJECT_DIRECTORY_ENTRY*)&Directory->HashBuckets[LookupContext->HashIndex];
/* Retrieve the entry at the head of the chain */
DirectoryEntry = *HashBucket;
/* Ensure there isan entry to delete */
if(DirectoryEntry)
{
/* Unlink the entry from the hash bucket chain */
*HashBucket = DirectoryEntry->ChainLink;
DirectoryEntry->ChainLink = NULLPTR;
/* Free the memory */
MM::Allocator::FreePool(DirectoryEntry);
/* Return TRUE */
return TRUE;
}
}
/* No entry found, return FALSE */
return FALSE;
}
/**
* Initializes the Object Manager lookup context.
*
* @param LookupContext
* Supplies a pointer to the caller-allocated lookup context to initialize.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTFASTCALL
VOID
OB::Directory::InitializeLookupContext(OUT POBJECT_LOOKUP_CONTEXT LookupContext)
{
/* Initialize the lookup context */
LookupContext->Directory = NULLPTR;
LookupContext->DirectoryLocked = FALSE;
LookupContext->LockStateSignature = OBJECT_LOCK_STATE_INITIALIZED;
LookupContext->Object = NULLPTR;
}
/**
* Inserts a newly created object into an object directory.
*
* @param Directory
* Pointer to the object directory where the object will be inserted.
*
* @param LookupContext
* Pointer to the lookup context containing the precomputed hash index.
*
* @param ObjectHeader
* Pointer to the object header of the object being inserted.
*
* @return TRUE if the insertion was successful, FALSE if pool allocation failed.
*
* @since XT 1.0
*/
XTAPI
BOOLEAN
OB::Directory::InsertDirectoryEntry(IN OUT POBJECT_DIRECTORY Directory,
IN POBJECT_LOOKUP_CONTEXT LookupContext,
IN OUT POBJECT_HEADER ObjectHeader)
{
POBJECT_DIRECTORY_ENTRY *HashBucket, NewEntry;
POBJECT_HEADER_NAME_INFO NameInfo;
XTSTATUS Status;
/* Extract the name information header */
NameInfo = OB::LifeCycle::GetObjectNameInformation(ObjectHeader);
/* Allocate the directory entry */
Status = MM::Allocator::AllocatePool(PagedPool, sizeof(OBJECT_DIRECTORY_ENTRY),
(PVOID *)&NewEntry, TAG_OB_DIRECTORY);
if(Status != STATUS_SUCCESS || !NewEntry)
{
/* Allocation failed, return FALSE */
return FALSE;
}
/* Resolve the hash bucket head */
HashBucket = (POBJECT_DIRECTORY_ENTRY*)&Directory->HashBuckets[LookupContext->HashIndex];
/* Insert the entry at the head of the collision chain */
NewEntry->ChainLink = *HashBucket;
*HashBucket = NewEntry;
/* Link the entry to the object body and establish the parent directory */
NewEntry->Object = &ObjectHeader->Body;
NameInfo->Directory = Directory;
/* Return TRUE */
return TRUE;
}
/**
* Acquires an exclusive lock on the specified object directory.
*
* @param Directory
* Supplies a pointer to the object directory to lock.
*
* @param LookupContext
* Supplies a pointer to the active lookup context used to track the lock state.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTFASTCALL
VOID
OB::Directory::LockLookupContext(IN POBJECT_DIRECTORY Directory,
IN POBJECT_LOOKUP_CONTEXT LookupContext)
{
/* Acquire exclusive access to the directory */
AcquireExclusiveDirectoryLock(Directory, LookupContext);
/* Cache the directory pointer and lock ownership */
LookupContext->Directory = Directory;
LookupContext->DirectoryLocked = TRUE;
}
/**
* Looks up an object directory entry by name within the namespace.
*
* @param Directory
* Supplies a pointer to the primary object directory to search.
*
* @param Name
* Supplies a pointer to the name of the object to locate.
*
* @param Attributes
* Supplies the object attributes bitmask.
*
* @param SearchGlobalDirectory
* Specifies whether to fallback into the device map's global shadow directory if the object is not found
* in the primary directory.
*
* @param LookupContext
* Supplies a pointer to the tracking context.
*
* @return This routine returns a pointer to the referenced object body, or NULLPTR if resolution fails.
*
* @since XT 1.0
*/
XTAPI
PVOID
OB::Directory::LookupDirectoryEntry(IN POBJECT_DIRECTORY Directory,
IN PUNICODE_STRING Name,
IN ULONG Attributes,
IN BOOLEAN SearchGlobalDirectory,
OUT POBJECT_LOOKUP_CONTEXT LookupContext)
{
POBJECT_HEADER_NAME_INFO PreviousNameInfo;
POBJECT_DIRECTORY CurrentDirectory;
BOOLEAN CaseInsensitive;
PVOID FoundObject;
ULONG HashIndex;
/* Initialize the default return value */
FoundObject = NULLPTR;
/* Check if global device map traversal is available */
if(!OB::DeviceMap::GetUniqueDeviceMaps())
{
/* Override caller's request to prevent shadow directory traversal */
SearchGlobalDirectory = FALSE;
}
/* Guard against invalid parameter combination */
if(Directory != NULLPTR && Name != NULLPTR && Name->Length != 0 && Name->Buffer != NULLPTR)
{
/* Determine if the string comparison should ignore case */
CaseInsensitive = (Attributes & OBJECT_CASE_INSENSITIVE) ? TRUE : FALSE;
/* Precompute the hash index */
HashIndex = ComputeObjectNameHash(Name);
/* Initialize the traversal pointer */
CurrentDirectory = Directory;
/* Cache the computed hash index in the lookup context */
LookupContext->HashIndex = (USHORT)HashIndex;
/* Iterate through the directory and linked shadow boundaries */
while(CurrentDirectory)
{
/* Check if the directory is locked */
if(!LookupContext->DirectoryLocked)
{
/* Acquire the directory lock */
AcquireSharedDirectoryLock(CurrentDirectory, LookupContext);
}
/* Traverse the hash bucket chain to find a matching entry */
FoundObject = SearchDirectory(CurrentDirectory, Name, CaseInsensitive, HashIndex, LookupContext);
if(FoundObject)
{
/* Match found, secure the object and its name info */
OB::LifeCycle::ReferenceObjectNameInformation(CONTAIN_RECORD(FoundObject, OBJECT_HEADER, Body));
OB::LifeCycle::ReferenceObject(FoundObject);
/* Check if the directory is locked */
if(!LookupContext->DirectoryLocked)
{
/* Drop the lock and restore standard kernel APC delivery */
OB::Directory::ReleaseDirectoryLock(CurrentDirectory, LookupContext);
}
/* Target resolved, break the loop */
break;
}
/* Check if the directory is locked */
if(!LookupContext->DirectoryLocked)
{
/* Drop the lock and restore standard kernel APC delivery */
OB::Directory::ReleaseDirectoryLock(CurrentDirectory, LookupContext);
}
/* Check if fallback to the global shadow directory is possible */
if(SearchGlobalDirectory && CurrentDirectory->DeviceMap != NULLPTR)
{
/* Resolve the shadow global devices directory in next iteration */
CurrentDirectory = OB::DeviceMap::GetGlobalDevicesDirectory(CurrentDirectory);
}
else
{
/* Terminate the traversal loop */
CurrentDirectory = NULLPTR;
}
}
}
/* Check if the lookup context contains a previously resolved object */
if(LookupContext->Object != NULLPTR)
{
/* Resolve the old object's name information header */
PreviousNameInfo = OB::LifeCycle::GetObjectNameInformation(CONTAIN_RECORD(LookupContext->Object,
OBJECT_HEADER,
Body));
/* Release the references */
OB::LifeCycle::DereferenceObjectNameInformation(PreviousNameInfo);
OB::LifeCycle::DereferenceObject(LookupContext->Object);
}
/* Store the newly found object payload inside the caller's lookup context */
LookupContext->Object = FoundObject;
/* Return the object body */
return FoundObject;
}
/**
* Releases a previously acquired object directory lock.
*
* @param Directory
* Supplies a pointer to the object directory to unlock.
*
* @param LookupContext
* Supplies a pointer to the lookup context for state tracking.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTFASTCALL
VOID
OB::Directory::ReleaseDirectoryLock(IN OUT POBJECT_DIRECTORY Directory,
IN OUT POBJECT_LOOKUP_CONTEXT LookupContext)
{
/* Release the directory lock */
KE::PushLock::ReleasePushLock(&Directory->Lock);
/* Update the lock state */
LookupContext->LockStateSignature = OBJECT_LOCK_STATE_RELEASED_SIGNATURE;
/* Restore APC delivery */
KE::KThread::LeaveCriticalRegion();
}
/**
* Releases all resources held within an Object Manager lookup context.
*
* @param LookupContext
* Supplies a pointer to the active lookup context to be released.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTFASTCALL
VOID
OB::Directory::ReleaseLookupContext(IN OUT POBJECT_LOOKUP_CONTEXT LookupContext)
{
/* Verify if a directory lock is held */
if(LookupContext->DirectoryLocked)
{
/* Release the directory lock */
ReleaseDirectoryLock(LookupContext->Directory, LookupContext);
/* Update lookup context state */
LookupContext->Directory = NULLPTR;
LookupContext->DirectoryLocked = FALSE;
}
/* Release the object references held within a lookup context */
ReleaseLookupContextObject(LookupContext);
}
/**
* Releases the object reference held within a lookup context.
*
* @param LookupContext
* Supplies a pointer to the active lookup context containing the object to be released.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTFASTCALL
VOID
OB::Directory::ReleaseLookupContextObject(IN OUT POBJECT_LOOKUP_CONTEXT LookupContext)
{
POBJECT_HEADER_NAME_INFO NameInfo;
POBJECT_HEADER ObjectHeader;
PVOID Object;
/* Extract the cached object pointer from the lookup context */
Object = LookupContext->Object;
if(Object)
{
/* Resolve the object header */
ObjectHeader = CONTAIN_RECORD(Object, OBJECT_HEADER, Body);
/* Retrieve the optional name information header */
NameInfo = OB::LifeCycle::GetObjectNameInformation(ObjectHeader);
/* Verify if the object has a registered name */
if(NameInfo)
{
/* Drop the name query reference */
OB::LifeCycle::DereferenceObjectNameInformation(NameInfo);
}
/* Release the pointer reference */
OB::LifeCycle::DereferenceObject(Object);
/* Purge the pointer */
LookupContext->Object = NULLPTR;
}
}
/**
* Traverses an object directory hash bucket to find a matching entry.
*
* @param Directory
* Supplies a pointer to the object directory being searched.
*
* @param Name
* Supplies ap ointer to the target object name.
*
* @param CaseInsensitive
* Specifies whether the string comparison should ignore case.
*
* @param HashIndex
* Supplies the pre-computed hash bucket index used to locate the collision chain.
*
* @param LookupContext
* Supplies a pointer to the caller's lookup context.
*
* @return This routine returns a pointer to the resolved object body if found, or NULLPTR otherwise.
*
* @since XT 1.0
*/
XTFASTCALL
PVOID
OB::Directory::SearchDirectory(IN POBJECT_DIRECTORY Directory,
IN PCUNICODE_STRING Name,
IN BOOLEAN CaseInsensitive,
IN ULONG HashIndex,
IN POBJECT_LOOKUP_CONTEXT LookupContext)
{
POBJECT_DIRECTORY_ENTRY DirectoryEntry, *HeadDirectoryEntry, *LookupBucket;
POBJECT_HEADER_NAME_INFO NameInfo;
POBJECT_HEADER ObjectHeader;
/* Resolve the head pointer of the target hash bucket chain */
LookupBucket = (POBJECT_DIRECTORY_ENTRY*)&Directory->HashBuckets[HashIndex];
/* Iterate through the collision chain */
HeadDirectoryEntry = LookupBucket;
while((DirectoryEntry = *HeadDirectoryEntry) != NULLPTR)
{
/* Resolve the underlying object header */
ObjectHeader = CONTAIN_RECORD(DirectoryEntry->Object, OBJECT_HEADER, Body);
/* Retrieve the optional name information header */
NameInfo = OB::LifeCycle::GetObjectNameInformation(ObjectHeader);
/* Check if the names match */
if((Name->Length == NameInfo->Name.Length) &&
RTL::Unicode::CompareString(Name, &NameInfo->Name, CaseInsensitive) == 0)
{
/* Check if it is already at the head of the bucket */
if(HeadDirectoryEntry != LookupBucket)
{
/* Check if the directory is locked */
if(LookupContext->DirectoryLocked || KE::PushLock::ConvertSharedPushLockToExclusive(&Directory->Lock))
{
/* Relocate the entry to the front */
*HeadDirectoryEntry = DirectoryEntry->ChainLink;
DirectoryEntry->ChainLink = *LookupBucket;
*LookupBucket = DirectoryEntry;
}
}
/* Return the pointer to the object body */
return DirectoryEntry->Object;
}
/* Advance to the next node entry */
HeadDirectoryEntry = &DirectoryEntry->ChainLink;
}
/* Return NULL pointer*/
return NULLPTR;
}

120
xtoskrnl/ob/obmgr.cc Normal file
View File

@@ -0,0 +1,120 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/ob/obmgr.cc
* DESCRIPTION: Object Manager
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#include <xtos.hh>
/**
* Initializes the Object Manager subsystem.
*
* @return This routine returns a status code indicating the success or failure of the operation.
*
* @since XT 1.0
*/
XTAPI
XTSTATUS
OB::Manager::InitializeObjectManager(VOID)
{
XTSTATUS Status;
/* Zero out the static global lookaside structures */
RTL::Memory::ZeroMemory(&CreateInfoList, sizeof(GENERAL_LOOKASIDE));
RTL::Memory::ZeroMemory(&NameBufferList, sizeof(GENERAL_LOOKASIDE));
/* Initialize the system-wide global lookaside list for object create information structures */
EX::LookasideList::InitializeLookasideList(&CreateInfoList, NonPagedPool,
sizeof(OBJECT_CREATE_INFORMATION), TAG_OB_CREATE_INFO,
64, EX::LookasideList::GetSystemLookasideListHead());
/* Initialize the system-wide global lookaside list for object name buffers */
EX::LookasideList::InitializeLookasideList(&NameBufferList, PagedPool,
OBJECT_NAME_BUFFER_SIZE, TAG_OB_NAME,
32, EX::LookasideList::GetSystemLookasideListHead());
/* Initialize system lookaside list for BSP */
InitializeSystemLookasideList();
/* Initialize device map support */
OB::DeviceMap::InitializeDeviceMap();
OB::LifeCycle::InitializeObjectLifeCycle();
/* Initialize object type registry */
Status = OB::TypeRegistry::InitializeObjectTypeRegistry();
if(Status != STATUS_SUCCESS)
{
/* Initialization failed, return error code */
return Status;
}
/* Return success */
return STATUS_SUCCESS;
}
/**
* Initializes the per-processor lookaside lists for the Object Manager.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
OB::Manager::InitializeSystemLookasideList(VOID)
{
PKPROCESSOR_CONTROL_BLOCK Prcb;
PGENERAL_LOOKASIDE LookasideList;
XTSTATUS Status;
/* Retrieve the Processor Control Block */
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
/* Allocate a contiguous memory block for lookaside lists */
Status = MM::Allocator::AllocatePool(NonPagedPool, sizeof(GENERAL_LOOKASIDE) * 2,
(PVOID*)&LookasideList, TAG_OB_CREATE_INFO);
/* Wire the global pointer for create information structures */
Prcb->LookasideList[LookasideCreateInfoList].Global = &CreateInfoList;
/* Check if the contiguous allocation was successful */
if(Status == STATUS_SUCCESS && LookasideList)
{
/* Map the pointer to the first half of the contiguous block */
Prcb->LookasideList[LookasideCreateInfoList].Local = &LookasideList[0];
/* Initialize the local list */
EX::LookasideList::InitializeLookasideList(&LookasideList[0], NonPagedPool,
sizeof(OBJECT_CREATE_INFORMATION), TAG_OB_CREATE_INFO,
64, EX::LookasideList::GetSystemLookasideListHead());
}
else
{
/* Allocation failed, use shared global list */
Prcb->LookasideList[LookasideCreateInfoList].Local = &CreateInfoList;
}
/* Wire the global pointer for object name buffers */
Prcb->LookasideList[LookasideNameBufferList].Global = &NameBufferList;
/* Check if the contiguous allocation was successful */
if(Status == STATUS_SUCCESS && LookasideList)
{
/* Map the pointer to the second half of the contiguous block */
Prcb->LookasideList[LookasideNameBufferList].Local = &LookasideList[1];
/* Initialize the local list */
EX::LookasideList::InitializeLookasideList(&LookasideList[1], PagedPool,
OBJECT_NAME_BUFFER_SIZE, TAG_OB_NAME,
32, EX::LookasideList::GetSystemLookasideListHead());
}
else
{
/* Allocation failed, use shared global list */
Prcb->LookasideList[LookasideNameBufferList].Local = &NameBufferList;
}
}

60
xtoskrnl/ob/security.cc Normal file
View File

@@ -0,0 +1,60 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/ob/security.cc
* DESCRIPTION: Object Manager Security API
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#include <xtos.hh>
/**
* Provides the default security procedure for handling object security descriptors.
*
* @param Object
* Supplies a pointer to the object whose security descriptor is being processed.
*
* @param OperationCode
* Supplies the specific security operation to perform (e.g., Assign, Delete, Query, Set).
*
* @param SecurityInformation
* Supplies a bitmask indicating which specific components of the security descriptor are involved.
*
* @param SecurityDescriptor
* Supplies a pointer to a caller-allocated buffer. For a set/assign operation, this contains the new
* security data. For a query operation, it receives the requested data.
*
* @param Length
* Supplies a pointer to a variable that specifies the size of the SecurityDescriptor buffer.
* On return for a query operation, it receives the actual number of bytes required.
*
* @param OldSecurityDescriptor
* Supplies a pointer to a variable that holds the current security descriptor of the object.
*
* @param PoolType
* Supplies the type of memory pool to use if a new security descriptor must be allocated.
*
* @param GenericMapping
* Supplies a pointer to the generic access mapping associated with the object's type.
*
* @return This routine returns a status code indicating the success or failure of the operation.
*
* @since XT 1.0
*/
XTAPI
XTSTATUS
OB::Security::ProcessObjectSecurityDescriptor(IN PVOID Object,
IN SECURITY_OPERATION_CODE OperationCode,
IN PSECURITY_INFORMATION SecurityInformation,
IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN OUT PULONG Length,
IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
IN MMPOOL_TYPE PoolType,
IN PGENERIC_MAPPING GenericMapping)
{
UNIMPLEMENTED;
/* Return success */
return STATUS_SUCCESS;
}

447
xtoskrnl/ob/typereg.cc Normal file
View File

@@ -0,0 +1,447 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/ob/typereg.cc
* DESCRIPTION: Object Manager Type Registry
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#include <xtos.hh>
/**
* Creates and initializes a new object type within the Object Manager namespace.
*
* @param TypeName
* Supplies the requested name of the new object type.
*
* @param Initializer
* Supplies the initialization parameters for the new object type.
*
* @param SecurityDescriptor
* Supplies an optional security descriptor. (Currently ignored).
*
* @param ObjectType
* Receives a pointer to the newly created object type.
*
* @return This routine returns a status code indicating the success or failure of the operation.
*
* @since XT 1.0
*/
XTAPI
XTSTATUS
OB::TypeRegistry::CreateObjectType(IN PUNICODE_STRING TypeName,
IN POBJECT_TYPE_INITIALIZER Initializer,
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
OUT POBJECT_TYPE *ObjectType)
{
POBJECT_HEADER_CREATOR_INFO CreatorInfo;
OBJECT_LOOKUP_CONTEXT LookupContext;
POBJECT_HEADER NewObjectTypeHeader;
POBJECT_TYPE NewObjectType;
UNICODE_STRING ObjectName;
XTSTATUS Status;
/* Validate incoming parameters */
Status = ValidateObjectTypeParameters(TypeName, Initializer);
if(Status != STATUS_SUCCESS)
{
/* Parameter validation failed, return error code */
return Status;
}
/* Initialize the lookup context */
OB::Directory::InitializeLookupContext(&LookupContext);
/* Check if the global type directory exists */
if(ObjectTypeDirectory)
{
/* Acquire the directory lock and prepare for namespace lookup */
OB::Directory::LockLookupContext(ObjectTypeDirectory, &LookupContext);
/* Search the directory to check if an object type with this name already exists */
if(OB::Directory::LookupDirectoryEntry(ObjectTypeDirectory, TypeName, OBJECT_CASE_INSENSITIVE,
FALSE, &LookupContext))
{
/* A collision detected, release the directory lock and lookup context */
OB::Directory::ReleaseLookupContext(&LookupContext);
/* Reject the creation due to a naming conflict */
return STATUS_OBJECT_NAME_COLLISION;
}
}
/* Allocate paged memory for the persistent object type name */
Status = MM::Allocator::AllocatePool(PagedPool, (ULONG)TypeName->MaximumLength,
(PVOID*)&ObjectName.Buffer, TAG_OB_NAME);
if(Status != STATUS_SUCCESS || ObjectName.Buffer == NULLPTR)
{
/* Pool allocation failed; release the lookup context and return error code */
OB::Directory::ReleaseLookupContext(&LookupContext);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Copy the requested type name */
ObjectName.MaximumLength = TypeName->MaximumLength;
RTL::Unicode::CopyString(&ObjectName, TypeName);
/* Allocate the physical memory block for the Object Type */
Status = OB::LifeCycle::AllocateObject(NULLPTR, KernelMode, MasterObjectType, &ObjectName,
sizeof(OBJECT_TYPE), &NewObjectTypeHeader);
if(Status != STATUS_SUCCESS)
{
/* Object allocation failed; release the directory lock and free allocated name buffer */
OB::Directory::ReleaseLookupContext(&LookupContext);
MM::Allocator::FreePool(ObjectName.Buffer);
/* Return error code */
return Status;
}
/* Resolve the object body pointer and assign the captured name */
NewObjectTypeHeader->Flags |= OBJECT_FLAG_KERNEL_MODE | OBJECT_FLAG_PERMANENT;
NewObjectType = (POBJECT_TYPE)&NewObjectTypeHeader->Body;
NewObjectType->Name = ObjectName;
/* Zero out the statistics block */
RTL::Memory::ZeroMemory(&NewObjectType->TotalNumberOfObjects,
FIELD_OFFSET(OBJECT_TYPE, TypeInfo) - FIELD_OFFSET(OBJECT_TYPE, TotalNumberOfObjects));
/* Check if master object type is already initialized */
if(MasterObjectType == NULLPTR)
{
/* Set the global master type, link its header to itself, and set the default tag */
MasterObjectType = NewObjectType;
NewObjectTypeHeader->Type = MasterObjectType;
NewObjectType->Key = TAG_OB_OBJECT_TYPE;
NewObjectType->TotalNumberOfObjects = 1;
}
else
{
/* Generate a clean tag from object name */
NewObjectType->Key = GenerateObjectPoolTag(TypeName);
}
/* Initialize default objects and pool charges */
InitializeObjectType(NewObjectType, Initializer, &ObjectName);
/* Suspend APCs and acquire exclusive access to the master type tracking list */
KE::KThread::EnterCriticalRegion();
KE::PushLock::AcquireExclusivePushLock(&MasterObjectType->TypeLock);
/* Retrieve the creator information header */
CreatorInfo = OB::LifeCycle::GetObjectCreatorInformation(NewObjectTypeHeader);
if(CreatorInfo != NULLPTR)
{
/* Link the new object type */
RTL::LinkedList::InsertTailList(&MasterObjectType->TypeList, &CreatorInfo->TypeList);
/* Prevent double-insertion during handle creation */
NewObjectTypeHeader->Flags &= ~OBJECT_FLAG_CREATOR_INFO;
}
/* Assign a type index */
NewObjectType->Index = MasterObjectType->TotalNumberOfObjects;
if(NewObjectType->Index < OBJECT_MAX_DEFINED_OBJECT_TYPES)
{
/* Register the new type in the global table */
ObjectTypesTable[NewObjectType->Index - 1] = NewObjectType;
}
/* Release the master type lock and restore APC delivery */
KE::PushLock::ReleaseExclusivePushLock(&MasterObjectType->TypeLock);
KE::KThread::LeaveCriticalRegion();
/* Publish into the namespace directory */
if(ObjectTypeDirectory == NULLPTR ||
OB::Directory::InsertDirectoryEntry(ObjectTypeDirectory, &LookupContext, NewObjectTypeHeader))
{
/* Verify if the directory is present */
if(ObjectTypeDirectory)
{
/* Increment the reference count */
OB::LifeCycle::ReferenceObject(ObjectTypeDirectory);
}
/* Release the directory lock and context */
OB::Directory::ReleaseLookupContext(&LookupContext);
/* Return the pointer to the object type */
*ObjectType = NewObjectType;
return STATUS_SUCCESS;
}
else
{
/* Directory insertion failed, release lock and return error code */
OB::Directory::ReleaseLookupContext(&LookupContext);
return STATUS_INSUFFICIENT_RESOURCES;
}
}
/**
* Cleans up internal resources associated with an object type before its deletion.
*
* @param Object
* Supplies a pointer to the Object Type body being deleted.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
OB::TypeRegistry::DeleteObjectType(IN PVOID Object)
{
/* Nothing to do */
}
/**
* Generates a 4-byte pool tag based on the object type name.
*
* @param TypeName
* Supplies the name of the object type.
*
* @return This routine returns a 32-bit pool tag.
*
* @since XT 1.0
*/
XTAPI
ULONG
OB::TypeRegistry::GenerateObjectPoolTag(IN PUNICODE_STRING TypeName)
{
ULONG Index, Tag;
PUCHAR TagBytes;
/* Default tag to four spaces */
Tag = SIGNATURE32(' ', ' ', ' ', ' ');
TagBytes = (PUCHAR)&Tag;
/* Extract up to the first 4 characters */
for(Index = 0; Index < 4; Index++)
{
/* Verify if the current index falls within the valid bounds */
if(Index < (TypeName->Length / sizeof(WCHAR)))
{
/* Strip the high unicode byte and store the resulting ASCII character */
TagBytes[Index] = (UCHAR)(TypeName->Buffer[Index] & 0xFF);
}
}
/* Return the tag */
return Tag;
}
/**
* Initializes the internal body and configuration of a newly allocated object type.
*
* @param ObjectType
* Supplies a pointer to the object type to initialize.
*
* @param Initializer
* Supplies the initialization parameters.
*
* @param TypeName
* Supplies the name of the object type.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
OB::TypeRegistry::InitializeObjectType(IN OUT POBJECT_TYPE ObjectType,
IN POBJECT_TYPE_INITIALIZER Initializer,
IN PUNICODE_STRING TypeName)
{
ULONG HeaderCharge;
/* Calculate standard header charges */
HeaderCharge = sizeof(OBJECT_HEADER) + sizeof(OBJECT_HEADER_NAME_INFO);
/* Verify if the object type requires handle count tracking */
if(Initializer->MaintainHandleCount)
{
/* Include the size of the handle information header in the total charge */
HeaderCharge += sizeof(OBJECT_HEADER_HANDLE_INFO);
}
/* Copy initialization data */
RTL::Memory::CopyMemory(&ObjectType->TypeInfo, Initializer, sizeof(OBJECT_TYPE_INITIALIZER));
/* Enforce global type list maintenance and configure the target pool type */
ObjectType->TypeInfo.MaintainTypeList = TRUE;
ObjectType->TypeInfo.PoolType = Initializer->PoolType;
/* Check pool type */
if(Initializer->PoolType == NonPagedPool)
{
/* Apply the charge to the non-paged pool requirement */
ObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderCharge;
}
else
{
/* Apply the charge to the paged pool requirement */
ObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderCharge;
}
/* Check if the caller supplied a custom procedure for security descriptor operations */
if(Initializer->SecurityProcedure == NULLPTR)
{
/* No custom procedure provided, attach the generic system handler */
ObjectType->TypeInfo.SecurityProcedure = OB::Security::ProcessObjectSecurityDescriptor;
}
/* Initialize synchronization mechanisms */
KE::PushLock::InitializePushLock(&ObjectType->TypeLock);
/* Initialize the queue for registered callbacks and the tracking list */
RTL::LinkedList::InitializeListHead(&ObjectType->CallbackList);
RTL::LinkedList::InitializeListHead(&ObjectType->TypeList);
/* Check if the object type has a default object */
if(ObjectType->TypeInfo.UseDefaultObject)
{
/* Map to the global default event and append the SYNCHRONIZE access right */
ObjectType->DefaultObject = &DefaultEvent;
ObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE;
}
else if(TypeName->Length == 8 && !RTL::WideString::CompareWideString(TypeName->Buffer, L"File", 0))
{
/* Point the synchronization offset directly to the internal Event field */
ObjectType->DefaultObject = (PVOID)(ULONG_PTR)FIELD_OFFSET(FILE_OBJECT, Event);
}
else if(TypeName->Length == 24 && !RTL::WideString::CompareWideString(TypeName->Buffer, L"WaitablePort", 0))
{
/* Point the synchronization offset directly to the WaitEvent field */
ObjectType->DefaultObject = (PVOID)(ULONG_PTR)FIELD_OFFSET(LPCP_PORT_OBJECT, WaitEvent);
}
else
{
/* Disable synchronization for this object type */
ObjectType->DefaultObject = NULLPTR;
}
}
/**
* Initializes the global Object Type Registry and bootstraps the master type object.
*
* @return This routine returns a status code indicating the success or failure of the operation.
*
* @since XT 1.0
*/
XTAPI
XTSTATUS
OB::TypeRegistry::InitializeObjectTypeRegistry(VOID)
{
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
UNICODE_STRING TypeName;
XTSTATUS Status;
/* Initialize the global directory pointer */
ObjectTypeDirectory = NULLPTR;
/* Clear the global object type lookup table and the default synchronization event block */
RTL::Memory::ZeroMemory(ObjectTypesTable, sizeof(ObjectTypesTable));
RTL::Memory::ZeroMemory(&DefaultEvent, sizeof(KEVENT));
/* Clear the initialization structure */
RTL::Memory::ZeroMemory(&ObjectTypeInitializer, sizeof(OBJECT_TYPE_INITIALIZER));
/* Configure the attributes and pool charges for the master "Type" object */
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_TYPE);
ObjectTypeInitializer.InvalidAttributes = OBJECT_OPENLINK;
ObjectTypeInitializer.Length = sizeof(OBJECT_TYPE_INITIALIZER);
ObjectTypeInitializer.MaintainTypeList = TRUE;
ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.UseDefaultObject = TRUE;
ObjectTypeInitializer.ValidAccessMask = OBJECT_TYPE_ALL_ACCESS;
/* Register default destructor */
ObjectTypeInitializer.DeleteProcedure = &DeleteObjectType;
/* Initialize the descriptor for the "Type" name */
RTL::Unicode::InitializeString(&TypeName, L"Type");
/* Create the master object type */
Status = CreateObjectType(&TypeName, &ObjectTypeInitializer, NULLPTR, &MasterObjectType);
if(Status != STATUS_SUCCESS)
{
/* Object type creation failed, return error code */
return STATUS_UNSUCCESSFUL;
}
/* Return success */
return STATUS_SUCCESS;
}
/**
* Validates the parameters supplied for creating a new object type.
*
* @param TypeName
* Supplies the requested name of the new object type.
*
* @param Initializer
* Supplies the initialization parameters for the new object type.
*
* @return This routine returns a status code indicating the success or failure of the operation.
*
* @since XT 1.0
*/
XTAPI
XTSTATUS
OB::TypeRegistry::ValidateObjectTypeParameters(IN PUNICODE_STRING TypeName,
IN POBJECT_TYPE_INITIALIZER Initializer)
{
ULONG Index;
PWCH Buffer;
/* Check the basic string validity and alignment */
if(TypeName == NULLPTR || TypeName->Length == 0 || (TypeName->Length % sizeof(WCHAR)) != 0)
{
/* Invalid type name, return error code */
return STATUS_INVALID_PARAMETER;
}
/* Check initializer block integrity and allowed flags */
if(Initializer == NULLPTR ||
(Initializer->InvalidAttributes & ~OBJECT_VALID_ATTRIBUTES) != 0 ||
Initializer->Length != sizeof(OBJECT_TYPE_INITIALIZER))
{
/* Invalid initializer block, return error code */
return STATUS_INVALID_PARAMETER;
}
/* Check the maintaining handle count and procedure presence */
if(Initializer->MaintainHandleCount &&
Initializer->OpenProcedure == NULLPTR &&
Initializer->CloseProcedure == NULLPTR)
{
/* Invalid initializer block, return error code */
return STATUS_INVALID_PARAMETER;
}
/* Validate memory pool type */
if(!Initializer->UseDefaultObject && Initializer->PoolType != NonPagedPool)
{
/* Invalid pool type, return error code */
return STATUS_INVALID_PARAMETER;
}
/* Extract the buffer pointer */
Buffer = TypeName->Buffer;
Index = TypeName->Length / sizeof(WCHAR);
/* Scan for illegal path separators in the type name */
while(Index--)
{
/* Check for path separator */
if(*Buffer++ == OBJECT_NAME_PATH_SEPARATOR)
{
/* Invalid type name, return error code */
return STATUS_OBJECT_NAME_INVALID;
}
}
/* Return success */
return STATUS_SUCCESS;
}