diff --git a/xtoskrnl/CMakeLists.txt b/xtoskrnl/CMakeLists.txt index 99f8b7a..10c4829 100644 --- a/xtoskrnl/CMakeLists.txt +++ b/xtoskrnl/CMakeLists.txt @@ -91,6 +91,7 @@ list(APPEND XTOSKRNL_SOURCE ${XTOSKRNL_SOURCE_DIR}/rtl/${ARCH}/dispatch.cc ${XTOSKRNL_SOURCE_DIR}/rtl/${ARCH}/exsup.cc ${XTOSKRNL_SOURCE_DIR}/rtl/${ARCH}/intrin.cc + ${XTOSKRNL_SOURCE_DIR}/rtl/${ARCH}/slist.cc ${XTOSKRNL_SOURCE_DIR}/rtl/atomic.cc ${XTOSKRNL_SOURCE_DIR}/rtl/bitmap.cc ${XTOSKRNL_SOURCE_DIR}/rtl/data.cc @@ -103,7 +104,6 @@ list(APPEND XTOSKRNL_SOURCE ${XTOSKRNL_SOURCE_DIR}/rtl/memory.cc ${XTOSKRNL_SOURCE_DIR}/rtl/rbtree.cc ${XTOSKRNL_SOURCE_DIR}/rtl/sha1.cc - ${XTOSKRNL_SOURCE_DIR}/rtl/slist.cc ${XTOSKRNL_SOURCE_DIR}/rtl/string.cc ${XTOSKRNL_SOURCE_DIR}/rtl/time.cc ${XTOSKRNL_SOURCE_DIR}/rtl/widestr.cc) diff --git a/xtoskrnl/rtl/amd64/slist.cc b/xtoskrnl/rtl/amd64/slist.cc new file mode 100644 index 0000000..97fd408 --- /dev/null +++ b/xtoskrnl/rtl/amd64/slist.cc @@ -0,0 +1,536 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/rtl/amd64/slist.cc + * DESCRIPTION: Singly linked list manipulation routines for AMD64 architecture + * DEVELOPERS: Rafal Kupiec + * Aiken Harris + */ + +#include + + +/** + * Retrieves the first entry from a singly linked list without removing it from the list. + * + * @param ListHead + * Supplies a pointer to a structure that serves as the list header. + * + * @return This routine returns a pointer to the first entry in the list, or NULLPTR if the list is empty. + * + * @since XT 1.0 + */ +XTCDECL +PSINGLE_LIST_ENTRY +RTL::SinglyList::GetFirstEntry(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* Empty list, return NULLPTR */ + return NULLPTR; + } + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Extract pointer from Region */ + return (PSINGLE_LIST_ENTRY)(ListHead->Region & ~0xFLL); + } + else + { + /* Decompress and return the pointer */ + return (PSINGLE_LIST_ENTRY)(((ULONG64)ListHead & 0xFFFFF8000000000FULL) | + ((ULONG64)ListHead->Header8.NextEntry << 4)); + } +} + +/** + * Initializes a structure representing the head of a singly linked list. + * + * @param ListHead + * Supplies a pointer to a structure that serves as the list header. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::InitializeListHead(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Initialize the singly linked list head */ + ListHead->Alignment = 0; + ListHead->Region = 0; + ListHead->Header16.HeaderType = 1; +} + +/** + * Inserts an entry at the head of a singly linked list. + * + * @param ListHead + * Supplies a pointer to the head of the list. + * + * @param Entry + * Supplies a pointer to the entry that will be inserted in the list. + * + * @return This routine returns a pointer to the original first entry in the list. + * + * @since XT 1.0 + */ +XTCDECL +PSINGLE_LIST_ENTRY +RTL::SinglyList::InsertHeadList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + PSINGLE_LIST_ENTRY OriginalEntry; + + /* Store the original first entry */ + OriginalEntry = RTL::SinglyList::GetFirstEntry(ListHead); + + /* Insert entry at the head of the list */ + Entry->Next = OriginalEntry; + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Update pointer and increment depth and sequence */ + ListHead->Region = ((ULONG64)Entry & ~0xFLL) | (ListHead->Region & 0xFLL); + ListHead->Header16.Depth++; + ListHead->Header16.Sequence++; + } + else + { + /* Update pointer and increment depth and sequence */ + ListHead->Header8.NextEntry = ((ULONG64)Entry >> 4) & 0x7FFFFFFFFFULL; + ListHead->Header8.Depth++; + ListHead->Header8.Sequence++; + } + + /* Return original first entry */ + return OriginalEntry; +} + +/** + * Inserts an entry at the tail of a singly linked list. + * + * @param ListHead + * Supplies a pointer to the head of the list. + * + * @param Entry + * Supplies a pointer to the entry that will be inserted in the list. + * + * @return This routine returns a pointer to the original last entry in the list. + * + * @since XT 1.0 + */ +XTCDECL +PSINGLE_LIST_ENTRY +RTL::SinglyList::InsertTailList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + PSINGLE_LIST_ENTRY CurrentEntry, OriginalEntry; + + /* Set Next pointer of the new entry to NULLPTR */ + Entry->Next = NULLPTR; + + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* Store the original last entry */ + OriginalEntry = NULLPTR; + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Insert entry at the head */ + ListHead->Region = ((ULONG64)Entry & ~0xFLL) | (ListHead->Region & 0xFLL); + } + else + { + /* Insert entry at the head */ + ListHead->Header8.NextEntry = ((ULONG64)Entry >> 4) & 0x7FFFFFFFFFULL; + } + } + else + { + /* Traverse the list to find the last entry */ + CurrentEntry = RTL::SinglyList::GetFirstEntry(ListHead); + while(CurrentEntry->Next != NULLPTR) + { + /* Move to the next entry */ + CurrentEntry = CurrentEntry->Next; + } + + /* Store the original last entry */ + OriginalEntry = CurrentEntry; + + /* Insert entry at the tail */ + CurrentEntry->Next = Entry; + } + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Increment list depth and sequence */ + ListHead->Header16.Depth++; + ListHead->Header16.Sequence++; + } + else + { + /* Increment list depth and sequence */ + ListHead->Header8.Depth++; + ListHead->Header8.Sequence++; + } + + /* Return original last entry */ + return OriginalEntry; +} + +/** + * Indicates whether a singly linked list structure is empty, or not initialized at all. + * + * @param ListHead + * Supplies a pointer to a structure that represents the head of the list. + * + * @return This routine returns TRUE if there are currently no entries in the list or FALSE otherwise. + * + * @since XT 1.0 + */ +XTCDECL +BOOLEAN +RTL::SinglyList::ListEmpty(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Check if the list is uninitialized */ + if(ListHead == NULLPTR) + { + /* Empty list, return TRUE */ + return TRUE; + } + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Check if the list is empty */ + return ((ListHead->Region & ~0xFLL) == 0); + } + else + { + /* Check if the list is empty */ + return (ListHead->Header8.NextEntry == 0); + } +} + +/** + * Queries the current depth (number of entries) of a singly linked list. + * + * @param ListHead + * Supplies a pointer to a structure that represents the head of the singly linked list. + * + * @return This routine returns the number of entries currently in the list, or zero if the list head is NULLPTR. + * + * @since XT 1.0 + */ +XTAPI +USHORT +RTL::SinglyList::QueryListDepth(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Check if the list head is initialized and valid */ + if(ListHead == NULLPTR) + { + /* Return zero */ + return 0; + } + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Return the list depth */ + return (USHORT)ListHead->Header16.Depth; + } + else + { + /* Return the list depth */ + return (USHORT)ListHead->Header8.Depth; + } +} + +/** + * Removes an entry from a singly linked list. + * + * @param ListHead + * Supplies a pointer to the head of the list. + * + * @param Entry + * Supplies a pointer to the entry that will be removed from the list. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::RemoveEntryList(IN PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + PSINGLE_LIST_ENTRY FirstEntry, PreviousEntry; + + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* List is empty, nothing to remove, return */ + return; + } + + /* Retrieve the first entry dynamically */ + FirstEntry = RTL::SinglyList::GetFirstEntry(ListHead); + + /* Check if the entry is the first one */ + if(FirstEntry == Entry) + { + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Remove the first entry and decrement depth */ + ListHead->Region = ((ULONG64)Entry->Next & ~0xFLL) | (ListHead->Region & 0xFLL); + ListHead->Header16.Depth--; + } + else + { + /* Remove the first entry and decrement depth */ + ListHead->Header8.NextEntry = ((ULONG64)Entry->Next >> 4) & 0x7FFFFFFFFFULL; + ListHead->Header8.Depth--; + } + + /* Nothing else to do, return */ + return; + } + + /* Find the previous entry */ + PreviousEntry = FirstEntry; + while(PreviousEntry->Next != Entry) + { + /* Move to the next entry */ + PreviousEntry = PreviousEntry->Next; + + /* Check if we reached the end of the list */ + if(PreviousEntry == NULLPTR) + { + /* Entry not found, return */ + return; + } + } + + /* Remove the entry */ + PreviousEntry->Next = Entry->Next; + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Decrement depth */ + ListHead->Header16.Depth--; + } + else + { + /* Decrement depth */ + ListHead->Header8.Depth--; + } +} + +/** + * Splices a singly linked list at the head of another list. The source list is reinitialized to empty. + * + * @param ListHead + * Supplies a pointer to a structure that represents the head of the list. + * + * @param SpliceList + * Supplies a pointer to a structure that represents the head of the list that will be spliced. + * + * @return This routine returns a pointer to the original first entry in the list. + * + * @since XT 1.0 + */ +XTCDECL +PSINGLE_LIST_ENTRY +RTL::SinglyList::SpliceHeadList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN OUT PSINGLE_LIST_HEADER SpliceList) +{ + PSINGLE_LIST_ENTRY LastEntry, OriginalEntry, SpliceFirstEntry; + + /* Store the original first entry */ + OriginalEntry = RTL::SinglyList::GetFirstEntry(ListHead); + + /* Check if the list to splice is empty */ + if(ListEmpty(SpliceList)) + { + /* Nothing to splice, return original first entry */ + return OriginalEntry; + } + + /* Find the last entry of the list to splice */ + SpliceFirstEntry = RTL::SinglyList::GetFirstEntry(SpliceList); + LastEntry = SpliceFirstEntry; + while(LastEntry->Next != NULLPTR) + { + /* Move to the next entry */ + LastEntry = LastEntry->Next; + } + + /* Splice the list at the head of destination */ + LastEntry->Next = OriginalEntry; + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Update destination list header pointers and values */ + ListHead->Region = ((ULONG64)SpliceFirstEntry & ~0xFLL) | (ListHead->Region & 0xFLL); + ListHead->Header16.Depth += RTL::SinglyList::QueryListDepth(SpliceList); + ListHead->Header16.Sequence++; + + /* Reinitialize the source list and preserve format flags */ + SpliceList->Region &= 0xFLL; + SpliceList->Header16.Depth = 0; + } + else + { + /* Update destination list header pointers and values */ + ListHead->Header8.NextEntry = ((ULONG64)SpliceFirstEntry >> 4) & 0x7FFFFFFFFFULL; + ListHead->Header8.Depth += RTL::SinglyList::QueryListDepth(SpliceList); + ListHead->Header8.Sequence++; + + /* Reinitialize the source list and preserve format flags */ + SpliceList->Header8.NextEntry = 0; + SpliceList->Header8.Depth = 0; + } + + /* Return the original first entry */ + return OriginalEntry; +} + +/** + * Splices a singly linked list at the tail of another list. The source list is reinitialized to empty. + * + * @param ListHead + * Supplies a pointer to the head of the destination list. + * + * @param SpliceList + * Supplies a pointer to the head of the list that will be spliced. + * + * @return This routine returns a pointer to the original last entry in the list. + * + * @since XT 1.0 + */ +XTCDECL +PSINGLE_LIST_ENTRY +RTL::SinglyList::SpliceTailList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN OUT PSINGLE_LIST_HEADER SpliceList) +{ + PSINGLE_LIST_ENTRY LastEntry, OriginalEntry, SpliceFirstEntry; + + /* Get the first entry of the list to splice */ + SpliceFirstEntry = RTL::SinglyList::GetFirstEntry(SpliceList); + + /* Check if the destination list is empty */ + if(ListEmpty(ListHead)) + { + /* Destination is empty, original last entry is NULLPTR */ + OriginalEntry = NULLPTR; + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Move the splice list to the destination head */ + ListHead->Region = ((ULONG64)SpliceFirstEntry & ~0xFLL) | (ListHead->Region & 0xFLL); + } + else + { + /* Move the splice list to the destination head */ + ListHead->Header8.NextEntry = ((ULONG64)SpliceFirstEntry >> 4) & 0x7FFFFFFFFFULL; + } + } + else + { + /* Find the last entry of the destination list */ + LastEntry = RTL::SinglyList::GetFirstEntry(ListHead); + while(LastEntry->Next != NULLPTR) + { + /* Move to the next entry */ + LastEntry = LastEntry->Next; + } + + /* Store the original last entry */ + OriginalEntry = LastEntry; + + /* Splice the list at the tail of destination */ + LastEntry->Next = SpliceFirstEntry; + } + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Update depth and sequence of the destination list */ + ListHead->Header16.Depth += RTL::SinglyList::QueryListDepth(SpliceList); + ListHead->Header16.Sequence++; + + /* Reinitialize the source list to empty while preserving format flags */ + SpliceList->Region &= 0xFLL; + SpliceList->Header16.Depth = 0; + } + else + { + /* Update depth and sequence of the destination list */ + ListHead->Header8.Depth += RTL::SinglyList::QueryListDepth(SpliceList); + ListHead->Header8.Sequence++; + + /* Reinitialize the source list to empty while preserving format flags */ + SpliceList->Header8.NextEntry = 0; + SpliceList->Header8.Depth = 0; + } + + /* Return the original last entry */ + return OriginalEntry; +} + +/** + * Retrieves the first entry from a singly linked list and removes it from the list. + * + * @param ListHead + * Pointer to a structure that serves as the list header. + * + * @return This routine returns a pointer to the first entry in the list, or NULLPTR if the list is empty. + * + * @since XT 1.0 + */ +XTCDECL +PSINGLE_LIST_ENTRY +RTL::SinglyList::TakeFirstEntry(IN PSINGLE_LIST_HEADER ListHead) +{ + PSINGLE_LIST_ENTRY Entry; + + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* List is empty, return NULLPTR */ + return NULLPTR; + } + + /* Get the first entry dynamically */ + Entry = RTL::SinglyList::GetFirstEntry(ListHead); + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Remove entry from the list and decrement depth */ + ListHead->Region = ((ULONG64)Entry->Next & ~0xFLL) | (ListHead->Region & 0xFLL); + ListHead->Header16.Depth--; + } + else + { + /* Remove entry from the list and decrement depth */ + ListHead->Header8.NextEntry = ((ULONG64)Entry->Next >> 4) & 0x7FFFFFFFFFULL; + ListHead->Header8.Depth--; + } + + /* Return the first entry */ + return Entry; +} diff --git a/xtoskrnl/rtl/slist.cc b/xtoskrnl/rtl/i686/slist.cc similarity index 98% rename from xtoskrnl/rtl/slist.cc rename to xtoskrnl/rtl/i686/slist.cc index 5677744..1cc2cd4 100644 --- a/xtoskrnl/rtl/slist.cc +++ b/xtoskrnl/rtl/i686/slist.cc @@ -1,8 +1,8 @@ /** * PROJECT: ExectOS * COPYRIGHT: See COPYING.md in the top level directory - * FILE: xtoskrnl/rtl/slist.cc - * DESCRIPTION: Singly linked list manipulation routines + * FILE: xtoskrnl/rtl/i686/slist.cc + * DESCRIPTION: Singly linked list manipulation routines for i686 architecture * DEVELOPERS: Rafal Kupiec */ @@ -112,7 +112,7 @@ RTL::SinglyList::InsertTailList(IN OUT PSINGLE_LIST_HEADER ListHead, if(ListEmpty(ListHead)) { /* Store the original last entry */ - OriginalEntry = ListHead->Next.Next; + OriginalEntry = NULLPTR; /* Insert entry at the head */ ListHead->Next.Next = Entry; @@ -263,7 +263,7 @@ RTL::SinglyList::SpliceHeadList(IN OUT PSINGLE_LIST_HEADER ListHead, { PSINGLE_LIST_ENTRY LastEntry, OriginalEntry; - /* Store the original last entry */ + /* Store the original first entry */ OriginalEntry = ListHead->Next.Next; /* Check if the list to splice is empty */