3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/npool.c
6 * PURPOSE: Implements the kernel memory pool
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
9 * Iwan Fatahi (i_fatahi@hotmail.com)
10 * Robert Bergkvist (fragdance@hotmail.com)
13 /* INCLUDES ****************************************************************/
17 #include <internal/debug.h>
19 #ifdef ENABLE_VALIDATE_POOL
20 #define VALIDATE_POOL validate_kernel_pool()
26 #define POOL_TRACE(args...) do { DbgPrint(args); } while(0);
29 #define POOL_TRACE(args...)
35 /* avl types ****************************************************************/
38 * This declarations should be moved into a separate header file.
43 struct _NODE
* link
[2];
49 /* TYPES *******************************************************************/
51 #define BLOCK_HDR_USED_MAGIC (0xdeadbeef)
52 #define BLOCK_HDR_FREE_MAGIC (0xceadbeef)
55 * fields present at the start of a block (this is for internal use only)
57 typedef struct _BLOCK_HDR
61 struct _BLOCK_HDR
* previous
;
69 LIST_ENTRY TagListEntry
;
82 #define BLOCK_HDR_SIZE ROUND_UP(sizeof(BLOCK_HDR), MM_POOL_ALIGNMENT)
85 ExAllocateWholePageBlock(ULONG Size
);
87 ExFreeWholePageBlock(PVOID Addr
);
89 /* GLOBALS *****************************************************************/
91 extern PVOID MiNonPagedPoolStart
;
92 extern ULONG MiNonPagedPoolLength
;
95 * Head of the list of free blocks
97 static PNODE FreeBlockListRoot
= NULL
;
100 * Head of the list of in use block
102 static LIST_ENTRY UsedBlockListHead
;
104 static LIST_ENTRY AddressListHead
;
106 #ifndef WHOLE_PAGE_ALLOCATIONS
108 * Count of free blocks
110 static ULONG EiNrFreeBlocks
= 0;
113 * Count of used blocks
115 static ULONG EiNrUsedBlocks
= 0;
119 * Lock that protects the non-paged pool data structures
121 static KSPIN_LOCK MmNpoolLock
;
124 * Total memory used for free nonpaged pool blocks
126 ULONG EiFreeNonPagedPool
= 0;
129 * Total memory used for nonpaged pool blocks
131 ULONG EiUsedNonPagedPool
= 0;
133 /* Total quota for Non Paged Pool */
134 ULONG MmTotalNonPagedPoolQuota
= 0;
137 * Allocate a range of memory in the nonpaged pool
140 MiAllocNonPagedPoolRegion(unsigned int nr_pages
);
143 MiFreeNonPagedPoolRegion(PVOID Addr
, ULONG Count
, BOOLEAN Free
);
145 #ifdef TAG_STATISTICS_TRACKING
146 #define TAG_HASH_TABLE_SIZE (1024)
147 static LIST_ENTRY tag_hash_table
[TAG_HASH_TABLE_SIZE
];
148 #endif /* TAG_STATISTICS_TRACKING */
150 #ifdef WHOLE_PAGE_ALLOCATIONS
151 static RTL_BITMAP NonPagedPoolAllocMap
;
152 static ULONG NonPagedPoolAllocMapHint
;
153 static ULONG MiCurrentNonPagedPoolLength
= 0;
155 static PULONG MiNonPagedPoolAllocMap
;
156 static ULONG MiNonPagedPoolNrOfPages
;
157 #endif /* WHOLE_PAGE_ALLOCATIONS */
159 /* avl helper functions ****************************************************/
161 void DumpFreeBlockNode(PNODE p
)
163 static int count
= 0;
170 DumpFreeBlockNode(p
->link
[0]);
171 blk
= CONTAINING_RECORD(p
, BLOCK_HDR
, Free
.Node
);
172 DbgPrint("%08x %8d (%d)\n", blk
, blk
->Size
, count
);
173 DumpFreeBlockNode(p
->link
[1]);
178 void DumpFreeBlockTree(void)
180 DbgPrint("--- Begin tree ------------------\n");
181 DbgPrint("%08x\n", CONTAINING_RECORD(FreeBlockListRoot
, BLOCK_HDR
, Free
.Node
));
182 DumpFreeBlockNode(FreeBlockListRoot
);
183 DbgPrint("--- End tree --------------------\n");
186 int compare_node(PNODE p1
, PNODE p2
)
188 BLOCK_HDR
* blk1
= CONTAINING_RECORD(p1
, BLOCK_HDR
, Free
.Node
);
189 BLOCK_HDR
* blk2
= CONTAINING_RECORD(p2
, BLOCK_HDR
, Free
.Node
);
191 if (blk1
->Size
== blk2
->Size
)
204 if (blk1
->Size
< blk2
->Size
)
208 if (blk1
->Size
> blk2
->Size
)
217 int compare_value(PVOID value
, PNODE p
)
219 BLOCK_HDR
* blk
= CONTAINING_RECORD(p
, BLOCK_HDR
, Free
.Node
);
220 ULONG v
= *(PULONG
)value
;
233 /* avl functions **********************************************************/
236 * The avl functions should be moved into a separate file.
239 /* The avl_insert and avl_remove are based on libavl (library for manipulation of binary trees). */
241 void avl_insert (PNODE
* root
, PNODE n
, int (*compare
)(PNODE
, PNODE
))
243 PNODE y
; /* Top node to update balance factor, and parent. */
244 PNODE p
, q
; /* Iterator, and parent. */
245 PNODE w
; /* New root of rebalanced subtree. */
246 int dir
= 0; /* Direction to descend. */
248 n
->link
[0] = n
->link
[1] = n
->parent
= NULL
;
252 for (q
= NULL
, p
= *root
; p
!= NULL
; q
= p
, p
= p
->link
[dir
])
254 dir
= compare(n
, p
) > 0;
276 for (p
= n
; p
!= y
; p
= q
)
279 dir
= q
->link
[0] != p
;
290 if (y
->balance
== -2)
292 PNODE x
= y
->link
[0];
293 if (x
->balance
== -1)
296 y
->link
[0] = x
->link
[1];
298 x
->balance
= y
->balance
= 0;
299 x
->parent
= y
->parent
;
301 if (y
->link
[0] != NULL
)
303 y
->link
[0]->parent
= y
;
308 ASSERT(x
->balance
== +1);
310 x
->link
[1] = w
->link
[0];
312 y
->link
[0] = w
->link
[1];
314 if (w
->balance
== -1)
319 else if (w
->balance
== 0)
321 x
->balance
= y
->balance
= 0;
323 else /* |w->pavl_balance == +1| */
329 w
->parent
= y
->parent
;
330 x
->parent
= y
->parent
= w
;
331 if (x
->link
[1] != NULL
)
333 x
->link
[1]->parent
= x
;
335 if (y
->link
[0] != NULL
)
337 y
->link
[0]->parent
= y
;
341 else if (y
->balance
== +2)
343 PNODE x
= y
->link
[1];
344 if (x
->balance
== +1)
347 y
->link
[1] = x
->link
[0];
349 x
->balance
= y
->balance
= 0;
350 x
->parent
= y
->parent
;
352 if (y
->link
[1] != NULL
)
354 y
->link
[1]->parent
= y
;
359 ASSERT(x
->balance
== -1);
361 x
->link
[0] = w
->link
[1];
363 y
->link
[1] = w
->link
[0];
370 else if (w
->balance
== 0)
372 x
->balance
= y
->balance
= 0;
374 else /* |w->pavl_balance == -1| */
380 w
->parent
= y
->parent
;
381 x
->parent
= y
->parent
= w
;
382 if (x
->link
[0] != NULL
)
384 x
->link
[0]->parent
= x
;
386 if (y
->link
[1] != NULL
)
388 y
->link
[1]->parent
= y
;
396 if (w
->parent
!= NULL
)
398 w
->parent
->link
[y
!= w
->parent
->link
[0]] = w
;
408 void avl_remove (PNODE
*root
, PNODE item
, int (*compare
)(PNODE
, PNODE
))
410 PNODE p
; /* Traverses tree to find node to delete. */
411 PNODE q
; /* Parent of |p|. */
412 int dir
; /* Side of |q| on which |p| is linked. */
414 if (root
== NULL
|| *root
== NULL
)
428 dir
= compare(p
, q
) > 0;
431 if (p
->link
[1] == NULL
)
433 q
->link
[dir
] = p
->link
[0];
434 if (q
->link
[dir
] != NULL
)
436 q
->link
[dir
]->parent
= p
->parent
;
441 PNODE r
= p
->link
[1];
442 if (r
->link
[0] == NULL
)
444 r
->link
[0] = p
->link
[0];
446 r
->parent
= p
->parent
;
447 if (r
->link
[0] != NULL
)
449 r
->link
[0]->parent
= r
;
451 r
->balance
= p
->balance
;
457 PNODE s
= r
->link
[0];
458 while (s
->link
[0] != NULL
)
463 r
->link
[0] = s
->link
[1];
464 s
->link
[0] = p
->link
[0];
465 s
->link
[1] = p
->link
[1];
467 if (s
->link
[0] != NULL
)
469 s
->link
[0]->parent
= s
;
471 s
->link
[1]->parent
= s
;
472 s
->parent
= p
->parent
;
473 if (r
->link
[0] != NULL
)
475 r
->link
[0]->parent
= r
;
477 s
->balance
= p
->balance
;
483 item
->link
[0] = item
->link
[1] = item
->parent
= NULL
;
486 while (q
!= (PNODE
) root
)
490 if (y
->parent
!= NULL
)
501 dir
= q
->link
[0] != y
;
503 if (y
->balance
== +1)
507 else if (y
->balance
== +2)
509 PNODE x
= y
->link
[1];
510 if (x
->balance
== -1)
514 ASSERT(x
->balance
== -1);
516 x
->link
[0] = w
->link
[1];
518 y
->link
[1] = w
->link
[0];
520 if (w
->balance
== +1)
525 else if (w
->balance
== 0)
527 x
->balance
= y
->balance
= 0;
529 else /* |w->pavl_balance == -1| */
535 w
->parent
= y
->parent
;
536 x
->parent
= y
->parent
= w
;
537 if (x
->link
[0] != NULL
)
539 x
->link
[0]->parent
= x
;
541 if (y
->link
[1] != NULL
)
543 y
->link
[1]->parent
= y
;
549 y
->link
[1] = x
->link
[0];
551 x
->parent
= y
->parent
;
553 if (y
->link
[1] != NULL
)
555 y
->link
[1]->parent
= y
;
566 x
->balance
= y
->balance
= 0;
574 dir
= q
->link
[0] != y
;
576 if (y
->balance
== -1)
580 else if (y
->balance
== -2)
582 PNODE x
= y
->link
[0];
583 if (x
->balance
== +1)
586 ASSERT(x
->balance
== +1);
588 x
->link
[1] = w
->link
[0];
590 y
->link
[0] = w
->link
[1];
592 if (w
->balance
== -1)
597 else if (w
->balance
== 0)
599 x
->balance
= y
->balance
= 0;
601 else /* |w->pavl_balance == +1| */
607 w
->parent
= y
->parent
;
608 x
->parent
= y
->parent
= w
;
609 if (x
->link
[1] != NULL
)
611 x
->link
[1]->parent
= x
;
613 if (y
->link
[0] != NULL
)
615 y
->link
[0]->parent
= y
;
621 y
->link
[0] = x
->link
[1];
623 x
->parent
= y
->parent
;
625 if (y
->link
[0] != NULL
)
627 y
->link
[0]->parent
= y
;
638 x
->balance
= y
->balance
= 0;
648 PNODE _cdecl
avl_get_first(PNODE root
)
663 PNODE
avl_get_next(PNODE root
, PNODE p
)
678 while (q
&& q
->link
[1] == p
)
694 PNODE
avl_find_equal_or_greater(PNODE root
, ULONG size
, int (compare
)(PVOID
, PNODE
))
700 for (p
= root
; p
!= NULL
;)
702 cmp
= compare((PVOID
)&size
, p
);
716 cmp
= compare((PVOID
)&size
, p
->link
[0]);
729 /* non paged pool functions ************************************************/
731 #ifdef TAG_STATISTICS_TRACKING
733 MiRemoveFromTagHashTable(BLOCK_HDR
* block
)
735 * Remove a block from the tag hash table
738 if (block
->Used
.Tag
== 0)
743 RemoveEntryList(&block
->Used
.TagListEntry
);
747 MiAddToTagHashTable(BLOCK_HDR
* block
)
749 * Add a block to the tag hash table
754 if (block
->Used
.Tag
== 0)
759 hash
= block
->Used
.Tag
% TAG_HASH_TABLE_SIZE
;
761 InsertHeadList(&tag_hash_table
[hash
], &block
->Used
.TagListEntry
);
763 #endif /* TAG_STATISTICS_TRACKING */
765 #if defined(TAG_STATISTICS_TRACKING) && !defined(WHOLE_PAGE_ALLOCATIONS)
767 MiDumpTagStats(ULONG CurrentTag
, ULONG CurrentNrBlocks
, ULONG CurrentSize
)
771 c1
= (CHAR
)((CurrentTag
>> 24) & 0xFF);
772 c2
= (CHAR
)((CurrentTag
>> 16) & 0xFF);
773 c3
= (CHAR
)((CurrentTag
>> 8) & 0xFF);
774 c4
= (CHAR
)(CurrentTag
& 0xFF);
776 if (isprint(c1
) && isprint(c2
) && isprint(c3
) && isprint(c4
))
778 DbgPrint("Tag %x (%c%c%c%c) Blocks %d Total Size %d Average Size %d\n",
779 CurrentTag
, c4
, c3
, c2
, c1
, CurrentNrBlocks
,
780 CurrentSize
, CurrentSize
/ CurrentNrBlocks
);
784 DbgPrint("Tag %x Blocks %d Total Size %d Average Size %d\n",
785 CurrentTag
, CurrentNrBlocks
, CurrentSize
,
786 CurrentSize
/ CurrentNrBlocks
);
789 #endif /* defined(TAG_STATISTICS_TRACKING) && !defined(WHOLE_PAGE_ALLOCATIONS); */
792 MiDebugDumpNonPagedPoolStats(BOOLEAN NewOnly
)
794 #if defined(TAG_STATISTICS_TRACKING) && !defined(WHOLE_PAGE_ALLOCATIONS)
798 ULONG CurrentNrBlocks
= 0;
799 ULONG CurrentSize
= 0;
803 LIST_ENTRY tmpListHead
;
804 PLIST_ENTRY current_entry
;
806 DbgPrint("******* Dumping non paging pool stats ******\n");
809 for (i
= 0; i
< TAG_HASH_TABLE_SIZE
; i
++)
811 InitializeListHead(&tmpListHead
);
813 while (!IsListEmpty(&tag_hash_table
[i
]))
817 current_entry
= tag_hash_table
[i
].Flink
;
818 while (current_entry
!= &tag_hash_table
[i
])
820 current
= CONTAINING_RECORD(current_entry
, BLOCK_HDR
, Used
.TagListEntry
);
821 current_entry
= current_entry
->Flink
;
824 CurrentTag
= current
->Used
.Tag
;
828 if (current
->Used
.Tag
== CurrentTag
)
830 RemoveEntryList(¤t
->Used
.TagListEntry
);
831 InsertHeadList(&tmpListHead
, ¤t
->Used
.TagListEntry
);
832 if (!NewOnly
|| !current
->Used
.Dumped
)
836 CurrentSize
+= current
->Size
;
837 TotalSize
+= current
->Size
;
838 current
->Used
.Dumped
= TRUE
;
842 if (CurrentTag
!= 0 && CurrentNrBlocks
!= 0)
844 MiDumpTagStats(CurrentTag
, CurrentNrBlocks
, CurrentSize
);
847 if (!IsListEmpty(&tmpListHead
))
849 tag_hash_table
[i
].Flink
= tmpListHead
.Flink
;
850 tag_hash_table
[i
].Flink
->Blink
= &tag_hash_table
[i
];
851 tag_hash_table
[i
].Blink
= tmpListHead
.Blink
;
852 tag_hash_table
[i
].Blink
->Flink
= &tag_hash_table
[i
];
855 if (TotalBlocks
!= 0)
857 DbgPrint("TotalBlocks %d TotalSize %d AverageSize %d\n",
858 TotalBlocks
, TotalSize
, TotalSize
/ TotalBlocks
);
862 DbgPrint("TotalBlocks %d TotalSize %d\n",
863 TotalBlocks
, TotalSize
);
865 Size
= EiFreeNonPagedPool
- (MiNonPagedPoolLength
- MiNonPagedPoolNrOfPages
* PAGE_SIZE
);
866 DbgPrint("Freeblocks %d TotalFreeSize %d AverageFreeSize %d\n",
867 EiNrFreeBlocks
, Size
, EiNrFreeBlocks
? Size
/ EiNrFreeBlocks
: 0);
868 DbgPrint("***************** Dump Complete ***************\n");
869 #endif /* defined(TAG_STATISTICS_TRACKING) && !defined(WHOLE_PAGE_ALLOCATIONS) */
873 MiDebugDumpNonPagedPool(BOOLEAN NewOnly
)
875 #if defined(POOL_DEBUG_APIS) && !defined(WHOLE_PAGE_ALLOCATIONS)
877 PLIST_ENTRY current_entry
;
880 KeAcquireSpinLock(&MmNpoolLock
, &oldIrql
);
882 DbgPrint("******* Dumping non paging pool contents ******\n");
883 current_entry
= UsedBlockListHead
.Flink
;
884 while (current_entry
!= &UsedBlockListHead
)
886 current
= CONTAINING_RECORD(current_entry
, BLOCK_HDR
, Used
.ListEntry
);
887 if (!NewOnly
|| !current
->Used
.Dumped
)
891 c1
= (CHAR
)((current
->Used
.Tag
>> 24) & 0xFF);
892 c2
= (CHAR
)((current
->Used
.Tag
>> 16) & 0xFF);
893 c3
= (CHAR
)((current
->Used
.Tag
>> 8) & 0xFF);
894 c4
= (CHAR
)(current
->Used
.Tag
& 0xFF);
896 if (isprint(c1
) && isprint(c2
) && isprint(c3
) && isprint(c4
))
898 DbgPrint("Size 0x%x Tag 0x%x (%c%c%c%c) Allocator 0x%x\n",
899 current
->Size
, current
->Used
.Tag
, c4
, c3
, c2
, c1
,
900 current
->Used
.Caller
);
904 DbgPrint("Size 0x%x Tag 0x%x Allocator 0x%x\n",
905 current
->Size
, current
->Used
.Tag
, current
->Used
.Caller
);
907 current
->Used
.Dumped
= TRUE
;
909 current_entry
= current_entry
->Flink
;
911 DbgPrint("***************** Dump Complete ***************\n");
912 KeReleaseSpinLock(&MmNpoolLock
, oldIrql
);
913 #endif /* not WHOLE_PAGE_ALLOCATIONS */
916 #ifndef WHOLE_PAGE_ALLOCATIONS
918 #ifdef ENABLE_VALIDATE_POOL
919 static void validate_free_list(void)
921 * FUNCTION: Validate the integrity of the list of free blocks
925 unsigned int blocks_seen
=0;
928 p
= avl_get_first(FreeBlockListRoot
);
934 current
= CONTAINING_RECORD(p
, BLOCK_HDR
, Free
.Node
);
935 base_addr
= (PVOID
)current
;
937 if (current
->Magic
!= BLOCK_HDR_FREE_MAGIC
)
939 DbgPrint("Bad block magic (probable pool corruption) at %x\n",
941 KEBUGCHECK(/*KBUG_POOL_FREE_LIST_CORRUPT*/0);
944 if (base_addr
< MiNonPagedPoolStart
||
945 base_addr
+ BLOCK_HDR_SIZE
+ current
->Size
> MiNonPagedPoolStart
+ MiNonPagedPoolLength
)
947 DbgPrint("Block %x found outside pool area\n",current
);
948 DbgPrint("Size %d\n",current
->Size
);
949 DbgPrint("Limits are %x %x\n",MiNonPagedPoolStart
,
950 MiNonPagedPoolStart
+MiNonPagedPoolLength
);
951 KEBUGCHECK(/*KBUG_POOL_FREE_LIST_CORRUPT*/0);
954 if (blocks_seen
> EiNrFreeBlocks
)
956 DbgPrint("Too many blocks on free list\n");
957 KEBUGCHECK(/*KBUG_POOL_FREE_LIST_CORRUPT*/0);
959 p
= avl_get_next(FreeBlockListRoot
, p
);
963 static void validate_used_list(void)
965 * FUNCTION: Validate the integrity of the list of used blocks
969 PLIST_ENTRY current_entry
;
970 unsigned int blocks_seen
=0;
972 current_entry
= UsedBlockListHead
.Flink
;
973 while (current_entry
!= &UsedBlockListHead
)
977 current
= CONTAINING_RECORD(current_entry
, BLOCK_HDR
, Used
.ListEntry
);
978 base_addr
= (PVOID
)current
;
980 if (current
->Magic
!= BLOCK_HDR_USED_MAGIC
)
982 DbgPrint("Bad block magic (probable pool corruption) at %x\n",
984 KEBUGCHECK(/*KBUG_POOL_FREE_LIST_CORRUPT*/0);
986 if (base_addr
< MiNonPagedPoolStart
||
987 (base_addr
+BLOCK_HDR_SIZE
+current
->Size
) >
988 MiNonPagedPoolStart
+MiNonPagedPoolLength
)
990 DbgPrint("Block %x found outside pool area\n",current
);
991 DbgPrint("Size %d\n",current
->Size
);
992 DbgPrint("Limits are %x %x\n",MiNonPagedPoolStart
,
993 MiNonPagedPoolStart
+MiNonPagedPoolLength
);
994 KEBUGCHECK(/*KBUG_POOL_FREE_LIST_CORRUPT*/0);
997 if (blocks_seen
> EiNrUsedBlocks
)
999 DbgPrint("Too many blocks on used list\n");
1000 KEBUGCHECK(/*KBUG_POOL_FREE_LIST_CORRUPT*/0);
1002 if (current
->Used
.ListEntry
.Flink
!= &UsedBlockListHead
&&
1003 current
->Used
.ListEntry
.Flink
->Blink
!= ¤t
->Used
.ListEntry
)
1005 DbgPrint("%s:%d:Break in list (current %x next %x "
1006 "current->next->previous %x)\n",
1007 __FILE__
,__LINE__
,current
, current
->Used
.ListEntry
.Flink
,
1008 current
->Used
.ListEntry
.Flink
->Blink
);
1009 KEBUGCHECK(/*KBUG_POOL_FREE_LIST_CORRUPT*/0);
1012 current_entry
= current_entry
->Flink
;
1016 static void check_duplicates(BLOCK_HDR
* blk
)
1018 * FUNCTION: Check a block has no duplicates
1020 * blk = block to check
1021 * NOTE: Bug checks if duplicates are found
1024 char* base
= (char*)blk
;
1025 char* last
= ((char*)blk
) + BLOCK_HDR_SIZE
+ blk
->Size
;
1027 PLIST_ENTRY current_entry
;
1030 p
= avl_get_first(FreeBlockListRoot
);
1034 current
= CONTAINING_RECORD(p
, BLOCK_HDR
, Free
.Node
);
1036 if (current
->Magic
!= BLOCK_HDR_FREE_MAGIC
)
1038 DbgPrint("Bad block magic (probable pool corruption) at %x\n",
1040 KEBUGCHECK(/*KBUG_POOL_FREE_LIST_CORRUPT*/0);
1043 if ( (char*)current
> base
&& (char*)current
< last
)
1045 DbgPrint("intersecting blocks on list\n");
1046 KEBUGCHECK(/*KBUG_POOL_FREE_LIST_CORRUPT*/0);
1048 if ( (char*)current
< base
&&
1049 ((char*)current
+ current
->Size
+ BLOCK_HDR_SIZE
)
1052 DbgPrint("intersecting blocks on list\n");
1053 KEBUGCHECK(/*KBUG_POOL_FREE_LIST_CORRUPT*/0);
1055 p
= avl_get_next(FreeBlockListRoot
, p
);
1058 current_entry
= UsedBlockListHead
.Flink
;
1059 while (current_entry
!= &UsedBlockListHead
)
1061 current
= CONTAINING_RECORD(current_entry
, BLOCK_HDR
, Used
.ListEntry
);
1063 if ( (char*)current
> base
&& (char*)current
< last
)
1065 DbgPrint("intersecting blocks on list\n");
1066 KEBUGCHECK(/*KBUG_POOL_FREE_LIST_CORRUPT*/0);
1068 if ( (char*)current
< base
&&
1069 ((char*)current
+ current
->Size
+ BLOCK_HDR_SIZE
)
1072 DbgPrint("intersecting blocks on list\n");
1073 KEBUGCHECK(/*KBUG_POOL_FREE_LIST_CORRUPT*/0);
1076 current_entry
= current_entry
->Flink
;
1081 static void validate_kernel_pool(void)
1083 * FUNCTION: Checks the integrity of the kernel memory heap
1087 PLIST_ENTRY current_entry
;
1090 validate_free_list();
1091 validate_used_list();
1093 p
= avl_get_first(FreeBlockListRoot
);
1096 current
= CONTAINING_RECORD(p
, BLOCK_HDR
, Free
.Node
);
1097 check_duplicates(current
);
1098 p
= avl_get_next(FreeBlockListRoot
, p
);
1100 current_entry
= UsedBlockListHead
.Flink
;
1101 while (current_entry
!= &UsedBlockListHead
)
1103 current
= CONTAINING_RECORD(current_entry
, BLOCK_HDR
, Used
.ListEntry
);
1104 check_duplicates(current
);
1105 current_entry
= current_entry
->Flink
;
1112 free_pages(BLOCK_HDR
* blk
)
1119 end
= (ULONG
)blk
+ BLOCK_HDR_SIZE
+ blk
->Size
;
1122 * If the block doesn't contain a whole page then there is nothing to do
1124 if (PAGE_ROUND_UP(start
) >= PAGE_ROUND_DOWN(end
))
1131 static void remove_from_used_list(BLOCK_HDR
* current
)
1133 RemoveEntryList(¤t
->Used
.ListEntry
);
1134 EiUsedNonPagedPool
-= current
->Size
;
1138 static void remove_from_free_list(BLOCK_HDR
* current
)
1140 DPRINT("remove_from_free_list %d\n", current
->Size
);
1142 avl_remove(&FreeBlockListRoot
, ¤t
->Free
.Node
, compare_node
);
1144 EiFreeNonPagedPool
-= current
->Size
;
1146 DPRINT("remove_from_free_list done\n");
1149 DumpFreeBlockTree();
1154 add_to_free_list(BLOCK_HDR
* blk
)
1156 * FUNCTION: add the block to the free list (internal)
1160 BOOL UpdatePrevPtr
= FALSE
;
1162 DPRINT("add_to_free_list (%d)\n", blk
->Size
);
1166 current
= blk
->previous
;
1167 if (current
&& current
->Magic
== BLOCK_HDR_FREE_MAGIC
)
1169 remove_from_free_list(current
);
1170 current
->Size
= current
->Size
+ BLOCK_HDR_SIZE
+ blk
->Size
;
1171 current
->Magic
= BLOCK_HDR_USED_MAGIC
;
1172 memset(blk
, 0xcc, BLOCK_HDR_SIZE
);
1174 UpdatePrevPtr
= TRUE
;
1177 current
= (BLOCK_HDR
*)((char*)blk
+ BLOCK_HDR_SIZE
+ blk
->Size
);
1178 if ((char*)current
< (char*)MiNonPagedPoolStart
+ MiNonPagedPoolLength
&&
1179 current
->Magic
== BLOCK_HDR_FREE_MAGIC
)
1181 remove_from_free_list(current
);
1182 blk
->Size
+= BLOCK_HDR_SIZE
+ current
->Size
;
1183 memset(current
, 0xcc, BLOCK_HDR_SIZE
);
1184 UpdatePrevPtr
= TRUE
;
1185 current
= (BLOCK_HDR
*)((char*)blk
+ BLOCK_HDR_SIZE
+ blk
->Size
);
1187 if (UpdatePrevPtr
&&
1188 (char*)current
< (char*)MiNonPagedPoolStart
+ MiNonPagedPoolLength
)
1190 current
->previous
= blk
;
1192 DPRINT("%d\n", blk
->Size
);
1193 blk
->Magic
= BLOCK_HDR_FREE_MAGIC
;
1194 EiFreeNonPagedPool
+= blk
->Size
;
1195 avl_insert(&FreeBlockListRoot
, &blk
->Free
.Node
, compare_node
);
1197 DPRINT("add_to_free_list done\n");
1200 DumpFreeBlockTree();
1204 static void add_to_used_list(BLOCK_HDR
* blk
)
1206 * FUNCTION: add the block to the used list (internal)
1209 InsertHeadList(&UsedBlockListHead
, &blk
->Used
.ListEntry
);
1210 EiUsedNonPagedPool
+= blk
->Size
;
1214 inline static void* block_to_address(BLOCK_HDR
* blk
)
1216 * FUNCTION: Translate a block header address to the corresponding block
1217 * address (internal)
1220 return ( (void *) ((char*)blk
+ BLOCK_HDR_SIZE
));
1223 inline static BLOCK_HDR
* address_to_block(void* addr
)
1225 return (BLOCK_HDR
*)
1226 ( ((char*)addr
) - BLOCK_HDR_SIZE
);
1230 grow_block(BLOCK_HDR
* blk
, PVOID end
)
1234 ULONG_PTR StartIndex
, EndIndex
;
1237 StartIndex
= (ULONG_PTR
)(PAGE_ROUND_UP((ULONG_PTR
)blk
+ BLOCK_HDR_SIZE
- (ULONG_PTR
)MiNonPagedPoolStart
)) / PAGE_SIZE
;
1238 EndIndex
= ((ULONG_PTR
)PAGE_ROUND_UP(end
) - (ULONG_PTR
)MiNonPagedPoolStart
) / PAGE_SIZE
;
1241 for (i
= StartIndex
; i
< EndIndex
; i
++)
1243 if (!(MiNonPagedPoolAllocMap
[i
/ 32] & (1 << (i
% 32))))
1245 for (j
= i
+ 1; j
< EndIndex
&& j
- i
< 32; j
++)
1247 if (MiNonPagedPoolAllocMap
[j
/ 32] & (1 << (j
% 32)))
1252 for (k
= 0; k
< j
- i
; k
++)
1254 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Page
[k
]);
1255 if (!NT_SUCCESS(Status
))
1257 for (i
= 0; i
< k
; i
++)
1259 MmReleasePageMemoryConsumer(MC_NPPOOL
, Page
[i
]);
1264 Status
= MmCreateVirtualMapping(NULL
,
1265 (PVOID
)((ULONG_PTR
)MiNonPagedPoolStart
+ i
* PAGE_SIZE
),
1266 PAGE_READWRITE
|PAGE_SYSTEM
,
1269 if (!NT_SUCCESS(Status
))
1271 for (i
= 0; i
< k
; i
++)
1273 MmReleasePageMemoryConsumer(MC_NPPOOL
, Page
[i
]);
1277 for (j
= i
; j
< k
+ i
; j
++)
1279 MiNonPagedPoolAllocMap
[j
/ 32] |= (1 << (j
% 32));
1281 MiNonPagedPoolNrOfPages
+= k
;
1288 static BLOCK_HDR
* get_block(unsigned int size
, unsigned long alignment
)
1290 BLOCK_HDR
*blk
, *current
, *previous
= NULL
, *next
= NULL
, *best
= NULL
;
1291 ULONG previous_size
= 0, current_size
, next_size
= 0, new_size
;
1293 PVOID addr
, aligned_addr
;
1296 DPRINT("get_block %d\n", size
);
1300 p
= avl_find_equal_or_greater(FreeBlockListRoot
, size
, compare_value
);
1303 best
= CONTAINING_RECORD(p
, BLOCK_HDR
, Free
.Node
);
1304 addr
= block_to_address(best
);
1309 p
= avl_find_equal_or_greater(FreeBlockListRoot
, size
, compare_value
);
1313 current
= CONTAINING_RECORD(p
, BLOCK_HDR
, Free
.Node
);
1314 addr
= block_to_address(current
);
1315 /* calculate first aligned address available within this block */
1316 aligned_addr
= MM_ROUND_UP(addr
, alignment
);
1317 /* check to see if this address is already aligned */
1318 if (addr
== aligned_addr
)
1320 if (current
->Size
>= size
&&
1321 (best
== NULL
|| current
->Size
< best
->Size
))
1328 /* make sure there's enough room to make a free block by the space skipped
1329 * from alignment. If not, calculate forward to the next alignment
1330 * and see if we allocate there...
1332 new_size
= (ULONG_PTR
)aligned_addr
- (ULONG_PTR
)addr
+ size
;
1333 if ((ULONG_PTR
)aligned_addr
- (ULONG_PTR
)addr
< BLOCK_HDR_SIZE
)
1335 /* not enough room for a free block header, add some more bytes */
1336 aligned_addr
= MM_ROUND_UP(block_to_address((BLOCK_HDR
*)((char*)current
+ BLOCK_HDR_SIZE
)), alignment
);
1337 new_size
= (ULONG_PTR
)aligned_addr
- (ULONG_PTR
)addr
+ size
;
1339 if (current
->Size
>= new_size
&&
1340 (best
== NULL
|| current
->Size
< best
->Size
))
1345 if (best
&& current
->Size
>= size
+ alignment
+ 2 * BLOCK_HDR_SIZE
)
1349 p
= avl_get_next(FreeBlockListRoot
, p
);
1355 * We didn't find anything suitable at all.
1363 current_size
= current
->Size
;
1367 addr
= block_to_address(current
);
1368 aligned_addr
= MM_ROUND_UP(addr
, alignment
);
1369 if (addr
!= aligned_addr
)
1371 blk
= address_to_block(aligned_addr
);
1372 if ((char*)blk
< (char*)current
+ BLOCK_HDR_SIZE
)
1374 aligned_addr
= MM_ROUND_UP(block_to_address((BLOCK_HDR
*)((char*)current
+ BLOCK_HDR_SIZE
)), alignment
);
1375 blk
= address_to_block(aligned_addr
);
1378 * if size-aligned, break off the preceding bytes into their own block...
1381 previous_size
= (ULONG_PTR
)blk
- (ULONG_PTR
)previous
- BLOCK_HDR_SIZE
;
1383 current_size
-= ((ULONG_PTR
)current
- (ULONG_PTR
)previous
);
1387 end
= (char*)current
+ BLOCK_HDR_SIZE
+ size
;
1389 if (current_size
>= size
+ BLOCK_HDR_SIZE
+ MM_POOL_ALIGNMENT
)
1391 /* create a new free block after our block, if the memory size is >= 4 byte for this block */
1392 next
= (BLOCK_HDR
*)((ULONG_PTR
)current
+ size
+ BLOCK_HDR_SIZE
);
1393 next_size
= current_size
- size
- BLOCK_HDR_SIZE
;
1394 current_size
= size
;
1395 end
= (char*)next
+ BLOCK_HDR_SIZE
;
1400 remove_from_free_list(previous
);
1401 if (!grow_block(previous
, end
))
1403 add_to_free_list(previous
);
1406 memset(current
, 0, BLOCK_HDR_SIZE
);
1407 current
->Size
= current_size
;
1408 current
->Magic
= BLOCK_HDR_USED_MAGIC
;
1409 current
->previous
= previous
;
1410 previous
->Size
= previous_size
;
1413 blk
= (BLOCK_HDR
*)((char*)current
+ BLOCK_HDR_SIZE
+ current
->Size
);
1414 if ((char*)blk
< (char*)MiNonPagedPoolStart
+ MiNonPagedPoolLength
)
1416 blk
->previous
= current
;
1420 add_to_free_list(previous
);
1424 remove_from_free_list(current
);
1426 if (!grow_block(current
, end
))
1428 add_to_free_list(current
);
1432 current
->Magic
= BLOCK_HDR_USED_MAGIC
;
1435 current
->Size
= current_size
;
1441 memset(next
, 0, BLOCK_HDR_SIZE
);
1443 next
->Size
= next_size
;
1444 next
->Magic
= BLOCK_HDR_FREE_MAGIC
;
1445 next
->previous
= current
;
1446 blk
= (BLOCK_HDR
*)((char*)next
+ BLOCK_HDR_SIZE
+ next
->Size
);
1447 if ((char*)blk
< (char*)MiNonPagedPoolStart
+ MiNonPagedPoolLength
)
1449 blk
->previous
= next
;
1451 add_to_free_list(next
);
1454 add_to_used_list(current
);
1459 #endif /* not WHOLE_PAGE_ALLOCATIONS */
1462 ExRosQueryNonPagedPoolTag ( PVOID Addr
)
1464 #ifdef WHOLE_PAGE_ALLOCATIONS /* WHOLE_PAGE_ALLOCATIONS */
1469 #else /* not WHOLE_PAGE_ALLOCATIONS */
1471 BLOCK_HDR
* blk
=address_to_block(Addr
);
1473 if (blk
->Magic
!= BLOCK_HDR_USED_MAGIC
)
1475 if (blk
->Magic
== BLOCK_HDR_FREE_MAGIC
)
1478 return blk
->Used
.Tag
;
1480 #endif /* WHOLE_PAGE_ALLOCATIONS */
1483 VOID STDCALL
ExFreeNonPagedPool (PVOID block
)
1485 * FUNCTION: Releases previously allocated memory
1487 * block = block to free
1490 #ifdef WHOLE_PAGE_ALLOCATIONS /* WHOLE_PAGE_ALLOCATIONS */
1498 DPRINT("freeing block %x\n",block
);
1500 POOL_TRACE("ExFreePool(block %x), size %d, caller %x\n",block
,blk
->size
,
1501 ((PULONG
)&block
)[-1]);
1503 KeAcquireSpinLock(&MmNpoolLock
, &oldIrql
);
1505 ExFreeWholePageBlock(block
);
1506 KeReleaseSpinLock(&MmNpoolLock
, oldIrql
);
1508 #else /* not WHOLE_PAGE_ALLOCATIONS */
1510 BLOCK_HDR
* blk
=address_to_block(block
);
1518 DPRINT("freeing block %x\n",blk
);
1520 POOL_TRACE("ExFreePool(block %x), size %d, caller %x\n",block
,blk
->Size
,
1521 ((PULONG
)&block
)[-1]);
1523 KeAcquireSpinLock(&MmNpoolLock
, &oldIrql
);
1527 if (blk
->Magic
!= BLOCK_HDR_USED_MAGIC
)
1529 if (blk
->Magic
== BLOCK_HDR_FREE_MAGIC
)
1531 DbgPrint("ExFreePool of already freed address %x\n", block
);
1535 DbgPrint("ExFreePool of non-allocated address %x (magic %x)\n",
1542 memset(block
, 0xcc, blk
->Size
);
1543 #ifdef TAG_STATISTICS_TRACKING
1545 MiRemoveFromTagHashTable(blk
);
1548 remove_from_used_list(blk
);
1549 blk
->Magic
= BLOCK_HDR_FREE_MAGIC
;
1550 add_to_free_list(blk
);
1552 KeReleaseSpinLock(&MmNpoolLock
, oldIrql
);
1554 #endif /* WHOLE_PAGE_ALLOCATIONS */
1558 ExAllocateNonPagedPoolWithTag(POOL_TYPE Type
, ULONG Size
, ULONG Tag
, PVOID Caller
)
1560 #ifdef WHOLE_PAGE_ALLOCATIONS
1564 ASSERT_IRQL(DISPATCH_LEVEL
);
1566 POOL_TRACE("ExAllocatePool(NumberOfBytes %d) caller %x ",
1569 KeAcquireSpinLock(&MmNpoolLock
, &oldIrql
);
1572 * accomodate this useful idiom
1576 POOL_TRACE("= NULL\n");
1577 KeReleaseSpinLock(&MmNpoolLock
, oldIrql
);
1581 block
= ExAllocateWholePageBlock(Size
);
1582 KeReleaseSpinLock(&MmNpoolLock
, oldIrql
);
1585 DPRINT1("Trying to allocate %lu bytes from nonpaged pool - nothing suitable found, returning NULL\n",
1590 #else /* not WHOLE_PAGE_ALLOCATIONS */
1593 BLOCK_HDR
* best
= NULL
;
1597 POOL_TRACE("ExAllocatePool(NumberOfBytes %d) caller %x ",
1600 KeAcquireSpinLock(&MmNpoolLock
, &oldIrql
);
1605 /* after some allocations print the npaged pool stats */
1606 #ifdef TAG_STATISTICS_TRACKING
1609 static ULONG counter
= 0;
1610 if (counter
++ % 100000 == 0)
1612 MiDebugDumpNonPagedPoolStats(FALSE
);
1618 * accomodate this useful idiom
1622 POOL_TRACE("= NULL\n");
1623 KeReleaseSpinLock(&MmNpoolLock
, oldIrql
);
1626 /* Make the size dword alligned, this makes the block dword alligned */
1627 Size
= ROUND_UP(Size
, MM_POOL_ALIGNMENT
);
1629 if (Size
>= PAGE_SIZE
)
1631 alignment
= PAGE_SIZE
;
1633 else if (Type
& CACHE_ALIGNED_POOL_MASK
)
1635 alignment
= MM_CACHE_LINE_SIZE
;
1642 best
= get_block(Size
, alignment
);
1645 KeReleaseSpinLock(&MmNpoolLock
, oldIrql
);
1646 DPRINT1("Trying to allocate %lu bytes from nonpaged pool - nothing suitable found, returning NULL\n",
1650 best
->Used
.Tag
= Tag
;
1651 best
->Used
.Caller
= Caller
;
1652 best
->Used
.Dumped
= FALSE
;
1653 best
->Used
.TagListEntry
.Flink
= best
->Used
.TagListEntry
.Blink
= NULL
;
1654 #ifdef TAG_STATISTICS_TRACKING
1656 MiAddToTagHashTable(best
);
1659 KeReleaseSpinLock(&MmNpoolLock
, oldIrql
);
1660 block
= block_to_address(best
);
1661 /* RtlZeroMemory(block, Size);*/
1663 #endif /* WHOLE_PAGE_ALLOCATIONS */
1666 #ifdef WHOLE_PAGE_ALLOCATIONS
1669 ExAllocateWholePageBlock(ULONG Size
)
1677 NrPages
= ROUND_UP(Size
, PAGE_SIZE
) / PAGE_SIZE
;
1679 Base
= RtlFindClearBitsAndSet(&NonPagedPoolAllocMap
, NrPages
+ 1, NonPagedPoolAllocMapHint
);
1680 if (Base
== 0xffffffff)
1682 DbgPrint("Out of non paged pool space.\n");
1685 if (NonPagedPoolAllocMapHint
== Base
)
1687 NonPagedPoolAllocMapHint
+= (NrPages
+ 1);
1690 Address
= MiNonPagedPoolStart
+ Base
* PAGE_SIZE
;
1692 for (i
= 0; i
< NrPages
; i
++)
1694 Page
= MmAllocPage(MC_NPPOOL
, 0);
1699 MmCreateVirtualMapping(NULL
,
1700 Address
+ (i
* PAGE_SIZE
),
1701 PAGE_READWRITE
| PAGE_SYSTEM
,
1706 MiCurrentNonPagedPoolLength
= max(MiCurrentNonPagedPoolLength
, (Base
+ NrPages
) * PAGE_SIZE
);
1707 Size
= (Size
+ 7) & ~7;
1708 Address
= ((PVOID
)((PUCHAR
)Address
+ (NrPages
* PAGE_SIZE
) - Size
));
1710 DPRINT("WPALLOC: %x (%d)\n", Address
, Size
);
1716 ExFreeWholePageBlock(PVOID Addr
)
1720 if (Addr
< MiNonPagedPoolStart
||
1721 Addr
>= (MiNonPagedPoolStart
+ MiCurrentNonPagedPoolLength
))
1723 DbgPrint("Block %x found outside pool area\n", Addr
);
1726 Base
= (Addr
- MiNonPagedPoolStart
) / PAGE_SIZE
;
1727 NonPagedPoolAllocMapHint
= min(NonPagedPoolAllocMapHint
, Base
);
1728 while (MmIsPagePresent(NULL
, Addr
))
1730 MmDeleteVirtualMapping(NULL
,
1735 RtlClearBits(&NonPagedPoolAllocMap
, Base
, 1);
1741 #endif /* WHOLE_PAGE_ALLOCATIONS */
1743 /* Whole Page Allocations note:
1745 * We need enough pages for these things:
1753 MiInitializeNonPagedPool(VOID
)
1759 #ifdef WHOLE_PAGE_ALLOCATIONS
1764 #ifdef TAG_STATISTICS_TRACKING
1766 for (i
= 0; i
< TAG_HASH_TABLE_SIZE
; i
++)
1768 InitializeListHead(&tag_hash_table
[i
]);
1771 KeInitializeSpinLock(&MmNpoolLock
);
1772 InitializeListHead(&UsedBlockListHead
);
1773 InitializeListHead(&AddressListHead
);
1774 FreeBlockListRoot
= NULL
;
1775 #ifdef WHOLE_PAGE_ALLOCATIONS
1777 NonPagedPoolAllocMapHint
= PAGE_ROUND_UP(MiNonPagedPoolLength
/ PAGE_SIZE
/ 8) / PAGE_SIZE
; /* Pages of bitmap buffer */
1778 MiCurrentNonPagedPoolLength
= NonPagedPoolAllocMapHint
* PAGE_SIZE
;
1779 Address
= MiNonPagedPoolStart
;
1780 for (i
= 0; i
< NonPagedPoolAllocMapHint
; i
++)
1782 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Page
);
1783 if (!NT_SUCCESS(Status
))
1785 DbgPrint("Unable to allocate a page\n");
1788 Status
= MmCreateVirtualMapping(NULL
,
1790 PAGE_READWRITE
|PAGE_SYSTEM
,
1793 if (!NT_SUCCESS(Status
))
1795 DbgPrint("Unable to create virtual mapping\n");
1798 Address
+= PAGE_SIZE
;
1800 RtlInitializeBitMap(&NonPagedPoolAllocMap
, MiNonPagedPoolStart
,
1801 MiNonPagedPoolLength
/ PAGE_SIZE
);
1802 RtlClearAllBits(&NonPagedPoolAllocMap
);
1803 RtlSetBits(&NonPagedPoolAllocMap
, 0, NonPagedPoolAllocMapHint
);
1806 MiNonPagedPoolAllocMap
= block_to_address((BLOCK_HDR
*)MiNonPagedPoolStart
);
1807 MiNonPagedPoolNrOfPages
= PAGE_ROUND_UP(ROUND_UP(MiNonPagedPoolLength
/ PAGE_SIZE
, 32) / 8 + 2 * BLOCK_HDR_SIZE
);
1808 MiNonPagedPoolNrOfPages
/= PAGE_SIZE
;
1809 Address
= MiNonPagedPoolStart
;
1810 for (i
= 0; i
< MiNonPagedPoolNrOfPages
; i
++)
1812 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Page
);
1813 if (!NT_SUCCESS(Status
))
1815 DbgPrint("Unable to allocate a page\n");
1818 Status
= MmCreateVirtualMapping(NULL
,
1820 PAGE_READWRITE
|PAGE_SYSTEM
,
1823 if (!NT_SUCCESS(Status
))
1825 DbgPrint("Unable to create virtual mapping\n");
1828 MiNonPagedPoolAllocMap
[i
/ 32] |= (1 << (i
% 32));
1829 Address
= (PVOID
)((ULONG_PTR
)Address
+ PAGE_SIZE
);
1831 /* the first block contains the non paged pool bitmap */
1832 blk
= (BLOCK_HDR
*)MiNonPagedPoolStart
;
1833 memset(blk
, 0, BLOCK_HDR_SIZE
);
1834 blk
->Magic
= BLOCK_HDR_USED_MAGIC
;
1835 blk
->Size
= ROUND_UP(MiNonPagedPoolLength
/ PAGE_SIZE
, 32) / 8;
1836 blk
->previous
= NULL
;
1837 blk
->Used
.Tag
= 0xffffffff;
1838 blk
->Used
.Caller
= 0;
1839 blk
->Used
.Dumped
= FALSE
;
1840 add_to_used_list(blk
);
1841 #ifdef TAG_STATISTICS_TRACKING
1843 MiAddToTagHashTable(blk
);
1845 /* the second block is the first free block */
1846 blk
= (BLOCK_HDR
*)((char*)blk
+ BLOCK_HDR_SIZE
+ blk
->Size
);
1847 memset(blk
, 0, BLOCK_HDR_SIZE
);
1848 memset((char*)blk
+ BLOCK_HDR_SIZE
, 0x0cc, MiNonPagedPoolNrOfPages
* PAGE_SIZE
- ((ULONG_PTR
)blk
+ BLOCK_HDR_SIZE
- (ULONG_PTR
)MiNonPagedPoolStart
));
1849 blk
->Magic
= BLOCK_HDR_FREE_MAGIC
;
1850 blk
->Size
= MiNonPagedPoolLength
- ((ULONG_PTR
)blk
+ BLOCK_HDR_SIZE
- (ULONG_PTR
)MiNonPagedPoolStart
);
1851 blk
->previous
= (BLOCK_HDR
*)MiNonPagedPoolStart
;
1852 add_to_free_list(blk
);
1858 MiAllocateSpecialPool (IN POOL_TYPE PoolType
,
1859 IN SIZE_T NumberOfBytes
,
1864 /* FIXME: Special Pools not Supported */
1865 DbgPrint("Special Pools not supported\n");