From 715f842445b8426c9deccf8a38674686024b8b75 Mon Sep 17 00:00:00 2001 From: Rafal Kupiec Date: Fri, 22 Mar 2024 18:53:30 +0100 Subject: [PATCH] Implement RtlClearSetBits(), RtlFindClearBits(), RtlFindSetBits() and RtlSetClearBits() routines --- sdk/xtdk/rtlfuncs.h | 24 ++++ xtoskrnl/includes/rtli.h | 14 ++ xtoskrnl/rtl/bitmap.c | 280 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 318 insertions(+) diff --git a/sdk/xtdk/rtlfuncs.h b/sdk/xtdk/rtlfuncs.h index 2e16ebaf..a7fe1988 100644 --- a/sdk/xtdk/rtlfuncs.h +++ b/sdk/xtdk/rtlfuncs.h @@ -64,6 +64,12 @@ RtlClearBits(IN PRTL_BITMAP BitMap, IN ULONG_PTR StartingIndex, IN ULONG_PTR Length); +XTAPI +ULONG +RtlClearSetBits(IN PRTL_BITMAP BitMap, + IN ULONG_PTR Length, + IN ULONG_PTR Index); + XTAPI BOOLEAN RtlCompareGuids(IN PGUID Guid1, @@ -143,6 +149,18 @@ RtlDivideLargeInteger(IN LARGE_INTEGER Dividend, IN ULONG Divisor, OUT PULONG Remainder); +XTAPI +ULONG_PTR +RtlFindClearBits(IN PRTL_BITMAP BitMap, + IN ULONG_PTR Length, + IN ULONG_PTR Index); + +XTAPI +ULONG_PTR +RtlFindSetBits(IN PRTL_BITMAP BitMap, + IN ULONG_PTR Length, + IN ULONG_PTR Index); + XTAPI XTSTATUS RtlFormatWideString(IN PRTL_PRINT_CONTEXT Context, @@ -197,6 +215,12 @@ RtlSetBits(IN PRTL_BITMAP BitMap, IN ULONG_PTR StartingIndex, IN ULONG_PTR Length); +XTAPI +ULONG +RtlSetClearBits(IN PRTL_BITMAP BitMap, + IN ULONG_PTR Length, + IN ULONG_PTR Index); + XTAPI VOID RtlSetMemory(OUT PVOID Destination, diff --git a/xtoskrnl/includes/rtli.h b/xtoskrnl/includes/rtli.h index 581d6bb0..8457e686 100644 --- a/xtoskrnl/includes/rtli.h +++ b/xtoskrnl/includes/rtli.h @@ -302,6 +302,20 @@ XTCDECL VOID RtlRemoveEntryList(IN PLIST_ENTRY Entry); +XTAPI +ULONG_PTR +RtlpCountBits(IN PRTL_BITMAP BitMap, + IN ULONG_PTR Length, + IN ULONG_PTR StartingIndex, + IN BOOLEAN SetBits); + +XTAPI +ULONG_PTR +RtlpFindBits(IN PRTL_BITMAP BitMap, + IN ULONG_PTR Length, + IN ULONG_PTR StartingIndex, + IN BOOLEAN SetBits); + XTAPI XTSTATUS RtlpFormatWideStringArgumentSpecifier(IN PRTL_PRINT_CONTEXT Context, diff --git a/xtoskrnl/rtl/bitmap.c b/xtoskrnl/rtl/bitmap.c index 04e6936b..8eec4ea5 100644 --- a/xtoskrnl/rtl/bitmap.c +++ b/xtoskrnl/rtl/bitmap.c @@ -130,6 +130,44 @@ RtlClearBits(IN PRTL_BITMAP BitMap, } } +/** + * Searches the bit map for a contiguous region of set bits and clears them. + * + * @param BitMap + * Supplies a pointer to the bit map. + * + * @param Length + * Supplies the length of contiguous region (number of set bits) to look for. + * + * @param Index + * Supplies the index of the first bit to start the search at a given position. + * + * @return This routine returns the bit map index position of the contiguous region found, or MAXULONG_PTR if not found. + * + * @since XT 1.0 + */ +XTAPI +ULONG +RtlClearSetBits(IN PRTL_BITMAP BitMap, + IN ULONG_PTR Length, + IN ULONG_PTR Index) +{ + ULONG_PTR StartingIndex; + + /* Find set bits */ + StartingIndex = RtlFindSetBits(BitMap, Length, Index); + + /* Check if set bits were found */ + if(StartingIndex != MAXULONG_PTR) + { + /* Clear bits */ + RtlClearBits(BitMap, StartingIndex, Length); + } + + /* Return position of bits found */ + return StartingIndex; +} + /** * Dumps the contents of the bit map. * @@ -156,6 +194,58 @@ RtlDumpBitMap(IN PRTL_BITMAP BitMap) } } +/** + * Searches the bit map for a contiguous region of clear bits. + * + * @param BitMap + * Supplies a pointer to the bit map. + * + * @param Length + * Supplies the length of contiguous region (number of clear bits) to look for. + * + * @param Index + * Supplies the index of the first bit to start the search at a given position. + * + * @return This routine returns the bit map index position of the contiguous region found, or MAXULONG_PTR if not found. + * + * @since NT 3.5 + */ +XTAPI +ULONG_PTR +RtlFindClearBits(IN PRTL_BITMAP BitMap, + IN ULONG_PTR Length, + IN ULONG_PTR Index) +{ + /* Find clear bits */ + return RtlpFindBits(BitMap, Length, Index, FALSE); +} + +/** + * Searches the bit map for a contiguous region of set bits. + * + * @param BitMap + * Supplies a pointer to the bit map. + * + * @param Length + * Supplies the length of contiguous region (number of set bits) to look for. + * + * @param Index + * Supplies the index of the first bit to start the search at a given position. + * + * @return This routine returns the bit map index position of the contiguous region found, or MAXULONG_PTR if not found. + * + * @since NT 3.5 + */ +XTAPI +ULONG_PTR +RtlFindSetBits(IN PRTL_BITMAP BitMap, + IN ULONG_PTR Length, + IN ULONG_PTR Index) +{ + /* Find set bits */ + return RtlpFindBits(BitMap, Length, Index, TRUE); +} + /** * Initializes a bit map. * @@ -304,6 +394,44 @@ RtlSetBits(IN PRTL_BITMAP BitMap, } } +/** + * Searches the bit map for a contiguous region of clear bits and sets them. + * + * @param BitMap + * Supplies a pointer to the bit map. + * + * @param Length + * Supplies the length of contiguous region (number of clear bits) to look for. + * + * @param Index + * Supplies the index of the first bit to start the search at a given position. + * + * @return This routine returns the bit map index position of the contiguous region found, or MAXULONG_PTR if not found. + * + * @since XT 1.0 + */ +XTAPI +ULONG +RtlSetClearBits(IN PRTL_BITMAP BitMap, + IN ULONG_PTR Length, + IN ULONG_PTR Index) +{ + ULONG_PTR StartingIndex; + + /* Find clear bits */ + StartingIndex = RtlFindClearBits(BitMap, Length, Index); + + /* Check if clear bits were found */ + if(StartingIndex != MAXULONG_PTR) + { + /* Set bits */ + RtlSetBits(BitMap, StartingIndex, Length); + } + + /* Return position of bits found */ + return StartingIndex; +} + /** * Tests a state of a single bit in the bit map. * @@ -332,3 +460,155 @@ RtlTestBit(IN PRTL_BITMAP BitMap, /* Test specified bit and return result */ return ((BitMap->Buffer[Bit / BITS_PER_LONG] >> (Bit & (BITS_PER_LONG - 1))) & 1) ? TRUE : FALSE; } + +/** + * Counts the number of either set or clear bits in the contiguous region of the bit map. + * + * @param BitMap + * Supplies a pointer to the bit map. + * + * @param Length + * Supplies the maximum length (number of bits) to count. + * + * @param StartingIndex + * Supplies the starting index of the first bit to count. + * + * @param SetBits + * Specifies whether count bits that are set or clear. + * + * @return This routine returns the number of equal bits found in the contiguous region. + * + * @since XT 1.0 + */ +XTAPI +ULONG_PTR +RtlpCountBits(IN PRTL_BITMAP BitMap, + IN ULONG_PTR Length, + IN ULONG_PTR StartingIndex, + IN BOOLEAN SetBits) +{ + PULONG_PTR Buffer, BufferEnd; + ULONG_PTR BitOffset, Size; + ULONGLONG Value; + + /* Get pointers to first and last bytes to check */ + Buffer = &BitMap->Buffer[StartingIndex / BITS_PER_LONG]; + BufferEnd = Buffer + ((Length + BITS_PER_LONG - 1) / BITS_PER_LONG); + + /* Get offset and value */ + BitOffset = StartingIndex & (BITS_PER_LONG - 1); + Value = (SetBits ? ~*Buffer : *Buffer) >> BitOffset << BitOffset; + + /* Find first bit set until the end of the buffer */ + while(!Value && Buffer + 1 < BufferEnd) + { + /* Advance buffer pointer and get value */ + Value = SetBits ? ~*(++Buffer) : *(++Buffer); + } + + /* Check if value found */ + if(!Value) + { + /* No bits found, return length */ + return Length; + } + + /* Calculate size */ + Size = ((Buffer - BitMap->Buffer) * BITS_PER_LONG) - StartingIndex + (ULONG_PTR)RtlCountTrailingZeroes64(Value); + + /* Return whatever is smaller */ + return Size > Length ? Length : Size; +} + +/** + * Searches the bit map for a contiguous region of either set or clear bits. + * + * @param BitMap + * Supplies a pointer to the bit map. + * + * @param Length + * Supplies the length (number of equal bits) to look for. + * + * @param StartingIndex + * Supplies the starting index of the first bit to start the search at a given position. + * + * @param SetBits + * Specifies whether count bits that are set or clear. + * + * @return This routine returns the bit map index position of the contiguous region found, or MAXULONG_PTR if not found. + * + * @since XT 1.0 + */ +XTAPI +ULONG_PTR +RtlpFindBits(IN PRTL_BITMAP BitMap, + IN ULONG_PTR Length, + IN ULONG_PTR StartingIndex, + IN BOOLEAN SetBits) +{ + ULONG_PTR BitMapEnd, BitOffset, Size; + ULONG Tries; + + /* Validate length */ + if(Length > BitMap->Size) + { + /* Length exceeds bit map size, return MAXULONG_PTR */ + return (ULONG_PTR)-1; + } + else if(!Length) + { + /* Length not specified, return starting index */ + return StartingIndex; + } + + /* Check if starting index is in range of bit map size */ + if(StartingIndex >= BitMap->Size) + { + /* Starting index exceeds bit map size, start from the beginning */ + StartingIndex = 0; + } + + /* Try from starting index */ + BitOffset = StartingIndex; + BitMapEnd = BitMap->Size; + + /* At least two tries are required */ + Tries = (StartingIndex != 0) + 2; + while(Tries) + { + /* Find until the end of the bit map */ + while(BitOffset + Length < BitMapEnd) + { + /* Increment offset */ + BitOffset += RtlpCountBits(BitMap, BitMap->Size - BitOffset, BitOffset, !SetBits); + if(BitOffset + Length > BitMapEnd) + { + /* No match found, break loop execution */ + break; + } + + /* Count bits in the contiguous region and check if match found */ + Size = RtlpCountBits(BitMap, Length, BitOffset, SetBits); + if(Size >= Length) + { + /* Match found, return offset */ + return BitOffset; + } + + /* Increment offset */ + BitOffset += Size; + } + + /* Try again if possible */ + Tries--; + if(Tries) + { + /* Restart from the beginning up to the starting index */ + BitOffset = 0; + BitMapEnd = StartingIndex; + } + } + + /* No match found, return MAXULONG_PTR */ + return (ULONG_PTR)-1; +}