From 2b1ff4aa9f39698b4239604c561716cc83276681 Mon Sep 17 00:00:00 2001 From: Aiken Harris Date: Thu, 9 Jul 2026 19:16:01 +0200 Subject: [PATCH] Implement handle table management interface --- xtoskrnl/CMakeLists.txt | 1 + xtoskrnl/ex/handle.cc | 302 +++++++++++++++++++++++++++++++++ xtoskrnl/includes/ex.hh | 1 + xtoskrnl/includes/ex/handle.hh | 37 ++++ 4 files changed, 341 insertions(+) create mode 100644 xtoskrnl/ex/handle.cc create mode 100644 xtoskrnl/includes/ex/handle.hh diff --git a/xtoskrnl/CMakeLists.txt b/xtoskrnl/CMakeLists.txt index 5ed4303..c7c929d 100644 --- a/xtoskrnl/CMakeLists.txt +++ b/xtoskrnl/CMakeLists.txt @@ -16,6 +16,7 @@ list(APPEND XTOSKRNL_SOURCE ${XTOSKRNL_SOURCE_DIR}/ar/${ARCH}/traps.cc ${XTOSKRNL_SOURCE_DIR}/ex/data.cc ${XTOSKRNL_SOURCE_DIR}/ex/exports.cc + ${XTOSKRNL_SOURCE_DIR}/ex/handle.cc ${XTOSKRNL_SOURCE_DIR}/ex/laslist.cc ${XTOSKRNL_SOURCE_DIR}/ex/resource.cc ${XTOSKRNL_SOURCE_DIR}/ex/rundown.cc diff --git a/xtoskrnl/ex/handle.cc b/xtoskrnl/ex/handle.cc new file mode 100644 index 0000000..8f9744b --- /dev/null +++ b/xtoskrnl/ex/handle.cc @@ -0,0 +1,302 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ex/handle.cc + * DESCRIPTION: Handle Table management interface + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Retrieves the extended information for a specific handle table entry. + * + * @param HandleTable + * Supplies a pointer to the handle table containing the handle. + * + * @param Handle + * Supplies the handle for which the extended information is requested. + * + * @param Locked + * Specifies whether the handle table entry is currently locked by the caller. + * + * @return This routine returns a pointer to the handle table entry information, or NULL pointer if the table + * does not support extra info pages or lookup fails. + * + * @since XT 1.0 + */ +XTFASTCALL +PHANDLE_TABLE_ENTRY_INFO +EX::Handle::GetHandleInformation(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle, + IN BOOLEAN Locked) +{ + PHANDLE_TABLE_ENTRY InfoStructure, TableEntry; + PHANDLE_TABLE_ENTRY_INFO ResultInfo; + EXHANDLE BaseHandle, ExHandle; + + /* Initialize local state */ + ResultInfo = NULLPTR; + TableEntry = NULLPTR; + + /* Check if the handle table maintains extra information pages */ + if(HandleTable->ExtraInfoPages) + { + /* Check if the caller has not locked the entry */ + if(!Locked) + { + /* Acquire the lock */ + TableEntry = MapHandleToPointer(HandleTable, Handle); + if(!TableEntry) + { + /* The handle is invalid or mapping failed, return NULL pointer */ + return NULLPTR; + } + } + + /* Isolate the base index of the handle table page */ + BaseHandle.GenericHandleOverlay = Handle; + BaseHandle.Index &= ~(HANDLE_LOWLEVEL_COUNT - 1); + + /* Fetch the base information structure */ + InfoStructure = LookupHandleTableEntry(HandleTable, BaseHandle); + + /* Validate the retrieved structure */ + if(InfoStructure && + InfoStructure->NextFreeTableEntry == HANDLE_ADDITIONAL_INFO_SIGNATURE && + InfoStructure->InfoTable) + { + /* Decode the target index */ + ExHandle.GenericHandleOverlay = Handle; + + /* Resolve the information entry pointer */ + ResultInfo = &InfoStructure->InfoTable[ExHandle.Index % HANDLE_LOWLEVEL_COUNT]; + } + else + { + /* Check if locked */ + if(TableEntry) + { + /* Release the lock */ + UnlockHandleTableEntry(HandleTable, TableEntry); + } + } + } + + /* Return the information pointer */ + return ResultInfo; +} + +/** + * Acquires the lock on a handle table entry, blocking the current thread if contention occurs. + * + * @param HandleTable + * Supplies a pointer to the handle table containing the entry. + * + * @param HandleTableEntry + * Supplies a pointer to the handle table entry to lock. + * + * @return This routine returns TRUE if the lock was successfully acquired, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +EX::Handle::LockHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN PHANDLE_TABLE_ENTRY HandleTableEntry) +{ + LONG_PTR CurrentValue, NewValue, OldValue; + KPUSH_LOCK_WAIT_BLOCK WaitBlock; + + /* Enter a retry loop */ + while(TRUE) + { + /* Get the state of the entry */ + OldValue = *(VOLATILE LONG_PTR *)&HandleTableEntry->Value; + + /* Check if the entry is currently unlocked */ + if(OldValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT) + { + /* Clear the lock bit */ + NewValue = OldValue & ~EXHANDLE_TABLE_ENTRY_LOCK_BIT; + + /* Attempt to apply the lock */ + if(RTL::Atomic::CompareExchangePointer((PVOID *)&HandleTableEntry->Value, + (PVOID)NewValue, (PVOID)OldValue) == (PVOID)OldValue) + { + /* Lock acquired, return TRUE */ + return TRUE; + } + } + else + { + /* Check if the entry is completely empty */ + if(!OldValue) + { + /* Cannot proceed, return FALSE */ + return FALSE; + } + } + + /* The entry is locked by another thread, block thread */ + KE::PushLock::BlockPushLock(&HandleTable->HandleContentionEvent, &WaitBlock); + + /* Check if the entry was freed or unlocked */ + CurrentValue = *(VOLATILE LONG_PTR *)&HandleTableEntry->Value; + if(!CurrentValue || (CurrentValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT)) + { + /* The state changed, abort the wait */ + KE::PushLock::UnblockPushLock(&HandleTable->HandleContentionEvent, &WaitBlock); + } + else + { + /* The entry is locked, commit to the wait state */ + KE::Dispatcher::WaitForSingleObject(&WaitBlock.WakeEvent, Executive, KernelMode, FALSE, NULLPTR); + } + } +} + +/** + * Translates a generic handle into a pointer to its underlying handle table entry. + * + * @param HandleTable + * Supplies a pointer to the handle table performing the lookup. + * + * @param Handle + * Supplies the structured handle to be translated. + * + * @return This routine returns a pointer to the corresponding handle table entry, or NULL pointer if the handle + * is out of bounds or invalid. + * + * @since XT 1.0 + */ +XTAPI +PHANDLE_TABLE_ENTRY +EX::Handle::LookupHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN EXHANDLE Handle) +{ + PHANDLE_TABLE_ENTRY EntryTable; + ULONG MaxHandle, TableLevel; + ULONG_PTR Index, TableCode; + PVOID *DirectoryTable; + + /* Strip the tag bits */ + Handle.Value &= ~(ULONG_PTR)(HANDLE_VALUE_INCREMENT - 1); + + /* Read the maximum handle value */ + MaxHandle = *(VOLATILE ULONG *)&HandleTable->NextHandleNeedingPool; + if(Handle.Value >= MaxHandle) + { + /* Handle is out of bounds, return NULL pointer */ + return NULLPTR; + } + + /* Convert the raw handle value to an array index */ + Index = Handle.Value / HANDLE_VALUE_INCREMENT; + + /* Read the table routing state */ + TableCode = *(VOLATILE ULONG_PTR *)&HandleTable->TableCode; + + /* Extract the table depth level */ + TableLevel = (ULONG)(TableCode & HANDLE_LEVEL_CODE_MASK); + + /* Validate the structural integrity of the table */ + if(TableLevel > 2) + { + /* Invalid table level, return NULL pointer */ + return NULLPTR; + } + + /* Isolate the base address of the table */ + DirectoryTable = (PVOID *)(TableCode & ~(ULONG_PTR)HANDLE_LEVEL_CODE_MASK); + + /* Cascade through the directory levels */ + if(TableLevel == 2) + { + /* Resolve the highest level directory routing */ + DirectoryTable = (PVOID *)DirectoryTable[Index / (HANDLE_LOWLEVEL_COUNT * HANDLE_MIDLEVEL_COUNT)]; + } + if(TableLevel >= 1) + { + /* Resolve the intermediate directory routing */ + DirectoryTable = (PVOID *)DirectoryTable[(Index / HANDLE_LOWLEVEL_COUNT) % HANDLE_MIDLEVEL_COUNT]; + } + + /* Resolve the final entry page base */ + EntryTable = (PHANDLE_TABLE_ENTRY)DirectoryTable; + + /* Return the memory location of the requested handle table entry */ + return &EntryTable[Index % HANDLE_LOWLEVEL_COUNT]; +} + +/** + * Resolves a handle to its corresponding handle table entry and locks it. + * + * @param HandleTable + * Supplies a pointer to the handle table where the lookup will be performed. + * + * @param Handle + * Supplies the generic handle to map. + * + * @return This routine returns a pointer to the locked handle table entry on success, or NULL pointer on failure. + * + * @since XT 1.0 + */ +XTAPI +PHANDLE_TABLE_ENTRY +EX::Handle::MapHandleToPointer(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle) +{ + PHANDLE_TABLE_ENTRY TableEntry; + EXHANDLE LocalHandle; + + /* Assume failure initially */ + TableEntry = NULLPTR; + + /* Overlay the generic handle */ + LocalHandle.GenericHandleOverlay = Handle; + + /* Validate the handle index */ + if(LocalHandle.Index & (HANDLE_LOWLEVEL_COUNT - 1)) + { + /* Lookup the handle table entry */ + TableEntry = LookupHandleTableEntry(HandleTable, LocalHandle); + if(TableEntry) + { + /* Acquire the entry lock */ + if (!LockHandleTableEntry(HandleTable, TableEntry)) + { + /* Lock acquisition failed, reset the pointer */ + TableEntry = NULLPTR; + } + + } + } + + /* Return the table entry pointer */ + return TableEntry; +} + +/** + * Unlocks a previously locked handle table entry and wakes up any threads waiting on the table's contention event. + * + * @param HandleTable + * Supplies a pointer to the handle table containing the entry. + * + * @param HandleTableEntry + * Supplies a pointer to the handle table entry to be unlocked. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +EX::Handle::UnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN PHANDLE_TABLE_ENTRY HandleTableEntry) +{ + /* Unlock entry and signal the handle contention event */ + RTL::Atomic::Or64((VOLATILE PLONG_PTR)&HandleTableEntry->Value, (LONG_PTR)EXHANDLE_TABLE_ENTRY_LOCK_BIT); + KE::PushLock::UnblockPushLock(&HandleTable->HandleContentionEvent, NULLPTR); +} diff --git a/xtoskrnl/includes/ex.hh b/xtoskrnl/includes/ex.hh index a4c31ec..59f9a77 100644 --- a/xtoskrnl/includes/ex.hh +++ b/xtoskrnl/includes/ex.hh @@ -11,6 +11,7 @@ #include +#include #include #include #include diff --git a/xtoskrnl/includes/ex/handle.hh b/xtoskrnl/includes/ex/handle.hh new file mode 100644 index 0000000..b1e2ba6 --- /dev/null +++ b/xtoskrnl/includes/ex/handle.hh @@ -0,0 +1,37 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ex/handle.hh + * DESCRIPTION: Handle Table management interface + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_EX_HANDLE_HH +#define __XTOSKRNL_EX_HANDLE_HH + +#include + + +/* Kernel Executive */ +namespace EX +{ + class Handle + { + public: + STATIC XTFASTCALL PHANDLE_TABLE_ENTRY_INFO GetHandleInformation(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle, + IN BOOLEAN Locked); + STATIC XTAPI BOOLEAN LockHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN PHANDLE_TABLE_ENTRY HandleTableEntry); + STATIC XTAPI PHANDLE_TABLE_ENTRY MapHandleToPointer(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle); + STATIC XTAPI VOID UnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN PHANDLE_TABLE_ENTRY HandleTableEntry); + + private: + STATIC XTAPI PHANDLE_TABLE_ENTRY LookupHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN EXHANDLE Handle); + }; +} + +#endif /* __XTOSKRNL_EX_HANDLE_HH */