summaryrefslogtreecommitdiffstats
path: root/private/mvdm/suballoc
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/mvdm/suballoc
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/mvdm/suballoc')
-rw-r--r--private/mvdm/suballoc/debug.c0
-rw-r--r--private/mvdm/suballoc/foo.bar177
-rw-r--r--private/mvdm/suballoc/makefile6
-rw-r--r--private/mvdm/suballoc/sources45
-rw-r--r--private/mvdm/suballoc/suballcp.h178
-rw-r--r--private/mvdm/suballoc/suballoc.c931
-rw-r--r--private/mvdm/suballoc/suballoc.txt276
-rw-r--r--private/mvdm/suballoc/tsa.c879
8 files changed, 2492 insertions, 0 deletions
diff --git a/private/mvdm/suballoc/debug.c b/private/mvdm/suballoc/debug.c
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/private/mvdm/suballoc/debug.c
diff --git a/private/mvdm/suballoc/foo.bar b/private/mvdm/suballoc/foo.bar
new file mode 100644
index 000000000..3d869b8c9
--- /dev/null
+++ b/private/mvdm/suballoc/foo.bar
@@ -0,0 +1,177 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ suballcp.h
+
+Abstract:
+
+ This is the private include file for the suballocation
+ package.
+
+Author:
+
+ Dave Hastings (daveh) creation-date 25-Jan-1994
+
+Revision History:
+
+
+--*/
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windows.h>
+#include <malloc.h>
+#include <suballoc.h>
+
+
+//
+// Constants
+//
+
+//
+// Smallest chunk that will be sub allocated
+// 1024 was chosen currently, because that is the
+// smallest chunk XMS will allocate.
+//
+#define SUBALLOC_GRANULARITY 1024
+
+//
+// Assertions and macros
+//
+
+//
+// Force code to be stepped through
+//
+#if 0
+#define ASSERT_STEPTHROUGH DbgBreakPoint()
+#else
+#define ASSERT_STEPTHROUGH
+#endif
+
+//
+// Signature macros for SUBALLOCATION
+//
+#if DBG
+//
+// signature is "SubA"
+//
+#define INIT_SUBALLOC_SIGNATURE(p) p->Signature = (ULONG)0x41627553
+#define ASSERT_SUBALLOC(p) ASSERT((p->Signature == (ULONG)0x41627553))
+#else
+#define INIT_SUBALLOC_SIGNATURE(p)
+#define ASSERT_SUBALLOC(p)
+#endif
+
+//
+// Macro for extracting a bit from a bitfield of type char
+//
+#define GET_BIT_FROM_CHAR_ARRAY(p, i) \
+((p[i/(sizeof(UCHAR) * 8)] >> (i % (sizeof(UCHAR) * 8))) & 1)
+
+//
+// Macro for setting a bit in a bitfield of type char
+//
+#define SET_BIT_IN_CHAR_ARRAY(p, i) \
+(p[i/(sizeof(UCHAR) * 8)] |= (1 << (i % (sizeof(UCHAR) * 8))))
+
+//
+// Macro for clearing a bit in a bitfield of type char
+//
+#define CLEAR_BIT_IN_CHAR_ARRAY(p, i) \
+(p[i/(sizeof(UCHAR) * 8)] &= ~(1 << (i % (sizeof(UCHAR) * 8))))
+
+//
+// Generate a sub alloc block index from an address
+//
+#define ADDRESS_TO_BLOCK_INDEX(p, i) \
+((i - p->BaseAddress)/ SUBALLOC_GRANULARITY)
+
+//
+// Generate an address from a block index
+//
+#define BLOCK_INDEX_TO_ADDRESS(p, i) \
+(p->BaseAddress + i * SUBALLOC_GRANULARITY)
+
+// Round the allocated size to next allocation
+// granularity
+//
+#define ALLOC_ROUND(s) \
+(s + SUBALLOC_GRANULARITY - 1) / SUBALLOC_GRANULARITY
+
+//
+// Types
+//
+
+//
+// Enum for commit acctions
+//
+
+typedef enum {
+ SACommit,
+ SADecommit
+} COMMIT_ACTION;
+
+//
+// Structure for tracking the address space. Each chunk of
+// memory of SUBALLOC_GRANULARITY in size is represented by
+// a bit. Each chunk of memory of COMMIT_GRANULARITY is
+// represented by one bit of the array Allocated.
+//
+// ?? Should we add a field to indicate whether the chunk is
+// committed? We can always check for all allocated bits
+// zero, and use that as an indication that the chunk is
+// not committed.
+//
+//
+typedef struct _SubAllocation {
+#if DBG
+ ULONG Signature;
+#endif
+ PSACOMMITROUTINE CommitRoutine;
+ PSACOMMITROUTINE DecommitRoutine;
+ PSAMEMORYMOVEROUTINE MoveMemRoutine;
+ ULONG BaseAddress;
+ ULONG Size; // size in SUBALLOC_GRANULARITY
+ ULONG FirstFree; // keeps block # of first free block
+ // cuts alloc time in half
+ //
+ // bitfield with one bit per chunk. Bit set indicates
+ // allocated. Bit clear indicates free. All bits
+ // clear indicates un committed
+ //
+ UCHAR Allocated[1];
+} SUBALLOCATIONDATA, *PSUBALLOCATIONDATA;
+
+//
+// Internal Routines
+//
+BOOL
+CommitChunk(
+ PSUBALLOCATIONDATA SubAllocation,
+ ULONG StartChunk,
+ ULONG Size,
+ COMMIT_ACTION Action
+ );
+
+BOOL
+IsBlockCommitted(
+ PSUBALLOCATIONDATA SubAlloc,
+ ULONG CurrentBlock
+ );
+
+BOOL
+AllocateChunkAt(
+ PSUBALLOCATIONDATA SubAlloc,
+ ULONG Size,
+ ULONG BlockIndex
+ );
+
+BOOL
+FreeChunk(
+ PSUBALLOCATIONDATA SubAlloc,
+ ULONG Size,
+ ULONG BlockIndex
+ );
diff --git a/private/mvdm/suballoc/makefile b/private/mvdm/suballoc/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/mvdm/suballoc/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/mvdm/suballoc/sources b/private/mvdm/suballoc/sources
new file mode 100644
index 000000000..888018bdd
--- /dev/null
+++ b/private/mvdm/suballoc/sources
@@ -0,0 +1,45 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Dave Hastings (daveh) 25-Jan-1994
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+
+MAJORCOMP=mvdm
+MINORCOMP=suballoc
+
+TARGETNAME=suballoc
+
+TARGETPATH=\nt\public\sdk\lib
+
+TARGETTYPE=LIBRARY
+
+
+
+INCLUDES=..\inc
+
+SOURCES=suballoc.c
+
+C_DEFINES=-DDEV_DBG
+
+UMTYPE=console
+UMTEST=tsa
+UMLIBS=\nt\public\sdk\lib\*\suballoc.lib
diff --git a/private/mvdm/suballoc/suballcp.h b/private/mvdm/suballoc/suballcp.h
new file mode 100644
index 000000000..54c51fcb8
--- /dev/null
+++ b/private/mvdm/suballoc/suballcp.h
@@ -0,0 +1,178 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ suballcp.h
+
+Abstract:
+
+ This is the private include file for the suballocation
+ package.
+
+Author:
+
+ Dave Hastings (daveh) creation-date 25-Jan-1994
+
+Revision History:
+
+
+--*/
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windows.h>
+#include <malloc.h>
+#include <suballoc.h>
+
+
+//
+// Constants
+//
+
+//
+// Smallest chunk that will be sub allocated
+// 1024 was chosen currently, because that is the
+// smallest chunk XMS will allocate.
+//
+#define SUBALLOC_GRANULARITY 1024
+
+//
+// Assertions and macros
+//
+
+//
+// Force code to be stepped through
+//
+#if 0
+#define ASSERT_STEPTHROUGH DbgBreakPoint()
+#else
+#define ASSERT_STEPTHROUGH
+#endif
+
+//
+// Signature macros for SUBALLOCATION
+//
+#if DBG
+//
+// signature is "SubA"
+//
+#define INIT_SUBALLOC_SIGNATURE(p) p->Signature = (ULONG)0x41627553
+#define ASSERT_SUBALLOC(p) ASSERT((p->Signature == (ULONG)0x41627553))
+#else
+#define INIT_SUBALLOC_SIGNATURE(p)
+#define ASSERT_SUBALLOC(p)
+#endif
+
+//
+// Macro for extracting a bit from a bitfield of type char
+//
+#define GET_BIT_FROM_CHAR_ARRAY(p, i) \
+((p[(i)/(sizeof(UCHAR) * 8)] >> ((i) % (sizeof(UCHAR) * 8))) & 1)
+
+//
+// Macro for setting a bit in a bitfield of type char
+//
+#define SET_BIT_IN_CHAR_ARRAY(p, i) \
+(p[(i)/(sizeof(UCHAR) * 8)] |= (1 << ((i) % (sizeof(UCHAR) * 8))))
+
+//
+// Macro for clearing a bit in a bitfield of type char
+//
+#define CLEAR_BIT_IN_CHAR_ARRAY(p, i) \
+(p[(i)/(sizeof(UCHAR) * 8)] &= ~(1 << ((i) % (sizeof(UCHAR) * 8))))
+
+//
+// Generate a sub alloc block index from an address
+//
+#define ADDRESS_TO_BLOCK_INDEX(p, i) \
+((i - p->BaseAddress)/ SUBALLOC_GRANULARITY)
+
+//
+// Generate an address from a block index
+//
+#define BLOCK_INDEX_TO_ADDRESS(p, i) \
+(p->BaseAddress + (i) * SUBALLOC_GRANULARITY)
+
+// Round the allocated size to next allocation
+// granularity
+//
+#define ALLOC_ROUND(s) \
+(s + SUBALLOC_GRANULARITY - 1) / SUBALLOC_GRANULARITY
+
+//
+// Types
+//
+
+//
+// Enum for commit acctions
+//
+
+typedef enum {
+ SACommit,
+ SADecommit
+} COMMIT_ACTION;
+
+//
+// Structure for tracking the address space. Each chunk of
+// memory of SUBALLOC_GRANULARITY in size is represented by
+// a bit. Each chunk of memory of COMMIT_GRANULARITY is
+// represented by one bit of the array Allocated.
+//
+// ?? Should we add a field to indicate whether the chunk is
+// committed? We can always check for all allocated bits
+// zero, and use that as an indication that the chunk is
+// not committed.
+//
+//
+typedef struct _SubAllocation {
+#if DBG
+ ULONG Signature;
+#endif
+ PSACOMMITROUTINE CommitRoutine;
+ PSACOMMITROUTINE DecommitRoutine;
+ PSAMEMORYMOVEROUTINE MoveMemRoutine;
+ ULONG BaseAddress;
+ ULONG Size; // size in SUBALLOC_GRANULARITY
+ ULONG FirstFree; // keeps block # of first free block
+ // cuts alloc time in half
+ //
+ // bitfield with one bit per chunk. Bit set indicates
+ // allocated. Bit clear indicates free. All bits
+ // clear indicates un committed
+ //
+ UCHAR Allocated[1];
+} SUBALLOCATIONDATA, *PSUBALLOCATIONDATA;
+
+//
+// Internal Routines
+//
+BOOL
+CommitChunk(
+ PSUBALLOCATIONDATA SubAllocation,
+ ULONG StartChunk,
+ ULONG Size,
+ COMMIT_ACTION Action
+ );
+
+BOOL
+IsBlockCommitted(
+ PSUBALLOCATIONDATA SubAlloc,
+ ULONG CurrentBlock
+ );
+
+BOOL
+AllocateChunkAt(
+ PSUBALLOCATIONDATA SubAlloc,
+ ULONG Size,
+ ULONG BlockIndex,
+ BOOLEAN CheckFree
+ );
+
+BOOL
+FreeChunk(
+ PSUBALLOCATIONDATA SubAlloc,
+ ULONG Size,
+ ULONG BlockIndex
+ );
diff --git a/private/mvdm/suballoc/suballoc.c b/private/mvdm/suballoc/suballoc.c
new file mode 100644
index 000000000..c2021ec4c
--- /dev/null
+++ b/private/mvdm/suballoc/suballoc.c
@@ -0,0 +1,931 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ suballoc.c
+
+Abstract:
+
+ This module contains code for managing a paritially commited address
+ space. It handles allocation of chunks of memory smaller than the
+ commit granularity. It commits and decommits memory as needed using
+ the supplied function for committing and decommitting memory. The
+ structures used for tracking the address space are allocated outside
+ of the specified addresss space.
+
+Author:
+
+ Dave Hastings (daveh) creation-date 21-Jan-1994
+
+Notes:
+
+ Since this package does not actually access memory in the address space
+ it is managing, it will work as well with real linear addresses or
+ "Intel Addresses" such as would be encountered with the Insignia Emulator
+ on risc.
+
+Revision History:
+
+
+--*/
+#include "suballcp.h"
+
+PVOID
+SAInitialize(
+ ULONG BaseAddress,
+ ULONG Size,
+ PSACOMMITROUTINE CommitRoutine,
+ PSACOMMITROUTINE DecommitRoutine,
+ PSAMEMORYMOVEROUTINE MemoryMoveRoutine
+ )
+/*++
+
+Routine Description:
+
+ This function performs initialization of the sub allocation package
+ for the specified addresss range. It allocates the data structures
+ necessary to track the allocations
+
+Arguments:
+
+ BaseAddress -- Supplies the base address of the address space to
+ sub allocate.
+ Size -- Supplies the size in bytes of the address space to sub allocate.
+ CommitRoutine -- Supplies a pointer to the routine used to commit regions
+ of the address space.
+
+Return Value:
+
+ If the function was successful it returns a pointer to the sub-allocation
+ data structures. Otherwise it returns NULL.
+
+--*/
+{
+ PSUBALLOCATIONDATA SubAlloc;
+ ULONG SASize;
+
+ ASSERT_STEPTHROUGH;
+ //
+ // Asserts to insure that everything is as we expect it to be
+ //
+ ASSERT(((COMMIT_GRANULARITY % SUBALLOC_GRANULARITY) == 0));
+
+ //
+ // Allocate the tracking structure
+ //
+ // SUBALLOCATIONDATA is declared with 1 uchar for the bitmap.
+ // this is the reason for subtracting one from the total size
+ // calculation.
+ //
+ SASize = sizeof(SUBALLOCATIONDATA)
+ + (Size / SUBALLOC_GRANULARITY) / sizeof(UCHAR) - 1;
+
+ SubAlloc = malloc(SASize);
+
+ if (SubAlloc == NULL) {
+ return NULL;
+ }
+
+ //
+ // Initialize the structure
+ //
+ RtlZeroMemory(SubAlloc, SASize);
+
+ INIT_SUBALLOC_SIGNATURE(SubAlloc);
+ SubAlloc->BaseAddress = BaseAddress;
+ SubAlloc->Size = Size / SUBALLOC_GRANULARITY;
+ SubAlloc->CommitRoutine = CommitRoutine;
+ SubAlloc->DecommitRoutine = DecommitRoutine;
+ SubAlloc->MoveMemRoutine = MemoryMoveRoutine;
+
+ return SubAlloc;
+}
+
+BOOL
+SAQueryFree(
+ PVOID SubAllocation,
+ PULONG FreeBytes,
+ PULONG LargestFreeBlock
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the number of free bytes in the
+ sub allocated address space.
+
+Arguments:
+
+ SubAllocation -- Supplies the pointer returned by SAInitialize
+ FreeBytes -- Returns the number of free bytes
+
+Return Value:
+
+ TRUE -- if successful, and FreeBytes contains the number of free bytes.
+ FALSE otherwise
+
+--*/
+{
+ ULONG i, FreeCount;
+ PSUBALLOCATIONDATA SubAlloc;
+ ULONG TempLargest, LargestBlock;
+
+ ASSERT_STEPTHROUGH;
+
+ //
+ // Get a typed pointer
+ //
+ SubAlloc = SubAllocation;
+
+ //
+ // Make sure that we have what we think we do
+ //
+ ASSERT_SUBALLOC(SubAlloc);
+
+ //
+ // Count the free chunks and find largest block
+ //
+ FreeCount = 0;
+ LargestBlock = 0;
+ i = 0;
+ while (i < SubAlloc->Size) {
+
+ TempLargest = 0;
+ while (
+ (i < SubAlloc->Size) &&
+ (GET_BIT_FROM_CHAR_ARRAY(SubAlloc->Allocated, i) == 0)
+ ){
+ FreeCount++;
+ TempLargest++;
+ i++;
+ }
+
+ if (TempLargest > LargestBlock) {
+ LargestBlock = TempLargest;
+ }
+
+ //
+ // Skip allocated blocks
+ //
+ while (
+ (i < SubAlloc->Size) &&
+ (GET_BIT_FROM_CHAR_ARRAY(SubAlloc->Allocated, i) == 1)
+ ) {
+ i++;
+ }
+ }
+
+ *FreeBytes = FreeCount * SUBALLOC_GRANULARITY;
+ *LargestFreeBlock = LargestBlock * SUBALLOC_GRANULARITY;
+ return TRUE;
+}
+
+BOOL
+SAAllocate(
+ PVOID SubAllocation,
+ ULONG Size,
+ PULONG Address
+ )
+/*++
+
+Routine Description:
+
+ This function allocates a portion of the address space described by
+ SubAllocation. If necessary, it will commit additional blocks.
+ Size is rounded up to the next higher multiple of SUBALLOC_GRANULARITY.
+
+Arguments:
+
+ SubAllocation -- Supplies the pointer returned by SAInitialize.
+ Size -- Supplies the size in bytes of the region to allocate.
+ Address -- Returns the address of the region allocated.
+
+Return Value:
+
+ TRUE if successful. If false is returned, no address is returned.
+
+Notes:
+
+ Zero is a valid value for the returned address.
+
+--*/
+{
+ ULONG AllocateSize, i, CurrentChunk;
+ BOOL Done = FALSE;
+ PSUBALLOCATIONDATA SubAlloc;
+ BOOL Success;
+
+ ASSERT_STEPTHROUGH;
+
+ //
+ // Get a typed pointer. This allows us to avoid
+ // casting every time we access the pointer.
+ //
+ SubAlloc = SubAllocation;
+
+ ASSERT_SUBALLOC(SubAlloc);
+
+ //
+ // Round size and make into number of blocks
+ //
+ AllocateSize = ALLOC_ROUND(Size);
+
+ //
+ // Find a chunk that is free
+ //
+ // We need this loop in spite of the fact that we
+ // are keeping an index to the first free block.
+ // We update this pointer somewhat heuristically.
+ // If we allocate the first free block, we update
+ // the index to point past the block we allocated.
+ // We don't repeat the free scan however, so the
+ // index may actually point to an allocated block.
+ //
+ CurrentChunk = SubAlloc->FirstFree;
+ while (CurrentChunk < SubAlloc->Size) {
+ if (GET_BIT_FROM_CHAR_ARRAY(SubAlloc->Allocated, CurrentChunk) == 0) {
+ SubAlloc->FirstFree = CurrentChunk;
+ break;
+ }
+ CurrentChunk++;
+ }
+
+ //
+ // Find a block that is big enough
+ //
+ while (!Done && (CurrentChunk < SubAlloc->Size)){
+
+ //
+ // Search for a contiguous block large enough
+ //
+ for (i = 0; i < AllocateSize; i++){
+ //
+ // Insure we don't walk off the end of the data structure
+ //
+ if ((i + CurrentChunk) >= SubAlloc->Size){
+ CurrentChunk += i; // Satisfy termination condition
+ break;
+ }
+
+ //
+ // Check to see if this chunk is free
+ //
+ if (
+ GET_BIT_FROM_CHAR_ARRAY(
+ SubAlloc->Allocated,
+ i + CurrentChunk
+ )
+ == 0
+ ){
+ continue;
+ } else {
+ //
+ // Chunk is not free, so advance the search
+ //
+ CurrentChunk += i + 1;
+ break;
+ }
+ }
+
+ //
+ // Check to see if we found a chunk
+ //
+ if (i == AllocateSize) {
+ Done = TRUE;
+ }
+ }
+
+ //
+ // If we found the chunk, commit it (if necessary) and mark it allocated
+ //
+ // N.B. It is important to commit it first, and mark it allocated last,
+ // because we use the allocated bits to determine if the chunk is
+ // committed. If all of the allocated bits are clear, the chunk
+ // is not commited yet.
+ //
+ if (Done) {
+
+ //
+ // Allocate and commit the memory
+ //
+ Success = AllocateChunkAt(
+ SubAlloc,
+ AllocateSize,
+ CurrentChunk,
+ FALSE
+ );
+
+ if (!Success) {
+ return FALSE;
+ }
+
+ *Address = BLOCK_INDEX_TO_ADDRESS(SubAlloc, CurrentChunk);
+
+ ASSERT((SubAlloc->BaseAddress <= *Address) &&
+ ((SubAlloc->BaseAddress + SubAlloc->Size * SUBALLOC_GRANULARITY)
+ > *Address));
+#if 0
+ {
+ char Buffer[80];
+
+ sprintf(Buffer, "SAAllocate: Allocating at address %lx\n", *Address);
+ OutputDebugString(Buffer);
+ }
+#endif
+ return TRUE;
+
+ } else {
+ return FALSE;
+ }
+}
+
+BOOL
+SAFree(
+ PVOID SubAllocation,
+ ULONG Size,
+ ULONG Address
+ )
+/*++
+
+Routine Description:
+
+ This routine frees a sub-allocated chunk of memory. If the
+ entire commited block (or blocks) that the specified chunk
+ belongs to are free, the chunks are decommitted. Address is
+ rounded down to the next lower SUBALLOC_GRANULARITY boundary.
+ size is rounded up to the next higher multiple of SUBALLOC_GRANULARITY.
+
+Arguments:
+
+ SubAllocation -- Supplies the pointer returned by SAInitialize.
+ Size -- Supplies the size in bytes of the region to free.
+ Address -- Supplies the address of the region to free.
+
+Return Value:
+
+ TRUE if successful.
+
+Notes:
+
+ It is possible to free a different size at a particular
+ address than was allocated. This will not cause the
+ SubAllocation package any problems.
+
+ BUGBUG decommit error handling?
+--*/
+{
+ PSUBALLOCATIONDATA SubAlloc;
+ ULONG AllocatedSize, BaseBlock;
+
+ SubAlloc = SubAllocation;
+ ASSERT_SUBALLOC(SubAlloc);
+
+ //
+ // Make sure that the space to free is really ours
+ // (Entire block within range, and correctly aligned)
+ if (
+ (Address < SubAlloc->BaseAddress) ||
+ (Address >= (SubAlloc->BaseAddress + SubAlloc->Size * SUBALLOC_GRANULARITY)) ||
+ ((Address + Size) > (SubAlloc->BaseAddress + SubAlloc->Size * SUBALLOC_GRANULARITY)) ||
+ (Address % SUBALLOC_GRANULARITY)
+ ) {
+ return FALSE;
+ }
+
+ //
+ // Turn Address into Block #
+ //
+ BaseBlock = ADDRESS_TO_BLOCK_INDEX(SubAlloc, Address);
+
+ //
+ // Round up the size
+ //
+ AllocatedSize = ALLOC_ROUND(Size);
+
+ return FreeChunk(
+ SubAlloc,
+ AllocatedSize,
+ BaseBlock
+ );
+}
+
+BOOL
+SAReallocate(
+ PVOID SubAllocation,
+ ULONG OriginalSize,
+ ULONG OriginalAddress,
+ ULONG NewSize,
+ PULONG NewAddress
+ )
+/*++
+
+Routine Description:
+
+ This routine reallocates a sub allocated block of memory.
+ The sizes are rounded up to the next SUBALLOC_GRANULARITY.
+ The Original address is rounded down to the next SUBALLOC_GRANULARITY
+ boundary. Only min(OriginalSize, NewSize) bytes of data are copied to
+ the new block. The block changed in place if possible.
+
+ The following is an enumation of the possible successful reallocs.
+
+ 1. NewSize < OriginalSize
+ free block tail
+ 2. NewSize > OriginalSize
+ a.) Sufficient freespace at OriginalAddress + OriginalSize
+ Allocate the space at the tail of the block
+ b.) Sufficient free space at OriginalAddress - size delta
+ Allocate the space at the beginning of the block, and
+ copy the data.
+ c.) Sufficient space elsewhere in the address space
+ Allocate the space, and copy the block.
+
+ If none of the above is true, the realloc fails. The above are
+ in order of preference.
+
+Arguments:
+
+ SubAllocation -- Supplies the pointer returned by SAInitialize.
+ OriginalSize -- Supplies the old size in bytes of the block.
+ OriginalAddress -- Supplies the old address of the block.
+ NewSize -- Supplies the new size in bytes of the block.
+ NewAddress -- Returns the new address of the block.
+
+Return Value:
+
+ True if successful. If unsucessful, no allocation is changed.
+
+Notes:
+
+ If the caller does not supply the correct original size for the block,
+ some memory may be lost, and the block may be moved unnecessarily.
+
+--*/
+{
+
+ ULONG OriginalSizeBlock, NewSizeBlock, OriginalIndex;
+ ULONG AdditionalBlocks, Address;
+ BOOL Success;
+ PSUBALLOCATIONDATA SubAlloc;
+
+ SubAlloc = SubAllocation;
+ ASSERT_SUBALLOC(SubAlloc);
+
+ //
+ // Convert Sizes and address to blocks
+ //
+ OriginalSizeBlock = ALLOC_ROUND(OriginalSize);
+ NewSizeBlock = ALLOC_ROUND(NewSize);
+ OriginalIndex = ADDRESS_TO_BLOCK_INDEX(SubAlloc, OriginalAddress);
+
+ //
+ // Check to see if we are changing the size of the block
+ //
+ // N.B. Because we have rounded the numbers to an allocation
+ // boundary, the following test may succeed (correctly)
+ // even though OriginalSize != NewSize
+ //
+ if (OriginalSizeBlock == NewSizeBlock) {
+ *NewAddress = OriginalAddress;
+ return TRUE;
+ }
+
+ //
+ // Check to see if the block is getting smaller
+ //
+ if (OriginalSizeBlock > NewSizeBlock) {
+
+ //
+ // Free the tail of the block
+ //
+ Success = FreeChunk(
+ SubAlloc,
+ OriginalSizeBlock - NewSizeBlock,
+ OriginalIndex + NewSizeBlock
+ );
+
+ if (Success) {
+ *NewAddress = OriginalAddress;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ //
+ // Try to allocate the space at the end of the block
+ //
+ AdditionalBlocks = NewSizeBlock - OriginalSizeBlock;
+
+ Success = AllocateChunkAt(
+ SubAlloc,
+ AdditionalBlocks,
+ OriginalIndex + OriginalSizeBlock,
+ TRUE
+ );
+
+ //
+ // If there was space, return success
+ //
+ if (Success) {
+ *NewAddress = OriginalAddress;
+ return TRUE;
+ }
+
+ //
+ // Try to allocate space at the beginning of the block
+ //
+ Success = AllocateChunkAt(
+ SubAlloc,
+ AdditionalBlocks,
+ OriginalIndex - AdditionalBlocks,
+ TRUE
+ );
+
+ if (Success) {
+ //
+ // Move the data
+ //
+ // N.B. We can't just call RtlMoveMemory,
+ // because we don't know the correspondence
+ // between the address space we manage, and
+ // real linear addresses. In addition, for
+ // risc NTVDM, some additional work may have
+ // to be done (such as flushing caches).
+ //
+ SubAlloc->MoveMemRoutine(
+ BLOCK_INDEX_TO_ADDRESS(
+ SubAlloc,
+ (OriginalIndex - AdditionalBlocks)
+ ),
+ OriginalAddress,
+ OriginalSize
+ );
+
+ *NewAddress = BLOCK_INDEX_TO_ADDRESS(
+ SubAlloc,
+ (OriginalIndex - AdditionalBlocks)
+ );
+
+ return TRUE;
+ }
+
+ //
+ // Attempt to allocate a new block
+ //
+ Success = SAAllocate(
+ SubAlloc,
+ NewSize,
+ &Address
+ );
+
+ if (Success) {
+ //
+ // Move the data
+ //
+ // N.B. We could copy the data, but it would
+ // require one more function pointer.
+ //
+ SubAlloc->MoveMemRoutine(
+ Address,
+ OriginalAddress,
+ OriginalSize
+ );
+
+ SAFree(
+ SubAlloc,
+ OriginalSize,
+ OriginalAddress
+ );
+
+ //
+ // Indicate success
+ //
+ *NewAddress = Address;
+ return TRUE;
+ }
+
+ //
+ // All reallocation strategies failed.
+ //
+ return FALSE;
+}
+
+BOOL
+AllocateChunkAt(
+ PSUBALLOCATIONDATA SubAlloc,
+ ULONG Size,
+ ULONG BlockIndex,
+ BOOLEAN CheckFree
+ )
+/*++
+
+Routine Description:
+
+ This routine attempts to allocate the specified chunk
+ of memory. It first checks to make sure that it is
+ free.
+
+Arguments:
+
+ SubAlloc -- Supplies a pointer to the suballocation data
+ Size -- Supplies the size of the chunk to allocate
+ BlockIndex -- Supplies the index of the beginning of the block
+ to allocate
+ CheckFree -- Supplies an indication of whether to check and see
+ if the memory is free. If this routine is called from
+ SAAllocate, we know the memory is free.
+
+Return Value:
+
+ True if successful
+
+--*/
+{
+ ULONG i;
+
+ if (CheckFree) {
+ //
+ // Verify that the memory is free
+ //
+ for (i = 0; i < Size; i++){
+ //
+ // Insure we don't walk off the end of the data structure
+ //
+ if ((i + BlockIndex) >= SubAlloc->Size){
+ break;
+ }
+
+ //
+ // Check to see if this chunk is free
+ //
+ if (
+ GET_BIT_FROM_CHAR_ARRAY(
+ SubAlloc->Allocated,
+ i + BlockIndex
+ )
+ == 0
+ ){
+ continue;
+ } else {
+ //
+ // Chunk is not free
+ //
+ break;
+ }
+ }
+
+ //
+ // If the chunk is not free
+ //
+ if (i != Size) {
+ return FALSE;
+ }
+ }
+
+ //
+ // Commit the chunk
+ //
+ if (!CommitChunk(SubAlloc, BlockIndex, Size, SACommit)) {
+ return FALSE;
+ }
+
+ //
+ // Mark it as allocated
+ //
+ for (i = BlockIndex; i < BlockIndex + Size; i++) {
+ SET_BIT_IN_CHAR_ARRAY(SubAlloc->Allocated, i);
+ }
+
+ //
+ // Update the pointer to the first free block
+ //
+ if (BlockIndex == SubAlloc->FirstFree) {
+ SubAlloc->FirstFree += Size;
+ }
+
+ return TRUE;
+}
+
+
+BOOL
+FreeChunk(
+ PSUBALLOCATIONDATA SubAlloc,
+ ULONG Size,
+ ULONG BlockIndex
+ )
+/*++
+
+Routine Description:
+
+ This routine actually marks the memory as free
+ and decommits it as necessary.
+
+Arguments:
+
+ SubAlloc -- Supplies a pointer to the suballocation data
+ Size -- Supplies the size (in SUBALLOC_GRANULARITY) of the
+ region to free
+ BlockIndex -- Supplies the index of the begining of the region
+ (in SUBALLOC_GRANULARITY)
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+{
+ SUBALLOCATIONDATA LocalSubAlloc;
+ ULONG CurrentBlock;
+ BOOL Success;
+
+ //
+ // Save a copy of the suballoc data
+ //
+ LocalSubAlloc = *SubAlloc;
+
+ //
+ // reset free pointer
+ //
+ if (BlockIndex < SubAlloc->FirstFree) {
+ SubAlloc->FirstFree = BlockIndex;
+ }
+ //
+ // Mark the region as free
+ //
+ // N.B. We mark the block as free before decommitting it, because
+ // the decommit code will use the allocated bits to determine which
+ // parts can be decommitted.
+ //
+ for (CurrentBlock = BlockIndex;
+ CurrentBlock < BlockIndex + Size;
+ CurrentBlock++
+ ) {
+ CLEAR_BIT_IN_CHAR_ARRAY(SubAlloc->Allocated, CurrentBlock);
+ }
+
+ //
+ // Decommit the memory
+ //
+ Success = CommitChunk(SubAlloc, BlockIndex, Size, SADecommit);
+
+ if (!Success) {
+ *SubAlloc = LocalSubAlloc;
+ }
+
+ return Success;
+}
+
+BOOL
+CommitChunk(
+ PSUBALLOCATIONDATA SubAlloc,
+ ULONG StartChunk,
+ ULONG Size,
+ COMMIT_ACTION Action
+ )
+/*++
+
+Routine Description:
+
+ This routine commits a chunk of memory. Part or all
+ of the specified chunk may already be commited.
+
+Arguments:
+
+ SubAllocation -- Supplies a pointer to the suballocation data
+ StartChunk -- Supplies the relative start of the region to be
+ committed (in SUBALLOCATION_GRANULARITY)
+ Size -- Supplies the size of the chunk to be commited
+ (in SUBALLOCATION_GRANULARITY)
+
+Return Value:
+
+ TRUE -- If the block was successfully committed (or already committed)
+ FALSE -- Otherwise
+
+Notes:
+
+ This routine depends on the allocated bits in SubAlloc to determine
+ whether memory is committed. When memory is to be committed, CommitBlock
+ must be called before the Allocated bits are modified. When memory is
+ decommitted, the Allocated bits must be modified before CommitBlock is
+ called.
+
+--*/
+{
+ ULONG FirstBlock, LastBlock, CurrentBlock;
+ NTSTATUS Status;
+
+ ASSERT_STEPTHROUGH;
+
+ ASSERT_SUBALLOC(SubAlloc);
+
+ //
+ // Round Start down to next COMMIT_GRANULARITY and convert to block #
+ //
+ FirstBlock = (StartChunk * SUBALLOC_GRANULARITY) / COMMIT_GRANULARITY;
+
+ //
+ // Round StartChunk + size up to next COMMIT_GRANULARITY
+ //
+ LastBlock = ((StartChunk + Size) * SUBALLOC_GRANULARITY +
+ (COMMIT_GRANULARITY - 1)) / COMMIT_GRANULARITY;
+
+ for (
+ CurrentBlock = FirstBlock;
+ CurrentBlock < LastBlock;
+ CurrentBlock++
+ ) {
+
+ //
+ // If the block is not committed, either commit it or decommit it,
+ // depending on the value of Action.
+ //
+ if (!IsBlockCommitted(SubAlloc, CurrentBlock)) {
+ if (Action == SACommit) {
+
+ Status = (SubAlloc->CommitRoutine)(
+ CurrentBlock * COMMIT_GRANULARITY + SubAlloc->BaseAddress,
+ COMMIT_GRANULARITY
+ );
+
+ } else if (Action == SADecommit) {
+
+ Status = (SubAlloc->DecommitRoutine)(
+ CurrentBlock * COMMIT_GRANULARITY + SubAlloc->BaseAddress,
+ COMMIT_GRANULARITY
+ );
+
+ }
+ if (Status != STATUS_SUCCESS) {
+ //
+ // Bugbug -- decommit any blocks committed here
+ //
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+BOOL
+IsBlockCommitted(
+ PSUBALLOCATIONDATA SubAlloc,
+ ULONG Block
+ )
+/*++
+
+Routine Description:
+
+ This routine checks to see if a particular block of the
+ suballocation is committed.
+
+Arguments:
+
+ SubAlloc -- Supplies a pointer to the suballocation data
+ Block -- Supplies the number of the block to check
+
+Return Value:
+
+ TRUE -- if the block is committed
+ FALSE -- if the block is not committed
+
+Notes:
+
+ The return value is based on the state of the bits in the
+ suballocation data, not on information from the NT memory
+ manager.
+
+--*/
+{
+ BOOL Committed = FALSE;
+ ULONG i;
+
+ ASSERT_STEPTHROUGH;
+ ASSERT_SUBALLOC(SubAlloc);
+
+ //
+ // Check the bits for each of the suballoc blocks in the
+ // commit block
+ //
+ for (i = 0; i < COMMIT_GRANULARITY / SUBALLOC_GRANULARITY; i++) {
+
+ //
+ // Check to see if this suballoc block is allocated
+ //
+ if (
+ GET_BIT_FROM_CHAR_ARRAY(
+ SubAlloc->Allocated,
+ i + Block * COMMIT_GRANULARITY / SUBALLOC_GRANULARITY
+ )
+ ) {
+ Committed = TRUE;
+ break;
+ }
+ }
+
+ return Committed;
+}
+
diff --git a/private/mvdm/suballoc/suballoc.txt b/private/mvdm/suballoc/suballoc.txt
new file mode 100644
index 000000000..03dfc9813
--- /dev/null
+++ b/private/mvdm/suballoc/suballoc.txt
@@ -0,0 +1,276 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ suballoc.c
+
+Abstract:
+
+ This module contains code for managing a paritially commited address
+ space. It handles allocation of chunks of memory smaller than the
+ commit granularity. It commits and decommits memory as needed using
+ the supplied function for committing and decommitting memory. The
+ structures used for tracking the address space are allocated outside
+ of the specified addresss space.
+
+Author:
+
+ Dave Hastings (daveh) creation-date 21-Jan-1994
+
+Notes:
+
+ Since this package does not actually access memory in the address space
+ it is managing, it will work as well with real linear addresses or
+ "Intel Addresses" such as would be encountered with the Insignia Emulator
+ on risc.
+
+Revision History:
+
+
+--*/
+
+//
+// Constants
+//
+
+//
+// Smallest chunk that will be sub allocated
+// 1024 was chosen currently, because that is the
+// smallest chunk XMS will allocate.
+//
+#define SUBALLOC_GRANULARITY 1024
+
+//
+// The size of the character array require to hold the
+// bits defining whether the individual allocation entities
+// in the commited chunk are allocated or free
+//
+// BUGBUG Assert that COMMIT_GRANULARITY is a multiple of SUBALLOC_GRANULARITY
+//
+#define SUBALLOC_BITFIELD_SIZE COMMIT_GRANULARITY / SUBALLOC_GRANULARITY
+
+//
+// Types
+//
+
+//
+// Routine for committing a specific region of of the address
+// space. Although the return type is NTSTATUS, the only value
+// that is checked is 0 (for STATUS_SUCCESS). If STATUS_SUCCESS
+// is returned, it is assumed that the function worked. If not,
+// it is assumed that it failed. No special meaning is attached to
+// particular non-zero values.
+//
+typedef
+NTSTATUS
+(*PSACOMMITROUTINE)(
+ ULONG BaseAddress,
+ ULONG Size
+ );
+
+//
+// Structure for tracking the address space. Each chunk of
+// memory of SUBALLOC_GRANULARITY in size is represented by
+// a bit. Each chunk of memory of COMMIT_GRANULARITY is
+// represented by one element of the array of bitfields.
+// The FreeCheck array half of the union allows us to check
+// whether the entire committed chunk is free more quickly.
+//
+// ?? Should we add a field to indicate whether the chunk is
+// committed? We can always check for all allocated bits
+// zero, and use that as an indication that the chunk is
+// not committed.
+//
+// BUGBUG Assert that the bits fit into memory the way we think
+// they do.
+//
+typedef struct _SubAllocation {
+ PSACOMMITROUTINE CommitRoutine;
+ ULONG BaseAddress;
+ ULONG Size;
+ union {
+ //
+ // bitfield with one bit per chunk. Bit set indicates
+ // allocated. Bit clear indicates free. All bits
+ // clear indicates un committed
+ //
+ UINT Allocated[SUBALLOC_BITFIELD_SIZE] : 1;
+ //
+ // Hopefully a faster way to check all bits.
+ //
+ UINT FreeCheck[SUBALLOC_BITFIELD_SIZE / sizeof(UINT)];
+ } CommitedChunk;
+} SUBALLOCATIONDATA, *PSUBALLOCATIONDATA
+
+
+PVOID
+SAInitialize(
+ ULONG BaseAddress,
+ ULONG Size,
+ PSACOMMITROUTINE CommitRoutine
+ )
+/*++
+
+Routine Description:
+
+ This function performs initialization of the sub allocation package
+ for the specified addresss range. It allocates the data structures
+ necessary to track the allocations
+
+Arguments:
+
+ BaseAddress -- Supplies the base address of the address space to
+ sub allocate.
+ Size -- Supplies the size in bytes of the address space to sub allocate.
+ CommitRoutine -- Supplies a pointer to the routine used to commit regions
+ of the address space.
+
+Return Value:
+
+ If the function was successful it returns a pointer to the sub-allocation
+ data structures. Otherwise it returns NULL.
+
+--*/
+{
+
+}
+
+BOOL
+SAQueryFree(
+ PVOID SubAllocation,
+ PULONG FreeBytes
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the number of free bytes in the
+ sub allocated address space.
+
+Arguments:
+
+ SubAllocation -- Supplies the pointer returned by SAInitialize
+ FreeBytes -- Returns the number of free bytes
+
+Return Value:
+
+ TRUE -- if successful, and FreeBytes contains the number of free bytes.
+ FALSE otherwise
+
+--*/
+{
+
+}
+
+BOOL
+SAAllocate(
+ PVOID SubAllocation,
+ ULONG Size,
+ PULONG Address
+ )
+/*++
+
+Routine Description:
+
+ This function allocates a portion of the address space described by
+ SubAllocation. If necessary, it will commit additional blocks. Address is
+ rounded down to the next lower SUBALLOC_GRANULARITY boundary.
+ size is rounded up to the next higher multiple of SUBALLOC_GRANULARITY.
+
+Arguments:
+
+ SubAllocation -- Supplies the pointer returned by SAInitialize.
+ Size -- Supplies the size in bytes of the region to allocate.
+ Address -- Returns the address of the region allocated.
+
+Return Value:
+
+ TRUE if successful. If false is returned, no address is returned.
+
+Notes:
+
+ Zero is a valid value for the returned address.
+
+--*/
+{
+
+}
+
+BOOL
+SAFree(
+ PVOID SubAllocation,
+ ULONG Size,
+ ULONG Address
+ )
+/*++
+
+Routine Description:
+
+ This routine frees a sub-allocated chunk of memory. If the
+ entire commited block (or blocks) that the specified chunk
+ belongs to are free, the chunks are decommitted. Address is
+ rounded down to the next lower SUBALLOC_GRANULARITY boundary.
+ size is rounded up to the next higher multiple of SUBALLOC_GRANULARITY.
+
+Arguments:
+
+ SubAllocation -- Supplies the pointer returned by SAInitialize.
+ Size -- Supplies the size in bytes of the region to free.
+ Address -- Supplies the address of the region to free.
+
+Return Value:
+
+ TRUE if successful.
+
+Notes:
+
+ It is possible to free a different size at a particular
+ address than was allocated. This will not cause the
+ SubAllocation package any problems.
+
+--*/
+{
+
+}
+
+BOOL
+SAReallocate(
+ PVOID SubAllocation,
+ ULONG OriginalSize,
+ ULONG OriginalAddress,
+ ULONG NewSize,
+ PULONG NewAddress
+ )
+/*++
+
+Routine Description:
+
+ This routine reallocates a sub allocated block of memory.
+ The sizes are rounded up to the next SUBALLOC_GRANULARITY.
+ The Original address is rounded down to the next SUBALLOC_GRANULARITY
+ boundary. Only min(OriginalSize, NewSize) bytes of data are copied to
+ the new block. The block changed in place if possible.
+
+Arguments:
+
+ SubAllocation -- Supplies the pointer returned by SAInitialize.
+ OriginalSize -- Supplies the old size in bytes of the block.
+ OriginalAddress -- Supplies the old address of the block.
+ NewSize -- Supplies the new size in bytes of the block.
+ NewAddress -- Returns the new address of the block.
+
+Return Value:
+
+ True if successful. If unsucessful, no allocation is changed.
+
+Notes:
+
+ If the caller does not supply the correct original size for the block,
+ some memory may be lost, and the block may be moved unnecessarily.
+
+--*/
+{
+
+}
diff --git a/private/mvdm/suballoc/tsa.c b/private/mvdm/suballoc/tsa.c
new file mode 100644
index 000000000..8e0cbe79b
--- /dev/null
+++ b/private/mvdm/suballoc/tsa.c
@@ -0,0 +1,879 @@
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windows.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <suballoc.h>
+
+typedef struct _MemTrack *PMEMTRACK;
+
+typedef struct _MemTrack {
+ PMEMTRACK Next;
+ ULONG Address;
+ ULONG Size;
+} MEMTRACK;
+
+VOID
+SimpleTest1(
+ PVOID SA
+ );
+
+VOID
+SimpleTest2(
+ PVOID SA
+ );
+
+VOID
+SimpleTest3(
+ PVOID SA
+ );
+
+VOID
+SimpleTest4(
+ PVOID
+ );
+
+VOID
+SimpleTest5(
+ PVOID
+ );
+
+VOID
+SimpleTest6(
+ PVOID
+ );
+
+NTSTATUS
+DecommitMem(
+ ULONG BaseAddress,
+ ULONG Size
+ );
+
+NTSTATUS
+CommitMem(
+ ULONG BaseAddress,
+ ULONG Size
+ );
+
+VOID
+MoveMem(
+ ULONG Destination,
+ ULONG Source,
+ ULONG Size
+ );
+
+main(argv, argc)
+char **argv;
+int argc;
+{
+ NTSTATUS Status;
+ PVOID BaseAddress, SA;
+ ULONG Size;
+ ULONG TotalFree, LargestFree;
+ ULONG i,j;
+ BOOL Success;
+
+ //
+ // Allocate a region of memory for SA to manage
+ //
+ BaseAddress = NULL;
+ Size = 15*1024*1024 - 64 * 1024;
+ Status = NtAllocateVirtualMemory(
+ NtCurrentProcess(),
+ &BaseAddress,
+ 0,
+ &Size,
+ MEM_RESERVE,
+ PAGE_READWRITE
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ printf("Couldn't allocate memory, %lx\n", Status);
+ return(0);
+ }
+
+ //
+ // Initialize the suballocation stuff
+ //
+ SA = SAInitialize(
+ (ULONG)BaseAddress,
+ Size,
+ CommitMem,
+ DecommitMem,
+ MoveMem
+ );
+ if (SA == NULL) {
+ printf("SAInitialize Failed\n");
+ }
+
+ //
+ // Find out how much free memory we have
+ //
+ Success = SAQueryFree(
+ SA,
+ &TotalFree,
+ &LargestFree
+ );
+
+ if (!Success) {
+ printf("Could not query free\n");
+ return;
+ }
+ //
+ // Run some tests
+ //
+ SimpleTest1(SA);
+
+ //
+ // Allocate blocks spanning two commit blocks
+ //
+ SimpleTest2(SA);
+
+ //
+ // Allocate and free all of memory (twice)
+ //
+ SimpleTest3(SA);
+
+ //
+ // More complex alloc and free test
+ //
+ SimpleTest4(SA);
+
+ //
+ // Test realloc
+ //
+ SimpleTest5(SA);
+
+ //
+ // Test Queryfree
+ //
+ SimpleTest6(SA);
+
+ //
+ // Make sure we didn't leak
+ //
+ Success = SAQueryFree(
+ SA,
+ &i,
+ &j
+ );
+
+ if (!Success){
+ printf("Couldn't requery free\n");
+ return;
+ }
+
+ if ((i != TotalFree) || (j != LargestFree)) {
+ printf("We leaked\n");
+ }
+}
+
+VOID
+SimpleTest1(
+ PVOID SA
+ )
+{
+ ULONG Address;
+ BOOL Success;
+
+ Success = SAAllocate(
+ SA,
+ 50,
+ &Address
+ );
+
+ if (!Success) {
+ printf("SimpleTest1: Failed to allocate\n");
+ return;
+ }
+
+ try {
+ *((PULONG)(Address + 4)) = 1;
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ printf("SimpleTest1: Faulted accessing memory\n");
+ return;
+ }
+
+ Success = SAFree(
+ SA,
+ 50,
+ Address
+ );
+
+ if (!Success) {
+ printf("SimpleTest1: Failed to free\n");
+ return;
+ }
+
+ Success = TRUE;
+
+ try {
+ *((PULONG)Address + 4) = 1;
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ Success = FALSE;
+ }
+
+ if (Success) {
+ printf("SimpleTest1: memory not decommited\n");
+ }
+}
+
+VOID
+SimpleTest2(
+ PVOID SA
+ )
+{
+ ULONG SmallAddress, LargeAddress;
+ BOOL Success;
+
+ Success = SAAllocate(
+ SA,
+ 50,
+ &SmallAddress
+ );
+
+ if (!Success) {
+ printf("SimpleTest2: Could not alloc small block\n");
+ return;
+ }
+
+ try {
+ *((PULONG)(SmallAddress + 4)) = 1;
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ printf("SimpleTest2: small block not committed\n");
+ return;
+ }
+
+ Success = SAAllocate(
+ SA,
+ COMMIT_GRANULARITY + 50,
+ &LargeAddress
+ );
+
+ if (!Success) {
+ printf("SimpleTest2: Could not alloc large block\n");
+ return;
+ }
+
+ try {
+ *((PULONG)(LargeAddress + 4)) = 1;
+ *((PULONG)(LargeAddress + COMMIT_GRANULARITY)) = 1;
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ printf("SimpleTest2: Large block not committed\n");
+ return;
+ }
+
+ Success = SAFree(
+ SA,
+ 50,
+ SmallAddress
+ );
+
+ if (!Success) {
+ printf("SimpleTest2: failed to free small block\n");
+ return;
+ }
+
+ try {
+ *((PULONG)(LargeAddress + 4)) = 1;
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ printf("SimpleTest2: LargeBlock decommited!!\n");
+ return;
+ }
+
+ Success = SAFree(
+ SA,
+ COMMIT_GRANULARITY + 50,
+ LargeAddress
+ );
+
+ if (!Success) {
+ printf("SimpleTest2: failed to free Large block\n");
+ return;
+ }
+
+ Success = FALSE;
+ try {
+ *((PULONG)(LargeAddress + 4)) = 1;
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ Success = TRUE;
+ }
+
+ if (!Success) {
+ printf("SimpleTest2: First block not decommited\n");
+ }
+
+ Success = FALSE;
+ try {
+ *((PULONG)(LargeAddress + COMMIT_GRANULARITY + 4)) = 1;
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ Success = TRUE;
+ }
+
+ if (!Success) {
+ printf("SimpleTest2: Last block not decommited\n");
+ }
+
+}
+
+VOID
+SimpleTest3(
+ PVOID SA
+ )
+{
+ ULONG BlockCount, i, Address;
+ PMEMTRACK p, Head, f;
+ BOOL Success;
+
+ Head = NULL;
+ BlockCount = 0;
+ do {
+
+ Success = SAAllocate(
+ SA,
+ 3072,
+ &Address
+ );
+
+ if (Success) {
+ p = malloc(sizeof(MEMTRACK));
+ if (p == NULL) {
+ printf("SimpleTest3: malloc error\n");
+ return;
+ }
+ p->Next = Head;
+ p->Size = 3072;
+ p->Address = Address;
+ Head = p;
+ BlockCount++;
+ }
+ } while (Success);
+
+ try {
+ p = Head;
+ while (p != NULL) {
+ *((PULONG)(p->Address + 100)) = 1;
+ p = p->Next;
+ }
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ printf("SimpleTest3: failed first access test\n");
+ return;
+ }
+
+ p = Head;
+ while (p != NULL) {
+
+ Success = SAFree(
+ SA,
+ 3072,
+ p->Address
+ );
+
+ if (!Success) {
+ printf("SimpleTest3: Failed first free test\n");
+ return;
+ }
+ f = p;
+ p = p->Next;
+ free(f);
+ }
+
+ Head = NULL;
+
+ for (i = 0; i < BlockCount; i++) {
+
+ Success = SAAllocate(
+ SA,
+ 3072,
+ &Address
+ );
+
+ if (!Success) {
+ printf("SimpleTest3: Failed second alloc test\n");
+ return;
+ }
+
+ p = malloc(sizeof(MEMTRACK));
+ if (p == NULL) {
+ printf("SimpleTest3: malloc error\n");
+ return;
+ }
+
+ p->Next = Head;
+ p->Size = 3072;
+ p->Address = Address;
+ Head = p;
+ }
+
+ try {
+ p = Head;
+ while (p != NULL) {
+ *((PULONG)(p->Address + 100)) = 1;
+ p = p->Next;
+ }
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ printf("SimpleTest3: failed second access test\n");
+ return;
+ }
+
+ p = Head;
+ while (p != NULL) {
+
+ Success = SAFree(
+ SA,
+ 3072,
+ p->Address
+ );
+
+ if (!Success) {
+ printf("SimpleTest3: Failed second free test\n");
+ return;
+ }
+ f = p;
+ p = p->Next;
+ free(f);
+ }
+}
+
+VOID
+SimpleTest4(
+ PVOID SA
+ )
+{
+ ULONG i, Address;
+ PMEMTRACK p, Head, f;
+ BOOL Success;
+
+ Head = NULL;
+ do {
+
+ Success = SAAllocate(
+ SA,
+ 3072,
+ &Address
+ );
+
+ if (Success) {
+ p = malloc(sizeof(MEMTRACK));
+ if (p == NULL) {
+ printf("SimpleTest4: malloc error\n");
+ return;
+ }
+ p->Next = Head;
+ p->Size = 3072;
+ p->Address = Address;
+ Head = p;
+ }
+ } while (Success);
+
+ p = Head;
+ p = p->Next;
+ p = p->Next;
+
+ Success = SAFree(
+ SA,
+ 3072,
+ p->Next->Address
+ );
+
+ if (!Success) {
+ printf("SimpleTest4: could not free\n");
+ return;
+ }
+
+ f = p->Next;
+ p->Next = p->Next->Next;
+ free (f);
+
+ p = p->Next;
+ p = p->Next;
+
+ Success = SAFree(
+ SA,
+ 3072,
+ p->Next->Address
+ );
+
+ if (!Success) {
+ printf("SimpleTest4: could not free\n");
+ return;
+ }
+
+ f = p->Next;
+ p->Next = p->Next->Next;
+ free (f);
+
+ Success = SAFree(
+ SA,
+ 3072,
+ p->Next->Address
+ );
+ if (!Success) {
+ printf("SimpleTest4: could not free\n");
+ return;
+ }
+
+ f = p->Next;
+ p->Next = p->Next->Next;
+ free (f);
+
+ Success = SAAllocate(
+ SA,
+ 3072,
+ &Address
+ );
+
+ try {
+ *((PULONG)(Address + 4)) = 1;
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ printf("SimpleTest4: failed to access\n");
+ return;
+ }
+
+ if (!Success) {
+ printf("SimpleTest4: could not allocate\n");
+ return;
+ }
+
+ p = malloc(sizeof(MEMTRACK));
+ if (!p) {
+ printf("SimpleTest4: could not malloc\n");
+ return;
+ }
+
+ p->Next = Head;
+ p->Size = 3072;
+ p->Address = Address;
+ Head = p;
+
+ Success = SAAllocate(
+ SA,
+ 3072,
+ &Address
+ );
+
+ try {
+ *((PULONG)(Address + 4)) = 1;
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ printf("SimpleTest4: failed to access\n");
+ return;
+ }
+
+ if (!Success) {
+ printf("SimpleTest4: could not allocate\n");
+ return;
+ }
+
+ p = malloc(sizeof(MEMTRACK));
+ if (!p) {
+ printf("SimpleTest4: could not malloc\n");
+ return;
+ }
+
+ p->Next = Head;
+ p->Size = 3072;
+ p->Address = Address;
+ Head = p;
+
+ p = Head;
+ while (p != NULL) {
+
+ Success = SAFree(
+ SA,
+ 3072,
+ p->Address
+ );
+
+ if (!Success) {
+ printf("SimpleTest3: Failed second free test\n");
+ return;
+ }
+ f = p;
+ p = p->Next;
+ free(f);
+ }
+}
+
+VOID
+SimpleTest5(
+ PVOID SA
+ )
+{
+ ULONG Address, NewAddress;
+ ULONG Address1, Address2, Address3;
+ ULONG Size1, Size2, Size3;
+ BOOL Success;
+
+ Success = SAAllocate(
+ SA,
+ 3072,
+ &Address
+ );
+
+ if (!Success) {
+ printf("SimpleTest5: failed to allocate\n");
+ return;
+ }
+
+ Success = SAReallocate(
+ SA,
+ 3072,
+ Address,
+ 3000,
+ &NewAddress
+ );
+
+ if (!Success) {
+ printf("SimpleTest5: failed to reallocate\n");
+ return;
+ }
+
+ if (NewAddress != Address) {
+ printf("SimpleTest5: Realloc in place failed\n");
+ }
+
+ Success = SAReallocate(
+ SA,
+ 3072,
+ Address,
+ 200,
+ &NewAddress
+ );
+
+ if (!Success) {
+ printf("SimpleTest5: failed to reallocate\n");
+ return;
+ }
+
+ if (NewAddress != Address) {
+ printf("SimpleTest5: Realloc in place failed\n");
+ return;
+ }
+
+ Success = SAReallocate(
+ SA,
+ 200,
+ Address,
+ 6000,
+ &NewAddress
+ );
+
+ if (!Success) {
+ printf("SimpleTest5: failed to reallocate\n");
+ return;
+ }
+
+ if (NewAddress != Address) {
+ printf("SimpleTest5: realloc in place failed\n");
+ return;
+ }
+
+ Success = SAAllocate(
+ SA,
+ 1500,
+ &Address
+ );
+
+ if (!Success) {
+ printf("SimpleTest5: failed to allocate\n");
+ return;
+ }
+
+ Address1 = NewAddress;
+ Size1 = 6000;
+ Address2 = Address;
+ Size2 = 1500;
+
+ Success = SAReallocate(
+ SA,
+ Size1,
+ Address1,
+ 3000,
+ &NewAddress
+ );
+
+ if (!Success) {
+ printf("SimpleTest5: failed to reallocate\n");
+ return;
+ }
+
+ if (Address1 != NewAddress) {
+ printf("SimpleTest5: realloc in place failed\n");
+ return;
+ }
+ Size1= 3000;
+
+ Success = SAAllocate(
+ SA,
+ 2000,
+ &Address
+ );
+
+ if (!Success) {
+ printf("SimpleTest5: failed to allocate\n");
+ return;
+ }
+
+ Address3 = Address;
+ Size3 = 2000;
+
+ Success = SAFree(
+ SA,
+ Size1,
+ Address1
+ );
+
+ if (!Success) {
+ printf("SimpleTest5: failed to free\n");
+ return;
+ }
+
+ Success = SAReallocate(
+ SA,
+ Size3,
+ Address3,
+ 5000,
+ &Address
+ );
+
+ if (!Success) {
+ printf("SimpleTest5: failed to reallocate\n");
+ return;
+ }
+
+ Address3 = Address;
+ Size3 = 5000;
+
+ Success = SAReallocate(
+ SA,
+ Size3,
+ Address3,
+ 10000,
+ &Address
+ );
+
+ if (!Success) {
+ printf("SimpleTest5: failed to reallocate\n");
+ return;
+ }
+ Address3 = Address;
+ Size3 = 10000;
+
+ Success = SAFree(
+ SA,
+ Size2,
+ Address2
+ );
+
+ if (!Success) {
+ printf("SimpleTest5: failed to free\n");
+ return;
+ }
+
+ Success = SAFree(
+ SA,
+ Size3,
+ Address3
+ );
+
+ if (!Success) {
+ printf("SimpleTest5: failed to free\n");
+ return;
+ }
+}
+
+VOID
+SimpleTest6(
+ PVOID SA
+ )
+{
+ ULONG LargestFree, TotalFree;
+ BOOL Success;
+
+ Success = SAQueryFree(
+ SA,
+ &TotalFree,
+ &LargestFree
+ );
+
+}
+
+
+NTSTATUS
+CommitMem(
+ ULONG BaseAddress,
+ ULONG Size
+ )
+{
+ NTSTATUS Status;
+ PVOID Address;
+ ULONG size;
+
+ Address = (PVOID)BaseAddress;
+ size = Size;
+ Status = NtAllocateVirtualMemory(
+ NtCurrentProcess(),
+ &Address,
+ 0L,
+ &size,
+ MEM_COMMIT,
+ PAGE_READWRITE
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ printf(
+ "CommitMem failed to commit %lx, %lx, error %lx\n",
+ Address,
+ size,
+ Status
+ );
+ }
+
+ return Status;
+}
+
+NTSTATUS
+DecommitMem(
+ ULONG BaseAddress,
+ ULONG Size
+ )
+{
+ NTSTATUS Status;
+ PVOID Address;
+ ULONG size;
+
+ Address = (PVOID)BaseAddress;
+ size = Size;
+ Status = NtFreeVirtualMemory(
+ NtCurrentProcess(),
+ &Address,
+ &size,
+ MEM_DECOMMIT
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ printf(
+ "DecommitMem failed to decommit %lx, %lx, error %lx\n",
+ Address,
+ size,
+ Status
+ );
+ }
+
+ return Status;
+}
+
+VOID
+MoveMem(
+ ULONG Destination,
+ ULONG Source,
+ ULONG Size
+ )
+{
+ RtlMoveMemory(
+ (PVOID)Destination,
+ (PVOID)Source,
+ Size
+ );
+}