00444 :
00445
00446 This routine attempts to remove
the specified physical address range
00447 from
the system.
00448
00449 Arguments:
00450
00451 StartAddress - Supplies
the starting physical address.
00452
00453 NumberOfBytes - Supplies a pointer to
the number of bytes being removed.
00454
00455 Return Value:
00456
00457
NTSTATUS.
00458
00459 Environment:
00460
00461 Kernel mode. PASSIVE level. No locks held.
00462
00463 --*/
00464
00465 {
00466 ULONG i;
00467 ULONG Additional;
00468 PFN_NUMBER Page;
00469 PFN_NUMBER LastPage;
00470 PFN_NUMBER OriginalLastPage;
00471 PFN_NUMBER start;
00472 PFN_NUMBER PagesReleased;
00473
PMMPFN Pfn1;
00474
PMMPFN StartPfn;
00475
PMMPFN EndPfn;
00476 KIRQL OldIrql;
00477 PFN_NUMBER StartPage;
00478 PFN_NUMBER EndPage;
00479 PFN_COUNT NumberOfPages;
00480 SPFN_NUMBER MaxPages;
00481 PFN_NUMBER PageFrameIndex;
00482 PFN_NUMBER RemovedPages;
00483 LOGICAL Inserted;
00484
NTSTATUS Status;
00485
PMMPTE PointerPte;
00486
PMMPTE EndPte;
00487 PVOID VirtualAddress;
00488
PPHYSICAL_MEMORY_DESCRIPTOR OldPhysicalMemoryBlock;
00489
PPHYSICAL_MEMORY_DESCRIPTOR NewPhysicalMemoryBlock;
00490
PPHYSICAL_MEMORY_RUN NewRun;
00491 LOGICAL PfnDatabaseIsPhysical;
00492
00493
ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
00494
00495
ASSERT (
BYTE_OFFSET(NumberOfBytes->LowPart) == 0);
00496
ASSERT (
BYTE_OFFSET(StartAddress->LowPart) == 0);
00497
00498
if (
MI_IS_PHYSICAL_ADDRESS(MmPfnDatabase)) {
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
if (
MmDynamicPfn ==
FALSE) {
00510
return STATUS_NOT_SUPPORTED;
00511 }
00512
00513 PfnDatabaseIsPhysical =
TRUE;
00514 }
00515
else {
00516 PfnDatabaseIsPhysical =
FALSE;
00517 }
00518
00519 StartPage = (PFN_NUMBER)(StartAddress->QuadPart >>
PAGE_SHIFT);
00520 NumberOfPages = (PFN_COUNT)(NumberOfBytes->QuadPart >>
PAGE_SHIFT);
00521
00522 EndPage = StartPage + NumberOfPages;
00523
00524
if (EndPage - 1 >
MmHighestPossiblePhysicalPage) {
00525
00526
00527
00528
00529
00530
00531 EndPage =
MmHighestPossiblePhysicalPage + 1;
00532 NumberOfPages = (PFN_COUNT)(EndPage - StartPage);
00533 }
00534
00535
00536
00537
00538
00539
if (StartPage >= EndPage) {
00540
return STATUS_INVALID_PARAMETER_1;
00541 }
00542
00543 StartPfn =
MI_PFN_ELEMENT (StartPage);
00544 EndPfn =
MI_PFN_ELEMENT (EndPage);
00545
00546 ExAcquireFastMutex (&MmDynamicMemoryMutex);
00547
00548
#if DBG
00549
MiDynmemData[0] += 1;
00550
#endif
00551
00552
00553
00554
00555
00556 ExAcquireSpinLock (&MmChargeCommitmentLock, &OldIrql);
00557
00558
ASSERT (MmTotalCommitLimit <= MmTotalCommitLimitMaximum);
00559
00560
if ((NumberOfPages + 100 >
MmTotalCommitLimit -
MmTotalCommittedPages) ||
00561 (
MmTotalCommittedPages >
MmTotalCommitLimit)) {
00562
00563
#if DBG
00564
MiDynmemData[1] += 1;
00565
#endif
00566
ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql);
00567 ExReleaseFastMutex (&MmDynamicMemoryMutex);
00568
return STATUS_INSUFFICIENT_RESOURCES;
00569 }
00570
00571
MmTotalCommitLimit -= NumberOfPages;
00572
MmTotalCommitLimitMaximum -= NumberOfPages;
00573
00574 ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql);
00575
00576
00577
00578
00579
00580
LOCK_PFN (OldIrql);
00581
00582 MaxPages =
MI_NONPAGABLE_MEMORY_AVAILABLE() - 100;
00583
00584
if ((SPFN_NUMBER)NumberOfPages > MaxPages) {
00585
#if DBG
00586
MiDynmemData[2] += 1;
00587
#endif
00588
UNLOCK_PFN (OldIrql);
00589
Status = STATUS_INSUFFICIENT_RESOURCES;
00590
goto giveup2;
00591 }
00592
00593
MmResidentAvailablePages -= NumberOfPages;
00594
MmNumberOfPhysicalPages -= NumberOfPages;
00595
00596
00597
00598
00599
00600
00601 Additional = (ULONG)-2;
00602
00603 start = 0;
00604
do {
00605
00606 Page =
MmPhysicalMemoryBlock->
Run[start].
BasePage;
00607 LastPage = Page +
MmPhysicalMemoryBlock->
Run[start].
PageCount;
00608
00609
if ((StartPage >= Page) && (EndPage <= LastPage)) {
00610
if ((StartPage == Page) && (EndPage == LastPage)) {
00611 Additional = (ULONG)-1;
00612 }
00613
else if ((StartPage == Page) || (EndPage == LastPage)) {
00614 Additional = 0;
00615 }
00616
else {
00617 Additional = 1;
00618 }
00619
break;
00620 }
00621
00622 start += 1;
00623
00624 }
while (start !=
MmPhysicalMemoryBlock->
NumberOfRuns);
00625
00626
if (Additional == (ULONG)-2) {
00627
#if DBG
00628
MiDynmemData[3] += 1;
00629
#endif
00630
MmResidentAvailablePages += NumberOfPages;
00631
MmNumberOfPhysicalPages += NumberOfPages;
00632
UNLOCK_PFN (OldIrql);
00633
Status = STATUS_CONFLICTING_ADDRESSES;
00634
goto giveup2;
00635 }
00636
00637
for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) {
00638 Pfn1->
u3.e1.RemovalRequested = 1;
00639 }
00640
00641
00642
00643
00644
00645
00646
00647 RemovedPages =
MiRemovePhysicalPages (StartPage, EndPage);
00648
00649
if (RemovedPages != NumberOfPages) {
00650
00651
#if DBG
00652
retry:
00653
#endif
00654
00655 Pfn1 = StartPfn;
00656
00657 InterlockedIncrement (&MiDelayPageFaults);
00658
00659
for (i = 0; i < 5; i += 1) {
00660
00661
UNLOCK_PFN (OldIrql);
00662
00663
00664
00665
00666
00667
00668
MiTrimRemovalPagesOnly =
TRUE;
00669
00670
MiEmptyAllWorkingSets ();
00671
00672
MiTrimRemovalPagesOnly =
FALSE;
00673
00674
MiFlushAllPages ();
00675
00676
KeDelayExecutionThread (KernelMode, FALSE, &MmHalfSecond);
00677
00678
LOCK_PFN (OldIrql);
00679
00680 RemovedPages +=
MiRemovePhysicalPages (StartPage, EndPage);
00681
00682
if (RemovedPages == NumberOfPages) {
00683
break;
00684 }
00685
00686
00687
00688
00689
00690
00691
00692
for ( ; Pfn1 < EndPfn; Pfn1 += 1) {
00693
if (Pfn1->
u3.e1.PageLocation !=
BadPageList) {
00694
break;
00695 }
00696 }
00697
00698
if (Pfn1 == EndPfn) {
00699 RemovedPages = NumberOfPages;
00700
break;
00701 }
00702 }
00703
00704 InterlockedDecrement (&MiDelayPageFaults);
00705 }
00706
00707
if (RemovedPages != NumberOfPages) {
00708
#if DBG
00709
MiDynmemData[4] += 1;
00710
if (MiShowStuckPages != 0) {
00711
00712 RemovedPages = 0;
00713
for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) {
00714
if (Pfn1->
u3.e1.PageLocation !=
BadPageList) {
00715 RemovedPages += 1;
00716 }
00717 }
00718
00719
ASSERT (RemovedPages != 0);
00720
00721
DbgPrint(
"MmRemovePhysicalMemory : could not get %d of %d pages\n",
00722 RemovedPages, NumberOfPages);
00723
00724
if (MiShowStuckPages & 0x2) {
00725
00726 ULONG PfnsPrinted;
00727 ULONG EnoughShown;
00728
PMMPFN FirstPfn;
00729 PFN_COUNT PfnCount;
00730
00731 PfnCount = 0;
00732 PfnsPrinted = 0;
00733 EnoughShown = 100;
00734
00735
if (MiShowStuckPages & 0x4) {
00736 EnoughShown = (ULONG)-1;
00737 }
00738
00739
DbgPrint(
"Stuck PFN list: ");
00740
for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) {
00741
if (Pfn1->
u3.e1.PageLocation !=
BadPageList) {
00742
if (PfnCount == 0) {
00743 FirstPfn = Pfn1;
00744 }
00745 PfnCount += 1;
00746 }
00747
else {
00748
if (PfnCount != 0) {
00749
DbgPrint(
"%x -> %x ; ", FirstPfn - MmPfnDatabase,
00750 (FirstPfn - MmPfnDatabase) + PfnCount - 1);
00751 PfnsPrinted += 1;
00752
if (PfnsPrinted == EnoughShown) {
00753
break;
00754 }
00755 PfnCount = 0;
00756 }
00757 }
00758 }
00759
if (PfnCount != 0) {
00760
DbgPrint(
"%x -> %x ; ", FirstPfn - MmPfnDatabase,
00761 (FirstPfn - MmPfnDatabase) + PfnCount - 1);
00762 }
00763
DbgPrint(
"\n");
00764 }
00765
if (MiShowStuckPages & 0x8) {
00766 DbgBreakPoint ();
00767 }
00768
if (MiShowStuckPages & 0x10) {
00769
goto retry;
00770 }
00771 }
00772
#endif
00773
UNLOCK_PFN (OldIrql);
00774
Status = STATUS_NO_MEMORY;
00775
goto giveup;
00776 }
00777
00778
#if DBG
00779
for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) {
00780
ASSERT (Pfn1->
u3.e1.PageLocation == BadPageList);
00781 }
00782
#endif
00783
00784
00785
00786
00787
00788
00789
if (Additional == 0) {
00790
00791
00792
00793
00794
00795
00796 NewPhysicalMemoryBlock =
MmPhysicalMemoryBlock;
00797 OldPhysicalMemoryBlock =
NULL;
00798 }
00799
else {
00800
00801
00802
00803
00804
00805
00806
UNLOCK_PFN (OldIrql);
00807
00808 i = (
sizeof(
PHYSICAL_MEMORY_DESCRIPTOR) +
00809 (
sizeof(
PHYSICAL_MEMORY_RUN) * (
MmPhysicalMemoryBlock->
NumberOfRuns + Additional)));
00810
00811 NewPhysicalMemoryBlock =
ExAllocatePoolWithTag (NonPagedPool,
00812 i,
00813 ' mM');
00814
00815
if (NewPhysicalMemoryBlock ==
NULL) {
00816
Status = STATUS_INSUFFICIENT_RESOURCES;
00817
#if DBG
00818
MiDynmemData[5] += 1;
00819
#endif
00820
goto giveup;
00821 }
00822
00823 OldPhysicalMemoryBlock =
MmPhysicalMemoryBlock;
00824 RtlZeroMemory (NewPhysicalMemoryBlock, i);
00825
00826
LOCK_PFN (OldIrql);
00827 }
00828
00829
00830
00831
00832
00833 NewPhysicalMemoryBlock->
NumberOfRuns =
MmPhysicalMemoryBlock->
NumberOfRuns + Additional;
00834 NewPhysicalMemoryBlock->
NumberOfPages =
MmPhysicalMemoryBlock->
NumberOfPages - NumberOfPages;
00835
00836 NewRun = &NewPhysicalMemoryBlock->
Run[0];
00837 start = 0;
00838 Inserted =
FALSE;
00839
00840
do {
00841
00842 Page =
MmPhysicalMemoryBlock->
Run[start].
BasePage;
00843 LastPage = Page +
MmPhysicalMemoryBlock->
Run[start].
PageCount;
00844
00845
if (Inserted ==
FALSE) {
00846
00847
if ((StartPage >= Page) && (EndPage <= LastPage)) {
00848
00849
if ((StartPage == Page) && (EndPage == LastPage)) {
00850
ASSERT (Additional == -1);
00851 start += 1;
00852
continue;
00853 }
00854
else if ((StartPage == Page) || (EndPage == LastPage)) {
00855
ASSERT (Additional == 0);
00856
if (StartPage == Page) {
00857
MmPhysicalMemoryBlock->
Run[start].
BasePage += NumberOfPages;
00858 }
00859
MmPhysicalMemoryBlock->
Run[start].
PageCount -= NumberOfPages;
00860 }
00861
else {
00862
ASSERT (Additional == 1);
00863
00864 OriginalLastPage = LastPage;
00865
00866
MmPhysicalMemoryBlock->
Run[start].
PageCount =
00867 StartPage -
MmPhysicalMemoryBlock->
Run[start].
BasePage;
00868
00869 *NewRun =
MmPhysicalMemoryBlock->
Run[start];
00870 NewRun += 1;
00871
00872 NewRun->
BasePage = EndPage;
00873 NewRun->
PageCount = OriginalLastPage - EndPage;
00874 NewRun += 1;
00875
00876 start += 1;
00877
continue;
00878 }
00879
00880 Inserted =
TRUE;
00881 }
00882 }
00883
00884 *NewRun =
MmPhysicalMemoryBlock->
Run[start];
00885 NewRun += 1;
00886 start += 1;
00887
00888 }
while (start !=
MmPhysicalMemoryBlock->
NumberOfRuns);
00889
00890
00891
00892
00893
00894
00895
MmPhysicalMemoryBlock = NewPhysicalMemoryBlock;
00896
00897
if (EndPage - 1 ==
MmHighestPhysicalPage) {
00898
MmHighestPhysicalPage = StartPage - 1;
00899 }
00900
00901
00902
00903
00904
00905
for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) {
00906
00907
ASSERT (Pfn1->
u3.e1.PageLocation == BadPageList);
00908
ASSERT (Pfn1->
u3.e1.RemovalRequested == 1);
00909
00910
MiUnlinkPageFromList (Pfn1);
00911
00912
ASSERT (Pfn1->
u1.Flink == 0);
00913
ASSERT (Pfn1->
u2.Blink == 0);
00914
ASSERT (Pfn1->
u3.e2.ReferenceCount == 0);
00915
ASSERT64 (Pfn1->UsedPageTableEntries == 0);
00916
00917 Pfn1->
PteAddress =
PFN_REMOVED;
00918 Pfn1->
u3.e2.ShortFlags = 0;
00919 Pfn1->
OriginalPte.
u.Long =
ZeroKernelPte.
u.Long;
00920 Pfn1->
PteFrame = 0;
00921 }
00922
00923
00924
00925
00926
00927
00928
00929
00930 PagesReleased = 0;
00931
00932
if (PfnDatabaseIsPhysical ==
FALSE) {
00933
00934 VirtualAddress = (PVOID)
ROUND_TO_PAGES(
MI_PFN_ELEMENT(StartPage));
00935 PointerPte =
MiGetPteAddress (VirtualAddress);
00936 EndPte =
MiGetPteAddress (
PAGE_ALIGN(
MI_PFN_ELEMENT(EndPage)));
00937
00938
while (PointerPte < EndPte) {
00939 PageFrameIndex =
MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);
00940 Pfn1 =
MI_PFN_ELEMENT (PageFrameIndex);
00941
ASSERT (Pfn1->
u2.ShareCount == 1);
00942
ASSERT (Pfn1->
u3.e2.ReferenceCount == 1);
00943 Pfn1->
u2.ShareCount = 0;
00944
MI_SET_PFN_DELETED (Pfn1);
00945
#if DBG
00946
Pfn1->
u3.e1.PageLocation =
StandbyPageList;
00947
#endif //DBG
00948
MiDecrementReferenceCount (PageFrameIndex);
00949
00950
KeFlushSingleTb (VirtualAddress,
00951 TRUE,
00952 TRUE,
00953 (PHARDWARE_PTE)PointerPte,
00954
ZeroKernelPte.
u.Flush);
00955
00956 PagesReleased += 1;
00957 PointerPte += 1;
00958 VirtualAddress = (PVOID)((PCHAR)VirtualAddress +
PAGE_SIZE);
00959 }
00960
00961
MmResidentAvailablePages += PagesReleased;
00962 }
00963
00964
#if DBG
00965
MiDynmemData[6] += 1;
00966
#endif
00967
00968
UNLOCK_PFN (OldIrql);
00969
00970
if (PagesReleased != 0) {
00971
MiReturnCommitment (PagesReleased);
00972 }
00973
00974 ExReleaseFastMutex (&MmDynamicMemoryMutex);
00975
00976
if (OldPhysicalMemoryBlock !=
NULL) {
00977
ExFreePool (OldPhysicalMemoryBlock);
00978 }
00979
00980 NumberOfBytes->QuadPart = (ULONGLONG)NumberOfPages *
PAGE_SIZE;
00981
00982
return STATUS_SUCCESS;
00983
00984 giveup:
00985
00986
00987
00988
00989
00990 PageFrameIndex = StartPage;
00991 Pfn1 =
MI_PFN_ELEMENT (PageFrameIndex);
00992
00993
LOCK_PFN (OldIrql);
00994
00995
while (PageFrameIndex < EndPage) {
00996
00997
ASSERT (Pfn1->
u3.e1.RemovalRequested == 1);
00998
00999 Pfn1->
u3.e1.RemovalRequested = 0;
01000
01001
if ((Pfn1->
u3.e1.PageLocation ==
BadPageList) &&
01002 (Pfn1->
u3.e1.ParityError == 0)) {
01003
01004
MiUnlinkPageFromList (Pfn1);
01005
MiInsertPageInList (MmPageLocationList[FreePageList],
01006 PageFrameIndex);
01007 }
01008
01009 Pfn1 += 1;
01010 PageFrameIndex += 1;
01011 }
01012
01013
MmResidentAvailablePages += NumberOfPages;
01014
MmNumberOfPhysicalPages += NumberOfPages;
01015
01016
UNLOCK_PFN (OldIrql);
01017
01018 giveup2:
01019
01020 ExAcquireSpinLock (&MmChargeCommitmentLock, &OldIrql);
01021
MmTotalCommitLimit += NumberOfPages;
01022
MmTotalCommitLimitMaximum += NumberOfPages;
01023 ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql);
01024
01025 ExReleaseFastMutex (&MmDynamicMemoryMutex);
01026
01027
return Status;
01028 }