ReactOS  0.4.9-dev-728-g3d012a4
expool.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: BSD - See COPYING.ARM in the top level directory
4  * FILE: ntoskrnl/mm/ARM3/expool.c
5  * PURPOSE: ARM Memory Manager Executive Pool Manager
6  * PROGRAMMERS: ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 #define MODULE_INVOLVED_IN_ARM3
16 #include <mm/ARM3/miarm.h>
17 
18 #undef ExAllocatePoolWithQuota
19 #undef ExAllocatePoolWithQuotaTag
20 
21 /* GLOBALS ********************************************************************/
22 
23 #define POOL_BIG_TABLE_ENTRY_FREE 0x1
24 
25 typedef struct _POOL_DPC_CONTEXT
26 {
32 
49 
50 /* Pool block/header/list access macros */
51 #define POOL_ENTRY(x) (PPOOL_HEADER)((ULONG_PTR)(x) - sizeof(POOL_HEADER))
52 #define POOL_FREE_BLOCK(x) (PLIST_ENTRY)((ULONG_PTR)(x) + sizeof(POOL_HEADER))
53 #define POOL_BLOCK(x, i) (PPOOL_HEADER)((ULONG_PTR)(x) + ((i) * POOL_BLOCK_SIZE))
54 #define POOL_NEXT_BLOCK(x) POOL_BLOCK((x), (x)->BlockSize)
55 #define POOL_PREV_BLOCK(x) POOL_BLOCK((x), -((x)->PreviousSize))
56 
57 /*
58  * Pool list access debug macros, similar to Arthur's pfnlist.c work.
59  * Microsoft actually implements similar checks in the Windows Server 2003 SP1
60  * pool code, but only for checked builds.
61  *
62  * As of Vista, however, an MSDN Blog entry by a Security Team Manager indicates
63  * that these checks are done even on retail builds, due to the increasing
64  * number of kernel-mode attacks which depend on dangling list pointers and other
65  * kinds of list-based attacks.
66  *
67  * For now, I will leave these checks on all the time, but later they are likely
68  * to be DBG-only, at least until there are enough kernel-mode security attacks
69  * against ReactOS to warrant the performance hit.
70  *
71  * For now, these are not made inline, so we can get good stack traces.
72  */
74 NTAPI
76 {
77  return (PLIST_ENTRY)((ULONG_PTR)Link & ~1);
78 }
79 
81 NTAPI
83 {
84  return (PLIST_ENTRY)((ULONG_PTR)Link | 1);
85 }
86 
87 VOID
88 NTAPI
90 {
91  if ((ExpDecodePoolLink(ExpDecodePoolLink(ListHead->Flink)->Blink) != ListHead) ||
92  (ExpDecodePoolLink(ExpDecodePoolLink(ListHead->Blink)->Flink) != ListHead))
93  {
94  KeBugCheckEx(BAD_POOL_HEADER,
95  3,
96  (ULONG_PTR)ListHead,
99  }
100 }
101 
102 VOID
103 NTAPI
105 {
106  ListHead->Flink = ListHead->Blink = ExpEncodePoolLink(ListHead);
107 }
108 
109 BOOLEAN
110 NTAPI
112 {
113  return (ExpDecodePoolLink(ListHead->Flink) == ListHead);
114 }
115 
116 VOID
117 NTAPI
119 {
120  PLIST_ENTRY Blink, Flink;
121  Flink = ExpDecodePoolLink(Entry->Flink);
122  Blink = ExpDecodePoolLink(Entry->Blink);
123  Flink->Blink = ExpEncodePoolLink(Blink);
124  Blink->Flink = ExpEncodePoolLink(Flink);
125 }
126 
128 NTAPI
130 {
131  PLIST_ENTRY Entry, Flink;
132  Entry = ExpDecodePoolLink(ListHead->Flink);
133  Flink = ExpDecodePoolLink(Entry->Flink);
134  ListHead->Flink = ExpEncodePoolLink(Flink);
135  Flink->Blink = ExpEncodePoolLink(ListHead);
136  return Entry;
137 }
138 
140 NTAPI
142 {
143  PLIST_ENTRY Entry, Blink;
144  Entry = ExpDecodePoolLink(ListHead->Blink);
145  Blink = ExpDecodePoolLink(Entry->Blink);
146  ListHead->Blink = ExpEncodePoolLink(Blink);
147  Blink->Flink = ExpEncodePoolLink(ListHead);
148  return Entry;
149 }
150 
151 VOID
152 NTAPI
155 {
156  PLIST_ENTRY Blink;
157  ExpCheckPoolLinks(ListHead);
158  Blink = ExpDecodePoolLink(ListHead->Blink);
159  Entry->Flink = ExpEncodePoolLink(ListHead);
160  Entry->Blink = ExpEncodePoolLink(Blink);
161  Blink->Flink = ExpEncodePoolLink(Entry);
162  ListHead->Blink = ExpEncodePoolLink(Entry);
163  ExpCheckPoolLinks(ListHead);
164 }
165 
166 VOID
167 NTAPI
170 {
171  PLIST_ENTRY Flink;
172  ExpCheckPoolLinks(ListHead);
173  Flink = ExpDecodePoolLink(ListHead->Flink);
174  Entry->Flink = ExpEncodePoolLink(Flink);
175  Entry->Blink = ExpEncodePoolLink(ListHead);
176  Flink->Blink = ExpEncodePoolLink(Entry);
177  ListHead->Flink = ExpEncodePoolLink(Entry);
178  ExpCheckPoolLinks(ListHead);
179 }
180 
181 VOID
182 NTAPI
184 {
185  PPOOL_HEADER PreviousEntry, NextEntry;
186 
187  /* Is there a block before this one? */
188  if (Entry->PreviousSize)
189  {
190  /* Get it */
191  PreviousEntry = POOL_PREV_BLOCK(Entry);
192 
193  /* The two blocks must be on the same page! */
194  if (PAGE_ALIGN(Entry) != PAGE_ALIGN(PreviousEntry))
195  {
196  /* Something is awry */
197  KeBugCheckEx(BAD_POOL_HEADER,
198  6,
199  (ULONG_PTR)PreviousEntry,
200  __LINE__,
201  (ULONG_PTR)Entry);
202  }
203 
204  /* This block should also indicate that it's as large as we think it is */
205  if (PreviousEntry->BlockSize != Entry->PreviousSize)
206  {
207  /* Otherwise, someone corrupted one of the sizes */
208  DPRINT1("PreviousEntry BlockSize %lu, tag %.4s. Entry PreviousSize %lu, tag %.4s\n",
209  PreviousEntry->BlockSize, (char *)&PreviousEntry->PoolTag,
210  Entry->PreviousSize, (char *)&Entry->PoolTag);
211  KeBugCheckEx(BAD_POOL_HEADER,
212  5,
213  (ULONG_PTR)PreviousEntry,
214  __LINE__,
215  (ULONG_PTR)Entry);
216  }
217  }
218  else if (PAGE_ALIGN(Entry) != Entry)
219  {
220  /* If there's no block before us, we are the first block, so we should be on a page boundary */
221  KeBugCheckEx(BAD_POOL_HEADER,
222  7,
223  0,
224  __LINE__,
225  (ULONG_PTR)Entry);
226  }
227 
228  /* This block must have a size */
229  if (!Entry->BlockSize)
230  {
231  /* Someone must've corrupted this field */
232  if (Entry->PreviousSize)
233  {
234  PreviousEntry = POOL_PREV_BLOCK(Entry);
235  DPRINT1("PreviousEntry tag %.4s. Entry tag %.4s\n",
236  (char *)&PreviousEntry->PoolTag,
237  (char *)&Entry->PoolTag);
238  }
239  else
240  {
241  DPRINT1("Entry tag %.4s\n",
242  (char *)&Entry->PoolTag);
243  }
244  KeBugCheckEx(BAD_POOL_HEADER,
245  8,
246  0,
247  __LINE__,
248  (ULONG_PTR)Entry);
249  }
250 
251  /* Okay, now get the next block */
252  NextEntry = POOL_NEXT_BLOCK(Entry);
253 
254  /* If this is the last block, then we'll be page-aligned, otherwise, check this block */
255  if (PAGE_ALIGN(NextEntry) != NextEntry)
256  {
257  /* The two blocks must be on the same page! */
258  if (PAGE_ALIGN(Entry) != PAGE_ALIGN(NextEntry))
259  {
260  /* Something is messed up */
261  KeBugCheckEx(BAD_POOL_HEADER,
262  9,
263  (ULONG_PTR)NextEntry,
264  __LINE__,
265  (ULONG_PTR)Entry);
266  }
267 
268  /* And this block should think we are as large as we truly are */
269  if (NextEntry->PreviousSize != Entry->BlockSize)
270  {
271  /* Otherwise, someone corrupted the field */
272  DPRINT1("Entry BlockSize %lu, tag %.4s. NextEntry PreviousSize %lu, tag %.4s\n",
273  Entry->BlockSize, (char *)&Entry->PoolTag,
274  NextEntry->PreviousSize, (char *)&NextEntry->PoolTag);
275  KeBugCheckEx(BAD_POOL_HEADER,
276  5,
277  (ULONG_PTR)NextEntry,
278  __LINE__,
279  (ULONG_PTR)Entry);
280  }
281  }
282 }
283 
284 VOID
285 NTAPI
287  PVOID P,
289  ULONG Tag)
290 {
292  ULONG i;
293  KIRQL OldIrql;
294  POOL_TYPE RealPoolType;
295 
296  /* Get the pool header */
297  Entry = ((PPOOL_HEADER)P) - 1;
298 
299  /* Check if this is a large allocation */
300  if (PAGE_ALIGN(P) == P)
301  {
302  /* Lock the pool table */
304 
305  /* Find the pool tag */
306  for (i = 0; i < PoolBigPageTableSize; i++)
307  {
308  /* Check if this is our allocation */
309  if (PoolBigPageTable[i].Va == P)
310  {
311  /* Make sure the tag is ok */
312  if (PoolBigPageTable[i].Key != Tag)
313  {
314  KeBugCheckEx(BAD_POOL_CALLER, 0x0A, (ULONG_PTR)P, PoolBigPageTable[i].Key, Tag);
315  }
316 
317  break;
318  }
319  }
320 
321  /* Release the lock */
323 
324  if (i == PoolBigPageTableSize)
325  {
326  /* Did not find the allocation */
327  //ASSERT(FALSE);
328  }
329 
330  /* Get Pool type by address */
331  RealPoolType = MmDeterminePoolType(P);
332  }
333  else
334  {
335  /* Verify the tag */
336  if (Entry->PoolTag != Tag)
337  {
338  DPRINT1("Allocation has wrong pool tag! Expected '%.4s', got '%.4s' (0x%08lx)\n",
339  &Tag, &Entry->PoolTag, Entry->PoolTag);
340  KeBugCheckEx(BAD_POOL_CALLER, 0x0A, (ULONG_PTR)P, Entry->PoolTag, Tag);
341  }
342 
343  /* Check the rest of the header */
344  ExpCheckPoolHeader(Entry);
345 
346  /* Get Pool type from entry */
347  RealPoolType = (Entry->PoolType - 1);
348  }
349 
350  /* Should we check the pool type? */
351  if (PoolType != -1)
352  {
353  /* Verify the pool type */
354  if (RealPoolType != PoolType)
355  {
356  DPRINT1("Wrong pool type! Expected %s, got %s\n",
357  PoolType & BASE_POOL_TYPE_MASK ? "PagedPool" : "NonPagedPool",
358  (Entry->PoolType - 1) & BASE_POOL_TYPE_MASK ? "PagedPool" : "NonPagedPool");
359  KeBugCheckEx(BAD_POOL_CALLER, 0xCC, (ULONG_PTR)P, Entry->PoolTag, Tag);
360  }
361  }
362 }
363 
364 VOID
365 NTAPI
367 {
368  BOOLEAN FoundBlock = FALSE;
369  SIZE_T Size = 0;
371 
372  /* Get the first entry for this page, make sure it really is the first */
373  Entry = PAGE_ALIGN(Block);
374  ASSERT(Entry->PreviousSize == 0);
375 
376  /* Now scan each entry */
377  while (TRUE)
378  {
379  /* When we actually found our block, remember this */
380  if (Entry == Block) FoundBlock = TRUE;
381 
382  /* Now validate this block header */
383  ExpCheckPoolHeader(Entry);
384 
385  /* And go to the next one, keeping track of our size */
386  Size += Entry->BlockSize;
387  Entry = POOL_NEXT_BLOCK(Entry);
388 
389  /* If we hit the last block, stop */
390  if (Size >= (PAGE_SIZE / POOL_BLOCK_SIZE)) break;
391 
392  /* If we hit the end of the page, stop */
393  if (PAGE_ALIGN(Entry) == Entry) break;
394  }
395 
396  /* We must've found our block, and we must have hit the end of the page */
397  if ((PAGE_ALIGN(Entry) != Entry) || !(FoundBlock))
398  {
399  /* Otherwise, the blocks are messed up */
400  KeBugCheckEx(BAD_POOL_HEADER, 10, (ULONG_PTR)Block, __LINE__, (ULONG_PTR)Entry);
401  }
402 }
403 
405 VOID
408  IN PVOID Entry)
409 {
410  //
411  // Validate IRQL: It must be APC_LEVEL or lower for Paged Pool, and it must
412  // be DISPATCH_LEVEL or lower for Non Paged Pool
413  //
414  if (((PoolType & BASE_POOL_TYPE_MASK) == PagedPool) ?
417  {
418  //
419  // Take the system down
420  //
421  KeBugCheckEx(BAD_POOL_CALLER,
424  PoolType,
425  !Entry ? NumberOfBytes : (ULONG_PTR)Entry);
426  }
427 }
428 
430 ULONG
432  IN SIZE_T BucketMask)
433 {
434  //
435  // Compute the hash by multiplying with a large prime number and then XORing
436  // with the HIDWORD of the result.
437  //
438  // Finally, AND with the bucket mask to generate a valid index/bucket into
439  // the table
440  //
441  ULONGLONG Result = (ULONGLONG)40543 * Tag;
442  return (ULONG)BucketMask & ((ULONG)Result ^ (Result >> 32));
443 }
444 
446 ULONG
448 {
449  ULONG Result;
450  //
451  // Compute the hash by converting the address into a page number, and then
452  // XORing each nibble with the next one.
453  //
454  // We do *NOT* AND with the bucket mask at this point because big table expansion
455  // might happen. Therefore, the final step of the hash must be performed
456  // while holding the expansion pushlock, and this is why we call this a
457  // "partial" hash only.
458  //
459  Result = (ULONG)((ULONG_PTR)BaseAddress >> PAGE_SHIFT);
460  return (Result >> 24) ^ (Result >> 16) ^ (Result >> 8) ^ Result;
461 }
462 
463 #if DBG
465 BOOLEAN
466 ExpTagAllowPrint(CHAR Tag)
467 {
468  if ((Tag >= 'a' && Tag <= 'z') ||
469  (Tag >= 'A' && Tag <= 'Z') ||
470  (Tag >= '0' && Tag <= '9') ||
471  Tag == ' ' || Tag == '=' ||
472  Tag == '?' || Tag == '@')
473  {
474  return TRUE;
475  }
476 
477  return FALSE;
478 }
479 
480 #ifdef KDBG
481 #define MiDumperPrint(dbg, fmt, ...) \
482  if (dbg) KdbpPrint(fmt, ##__VA_ARGS__); \
483  else DPRINT1(fmt, ##__VA_ARGS__)
484 #else
485 #define MiDumperPrint(dbg, fmt, ...) \
486  DPRINT1(fmt, ##__VA_ARGS__)
487 #endif
488 
489 VOID
490 MiDumpPoolConsumers(BOOLEAN CalledFromDbg, ULONG Tag, ULONG Mask, ULONG Flags)
491 {
492  SIZE_T i;
494 
495  //
496  // Only print header if called from OOM situation
497  //
498  if (!CalledFromDbg)
499  {
500  DPRINT1("---------------------\n");
501  DPRINT1("Out of memory dumper!\n");
502  }
503 #ifdef KDBG
504  else
505  {
506  KdbpPrint("Pool Used:\n");
507  }
508 #endif
509 
510  //
511  // Remember whether we'll have to be verbose
512  // This is the only supported flag!
513  //
514  Verbose = BooleanFlagOn(Flags, 1);
515 
516  //
517  // Print table header
518  //
519  if (Verbose)
520  {
521  MiDumperPrint(CalledFromDbg, "\t\t\t\tNonPaged\t\t\t\t\t\t\tPaged\n");
522  MiDumperPrint(CalledFromDbg, "Tag\t\tAllocs\t\tFrees\t\tDiff\t\tUsed\t\tAllocs\t\tFrees\t\tDiff\t\tUsed\n");
523  }
524  else
525  {
526  MiDumperPrint(CalledFromDbg, "\t\tNonPaged\t\t\tPaged\n");
527  MiDumperPrint(CalledFromDbg, "Tag\t\tAllocs\t\tUsed\t\tAllocs\t\tUsed\n");
528  }
529 
530  //
531  // We'll extract allocations for all the tracked pools
532  //
533  for (i = 0; i < PoolTrackTableSize; ++i)
534  {
536 
537  TableEntry = &PoolTrackTable[i];
538 
539  //
540  // We only care about tags which have allocated memory
541  //
542  if (TableEntry->NonPagedBytes != 0 || TableEntry->PagedBytes != 0)
543  {
544  //
545  // If there's a tag, attempt to do a pretty print
546  // only if it matches the caller's tag, or if
547  // any tag is allowed
548  // For checking whether it matches caller's tag,
549  // use the mask to make sure not to mess with the wildcards
550  //
551  if (TableEntry->Key != 0 && TableEntry->Key != TAG_NONE &&
552  (Tag == 0 || (TableEntry->Key & Mask) == (Tag & Mask)))
553  {
554  CHAR Tag[4];
555 
556  //
557  // Extract each 'component' and check whether they are printable
558  //
559  Tag[0] = TableEntry->Key & 0xFF;
560  Tag[1] = TableEntry->Key >> 8 & 0xFF;
561  Tag[2] = TableEntry->Key >> 16 & 0xFF;
562  Tag[3] = TableEntry->Key >> 24 & 0xFF;
563 
564  if (ExpTagAllowPrint(Tag[0]) && ExpTagAllowPrint(Tag[1]) && ExpTagAllowPrint(Tag[2]) && ExpTagAllowPrint(Tag[3]))
565  {
566  //
567  // Print in direct order to make !poolused TAG usage easier
568  //
569  if (Verbose)
570  {
571  MiDumperPrint(CalledFromDbg, "'%c%c%c%c'\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n", Tag[0], Tag[1], Tag[2], Tag[3],
572  TableEntry->NonPagedAllocs, TableEntry->NonPagedFrees,
573  (TableEntry->NonPagedAllocs - TableEntry->NonPagedFrees), TableEntry->NonPagedBytes,
574  TableEntry->PagedAllocs, TableEntry->PagedFrees,
575  (TableEntry->PagedAllocs - TableEntry->PagedFrees), TableEntry->PagedBytes);
576  }
577  else
578  {
579  MiDumperPrint(CalledFromDbg, "'%c%c%c%c'\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n", Tag[0], Tag[1], Tag[2], Tag[3],
580  TableEntry->NonPagedAllocs, TableEntry->NonPagedBytes,
581  TableEntry->PagedAllocs, TableEntry->PagedBytes);
582  }
583  }
584  else
585  {
586  if (Verbose)
587  {
588  MiDumperPrint(CalledFromDbg, "%x\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n", TableEntry->Key,
589  TableEntry->NonPagedAllocs, TableEntry->NonPagedFrees,
590  (TableEntry->NonPagedAllocs - TableEntry->NonPagedFrees), TableEntry->NonPagedBytes,
591  TableEntry->PagedAllocs, TableEntry->PagedFrees,
592  (TableEntry->PagedAllocs - TableEntry->PagedFrees), TableEntry->PagedBytes);
593  }
594  else
595  {
596  MiDumperPrint(CalledFromDbg, "%x\t%ld\t\t%ld\t\t%ld\t\t%ld\n", TableEntry->Key,
597  TableEntry->NonPagedAllocs, TableEntry->NonPagedBytes,
598  TableEntry->PagedAllocs, TableEntry->PagedBytes);
599  }
600  }
601  }
602  else if (Tag == 0 || (Tag & Mask) == (TAG_NONE & Mask))
603  {
604  if (Verbose)
605  {
606  MiDumperPrint(CalledFromDbg, "Anon\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n",
607  TableEntry->NonPagedAllocs, TableEntry->NonPagedFrees,
608  (TableEntry->NonPagedAllocs - TableEntry->NonPagedFrees), TableEntry->NonPagedBytes,
609  TableEntry->PagedAllocs, TableEntry->PagedFrees,
610  (TableEntry->PagedAllocs - TableEntry->PagedFrees), TableEntry->PagedBytes);
611  }
612  else
613  {
614  MiDumperPrint(CalledFromDbg, "Anon\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n",
615  TableEntry->NonPagedAllocs, TableEntry->NonPagedBytes,
616  TableEntry->PagedAllocs, TableEntry->PagedBytes);
617  }
618  }
619  }
620  }
621 
622  if (!CalledFromDbg)
623  {
624  DPRINT1("---------------------\n");
625  }
626 }
627 #endif
628 
629 /* PRIVATE FUNCTIONS **********************************************************/
630 
631 VOID
632 NTAPI
635 {
636  ULONG i, Key, Hash, Index;
637  PPOOL_TRACKER_TABLE TrackTable = PoolTrackTable;
638  ULONG TagList[] =
639  {
640  ' oI',
641  ' laH',
642  'PldM',
643  'LooP',
644  'tSbO',
645  ' prI',
646  'bdDN',
647  'LprI',
648  'pOoI',
649  ' ldM',
650  'eliF',
651  'aVMC',
652  'dSeS',
653  'CFtN',
654  'looP',
655  'rPCT',
656  'bNMC',
657  'dTeS',
658  'sFtN',
659  'TPCT',
660  'CPCT',
661  ' yeK',
662  'qSbO',
663  'mNoI',
664  'aEoI',
665  'cPCT',
666  'aFtN',
667  '0ftN',
668  'tceS',
669  'SprI',
670  'ekoT',
671  ' eS',
672  'lCbO',
673  'cScC',
674  'lFtN',
675  'cAeS',
676  'mfSF',
677  'kWcC',
678  'miSF',
679  'CdfA',
680  'EdfA',
681  'orSF',
682  'nftN',
683  'PRIU',
684  'rFpN',
685  'RFpN',
686  'aPeS',
687  'sUeS',
688  'FpcA',
689  'MpcA',
690  'cSeS',
691  'mNbO',
692  'sFpN',
693  'uLeS',
694  'DPcS',
695  'nevE',
696  'vrqR',
697  'ldaV',
698  ' pP',
699  'SdaV',
700  ' daV',
701  'LdaV',
702  'FdaV',
703  ' GIB',
704  };
705 
706  //
707  // Loop all 64 hot tags
708  //
709  ASSERT((sizeof(TagList) / sizeof(ULONG)) == 64);
710  for (i = 0; i < sizeof(TagList) / sizeof(ULONG); i++)
711  {
712  //
713  // Get the current tag, and compute its hash in the tracker table
714  //
715  Key = TagList[i];
717 
718  //
719  // Loop all the hashes in this index/bucket
720  //
721  Index = Hash;
722  while (TRUE)
723  {
724  //
725  // Find an empty entry, and make sure this isn't the last hash that
726  // can fit.
727  //
728  // On checked builds, also make sure this is the first time we are
729  // seeding this tag.
730  //
731  ASSERT(TrackTable[Hash].Key != Key);
732  if (!(TrackTable[Hash].Key) && (Hash != PoolTrackTableSize - 1))
733  {
734  //
735  // It has been seeded, move on to the next tag
736  //
737  TrackTable[Hash].Key = Key;
738  break;
739  }
740 
741  //
742  // This entry was already taken, compute the next possible hash while
743  // making sure we're not back at our initial index.
744  //
745  ASSERT(TrackTable[Hash].Key != Key);
746  Hash = (Hash + 1) & PoolTrackTableMask;
747  if (Hash == Index) break;
748  }
749  }
750 }
751 
752 VOID
753 NTAPI
757 {
758  ULONG Hash, Index;
760  SIZE_T TableMask, TableSize;
761 
762  //
763  // Remove the PROTECTED_POOL flag which is not part of the tag
764  //
765  Key &= ~PROTECTED_POOL;
766 
767  //
768  // With WinDBG you can set a tag you want to break on when an allocation is
769  // attempted
770  //
771  if (Key == PoolHitTag) DbgBreakPoint();
772 
773  //
774  // Why the double indirection? Because normally this function is also used
775  // when doing session pool allocations, which has another set of tables,
776  // sizes, and masks that live in session pool. Now we don't support session
777  // pool so we only ever use the regular tables, but I'm keeping the code this
778  // way so that the day we DO support session pool, it won't require that
779  // many changes
780  //
781  Table = PoolTrackTable;
782  TableMask = PoolTrackTableMask;
783  TableSize = PoolTrackTableSize;
785 
786  //
787  // Compute the hash for this key, and loop all the possible buckets
788  //
789  Hash = ExpComputeHashForTag(Key, TableMask);
790  Index = Hash;
791  while (TRUE)
792  {
793  //
794  // Have we found the entry for this tag? */
795  //
796  TableEntry = &Table[Hash];
797  if (TableEntry->Key == Key)
798  {
799  //
800  // Decrement the counters depending on if this was paged or nonpaged
801  // pool
802  //
803  if ((PoolType & BASE_POOL_TYPE_MASK) == NonPagedPool)
804  {
805  InterlockedIncrement(&TableEntry->NonPagedFrees);
807  -(SSIZE_T)NumberOfBytes);
808  return;
809  }
810  InterlockedIncrement(&TableEntry->PagedFrees);
812  -(SSIZE_T)NumberOfBytes);
813  return;
814  }
815 
816  //
817  // We should have only ended up with an empty entry if we've reached
818  // the last bucket
819  //
820  if (!TableEntry->Key)
821  {
822  DPRINT1("Empty item reached in tracker table. Hash=0x%lx, TableMask=0x%lx, Tag=0x%08lx, NumberOfBytes=%lu, PoolType=%d\n",
823  Hash, TableMask, Key, (ULONG)NumberOfBytes, PoolType);
824  ASSERT(Hash == TableMask);
825  }
826 
827  //
828  // This path is hit when we don't have an entry, and the current bucket
829  // is full, so we simply try the next one
830  //
831  Hash = (Hash + 1) & TableMask;
832  if (Hash == Index) break;
833  }
834 
835  //
836  // And finally this path is hit when all the buckets are full, and we need
837  // some expansion. This path is not yet supported in ReactOS and so we'll
838  // ignore the tag
839  //
840  DPRINT1("Out of pool tag space, ignoring...\n");
841 }
842 
843 VOID
844 NTAPI
848 {
849  ULONG Hash, Index;
850  KIRQL OldIrql;
852  SIZE_T TableMask, TableSize;
853 
854  //
855  // Remove the PROTECTED_POOL flag which is not part of the tag
856  //
857  Key &= ~PROTECTED_POOL;
858 
859  //
860  // With WinDBG you can set a tag you want to break on when an allocation is
861  // attempted
862  //
863  if (Key == PoolHitTag) DbgBreakPoint();
864 
865  //
866  // There is also an internal flag you can set to break on malformed tags
867  //
868  if (ExStopBadTags) ASSERT(Key & 0xFFFFFF00);
869 
870  //
871  // ASSERT on ReactOS features not yet supported
872  //
873  ASSERT(!(PoolType & SESSION_POOL_MASK));
875 
876  //
877  // Why the double indirection? Because normally this function is also used
878  // when doing session pool allocations, which has another set of tables,
879  // sizes, and masks that live in session pool. Now we don't support session
880  // pool so we only ever use the regular tables, but I'm keeping the code this
881  // way so that the day we DO support session pool, it won't require that
882  // many changes
883  //
884  Table = PoolTrackTable;
885  TableMask = PoolTrackTableMask;
886  TableSize = PoolTrackTableSize;
888 
889  //
890  // Compute the hash for this key, and loop all the possible buckets
891  //
892  Hash = ExpComputeHashForTag(Key, TableMask);
893  Index = Hash;
894  while (TRUE)
895  {
896  //
897  // Do we already have an entry for this tag? */
898  //
899  TableEntry = &Table[Hash];
900  if (TableEntry->Key == Key)
901  {
902  //
903  // Increment the counters depending on if this was paged or nonpaged
904  // pool
905  //
906  if ((PoolType & BASE_POOL_TYPE_MASK) == NonPagedPool)
907  {
908  InterlockedIncrement(&TableEntry->NonPagedAllocs);
909  InterlockedExchangeAddSizeT(&TableEntry->NonPagedBytes, NumberOfBytes);
910  return;
911  }
912  InterlockedIncrement(&TableEntry->PagedAllocs);
913  InterlockedExchangeAddSizeT(&TableEntry->PagedBytes, NumberOfBytes);
914  return;
915  }
916 
917  //
918  // We don't have an entry yet, but we've found a free bucket for it
919  //
920  if (!(TableEntry->Key) && (Hash != PoolTrackTableSize - 1))
921  {
922  //
923  // We need to hold the lock while creating a new entry, since other
924  // processors might be in this code path as well
925  //
927  if (!PoolTrackTable[Hash].Key)
928  {
929  //
930  // We've won the race, so now create this entry in the bucket
931  //
932  ASSERT(Table[Hash].Key == 0);
933  PoolTrackTable[Hash].Key = Key;
934  TableEntry->Key = Key;
935  }
937 
938  //
939  // Now we force the loop to run again, and we should now end up in
940  // the code path above which does the interlocked increments...
941  //
942  continue;
943  }
944 
945  //
946  // This path is hit when we don't have an entry, and the current bucket
947  // is full, so we simply try the next one
948  //
949  Hash = (Hash + 1) & TableMask;
950  if (Hash == Index) break;
951  }
952 
953  //
954  // And finally this path is hit when all the buckets are full, and we need
955  // some expansion. This path is not yet supported in ReactOS and so we'll
956  // ignore the tag
957  //
958  DPRINT1("Out of pool tag space, ignoring...\n");
959 }
960 
961 VOID
962 NTAPI
966  IN ULONG PoolIndex,
967  IN ULONG Threshold,
968  IN PVOID PoolLock)
969 {
970  PLIST_ENTRY NextEntry, LastEntry;
971 
972  //
973  // Setup the descriptor based on the caller's request
974  //
975  PoolDescriptor->PoolType = PoolType;
976  PoolDescriptor->PoolIndex = PoolIndex;
977  PoolDescriptor->Threshold = Threshold;
978  PoolDescriptor->LockAddress = PoolLock;
979 
980  //
981  // Initialize accounting data
982  //
983  PoolDescriptor->RunningAllocs = 0;
984  PoolDescriptor->RunningDeAllocs = 0;
985  PoolDescriptor->TotalPages = 0;
986  PoolDescriptor->TotalBytes = 0;
987  PoolDescriptor->TotalBigPages = 0;
988 
989  //
990  // Nothing pending for now
991  //
992  PoolDescriptor->PendingFrees = NULL;
993  PoolDescriptor->PendingFreeDepth = 0;
994 
995  //
996  // Loop all the descriptor's allocation lists and initialize them
997  //
998  NextEntry = PoolDescriptor->ListHeads;
999  LastEntry = NextEntry + POOL_LISTS_PER_PAGE;
1000  while (NextEntry < LastEntry)
1001  {
1002  ExpInitializePoolListHead(NextEntry);
1003  NextEntry++;
1004  }
1005 
1006  //
1007  // Note that ReactOS does not support Session Pool Yet
1008  //
1009  ASSERT(PoolType != PagedPoolSession);
1010 }
1011 
1012 VOID
1013 NTAPI
1016  IN ULONG Threshold)
1017 {
1019  SIZE_T TableSize;
1020  ULONG i;
1021 
1022  //
1023  // Check what kind of pool this is
1024  //
1025  if (PoolType == NonPagedPool)
1026  {
1027  //
1028  // Compute the track table size and convert it from a power of two to an
1029  // actual byte size
1030  //
1031  // NOTE: On checked builds, we'll assert if the registry table size was
1032  // invalid, while on retail builds we'll just break out of the loop at
1033  // that point.
1034  //
1035  TableSize = min(PoolTrackTableSize, MmSizeOfNonPagedPoolInBytes >> 8);
1036  for (i = 0; i < 32; i++)
1037  {
1038  if (TableSize & 1)
1039  {
1040  ASSERT((TableSize & ~1) == 0);
1041  if (!(TableSize & ~1)) break;
1042  }
1043  TableSize >>= 1;
1044  }
1045 
1046  //
1047  // If we hit bit 32, than no size was defined in the registry, so
1048  // we'll use the default size of 2048 entries.
1049  //
1050  // Otherwise, use the size from the registry, as long as it's not
1051  // smaller than 64 entries.
1052  //
1053  if (i == 32)
1054  {
1055  PoolTrackTableSize = 2048;
1056  }
1057  else
1058  {
1059  PoolTrackTableSize = max(1 << i, 64);
1060  }
1061 
1062  //
1063  // Loop trying with the biggest specified size first, and cut it down
1064  // by a power of two each iteration in case not enough memory exist
1065  //
1066  while (TRUE)
1067  {
1068  //
1069  // Do not allow overflow
1070  //
1071  if ((PoolTrackTableSize + 1) > (MAXULONG_PTR / sizeof(POOL_TRACKER_TABLE)))
1072  {
1073  PoolTrackTableSize >>= 1;
1074  continue;
1075  }
1076 
1077  //
1078  // Allocate the tracker table and exit the loop if this worked
1079  //
1080  PoolTrackTable = MiAllocatePoolPages(NonPagedPool,
1081  (PoolTrackTableSize + 1) *
1082  sizeof(POOL_TRACKER_TABLE));
1083  if (PoolTrackTable) break;
1084 
1085  //
1086  // Otherwise, as long as we're not down to the last bit, keep
1087  // iterating
1088  //
1089  if (PoolTrackTableSize == 1)
1090  {
1091  KeBugCheckEx(MUST_SUCCEED_POOL_EMPTY,
1092  TableSize,
1093  0xFFFFFFFF,
1094  0xFFFFFFFF,
1095  0xFFFFFFFF);
1096  }
1097  PoolTrackTableSize >>= 1;
1098  }
1099 
1100  //
1101  // Add one entry, compute the hash, and zero the table
1102  //
1103  PoolTrackTableSize++;
1104  PoolTrackTableMask = PoolTrackTableSize - 2;
1105 
1106  RtlZeroMemory(PoolTrackTable,
1107  PoolTrackTableSize * sizeof(POOL_TRACKER_TABLE));
1108 
1109  //
1110  // Finally, add the most used tags to speed up those allocations
1111  //
1112  ExpSeedHotTags();
1113 
1114  //
1115  // We now do the exact same thing with the tracker table for big pages
1116  //
1118  for (i = 0; i < 32; i++)
1119  {
1120  if (TableSize & 1)
1121  {
1122  ASSERT((TableSize & ~1) == 0);
1123  if (!(TableSize & ~1)) break;
1124  }
1125  TableSize >>= 1;
1126  }
1127 
1128  //
1129  // For big pages, the default tracker table is 4096 entries, while the
1130  // minimum is still 64
1131  //
1132  if (i == 32)
1133  {
1134  PoolBigPageTableSize = 4096;
1135  }
1136  else
1137  {
1138  PoolBigPageTableSize = max(1 << i, 64);
1139  }
1140 
1141  //
1142  // Again, run the exact same loop we ran earlier, but this time for the
1143  // big pool tracker instead
1144  //
1145  while (TRUE)
1146  {
1148  {
1149  PoolBigPageTableSize >>= 1;
1150  continue;
1151  }
1152 
1153  PoolBigPageTable = MiAllocatePoolPages(NonPagedPool,
1155  sizeof(POOL_TRACKER_BIG_PAGES));
1156  if (PoolBigPageTable) break;
1157 
1158  if (PoolBigPageTableSize == 1)
1159  {
1160  KeBugCheckEx(MUST_SUCCEED_POOL_EMPTY,
1161  TableSize,
1162  0xFFFFFFFF,
1163  0xFFFFFFFF,
1164  0xFFFFFFFF);
1165  }
1166 
1167  PoolBigPageTableSize >>= 1;
1168  }
1169 
1170  //
1171  // An extra entry is not needed for for the big pool tracker, so just
1172  // compute the hash and zero it
1173  //
1175  RtlZeroMemory(PoolBigPageTable,
1177  for (i = 0; i < PoolBigPageTableSize; i++) PoolBigPageTable[i].Va = (PVOID)1;
1178 
1179  //
1180  // During development, print this out so we can see what's happening
1181  //
1182  DPRINT("EXPOOL: Pool Tracker Table at: 0x%p with 0x%lx bytes\n",
1183  PoolTrackTable, PoolTrackTableSize * sizeof(POOL_TRACKER_TABLE));
1184  DPRINT("EXPOOL: Big Pool Tracker Table at: 0x%p with 0x%lx bytes\n",
1185  PoolBigPageTable, PoolBigPageTableSize * sizeof(POOL_TRACKER_BIG_PAGES));
1186 
1187  //
1188  // Insert the generic tracker for all of big pool
1189  //
1190  ExpInsertPoolTracker('looP',
1191  ROUND_TO_PAGES(PoolBigPageTableSize *
1192  sizeof(POOL_TRACKER_BIG_PAGES)),
1193  NonPagedPool);
1194 
1195  //
1196  // No support for NUMA systems at this time
1197  //
1198  ASSERT(KeNumberNodes == 1);
1199 
1200  //
1201  // Initialize the tag spinlock
1202  //
1204 
1205  //
1206  // Initialize the nonpaged pool descriptor
1207  //
1208  PoolVector[NonPagedPool] = &NonPagedPoolDescriptor;
1210  NonPagedPool,
1211  0,
1212  Threshold,
1213  NULL);
1214  }
1215  else
1216  {
1217  //
1218  // No support for NUMA systems at this time
1219  //
1220  ASSERT(KeNumberNodes == 1);
1221 
1222  //
1223  // Allocate the pool descriptor
1224  //
1225  Descriptor = ExAllocatePoolWithTag(NonPagedPool,
1226  sizeof(KGUARDED_MUTEX) +
1227  sizeof(POOL_DESCRIPTOR),
1228  'looP');
1229  if (!Descriptor)
1230  {
1231  //
1232  // This is really bad...
1233  //
1234  KeBugCheckEx(MUST_SUCCEED_POOL_EMPTY,
1235  0,
1236  -1,
1237  -1,
1238  -1);
1239  }
1240 
1241  //
1242  // Setup the vector and guarded mutex for paged pool
1243  //
1244  PoolVector[PagedPool] = Descriptor;
1245  ExpPagedPoolMutex = (PKGUARDED_MUTEX)(Descriptor + 1);
1246  ExpPagedPoolDescriptor[0] = Descriptor;
1247  KeInitializeGuardedMutex(ExpPagedPoolMutex);
1248  ExInitializePoolDescriptor(Descriptor,
1249  PagedPool,
1250  0,
1251  Threshold,
1252  ExpPagedPoolMutex);
1253 
1254  //
1255  // Insert the generic tracker for all of nonpaged pool
1256  //
1257  ExpInsertPoolTracker('looP',
1258  ROUND_TO_PAGES(PoolTrackTableSize * sizeof(POOL_TRACKER_TABLE)),
1259  NonPagedPool);
1260  }
1261 }
1262 
1264 KIRQL
1266 {
1267  //
1268  // Check if this is nonpaged pool
1269  //
1270  if ((Descriptor->PoolType & BASE_POOL_TYPE_MASK) == NonPagedPool)
1271  {
1272  //
1273  // Use the queued spin lock
1274  //
1276  }
1277  else
1278  {
1279  //
1280  // Use the guarded mutex
1281  //
1282  KeAcquireGuardedMutex(Descriptor->LockAddress);
1283  return APC_LEVEL;
1284  }
1285 }
1286 
1288 VOID
1290  IN KIRQL OldIrql)
1291 {
1292  //
1293  // Check if this is nonpaged pool
1294  //
1295  if ((Descriptor->PoolType & BASE_POOL_TYPE_MASK) == NonPagedPool)
1296  {
1297  //
1298  // Use the queued spin lock
1299  //
1301  }
1302  else
1303  {
1304  //
1305  // Use the guarded mutex
1306  //
1307  KeReleaseGuardedMutex(Descriptor->LockAddress);
1308  }
1309 }
1310 
1311 VOID
1312 NTAPI
1317 {
1318  PPOOL_DPC_CONTEXT Context = DeferredContext;
1321 
1322  //
1323  // Make sure we win the race, and if we did, copy the data atomically
1324  //
1325  if (KeSignalCallDpcSynchronize(SystemArgument2))
1326  {
1327  RtlCopyMemory(Context->PoolTrackTable,
1328  PoolTrackTable,
1329  Context->PoolTrackTableSize * sizeof(POOL_TRACKER_TABLE));
1330 
1331  //
1332  // This is here because ReactOS does not yet support expansion
1333  //
1334  ASSERT(Context->PoolTrackTableSizeExpansion == 0);
1335  }
1336 
1337  //
1338  // Regardless of whether we won or not, we must now synchronize and then
1339  // decrement the barrier since this is one more processor that has completed
1340  // the callback.
1341  //
1342  KeSignalCallDpcSynchronize(SystemArgument2);
1343  KeSignalCallDpcDone(SystemArgument1);
1344 }
1345 
1346 NTSTATUS
1347 NTAPI
1349  IN ULONG SystemInformationLength,
1351 {
1352  ULONG TableSize, CurrentLength;
1353  ULONG EntryCount;
1355  PSYSTEM_POOLTAG TagEntry;
1356  PPOOL_TRACKER_TABLE Buffer, TrackerEntry;
1359 
1360  //
1361  // Keep track of how much data the caller's buffer must hold
1362  //
1363  CurrentLength = FIELD_OFFSET(SYSTEM_POOLTAG_INFORMATION, TagInfo);
1364 
1365  //
1366  // Initialize the caller's buffer
1367  //
1368  TagEntry = &SystemInformation->TagInfo[0];
1369  SystemInformation->Count = 0;
1370 
1371  //
1372  // Capture the number of entries, and the total size needed to make a copy
1373  // of the table
1374  //
1375  EntryCount = (ULONG)PoolTrackTableSize;
1376  TableSize = EntryCount * sizeof(POOL_TRACKER_TABLE);
1377 
1378  //
1379  // Allocate the "Generic DPC" temporary buffer
1380  //
1381  Buffer = ExAllocatePoolWithTag(NonPagedPool, TableSize, 'ofnI');
1382  if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
1383 
1384  //
1385  // Do a "Generic DPC" to atomically retrieve the tag and allocation data
1386  //
1387  Context.PoolTrackTable = Buffer;
1389  Context.PoolTrackTableExpansion = NULL;
1390  Context.PoolTrackTableSizeExpansion = 0;
1392 
1393  //
1394  // Now parse the results
1395  //
1396  for (TrackerEntry = Buffer; TrackerEntry < (Buffer + EntryCount); TrackerEntry++)
1397  {
1398  //
1399  // If the entry is empty, skip it
1400  //
1401  if (!TrackerEntry->Key) continue;
1402 
1403  //
1404  // Otherwise, add one more entry to the caller's buffer, and ensure that
1405  // enough space has been allocated in it
1406  //
1407  SystemInformation->Count++;
1408  CurrentLength += sizeof(*TagEntry);
1409  if (SystemInformationLength < CurrentLength)
1410  {
1411  //
1412  // The caller's buffer is too small, so set a failure code. The
1413  // caller will know the count, as well as how much space is needed.
1414  //
1415  // We do NOT break out of the loop, because we want to keep incrementing
1416  // the Count as well as CurrentLength so that the caller can know the
1417  // final numbers
1418  //
1419  Status = STATUS_INFO_LENGTH_MISMATCH;
1420  }
1421  else
1422  {
1423  //
1424  // Small sanity check that our accounting is working correctly
1425  //
1426  ASSERT(TrackerEntry->PagedAllocs >= TrackerEntry->PagedFrees);
1427  ASSERT(TrackerEntry->NonPagedAllocs >= TrackerEntry->NonPagedFrees);
1428 
1429  //
1430  // Return the data into the caller's buffer
1431  //
1432  TagEntry->TagUlong = TrackerEntry->Key;
1433  TagEntry->PagedAllocs = TrackerEntry->PagedAllocs;
1434  TagEntry->PagedFrees = TrackerEntry->PagedFrees;
1435  TagEntry->PagedUsed = TrackerEntry->PagedBytes;
1436  TagEntry->NonPagedAllocs = TrackerEntry->NonPagedAllocs;
1437  TagEntry->NonPagedFrees = TrackerEntry->NonPagedFrees;
1438  TagEntry->NonPagedUsed = TrackerEntry->NonPagedBytes;
1439  TagEntry++;
1440  }
1441  }
1442 
1443  //
1444  // Free the "Generic DPC" temporary buffer, return the buffer length and status
1445  //
1446  ExFreePoolWithTag(Buffer, 'ofnI');
1447  if (ReturnLength) *ReturnLength = CurrentLength;
1448  return Status;
1449 }
1450 
1451 BOOLEAN
1452 NTAPI
1454  IN ULONG Key,
1455  IN ULONG NumberOfPages,
1457 {
1458  ULONG Hash, i = 0;
1459  PVOID OldVa;
1460  KIRQL OldIrql;
1461  SIZE_T TableSize;
1462  PPOOL_TRACKER_BIG_PAGES Entry, EntryEnd, EntryStart;
1464  ASSERT(!(PoolType & SESSION_POOL_MASK));
1465 
1466  //
1467  // As the table is expandable, these values must only be read after acquiring
1468  // the lock to avoid a teared access during an expansion
1469  //
1472  Hash &= PoolBigPageTableHash;
1473  TableSize = PoolBigPageTableSize;
1474 
1475  //
1476  // We loop from the current hash bucket to the end of the table, and then
1477  // rollover to hash bucket 0 and keep going from there. If we return back
1478  // to the beginning, then we attempt expansion at the bottom of the loop
1479  //
1480  EntryStart = Entry = &PoolBigPageTable[Hash];
1481  EntryEnd = &PoolBigPageTable[TableSize];
1482  do
1483  {
1484  //
1485  // Make sure that this is a free entry and attempt to atomically make the
1486  // entry busy now
1487  //
1488  OldVa = Entry->Va;
1489  if (((ULONG_PTR)OldVa & POOL_BIG_TABLE_ENTRY_FREE) &&
1490  (InterlockedCompareExchangePointer(&Entry->Va, Va, OldVa) == OldVa))
1491  {
1492  //
1493  // We now own this entry, write down the size and the pool tag
1494  //
1495  Entry->Key = Key;
1496  Entry->NumberOfPages = NumberOfPages;
1497 
1498  //
1499  // Add one more entry to the count, and see if we're getting within
1500  // 25% of the table size, at which point we'll do an expansion now
1501  // to avoid blocking too hard later on.
1502  //
1503  // Note that we only do this if it's also been the 16th time that we
1504  // keep losing the race or that we are not finding a free entry anymore,
1505  // which implies a massive number of concurrent big pool allocations.
1506  //
1508  if ((i >= 16) && (ExpPoolBigEntriesInUse > (TableSize / 4)))
1509  {
1510  DPRINT("Should attempt expansion since we now have %lu entries\n",
1512  }
1513 
1514  //
1515  // We have our entry, return
1516  //
1518  return TRUE;
1519  }
1520 
1521  //
1522  // We don't have our entry yet, so keep trying, making the entry list
1523  // circular if we reach the last entry. We'll eventually break out of
1524  // the loop once we've rolled over and returned back to our original
1525  // hash bucket
1526  //
1527  i++;
1528  if (++Entry >= EntryEnd) Entry = &PoolBigPageTable[0];
1529  } while (Entry != EntryStart);
1530 
1531  //
1532  // This means there's no free hash buckets whatsoever, so we would now have
1533  // to attempt expanding the table
1534  //
1535  DPRINT1("Big pool expansion needed, not implemented!\n");
1537  return FALSE;
1538 }
1539 
1540 ULONG
1541 NTAPI
1543  OUT PULONG_PTR BigPages,
1545 {
1546  BOOLEAN FirstTry = TRUE;
1547  SIZE_T TableSize;
1548  KIRQL OldIrql;
1549  ULONG PoolTag, Hash;
1552  ASSERT(!(PoolType & SESSION_POOL_MASK));
1553 
1554  //
1555  // As the table is expandable, these values must only be read after acquiring
1556  // the lock to avoid a teared access during an expansion
1557  //
1560  Hash &= PoolBigPageTableHash;
1561  TableSize = PoolBigPageTableSize;
1562 
1563  //
1564  // Loop while trying to find this big page allocation
1565  //
1566  while (PoolBigPageTable[Hash].Va != Va)
1567  {
1568  //
1569  // Increment the size until we go past the end of the table
1570  //
1571  if (++Hash >= TableSize)
1572  {
1573  //
1574  // Is this the second time we've tried?
1575  //
1576  if (!FirstTry)
1577  {
1578  //
1579  // This means it was never inserted into the pool table and it
1580  // received the special "BIG" tag -- return that and return 0
1581  // so that the code can ask Mm for the page count instead
1582  //
1584  *BigPages = 0;
1585  return ' GIB';
1586  }
1587 
1588  //
1589  // The first time this happens, reset the hash index and try again
1590  //
1591  Hash = 0;
1592  FirstTry = FALSE;
1593  }
1594  }
1595 
1596  //
1597  // Now capture all the information we need from the entry, since after we
1598  // release the lock, the data can change
1599  //
1600  Entry = &PoolBigPageTable[Hash];
1601  *BigPages = Entry->NumberOfPages;
1602  PoolTag = Entry->Key;
1603 
1604  //
1605  // Set the free bit, and decrement the number of allocations. Finally, release
1606  // the lock and return the tag that was located
1607  //
1608  InterlockedIncrement((PLONG)&Entry->Va);
1611  return PoolTag;
1612 }
1613 
1614 VOID
1615 NTAPI
1616 ExQueryPoolUsage(OUT PULONG PagedPoolPages,
1617  OUT PULONG NonPagedPoolPages,
1618  OUT PULONG PagedPoolAllocs,
1619  OUT PULONG PagedPoolFrees,
1620  OUT PULONG PagedPoolLookasideHits,
1621  OUT PULONG NonPagedPoolAllocs,
1622  OUT PULONG NonPagedPoolFrees,
1623  OUT PULONG NonPagedPoolLookasideHits)
1624 {
1625  ULONG i;
1626  PPOOL_DESCRIPTOR PoolDesc;
1627 
1628  //
1629  // Assume all failures
1630  //
1631  *PagedPoolPages = 0;
1632  *PagedPoolAllocs = 0;
1633  *PagedPoolFrees = 0;
1634 
1635  //
1636  // Tally up the totals for all the apged pool
1637  //
1638  for (i = 0; i < ExpNumberOfPagedPools + 1; i++)
1639  {
1640  PoolDesc = ExpPagedPoolDescriptor[i];
1641  *PagedPoolPages += PoolDesc->TotalPages + PoolDesc->TotalBigPages;
1642  *PagedPoolAllocs += PoolDesc->RunningAllocs;
1643  *PagedPoolFrees += PoolDesc->RunningDeAllocs;
1644  }
1645 
1646  //
1647  // The first non-paged pool has a hardcoded well-known descriptor name
1648  //
1649  PoolDesc = &NonPagedPoolDescriptor;
1650  *NonPagedPoolPages = PoolDesc->TotalPages + PoolDesc->TotalBigPages;
1651  *NonPagedPoolAllocs = PoolDesc->RunningAllocs;
1652  *NonPagedPoolFrees = PoolDesc->RunningDeAllocs;
1653 
1654  //
1655  // If the system has more than one non-paged pool, copy the other descriptor
1656  // totals as well
1657  //
1658 #if 0
1659  if (ExpNumberOfNonPagedPools > 1)
1660  {
1661  for (i = 0; i < ExpNumberOfNonPagedPools; i++)
1662  {
1663  PoolDesc = ExpNonPagedPoolDescriptor[i];
1664  *NonPagedPoolPages += PoolDesc->TotalPages + PoolDesc->TotalBigPages;
1665  *NonPagedPoolAllocs += PoolDesc->RunningAllocs;
1666  *NonPagedPoolFrees += PoolDesc->RunningDeAllocs;
1667  }
1668  }
1669 #endif
1670 
1671  //
1672  // FIXME: Not yet supported
1673  //
1674  *NonPagedPoolLookasideHits += 0;
1675  *PagedPoolLookasideHits += 0;
1676 }
1677 
1678 VOID
1679 NTAPI
1681 {
1684  USHORT BlockSize;
1686 
1689  {
1690  return;
1691  }
1692 
1693  Entry = P;
1694  Entry--;
1695  ASSERT((ULONG_PTR)Entry % POOL_BLOCK_SIZE == 0);
1696 
1697  PoolType = Entry->PoolType - 1;
1698  BlockSize = Entry->BlockSize;
1699 
1700  if (PoolType & QUOTA_POOL_MASK)
1701  {
1702  Process = ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1];
1703  ASSERT(Process != NULL);
1704  if (Process)
1705  {
1706  if (Process->Pcb.Header.Type != ProcessObject)
1707  {
1708  DPRINT1("Object %p is not a process. Type %u, pool type 0x%x, block size %u\n",
1709  Process, Process->Pcb.Header.Type, Entry->PoolType, BlockSize);
1710  KeBugCheckEx(BAD_POOL_CALLER,
1711  0x0D,
1712  (ULONG_PTR)P,
1713  Entry->PoolTag,
1714  (ULONG_PTR)Process);
1715  }
1716  ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1] = NULL;
1717  PsReturnPoolQuota(Process,
1718  PoolType & BASE_POOL_TYPE_MASK,
1719  BlockSize * POOL_BLOCK_SIZE);
1720  ObDereferenceObject(Process);
1721  }
1722  }
1723 }
1724 
1725 /* PUBLIC FUNCTIONS ***********************************************************/
1726 
1727 /*
1728  * @implemented
1729  */
1730 PVOID
1731 NTAPI
1734  IN ULONG Tag)
1735 {
1736  PPOOL_DESCRIPTOR PoolDesc;
1737  PLIST_ENTRY ListHead;
1738  PPOOL_HEADER Entry, NextEntry, FragmentEntry;
1739  KIRQL OldIrql;
1740  USHORT BlockSize, i;
1741  ULONG OriginalType;
1742  PKPRCB Prcb = KeGetCurrentPrcb();
1744 
1745  //
1746  // Some sanity checks
1747  //
1748  ASSERT(Tag != 0);
1749  ASSERT(Tag != ' GIB');
1750  ASSERT(NumberOfBytes != 0);
1751  ExpCheckPoolIrqlLevel(PoolType, NumberOfBytes, NULL);
1752 
1753  //
1754  // Not supported in ReactOS
1755  //
1756  ASSERT(!(PoolType & SESSION_POOL_MASK));
1757 
1758  //
1759  // Check if verifier or special pool is enabled
1760  //
1762  {
1763  //
1764  // For verifier, we should call the verification routine
1765  //
1767  {
1768  DPRINT1("Driver Verifier is not yet supported\n");
1769  }
1770 
1771  //
1772  // For special pool, we check if this is a suitable allocation and do
1773  // the special allocation if needed
1774  //
1776  {
1777  //
1778  // Check if this is a special pool allocation
1779  //
1780  if (MmUseSpecialPool(NumberOfBytes, Tag))
1781  {
1782  //
1783  // Try to allocate using special pool
1784  //
1785  Entry = MmAllocateSpecialPool(NumberOfBytes, Tag, PoolType, 2);
1786  if (Entry) return Entry;
1787  }
1788  }
1789  }
1790 
1791  //
1792  // Get the pool type and its corresponding vector for this request
1793  //
1794  OriginalType = PoolType;
1795  PoolType = PoolType & BASE_POOL_TYPE_MASK;
1796  PoolDesc = PoolVector[PoolType];
1797  ASSERT(PoolDesc != NULL);
1798 
1799  //
1800  // Check if this is a big page allocation
1801  //
1802  if (NumberOfBytes > POOL_MAX_ALLOC)
1803  {
1804  //
1805  // Allocate pages for it
1806  //
1807  Entry = MiAllocatePoolPages(OriginalType, NumberOfBytes);
1808  if (!Entry)
1809  {
1810 #if DBG
1811  //
1812  // Out of memory, display current consumption
1813  // Let's consider that if the caller wanted more
1814  // than a hundred pages, that's a bogus caller
1815  // and we are not out of memory
1816  //
1817  if (NumberOfBytes < 100 * PAGE_SIZE)
1818  {
1819  MiDumpPoolConsumers(FALSE, 0, 0, 0);
1820  }
1821 #endif
1822 
1823  //
1824  // Must succeed pool is deprecated, but still supported. These allocation
1825  // failures must cause an immediate bugcheck
1826  //
1827  if (OriginalType & MUST_SUCCEED_POOL_MASK)
1828  {
1829  KeBugCheckEx(MUST_SUCCEED_POOL_EMPTY,
1830  NumberOfBytes,
1831  NonPagedPoolDescriptor.TotalPages,
1832  NonPagedPoolDescriptor.TotalBigPages,
1833  0);
1834  }
1835 
1836  //
1837  // Internal debugging
1838  //
1839  ExPoolFailures++;
1840 
1841  //
1842  // This flag requests printing failures, and can also further specify
1843  // breaking on failures
1844  //
1846  {
1847  DPRINT1("EX: ExAllocatePool (%lu, 0x%x) returning NULL\n",
1848  NumberOfBytes,
1849  OriginalType);
1851  }
1852 
1853  //
1854  // Finally, this flag requests an exception, which we are more than
1855  // happy to raise!
1856  //
1857  if (OriginalType & POOL_RAISE_IF_ALLOCATION_FAILURE)
1858  {
1860  }
1861 
1862  return NULL;
1863  }
1864 
1865  //
1866  // Increment required counters
1867  //
1869  (LONG)BYTES_TO_PAGES(NumberOfBytes));
1870  InterlockedExchangeAddSizeT(&PoolDesc->TotalBytes, NumberOfBytes);
1872 
1873  //
1874  // Add a tag for the big page allocation and switch to the generic "BIG"
1875  // tag if we failed to do so, then insert a tracker for this alloation.
1876  //
1877  if (!ExpAddTagForBigPages(Entry,
1878  Tag,
1879  (ULONG)BYTES_TO_PAGES(NumberOfBytes),
1880  OriginalType))
1881  {
1882  Tag = ' GIB';
1883  }
1884  ExpInsertPoolTracker(Tag, ROUND_TO_PAGES(NumberOfBytes), OriginalType);
1885  return Entry;
1886  }
1887 
1888  //
1889  // Should never request 0 bytes from the pool, but since so many drivers do
1890  // it, we'll just assume they want 1 byte, based on NT's similar behavior
1891  //
1892  if (!NumberOfBytes) NumberOfBytes = 1;
1893 
1894  //
1895  // A pool allocation is defined by its data, a linked list to connect it to
1896  // the free list (if necessary), and a pool header to store accounting info.
1897  // Calculate this size, then convert it into a block size (units of pool
1898  // headers)
1899  //
1900  // Note that i cannot overflow (past POOL_LISTS_PER_PAGE) because any such
1901  // request would've been treated as a POOL_MAX_ALLOC earlier and resulted in
1902  // the direct allocation of pages.
1903  //
1904  i = (USHORT)((NumberOfBytes + sizeof(POOL_HEADER) + (POOL_BLOCK_SIZE - 1))
1905  / POOL_BLOCK_SIZE);
1907 
1908  //
1909  // Handle lookaside list optimization for both paged and nonpaged pool
1910  //
1911  if (i <= NUMBER_POOL_LOOKASIDE_LISTS)
1912  {
1913  //
1914  // Try popping it from the per-CPU lookaside list
1915  //
1916  LookasideList = (PoolType == PagedPool) ?
1917  Prcb->PPPagedLookasideList[i - 1].P :
1918  Prcb->PPNPagedLookasideList[i - 1].P;
1919  LookasideList->TotalAllocates++;
1920  Entry = (PPOOL_HEADER)InterlockedPopEntrySList(&LookasideList->ListHead);
1921  if (!Entry)
1922  {
1923  //
1924  // We failed, try popping it from the global list
1925  //
1926  LookasideList = (PoolType == PagedPool) ?
1927  Prcb->PPPagedLookasideList[i - 1].L :
1928  Prcb->PPNPagedLookasideList[i - 1].L;
1929  LookasideList->TotalAllocates++;
1930  Entry = (PPOOL_HEADER)InterlockedPopEntrySList(&LookasideList->ListHead);
1931  }
1932 
1933  //
1934  // If we were able to pop it, update the accounting and return the block
1935  //
1936  if (Entry)
1937  {
1938  LookasideList->AllocateHits++;
1939 
1940  //
1941  // Get the real entry, write down its pool type, and track it
1942  //
1943  Entry--;
1944  Entry->PoolType = OriginalType + 1;
1946  Entry->BlockSize * POOL_BLOCK_SIZE,
1947  OriginalType);
1948 
1949  //
1950  // Return the pool allocation
1951  //
1952  Entry->PoolTag = Tag;
1953  (POOL_FREE_BLOCK(Entry))->Flink = NULL;
1954  (POOL_FREE_BLOCK(Entry))->Blink = NULL;
1955  return POOL_FREE_BLOCK(Entry);
1956  }
1957  }
1958 
1959  //
1960  // Loop in the free lists looking for a block if this size. Start with the
1961  // list optimized for this kind of size lookup
1962  //
1963  ListHead = &PoolDesc->ListHeads[i];
1964  do
1965  {
1966  //
1967  // Are there any free entries available on this list?
1968  //
1969  if (!ExpIsPoolListEmpty(ListHead))
1970  {
1971  //
1972  // Acquire the pool lock now
1973  //
1974  OldIrql = ExLockPool(PoolDesc);
1975 
1976  //
1977  // And make sure the list still has entries
1978  //
1979  if (ExpIsPoolListEmpty(ListHead))
1980  {
1981  //
1982  // Someone raced us (and won) before we had a chance to acquire
1983  // the lock.
1984  //
1985  // Try again!
1986  //
1987  ExUnlockPool(PoolDesc, OldIrql);
1988  continue;
1989  }
1990 
1991  //
1992  // Remove a free entry from the list
1993  // Note that due to the way we insert free blocks into multiple lists
1994  // there is a guarantee that any block on this list will either be
1995  // of the correct size, or perhaps larger.
1996  //
1997  ExpCheckPoolLinks(ListHead);
1998  Entry = POOL_ENTRY(ExpRemovePoolHeadList(ListHead));
1999  ExpCheckPoolLinks(ListHead);
2000  ExpCheckPoolBlocks(Entry);
2001  ASSERT(Entry->BlockSize >= i);
2002  ASSERT(Entry->PoolType == 0);
2003 
2004  //
2005  // Check if this block is larger that what we need. The block could
2006  // not possibly be smaller, due to the reason explained above (and
2007  // we would've asserted on a checked build if this was the case).
2008  //
2009  if (Entry->BlockSize != i)
2010  {
2011  //
2012  // Is there an entry before this one?
2013  //
2014  if (Entry->PreviousSize == 0)
2015  {
2016  //
2017  // There isn't anyone before us, so take the next block and
2018  // turn it into a fragment that contains the leftover data
2019  // that we don't need to satisfy the caller's request
2020  //
2021  FragmentEntry = POOL_BLOCK(Entry, i);
2022  FragmentEntry->BlockSize = Entry->BlockSize - i;
2023 
2024  //
2025  // And make it point back to us
2026  //
2027  FragmentEntry->PreviousSize = i;
2028 
2029  //
2030  // Now get the block that follows the new fragment and check
2031  // if it's still on the same page as us (and not at the end)
2032  //
2033  NextEntry = POOL_NEXT_BLOCK(FragmentEntry);
2034  if (PAGE_ALIGN(NextEntry) != NextEntry)
2035  {
2036  //
2037  // Adjust this next block to point to our newly created
2038  // fragment block
2039  //
2040  NextEntry->PreviousSize = FragmentEntry->BlockSize;
2041  }
2042  }
2043  else
2044  {
2045  //
2046  // There is a free entry before us, which we know is smaller
2047  // so we'll make this entry the fragment instead
2048  //
2049  FragmentEntry = Entry;
2050 
2051  //
2052  // And then we'll remove from it the actual size required.
2053  // Now the entry is a leftover free fragment
2054  //
2055  Entry->BlockSize -= i;
2056 
2057  //
2058  // Now let's go to the next entry after the fragment (which
2059  // used to point to our original free entry) and make it
2060  // reference the new fragment entry instead.
2061  //
2062  // This is the entry that will actually end up holding the
2063  // allocation!
2064  //
2065  Entry = POOL_NEXT_BLOCK(Entry);
2066  Entry->PreviousSize = FragmentEntry->BlockSize;
2067 
2068  //
2069  // And now let's go to the entry after that one and check if
2070  // it's still on the same page, and not at the end
2071  //
2072  NextEntry = POOL_BLOCK(Entry, i);
2073  if (PAGE_ALIGN(NextEntry) != NextEntry)
2074  {
2075  //
2076  // Make it reference the allocation entry
2077  //
2078  NextEntry->PreviousSize = i;
2079  }
2080  }
2081 
2082  //
2083  // Now our (allocation) entry is the right size
2084  //
2085  Entry->BlockSize = i;
2086 
2087  //
2088  // And the next entry is now the free fragment which contains
2089  // the remaining difference between how big the original entry
2090  // was, and the actual size the caller needs/requested.
2091  //
2092  FragmentEntry->PoolType = 0;
2093  BlockSize = FragmentEntry->BlockSize;
2094 
2095  //
2096  // Now check if enough free bytes remained for us to have a
2097  // "full" entry, which contains enough bytes for a linked list
2098  // and thus can be used for allocations (up to 8 bytes...)
2099  //
2100  ExpCheckPoolLinks(&PoolDesc->ListHeads[BlockSize - 1]);
2101  if (BlockSize != 1)
2102  {
2103  //
2104  // Insert the free entry into the free list for this size
2105  //
2106  ExpInsertPoolTailList(&PoolDesc->ListHeads[BlockSize - 1],
2107  POOL_FREE_BLOCK(FragmentEntry));
2108  ExpCheckPoolLinks(POOL_FREE_BLOCK(FragmentEntry));
2109  }
2110  }
2111 
2112  //
2113  // We have found an entry for this allocation, so set the pool type
2114  // and release the lock since we're done
2115  //
2116  Entry->PoolType = OriginalType + 1;
2117  ExpCheckPoolBlocks(Entry);
2118  ExUnlockPool(PoolDesc, OldIrql);
2119 
2120  //
2121  // Increment required counters
2122  //
2125 
2126  //
2127  // Track this allocation
2128  //
2130  Entry->BlockSize * POOL_BLOCK_SIZE,
2131  OriginalType);
2132 
2133  //
2134  // Return the pool allocation
2135  //
2136  Entry->PoolTag = Tag;
2137  (POOL_FREE_BLOCK(Entry))->Flink = NULL;
2138  (POOL_FREE_BLOCK(Entry))->Blink = NULL;
2139  return POOL_FREE_BLOCK(Entry);
2140  }
2141  } while (++ListHead != &PoolDesc->ListHeads[POOL_LISTS_PER_PAGE]);
2142 
2143  //
2144  // There were no free entries left, so we have to allocate a new fresh page
2145  //
2146  Entry = MiAllocatePoolPages(OriginalType, PAGE_SIZE);
2147  if (!Entry)
2148  {
2149 #if DBG
2150  //
2151  // Out of memory, display current consumption
2152  // Let's consider that if the caller wanted more
2153  // than a hundred pages, that's a bogus caller
2154  // and we are not out of memory
2155  //
2156  if (NumberOfBytes < 100 * PAGE_SIZE)
2157  {
2158  MiDumpPoolConsumers(FALSE, 0, 0, 0);
2159  }
2160 #endif
2161 
2162  //
2163  // Must succeed pool is deprecated, but still supported. These allocation
2164  // failures must cause an immediate bugcheck
2165  //
2166  if (OriginalType & MUST_SUCCEED_POOL_MASK)
2167  {
2168  KeBugCheckEx(MUST_SUCCEED_POOL_EMPTY,
2169  PAGE_SIZE,
2170  NonPagedPoolDescriptor.TotalPages,
2171  NonPagedPoolDescriptor.TotalBigPages,
2172  0);
2173  }
2174 
2175  //
2176  // Internal debugging
2177  //
2178  ExPoolFailures++;
2179 
2180  //
2181  // This flag requests printing failures, and can also further specify
2182  // breaking on failures
2183  //
2185  {
2186  DPRINT1("EX: ExAllocatePool (%lu, 0x%x) returning NULL\n",
2187  NumberOfBytes,
2188  OriginalType);
2190  }
2191 
2192  //
2193  // Finally, this flag requests an exception, which we are more than
2194  // happy to raise!
2195  //
2196  if (OriginalType & POOL_RAISE_IF_ALLOCATION_FAILURE)
2197  {
2199  }
2200 
2201  //
2202  // Return NULL to the caller in all other cases
2203  //
2204  return NULL;
2205  }
2206 
2207  //
2208  // Setup the entry data
2209  //
2210  Entry->Ulong1 = 0;
2211  Entry->BlockSize = i;
2212  Entry->PoolType = OriginalType + 1;
2213 
2214  //
2215  // This page will have two entries -- one for the allocation (which we just
2216  // created above), and one for the remaining free bytes, which we're about
2217  // to create now. The free bytes are the whole page minus what was allocated
2218  // and then converted into units of block headers.
2219  //
2220  BlockSize = (PAGE_SIZE / POOL_BLOCK_SIZE) - i;
2221  FragmentEntry = POOL_BLOCK(Entry, i);
2222  FragmentEntry->Ulong1 = 0;
2223  FragmentEntry->BlockSize = BlockSize;
2224  FragmentEntry->PreviousSize = i;
2225 
2226  //
2227  // Increment required counters
2228  //
2229  InterlockedIncrement((PLONG)&PoolDesc->TotalPages);
2231 
2232  //
2233  // Now check if enough free bytes remained for us to have a "full" entry,
2234  // which contains enough bytes for a linked list and thus can be used for
2235  // allocations (up to 8 bytes...)
2236  //
2237  if (FragmentEntry->BlockSize != 1)
2238  {
2239  //
2240  // Excellent -- acquire the pool lock
2241  //
2242  OldIrql = ExLockPool(PoolDesc);
2243 
2244  //
2245  // And insert the free entry into the free list for this block size
2246  //
2247  ExpCheckPoolLinks(&PoolDesc->ListHeads[BlockSize - 1]);
2248  ExpInsertPoolTailList(&PoolDesc->ListHeads[BlockSize - 1],
2249  POOL_FREE_BLOCK(FragmentEntry));
2250  ExpCheckPoolLinks(POOL_FREE_BLOCK(FragmentEntry));
2251 
2252  //
2253  // Release the pool lock
2254  //
2255  ExpCheckPoolBlocks(Entry);
2256  ExUnlockPool(PoolDesc, OldIrql);
2257  }
2258  else
2259  {
2260  //
2261  // Simply do a sanity check
2262  //
2263  ExpCheckPoolBlocks(Entry);
2264  }
2265 
2266  //
2267  // Increment performance counters and track this allocation
2268  //
2271  Entry->BlockSize * POOL_BLOCK_SIZE,
2272  OriginalType);
2273 
2274  //
2275  // And return the pool allocation
2276  //
2277  ExpCheckPoolBlocks(Entry);
2278  Entry->PoolTag = Tag;
2279  return POOL_FREE_BLOCK(Entry);
2280 }
2281 
2282 /*
2283  * @implemented
2284  */
2285 PVOID
2286 NTAPI
2289 {
2290  ULONG Tag = TAG_NONE;
2291 #if 0 && DBG
2292  PLDR_DATA_TABLE_ENTRY LdrEntry;
2293 
2294  /* Use the first four letters of the driver name, or "None" if unavailable */
2295  LdrEntry = KeGetCurrentIrql() <= APC_LEVEL
2297  : NULL;
2298  if (LdrEntry)
2299  {
2300  ULONG i;
2301  Tag = 0;
2302  for (i = 0; i < min(4, LdrEntry->BaseDllName.Length / sizeof(WCHAR)); i++)
2303  Tag = Tag >> 8 | (LdrEntry->BaseDllName.Buffer[i] & 0xff) << 24;
2304  for (; i < 4; i++)
2305  Tag = Tag >> 8 | ' ' << 24;
2306  }
2307 #endif
2308  return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
2309 }
2310 
2311 /*
2312  * @implemented
2313  */
2314 VOID
2315 NTAPI
2317  IN ULONG TagToFree)
2318 {
2319  PPOOL_HEADER Entry, NextEntry;
2320  USHORT BlockSize;
2321  KIRQL OldIrql;
2323  PPOOL_DESCRIPTOR PoolDesc;
2324  ULONG Tag;
2325  BOOLEAN Combined = FALSE;
2326  PFN_NUMBER PageCount, RealPageCount;
2327  PKPRCB Prcb = KeGetCurrentPrcb();
2330 
2331  //
2332  // Check if any of the debug flags are enabled
2333  //
2340  {
2341  //
2342  // Check if special pool is enabled
2343  //
2345  {
2346  //
2347  // Check if it was allocated from a special pool
2348  //
2349  if (MmIsSpecialPoolAddress(P))
2350  {
2351  //
2352  // Was deadlock verification also enabled? We can do some extra
2353  // checks at this point
2354  //
2356  {
2357  DPRINT1("Verifier not yet supported\n");
2358  }
2359 
2360  //
2361  // It is, so handle it via special pool free routine
2362  //
2363  MmFreeSpecialPool(P);
2364  return;
2365  }
2366  }
2367 
2368  //
2369  // For non-big page allocations, we'll do a bunch of checks in here
2370  //
2371  if (PAGE_ALIGN(P) != P)
2372  {
2373  //
2374  // Get the entry for this pool allocation
2375  // The pointer math here may look wrong or confusing, but it is quite right
2376  //
2377  Entry = P;
2378  Entry--;
2379 
2380  //
2381  // Get the pool type
2382  //
2383  PoolType = (Entry->PoolType - 1) & BASE_POOL_TYPE_MASK;
2384 
2385  //
2386  // FIXME: Many other debugging checks go here
2387  //
2388  ExpCheckPoolIrqlLevel(PoolType, 0, P);
2389  }
2390  }
2391 
2392  //
2393  // Check if this is a big page allocation
2394  //
2395  if (PAGE_ALIGN(P) == P)
2396  {
2397  //
2398  // We need to find the tag for it, so first we need to find out what
2399  // kind of allocation this was (paged or nonpaged), then we can go
2400  // ahead and try finding the tag for it. Remember to get rid of the
2401  // PROTECTED_POOL tag if it's found.
2402  //
2403  // Note that if at insertion time, we failed to add the tag for a big
2404  // pool allocation, we used a special tag called 'BIG' to identify the
2405  // allocation, and we may get this tag back. In this scenario, we must
2406  // manually get the size of the allocation by actually counting through
2407  // the PFN database.
2408  //
2409  PoolType = MmDeterminePoolType(P);
2410  ExpCheckPoolIrqlLevel(PoolType, 0, P);
2411  Tag = ExpFindAndRemoveTagBigPages(P, &PageCount, PoolType);
2412  if (!Tag)
2413  {
2414  DPRINT1("We do not know the size of this allocation. This is not yet supported\n");
2415  ASSERT(Tag == ' GIB');
2416  PageCount = 1; // We are going to lie! This might screw up accounting?
2417  }
2418  else if (Tag & PROTECTED_POOL)
2419  {
2420  Tag &= ~PROTECTED_POOL;
2421  }
2422 
2423  //
2424  // Check block tag
2425  //
2426  if (TagToFree && TagToFree != Tag)
2427  {
2428  DPRINT1("Freeing pool - invalid tag specified: %.4s != %.4s\n", (char*)&TagToFree, (char*)&Tag);
2429  KeBugCheckEx(BAD_POOL_CALLER, 0x0A, (ULONG_PTR)P, Tag, TagToFree);
2430  }
2431 
2432  //
2433  // We have our tag and our page count, so we can go ahead and remove this
2434  // tracker now
2435  //
2436  ExpRemovePoolTracker(Tag, PageCount << PAGE_SHIFT, PoolType);
2437 
2438  //
2439  // Check if any of the debug flags are enabled
2440  //
2445  {
2446  //
2447  // Was deadlock verification also enabled? We can do some extra
2448  // checks at this point
2449  //
2451  {
2452  DPRINT1("Verifier not yet supported\n");
2453  }
2454 
2455  //
2456  // FIXME: Many debugging checks go here
2457  //
2458  }
2459 
2460  //
2461  // Update counters
2462  //
2463  PoolDesc = PoolVector[PoolType];
2466  -(LONG_PTR)(PageCount << PAGE_SHIFT));
2467 
2468  //
2469  // Do the real free now and update the last counter with the big page count
2470  //
2471  RealPageCount = MiFreePoolPages(P);
2472  ASSERT(RealPageCount == PageCount);
2474  -(LONG)RealPageCount);
2475  return;
2476  }
2477 
2478  //
2479  // Get the entry for this pool allocation
2480  // The pointer math here may look wrong or confusing, but it is quite right
2481  //
2482  Entry = P;
2483  Entry--;
2484  ASSERT((ULONG_PTR)Entry % POOL_BLOCK_SIZE == 0);
2485 
2486  //
2487  // Get the size of the entry, and it's pool type, then load the descriptor
2488  // for this pool type
2489  //
2490  BlockSize = Entry->BlockSize;
2491  PoolType = (Entry->PoolType - 1) & BASE_POOL_TYPE_MASK;
2492  PoolDesc = PoolVector[PoolType];
2493 
2494  //
2495  // Make sure that the IRQL makes sense
2496  //
2497  ExpCheckPoolIrqlLevel(PoolType, 0, P);
2498 
2499  //
2500  // Get the pool tag and get rid of the PROTECTED_POOL flag
2501  //
2502  Tag = Entry->PoolTag;
2503  if (Tag & PROTECTED_POOL) Tag &= ~PROTECTED_POOL;
2504 
2505  //
2506  // Check block tag
2507  //
2508  if (TagToFree && TagToFree != Tag)
2509  {
2510  DPRINT1("Freeing pool - invalid tag specified: %.4s != %.4s\n", (char*)&TagToFree, (char*)&Tag);
2511  KeBugCheckEx(BAD_POOL_CALLER, 0x0A, (ULONG_PTR)P, Tag, TagToFree);
2512  }
2513 
2514  //
2515  // Track the removal of this allocation
2516  //
2518  BlockSize * POOL_BLOCK_SIZE,
2519  Entry->PoolType - 1);
2520 
2521  //
2522  // Release pool quota, if any
2523  //
2524  if ((Entry->PoolType - 1) & QUOTA_POOL_MASK)
2525  {
2526  Process = ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1];
2527  if (Process)
2528  {
2529  if (Process->Pcb.Header.Type != ProcessObject)
2530  {
2531  DPRINT1("Object %p is not a process. Type %u, pool type 0x%x, block size %u\n",
2532  Process, Process->Pcb.Header.Type, Entry->PoolType, BlockSize);
2533  KeBugCheckEx(BAD_POOL_CALLER,
2534  0x0D,
2535  (ULONG_PTR)P,
2536  Tag,
2537  (ULONG_PTR)Process);
2538  }
2539  PsReturnPoolQuota(Process, PoolType, BlockSize * POOL_BLOCK_SIZE);
2540  ObDereferenceObject(Process);
2541  }
2542  }
2543 
2544  //
2545  // Is this allocation small enough to have come from a lookaside list?
2546  //
2547  if (BlockSize <= NUMBER_POOL_LOOKASIDE_LISTS)
2548  {
2549  //
2550  // Try pushing it into the per-CPU lookaside list
2551  //
2552  LookasideList = (PoolType == PagedPool) ?
2553  Prcb->PPPagedLookasideList[BlockSize - 1].P :
2554  Prcb->PPNPagedLookasideList[BlockSize - 1].P;
2555  LookasideList->TotalFrees++;
2556  if (ExQueryDepthSList(&LookasideList->ListHead) < LookasideList->Depth)
2557  {
2558  LookasideList->FreeHits++;
2559  InterlockedPushEntrySList(&LookasideList->ListHead, P);
2560  return;
2561  }
2562 
2563  //
2564  // We failed, try to push it into the global lookaside list
2565  //
2566  LookasideList = (PoolType == PagedPool) ?
2567  Prcb->PPPagedLookasideList[BlockSize - 1].L :
2568  Prcb->PPNPagedLookasideList[BlockSize - 1].L;
2569  LookasideList->TotalFrees++;
2570  if (ExQueryDepthSList(&LookasideList->ListHead) < LookasideList->Depth)
2571  {
2572  LookasideList->FreeHits++;
2573  InterlockedPushEntrySList(&LookasideList->ListHead, P);
2574  return;
2575  }
2576  }
2577 
2578  //
2579  // Get the pointer to the next entry
2580  //
2581  NextEntry = POOL_BLOCK(Entry, BlockSize);
2582 
2583  //
2584  // Update performance counters
2585  //
2587  InterlockedExchangeAddSizeT(&PoolDesc->TotalBytes, -BlockSize * POOL_BLOCK_SIZE);
2588 
2589  //
2590  // Acquire the pool lock
2591  //
2592  OldIrql = ExLockPool(PoolDesc);
2593 
2594  //
2595  // Check if the next allocation is at the end of the page
2596  //
2597  ExpCheckPoolBlocks(Entry);
2598  if (PAGE_ALIGN(NextEntry) != NextEntry)
2599  {
2600  //
2601  // We may be able to combine the block if it's free
2602  //
2603  if (NextEntry->PoolType == 0)
2604  {
2605  //
2606  // The next block is free, so we'll do a combine
2607  //
2608  Combined = TRUE;
2609 
2610  //
2611  // Make sure there's actual data in the block -- anything smaller
2612  // than this means we only have the header, so there's no linked list
2613  // for us to remove
2614  //
2615  if ((NextEntry->BlockSize != 1))
2616  {
2617  //
2618  // The block is at least big enough to have a linked list, so go
2619  // ahead and remove it
2620  //
2621  ExpCheckPoolLinks(POOL_FREE_BLOCK(NextEntry));
2623  ExpCheckPoolLinks(ExpDecodePoolLink((POOL_FREE_BLOCK(NextEntry))->Flink));
2624  ExpCheckPoolLinks(ExpDecodePoolLink((POOL_FREE_BLOCK(NextEntry))->Blink));
2625  }
2626 
2627  //
2628  // Our entry is now combined with the next entry
2629  //
2630  Entry->BlockSize = Entry->BlockSize + NextEntry->BlockSize;
2631  }
2632  }
2633 
2634  //
2635  // Now check if there was a previous entry on the same page as us
2636  //
2637  if (Entry->PreviousSize)
2638  {
2639  //
2640  // Great, grab that entry and check if it's free
2641  //
2642  NextEntry = POOL_PREV_BLOCK(Entry);
2643  if (NextEntry->PoolType == 0)
2644  {
2645  //
2646  // It is, so we can do a combine
2647  //
2648  Combined = TRUE;
2649 
2650  //
2651  // Make sure there's actual data in the block -- anything smaller
2652  // than this means we only have the header so there's no linked list
2653  // for us to remove
2654  //
2655  if ((NextEntry->BlockSize != 1))
2656  {
2657  //
2658  // The block is at least big enough to have a linked list, so go
2659  // ahead and remove it
2660  //
2661  ExpCheckPoolLinks(POOL_FREE_BLOCK(NextEntry));
2663  ExpCheckPoolLinks(ExpDecodePoolLink((POOL_FREE_BLOCK(NextEntry))->Flink));
2664  ExpCheckPoolLinks(ExpDecodePoolLink((POOL_FREE_BLOCK(NextEntry))->Blink));
2665  }
2666 
2667  //
2668  // Combine our original block (which might've already been combined
2669  // with the next block), into the previous block
2670  //
2671  NextEntry->BlockSize = NextEntry->BlockSize + Entry->BlockSize;
2672 
2673  //
2674  // And now we'll work with the previous block instead
2675  //
2676  Entry = NextEntry;
2677  }
2678  }
2679 
2680  //
2681  // By now, it may have been possible for our combined blocks to actually
2682  // have made up a full page (if there were only 2-3 allocations on the
2683  // page, they could've all been combined).
2684  //
2685  if ((PAGE_ALIGN(Entry) == Entry) &&
2686  (PAGE_ALIGN(POOL_NEXT_BLOCK(Entry)) == POOL_NEXT_BLOCK(Entry)))
2687  {
2688  //
2689  // In this case, release the pool lock, update the performance counter,
2690  // and free the page
2691  //
2692  ExUnlockPool(PoolDesc, OldIrql);
2693  InterlockedExchangeAdd((PLONG)&PoolDesc->TotalPages, -1);
2694  MiFreePoolPages(Entry);
2695  return;
2696  }
2697 
2698  //
2699  // Otherwise, we now have a free block (or a combination of 2 or 3)
2700  //
2701  Entry->PoolType = 0;
2702  BlockSize = Entry->BlockSize;
2703  ASSERT(BlockSize != 1);
2704 
2705  //
2706  // Check if we actually did combine it with anyone
2707  //
2708  if (Combined)
2709  {
2710  //
2711  // Get the first combined block (either our original to begin with, or
2712  // the one after the original, depending if we combined with the previous)
2713  //
2714  NextEntry = POOL_NEXT_BLOCK(Entry);
2715 
2716  //
2717  // As long as the next block isn't on a page boundary, have it point
2718  // back to us
2719  //
2720  if (PAGE_ALIGN(NextEntry) != NextEntry) NextEntry->PreviousSize = BlockSize;
2721  }
2722 
2723  //
2724  // Insert this new free block, and release the pool lock
2725  //
2726  ExpInsertPoolHeadList(&PoolDesc->ListHeads[BlockSize - 1], POOL_FREE_BLOCK(Entry));
2728  ExUnlockPool(PoolDesc, OldIrql);
2729 }
2730 
2731 /*
2732  * @implemented
2733  */
2734 VOID
2735 NTAPI
2737 {
2738  //
2739  // Just free without checking for the tag
2740  //
2741  ExFreePoolWithTag(P, 0);
2742 }
2743 
2744 /*
2745  * @unimplemented
2746  */
2747 SIZE_T
2748 NTAPI
2751 {
2752  //
2753  // Not implemented
2754  //
2755  UNIMPLEMENTED;
2756  return FALSE;
2757 }
2758 
2759 /*
2760  * @implemented
2761  */
2762 
2763 PVOID
2764 NTAPI
2767 {
2768  //
2769  // Allocate the pool
2770  //
2771  return ExAllocatePoolWithQuotaTag(PoolType, NumberOfBytes, TAG_NONE);
2772 }
2773 
2774 /*
2775  * @implemented
2776  */
2777 PVOID
2778 NTAPI
2781  IN ULONG Tag,
2783 {
2784  PVOID Buffer;
2785 
2786  //
2787  // Allocate the pool
2788  //
2789  Buffer = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
2790  if (Buffer == NULL)
2791  {
2792  UNIMPLEMENTED;
2793  }
2794 
2795  return Buffer;
2796 }
2797 
2798 /*
2799  * @implemented
2800  */
2801 PVOID
2802 NTAPI
2805  IN ULONG Tag)
2806 {
2807  BOOLEAN Raise = TRUE;
2808  PVOID Buffer;
2810  NTSTATUS Status;
2812 
2813  //
2814  // Check if we should fail instead of raising an exception
2815  //
2816  if (PoolType & POOL_QUOTA_FAIL_INSTEAD_OF_RAISE)
2817  {
2818  Raise = FALSE;
2819  PoolType &= ~POOL_QUOTA_FAIL_INSTEAD_OF_RAISE;
2820  }
2821 
2822  //
2823  // Inject the pool quota mask
2824  //
2825  PoolType += QUOTA_POOL_MASK;
2826 
2827  //
2828  // Check if we have enough space to add the quota owner process, as long as
2829  // this isn't the system process, which never gets charged quota
2830  //
2831  ASSERT(NumberOfBytes != 0);
2832  if ((NumberOfBytes <= (PAGE_SIZE - POOL_BLOCK_SIZE - sizeof(PVOID))) &&
2833  (Process != PsInitialSystemProcess))
2834  {
2835  //
2836  // Add space for our EPROCESS pointer
2837  //
2838  NumberOfBytes += sizeof(PEPROCESS);
2839  }
2840  else
2841  {
2842  //
2843  // We won't be able to store the pointer, so don't use quota for this
2844  //
2845  PoolType -= QUOTA_POOL_MASK;
2846  }
2847 
2848  //
2849  // Allocate the pool buffer now
2850  //
2851  Buffer = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
2852 
2853  //
2854  // If the buffer is page-aligned, this is a large page allocation and we
2855  // won't touch it
2856  //
2857  if (PAGE_ALIGN(Buffer) != Buffer)
2858  {
2859  //
2860  // Also if special pool is enabled, and this was allocated from there,
2861  // we won't touch it either
2862  //
2864  (MmIsSpecialPoolAddress(Buffer)))
2865  {
2866  return Buffer;
2867  }
2868 
2869  //
2870  // If it wasn't actually allocated with quota charges, ignore it too
2871  //
2872  if (!(PoolType & QUOTA_POOL_MASK)) return Buffer;
2873 
2874  //
2875  // If this is the system process, we don't charge quota, so ignore
2876  //
2877  if (Process == PsInitialSystemProcess) return Buffer;
2878 
2879  //
2880  // Actually go and charge quota for the process now
2881  //
2882  Entry = POOL_ENTRY(Buffer);
2883  Status = PsChargeProcessPoolQuota(Process,
2884  PoolType & BASE_POOL_TYPE_MASK,
2885  Entry->BlockSize * POOL_BLOCK_SIZE);
2886  if (!NT_SUCCESS(Status))
2887  {
2888  //
2889  // Quota failed, back out the allocation, clear the owner, and fail
2890  //
2891  ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1] = NULL;
2892  ExFreePoolWithTag(Buffer, Tag);
2893  if (Raise) RtlRaiseStatus(Status);
2894  return NULL;
2895  }
2896 
2897  //
2898  // Quota worked, write the owner and then reference it before returning
2899  //
2900  ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1] = Process;
2901  ObReferenceObject(Process);
2902  }
2903  else if (!(Buffer) && (Raise))
2904  {
2905  //
2906  // The allocation failed, raise an error if we are in raise mode
2907  //
2909  }
2910 
2911  //
2912  // Return the allocated buffer
2913  //
2914  return Buffer;
2915 }
2916 
2917 #if DBG && defined(KDBG)
2918 
2919 BOOLEAN
2921  ULONG Argc,
2922  PCHAR Argv[])
2923 {
2924  ULONG_PTR Address = 0, Flags = 0;
2925  PVOID PoolPage;
2927  BOOLEAN ThisOne;
2928  PULONG Data;
2929 
2930  if (Argc > 1)
2931  {
2932  /* Get address */
2933  if (!KdbpGetHexNumber(Argv[1], &Address))
2934  {
2935  KdbpPrint("Invalid parameter: %s\n", Argv[0]);
2936  return TRUE;
2937  }
2938  }
2939 
2940  if (Argc > 2)
2941  {
2942  /* Get address */
2943  if (!KdbpGetHexNumber(Argv[1], &Flags))
2944  {
2945  KdbpPrint("Invalid parameter: %s\n", Argv[0]);
2946  return TRUE;
2947  }
2948  }
2949 
2950  /* Check if we got an address */
2951  if (Address != 0)
2952  {
2953  /* Get the base page */
2954  PoolPage = PAGE_ALIGN(Address);
2955  }
2956  else
2957  {
2958  KdbpPrint("Heap is unimplemented\n");
2959  return TRUE;
2960  }
2961 
2962  /* No paging support! */
2963  if (!MmIsAddressValid(PoolPage))
2964  {
2965  KdbpPrint("Address not accessible!\n");
2966  return TRUE;
2967  }
2968 
2969  /* Get pool type */
2970  if ((Address >= (ULONG_PTR)MmPagedPoolStart) && (Address <= (ULONG_PTR)MmPagedPoolEnd))
2971  KdbpPrint("Allocation is from PagedPool region\n");
2972  else if ((Address >= (ULONG_PTR)MmNonPagedPoolStart) && (Address <= (ULONG_PTR)MmNonPagedPoolEnd))
2973  KdbpPrint("Allocation is from NonPagedPool region\n");
2974  else
2975  {
2976  KdbpPrint("Address 0x%p is not within any pool!\n", (PVOID)Address);
2977  return TRUE;
2978  }
2979 
2980  /* Loop all entries of that page */
2981  Entry = PoolPage;
2982  do
2983  {
2984  /* Check if the address is within that entry */
2985  ThisOne = ((Address >= (ULONG_PTR)Entry) &&
2986  (Address < (ULONG_PTR)(Entry + Entry->BlockSize)));
2987 
2988  if (!(Flags & 1) || ThisOne)
2989  {
2990  /* Print the line */
2991  KdbpPrint("%c%p size: %4d previous size: %4d %s %.4s\n",
2992  ThisOne ? '*' : ' ', Entry, Entry->BlockSize, Entry->PreviousSize,
2993  (Flags & 0x80000000) ? "" : (Entry->PoolType ? "(Allocated)" : "(Free) "),
2994  (Flags & 0x80000000) ? "" : (PCHAR)&Entry->PoolTag);
2995  }
2996 
2997  if (Flags & 1)
2998  {
2999  Data = (PULONG)(Entry + 1);
3000  KdbpPrint(" %p %08lx %08lx %08lx %08lx\n"
3001  " %p %08lx %08lx %08lx %08lx\n",
3002  &Data[0], Data[0], Data[1], Data[2], Data[3],
3003  &Data[4], Data[4], Data[5], Data[6], Data[7]);
3004  }
3005 
3006  /* Go to next entry */
3007  Entry = POOL_BLOCK(Entry, Entry->BlockSize);
3008  }
3009  while ((Entry->BlockSize != 0) && ((ULONG_PTR)Entry < (ULONG_PTR)PoolPage + PAGE_SIZE));
3010 
3011  return TRUE;
3012 }
3013 
3014 static
3015 VOID
3016 ExpKdbgExtPoolUsedGetTag(PCHAR Arg, PULONG Tag, PULONG Mask)
3017 {
3018  CHAR Tmp[4];
3019  ULONG Len;
3020  USHORT i;
3021 
3022  /* Get the tag */
3023  Len = strlen(Arg);
3024  if (Len > 4)
3025  {
3026  Len = 4;
3027  }
3028 
3029  /* Generate the mask to have wildcards support */
3030  for (i = 0; i < Len; ++i)
3031  {
3032  Tmp[i] = Arg[i];
3033  if (Tmp[i] != '?')
3034  {
3035  *Mask |= (0xFF << i * 8);
3036  }
3037  }
3038 
3039  /* Get the tag in the ulong form */
3040  *Tag = *((PULONG)Tmp);
3041 }
3042 
3043 BOOLEAN
3045  ULONG Argc,
3046  PCHAR Argv[])
3047 {
3048  ULONG Tag = 0;
3049  ULONG Mask = 0;
3050  ULONG Flags = 0;
3051 
3052  if (Argc > 1)
3053  {
3054  /* If we have 2+ args, easy: flags then tag */
3055  if (Argc > 2)
3056  {
3057  ExpKdbgExtPoolUsedGetTag(Argv[2], &Tag, &Mask);
3058  if (!KdbpGetHexNumber(Argv[1], &Flags))
3059  {
3060  KdbpPrint("Invalid parameter: %s\n", Argv[0]);
3061  }
3062  }
3063  else
3064  {
3065  /* Otherwise, try to find out whether that's flags */
3066  if (strlen(Argv[1]) == 1 ||
3067  (strlen(Argv[1]) == 3 && Argv[1][0] == '0' && Argv[1][1] == 'x'))
3068  {
3069  /* Fallback: if reading flags failed, assume it's a tag */
3070  if (!KdbpGetHexNumber(Argv[1], &Flags))
3071  {
3072  ExpKdbgExtPoolUsedGetTag(Argv[1], &Tag, &Mask);
3073  }
3074  }
3075  /* Or tag */
3076  else
3077  {
3078  ExpKdbgExtPoolUsedGetTag(Argv[1], &Tag, &Mask);
3079  }
3080  }
3081  }
3082 
3083  /* Call the dumper */
3084  MiDumpPoolConsumers(TRUE, Tag, Mask, Flags);
3085 
3086  return TRUE;
3087 }
3088 
3089 #endif // DBG && KDBG
3090 
3091 /* EOF */
DWORD *typedef PVOID
Definition: winlogon.h:52
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
PVOID NTAPI ExAllocatePoolWithTag(IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes, IN ULONG Tag)
Definition: expool.c:1732
signed char * PCHAR
Definition: retypes.h:7
static int Hash(const char *)
Definition: reader.c:2258
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:39
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
#define IN
Definition: typedefs.h:38
DECLSPEC_NORETURN NTSYSAPI VOID NTAPI RtlRaiseStatus(_In_ NTSTATUS Status)
GENERAL_LOOKASIDE_POOL PPNPagedLookasideList[NUMBER_POOL_LOOKASIDE_LISTS]
Definition: ketypes.h:625
#define max(a, b)
Definition: svc.c:63
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
VOID NTAPI ExpCheckPoolLinks(IN PLIST_ENTRY ListHead)
Definition: expool.c:89
PLIST_ENTRY NTAPI ExpRemovePoolHeadList(IN PLIST_ENTRY ListHead)
Definition: expool.c:129
PVOID ULONG Address
Definition: oprghdlr.h:14
ULONG PagedAllocs
Definition: extypes.h:1129
BOOLEAN NTAPI ExpIsPoolListEmpty(IN PLIST_ENTRY ListHead)
Definition: expool.c:111
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
SIZE_T PoolTrackTableMask
Definition: expool.c:38
#define SESSION_POOL_MASK
Definition: mm.h:102
PVOID NTAPI ExAllocatePoolWithQuotaTag(IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes, IN ULONG Tag)
Definition: expool.c:2803
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133
NTSTATUS NTAPI PsChargeProcessPoolQuota(IN PEPROCESS Process, IN POOL_TYPE PoolType, IN SIZE_T Amount)
Definition: quota.c:220
#define POOL_FLAG_VERIFIER
Definition: miarm.h:260
struct _Entry Entry
Definition: kefuncs.h:640
SIZE_T PoolTrackTableSize
Definition: expool.c:28
struct _KGUARDED_MUTEX * PKGUARDED_MUTEX
VOID NTAPI ExpCheckPoolAllocation(PVOID P, POOL_TYPE PoolType, ULONG Tag)
Definition: expool.c:286
VOID FASTCALL KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:42
BOOL Verbose
Definition: chkdsk.c:69
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel)?(CompletionRoutine!=NULL):TRUE)
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:182
#define POOL_FLAG_SPECIAL_POOL
Definition: miarm.h:262
struct _LIST_ENTRY * Blink
Definition: typedefs.h:120
return STATUS_SUCCESS
Definition: btrfs.c:2690
#define ExReleaseSpinLock(Lock, OldIrql)
char CHAR
Definition: xmlstorage.h:175
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1054
struct _EPROCESS * PEPROCESS
Definition: nt_native.h:30
PLIST_ENTRY NTAPI ExpEncodePoolLink(IN PLIST_ENTRY Link)
Definition: expool.c:82
_In_ KPRIORITY Priority
Definition: kefuncs.h:516
SIZE_T PoolTrackTableSize
Definition: expool.c:38
PLDR_DATA_TABLE_ENTRY NTAPI MiLookupDataTableEntry(IN PVOID Address)
Definition: sysldr.c:3365
#define POOL_FLAG_CRASH_ON_FAILURE
Definition: miarm.h:264
#define ExRaiseStatus
Definition: ntoskrnl.h:94
#define MAXULONG_PTR
Definition: basetsd.h:103
#define POOL_PREV_BLOCK(x)
Definition: expool.c:55
PVOID MmPagedPoolEnd
Definition: init.c:26
VOID NTAPI ExpRemovePoolEntryList(IN PLIST_ENTRY Entry)
Definition: expool.c:118
BOOLEAN ExpKdbgExtPool(ULONG Argc, PCHAR Argv[])
SIZE_T TotalBytes
Definition: miarm.h:300
LONG_PTR SSIZE_T
Definition: basetsd.h:183
PVOID ULONG ULONG PULONG Data
Definition: oprghdlr.h:14
VOID NTAPI ExReturnPoolQuota(IN PVOID P)
Definition: expool.c:1680
VOID NTAPI ExpInsertPoolHeadList(IN PLIST_ENTRY ListHead, IN PLIST_ENTRY Entry)
Definition: expool.c:168
#define POOL_FREE_IRQL_INVALID
Definition: miarm.h:284
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
ULONG NonPagedFrees
Definition: extypes.h:1133
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
PKGUARDED_MUTEX ExpPagedPoolMutex
Definition: expool.c:37
VOID NTAPI ExpInitializePoolListHead(IN PLIST_ENTRY ListHead)
Definition: expool.c:104
void DbgBreakPoint()
Definition: mach.c:558
#define TAG_NONE
Definition: tag.h:127
ULONG RunningDeAllocs
Definition: miarm.h:293
LIST_ENTRY ListHeads[POOL_LISTS_PER_PAGE]
Definition: miarm.h:302
PVOID NTAPI MmAllocateSpecialPool(IN SIZE_T NumberOfBytes, IN ULONG Tag, IN POOL_TYPE PoolType, IN ULONG SpecialType)
#define ExAcquireSpinLock(Lock, OldIrql)
BOOLEAN NTAPI KdbpGetHexNumber(IN PCHAR pszNum, OUT ULONG_PTR *pulValue)
Definition: kdb_cli.c:419
ULONG PoolHitTag
Definition: expool.c:43
static int Link(const char **args)
Definition: vfdcmd.c:2414
PSLIST_ENTRY WINAPI InterlockedPopEntrySList(PSLIST_HEADER ListHead)
Definition: interlocked.c:55
BOOLEAN NTAPI ExpAddTagForBigPages(IN PVOID Va, IN ULONG Key, IN ULONG NumberOfPages, IN POOL_TYPE PoolType)
Definition: expool.c:1453
NTSTATUS NTAPI ExGetPoolTagInfo(IN PSYSTEM_POOLTAG_INFORMATION SystemInformation, IN ULONG SystemInformationLength, IN OUT PULONG ReturnLength OPTIONAL)
Definition: expool.c:1348
PVOID MmNonPagedPoolEnd
Definition: mminit.c:99
uint32_t ULONG_PTR
Definition: typedefs.h:63
KSPIN_LOCK ExpLargePoolTableLock
Definition: expool.c:45
FORCEINLINE ULONG KeGetCurrentProcessorNumber(VOID)
Definition: ke.h:325
#define POOL_FLAG_CHECK_TIMERS
Definition: miarm.h:257
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define POOL_FREE_BLOCK(x)
Definition: expool.c:52
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
GLenum GLclampf GLint i
Definition: glfuncs.h:14
struct _POOL_DPC_CONTEXT POOL_DPC_CONTEXT
ULONG PFN_NUMBER
Definition: ke.h:8
SIZE_T PoolTrackTableSizeExpansion
Definition: expool.c:30
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
PEPROCESS PsInitialSystemProcess
Definition: psmgr.c:50
PPOOL_DESCRIPTOR PoolVector[2]
Definition: expool.c:36
long LONG
Definition: pedump.c:60
#define POOL_NEXT_BLOCK(x)
Definition: expool.c:54
struct LOOKASIDE_ALIGN _GENERAL_LOOKASIDE * PGENERAL_LOOKASIDE
enum _EX_POOL_PRIORITY EX_POOL_PRIORITY
SIZE_T PoolBigPageTableSize
Definition: expool.c:39
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
VOID NTAPI PsReturnPoolQuota(IN PEPROCESS Process, IN POOL_TYPE PoolType, IN SIZE_T Amount)
Definition: quota.c:237
#define POOL_BLOCK(x, i)
Definition: expool.c:53
#define PsGetCurrentProcess
Definition: psfuncs.h:17
PPOOL_TRACKER_TABLE PoolTrackTableExpansion
Definition: expool.c:29
FORCEINLINE VOID KeInitializeSpinLock(_Out_ PKSPIN_LOCK SpinLock)
Definition: kefuncs.h:251
_Must_inspect_result_ _In_ LPCGUID ULONG _In_ FSRTL_ALLOCATE_ECP_FLAGS _In_opt_ PFSRTL_EXTRA_CREATE_PARAMETER_CLEANUP_CALLBACK _In_ ULONG PoolTag
Definition: fltkernel.h:2520
struct _POOL_DPC_CONTEXT * PPOOL_DPC_CONTEXT
VOID NTAPI ExpCheckPoolHeader(IN PPOOL_HEADER Entry)
Definition: expool.c:183
smooth NULL
Definition: ftsmooth.c:416
VOID * Table
Definition: acefiex.h:656
#define POOL_ENTRY(x)
Definition: expool.c:51
ULONG ExpNumberOfPagedPools
Definition: expool.c:33
#define FORCEINLINE
Definition: ntbasedef.h:221
void DPRINT(...)
Definition: polytest.cpp:61
ULONG ExpPoolBigEntriesInUse
Definition: expool.c:46
SIZE_T NonPagedBytes
Definition: miarm.h:351
ULONG NonPagedAllocs
Definition: extypes.h:1132
ULONG NTAPI ExpFindAndRemoveTagBigPages(IN PVOID Va, OUT PULONG_PTR BigPages, IN POOL_TYPE PoolType)
Definition: expool.c:1542
#define BASE_POOL_TYPE_MASK
Definition: ExPools.c:15
struct _POOL_TRACKER_TABLE POOL_TRACKER_TABLE
struct _POOL_HEADER * PPOOL_HEADER
#define InterlockedExchangeAdd
Definition: interlocked.h:181
#define POOL_ALLOC_IRQL_INVALID
Definition: miarm.h:283
UINTN Size
Definition: acefiex.h:555
PVOID NTAPI ExAllocatePool(POOL_TYPE PoolType, SIZE_T NumberOfBytes)
Definition: expool.c:2287
SIZE_T NonPagedUsed
Definition: extypes.h:1134
VOID NTAPI ExpCheckPoolBlocks(IN PVOID Block)
Definition: expool.c:366
#define DBG_UNREFERENCED_LOCAL_VARIABLE(L)
Definition: ntbasedef.h:326
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:675
PLIST_ENTRY NTAPI ExpDecodePoolLink(IN PLIST_ENTRY Link)
Definition: expool.c:75
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
unsigned char BOOLEAN
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
_In_ LARGE_INTEGER _In_opt_ PKDPC Dpc
Definition: kefuncs.h:524
BOOLEAN ExStopBadTags
Definition: expool.c:44
POOL_TYPE NTAPI MmDeterminePoolType(IN PVOID VirtualAddress)
Definition: pool.c:406
LONG NTSTATUS
Definition: precomp.h:26
VOID NTAPI ExpRemovePoolTracker(IN ULONG Key, IN SIZE_T NumberOfBytes, IN POOL_TYPE PoolType)
Definition: expool.c:754
_Out_ PBOOLEAN QuotaCharged
Definition: exfuncs.h:945
ULONG RunningAllocs
Definition: miarm.h:292
if(!(yy_init))
Definition: macro.lex.yy.c:717
PPOOL_TRACKER_TABLE PoolTrackTable
Definition: expool.c:40
VOID NTAPI INIT_SECTION InitializePool(IN POOL_TYPE PoolType, IN ULONG Threshold)
Definition: expool.c:1015
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
PPOOL_DESCRIPTOR ExpPagedPoolDescriptor[16+1]
Definition: expool.c:35
INT POOL_TYPE
Definition: typedefs.h:76
VOID NTAPI ExpGetPoolTagInfoTarget(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: expool.c:1313
uint64_t ULONGLONG
Definition: typedefs.h:65
VOID NTAPI INIT_SECTION ExpSeedHotTags(VOID)
Definition: expool.c:634
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
POOL_DESCRIPTOR NonPagedPoolDescriptor
Definition: expool.c:34
SIZE_T PagedUsed
Definition: extypes.h:1131
static const UCHAR Index[8]
Definition: usbohci.c:11
#define PROTECTED_POOL
Definition: extypes.h:294
VOID FASTCALL KeReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber, IN KIRQL OldIrql)
Definition: spinlock.c:154
#define PAGE_ALIGN(Va)
LONG NonPagedFrees
Definition: miarm.h:350
#define Len
Definition: deflate.h:82
FORCEINLINE USHORT ExQueryDepthSList(_In_ PSLIST_HEADER SListHead)
Definition: exfuncs.h:153
PPOOL_TRACKER_TABLE PoolTrackTable
Definition: expool.c:27
#define MUST_SUCCEED_POOL_MASK
Definition: mm.h:99
UINTN VOID * Buffer
Definition: acefiex.h:370
SIZE_T PagedBytes
Definition: miarm.h:354
BOOLEAN NTAPI MmIsAddressValid(IN PVOID VirtualAddress)
Definition: mmsup.c:174
ULONG TotalPages
Definition: miarm.h:294
PVOID NTAPI MiAllocatePoolPages(IN POOL_TYPE PoolType, IN SIZE_T SizeInBytes)
Definition: pool.c:420
#define BYTES_TO_PAGES(Size)
#define INIT_SECTION
Definition: cdfs.h:11
ULONG NTAPI MiFreePoolPages(IN PVOID StartingAddress)
Definition: pool.c:901
VOID NTAPI ExpInsertPoolTailList(IN PLIST_ENTRY ListHead, IN PLIST_ENTRY Entry)
Definition: expool.c:153
char * PBOOLEAN
Definition: retypes.h:11
#define InterlockedExchangeAddSizeT(a, b)
Definition: interlocked.h:196
FORCEINLINE KIRQL ExLockPool(IN PPOOL_DESCRIPTOR Descriptor)
Definition: expool.c:1265
VOID KdbpPrint(IN PCHAR Format, IN...OPTIONAL)
Prints the given string with printf-like formatting.
Definition: kdb_cli.c:2468
IN REFCLSID IN PUNKNOWN IN POOL_TYPE PoolType
Definition: unknown.h:68
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
Definition: ketypes.h:687
IN SIZE_T NumberOfBytes
Definition: ndis.h:3915
FORCEINLINE VOID ExpCheckPoolIrqlLevel(IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes, IN PVOID Entry)
Definition: expool.c:406
Definition: btrfs_drv.h:1762
#define InterlockedDecrementUL(Addend)
Definition: ex.h:1466
ULONG PagedFrees
Definition: extypes.h:1130
#define PAGE_SIZE
Definition: env_spec_w32.h:49
Definition: typedefs.h:117
BOOLEAN ExpKdbgExtPoolUsed(ULONG Argc, PCHAR Argv[])
KPROCESS Pcb
Definition: pstypes.h:1194
NTKERNELAPI PSLIST_ENTRY FASTCALL InterlockedPushEntrySList(IN PSLIST_HEADER ListHead, IN PSLIST_ENTRY ListEntry)
Definition: interlocked.c:82
Definition: copy.c:32
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
KIRQL FASTCALL KeAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber)
Definition: spinlock.c:108
PVOID NTAPI ExAllocatePoolWithQuota(IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes)
Definition: expool.c:2765
UCHAR KeNumberNodes
Definition: krnlinit.c:40
Status
Definition: gdiplustypes.h:24
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:675
PVOID MmPagedPoolStart
Definition: miarm.h:554
PVOID MmNonPagedPoolStart
Definition: init.c:24
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
ULONG TotalBigPages
Definition: miarm.h:295
#define POOL_FLAG_CHECK_DEADLOCK
Definition: miarm.h:261
ULONG_PTR SIZE_T
Definition: typedefs.h:78
VOID NTAPI INIT_SECTION ExInitializePoolDescriptor(IN PPOOL_DESCRIPTOR PoolDescriptor, IN POOL_TYPE PoolType, IN ULONG PoolIndex, IN ULONG Threshold, IN PVOID PoolLock)
Definition: expool.c:964
VOID FASTCALL KeInitializeGuardedMutex(OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:31
#define QUOTA_POOL_MASK
Definition: ExPools.c:16
#define InterlockedIncrement
Definition: armddk.h:53
VOID NTAPI KeSignalCallDpcDone(IN PVOID SystemArgument1)
Definition: dpc.c:1012
USHORT PreviousSize
#define NUMBER_POOL_LOOKASIDE_LISTS
Definition: ketypes.h:286
#define ROUND_TO_PAGES(Size)
unsigned short USHORT
Definition: pedump.c:61
VOID NTAPI KeGenericCallDpc(IN PKDEFERRED_ROUTINE Routine, IN PVOID Context)
Definition: dpc.c:983
#define InterlockedIncrementUL(Addend)
Definition: ex.h:1469
SIZE_T NTAPI ExQueryPoolBlockSize(IN PVOID PoolBlock, OUT PBOOLEAN QuotaCharged)
Definition: expool.c:2749
#define POOL_FLAG_CHECK_WORKERS
Definition: miarm.h:258
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
UNICODE_STRING BaseDllName
Definition: ldrtypes.h:143
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
PVOID NTAPI ExAllocatePoolWithTagPriority(IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes, IN ULONG Tag, IN EX_POOL_PRIORITY Priority)
Definition: expool.c:2779
ULONG ExPoolFailures
Definition: expool.c:48
VOID NTAPI ExpInsertPoolTracker(IN ULONG Key, IN SIZE_T NumberOfBytes, IN POOL_TYPE PoolType)
Definition: expool.c:845
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
unsigned int * PULONG
Definition: retypes.h:1
#define min(a, b)
Definition: monoChain.cc:55
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
FORCEINLINE ULONG ExpComputeHashForTag(IN ULONG Tag, IN SIZE_T BucketMask)
Definition: expool.c:431
#define POOL_FLAG_DBGPRINT_ON_FAILURE
Definition: miarm.h:263
VOID FASTCALL KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:53
FORCEINLINE ULONG ExpComputePartialHashForAddress(IN PVOID BaseAddress)
Definition: expool.c:447
#define DPRINT1
Definition: precomp.h:8
_Must_inspect_result_ typedef _In_ ULONG TableEntry
Definition: iotypes.h:3914
#define POOL_LISTS_PER_PAGE
Definition: miarm.h:250
IN ULONG IN ULONG Tag
Definition: evtlib.h:159
PPOOL_TRACKER_BIG_PAGES PoolBigPageTable
Definition: expool.c:41
SIZE_T PoolBigPageTableHash
Definition: expool.c:39
#define POOL_BIG_TABLE_ENTRY_FREE
Definition: expool.c:23
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
void * _ReturnAddress(void)
LONG NonPagedAllocs
Definition: miarm.h:349
#define OUT
Definition: typedefs.h:39
#define ObReferenceObject
Definition: obfuncs.h:204
_Must_inspect_result_ typedef _Out_ PULONG TableSize
Definition: iotypes.h:3938
FORCEINLINE VOID ExUnlockPool(IN PPOOL_DESCRIPTOR Descriptor, IN KIRQL OldIrql)
Definition: expool.c:1289
ULONG ExpPoolFlags
Definition: expool.c:47
struct tagContext Context
Definition: acpixf.h:1014
unsigned int ULONG
Definition: retypes.h:1
VOID NTAPI ExFreePool(PVOID P)
Definition: expool.c:2736
#define UNIMPLEMENTED
Definition: debug.h:114
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
VOID NTAPI MmFreeSpecialPool(IN PVOID P)
#define ULONG_PTR
Definition: config.h:101
uint32_t * PULONG_PTR
Definition: typedefs.h:63
BOOLEAN NTAPI MmUseSpecialPool(IN SIZE_T NumberOfBytes, IN ULONG Tag)
ULONG TagUlong
Definition: extypes.h:1127
#define POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
#define POOL_MAX_ALLOC
Definition: miarm.h:252
#define POOL_RAISE_IF_ALLOCATION_FAILURE
#define POOL_BLOCK_SIZE
Definition: miarm.h:248
ULONG MmSizeOfNonPagedPoolInBytes
Definition: init.c:21
PLIST_ENTRY NTAPI ExpRemovePoolTailList(IN PLIST_ENTRY ListHead)
Definition: expool.c:141
VOID NTAPI ExFreePoolWithTag(IN PVOID P, IN ULONG TagToFree)
Definition: expool.c:2316
signed int * PLONG
Definition: retypes.h:5
BOOLEAN NTAPI MmIsSpecialPoolAddress(IN PVOID P)
#define APC_LEVEL
Definition: env_spec_w32.h:695
IN HDEVINFO IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
Definition: devinst.c:44
ACPI_EFI_GUID ACPI_EFI_OPEN_PROTOCOL_INFORMATION_ENTRY UINTN * EntryCount
Definition: acefiex.h:694
base of all file and directory entries
Definition: entries.h:82
VOID NTAPI KeBugCheckEx(_In_ ULONG BugCheckCode, _In_ ULONG_PTR BugCheckParameter1, _In_ ULONG_PTR BugCheckParameter2, _In_ ULONG_PTR BugCheckParameter3, _In_ ULONG_PTR BugCheckParameter4)
Definition: rtlcompat.c:94
ACPI_EFI_INPUT_KEY * Key
Definition: acefiex.h:303
VOID NTAPI ExQueryPoolUsage(OUT PULONG PagedPoolPages, OUT PULONG NonPagedPoolPages, OUT PULONG PagedPoolAllocs, OUT PULONG PagedPoolFrees, OUT PULONG PagedPoolLookasideHits, OUT PULONG NonPagedPoolAllocs, OUT PULONG NonPagedPoolFrees, OUT PULONG NonPagedPoolLookasideHits)
Definition: expool.c:1616
DISPATCHER_HEADER Header
Definition: ketypes.h:1974
#define P(row, col)
Definition: m_matrix.c:147
_Must_inspect_result_ _In_ LPCGUID _In_ ULONG _In_ FSRTL_ALLOCATE_ECP_FLAGS _In_opt_ PFSRTL_EXTRA_CREATE_PARAMETER_CLEANUP_CALLBACK _Inout_ PVOID LookasideList
Definition: fltkernel.h:2551
BOOLEAN NTAPI KeSignalCallDpcSynchronize(IN PVOID SystemArgument2)
Definition: dpc.c:1025
#define POOL_FLAG_CHECK_RESOURCES
Definition: miarm.h:259
GENERAL_LOOKASIDE_POOL PPPagedLookasideList[NUMBER_POOL_LOOKASIDE_LISTS]
Definition: ketypes.h:626
KSPIN_LOCK ExpTaggedPoolLock
Definition: expool.c:42
_In_ PSTORAGE_PROPERTY_ID _Outptr_ PSTORAGE_DESCRIPTOR_HEADER * Descriptor
Definition: classpnp.h:966
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:675