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 // MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET; 258 // memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16); 259 #endif 260 } 261 262 VOID 263 NTAPI 264 MiUnlinkPageFromList(IN PMMPFN Pfn) 265 { 266 PMMPFNLIST ListHead; 267 PFN_NUMBER OldFlink, OldBlink; 268 269 /* Make sure the PFN lock is held */ 270 MI_ASSERT_PFN_LOCK_HELD(); 271 272 /* ARM3 should only call this for dead pages */ 273 ASSERT(Pfn->u3.e2.ReferenceCount == 0); 274 275 /* Transition pages are supposed to be standby/modified/nowrite */ 276 ListHead = MmPageLocationList[Pfn->u3.e1.PageLocation]; 277 ASSERT(ListHead->ListName >= StandbyPageList); 278 279 /* Check if this was standby, or modified */ 280 if (ListHead == &MmStandbyPageListHead) 281 { 282 /* Should not be a ROM page */ 283 ASSERT(Pfn->u3.e1.Rom == 0); 284 285 /* Get the exact list */ 286 ListHead = &MmStandbyPageListByPriority[Pfn->u4.Priority]; 287 288 /* Decrement number of available pages */ 289 MiDecrementAvailablePages(); 290 291 /* Decrease transition page counter */ 292 ASSERT(Pfn->u3.e1.PrototypePte == 1); /* Only supported ARM3 case */ 293 MmTransitionSharedPages--; 294 } 295 else if (ListHead == &MmModifiedPageListHead) 296 { 297 /* Only shared memory (page-file backed) modified pages are supported */ 298 ASSERT(Pfn->OriginalPte.u.Soft.Prototype == 0); 299 300 /* Decrement the counters */ 301 ListHead->Total--; 302 MmTotalPagesForPagingFile--; 303 304 /* Pick the correct colored list */ 305 ListHead = &MmModifiedPageListByColor[0]; 306 307 /* Decrease transition page counter */ 308 MmTransitionSharedPages--; 309 } 310 else if (ListHead == &MmModifiedNoWritePageListHead) 311 { 312 /* List not yet supported */ 313 ASSERT(FALSE); 314 } 315 316 /* Nothing should be in progress and the list should not be empty */ 317 ASSERT(Pfn->u3.e1.WriteInProgress == 0); 318 ASSERT(Pfn->u3.e1.ReadInProgress == 0); 319 ASSERT(ListHead->Total != 0); 320 321 /* Get the forward and back pointers */ 322 OldFlink = Pfn->u1.Flink; 323 OldBlink = Pfn->u2.Blink; 324 325 /* Check if the next entry is the list head */ 326 if (OldFlink != LIST_HEAD) 327 { 328 /* It is not, so set the backlink of the actual entry, to our backlink */ 329 MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink; 330 } 331 else 332 { 333 /* Set the list head's backlink instead */ 334 ListHead->Blink = OldBlink; 335 } 336 337 /* Check if the back entry is the list head */ 338 if (OldBlink != LIST_HEAD) 339 { 340 /* It is not, so set the backlink of the actual entry, to our backlink */ 341 MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink; 342 } 343 else 344 { 345 /* Set the list head's backlink instead */ 346 ListHead->Flink = OldFlink; 347 } 348 349 /* ReactOS Hack */ 350 Pfn->OriginalPte.u.Long = 0; 351 352 /* We are not on a list anymore */ 353 Pfn->u1.Flink = Pfn->u2.Blink = 0; 354 355 /* Remove one entry from the list */ 356 ListHead->Total--; 357 358 ASSERT_LIST_INVARIANT(ListHead); 359 } 360 361 PFN_NUMBER 362 NTAPI 363 MiRemovePageByColor(IN PFN_NUMBER PageIndex, 364 IN ULONG Color) 365 { 366 PMMPFN Pfn1; 367 PMMPFNLIST ListHead; 368 MMLISTS ListName; 369 PFN_NUMBER OldFlink, OldBlink; 370 USHORT OldColor, OldCache; 371 PMMCOLOR_TABLES ColorTable; 372 373 /* Make sure PFN lock is held */ 374 MI_ASSERT_PFN_LOCK_HELD(); 375 ASSERT(Color < MmSecondaryColors); 376 377 /* Get the PFN entry */ 378 Pfn1 = MI_PFN_ELEMENT(PageIndex); 379 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 380 ASSERT(Pfn1->u3.e1.Rom == 0); 381 382 /* Capture data for later */ 383 OldColor = Pfn1->u3.e1.PageColor; 384 OldCache = Pfn1->u3.e1.CacheAttribute; 385 386 /* Could be either on free or zero list */ 387 ListHead = MmPageLocationList[Pfn1->u3.e1.PageLocation]; 388 ASSERT_LIST_INVARIANT(ListHead); 389 ListName = ListHead->ListName; 390 ASSERT(ListName <= FreePageList); 391 392 /* Remove a page */ 393 ListHead->Total--; 394 395 /* Get the forward and back pointers */ 396 OldFlink = Pfn1->u1.Flink; 397 OldBlink = Pfn1->u2.Blink; 398 399 /* Check if the next entry is the list head */ 400 if (OldFlink != LIST_HEAD) 401 { 402 /* It is not, so set the backlink of the actual entry, to our backlink */ 403 MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink; 404 } 405 else 406 { 407 /* Set the list head's backlink instead */ 408 ListHead->Blink = OldBlink; 409 } 410 411 /* Check if the back entry is the list head */ 412 if (OldBlink != LIST_HEAD) 413 { 414 /* It is not, so set the backlink of the actual entry, to our backlink */ 415 MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink; 416 } 417 else 418 { 419 /* Set the list head's backlink instead */ 420 ListHead->Flink = OldFlink; 421 } 422 423 /* We are not on a list anymore */ 424 ASSERT_LIST_INVARIANT(ListHead); 425 Pfn1->u1.Flink = Pfn1->u2.Blink = 0; 426 427 /* Zero flags but restore color and cache */ 428 Pfn1->u3.e2.ShortFlags = 0; 429 Pfn1->u3.e1.PageColor = OldColor; 430 Pfn1->u3.e1.CacheAttribute = OldCache; 431 432 /* Get the first page on the color list */ 433 ASSERT(Color < MmSecondaryColors); 434 ColorTable = &MmFreePagesByColor[ListName][Color]; 435 ASSERT(ColorTable->Count >= 1); 436 437 /* Set the forward link to whoever we were pointing to */ 438 ColorTable->Flink = Pfn1->OriginalPte.u.Long; 439 440 /* Get the first page on the color list */ 441 if (ColorTable->Flink == LIST_HEAD) 442 { 443 /* This is the beginning of the list, so set the sentinel value */ 444 ColorTable->Blink = (PVOID)LIST_HEAD; 445 } 446 else 447 { 448 /* The list is empty, so we are the first page */ 449 MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD; 450 } 451 452 /* One less page */ 453 ColorTable->Count--; 454 455 /* ReactOS Hack */ 456 Pfn1->OriginalPte.u.Long = 0; 457 458 /* Decrement number of available pages */ 459 MiDecrementAvailablePages(); 460 461 #if MI_TRACE_PFNS 462 //ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET); 463 Pfn1->PfnUsage = MI_PFN_CURRENT_USAGE; 464 memcpy(Pfn1->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16); 465 //MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET; 466 //memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16); 467 #endif 468 469 /* Return the page */ 470 return PageIndex; 471 } 472 473 PFN_NUMBER 474 NTAPI 475 MiRemoveAnyPage(IN ULONG Color) 476 { 477 PFN_NUMBER PageIndex; 478 PMMPFN Pfn1; 479 480 /* Make sure PFN lock is held and we have pages */ 481 MI_ASSERT_PFN_LOCK_HELD(); 482 ASSERT(MmAvailablePages != 0); 483 ASSERT(Color < MmSecondaryColors); 484 485 /* Check the colored free list */ 486 PageIndex = MmFreePagesByColor[FreePageList][Color].Flink; 487 if (PageIndex == LIST_HEAD) 488 { 489 /* Check the colored zero list */ 490 PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink; 491 if (PageIndex == LIST_HEAD) 492 { 493 /* Check the free list */ 494 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 495 PageIndex = MmFreePageListHead.Flink; 496 Color = PageIndex & MmSecondaryColorMask; 497 if (PageIndex == LIST_HEAD) 498 { 499 /* Check the zero list */ 500 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 501 PageIndex = MmZeroedPageListHead.Flink; 502 Color = PageIndex & MmSecondaryColorMask; 503 ASSERT(PageIndex != LIST_HEAD); 504 if (PageIndex == LIST_HEAD) 505 { 506 /* FIXME: Should check the standby list */ 507 ASSERT(MmZeroedPageListHead.Total == 0); 508 } 509 } 510 } 511 } 512 513 /* Remove the page from its list */ 514 PageIndex = MiRemovePageByColor(PageIndex, Color); 515 516 /* Sanity checks */ 517 Pfn1 = MI_PFN_ELEMENT(PageIndex); 518 ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) || 519 (Pfn1->u3.e1.PageLocation == ZeroedPageList)); 520 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 521 ASSERT(Pfn1->u2.ShareCount == 0); 522 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 523 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 524 525 /* Return the page */ 526 return PageIndex; 527 } 528 529 PFN_NUMBER 530 NTAPI 531 MiRemoveZeroPage(IN ULONG Color) 532 { 533 PFN_NUMBER PageIndex; 534 PMMPFN Pfn1; 535 BOOLEAN Zero = FALSE; 536 537 /* Make sure PFN lock is held and we have pages */ 538 MI_ASSERT_PFN_LOCK_HELD(); 539 ASSERT(MmAvailablePages != 0); 540 ASSERT(Color < MmSecondaryColors); 541 542 /* Check the colored zero list */ 543 PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink; 544 if (PageIndex == LIST_HEAD) 545 { 546 /* Check the zero list */ 547 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 548 PageIndex = MmZeroedPageListHead.Flink; 549 if (PageIndex == LIST_HEAD) 550 { 551 /* This means there's no zero pages, we have to look for free ones */ 552 ASSERT(MmZeroedPageListHead.Total == 0); 553 Zero = TRUE; 554 555 /* Check the colored free list */ 556 PageIndex = MmFreePagesByColor[FreePageList][Color].Flink; 557 if (PageIndex == LIST_HEAD) 558 { 559 /* Check the free list */ 560 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 561 PageIndex = MmFreePageListHead.Flink; 562 Color = PageIndex & MmSecondaryColorMask; 563 ASSERT(PageIndex != LIST_HEAD); 564 if (PageIndex == LIST_HEAD) 565 { 566 /* FIXME: Should check the standby list */ 567 ASSERT(MmZeroedPageListHead.Total == 0); 568 } 569 } 570 } 571 else 572 { 573 Color = PageIndex & MmSecondaryColorMask; 574 } 575 } 576 577 /* Sanity checks */ 578 Pfn1 = MI_PFN_ELEMENT(PageIndex); 579 ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) || 580 (Pfn1->u3.e1.PageLocation == ZeroedPageList)); 581 582 /* Remove the page from its list */ 583 PageIndex = MiRemovePageByColor(PageIndex, Color); 584 ASSERT(Pfn1 == MI_PFN_ELEMENT(PageIndex)); 585 586 /* Zero it, if needed */ 587 if (Zero) MiZeroPhysicalPage(PageIndex); 588 589 /* Sanity checks */ 590 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 591 ASSERT(Pfn1->u2.ShareCount == 0); 592 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 593 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 594 595 /* Return the page */ 596 return PageIndex; 597 } 598 599 /* HACK for keeping legacy Mm alive */ 600 extern BOOLEAN MmRosNotifyAvailablePage(PFN_NUMBER PageFrameIndex); 601 602 VOID 603 NTAPI 604 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex) 605 { 606 PMMPFNLIST ListHead; 607 PFN_NUMBER LastPage; 608 PMMPFN Pfn1; 609 ULONG Color; 610 PMMPFN Blink; 611 PMMCOLOR_TABLES ColorTable; 612 613 /* Make sure the page index is valid */ 614 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); 615 ASSERT((PageFrameIndex != 0) && 616 (PageFrameIndex <= MmHighestPhysicalPage) && 617 (PageFrameIndex >= MmLowestPhysicalPage)); 618 619 /* Get the PFN entry */ 620 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 621 622 /* Sanity checks that a right kind of page is being inserted here */ 623 ASSERT(Pfn1->u4.MustBeCached == 0); 624 ASSERT(Pfn1->u3.e1.Rom != 1); 625 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 626 ASSERT(Pfn1->u4.VerifierAllocation == 0); 627 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 628 629 /* HACK HACK HACK : Feed the page to legacy Mm */ 630 if (MmRosNotifyAvailablePage(PageFrameIndex)) 631 { 632 DPRINT1("Legacy Mm eating ARM3 page!.\n"); 633 return; 634 } 635 636 /* Get the free page list and increment its count */ 637 ListHead = &MmFreePageListHead; 638 ASSERT_LIST_INVARIANT(ListHead); 639 ListHead->Total++; 640 641 /* Get the last page on the list */ 642 LastPage = ListHead->Blink; 643 if (LastPage != LIST_HEAD) 644 { 645 /* Link us with the previous page, so we're at the end now */ 646 MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex; 647 } 648 else 649 { 650 /* The list is empty, so we are the first page */ 651 ListHead->Flink = PageFrameIndex; 652 } 653 654 /* Now make the list head point back to us (since we go at the end) */ 655 ListHead->Blink = PageFrameIndex; 656 ASSERT_LIST_INVARIANT(ListHead); 657 658 /* And initialize our own list pointers */ 659 Pfn1->u1.Flink = LIST_HEAD; 660 Pfn1->u2.Blink = LastPage; 661 662 /* Set the list name and default priority */ 663 Pfn1->u3.e1.PageLocation = FreePageList; 664 Pfn1->u4.Priority = 3; 665 666 /* Clear some status fields */ 667 Pfn1->u4.InPageError = 0; 668 Pfn1->u4.AweAllocation = 0; 669 670 /* Increment number of available pages */ 671 MiIncrementAvailablePages(); 672 673 /* Get the page color */ 674 Color = PageFrameIndex & MmSecondaryColorMask; 675 676 /* Get the first page on the color list */ 677 ColorTable = &MmFreePagesByColor[FreePageList][Color]; 678 if (ColorTable->Flink == LIST_HEAD) 679 { 680 /* The list is empty, so we are the first page */ 681 Pfn1->u4.PteFrame = COLORED_LIST_HEAD; 682 ColorTable->Flink = PageFrameIndex; 683 } 684 else 685 { 686 /* Get the previous page */ 687 Blink = (PMMPFN)ColorTable->Blink; 688 689 /* Make it link to us, and link back to it */ 690 Blink->OriginalPte.u.Long = PageFrameIndex; 691 Pfn1->u4.PteFrame = MiGetPfnEntryIndex(Blink); 692 } 693 694 /* Now initialize our own list pointers */ 695 ColorTable->Blink = Pfn1; 696 697 /* This page is now the last */ 698 Pfn1->OriginalPte.u.Long = LIST_HEAD; 699 700 /* And increase the count in the colored list */ 701 ColorTable->Count++; 702 703 /* Notify zero page thread if enough pages are on the free list now */ 704 if ((ListHead->Total >= 8) && !(MmZeroingPageThreadActive)) 705 { 706 /* Set the event */ 707 KeSetEvent(&MmZeroingPageEvent, IO_NO_INCREMENT, FALSE); 708 } 709 710 #if MI_TRACE_PFNS 711 Pfn1->PfnUsage = MI_USAGE_FREE_PAGE; 712 RtlZeroMemory(Pfn1->ProcessName, 16); 713 #endif 714 } 715 716 VOID 717 FASTCALL 718 MiInsertStandbyListAtFront(IN PFN_NUMBER PageFrameIndex) 719 { 720 PMMPFNLIST ListHead; 721 PFN_NUMBER Flink; 722 PMMPFN Pfn1, Pfn2; 723 724 /* Make sure the lock is held */ 725 DPRINT("Inserting page: %lx into standby list !\n", PageFrameIndex); 726 MI_ASSERT_PFN_LOCK_HELD(); 727 728 /* Make sure the PFN is valid */ 729 ASSERT((PageFrameIndex != 0) && 730 (PageFrameIndex <= MmHighestPhysicalPage) && 731 (PageFrameIndex >= MmLowestPhysicalPage)); 732 733 /* Grab the PFN and validate it is the right kind of PFN being inserted */ 734 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 735 ASSERT(Pfn1->u4.MustBeCached == 0); 736 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 737 ASSERT(Pfn1->u3.e1.PrototypePte == 1); 738 ASSERT(Pfn1->u3.e1.Rom != 1); 739 740 /* One more transition page on a list */ 741 MmTransitionSharedPages++; 742 743 /* Get the standby page list and increment its count */ 744 ListHead = &MmStandbyPageListByPriority [Pfn1->u4.Priority]; 745 ASSERT_LIST_INVARIANT(ListHead); 746 ListHead->Total++; 747 748 /* Make the head of the list point to this page now */ 749 Flink = ListHead->Flink; 750 ListHead->Flink = PageFrameIndex; 751 752 /* Make the page point to the previous head, and back to the list */ 753 Pfn1->u1.Flink = Flink; 754 Pfn1->u2.Blink = LIST_HEAD; 755 756 /* Was the list empty? */ 757 if (Flink != LIST_HEAD) 758 { 759 /* It wasn't, so update the backlink of the previous head page */ 760 Pfn2 = MI_PFN_ELEMENT(Flink); 761 Pfn2->u2.Blink = PageFrameIndex; 762 } 763 else 764 { 765 /* It was empty, so have it loop back around to this new page */ 766 ListHead->Blink = PageFrameIndex; 767 } 768 769 /* Move the page onto its new location */ 770 Pfn1->u3.e1.PageLocation = StandbyPageList; 771 772 /* Increment number of available pages */ 773 MiIncrementAvailablePages(); 774 } 775 776 VOID 777 NTAPI 778 MiInsertPageInList(IN PMMPFNLIST ListHead, 779 IN PFN_NUMBER PageFrameIndex) 780 { 781 PFN_NUMBER Flink, LastPage; 782 PMMPFN Pfn1, Pfn2; 783 MMLISTS ListName; 784 PMMCOLOR_TABLES ColorHead; 785 ULONG Color; 786 787 /* For free pages, use MiInsertPageInFreeList */ 788 ASSERT(ListHead != &MmFreePageListHead); 789 790 /* Make sure the lock is held */ 791 MI_ASSERT_PFN_LOCK_HELD(); 792 793 /* Make sure the PFN is valid */ 794 ASSERT((PageFrameIndex) && 795 (PageFrameIndex <= MmHighestPhysicalPage) && 796 (PageFrameIndex >= MmLowestPhysicalPage)); 797 798 /* Page should be unused */ 799 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 800 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 801 ASSERT(Pfn1->u3.e1.Rom != 1); 802 803 /* Is a standby or modified page being inserted? */ 804 ListName = ListHead->ListName; 805 if ((ListName == StandbyPageList) || (ListName == ModifiedPageList)) 806 { 807 /* If the page is in transition, it must also be a prototype page */ 808 if ((Pfn1->OriginalPte.u.Soft.Prototype == 0) && 809 (Pfn1->OriginalPte.u.Soft.Transition == 1)) 810 { 811 /* Crash the system on inconsistency */ 812 KeBugCheckEx(MEMORY_MANAGEMENT, 0x8888, 0, 0, 0); 813 } 814 } 815 816 /* Standby pages are prioritized, so we need to get the real head */ 817 if (ListHead == &MmStandbyPageListHead) 818 { 819 /* Obviously the prioritized list should still have the same name */ 820 ListHead = &MmStandbyPageListByPriority[Pfn1->u4.Priority]; 821 ASSERT(ListHead->ListName == ListName); 822 } 823 824 /* Increment the list count */ 825 ListHead->Total++; 826 827 /* Is a modified page being inserted? */ 828 if (ListHead == &MmModifiedPageListHead) 829 { 830 /* For now, only single-prototype pages should end up in this path */ 831 DPRINT("Modified page being added: %lx\n", PageFrameIndex); 832 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0); 833 834 /* Modified pages are colored when they are selected for page file */ 835 ListHead = &MmModifiedPageListByColor[0]; 836 ASSERT (ListHead->ListName == ListName); 837 ListHead->Total++; 838 839 /* Increment the number of paging file modified pages */ 840 MmTotalPagesForPagingFile++; 841 } 842 843 /* Don't handle bad pages yet yet */ 844 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 845 846 /* Zero pages go to the head, all other pages go to the end */ 847 if (ListName == ZeroedPageList) 848 { 849 /* Make the head of the list point to this page now */ 850 Flink = ListHead->Flink; 851 ListHead->Flink = PageFrameIndex; 852 853 /* Make the page point to the previous head, and back to the list */ 854 Pfn1->u1.Flink = Flink; 855 Pfn1->u2.Blink = LIST_HEAD; 856 857 /* Was the list empty? */ 858 if (Flink != LIST_HEAD) 859 { 860 /* It wasn't, so update the backlink of the previous head page */ 861 Pfn2 = MI_PFN_ELEMENT(Flink); 862 Pfn2->u2.Blink = PageFrameIndex; 863 } 864 else 865 { 866 /* It was empty, so have it loop back around to this new page */ 867 ListHead->Blink = PageFrameIndex; 868 } 869 } 870 else 871 { 872 /* Get the last page on the list */ 873 LastPage = ListHead->Blink; 874 if (LastPage != LIST_HEAD) 875 { 876 /* Link us with the previous page, so we're at the end now */ 877 MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex; 878 } 879 else 880 { 881 /* The list is empty, so we are the first page */ 882 ListHead->Flink = PageFrameIndex; 883 } 884 885 /* Now make the list head point back to us (since we go at the end) */ 886 ListHead->Blink = PageFrameIndex; 887 ASSERT_LIST_INVARIANT(ListHead); 888 889 /* And initialize our own list pointers */ 890 Pfn1->u1.Flink = LIST_HEAD; 891 Pfn1->u2.Blink = LastPage; 892 } 893 894 /* Move the page onto its new location */ 895 Pfn1->u3.e1.PageLocation = ListName; 896 897 /* For zero/free pages, we also have to handle the colored lists */ 898 if (ListName <= StandbyPageList) 899 { 900 /* Increment number of available pages */ 901 MiIncrementAvailablePages(); 902 903 /* Sanity checks */ 904 ASSERT(ListName == ZeroedPageList); 905 ASSERT(Pfn1->u4.InPageError == 0); 906 907 /* Get the page color */ 908 Color = PageFrameIndex & MmSecondaryColorMask; 909 910 /* Get the list for this color */ 911 ColorHead = &MmFreePagesByColor[ZeroedPageList][Color]; 912 913 /* Get the old head */ 914 Flink = ColorHead->Flink; 915 916 /* Make this page point back to the list, and point forwards to the old head */ 917 Pfn1->OriginalPte.u.Long = Flink; 918 Pfn1->u4.PteFrame = COLORED_LIST_HEAD; 919 920 /* Set the new head */ 921 ColorHead->Flink = PageFrameIndex; 922 923 /* Was the head empty? */ 924 if (Flink != LIST_HEAD) 925 { 926 /* No, so make the old head point to this page */ 927 Pfn2 = MI_PFN_ELEMENT(Flink); 928 Pfn2->u4.PteFrame = PageFrameIndex; 929 } 930 else 931 { 932 /* Yes, make it loop back to this page */ 933 ColorHead->Blink = (PVOID)Pfn1; 934 } 935 936 /* One more paged on the colored list */ 937 ColorHead->Count++; 938 939 #if MI_TRACE_PFNS 940 //ASSERT(MI_PFN_CURRENT_USAGE == MI_USAGE_NOT_SET); 941 Pfn1->PfnUsage = MI_USAGE_FREE_PAGE; 942 MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET; 943 RtlZeroMemory(Pfn1->ProcessName, 16); 944 #endif 945 } 946 else if (ListName == ModifiedPageList) 947 { 948 /* In ARM3, page must be destined for page file, and not yet written out */ 949 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0); 950 ASSERT(Pfn1->OriginalPte.u.Soft.PageFileHigh == 0); 951 952 /* One more transition page */ 953 MmTransitionSharedPages++; 954 955 /* Increment the number of per-process modified pages */ 956 PsGetCurrentProcess()->ModifiedPageCount++; 957 958 /* FIXME: Wake up modified page writer if there are not enough free pages */ 959 } 960 else if (ListName == ModifiedNoWritePageList) 961 { 962 /* This list is not yet implemented */ 963 ASSERT(FALSE); 964 } 965 } 966 967 VOID 968 NTAPI 969 MiInitializePfn(IN PFN_NUMBER PageFrameIndex, 970 IN PMMPTE PointerPte, 971 IN BOOLEAN Modified) 972 { 973 PMMPFN Pfn1; 974 NTSTATUS Status; 975 PMMPTE PointerPtePte; 976 MI_ASSERT_PFN_LOCK_HELD(); 977 978 /* Setup the PTE */ 979 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 980 Pfn1->PteAddress = PointerPte; 981 982 /* Check if this PFN is part of a valid address space */ 983 if (PointerPte->u.Hard.Valid == 1) 984 { 985 /* Only valid from MmCreateProcessAddressSpace path */ 986 ASSERT(PsGetCurrentProcess()->Vm.WorkingSetSize == 0); 987 988 /* Make this a demand zero PTE */ 989 MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE); 990 } 991 else 992 { 993 /* Copy the PTE data */ 994 Pfn1->OriginalPte = *PointerPte; 995 ASSERT(!((Pfn1->OriginalPte.u.Soft.Prototype == 0) && 996 (Pfn1->OriginalPte.u.Soft.Transition == 1))); 997 } 998 999 /* Otherwise this is a fresh page -- set it up */ 1000 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 1001 Pfn1->u3.e2.ReferenceCount = 1; 1002 Pfn1->u2.ShareCount = 1; 1003 Pfn1->u3.e1.PageLocation = ActiveAndValid; 1004 ASSERT(Pfn1->u3.e1.Rom == 0); 1005 Pfn1->u3.e1.Modified = Modified; 1006 1007 /* Get the page table for the PTE */ 1008 PointerPtePte = MiAddressToPte(PointerPte); 1009 if (PointerPtePte->u.Hard.Valid == 0) 1010 { 1011 /* Make sure the PDE gets paged in properly */ 1012 Status = MiCheckPdeForPagedPool(PointerPte); 1013 if (!NT_SUCCESS(Status)) 1014 { 1015 /* Crash */ 1016 KeBugCheckEx(MEMORY_MANAGEMENT, 1017 0x61940, 1018 (ULONG_PTR)PointerPte, 1019 (ULONG_PTR)PointerPtePte->u.Long, 1020 (ULONG_PTR)MiPteToAddress(PointerPte)); 1021 } 1022 } 1023 1024 /* Get the PFN for the page table */ 1025 PageFrameIndex = PFN_FROM_PTE(PointerPtePte); 1026 ASSERT(PageFrameIndex != 0); 1027 Pfn1->u4.PteFrame = PageFrameIndex; 1028 1029 /* Increase its share count so we don't get rid of it */ 1030 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 1031 Pfn1->u2.ShareCount++; 1032 } 1033 1034 VOID 1035 NTAPI 1036 MiInitializePfnAndMakePteValid(IN PFN_NUMBER PageFrameIndex, 1037 IN PMMPTE PointerPte, 1038 IN MMPTE TempPte) 1039 { 1040 PMMPFN Pfn1; 1041 NTSTATUS Status; 1042 PMMPTE PointerPtePte; 1043 MI_ASSERT_PFN_LOCK_HELD(); 1044 1045 /* PTE must be invalid */ 1046 ASSERT(PointerPte->u.Hard.Valid == 0); 1047 1048 /* Setup the PTE */ 1049 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 1050 Pfn1->PteAddress = PointerPte; 1051 Pfn1->OriginalPte = DemandZeroPte; 1052 1053 /* Otherwise this is a fresh page -- set it up */ 1054 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 1055 Pfn1->u3.e2.ReferenceCount++; 1056 Pfn1->u2.ShareCount++; 1057 Pfn1->u3.e1.PageLocation = ActiveAndValid; 1058 ASSERT(Pfn1->u3.e1.Rom == 0); 1059 Pfn1->u3.e1.Modified = 1; 1060 1061 /* Get the page table for the PTE */ 1062 PointerPtePte = MiAddressToPte(PointerPte); 1063 if (PointerPtePte->u.Hard.Valid == 0) 1064 { 1065 /* Make sure the PDE gets paged in properly */ 1066 Status = MiCheckPdeForPagedPool(PointerPte); 1067 if (!NT_SUCCESS(Status)) 1068 { 1069 /* Crash */ 1070 KeBugCheckEx(MEMORY_MANAGEMENT, 1071 0x61940, 1072 (ULONG_PTR)PointerPte, 1073 (ULONG_PTR)PointerPtePte->u.Long, 1074 (ULONG_PTR)MiPteToAddress(PointerPte)); 1075 } 1076 } 1077 1078 /* Get the PFN for the page table */ 1079 PageFrameIndex = PFN_FROM_PTE(PointerPtePte); 1080 ASSERT(PageFrameIndex != 0); 1081 Pfn1->u4.PteFrame = PageFrameIndex; 1082 1083 /* Increase its share count so we don't get rid of it */ 1084 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 1085 Pfn1->u2.ShareCount++; 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 /* Page must be in-use */ 1145 if ((Pfn1->u3.e1.PageLocation != ActiveAndValid) && 1146 (Pfn1->u3.e1.PageLocation != StandbyPageList)) 1147 { 1148 /* Otherwise we have PFN corruption */ 1149 KeBugCheckEx(PFN_LIST_CORRUPT, 1150 0x99, 1151 PageFrameIndex, 1152 Pfn1->u3.e1.PageLocation, 1153 0); 1154 } 1155 1156 /* Page should at least have one reference */ 1157 ASSERT(Pfn1->u3.e2.ReferenceCount != 0); 1158 1159 /* Check if the share count is now 0 */ 1160 ASSERT(Pfn1->u2.ShareCount < 0xF000000); 1161 if (!--Pfn1->u2.ShareCount) 1162 { 1163 /* Was this a prototype PTE? */ 1164 if (Pfn1->u3.e1.PrototypePte) 1165 { 1166 /* Grab the PTE address and make sure it's in prototype pool */ 1167 PointerPte = Pfn1->PteAddress; 1168 ASSERT((PointerPte >= (PMMPTE)MmPagedPoolStart) && (PointerPte <= (PMMPTE)MmPagedPoolEnd)); 1169 1170 /* The PTE that backs it should also be valdi */ 1171 PointerPte = MiAddressToPte(PointerPte); 1172 ASSERT(PointerPte->u.Hard.Valid == 1); 1173 1174 /* Get the original prototype PTE and turn it into a transition PTE */ 1175 PointerPte = Pfn1->PteAddress; 1176 TempPte = *PointerPte; 1177 TempPte.u.Soft.Transition = 1; 1178 TempPte.u.Soft.Valid = 0; 1179 TempPte.u.Soft.Prototype = 0; 1180 TempPte.u.Soft.Protection = Pfn1->OriginalPte.u.Soft.Protection; 1181 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 1182 DPRINT("Marking PTE: %p as transition (%p - %lx)\n", PointerPte, Pfn1, MiGetPfnEntryIndex(Pfn1)); 1183 } 1184 1185 /* Put the page in transition */ 1186 Pfn1->u3.e1.PageLocation = TransitionPage; 1187 1188 /* PFN lock must be held */ 1189 MI_ASSERT_PFN_LOCK_HELD(); 1190 1191 if (Pfn1->u3.e2.ReferenceCount == 1) 1192 { 1193 /* Is there still a PFN for this page? */ 1194 if (MI_IS_PFN_DELETED(Pfn1)) 1195 { 1196 /* Clear the last reference */ 1197 Pfn1->u3.e2.ReferenceCount = 0; 1198 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0); 1199 1200 /* Mark the page temporarily as valid, we're going to make it free soon */ 1201 Pfn1->u3.e1.PageLocation = ActiveAndValid; 1202 1203 /* Bring it back into the free list */ 1204 MiInsertPageInFreeList(PageFrameIndex); 1205 } 1206 else 1207 { 1208 /* PFN not yet deleted, drop a ref count */ 1209 MiDecrementReferenceCount(Pfn1, PageFrameIndex); 1210 } 1211 } 1212 else 1213 { 1214 /* Otherwise, just drop the reference count */ 1215 InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount); 1216 } 1217 } 1218 } 1219 1220 VOID 1221 NTAPI 1222 MiDecrementReferenceCount(IN PMMPFN Pfn1, 1223 IN PFN_NUMBER PageFrameIndex) 1224 { 1225 /* PFN lock must be held */ 1226 MI_ASSERT_PFN_LOCK_HELD(); 1227 1228 /* Sanity checks on the page */ 1229 if (PageFrameIndex > MmHighestPhysicalPage || 1230 Pfn1 != MI_PFN_ELEMENT(PageFrameIndex) || 1231 Pfn1->u3.e2.ReferenceCount == 0 || 1232 Pfn1->u3.e2.ReferenceCount >= 2500) 1233 { 1234 DPRINT1("PageFrameIndex=0x%lx, MmHighestPhysicalPage=0x%lx\n", PageFrameIndex, MmHighestPhysicalPage); 1235 DPRINT1("Pfn1=%p, Element=%p, RefCount=%u\n", Pfn1, MI_PFN_ELEMENT(PageFrameIndex), Pfn1->u3.e2.ReferenceCount); 1236 ASSERT(PageFrameIndex <= MmHighestPhysicalPage); 1237 ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex)); 1238 ASSERT(Pfn1->u3.e2.ReferenceCount != 0); 1239 ASSERT(Pfn1->u3.e2.ReferenceCount < 2500); 1240 } 1241 1242 /* Dereference the page, bail out if it's still alive */ 1243 InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount); 1244 if (Pfn1->u3.e2.ReferenceCount) return; 1245 1246 /* Nobody should still have reference to this page */ 1247 if (Pfn1->u2.ShareCount != 0) 1248 { 1249 /* Otherwise something's really wrong */ 1250 KeBugCheckEx(PFN_LIST_CORRUPT, 7, PageFrameIndex, Pfn1->u2.ShareCount, 0); 1251 } 1252 1253 /* And it should be lying on some page list */ 1254 ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid); 1255 1256 /* Did someone set the delete flag? */ 1257 if (MI_IS_PFN_DELETED(Pfn1)) 1258 { 1259 /* Insert it into the free list, there's nothing left to do */ 1260 MiInsertPageInFreeList(PageFrameIndex); 1261 return; 1262 } 1263 1264 /* Check to see which list this page should go into */ 1265 if (Pfn1->u3.e1.Modified == 1) 1266 { 1267 /* Push it into the modified page list */ 1268 MiInsertPageInList(&MmModifiedPageListHead, PageFrameIndex); 1269 } 1270 else 1271 { 1272 /* Otherwise, insert this page into the standby list */ 1273 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 1274 MiInsertStandbyListAtFront(PageFrameIndex); 1275 } 1276 } 1277 1278 VOID 1279 NTAPI 1280 MiInitializePfnForOtherProcess(IN PFN_NUMBER PageFrameIndex, 1281 IN PVOID PteAddress, 1282 IN PFN_NUMBER PteFrame) 1283 { 1284 PMMPFN Pfn1; 1285 1286 /* Setup the PTE */ 1287 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 1288 Pfn1->PteAddress = PteAddress; 1289 1290 /* Make this a software PTE */ 1291 MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE); 1292 1293 /* Setup the page */ 1294 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 1295 Pfn1->u3.e2.ReferenceCount = 1; 1296 Pfn1->u2.ShareCount = 1; 1297 Pfn1->u3.e1.PageLocation = ActiveAndValid; 1298 Pfn1->u3.e1.Modified = TRUE; 1299 Pfn1->u4.InPageError = FALSE; 1300 1301 /* Did we get a PFN for the page table */ 1302 if (PteFrame) 1303 { 1304 /* Store it */ 1305 Pfn1->u4.PteFrame = PteFrame; 1306 1307 /* Increase its share count so we don't get rid of it */ 1308 Pfn1 = MI_PFN_ELEMENT(PteFrame); 1309 Pfn1->u2.ShareCount++; 1310 } 1311 } 1312 1313 /* EOF */ 1314