1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: ntoskrnl/mm/ARM3/special.c 5 * PURPOSE: ARM Memory Manager Special Pool implementation 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* 10 References: 11 http://msdn.microsoft.com/en-us/library/ff551832(v=VS.85).aspx 12 */ 13 14 /* INCLUDES *******************************************************************/ 15 16 #include <ntoskrnl.h> 17 #define NDEBUG 18 #include <debug.h> 19 20 #define MODULE_INVOLVED_IN_ARM3 21 #include <mm/ARM3/miarm.h> 22 23 extern ULONG ExpPoolFlags; 24 extern PMMPTE MmSystemPteBase; 25 26 PMMPTE 27 NTAPI 28 MiReserveAlignedSystemPtes(IN ULONG NumberOfPtes, 29 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType, 30 IN ULONG Alignment); 31 32 /* GLOBALS ********************************************************************/ 33 34 #define SPECIAL_POOL_PAGED_PTE 0x2000 35 #define SPECIAL_POOL_NONPAGED_PTE 0x4000 36 #define SPECIAL_POOL_PAGED 0x8000 37 38 PVOID MmSpecialPoolStart; 39 PVOID MmSpecialPoolEnd; 40 PVOID MiSpecialPoolExtra; 41 ULONG MiSpecialPoolExtraCount; 42 43 PMMPTE MiSpecialPoolFirstPte; 44 PMMPTE MiSpecialPoolLastPte; 45 46 PFN_COUNT MmSpecialPagesInUse; 47 PFN_COUNT MmSpecialPagesInUsePeak; 48 PFN_COUNT MiSpecialPagesPagable; 49 PFN_COUNT MiSpecialPagesPagablePeak; 50 PFN_COUNT MiSpecialPagesNonPaged; 51 PFN_COUNT MiSpecialPagesNonPagedPeak; 52 PFN_COUNT MiSpecialPagesNonPagedMaximum; 53 54 BOOLEAN MmSpecialPoolCatchOverruns = TRUE; 55 56 typedef struct _MI_FREED_SPECIAL_POOL 57 { 58 POOL_HEADER OverlaidPoolHeader; 59 /* TODO: Add overlaid verifier pool header */ 60 ULONG Signature; 61 ULONG TickCount; 62 ULONG NumberOfBytesRequested; 63 BOOLEAN Pagable; 64 PVOID VirtualAddress; 65 PVOID StackPointer; 66 ULONG StackBytes; 67 PETHREAD Thread; 68 UCHAR StackData[0x400]; 69 } MI_FREED_SPECIAL_POOL, *PMI_FREED_SPECIAL_POOL; 70 71 /* PRIVATE FUNCTIONS **********************************************************/ 72 73 VOID NTAPI MiTestSpecialPool(VOID); 74 75 BOOLEAN 76 NTAPI 77 MmUseSpecialPool(SIZE_T NumberOfBytes, ULONG Tag) 78 { 79 /* Special pool is not suitable for allocations bigger than 1 page */ 80 if (NumberOfBytes > (PAGE_SIZE - sizeof(POOL_HEADER))) 81 { 82 return FALSE; 83 } 84 85 if (MmSpecialPoolTag == '*') 86 { 87 return TRUE; 88 } 89 90 return Tag == MmSpecialPoolTag; 91 } 92 93 BOOLEAN 94 NTAPI 95 MmIsSpecialPoolAddress(PVOID P) 96 { 97 return ((P >= MmSpecialPoolStart) && 98 (P <= MmSpecialPoolEnd)); 99 } 100 101 BOOLEAN 102 NTAPI 103 MmIsSpecialPoolAddressFree(PVOID P) 104 { 105 PMMPTE PointerPte; 106 107 ASSERT(MmIsSpecialPoolAddress(P)); 108 PointerPte = MiAddressToPte(P); 109 110 if (PointerPte->u.Soft.PageFileHigh == SPECIAL_POOL_PAGED_PTE || 111 PointerPte->u.Soft.PageFileHigh == SPECIAL_POOL_NONPAGED_PTE) 112 { 113 /* Guard page PTE */ 114 return FALSE; 115 } 116 117 /* Free PTE */ 118 return TRUE; 119 } 120 121 VOID 122 NTAPI 123 MiInitializeSpecialPool(VOID) 124 { 125 ULONG SpecialPoolPtes, i; 126 PMMPTE PointerPte; 127 128 /* Check if there is a special pool tag */ 129 if ((MmSpecialPoolTag == 0) || 130 (MmSpecialPoolTag == -1)) return; 131 132 /* Calculate number of system PTEs for the special pool */ 133 if (MmNumberOfSystemPtes >= 0x3000) 134 SpecialPoolPtes = MmNumberOfSystemPtes / 3; 135 else 136 SpecialPoolPtes = MmNumberOfSystemPtes / 6; 137 138 /* Don't let the number go too high */ 139 if (SpecialPoolPtes > 0x6000) SpecialPoolPtes = 0x6000; 140 141 /* Round up to the page size */ 142 SpecialPoolPtes = PAGE_ROUND_UP(SpecialPoolPtes); 143 144 ASSERT((SpecialPoolPtes & (PTE_PER_PAGE - 1)) == 0); 145 146 /* Reserve those PTEs */ 147 do 148 { 149 PointerPte = MiReserveAlignedSystemPtes(SpecialPoolPtes, 150 SystemPteSpace, 151 /*0x400000*/0); // FIXME: 152 if (PointerPte) break; 153 154 /* Reserving didn't work, so try to reduce the requested size */ 155 ASSERT(SpecialPoolPtes >= PTE_PER_PAGE); 156 SpecialPoolPtes -= PTE_PER_PAGE; 157 } while (SpecialPoolPtes); 158 159 /* Fail if we couldn't reserve them at all */ 160 if (!SpecialPoolPtes) return; 161 162 /* Make sure we got enough */ 163 ASSERT(SpecialPoolPtes >= PTE_PER_PAGE); 164 165 /* Save first PTE and its address */ 166 MiSpecialPoolFirstPte = PointerPte; 167 MmSpecialPoolStart = MiPteToAddress(PointerPte); 168 169 for (i = 0; i < PTE_PER_PAGE / 2; i++) 170 { 171 /* Point it to the next entry */ 172 PointerPte->u.List.NextEntry = &PointerPte[2] - MmSystemPteBase; 173 174 /* Move to the next pair */ 175 PointerPte += 2; 176 } 177 178 /* Save extra values */ 179 MiSpecialPoolExtra = PointerPte; 180 MiSpecialPoolExtraCount = SpecialPoolPtes - PTE_PER_PAGE; 181 182 /* Mark the previous PTE as the last one */ 183 MiSpecialPoolLastPte = PointerPte - 2; 184 MiSpecialPoolLastPte->u.List.NextEntry = MM_EMPTY_PTE_LIST; 185 186 /* Save end address of the special pool */ 187 MmSpecialPoolEnd = MiPteToAddress(MiSpecialPoolLastPte + 1); 188 189 /* Calculate maximum non-paged part of the special pool */ 190 MiSpecialPagesNonPagedMaximum = MmResidentAvailablePages >> 4; 191 192 /* And limit it if it turned out to be too big */ 193 if (MmNumberOfPhysicalPages > 0x3FFF) 194 MiSpecialPagesNonPagedMaximum = MmResidentAvailablePages >> 3; 195 196 DPRINT1("Special pool start %p - end %p\n", MmSpecialPoolStart, MmSpecialPoolEnd); 197 ExpPoolFlags |= POOL_FLAG_SPECIAL_POOL; 198 199 //MiTestSpecialPool(); 200 } 201 202 NTSTATUS 203 NTAPI 204 MmExpandSpecialPool(VOID) 205 { 206 ULONG i; 207 PMMPTE PointerPte; 208 209 MI_ASSERT_PFN_LOCK_HELD(); 210 211 if (MiSpecialPoolExtraCount == 0) 212 return STATUS_INSUFFICIENT_RESOURCES; 213 214 PointerPte = MiSpecialPoolExtra; 215 ASSERT(MiSpecialPoolFirstPte == MiSpecialPoolLastPte); 216 ASSERT(MiSpecialPoolFirstPte->u.List.NextEntry == MM_EMPTY_PTE_LIST); 217 MiSpecialPoolFirstPte->u.List.NextEntry = PointerPte - MmSystemPteBase; 218 219 ASSERT(MiSpecialPoolExtraCount >= PTE_PER_PAGE); 220 for (i = 0; i < PTE_PER_PAGE / 2; i++) 221 { 222 /* Point it to the next entry */ 223 PointerPte->u.List.NextEntry = &PointerPte[2] - MmSystemPteBase; 224 225 /* Move to the next pair */ 226 PointerPte += 2; 227 } 228 229 /* Save remaining extra values */ 230 MiSpecialPoolExtra = PointerPte; 231 MiSpecialPoolExtraCount -= PTE_PER_PAGE; 232 233 /* Mark the previous PTE as the last one */ 234 MiSpecialPoolLastPte = PointerPte - 2; 235 MiSpecialPoolLastPte->u.List.NextEntry = MM_EMPTY_PTE_LIST; 236 237 /* Save new end address of the special pool */ 238 MmSpecialPoolEnd = MiPteToAddress(MiSpecialPoolLastPte + 1); 239 240 return STATUS_SUCCESS; 241 } 242 243 PVOID 244 NTAPI 245 MmAllocateSpecialPool(SIZE_T NumberOfBytes, ULONG Tag, POOL_TYPE PoolType, ULONG SpecialType) 246 { 247 KIRQL Irql; 248 MMPTE TempPte = ValidKernelPte; 249 PMMPTE PointerPte; 250 PFN_NUMBER PageFrameNumber; 251 LARGE_INTEGER TickCount; 252 PVOID Entry; 253 PPOOL_HEADER Header; 254 PFN_COUNT PagesInUse; 255 256 DPRINT("MmAllocateSpecialPool(%x %x %x %x)\n", NumberOfBytes, Tag, PoolType, SpecialType); 257 258 /* Check if the pool is initialized and quit if it's not */ 259 if (!MiSpecialPoolFirstPte) return NULL; 260 261 /* Get the pool type */ 262 PoolType &= BASE_POOL_TYPE_MASK; 263 264 /* Check whether current IRQL matches the pool type */ 265 Irql = KeGetCurrentIrql(); 266 267 if (((PoolType == PagedPool) && (Irql > APC_LEVEL)) || 268 ((PoolType != PagedPool) && (Irql > DISPATCH_LEVEL))) 269 { 270 /* Bad caller */ 271 KeBugCheckEx(SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION, 272 Irql, 273 PoolType, 274 NumberOfBytes, 275 0x30); 276 } 277 278 /* Some allocations from Mm must never use special pool */ 279 if (Tag == 'tSmM') 280 { 281 /* Reject and let normal pool handle it */ 282 return NULL; 283 } 284 285 /* TODO: Take into account various limitations */ 286 287 /* Heed the maximum limit of nonpaged pages */ 288 if ((PoolType == NonPagedPool) && 289 (MiSpecialPagesNonPaged > MiSpecialPagesNonPagedMaximum)) 290 { 291 return NULL; 292 } 293 294 /* Lock PFN database */ 295 Irql = MiAcquirePfnLock(); 296 297 /* Reject allocation in case amount of available pages is too small */ 298 if (MmAvailablePages < 0x100) 299 { 300 /* Release the PFN database lock */ 301 MiReleasePfnLock(Irql); 302 DPRINT1("Special pool: MmAvailablePages 0x%x is too small\n", MmAvailablePages); 303 return NULL; 304 } 305 306 /* Check if special pool PTE list is exhausted */ 307 if (MiSpecialPoolFirstPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) 308 { 309 /* Try to expand it */ 310 if (!NT_SUCCESS(MmExpandSpecialPool())) 311 { 312 /* No reserves left, reject this allocation */ 313 static int once; 314 MiReleasePfnLock(Irql); 315 if (!once++) DPRINT1("Special pool: No PTEs left!\n"); 316 return NULL; 317 } 318 ASSERT(MiSpecialPoolFirstPte->u.List.NextEntry != MM_EMPTY_PTE_LIST); 319 } 320 321 /* Save allocation time */ 322 KeQueryTickCount(&TickCount); 323 324 /* Get a pointer to the first PTE */ 325 PointerPte = MiSpecialPoolFirstPte; 326 327 /* Set the first PTE pointer to the next one in the list */ 328 MiSpecialPoolFirstPte = MmSystemPteBase + PointerPte->u.List.NextEntry; 329 330 /* Allocate a physical page */ 331 if (PoolType == PagedPool) 332 { 333 MI_SET_USAGE(MI_USAGE_PAGED_POOL); 334 } 335 else 336 { 337 MI_SET_USAGE(MI_USAGE_NONPAGED_POOL); 338 } 339 MI_SET_PROCESS2("Kernel-Special"); 340 PageFrameNumber = MiRemoveAnyPage(MI_GET_NEXT_COLOR()); 341 342 /* Initialize PFN and make it valid */ 343 TempPte.u.Hard.PageFrameNumber = PageFrameNumber; 344 MiInitializePfnAndMakePteValid(PageFrameNumber, PointerPte, TempPte); 345 346 /* Release the PFN database lock */ 347 MiReleasePfnLock(Irql); 348 349 /* Increase page counter */ 350 PagesInUse = InterlockedIncrementUL(&MmSpecialPagesInUse); 351 if (PagesInUse > MmSpecialPagesInUsePeak) 352 MmSpecialPagesInUsePeak = PagesInUse; 353 354 /* Put some content into the page. Low value of tick count would do */ 355 Entry = MiPteToAddress(PointerPte); 356 RtlFillMemory(Entry, PAGE_SIZE, TickCount.LowPart); 357 358 /* Calculate header and entry addresses */ 359 if ((SpecialType != 0) && 360 ((SpecialType == 1) || (!MmSpecialPoolCatchOverruns))) 361 { 362 /* We catch underruns. Data is at the beginning of the page */ 363 Header = (PPOOL_HEADER)((PUCHAR)Entry + PAGE_SIZE - sizeof(POOL_HEADER)); 364 } 365 else 366 { 367 /* We catch overruns. Data is at the end of the page */ 368 Header = (PPOOL_HEADER)Entry; 369 Entry = (PVOID)((ULONG_PTR)((PUCHAR)Entry - NumberOfBytes + PAGE_SIZE) & ~((LONG_PTR)sizeof(POOL_HEADER) - 1)); 370 } 371 372 /* Initialize the header */ 373 RtlZeroMemory(Header, sizeof(POOL_HEADER)); 374 375 /* Save allocation size there */ 376 Header->Ulong1 = (ULONG)NumberOfBytes; 377 378 /* Make sure it's all good */ 379 ASSERT((NumberOfBytes <= PAGE_SIZE - sizeof(POOL_HEADER)) && 380 (PAGE_SIZE <= 32 * 1024)); 381 382 /* Mark it as paged or nonpaged */ 383 if (PoolType == PagedPool) 384 { 385 /* Add pagedpool flag into the pool header too */ 386 Header->Ulong1 |= SPECIAL_POOL_PAGED; 387 388 /* Also mark the next PTE as special-pool-paged */ 389 PointerPte[1].u.Soft.PageFileHigh |= SPECIAL_POOL_PAGED_PTE; 390 391 /* Increase pagable counter */ 392 PagesInUse = InterlockedIncrementUL(&MiSpecialPagesPagable); 393 if (PagesInUse > MiSpecialPagesPagablePeak) 394 MiSpecialPagesPagablePeak = PagesInUse; 395 } 396 else 397 { 398 /* Mark the next PTE as special-pool-nonpaged */ 399 PointerPte[1].u.Soft.PageFileHigh |= SPECIAL_POOL_NONPAGED_PTE; 400 401 /* Increase nonpaged counter */ 402 PagesInUse = InterlockedIncrementUL(&MiSpecialPagesNonPaged); 403 if (PagesInUse > MiSpecialPagesNonPagedPeak) 404 MiSpecialPagesNonPagedPeak = PagesInUse; 405 } 406 407 /* Finally save tag and put allocation time into the header's blocksize. 408 That time will be used to check memory consistency within the allocated 409 page. */ 410 Header->PoolTag = Tag; 411 Header->BlockSize = (UCHAR)TickCount.LowPart; 412 DPRINT("%p\n", Entry); 413 return Entry; 414 } 415 416 VOID 417 NTAPI 418 MiSpecialPoolCheckPattern(PUCHAR P, PPOOL_HEADER Header) 419 { 420 ULONG BytesToCheck, BytesRequested, Index; 421 PUCHAR Ptr; 422 423 /* Get amount of bytes user requested to be allocated by clearing out the paged mask */ 424 BytesRequested = (Header->Ulong1 & ~SPECIAL_POOL_PAGED) & 0xFFFF; 425 ASSERT(BytesRequested <= PAGE_SIZE - sizeof(POOL_HEADER)); 426 427 /* Get a pointer to the end of user's area */ 428 Ptr = P + BytesRequested; 429 430 /* Calculate how many bytes to check */ 431 BytesToCheck = (ULONG)((PUCHAR)PAGE_ALIGN(P) + PAGE_SIZE - Ptr); 432 433 /* Remove pool header size if we're catching underruns */ 434 if (((ULONG_PTR)P & (PAGE_SIZE - 1)) == 0) 435 { 436 /* User buffer is located in the beginning of the page */ 437 BytesToCheck -= sizeof(POOL_HEADER); 438 } 439 440 /* Check the pattern after user buffer */ 441 for (Index = 0; Index < BytesToCheck; Index++) 442 { 443 /* Bugcheck if bytes don't match */ 444 if (Ptr[Index] != Header->BlockSize) 445 { 446 KeBugCheckEx(SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION, 447 (ULONG_PTR)P, 448 (ULONG_PTR)&Ptr[Index], 449 Header->BlockSize, 450 0x24); 451 } 452 } 453 } 454 455 VOID 456 NTAPI 457 MmFreeSpecialPool(PVOID P) 458 { 459 PMMPTE PointerPte; 460 PPOOL_HEADER Header; 461 BOOLEAN Overruns = FALSE; 462 KIRQL Irql = KeGetCurrentIrql(); 463 POOL_TYPE PoolType; 464 ULONG BytesRequested, BytesReal = 0; 465 ULONG PtrOffset; 466 PUCHAR b; 467 PMI_FREED_SPECIAL_POOL FreedHeader; 468 LARGE_INTEGER TickCount; 469 PMMPFN Pfn; 470 471 DPRINT("MmFreeSpecialPool(%p)\n", P); 472 473 /* Get the PTE */ 474 PointerPte = MiAddressToPte(P); 475 476 /* Check if it's valid */ 477 if (PointerPte->u.Hard.Valid == 0) 478 { 479 /* Bugcheck if it has NOACCESS or 0 set as protection */ 480 if (PointerPte->u.Soft.Protection == MM_NOACCESS || 481 !PointerPte->u.Soft.Protection) 482 { 483 KeBugCheckEx(SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION, 484 (ULONG_PTR)P, 485 (ULONG_PTR)PointerPte, 486 0, 487 0x20); 488 } 489 } 490 491 /* Determine if it's a underruns or overruns pool pointer */ 492 PtrOffset = (ULONG)((ULONG_PTR)P & (PAGE_SIZE - 1)); 493 if (PtrOffset) 494 { 495 /* Pool catches overruns */ 496 Header = PAGE_ALIGN(P); 497 Overruns = TRUE; 498 } 499 else 500 { 501 /* Pool catches underruns */ 502 Header = (PPOOL_HEADER)((PUCHAR)PAGE_ALIGN(P) + PAGE_SIZE - sizeof(POOL_HEADER)); 503 } 504 505 /* Check if it's non paged pool */ 506 if ((Header->Ulong1 & SPECIAL_POOL_PAGED) == 0) 507 { 508 /* Non-paged allocation, ensure that IRQ is not higher that DISPATCH */ 509 PoolType = NonPagedPool; 510 ASSERT(PointerPte[1].u.Soft.PageFileHigh == SPECIAL_POOL_NONPAGED_PTE); 511 if (Irql > DISPATCH_LEVEL) 512 { 513 KeBugCheckEx(SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION, 514 Irql, 515 PoolType, 516 (ULONG_PTR)P, 517 0x31); 518 } 519 } 520 else 521 { 522 /* Paged allocation, ensure */ 523 PoolType = PagedPool; 524 ASSERT(PointerPte[1].u.Soft.PageFileHigh == SPECIAL_POOL_PAGED_PTE); 525 if (Irql > APC_LEVEL) 526 { 527 KeBugCheckEx(SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION, 528 Irql, 529 PoolType, 530 (ULONG_PTR)P, 531 0x31); 532 } 533 } 534 535 /* Get amount of bytes user requested to be allocated by clearing out the paged mask */ 536 BytesRequested = (Header->Ulong1 & ~SPECIAL_POOL_PAGED) & 0xFFFF; 537 ASSERT(BytesRequested <= PAGE_SIZE - sizeof(POOL_HEADER)); 538 539 /* Check memory before the allocated user buffer in case of overruns detection */ 540 if (Overruns) 541 { 542 /* Calculate the real placement of the buffer */ 543 BytesReal = PAGE_SIZE - PtrOffset; 544 545 /* If they mismatch, it's unrecoverable */ 546 if (BytesRequested > BytesReal) 547 { 548 KeBugCheckEx(SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION, 549 (ULONG_PTR)P, 550 BytesRequested, 551 BytesReal, 552 0x21); 553 } 554 555 if (BytesRequested + sizeof(POOL_HEADER) < BytesReal) 556 { 557 KeBugCheckEx(SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION, 558 (ULONG_PTR)P, 559 BytesRequested, 560 BytesReal, 561 0x22); 562 } 563 564 /* Actually check the memory pattern */ 565 for (b = (PUCHAR)(Header + 1); b < (PUCHAR)P; b++) 566 { 567 if (*b != Header->BlockSize) 568 { 569 /* Bytes mismatch */ 570 KeBugCheckEx(SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION, 571 (ULONG_PTR)P, 572 (ULONG_PTR)b, 573 Header->BlockSize, 574 0x23); 575 } 576 } 577 } 578 579 /* Check the memory pattern after the user buffer */ 580 MiSpecialPoolCheckPattern(P, Header); 581 582 /* Fill the freed header */ 583 KeQueryTickCount(&TickCount); 584 FreedHeader = (PMI_FREED_SPECIAL_POOL)PAGE_ALIGN(P); 585 FreedHeader->Signature = 0x98764321; 586 FreedHeader->TickCount = TickCount.LowPart; 587 FreedHeader->NumberOfBytesRequested = BytesRequested; 588 FreedHeader->Pagable = PoolType; 589 FreedHeader->VirtualAddress = P; 590 FreedHeader->Thread = PsGetCurrentThread(); 591 /* TODO: Fill StackPointer and StackBytes */ 592 FreedHeader->StackPointer = NULL; 593 FreedHeader->StackBytes = 0; 594 595 if (PoolType == NonPagedPool) 596 { 597 /* Non pagable. Get PFN element corresponding to the PTE */ 598 Pfn = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber); 599 600 /* Count the page as free */ 601 InterlockedDecrementUL(&MiSpecialPagesNonPaged); 602 603 /* Lock PFN database */ 604 Irql = MiAcquirePfnLock(); 605 606 /* Delete this PFN */ 607 MI_SET_PFN_DELETED(Pfn); 608 609 /* Decrement share count of this PFN */ 610 MiDecrementShareCount(Pfn, PointerPte->u.Hard.PageFrameNumber); 611 612 MI_ERASE_PTE(PointerPte); 613 614 /* Flush the TLB */ 615 //FIXME: Use KeFlushSingleTb() instead 616 KeFlushEntireTb(TRUE, TRUE); 617 } 618 else 619 { 620 /* Pagable. Delete that virtual address */ 621 MiDeleteSystemPageableVm(PointerPte, 1, 0, NULL); 622 623 /* Count the page as free */ 624 InterlockedDecrementUL(&MiSpecialPagesPagable); 625 626 /* Lock PFN database */ 627 Irql = MiAcquirePfnLock(); 628 } 629 630 /* Mark next PTE as invalid */ 631 MI_ERASE_PTE(PointerPte + 1); 632 633 /* Make sure that the last entry is really the last one */ 634 ASSERT(MiSpecialPoolLastPte->u.List.NextEntry == MM_EMPTY_PTE_LIST); 635 636 /* Update the current last PTE next pointer */ 637 MiSpecialPoolLastPte->u.List.NextEntry = PointerPte - MmSystemPteBase; 638 639 /* PointerPte becomes the new last PTE */ 640 PointerPte->u.List.NextEntry = MM_EMPTY_PTE_LIST; 641 MiSpecialPoolLastPte = PointerPte; 642 643 /* Release the PFN database lock */ 644 MiReleasePfnLock(Irql); 645 646 /* Update page counter */ 647 InterlockedDecrementUL(&MmSpecialPagesInUse); 648 } 649 650 VOID 651 NTAPI 652 MiTestSpecialPool(VOID) 653 { 654 ULONG i; 655 PVOID p1, p2[100]; 656 //PUCHAR p3; 657 ULONG ByteSize; 658 POOL_TYPE PoolType = PagedPool; 659 660 // First allocate/free 661 for (i=0; i<100; i++) 662 { 663 ByteSize = (100 * (i+1)) % (PAGE_SIZE - sizeof(POOL_HEADER)); 664 p1 = MmAllocateSpecialPool(ByteSize, 'TEST', PoolType, 0); 665 DPRINT1("p1 %p size %lu\n", p1, ByteSize); 666 MmFreeSpecialPool(p1); 667 } 668 669 // Now allocate all at once, then free at once 670 for (i=0; i<100; i++) 671 { 672 ByteSize = (100 * (i+1)) % (PAGE_SIZE - sizeof(POOL_HEADER)); 673 p2[i] = MmAllocateSpecialPool(ByteSize, 'TEST', PoolType, 0); 674 DPRINT1("p2[%lu] %p size %lu\n", i, p1, ByteSize); 675 } 676 for (i=0; i<100; i++) 677 { 678 DPRINT1("Freeing %p\n", p2[i]); 679 MmFreeSpecialPool(p2[i]); 680 } 681 682 // Overrun the buffer to test 683 //ByteSize = 16; 684 //p3 = MmAllocateSpecialPool(ByteSize, 'TEST', NonPagedPool, 0); 685 //p3[ByteSize] = 0xF1; // This should cause an exception 686 687 // Underrun the buffer to test 688 //p3 = MmAllocateSpecialPool(ByteSize, 'TEST', NonPagedPool, 1); 689 //p3--; 690 //*p3 = 0xF1; // This should cause an exception 691 692 } 693 694 /* EOF */ 695