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(Color < MmSecondaryColors); 485 if (MmAvailablePages == 0) 486 { 487 return 0; 488 } 489 490 /* Check the colored free list */ 491 PageIndex = MmFreePagesByColor[FreePageList][Color].Flink; 492 if (PageIndex == LIST_HEAD) 493 { 494 /* Check the colored zero list */ 495 PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink; 496 if (PageIndex == LIST_HEAD) 497 { 498 /* Check the free list */ 499 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 500 PageIndex = MmFreePageListHead.Flink; 501 Color = PageIndex & MmSecondaryColorMask; 502 if (PageIndex == LIST_HEAD) 503 { 504 /* Check the zero list */ 505 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 506 PageIndex = MmZeroedPageListHead.Flink; 507 Color = PageIndex & MmSecondaryColorMask; 508 ASSERT(PageIndex != LIST_HEAD); 509 if (PageIndex == LIST_HEAD) 510 { 511 /* FIXME: Should check the standby list */ 512 ASSERT(MmZeroedPageListHead.Total == 0); 513 } 514 } 515 } 516 } 517 518 /* Remove the page from its list */ 519 PageIndex = MiRemovePageByColor(PageIndex, Color); 520 ASSERT(PageIndex != 0); 521 522 /* Sanity checks */ 523 Pfn1 = MI_PFN_ELEMENT(PageIndex); 524 ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) || 525 (Pfn1->u3.e1.PageLocation == ZeroedPageList)); 526 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 527 ASSERT(Pfn1->u2.ShareCount == 0); 528 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 529 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 530 531 /* Return the page */ 532 return PageIndex; 533 } 534 535 PFN_NUMBER 536 NTAPI 537 MiRemoveZeroPage(IN ULONG Color) 538 { 539 PFN_NUMBER PageIndex; 540 PMMPFN Pfn1; 541 BOOLEAN Zero = FALSE; 542 543 /* Make sure PFN lock is held and we have pages */ 544 MI_ASSERT_PFN_LOCK_HELD(); 545 ASSERT(Color < MmSecondaryColors); 546 if (MmAvailablePages == 0) 547 { 548 return 0; 549 } 550 551 /* Check the colored zero list */ 552 PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink; 553 if (PageIndex == LIST_HEAD) 554 { 555 /* Check the zero list */ 556 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 557 PageIndex = MmZeroedPageListHead.Flink; 558 if (PageIndex == LIST_HEAD) 559 { 560 /* This means there's no zero pages, we have to look for free ones */ 561 ASSERT(MmZeroedPageListHead.Total == 0); 562 Zero = TRUE; 563 564 /* Check the colored free list */ 565 PageIndex = MmFreePagesByColor[FreePageList][Color].Flink; 566 if (PageIndex == LIST_HEAD) 567 { 568 /* Check the free list */ 569 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 570 PageIndex = MmFreePageListHead.Flink; 571 Color = PageIndex & MmSecondaryColorMask; 572 ASSERT(PageIndex != LIST_HEAD); 573 if (PageIndex == LIST_HEAD) 574 { 575 /* FIXME: Should check the standby list */ 576 ASSERT(MmZeroedPageListHead.Total == 0); 577 } 578 } 579 } 580 else 581 { 582 Color = PageIndex & MmSecondaryColorMask; 583 } 584 } 585 586 /* Sanity checks */ 587 Pfn1 = MI_PFN_ELEMENT(PageIndex); 588 ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) || 589 (Pfn1->u3.e1.PageLocation == ZeroedPageList)); 590 591 /* Remove the page from its list */ 592 PageIndex = MiRemovePageByColor(PageIndex, Color); 593 ASSERT(PageIndex != 0); 594 ASSERT(Pfn1 == MI_PFN_ELEMENT(PageIndex)); 595 596 /* Zero it, if needed */ 597 if (Zero) MiZeroPhysicalPage(PageIndex); 598 599 /* Sanity checks */ 600 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 601 ASSERT(Pfn1->u2.ShareCount == 0); 602 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 603 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 604 605 /* Return the page */ 606 return PageIndex; 607 } 608 609 VOID 610 NTAPI 611 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex) 612 { 613 PMMPFNLIST ListHead; 614 PFN_NUMBER LastPage; 615 PMMPFN Pfn1; 616 ULONG Color; 617 PMMPFN Blink; 618 PMMCOLOR_TABLES ColorTable; 619 620 /* Make sure the page index is valid */ 621 MI_ASSERT_PFN_LOCK_HELD(); 622 ASSERT((PageFrameIndex != 0) && 623 (PageFrameIndex <= MmHighestPhysicalPage) && 624 (PageFrameIndex >= MmLowestPhysicalPage)); 625 626 /* Get the PFN entry */ 627 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 628 629 /* Sanity checks that a right kind of page is being inserted here */ 630 ASSERT(Pfn1->u4.MustBeCached == 0); 631 ASSERT(Pfn1->u3.e1.Rom != 1); 632 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 633 ASSERT(Pfn1->u4.VerifierAllocation == 0); 634 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 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) 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 Pfn1->CallSite = NULL; 714 #endif 715 } 716 717 VOID 718 FASTCALL 719 MiInsertStandbyListAtFront(IN PFN_NUMBER PageFrameIndex) 720 { 721 PMMPFNLIST ListHead; 722 PFN_NUMBER Flink; 723 PMMPFN Pfn1, Pfn2; 724 725 /* Make sure the lock is held */ 726 DPRINT("Inserting page: %lx into standby list !\n", PageFrameIndex); 727 MI_ASSERT_PFN_LOCK_HELD(); 728 729 /* Make sure the PFN is valid */ 730 ASSERT((PageFrameIndex != 0) && 731 (PageFrameIndex <= MmHighestPhysicalPage) && 732 (PageFrameIndex >= MmLowestPhysicalPage)); 733 734 /* Grab the PFN and validate it is the right kind of PFN being inserted */ 735 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 736 ASSERT(Pfn1->u4.MustBeCached == 0); 737 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 738 ASSERT(Pfn1->u3.e1.PrototypePte == 1); 739 ASSERT(Pfn1->u3.e1.Rom != 1); 740 741 /* One more transition page on a list */ 742 MmTransitionSharedPages++; 743 744 /* Get the standby page list and increment its count */ 745 ListHead = &MmStandbyPageListByPriority [Pfn1->u4.Priority]; 746 ASSERT_LIST_INVARIANT(ListHead); 747 ListHead->Total++; 748 749 /* Make the head of the list point to this page now */ 750 Flink = ListHead->Flink; 751 ListHead->Flink = PageFrameIndex; 752 753 /* Make the page point to the previous head, and back to the list */ 754 Pfn1->u1.Flink = Flink; 755 Pfn1->u2.Blink = LIST_HEAD; 756 757 /* Was the list empty? */ 758 if (Flink != LIST_HEAD) 759 { 760 /* It wasn't, so update the backlink of the previous head page */ 761 Pfn2 = MI_PFN_ELEMENT(Flink); 762 Pfn2->u2.Blink = PageFrameIndex; 763 } 764 else 765 { 766 /* It was empty, so have it loop back around to this new page */ 767 ListHead->Blink = PageFrameIndex; 768 } 769 770 /* Move the page onto its new location */ 771 Pfn1->u3.e1.PageLocation = StandbyPageList; 772 773 /* Increment number of available pages */ 774 MiIncrementAvailablePages(); 775 } 776 777 VOID 778 NTAPI 779 MiInsertPageInList(IN PMMPFNLIST ListHead, 780 IN PFN_NUMBER PageFrameIndex) 781 { 782 PFN_NUMBER Flink, LastPage; 783 PMMPFN Pfn1, Pfn2; 784 MMLISTS ListName; 785 PMMCOLOR_TABLES ColorHead; 786 ULONG Color; 787 788 /* For free pages, use MiInsertPageInFreeList */ 789 ASSERT(ListHead != &MmFreePageListHead); 790 791 /* Make sure the lock is held */ 792 MI_ASSERT_PFN_LOCK_HELD(); 793 794 /* Make sure the PFN is valid */ 795 ASSERT((PageFrameIndex) && 796 (PageFrameIndex <= MmHighestPhysicalPage) && 797 (PageFrameIndex >= MmLowestPhysicalPage)); 798 799 /* Page should be unused */ 800 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 801 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 802 ASSERT(Pfn1->u3.e1.Rom != 1); 803 804 /* Is a standby or modified page being inserted? */ 805 ListName = ListHead->ListName; 806 if ((ListName == StandbyPageList) || (ListName == ModifiedPageList)) 807 { 808 /* If the page is in transition, it must also be a prototype page */ 809 if ((Pfn1->OriginalPte.u.Soft.Prototype == 0) && 810 (Pfn1->OriginalPte.u.Soft.Transition == 1)) 811 { 812 /* Crash the system on inconsistency */ 813 KeBugCheckEx(MEMORY_MANAGEMENT, 0x8888, 0, 0, 0); 814 } 815 } 816 817 /* Standby pages are prioritized, so we need to get the real head */ 818 if (ListHead == &MmStandbyPageListHead) 819 { 820 /* Obviously the prioritized list should still have the same name */ 821 ListHead = &MmStandbyPageListByPriority[Pfn1->u4.Priority]; 822 ASSERT(ListHead->ListName == ListName); 823 } 824 825 /* Increment the list count */ 826 ListHead->Total++; 827 828 /* Is a modified page being inserted? */ 829 if (ListHead == &MmModifiedPageListHead) 830 { 831 /* For now, only single-prototype pages should end up in this path */ 832 DPRINT("Modified page being added: %lx\n", PageFrameIndex); 833 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0); 834 835 /* Modified pages are colored when they are selected for page file */ 836 ListHead = &MmModifiedPageListByColor[0]; 837 ASSERT (ListHead->ListName == ListName); 838 ListHead->Total++; 839 840 /* Increment the number of paging file modified pages */ 841 MmTotalPagesForPagingFile++; 842 } 843 844 /* Don't handle bad pages yet yet */ 845 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 846 847 /* Zero pages go to the head, all other pages go to the end */ 848 if (ListName == ZeroedPageList) 849 { 850 /* Make the head of the list point to this page now */ 851 Flink = ListHead->Flink; 852 ListHead->Flink = PageFrameIndex; 853 854 /* Make the page point to the previous head, and back to the list */ 855 Pfn1->u1.Flink = Flink; 856 Pfn1->u2.Blink = LIST_HEAD; 857 858 /* Was the list empty? */ 859 if (Flink != LIST_HEAD) 860 { 861 /* It wasn't, so update the backlink of the previous head page */ 862 Pfn2 = MI_PFN_ELEMENT(Flink); 863 Pfn2->u2.Blink = PageFrameIndex; 864 } 865 else 866 { 867 /* It was empty, so have it loop back around to this new page */ 868 ListHead->Blink = PageFrameIndex; 869 } 870 } 871 else 872 { 873 /* Get the last page on the list */ 874 LastPage = ListHead->Blink; 875 if (LastPage != LIST_HEAD) 876 { 877 /* Link us with the previous page, so we're at the end now */ 878 MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex; 879 } 880 else 881 { 882 /* The list is empty, so we are the first page */ 883 ListHead->Flink = PageFrameIndex; 884 } 885 886 /* Now make the list head point back to us (since we go at the end) */ 887 ListHead->Blink = PageFrameIndex; 888 ASSERT_LIST_INVARIANT(ListHead); 889 890 /* And initialize our own list pointers */ 891 Pfn1->u1.Flink = LIST_HEAD; 892 Pfn1->u2.Blink = LastPage; 893 } 894 895 /* Move the page onto its new location */ 896 Pfn1->u3.e1.PageLocation = ListName; 897 898 /* For zero/free pages, we also have to handle the colored lists */ 899 if (ListName <= StandbyPageList) 900 { 901 /* Increment number of available pages */ 902 MiIncrementAvailablePages(); 903 904 /* Sanity checks */ 905 ASSERT(ListName == ZeroedPageList); 906 ASSERT(Pfn1->u4.InPageError == 0); 907 908 /* Get the page color */ 909 Color = PageFrameIndex & MmSecondaryColorMask; 910 911 /* Get the list for this color */ 912 ColorHead = &MmFreePagesByColor[ZeroedPageList][Color]; 913 914 /* Get the old head */ 915 Flink = ColorHead->Flink; 916 917 /* Make this page point back to the list, and point forwards to the old head */ 918 Pfn1->OriginalPte.u.Long = Flink; 919 Pfn1->u4.PteFrame = COLORED_LIST_HEAD; 920 921 /* Set the new head */ 922 ColorHead->Flink = PageFrameIndex; 923 924 /* Was the head empty? */ 925 if (Flink != LIST_HEAD) 926 { 927 /* No, so make the old head point to this page */ 928 Pfn2 = MI_PFN_ELEMENT(Flink); 929 Pfn2->u4.PteFrame = PageFrameIndex; 930 } 931 else 932 { 933 /* Yes, make it loop back to this page */ 934 ColorHead->Blink = (PVOID)Pfn1; 935 } 936 937 /* One more paged on the colored list */ 938 ColorHead->Count++; 939 940 #if MI_TRACE_PFNS 941 ASSERT(MI_PFN_CURRENT_USAGE == MI_USAGE_NOT_SET); 942 Pfn1->PfnUsage = MI_USAGE_FREE_PAGE; 943 RtlZeroMemory(Pfn1->ProcessName, 16); 944 Pfn1->CallSite = NULL; 945 #endif 946 } 947 else if (ListName == ModifiedPageList) 948 { 949 /* In ARM3, page must be destined for page file, and not yet written out */ 950 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0); 951 ASSERT(Pfn1->OriginalPte.u.Soft.PageFileHigh == 0); 952 953 /* One more transition page */ 954 MmTransitionSharedPages++; 955 956 /* Increment the number of per-process modified pages */ 957 PsGetCurrentProcess()->ModifiedPageCount++; 958 959 /* FIXME: Wake up modified page writer if there are not enough free pages */ 960 } 961 else if (ListName == ModifiedNoWritePageList) 962 { 963 /* This list is not yet implemented */ 964 ASSERT(FALSE); 965 } 966 } 967 968 VOID 969 NTAPI 970 MiInitializePfn(IN PFN_NUMBER PageFrameIndex, 971 IN PMMPTE PointerPte, 972 IN BOOLEAN Modified) 973 { 974 PMMPFN Pfn1; 975 NTSTATUS Status; 976 PMMPTE PointerPtePte; 977 MI_ASSERT_PFN_LOCK_HELD(); 978 979 /* Setup the PTE */ 980 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 981 Pfn1->PteAddress = PointerPte; 982 983 DPRINT("Called for %p from %p\n", Pfn1, _ReturnAddress()); 984 985 /* Check if this PFN is part of a valid address space */ 986 if (PointerPte->u.Hard.Valid == 1) 987 { 988 /* Only valid from MmCreateProcessAddressSpace path */ 989 ASSERT(PsGetCurrentProcess()->Vm.WorkingSetSize == 0); 990 991 /* Make this a demand zero PTE */ 992 MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE); 993 } 994 else 995 { 996 /* Copy the PTE data */ 997 Pfn1->OriginalPte = *PointerPte; 998 ASSERT(!((Pfn1->OriginalPte.u.Soft.Prototype == 0) && 999 (Pfn1->OriginalPte.u.Soft.Transition == 1))); 1000 } 1001 1002 /* Otherwise this is a fresh page -- set it up */ 1003 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 1004 Pfn1->u3.e2.ReferenceCount = 1; 1005 Pfn1->u2.ShareCount = 1; 1006 Pfn1->u3.e1.PageLocation = ActiveAndValid; 1007 ASSERT(Pfn1->u3.e1.Rom == 0); 1008 Pfn1->u3.e1.Modified = Modified; 1009 1010 /* Get the page table for the PTE */ 1011 PointerPtePte = MiAddressToPte(PointerPte); 1012 if (PointerPtePte->u.Hard.Valid == 0) 1013 { 1014 /* Make sure the PDE gets paged in properly */ 1015 Status = MiCheckPdeForPagedPool(PointerPte); 1016 if (!NT_SUCCESS(Status)) 1017 { 1018 /* Crash */ 1019 KeBugCheckEx(MEMORY_MANAGEMENT, 1020 0x61940, 1021 (ULONG_PTR)PointerPte, 1022 (ULONG_PTR)PointerPtePte->u.Long, 1023 (ULONG_PTR)MiPteToAddress(PointerPte)); 1024 } 1025 } 1026 1027 /* Get the PFN for the page table */ 1028 PageFrameIndex = PFN_FROM_PTE(PointerPtePte); 1029 ASSERT(PageFrameIndex != 0); 1030 Pfn1->u4.PteFrame = PageFrameIndex; 1031 1032 DPRINT("Incrementing share count of %lp from %p\n", PageFrameIndex, _ReturnAddress()); 1033 1034 /* Increase its share count so we don't get rid of it */ 1035 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 1036 Pfn1->u2.ShareCount++; 1037 } 1038 1039 VOID 1040 NTAPI 1041 MiInitializePfnAndMakePteValid(IN PFN_NUMBER PageFrameIndex, 1042 IN PMMPTE PointerPte, 1043 IN MMPTE TempPte) 1044 { 1045 PMMPFN Pfn1; 1046 NTSTATUS Status; 1047 PMMPTE PointerPtePte; 1048 MI_ASSERT_PFN_LOCK_HELD(); 1049 1050 /* PTE must be invalid */ 1051 ASSERT(PointerPte->u.Hard.Valid == 0); 1052 1053 /* Setup the PTE */ 1054 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 1055 Pfn1->PteAddress = PointerPte; 1056 Pfn1->OriginalPte = DemandZeroPte; 1057 1058 DPRINT("Incrementing %p from %p\n", Pfn1, _ReturnAddress()); 1059 1060 /* Otherwise this is a fresh page -- set it up */ 1061 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 1062 Pfn1->u3.e2.ReferenceCount++; 1063 Pfn1->u2.ShareCount++; 1064 Pfn1->u3.e1.PageLocation = ActiveAndValid; 1065 ASSERT(Pfn1->u3.e1.Rom == 0); 1066 Pfn1->u3.e1.Modified = 1; 1067 1068 /* Get the page table for the PTE */ 1069 PointerPtePte = MiAddressToPte(PointerPte); 1070 if (PointerPtePte->u.Hard.Valid == 0) 1071 { 1072 /* Make sure the PDE gets paged in properly */ 1073 Status = MiCheckPdeForPagedPool(PointerPte); 1074 if (!NT_SUCCESS(Status)) 1075 { 1076 /* Crash */ 1077 KeBugCheckEx(MEMORY_MANAGEMENT, 1078 0x61940, 1079 (ULONG_PTR)PointerPte, 1080 (ULONG_PTR)PointerPtePte->u.Long, 1081 (ULONG_PTR)MiPteToAddress(PointerPte)); 1082 } 1083 } 1084 1085 /* Get the PFN for the page table */ 1086 PageFrameIndex = PFN_FROM_PTE(PointerPtePte); 1087 ASSERT(PageFrameIndex != 0); 1088 Pfn1->u4.PteFrame = PageFrameIndex; 1089 1090 /* Increase its share count so we don't get rid of it */ 1091 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 1092 Pfn1->u2.ShareCount++; 1093 DPRINT("Incrementing %p from %p\n", Pfn1, _ReturnAddress()); 1094 1095 /* Write valid PTE */ 1096 MI_WRITE_VALID_PTE(PointerPte, TempPte); 1097 } 1098 1099 NTSTATUS 1100 NTAPI 1101 MiInitializeAndChargePfn(OUT PPFN_NUMBER PageFrameIndex, 1102 IN PMMPDE PointerPde, 1103 IN PFN_NUMBER ContainingPageFrame, 1104 IN BOOLEAN SessionAllocation) 1105 { 1106 MMPDE TempPde; 1107 KIRQL OldIrql; 1108 1109 /* Use either a global or local PDE */ 1110 TempPde = SessionAllocation ? ValidKernelPdeLocal : ValidKernelPde; 1111 1112 /* Lock the PFN database */ 1113 OldIrql = MiAcquirePfnLock(); 1114 1115 /* Make sure nobody is racing us */ 1116 if (PointerPde->u.Hard.Valid == 1) 1117 { 1118 /* Return special error if that was the case */ 1119 MiReleasePfnLock(OldIrql); 1120 return STATUS_RETRY; 1121 } 1122 1123 /* Grab a zero page and set the PFN, then make it valid */ 1124 *PageFrameIndex = MiRemoveZeroPage(MI_GET_NEXT_COLOR()); 1125 TempPde.u.Hard.PageFrameNumber = *PageFrameIndex; 1126 MI_WRITE_VALID_PDE(PointerPde, TempPde); 1127 1128 /* Initialize the PFN */ 1129 MiInitializePfnForOtherProcess(*PageFrameIndex, 1130 PointerPde, 1131 ContainingPageFrame); 1132 ASSERT(MI_PFN_ELEMENT(*PageFrameIndex)->u1.WsIndex == 0); 1133 1134 /* Release the lock and return success */ 1135 MiReleasePfnLock(OldIrql); 1136 return STATUS_SUCCESS; 1137 } 1138 1139 VOID 1140 NTAPI 1141 MiDecrementShareCount(IN PMMPFN Pfn1, 1142 IN PFN_NUMBER PageFrameIndex) 1143 { 1144 PMMPTE PointerPte; 1145 MMPTE TempPte; 1146 1147 ASSERT(PageFrameIndex > 0); 1148 ASSERT(MI_PFN_ELEMENT(PageFrameIndex) != NULL); 1149 ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex)); 1150 ASSERT(MI_IS_ROS_PFN(Pfn1) == FALSE); 1151 1152 DPRINT("Decrementing %p from %p\n", Pfn1, _ReturnAddress()); 1153 1154 /* Page must be in-use */ 1155 if ((Pfn1->u3.e1.PageLocation != ActiveAndValid) && 1156 (Pfn1->u3.e1.PageLocation != StandbyPageList)) 1157 { 1158 /* Otherwise we have PFN corruption */ 1159 KeBugCheckEx(PFN_LIST_CORRUPT, 1160 0x99, 1161 PageFrameIndex, 1162 Pfn1->u3.e1.PageLocation, 1163 0); 1164 } 1165 1166 /* Page should at least have one reference */ 1167 ASSERT(Pfn1->u3.e2.ReferenceCount != 0); 1168 1169 /* Check if the share count is now 0 */ 1170 ASSERT(Pfn1->u2.ShareCount < 0xF000000); 1171 if (!--Pfn1->u2.ShareCount) 1172 { 1173 /* Was this a prototype PTE? */ 1174 if (Pfn1->u3.e1.PrototypePte) 1175 { 1176 /* Grab the PTE address and make sure it's in prototype pool */ 1177 PointerPte = Pfn1->PteAddress; 1178 ASSERT((PointerPte >= (PMMPTE)MmPagedPoolStart) && (PointerPte <= (PMMPTE)MmPagedPoolEnd)); 1179 1180 /* The PTE that backs it should also be valdi */ 1181 PointerPte = MiAddressToPte(PointerPte); 1182 ASSERT(PointerPte->u.Hard.Valid == 1); 1183 1184 /* Get the original prototype PTE and turn it into a transition PTE */ 1185 PointerPte = Pfn1->PteAddress; 1186 TempPte = *PointerPte; 1187 TempPte.u.Soft.Transition = 1; 1188 TempPte.u.Soft.Valid = 0; 1189 TempPte.u.Soft.Prototype = 0; 1190 TempPte.u.Soft.Protection = Pfn1->OriginalPte.u.Soft.Protection; 1191 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 1192 DPRINT("Marking PTE: %p as transition (%p - %lx)\n", PointerPte, Pfn1, MiGetPfnEntryIndex(Pfn1)); 1193 } 1194 1195 /* Put the page in transition */ 1196 Pfn1->u3.e1.PageLocation = TransitionPage; 1197 1198 /* PFN lock must be held */ 1199 MI_ASSERT_PFN_LOCK_HELD(); 1200 1201 if (Pfn1->u3.e2.ReferenceCount == 1) 1202 { 1203 /* Is there still a PFN for this page? */ 1204 if (MI_IS_PFN_DELETED(Pfn1)) 1205 { 1206 /* Clear the last reference */ 1207 Pfn1->u3.e2.ReferenceCount = 0; 1208 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0); 1209 1210 /* Mark the page temporarily as valid, we're going to make it free soon */ 1211 Pfn1->u3.e1.PageLocation = ActiveAndValid; 1212 1213 /* Bring it back into the free list */ 1214 MiInsertPageInFreeList(PageFrameIndex); 1215 } 1216 else 1217 { 1218 /* PFN not yet deleted, drop a ref count */ 1219 MiDecrementReferenceCount(Pfn1, PageFrameIndex); 1220 } 1221 } 1222 else 1223 { 1224 /* Otherwise, just drop the reference count */ 1225 InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount); 1226 } 1227 } 1228 } 1229 1230 VOID 1231 NTAPI 1232 MmDereferencePage(PFN_NUMBER Pfn); 1233 1234 VOID 1235 NTAPI 1236 MiDecrementReferenceCount(IN PMMPFN Pfn1, 1237 IN PFN_NUMBER PageFrameIndex) 1238 { 1239 /* PFN lock must be held */ 1240 MI_ASSERT_PFN_LOCK_HELD(); 1241 1242 /* Handle RosMm PFNs here, too (in case they got locked/unlocked by ARM3) */ 1243 if (MI_IS_ROS_PFN(Pfn1)) 1244 { 1245 MmDereferencePage(PageFrameIndex); 1246 return; 1247 } 1248 1249 /* Sanity checks on the page */ 1250 if (PageFrameIndex > MmHighestPhysicalPage || 1251 Pfn1 != MI_PFN_ELEMENT(PageFrameIndex) || 1252 Pfn1->u3.e2.ReferenceCount == 0 || 1253 Pfn1->u3.e2.ReferenceCount >= 2500) 1254 { 1255 DPRINT1("PageFrameIndex=0x%lx, MmHighestPhysicalPage=0x%lx\n", PageFrameIndex, MmHighestPhysicalPage); 1256 DPRINT1("Pfn1=%p, Element=%p, RefCount=%u\n", Pfn1, MI_PFN_ELEMENT(PageFrameIndex), Pfn1->u3.e2.ReferenceCount); 1257 ASSERT(PageFrameIndex <= MmHighestPhysicalPage); 1258 ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex)); 1259 ASSERT(Pfn1->u3.e2.ReferenceCount != 0); 1260 ASSERT(Pfn1->u3.e2.ReferenceCount < 2500); 1261 } 1262 1263 /* Dereference the page, bail out if it's still alive */ 1264 InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount); 1265 if (Pfn1->u3.e2.ReferenceCount) return; 1266 1267 /* Nobody should still have reference to this page */ 1268 if (Pfn1->u2.ShareCount != 0) 1269 { 1270 /* Otherwise something's really wrong */ 1271 KeBugCheckEx(PFN_LIST_CORRUPT, 7, PageFrameIndex, Pfn1->u2.ShareCount, 0); 1272 } 1273 1274 /* And it should be lying on some page list */ 1275 ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid); 1276 1277 /* Did someone set the delete flag? */ 1278 if (MI_IS_PFN_DELETED(Pfn1)) 1279 { 1280 /* Insert it into the free list, there's nothing left to do */ 1281 MiInsertPageInFreeList(PageFrameIndex); 1282 return; 1283 } 1284 1285 /* Check to see which list this page should go into */ 1286 if (Pfn1->u3.e1.Modified == 1) 1287 { 1288 /* Push it into the modified page list */ 1289 MiInsertPageInList(&MmModifiedPageListHead, PageFrameIndex); 1290 } 1291 else 1292 { 1293 /* Otherwise, insert this page into the standby list */ 1294 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 1295 MiInsertStandbyListAtFront(PageFrameIndex); 1296 } 1297 } 1298 1299 VOID 1300 NTAPI 1301 MiInitializePfnForOtherProcess(IN PFN_NUMBER PageFrameIndex, 1302 IN PVOID PteAddress, 1303 IN PFN_NUMBER PteFrame) 1304 { 1305 PMMPFN Pfn1; 1306 1307 /* Setup the PTE */ 1308 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 1309 Pfn1->PteAddress = PteAddress; 1310 1311 /* Make this a software PTE */ 1312 MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE); 1313 1314 DPRINT("Called for %p from %p\n", Pfn1, _ReturnAddress()); 1315 1316 /* Setup the page */ 1317 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 1318 Pfn1->u3.e2.ReferenceCount = 1; 1319 Pfn1->u2.ShareCount = 1; 1320 Pfn1->u3.e1.PageLocation = ActiveAndValid; 1321 Pfn1->u3.e1.Modified = TRUE; 1322 Pfn1->u4.InPageError = FALSE; 1323 1324 /* Did we get a PFN for the page table */ 1325 if (PteFrame) 1326 { 1327 /* Store it */ 1328 Pfn1->u4.PteFrame = PteFrame; 1329 1330 /* Increase its share count so we don't get rid of it */ 1331 Pfn1 = MI_PFN_ELEMENT(PteFrame); 1332 1333 DPRINT("Incrementing %p from %p\n", Pfn1, _ReturnAddress()); 1334 Pfn1->u2.ShareCount++; 1335 } 1336 } 1337 1338 /* EOF */ 1339