1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: ntoskrnl/mm/ARM3/pfnlist.c 5 * PURPOSE: ARM Memory Manager PFN List Manipulation 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 #if DBG 19 #define ASSERT_LIST_INVARIANT(x) \ 20 do { \ 21 ASSERT(((x)->Total == 0 && \ 22 (x)->Flink == LIST_HEAD && \ 23 (x)->Blink == LIST_HEAD) || \ 24 ((x)->Total != 0 && \ 25 (x)->Flink != LIST_HEAD && \ 26 (x)->Blink != LIST_HEAD)); \ 27 } while (0) 28 #else 29 #define ASSERT_LIST_INVARIANT(x) 30 #endif 31 32 /* GLOBALS ********************************************************************/ 33 34 BOOLEAN MmDynamicPfn; 35 BOOLEAN MmMirroring; 36 ULONG MmSystemPageColor; 37 38 ULONG MmTransitionSharedPages; 39 ULONG MmTotalPagesForPagingFile; 40 41 MMPFNLIST MmZeroedPageListHead = {0, ZeroedPageList, LIST_HEAD, LIST_HEAD}; 42 MMPFNLIST MmFreePageListHead = {0, FreePageList, LIST_HEAD, LIST_HEAD}; 43 MMPFNLIST MmStandbyPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD}; 44 MMPFNLIST MmStandbyPageListByPriority[8]; 45 MMPFNLIST MmModifiedPageListHead = {0, ModifiedPageList, LIST_HEAD, LIST_HEAD}; 46 MMPFNLIST MmModifiedPageListByColor[1] = {{0, ModifiedPageList, LIST_HEAD, LIST_HEAD}}; 47 MMPFNLIST MmModifiedNoWritePageListHead = {0, ModifiedNoWritePageList, LIST_HEAD, LIST_HEAD}; 48 MMPFNLIST MmBadPageListHead = {0, BadPageList, LIST_HEAD, LIST_HEAD}; 49 MMPFNLIST MmRomPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD}; 50 51 PMMPFNLIST MmPageLocationList[] = 52 { 53 &MmZeroedPageListHead, 54 &MmFreePageListHead, 55 &MmStandbyPageListHead, 56 &MmModifiedPageListHead, 57 &MmModifiedNoWritePageListHead, 58 &MmBadPageListHead, 59 NULL, 60 NULL 61 }; 62 63 ULONG MI_PFN_CURRENT_USAGE; 64 CHAR MI_PFN_CURRENT_PROCESS_NAME[16] = "None yet"; 65 66 /* FUNCTIONS ******************************************************************/ 67 static 68 VOID 69 MiIncrementAvailablePages( 70 VOID) 71 { 72 /* Increment available pages */ 73 MmAvailablePages++; 74 75 /* Check if we've reached the configured low memory threshold */ 76 if (MmAvailablePages == MmLowMemoryThreshold) 77 { 78 /* Clear the event, because now we're ABOVE the threshold */ 79 KeClearEvent(MiLowMemoryEvent); 80 } 81 else if (MmAvailablePages == MmHighMemoryThreshold) 82 { 83 /* Otherwise check if we reached the high threshold and signal the event */ 84 KeSetEvent(MiHighMemoryEvent, 0, FALSE); 85 } 86 } 87 88 static 89 VOID 90 MiDecrementAvailablePages( 91 VOID) 92 { 93 ASSERT(MmAvailablePages > 0); 94 95 /* See if we hit any thresholds */ 96 if (MmAvailablePages == MmHighMemoryThreshold) 97 { 98 /* Clear the high memory event */ 99 KeClearEvent(MiHighMemoryEvent); 100 } 101 else if (MmAvailablePages == MmLowMemoryThreshold) 102 { 103 /* Signal the low memory event */ 104 KeSetEvent(MiLowMemoryEvent, 0, FALSE); 105 } 106 107 /* One less page */ 108 MmAvailablePages--; 109 if (MmAvailablePages < MmMinimumFreePages) 110 { 111 /* FIXME: Should wake up the MPW and working set manager, if we had one */ 112 113 DPRINT1("Running low on pages: %lu remaining\n", MmAvailablePages); 114 115 /* Call RosMm and see if it can release any pages for us */ 116 MmRebalanceMemoryConsumers(); 117 } 118 } 119 120 VOID 121 NTAPI 122 MiZeroPhysicalPage(IN PFN_NUMBER PageFrameIndex) 123 { 124 KIRQL OldIrql; 125 PVOID VirtualAddress; 126 PEPROCESS Process = PsGetCurrentProcess(); 127 128 /* Map in hyperspace, then wipe it using XMMI or MEMSET */ 129 VirtualAddress = MiMapPageInHyperSpace(Process, PageFrameIndex, &OldIrql); 130 ASSERT(VirtualAddress); 131 KeZeroPages(VirtualAddress, PAGE_SIZE); 132 MiUnmapPageInHyperSpace(Process, VirtualAddress, OldIrql); 133 } 134 135 VOID 136 NTAPI 137 MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry) 138 { 139 PFN_NUMBER OldFlink, OldBlink; 140 PMMPFNLIST ListHead; 141 MMLISTS ListName; 142 ULONG Color; 143 PMMCOLOR_TABLES ColorTable; 144 PMMPFN Pfn1; 145 146 /* Make sure the PFN lock is held */ 147 MI_ASSERT_PFN_LOCK_HELD(); 148 149 /* Make sure the PFN entry isn't in-use */ 150 ASSERT(Entry->u3.e1.WriteInProgress == 0); 151 ASSERT(Entry->u3.e1.ReadInProgress == 0); 152 153 /* Find the list for this entry, make sure it's the free or zero list */ 154 ListHead = MmPageLocationList[Entry->u3.e1.PageLocation]; 155 ListName = ListHead->ListName; 156 ASSERT(ListHead != NULL); 157 ASSERT(ListName <= FreePageList); 158 ASSERT_LIST_INVARIANT(ListHead); 159 160 /* Remove one count */ 161 ASSERT(ListHead->Total != 0); 162 ListHead->Total--; 163 164 /* Get the forward and back pointers */ 165 OldFlink = Entry->u1.Flink; 166 OldBlink = Entry->u2.Blink; 167 168 /* Check if the next entry is the list head */ 169 if (OldFlink != LIST_HEAD) 170 { 171 /* It is not, so set the backlink of the actual entry, to our backlink */ 172 MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink; 173 } 174 else 175 { 176 /* Set the list head's backlink instead */ 177 ListHead->Blink = OldBlink; 178 } 179 180 /* Check if the back entry is the list head */ 181 if (OldBlink != LIST_HEAD) 182 { 183 /* It is not, so set the backlink of the actual entry, to our backlink */ 184 MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink; 185 } 186 else 187 { 188 /* Set the list head's backlink instead */ 189 ListHead->Flink = OldFlink; 190 } 191 192 /* Get the page color */ 193 OldBlink = MiGetPfnEntryIndex(Entry); 194 Color = OldBlink & MmSecondaryColorMask; 195 196 /* Get the first page on the color list */ 197 ColorTable = &MmFreePagesByColor[ListName][Color]; 198 199 /* Check if this was was actually the head */ 200 OldFlink = ColorTable->Flink; 201 if (OldFlink == OldBlink) 202 { 203 /* Make the table point to the next page this page was linking to */ 204 ColorTable->Flink = Entry->OriginalPte.u.Long; 205 if (ColorTable->Flink != LIST_HEAD) 206 { 207 /* And make the previous link point to the head now */ 208 MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD; 209 } 210 else 211 { 212 /* And if that page was the head, loop the list back around */ 213 ColorTable->Blink = (PVOID)LIST_HEAD; 214 } 215 } 216 else 217 { 218 /* This page shouldn't be pointing back to the head */ 219 ASSERT(Entry->u4.PteFrame != COLORED_LIST_HEAD); 220 221 /* Make the back link point to whoever the next page is */ 222 Pfn1 = MI_PFN_ELEMENT(Entry->u4.PteFrame); 223 Pfn1->OriginalPte.u.Long = Entry->OriginalPte.u.Long; 224 225 /* Check if this page was pointing to the head */ 226 if (Entry->OriginalPte.u.Long != LIST_HEAD) 227 { 228 /* Make the back link point to the head */ 229 Pfn1 = MI_PFN_ELEMENT(Entry->OriginalPte.u.Long); 230 Pfn1->u4.PteFrame = Entry->u4.PteFrame; 231 } 232 else 233 { 234 /* Then the table is directly back pointing to this page now */ 235 ColorTable->Blink = Pfn1; 236 } 237 } 238 239 /* One less colored page */ 240 ASSERT(ColorTable->Count >= 1); 241 ColorTable->Count--; 242 243 /* ReactOS Hack */ 244 Entry->OriginalPte.u.Long = 0; 245 246 /* We are not on a list anymore */ 247 Entry->u1.Flink = Entry->u2.Blink = 0; 248 ASSERT_LIST_INVARIANT(ListHead); 249 250 /* Decrement number of available pages */ 251 MiDecrementAvailablePages(); 252 253 #if MI_TRACE_PFNS 254 ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET); 255 Entry->PfnUsage = MI_PFN_CURRENT_USAGE; 256 memcpy(Entry->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16); 257 Entry->CallSite = _ReturnAddress(); 258 MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET; 259 MI_SET_PROCESS2("Not Set"); 260 #endif 261 } 262 263 VOID 264 NTAPI 265 MiUnlinkPageFromList(IN PMMPFN Pfn) 266 { 267 PMMPFNLIST ListHead; 268 PFN_NUMBER OldFlink, OldBlink; 269 270 /* Make sure the PFN lock is held */ 271 MI_ASSERT_PFN_LOCK_HELD(); 272 273 /* ARM3 should only call this for dead pages */ 274 ASSERT(Pfn->u3.e2.ReferenceCount == 0); 275 276 /* Transition pages are supposed to be standby/modified/nowrite */ 277 ListHead = MmPageLocationList[Pfn->u3.e1.PageLocation]; 278 ASSERT(ListHead->ListName >= StandbyPageList); 279 280 /* Check if this was standby, or modified */ 281 if (ListHead == &MmStandbyPageListHead) 282 { 283 /* Should not be a ROM page */ 284 ASSERT(Pfn->u3.e1.Rom == 0); 285 286 /* Get the exact list */ 287 ListHead = &MmStandbyPageListByPriority[Pfn->u4.Priority]; 288 289 /* Decrement number of available pages */ 290 MiDecrementAvailablePages(); 291 292 /* Decrease transition page counter */ 293 ASSERT(Pfn->u3.e1.PrototypePte == 1); /* Only supported ARM3 case */ 294 MmTransitionSharedPages--; 295 } 296 else if (ListHead == &MmModifiedPageListHead) 297 { 298 /* Only shared memory (page-file backed) modified pages are supported */ 299 ASSERT(Pfn->OriginalPte.u.Soft.Prototype == 0); 300 301 /* Decrement the counters */ 302 ListHead->Total--; 303 MmTotalPagesForPagingFile--; 304 305 /* Pick the correct colored list */ 306 ListHead = &MmModifiedPageListByColor[0]; 307 308 /* Decrease transition page counter */ 309 MmTransitionSharedPages--; 310 } 311 else if (ListHead == &MmModifiedNoWritePageListHead) 312 { 313 /* List not yet supported */ 314 ASSERT(FALSE); 315 } 316 317 /* Nothing should be in progress and the list should not be empty */ 318 ASSERT(Pfn->u3.e1.WriteInProgress == 0); 319 ASSERT(Pfn->u3.e1.ReadInProgress == 0); 320 ASSERT(ListHead->Total != 0); 321 322 /* Get the forward and back pointers */ 323 OldFlink = Pfn->u1.Flink; 324 OldBlink = Pfn->u2.Blink; 325 326 /* Check if the next entry is the list head */ 327 if (OldFlink != LIST_HEAD) 328 { 329 /* It is not, so set the backlink of the actual entry, to our backlink */ 330 MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink; 331 } 332 else 333 { 334 /* Set the list head's backlink instead */ 335 ListHead->Blink = OldBlink; 336 } 337 338 /* Check if the back entry is the list head */ 339 if (OldBlink != LIST_HEAD) 340 { 341 /* It is not, so set the backlink of the actual entry, to our backlink */ 342 MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink; 343 } 344 else 345 { 346 /* Set the list head's backlink instead */ 347 ListHead->Flink = OldFlink; 348 } 349 350 /* ReactOS Hack */ 351 Pfn->OriginalPte.u.Long = 0; 352 353 /* We are not on a list anymore */ 354 Pfn->u1.Flink = Pfn->u2.Blink = 0; 355 356 /* Remove one entry from the list */ 357 ListHead->Total--; 358 359 ASSERT_LIST_INVARIANT(ListHead); 360 } 361 362 PFN_NUMBER 363 NTAPI 364 MiRemovePageByColor(IN PFN_NUMBER PageIndex, 365 IN ULONG Color) 366 { 367 PMMPFN Pfn1; 368 PMMPFNLIST ListHead; 369 MMLISTS ListName; 370 PFN_NUMBER OldFlink, OldBlink; 371 USHORT OldColor, OldCache; 372 PMMCOLOR_TABLES ColorTable; 373 374 /* Make sure PFN lock is held */ 375 MI_ASSERT_PFN_LOCK_HELD(); 376 ASSERT(Color < MmSecondaryColors); 377 378 /* Get the PFN entry */ 379 Pfn1 = MI_PFN_ELEMENT(PageIndex); 380 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 381 ASSERT(Pfn1->u3.e1.Rom == 0); 382 383 /* Capture data for later */ 384 OldColor = Pfn1->u3.e1.PageColor; 385 OldCache = Pfn1->u3.e1.CacheAttribute; 386 387 /* Could be either on free or zero list */ 388 ListHead = MmPageLocationList[Pfn1->u3.e1.PageLocation]; 389 ASSERT_LIST_INVARIANT(ListHead); 390 ListName = ListHead->ListName; 391 ASSERT(ListName <= FreePageList); 392 393 /* Remove a page */ 394 ListHead->Total--; 395 396 /* Get the forward and back pointers */ 397 OldFlink = Pfn1->u1.Flink; 398 OldBlink = Pfn1->u2.Blink; 399 400 /* Check if the next entry is the list head */ 401 if (OldFlink != LIST_HEAD) 402 { 403 /* It is not, so set the backlink of the actual entry, to our backlink */ 404 MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink; 405 } 406 else 407 { 408 /* Set the list head's backlink instead */ 409 ListHead->Blink = OldBlink; 410 } 411 412 /* Check if the back entry is the list head */ 413 if (OldBlink != LIST_HEAD) 414 { 415 /* It is not, so set the backlink of the actual entry, to our backlink */ 416 MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink; 417 } 418 else 419 { 420 /* Set the list head's backlink instead */ 421 ListHead->Flink = OldFlink; 422 } 423 424 /* We are not on a list anymore */ 425 ASSERT_LIST_INVARIANT(ListHead); 426 Pfn1->u1.Flink = Pfn1->u2.Blink = 0; 427 428 /* Zero flags but restore color and cache */ 429 Pfn1->u3.e2.ShortFlags = 0; 430 Pfn1->u3.e1.PageColor = OldColor; 431 Pfn1->u3.e1.CacheAttribute = OldCache; 432 433 /* Get the first page on the color list */ 434 ASSERT(Color < MmSecondaryColors); 435 ColorTable = &MmFreePagesByColor[ListName][Color]; 436 ASSERT(ColorTable->Count >= 1); 437 438 /* Set the forward link to whoever we were pointing to */ 439 ColorTable->Flink = Pfn1->OriginalPte.u.Long; 440 441 /* Get the first page on the color list */ 442 if (ColorTable->Flink == LIST_HEAD) 443 { 444 /* This is the beginning of the list, so set the sentinel value */ 445 ColorTable->Blink = (PVOID)LIST_HEAD; 446 } 447 else 448 { 449 /* The list is empty, so we are the first page */ 450 MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD; 451 } 452 453 /* One less page */ 454 ColorTable->Count--; 455 456 /* ReactOS Hack */ 457 Pfn1->OriginalPte.u.Long = 0; 458 459 /* Decrement number of available pages */ 460 MiDecrementAvailablePages(); 461 462 #if MI_TRACE_PFNS 463 ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET); 464 Pfn1->PfnUsage = MI_PFN_CURRENT_USAGE; 465 memcpy(Pfn1->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16); 466 Pfn1->CallSite = _ReturnAddress(); 467 MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET; 468 MI_SET_PROCESS2("Not Set"); 469 #endif 470 471 /* Return the page */ 472 return PageIndex; 473 } 474 475 PFN_NUMBER 476 NTAPI 477 MiRemoveAnyPage(IN ULONG Color) 478 { 479 PFN_NUMBER PageIndex; 480 PMMPFN Pfn1; 481 482 /* Make sure PFN lock is held and we have pages */ 483 MI_ASSERT_PFN_LOCK_HELD(); 484 ASSERT(MmAvailablePages != 0); 485 ASSERT(Color < MmSecondaryColors); 486 487 /* Check the colored free list */ 488 PageIndex = MmFreePagesByColor[FreePageList][Color].Flink; 489 if (PageIndex == LIST_HEAD) 490 { 491 /* Check the colored zero list */ 492 PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink; 493 if (PageIndex == LIST_HEAD) 494 { 495 /* Check the free list */ 496 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 497 PageIndex = MmFreePageListHead.Flink; 498 Color = PageIndex & MmSecondaryColorMask; 499 if (PageIndex == LIST_HEAD) 500 { 501 /* Check the zero list */ 502 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 503 PageIndex = MmZeroedPageListHead.Flink; 504 Color = PageIndex & MmSecondaryColorMask; 505 ASSERT(PageIndex != LIST_HEAD); 506 if (PageIndex == LIST_HEAD) 507 { 508 /* FIXME: Should check the standby list */ 509 ASSERT(MmZeroedPageListHead.Total == 0); 510 } 511 } 512 } 513 } 514 515 /* Remove the page from its list */ 516 PageIndex = MiRemovePageByColor(PageIndex, Color); 517 518 /* Sanity checks */ 519 Pfn1 = MI_PFN_ELEMENT(PageIndex); 520 ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) || 521 (Pfn1->u3.e1.PageLocation == ZeroedPageList)); 522 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 523 ASSERT(Pfn1->u2.ShareCount == 0); 524 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 525 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 526 527 /* Return the page */ 528 return PageIndex; 529 } 530 531 PFN_NUMBER 532 NTAPI 533 MiRemoveZeroPage(IN ULONG Color) 534 { 535 PFN_NUMBER PageIndex; 536 PMMPFN Pfn1; 537 BOOLEAN Zero = FALSE; 538 539 /* Make sure PFN lock is held and we have pages */ 540 MI_ASSERT_PFN_LOCK_HELD(); 541 ASSERT(MmAvailablePages != 0); 542 ASSERT(Color < MmSecondaryColors); 543 544 /* Check the colored zero list */ 545 PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink; 546 if (PageIndex == LIST_HEAD) 547 { 548 /* Check the zero list */ 549 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 550 PageIndex = MmZeroedPageListHead.Flink; 551 if (PageIndex == LIST_HEAD) 552 { 553 /* This means there's no zero pages, we have to look for free ones */ 554 ASSERT(MmZeroedPageListHead.Total == 0); 555 Zero = TRUE; 556 557 /* Check the colored free list */ 558 PageIndex = MmFreePagesByColor[FreePageList][Color].Flink; 559 if (PageIndex == LIST_HEAD) 560 { 561 /* Check the free list */ 562 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 563 PageIndex = MmFreePageListHead.Flink; 564 Color = PageIndex & MmSecondaryColorMask; 565 ASSERT(PageIndex != LIST_HEAD); 566 if (PageIndex == LIST_HEAD) 567 { 568 /* FIXME: Should check the standby list */ 569 ASSERT(MmZeroedPageListHead.Total == 0); 570 } 571 } 572 } 573 else 574 { 575 Color = PageIndex & MmSecondaryColorMask; 576 } 577 } 578 579 /* Sanity checks */ 580 Pfn1 = MI_PFN_ELEMENT(PageIndex); 581 ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) || 582 (Pfn1->u3.e1.PageLocation == ZeroedPageList)); 583 584 /* Remove the page from its list */ 585 PageIndex = MiRemovePageByColor(PageIndex, Color); 586 ASSERT(Pfn1 == MI_PFN_ELEMENT(PageIndex)); 587 588 /* Zero it, if needed */ 589 if (Zero) MiZeroPhysicalPage(PageIndex); 590 591 /* Sanity checks */ 592 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 593 ASSERT(Pfn1->u2.ShareCount == 0); 594 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 595 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 596 597 /* Return the page */ 598 return PageIndex; 599 } 600 601 VOID 602 NTAPI 603 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex) 604 { 605 PMMPFNLIST ListHead; 606 PFN_NUMBER LastPage; 607 PMMPFN Pfn1; 608 ULONG Color; 609 PMMPFN Blink; 610 PMMCOLOR_TABLES ColorTable; 611 612 /* Make sure the page index is valid */ 613 MI_ASSERT_PFN_LOCK_HELD(); 614 ASSERT((PageFrameIndex != 0) && 615 (PageFrameIndex <= MmHighestPhysicalPage) && 616 (PageFrameIndex >= MmLowestPhysicalPage)); 617 618 /* Get the PFN entry */ 619 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 620 621 /* Sanity checks that a right kind of page is being inserted here */ 622 ASSERT(Pfn1->u4.MustBeCached == 0); 623 ASSERT(Pfn1->u3.e1.Rom != 1); 624 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 625 ASSERT(Pfn1->u4.VerifierAllocation == 0); 626 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 627 628 /* Get the free page list and increment its count */ 629 ListHead = &MmFreePageListHead; 630 ASSERT_LIST_INVARIANT(ListHead); 631 ListHead->Total++; 632 633 /* Get the last page on the list */ 634 LastPage = ListHead->Blink; 635 if (LastPage != LIST_HEAD) 636 { 637 /* Link us with the previous page, so we're at the end now */ 638 MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex; 639 } 640 else 641 { 642 /* The list is empty, so we are the first page */ 643 ListHead->Flink = PageFrameIndex; 644 } 645 646 /* Now make the list head point back to us (since we go at the end) */ 647 ListHead->Blink = PageFrameIndex; 648 ASSERT_LIST_INVARIANT(ListHead); 649 650 /* And initialize our own list pointers */ 651 Pfn1->u1.Flink = LIST_HEAD; 652 Pfn1->u2.Blink = LastPage; 653 654 /* Set the list name and default priority */ 655 Pfn1->u3.e1.PageLocation = FreePageList; 656 Pfn1->u4.Priority = 3; 657 658 /* Clear some status fields */ 659 Pfn1->u4.InPageError = 0; 660 Pfn1->u4.AweAllocation = 0; 661 662 /* Increment number of available pages */ 663 MiIncrementAvailablePages(); 664 665 /* Get the page color */ 666 Color = PageFrameIndex & MmSecondaryColorMask; 667 668 /* Get the first page on the color list */ 669 ColorTable = &MmFreePagesByColor[FreePageList][Color]; 670 if (ColorTable->Flink == LIST_HEAD) 671 { 672 /* The list is empty, so we are the first page */ 673 Pfn1->u4.PteFrame = COLORED_LIST_HEAD; 674 ColorTable->Flink = PageFrameIndex; 675 } 676 else 677 { 678 /* Get the previous page */ 679 Blink = (PMMPFN)ColorTable->Blink; 680 681 /* Make it link to us, and link back to it */ 682 Blink->OriginalPte.u.Long = PageFrameIndex; 683 Pfn1->u4.PteFrame = MiGetPfnEntryIndex(Blink); 684 } 685 686 /* Now initialize our own list pointers */ 687 ColorTable->Blink = Pfn1; 688 689 /* This page is now the last */ 690 Pfn1->OriginalPte.u.Long = LIST_HEAD; 691 692 /* And increase the count in the colored list */ 693 ColorTable->Count++; 694 695 /* Notify zero page thread if enough pages are on the free list now */ 696 if (ListHead->Total >= 8) 697 { 698 /* Set the event */ 699 KeSetEvent(&MmZeroingPageEvent, IO_NO_INCREMENT, FALSE); 700 } 701 702 #if MI_TRACE_PFNS 703 Pfn1->PfnUsage = MI_USAGE_FREE_PAGE; 704 RtlZeroMemory(Pfn1->ProcessName, 16); 705 Pfn1->CallSite = NULL; 706 #endif 707 } 708 709 VOID 710 FASTCALL 711 MiInsertStandbyListAtFront(IN PFN_NUMBER PageFrameIndex) 712 { 713 PMMPFNLIST ListHead; 714 PFN_NUMBER Flink; 715 PMMPFN Pfn1, Pfn2; 716 717 /* Make sure the lock is held */ 718 DPRINT("Inserting page: %lx into standby list !\n", PageFrameIndex); 719 MI_ASSERT_PFN_LOCK_HELD(); 720 721 /* Make sure the PFN is valid */ 722 ASSERT((PageFrameIndex != 0) && 723 (PageFrameIndex <= MmHighestPhysicalPage) && 724 (PageFrameIndex >= MmLowestPhysicalPage)); 725 726 /* Grab the PFN and validate it is the right kind of PFN being inserted */ 727 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 728 ASSERT(Pfn1->u4.MustBeCached == 0); 729 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 730 ASSERT(Pfn1->u3.e1.PrototypePte == 1); 731 ASSERT(Pfn1->u3.e1.Rom != 1); 732 733 /* One more transition page on a list */ 734 MmTransitionSharedPages++; 735 736 /* Get the standby page list and increment its count */ 737 ListHead = &MmStandbyPageListByPriority [Pfn1->u4.Priority]; 738 ASSERT_LIST_INVARIANT(ListHead); 739 ListHead->Total++; 740 741 /* Make the head of the list point to this page now */ 742 Flink = ListHead->Flink; 743 ListHead->Flink = PageFrameIndex; 744 745 /* Make the page point to the previous head, and back to the list */ 746 Pfn1->u1.Flink = Flink; 747 Pfn1->u2.Blink = LIST_HEAD; 748 749 /* Was the list empty? */ 750 if (Flink != LIST_HEAD) 751 { 752 /* It wasn't, so update the backlink of the previous head page */ 753 Pfn2 = MI_PFN_ELEMENT(Flink); 754 Pfn2->u2.Blink = PageFrameIndex; 755 } 756 else 757 { 758 /* It was empty, so have it loop back around to this new page */ 759 ListHead->Blink = PageFrameIndex; 760 } 761 762 /* Move the page onto its new location */ 763 Pfn1->u3.e1.PageLocation = StandbyPageList; 764 765 /* Increment number of available pages */ 766 MiIncrementAvailablePages(); 767 } 768 769 VOID 770 NTAPI 771 MiInsertPageInList(IN PMMPFNLIST ListHead, 772 IN PFN_NUMBER PageFrameIndex) 773 { 774 PFN_NUMBER Flink, LastPage; 775 PMMPFN Pfn1, Pfn2; 776 MMLISTS ListName; 777 PMMCOLOR_TABLES ColorHead; 778 ULONG Color; 779 780 /* For free pages, use MiInsertPageInFreeList */ 781 ASSERT(ListHead != &MmFreePageListHead); 782 783 /* Make sure the lock is held */ 784 MI_ASSERT_PFN_LOCK_HELD(); 785 786 /* Make sure the PFN is valid */ 787 ASSERT((PageFrameIndex) && 788 (PageFrameIndex <= MmHighestPhysicalPage) && 789 (PageFrameIndex >= MmLowestPhysicalPage)); 790 791 /* Page should be unused */ 792 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 793 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 794 ASSERT(Pfn1->u3.e1.Rom != 1); 795 796 /* Is a standby or modified page being inserted? */ 797 ListName = ListHead->ListName; 798 if ((ListName == StandbyPageList) || (ListName == ModifiedPageList)) 799 { 800 /* If the page is in transition, it must also be a prototype page */ 801 if ((Pfn1->OriginalPte.u.Soft.Prototype == 0) && 802 (Pfn1->OriginalPte.u.Soft.Transition == 1)) 803 { 804 /* Crash the system on inconsistency */ 805 KeBugCheckEx(MEMORY_MANAGEMENT, 0x8888, 0, 0, 0); 806 } 807 } 808 809 /* Standby pages are prioritized, so we need to get the real head */ 810 if (ListHead == &MmStandbyPageListHead) 811 { 812 /* Obviously the prioritized list should still have the same name */ 813 ListHead = &MmStandbyPageListByPriority[Pfn1->u4.Priority]; 814 ASSERT(ListHead->ListName == ListName); 815 } 816 817 /* Increment the list count */ 818 ListHead->Total++; 819 820 /* Is a modified page being inserted? */ 821 if (ListHead == &MmModifiedPageListHead) 822 { 823 /* For now, only single-prototype pages should end up in this path */ 824 DPRINT("Modified page being added: %lx\n", PageFrameIndex); 825 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0); 826 827 /* Modified pages are colored when they are selected for page file */ 828 ListHead = &MmModifiedPageListByColor[0]; 829 ASSERT (ListHead->ListName == ListName); 830 ListHead->Total++; 831 832 /* Increment the number of paging file modified pages */ 833 MmTotalPagesForPagingFile++; 834 } 835 836 /* Don't handle bad pages yet yet */ 837 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 838 839 /* Zero pages go to the head, all other pages go to the end */ 840 if (ListName == ZeroedPageList) 841 { 842 /* Make the head of the list point to this page now */ 843 Flink = ListHead->Flink; 844 ListHead->Flink = PageFrameIndex; 845 846 /* Make the page point to the previous head, and back to the list */ 847 Pfn1->u1.Flink = Flink; 848 Pfn1->u2.Blink = LIST_HEAD; 849 850 /* Was the list empty? */ 851 if (Flink != LIST_HEAD) 852 { 853 /* It wasn't, so update the backlink of the previous head page */ 854 Pfn2 = MI_PFN_ELEMENT(Flink); 855 Pfn2->u2.Blink = PageFrameIndex; 856 } 857 else 858 { 859 /* It was empty, so have it loop back around to this new page */ 860 ListHead->Blink = PageFrameIndex; 861 } 862 } 863 else 864 { 865 /* Get the last page on the list */ 866 LastPage = ListHead->Blink; 867 if (LastPage != LIST_HEAD) 868 { 869 /* Link us with the previous page, so we're at the end now */ 870 MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex; 871 } 872 else 873 { 874 /* The list is empty, so we are the first page */ 875 ListHead->Flink = PageFrameIndex; 876 } 877 878 /* Now make the list head point back to us (since we go at the end) */ 879 ListHead->Blink = PageFrameIndex; 880 ASSERT_LIST_INVARIANT(ListHead); 881 882 /* And initialize our own list pointers */ 883 Pfn1->u1.Flink = LIST_HEAD; 884 Pfn1->u2.Blink = LastPage; 885 } 886 887 /* Move the page onto its new location */ 888 Pfn1->u3.e1.PageLocation = ListName; 889 890 /* For zero/free pages, we also have to handle the colored lists */ 891 if (ListName <= StandbyPageList) 892 { 893 /* Increment number of available pages */ 894 MiIncrementAvailablePages(); 895 896 /* Sanity checks */ 897 ASSERT(ListName == ZeroedPageList); 898 ASSERT(Pfn1->u4.InPageError == 0); 899 900 /* Get the page color */ 901 Color = PageFrameIndex & MmSecondaryColorMask; 902 903 /* Get the list for this color */ 904 ColorHead = &MmFreePagesByColor[ZeroedPageList][Color]; 905 906 /* Get the old head */ 907 Flink = ColorHead->Flink; 908 909 /* Make this page point back to the list, and point forwards to the old head */ 910 Pfn1->OriginalPte.u.Long = Flink; 911 Pfn1->u4.PteFrame = COLORED_LIST_HEAD; 912 913 /* Set the new head */ 914 ColorHead->Flink = PageFrameIndex; 915 916 /* Was the head empty? */ 917 if (Flink != LIST_HEAD) 918 { 919 /* No, so make the old head point to this page */ 920 Pfn2 = MI_PFN_ELEMENT(Flink); 921 Pfn2->u4.PteFrame = PageFrameIndex; 922 } 923 else 924 { 925 /* Yes, make it loop back to this page */ 926 ColorHead->Blink = (PVOID)Pfn1; 927 } 928 929 /* One more paged on the colored list */ 930 ColorHead->Count++; 931 932 #if MI_TRACE_PFNS 933 ASSERT(MI_PFN_CURRENT_USAGE == MI_USAGE_NOT_SET); 934 Pfn1->PfnUsage = MI_USAGE_FREE_PAGE; 935 RtlZeroMemory(Pfn1->ProcessName, 16); 936 Pfn1->CallSite = NULL; 937 #endif 938 } 939 else if (ListName == ModifiedPageList) 940 { 941 /* In ARM3, page must be destined for page file, and not yet written out */ 942 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0); 943 ASSERT(Pfn1->OriginalPte.u.Soft.PageFileHigh == 0); 944 945 /* One more transition page */ 946 MmTransitionSharedPages++; 947 948 /* Increment the number of per-process modified pages */ 949 PsGetCurrentProcess()->ModifiedPageCount++; 950 951 /* FIXME: Wake up modified page writer if there are not enough free pages */ 952 } 953 else if (ListName == ModifiedNoWritePageList) 954 { 955 /* This list is not yet implemented */ 956 ASSERT(FALSE); 957 } 958 } 959 960 VOID 961 NTAPI 962 MiInitializePfn(IN PFN_NUMBER PageFrameIndex, 963 IN PMMPTE PointerPte, 964 IN BOOLEAN Modified) 965 { 966 PMMPFN Pfn1; 967 NTSTATUS Status; 968 PMMPTE PointerPtePte; 969 MI_ASSERT_PFN_LOCK_HELD(); 970 971 /* Setup the PTE */ 972 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 973 Pfn1->PteAddress = PointerPte; 974 975 DPRINT("Called for %p from %p\n", Pfn1, _ReturnAddress()); 976 977 /* Check if this PFN is part of a valid address space */ 978 if (PointerPte->u.Hard.Valid == 1) 979 { 980 /* Only valid from MmCreateProcessAddressSpace path */ 981 ASSERT(PsGetCurrentProcess()->Vm.WorkingSetSize == 0); 982 983 /* Make this a demand zero PTE */ 984 MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE); 985 } 986 else 987 { 988 /* Copy the PTE data */ 989 Pfn1->OriginalPte = *PointerPte; 990 ASSERT(!((Pfn1->OriginalPte.u.Soft.Prototype == 0) && 991 (Pfn1->OriginalPte.u.Soft.Transition == 1))); 992 } 993 994 /* Otherwise this is a fresh page -- set it up */ 995 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 996 Pfn1->u3.e2.ReferenceCount = 1; 997 Pfn1->u2.ShareCount = 1; 998 Pfn1->u3.e1.PageLocation = ActiveAndValid; 999 ASSERT(Pfn1->u3.e1.Rom == 0); 1000 Pfn1->u3.e1.Modified = Modified; 1001 1002 /* Get the page table for the PTE */ 1003 PointerPtePte = MiAddressToPte(PointerPte); 1004 if (PointerPtePte->u.Hard.Valid == 0) 1005 { 1006 /* Make sure the PDE gets paged in properly */ 1007 Status = MiCheckPdeForPagedPool(PointerPte); 1008 if (!NT_SUCCESS(Status)) 1009 { 1010 /* Crash */ 1011 KeBugCheckEx(MEMORY_MANAGEMENT, 1012 0x61940, 1013 (ULONG_PTR)PointerPte, 1014 (ULONG_PTR)PointerPtePte->u.Long, 1015 (ULONG_PTR)MiPteToAddress(PointerPte)); 1016 } 1017 } 1018 1019 /* Get the PFN for the page table */ 1020 PageFrameIndex = PFN_FROM_PTE(PointerPtePte); 1021 ASSERT(PageFrameIndex != 0); 1022 Pfn1->u4.PteFrame = PageFrameIndex; 1023 1024 DPRINT("Incrementing share count of %lp from %p\n", PageFrameIndex, _ReturnAddress()); 1025 1026 /* Increase its share count so we don't get rid of it */ 1027 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 1028 Pfn1->u2.ShareCount++; 1029 } 1030 1031 VOID 1032 NTAPI 1033 MiInitializePfnAndMakePteValid(IN PFN_NUMBER PageFrameIndex, 1034 IN PMMPTE PointerPte, 1035 IN MMPTE TempPte) 1036 { 1037 PMMPFN Pfn1; 1038 NTSTATUS Status; 1039 PMMPTE PointerPtePte; 1040 MI_ASSERT_PFN_LOCK_HELD(); 1041 1042 /* PTE must be invalid */ 1043 ASSERT(PointerPte->u.Hard.Valid == 0); 1044 1045 /* Setup the PTE */ 1046 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 1047 Pfn1->PteAddress = PointerPte; 1048 Pfn1->OriginalPte = DemandZeroPte; 1049 1050 DPRINT("Incrementing %p from %p\n", Pfn1, _ReturnAddress()); 1051 1052 /* Otherwise this is a fresh page -- set it up */ 1053 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 1054 Pfn1->u3.e2.ReferenceCount++; 1055 Pfn1->u2.ShareCount++; 1056 Pfn1->u3.e1.PageLocation = ActiveAndValid; 1057 ASSERT(Pfn1->u3.e1.Rom == 0); 1058 Pfn1->u3.e1.Modified = 1; 1059 1060 /* Get the page table for the PTE */ 1061 PointerPtePte = MiAddressToPte(PointerPte); 1062 if (PointerPtePte->u.Hard.Valid == 0) 1063 { 1064 /* Make sure the PDE gets paged in properly */ 1065 Status = MiCheckPdeForPagedPool(PointerPte); 1066 if (!NT_SUCCESS(Status)) 1067 { 1068 /* Crash */ 1069 KeBugCheckEx(MEMORY_MANAGEMENT, 1070 0x61940, 1071 (ULONG_PTR)PointerPte, 1072 (ULONG_PTR)PointerPtePte->u.Long, 1073 (ULONG_PTR)MiPteToAddress(PointerPte)); 1074 } 1075 } 1076 1077 /* Get the PFN for the page table */ 1078 PageFrameIndex = PFN_FROM_PTE(PointerPtePte); 1079 ASSERT(PageFrameIndex != 0); 1080 Pfn1->u4.PteFrame = PageFrameIndex; 1081 1082 /* Increase its share count so we don't get rid of it */ 1083 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 1084 Pfn1->u2.ShareCount++; 1085 DPRINT("Incrementing %p from %p\n", Pfn1, _ReturnAddress()); 1086 1087 /* Write valid PTE */ 1088 MI_WRITE_VALID_PTE(PointerPte, TempPte); 1089 } 1090 1091 NTSTATUS 1092 NTAPI 1093 MiInitializeAndChargePfn(OUT PPFN_NUMBER PageFrameIndex, 1094 IN PMMPDE PointerPde, 1095 IN PFN_NUMBER ContainingPageFrame, 1096 IN BOOLEAN SessionAllocation) 1097 { 1098 MMPDE TempPde; 1099 KIRQL OldIrql; 1100 1101 /* Use either a global or local PDE */ 1102 TempPde = SessionAllocation ? ValidKernelPdeLocal : ValidKernelPde; 1103 1104 /* Lock the PFN database */ 1105 OldIrql = MiAcquirePfnLock(); 1106 1107 /* Make sure nobody is racing us */ 1108 if (PointerPde->u.Hard.Valid == 1) 1109 { 1110 /* Return special error if that was the case */ 1111 MiReleasePfnLock(OldIrql); 1112 return STATUS_RETRY; 1113 } 1114 1115 /* Grab a zero page and set the PFN, then make it valid */ 1116 *PageFrameIndex = MiRemoveZeroPage(MI_GET_NEXT_COLOR()); 1117 TempPde.u.Hard.PageFrameNumber = *PageFrameIndex; 1118 MI_WRITE_VALID_PDE(PointerPde, TempPde); 1119 1120 /* Initialize the PFN */ 1121 MiInitializePfnForOtherProcess(*PageFrameIndex, 1122 PointerPde, 1123 ContainingPageFrame); 1124 ASSERT(MI_PFN_ELEMENT(*PageFrameIndex)->u1.WsIndex == 0); 1125 1126 /* Release the lock and return success */ 1127 MiReleasePfnLock(OldIrql); 1128 return STATUS_SUCCESS; 1129 } 1130 1131 VOID 1132 NTAPI 1133 MiDecrementShareCount(IN PMMPFN Pfn1, 1134 IN PFN_NUMBER PageFrameIndex) 1135 { 1136 PMMPTE PointerPte; 1137 MMPTE TempPte; 1138 1139 ASSERT(PageFrameIndex > 0); 1140 ASSERT(MI_PFN_ELEMENT(PageFrameIndex) != NULL); 1141 ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex)); 1142 ASSERT(MI_IS_ROS_PFN(Pfn1) == FALSE); 1143 1144 DPRINT("Decrementing %p from %p\n", Pfn1, _ReturnAddress()); 1145 1146 /* Page must be in-use */ 1147 if ((Pfn1->u3.e1.PageLocation != ActiveAndValid) && 1148 (Pfn1->u3.e1.PageLocation != StandbyPageList)) 1149 { 1150 /* Otherwise we have PFN corruption */ 1151 KeBugCheckEx(PFN_LIST_CORRUPT, 1152 0x99, 1153 PageFrameIndex, 1154 Pfn1->u3.e1.PageLocation, 1155 0); 1156 } 1157 1158 /* Page should at least have one reference */ 1159 ASSERT(Pfn1->u3.e2.ReferenceCount != 0); 1160 1161 /* Check if the share count is now 0 */ 1162 ASSERT(Pfn1->u2.ShareCount < 0xF000000); 1163 if (!--Pfn1->u2.ShareCount) 1164 { 1165 /* Was this a prototype PTE? */ 1166 if (Pfn1->u3.e1.PrototypePte) 1167 { 1168 /* Grab the PTE address and make sure it's in prototype pool */ 1169 PointerPte = Pfn1->PteAddress; 1170 ASSERT((PointerPte >= (PMMPTE)MmPagedPoolStart) && (PointerPte <= (PMMPTE)MmPagedPoolEnd)); 1171 1172 /* The PTE that backs it should also be valdi */ 1173 PointerPte = MiAddressToPte(PointerPte); 1174 ASSERT(PointerPte->u.Hard.Valid == 1); 1175 1176 /* Get the original prototype PTE and turn it into a transition PTE */ 1177 PointerPte = Pfn1->PteAddress; 1178 TempPte = *PointerPte; 1179 TempPte.u.Soft.Transition = 1; 1180 TempPte.u.Soft.Valid = 0; 1181 TempPte.u.Soft.Prototype = 0; 1182 TempPte.u.Soft.Protection = Pfn1->OriginalPte.u.Soft.Protection; 1183 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 1184 DPRINT("Marking PTE: %p as transition (%p - %lx)\n", PointerPte, Pfn1, MiGetPfnEntryIndex(Pfn1)); 1185 } 1186 1187 /* Put the page in transition */ 1188 Pfn1->u3.e1.PageLocation = TransitionPage; 1189 1190 /* PFN lock must be held */ 1191 MI_ASSERT_PFN_LOCK_HELD(); 1192 1193 if (Pfn1->u3.e2.ReferenceCount == 1) 1194 { 1195 /* Is there still a PFN for this page? */ 1196 if (MI_IS_PFN_DELETED(Pfn1)) 1197 { 1198 /* Clear the last reference */ 1199 Pfn1->u3.e2.ReferenceCount = 0; 1200 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0); 1201 1202 /* Mark the page temporarily as valid, we're going to make it free soon */ 1203 Pfn1->u3.e1.PageLocation = ActiveAndValid; 1204 1205 /* Bring it back into the free list */ 1206 MiInsertPageInFreeList(PageFrameIndex); 1207 } 1208 else 1209 { 1210 /* PFN not yet deleted, drop a ref count */ 1211 MiDecrementReferenceCount(Pfn1, PageFrameIndex); 1212 } 1213 } 1214 else 1215 { 1216 /* Otherwise, just drop the reference count */ 1217 InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount); 1218 } 1219 } 1220 } 1221 1222 VOID 1223 NTAPI 1224 MiDecrementReferenceCount(IN PMMPFN Pfn1, 1225 IN PFN_NUMBER PageFrameIndex) 1226 { 1227 /* PFN lock must be held */ 1228 MI_ASSERT_PFN_LOCK_HELD(); 1229 1230 /* Sanity checks on the page */ 1231 if (PageFrameIndex > MmHighestPhysicalPage || 1232 Pfn1 != MI_PFN_ELEMENT(PageFrameIndex) || 1233 Pfn1->u3.e2.ReferenceCount == 0 || 1234 Pfn1->u3.e2.ReferenceCount >= 2500) 1235 { 1236 DPRINT1("PageFrameIndex=0x%lx, MmHighestPhysicalPage=0x%lx\n", PageFrameIndex, MmHighestPhysicalPage); 1237 DPRINT1("Pfn1=%p, Element=%p, RefCount=%u\n", Pfn1, MI_PFN_ELEMENT(PageFrameIndex), Pfn1->u3.e2.ReferenceCount); 1238 ASSERT(PageFrameIndex <= MmHighestPhysicalPage); 1239 ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex)); 1240 ASSERT(Pfn1->u3.e2.ReferenceCount != 0); 1241 ASSERT(Pfn1->u3.e2.ReferenceCount < 2500); 1242 } 1243 1244 /* Dereference the page, bail out if it's still alive */ 1245 InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount); 1246 if (Pfn1->u3.e2.ReferenceCount) return; 1247 1248 /* Nobody should still have reference to this page */ 1249 if (Pfn1->u2.ShareCount != 0) 1250 { 1251 /* Otherwise something's really wrong */ 1252 KeBugCheckEx(PFN_LIST_CORRUPT, 7, PageFrameIndex, Pfn1->u2.ShareCount, 0); 1253 } 1254 1255 /* And it should be lying on some page list */ 1256 ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid); 1257 1258 /* Did someone set the delete flag? */ 1259 if (MI_IS_PFN_DELETED(Pfn1)) 1260 { 1261 /* Insert it into the free list, there's nothing left to do */ 1262 MiInsertPageInFreeList(PageFrameIndex); 1263 return; 1264 } 1265 1266 /* Check to see which list this page should go into */ 1267 if (Pfn1->u3.e1.Modified == 1) 1268 { 1269 /* Push it into the modified page list */ 1270 MiInsertPageInList(&MmModifiedPageListHead, PageFrameIndex); 1271 } 1272 else 1273 { 1274 /* Otherwise, insert this page into the standby list */ 1275 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 1276 MiInsertStandbyListAtFront(PageFrameIndex); 1277 } 1278 } 1279 1280 VOID 1281 NTAPI 1282 MiInitializePfnForOtherProcess(IN PFN_NUMBER PageFrameIndex, 1283 IN PVOID PteAddress, 1284 IN PFN_NUMBER PteFrame) 1285 { 1286 PMMPFN Pfn1; 1287 1288 /* Setup the PTE */ 1289 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 1290 Pfn1->PteAddress = PteAddress; 1291 1292 /* Make this a software PTE */ 1293 MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE); 1294 1295 DPRINT("Called for %p from %p\n", Pfn1, _ReturnAddress()); 1296 1297 /* Setup the page */ 1298 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 1299 Pfn1->u3.e2.ReferenceCount = 1; 1300 Pfn1->u2.ShareCount = 1; 1301 Pfn1->u3.e1.PageLocation = ActiveAndValid; 1302 Pfn1->u3.e1.Modified = TRUE; 1303 Pfn1->u4.InPageError = FALSE; 1304 1305 /* Did we get a PFN for the page table */ 1306 if (PteFrame) 1307 { 1308 /* Store it */ 1309 Pfn1->u4.PteFrame = PteFrame; 1310 1311 /* Increase its share count so we don't get rid of it */ 1312 Pfn1 = MI_PFN_ELEMENT(PteFrame); 1313 1314 DPRINT("Incrementing %p from %p\n", Pfn1, _ReturnAddress()); 1315 Pfn1->u2.ShareCount++; 1316 } 1317 } 1318 1319 /* EOF */ 1320