test: vlm.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# vlm.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1996  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007    VLM.C
    00008
    00009 Abstract:
    00010
    00011     This module contains the routines which implement the 64-bit Very Large
    00012     Memory support.
    00013
    00014 Author:
    00015
    00016     Lou Perazzoli (loup) 3-Sep-1996
    00017
    00018 Revision History:
    00019
    00020 --*/
    00021
    00022 #include "mi.h"
    00023
    00024 extern ULONG MMVADKEY;
    00025
    00026 #ifdef VLM_SUPPORT
    00027
    00028 #define ROUND_TO_PAGES64(Size)  ((ULONGLONG)(Size) + (PAGE_SIZE - 1) & ~((LONGLONG)PAGE_SIZE - 1))
    00029
    00030 #define MM_VALID_PTE_SIZE (256)
    00031
    00032 #define MM_LARGEST_VLM_RANGE \
    00033    ((ULONGLONG)MM_HIGHEST_USER_ADDRESS64 - (ULONGLONG)MM_LOWEST_USER_ADDRESS64)
    00034
    00035 #define DELETE_TYPE_PRIVATE 0
    00036 #define DELETE_TYPE_SHARED 1
    00037
    00038 MMPTE
    00039 MiCaptureSystemPte (
    00040     IN PMMPTE PointerProtoPte,
    00041     IN PEPROCESS Process
    00042     );
    00043
    00044 LOGICAL
    00045 MiCommitPages64 (
    00046     IN PMMPTE StartPte,
    00047     IN PMMPTE LastPte,
    00048     IN ULONG ProtectionMask,
    00049     IN PEPROCESS Process,
    00050     OUT PSIZE_T ValidPtes
    00051     );
    00052
    00053 ULONG
    00054 MiDecommitOrDeletePages64 (
    00055     IN PMMPTE StartingPte,
    00056     IN PMMPTE EndingPte,
    00057     IN PEPROCESS Process,
    00058     IN ULONG Type,
    00059     IN LOGICAL FlushTb
    00060     );
    00061
    00062 VOID
    00063 MiFlushPteList64 (
    00064     IN PMMPTE_FLUSH_LIST64 PteFlushList,
    00065     IN ULONG AllProcessors,
    00066     IN MMPTE FillPte
    00067     );
    00068
    00069 VOID
    00070 MiReturnAvailablePages (
    00071     IN PFN_NUMBER Amount
    00072     );
    00073
    00074 LOGICAL
    00075 MiCheckPdeForDeletion (
    00076     IN PMMPTE PointerPde,
    00077     IN LOGICAL FlushTb
    00078     );
    00079
    00080 VOID
    00081 MiProcessValidPteList64 (
    00082     IN PMMPTE *ValidPteList,
    00083     IN ULONG Count,
    00084     IN LOGICAL FlushTb
    00085     );
    00086
    00087 ULONG
    00088 MiDoesPdeExist64 (
    00089     IN PMMPTE PointerPde
    00090     );
    00091
    00092 LOGICAL
    00093 MiMakePdeExistAndMakeValid64 (
    00094     IN PMMPTE PointerPde,
    00095     IN PEPROCESS TargetProcess,
    00096     IN LOGICAL PfnLockHeld,
    00097     IN LOGICAL MakePageTablePage
    00098     );
    00099
    00100 HARDWARE_PTE
    00101 MiFlushTbAndCapture(
    00102     IN PMMPTE PtePointer,
    00103     IN HARDWARE_PTE TempPte,
    00104     IN PMMPFN Pfn1
    00105     );
    00106
    00107 NTSTATUS
    00108 MiMapViewOfVlmDataSection (
    00109     IN PCONTROL_AREA ControlArea,
    00110     IN PEPROCESS Process,
    00111     IN PVOID64 *CapturedBase,
    00112     IN PULONGLONG SectionOffset,
    00113     IN PULONGLONG CapturedViewSize,
    00114     IN PSECTION Section,
    00115     IN ULONG ProtectionMask,
    00116     IN ULONG AllocationType,
    00117     IN PULONG ReleasedWsMutex
    00118     );
    00119
    00120 ULONG
    00121 MiIsEntireRangeCommitted64 (
    00122     IN PVOID64 StartingAddress,
    00123     IN PVOID64 EndingAddress,
    00124     IN PMMVAD Vad,
    00125     IN PEPROCESS Process
    00126     );
    00127
    00128 VOID
    00129 MiMakeValidPageNoAccess64 (
    00130     IN PMMPTE PointePte
    00131     );
    00132
    00133 VOID
    00134 MiMakeNoAccessPageValid64 (
    00135     IN PMMPTE PointerPte,
    00136     IN ULONG Protect
    00137     );
    00138
    00139 ULONG
    00140 MiSetProtectionOnTransitionPte (
    00141     IN PMMPTE PointerPte,
    00142     IN ULONG ProtectionMask
    00143     );
    00144
    00145 ULONG
    00146 MiQueryAddressState64 (
    00147     IN PVOID64 Va,
    00148     IN PMMVAD Vad,
    00149     IN PEPROCESS TargetProcess,
    00150     OUT PULONG ReturnedProtect
    00151     );
    00152
    00153 #define MI_NONPAGABLE_MEMORY_AVAILABLE(_SizeInPages) \
    00154     (MmResidentAvailablePages > ((SPFN_NUMBER)_SizeInPages + (SPFN_NUMBER)MmTotalFreeSystemPtes[NonPagedPoolExpansion] + ((SPFN_NUMBER)MiSpecialPagesNonPagedMaximum - (SPFN_NUMBER)MiSpecialPagesNonPaged) + (SPFN_NUMBER)MM_VLM_FLUID_PAGES))
    00155
    00156 #define MI_GET_USED_PDE64_HANDLE(PDE64) \
    00157         (&(((PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long))->UsedPageTableEntries[PDE64 - MiGetPdeAddress64 (MM_LOWEST_USER_ADDRESS64)]))
    00158
    00159 ULONG MmSharedCommitVlm;            // Protected by the PFN lock.
    00160
    00161 KSPIN_LOCK MiVlmStatisticsLock;     // Protects both fields below.
    00162
    00163 ULONG MiVlmCommitChargeInPages;
    00164 ULONG MiVlmCommitChargeInPagesPeak;
    00165
    00166
    00167 NTSTATUS
    00168 NtAllocateVirtualMemory64 (
    00169     IN HANDLE ProcessHandle,
    00170     IN OUT PVOID64 *BaseAddress,
    00171     IN ULONG ZeroBits,
    00172     IN OUT PULONGLONG RegionSize,
    00173     IN ULONG AllocationType,
    00174     IN ULONG Protect
    00175     )
    00176
    00177 /*++
    00178
    00179 Routine Description:
    00180
    00181     This function creates a region of pages within the virtual address
    00182     space of a subject process.
    00183
    00184 Arguments:
    00185
    00186     ProcessHandle - Supplies an open handle to a process object.
    00187
    00188     BaseAddress - Supplies a pointer to a variable that will receive
    00189          the base address of the allocated region of pages.
    00190          If the initial value of this argument is not null,
    00191          then the region will be allocated starting at the
    00192          specified virtual address rounded down to the next
    00193          host page size address boundary. If the initial
    00194          value of this argument is null, then the operating
    00195          system will determine where to allocate the
    00196          region.
    00197
    00198     ZeroBits - IGNORED
    00199
    00200     RegionSize - Supplies a pointer to a variable that will receive
    00201          the actual size in bytes of the allocated region
    00202          of pages. The initial value of this argument
    00203          specifies the size in bytes of the region and is
    00204          rounded up to the next host page size boundary.
    00205
    00206     AllocationType - Supplies a set of flags that describe the type
    00207          of allocation that is to be performed for the
    00208          specified region of pages. Flags are:
    00209
    00210
    00211          MEM_COMMIT - The specified region of pages is to
    00212               be committed.
    00213
    00214          MEM_RESERVE - The specified region of pages is to
    00215               be reserved.
    00216
    00217          MEM_TOP_DOWN - NOT ALLOWED.
    00218
    00219          MEM_RESET - IGNORED.
    00220
    00221     Protect - Supplies the protection desired for the committed
    00222          region of pages.
    00223
    00224         Protect Values:
    00225
    00226
    00227          PAGE_NOACCESS - No access to the committed region
    00228               of pages is allowed. An attempt to read,
    00229               write, or execute the committed region
    00230               results in an access violation (i.e. a GP
    00231               fault).
    00232
    00233          PAGE_EXECUTE - Not allowed
    00234
    00235          PAGE_READONLY - Read only and execute access to the
    00236               committed region of pages is allowed. An
    00237               attempt to write the committed region results
    00238               in an access violation.
    00239
    00240          PAGE_READWRITE - Read, write, and execute access to
    00241               the committed region of pages is allowed. If
    00242               write access to the underlying section is
    00243               allowed, then a single copy of the pages are
    00244               shared. Otherwise the pages are shared read
    00245               only/copy on write.
    00246
    00247          PAGE_NOCACHE - not allowed.
    00248
    00249 Return Value:
    00250
    00251     Returns the status
    00252
    00253     TBS
    00254
    00255
    00256 --*/
    00257
    00258 {
    00259     PMMVAD Vad;
    00260     PMMVAD FoundVad;
    00261     PEPROCESS Process;
    00262     KPROCESSOR_MODE PreviousMode;
    00263     PVOID64 StartingAddress;
    00264     PVOID64 EndingAddress;
    00265     NTSTATUS Status;
    00266     PVOID64 CapturedBase;
    00267     ULONGLONG CapturedRegionSize;
    00268     PMMPTE CommitLimitPte;
    00269     ULONG ProtectionMask;
    00270     PMMPTE LastPte;
    00271     PMMPTE PointerPde;
    00272     PMMPTE StartingPte;
    00273     PMMPTE PointerPte;
    00274     MMPTE TempPte;
    00275     ULONG OldProtect;
    00276     SSIZE_T QuotaCharge;
    00277     SIZE_T QuotaFree;
    00278     ULONG CopyOnWriteCharge;
    00279     BOOLEAN PageFileChargeSucceeded;
    00280     LOGICAL Attached;
    00281     KIRQL OldIrql;
    00282     ULONG_PTR NewPages;
    00283     LOGICAL ChargedExactQuota;
    00284     LOGICAL CommitSucceeded;
    00285     LOGICAL LargeVad;
    00286     LOGICAL GotResidentAvail;
    00287     PMI_PROCESS_VLM_INFO VlmInfo;
    00288     ULONG CommitCharge;
    00289
    00290     Attached = FALSE;
    00291
    00292     if (MI_VLM_ENABLED() == FALSE) {
    00293         return STATUS_NOT_IMPLEMENTED;
    00294     }
    00295
    00296     //
    00297     // Check the AllocationType for correctness.
    00298     //
    00299
    00300     if ((AllocationType & ~(MEM_COMMIT | MEM_RESERVE |
    00301                             MEM_RESET)) != 0) {
    00302         return STATUS_INVALID_PARAMETER_5;
    00303     }
    00304
    00305     //
    00306     // One of MEM_COMMIT, MEM_RESET or MEM_RESERVE must be set.
    00307     //
    00308
    00309     if ((AllocationType & (MEM_COMMIT | MEM_RESERVE | MEM_RESET)) == 0) {
    00310         return STATUS_INVALID_PARAMETER_5;
    00311     }
    00312
    00313     if ((AllocationType & MEM_RESET) && (AllocationType != MEM_RESET)) {
    00314
    00315         //
    00316         // MEM_RESET may not be used with any other flag.
    00317         //
    00318
    00319         return STATUS_INVALID_PARAMETER_5;
    00320     }
    00321
    00322     //
    00323     // Check the protection field.  This could raise an exception.
    00324     //
    00325
    00326     try {
    00327         ProtectionMask = MiMakeProtectionMask (Protect);
    00328     } except (EXCEPTION_EXECUTE_HANDLER) {
    00329         return GetExceptionCode();
    00330     }
    00331
    00332     if ((ProtectionMask == MM_NOACCESS) &&
    00333         (AllocationType & MEM_COMMIT)) {
    00334
    00335         return STATUS_INVALID_PAGE_PROTECTION;
    00336     }
    00337
    00338     PreviousMode = KeGetPreviousMode();
    00339
    00340     //
    00341     // Establish an exception handler, probe the specified addresses
    00342     // for write access and capture the initial values.
    00343     //
    00344
    00345     try {
    00346
    00347         if (PreviousMode != KernelMode) {
    00348
    00349             ProbeForWrite (BaseAddress, sizeof(PVOID64), sizeof(PVOID64));
    00350             ProbeForWrite (RegionSize, sizeof(ULONGLONG), sizeof(ULONGLONG));
    00351         }
    00352
    00353         //
    00354         // Capture the base address.
    00355         //
    00356
    00357         CapturedBase = *BaseAddress;
    00358
    00359         //
    00360         // Capture the region size.
    00361         //
    00362
    00363         CapturedRegionSize = *RegionSize;
    00364
    00365     } except (ExSystemExceptionFilter()) {
    00366
    00367         //
    00368         // If an exception occurs during the probe or capture
    00369         // of the initial values, then handle the exception and
    00370         // return the exception code as the status value.
    00371         //
    00372
    00373         return GetExceptionCode();
    00374     }
    00375
    00376 #if 0
    00377     if (MmDebug & MM_DBG_SHOW_NT_CALLS) {
    00378         if ( MmWatchProcess ) {
    00379             ;
    00380         } else {
    00381             DbgPrint("allocvm process handle %lx base address %p zero bits %lx\n",
    00382                 ProcessHandle, CapturedBase, ZeroBits);
    00383             DbgPrint("    region size %p alloc type %lx protect %lx\n",
    00384                 CapturedRegionSize, AllocationType, Protect);
    00385         }
    00386     }
    00387 #endif
    00388
    00389     //
    00390     // Make sure the specified starting and ending addresses are
    00391     // within the user part of the virtual address space.
    00392     //
    00393
    00394     if ((CapturedBase != NULL ) &&
    00395         ((CapturedBase > (PVOID64)MM_HIGHEST_USER_ADDRESS64) ||
    00396         (CapturedBase < (PVOID64)MM_LOWEST_USER_ADDRESS64))) {
    00397
    00398         //
    00399         // Invalid base address.
    00400         //
    00401
    00402         return STATUS_INVALID_PARAMETER_2;
    00403     }
    00404
    00405     if (CapturedBase != NULL) {
    00406
    00407         if ((ULONGLONG)CapturedBase + CapturedRegionSize < (ULONGLONG)CapturedBase) {
    00408
    00409             //
    00410             // the requested region wraps
    00411             //
    00412
    00413             return STATUS_INVALID_PARAMETER_4;
    00414         }
    00415
    00416
    00417         if ((ULONGLONG)CapturedBase + CapturedRegionSize > (ULONGLONG)MM_HIGHEST_USER_ADDRESS64 - X64K) {
    00418
    00419             //
    00420             // the requested region goes beyond the end of user memory - flag it
    00421             //
    00422
    00423             return STATUS_INVALID_PARAMETER_4;
    00424         }
    00425     }
    00426     else if (CapturedRegionSize > (ULONGLONG)MM_LARGEST_VLM_RANGE - X64K) {
    00427
    00428         //
    00429         // Invalid region size;
    00430         //
    00431
    00432         return STATUS_INVALID_PARAMETER_4;
    00433     }
    00434
    00435     if (CapturedRegionSize == 0) {
    00436
    00437         //
    00438         // Region size cannot be 0.
    00439         //
    00440
    00441         return STATUS_INVALID_PARAMETER_4;
    00442     }
    00443
    00444     //
    00445     // Reference the specified process handle for VM_OPERATION access.
    00446     //
    00447
    00448     if ( ProcessHandle == NtCurrentProcess() ) {
    00449         Process = PsGetCurrentProcess();
    00450     } else {
    00451         Status = ObReferenceObjectByHandle ( ProcessHandle,
    00452                                              PROCESS_VM_OPERATION,
    00453                                              PsProcessType,
    00454                                              PreviousMode,
    00455                                              (PVOID *)&Process,
    00456                                              NULL );
    00457
    00458         if (!NT_SUCCESS(Status)) {
    00459             return Status;
    00460         }
    00461     }
    00462
    00463     //
    00464     // If the specified process is not the current process, attach
    00465     // to the specified process.
    00466     //
    00467
    00468     if (PsGetCurrentProcess() != Process) {
    00469         KeAttachProcess (&Process->Pcb);
    00470         Attached = TRUE;
    00471     }
    00472
    00473     //
    00474     // Get the address creation mutex to block multiple threads from
    00475     // creating or deleting address space at the same time and
    00476     // get the working set mutex so virtual address descriptors can
    00477     // be inserted and walked.  Block APCs so an APC which takes a page
    00478     // fault does not corrupt various structures.
    00479     //
    00480
    00481     LOCK_WS_AND_ADDRESS_SPACE (Process);
    00482
    00483     //
    00484     // Make sure the address space was not deleted, if so, return an error.
    00485     //
    00486
    00487     if (Process->AddressSpaceDeleted != 0) {
    00488         Status = STATUS_PROCESS_IS_TERMINATING;
    00489         goto ErrorReturn;
    00490     }
    00491
    00492     //
    00493     // Don't allow POSIX apps to do VLM operations.
    00494     //
    00495
    00496     if ((Process->CloneRoot != NULL) &&
    00497          (Process->ForkWasSuccessful != MM_NO_FORK_ALLOWED)) {
    00498         Status = STATUS_INVALID_VLM_OPERATION;
    00499         goto ErrorReturn;
    00500     }
    00501     Process->ForkWasSuccessful = MM_NO_FORK_ALLOWED;
    00502
    00503     if ((CapturedBase == NULL) || (AllocationType & MEM_RESERVE)) {
    00504
    00505         //
    00506         // PAGE_WRITECOPY is not valid for private pages.
    00507         //
    00508
    00509         if ((Protect & PAGE_WRITECOPY) ||
    00510             (Protect & PAGE_EXECUTE_WRITECOPY)) {
    00511             Status = STATUS_INVALID_PAGE_PROTECTION;
    00512             goto ErrorReturn;
    00513         }
    00514
    00515         //
    00516         // Reserve the address space.
    00517         //
    00518
    00519         if (CapturedBase == NULL) {
    00520
    00521             //
    00522             // No base address was specified.  This MUST be a reserve or
    00523             // reserve and commit.
    00524             //
    00525
    00526             CapturedRegionSize = ROUND_TO_PAGES64 (CapturedRegionSize);
    00527
    00528             //
    00529             // Establish exception handler as MiFindEmptyAddressRange
    00530             // will raise an exception if it fails.
    00531             //
    00532
    00533             try {
    00534
    00535
    00536                 StartingAddress = MiFindEmptyAddressRangeInTree64 (
    00537                                    CapturedRegionSize,
    00538                                    X64K,
    00539                                    (PMMADDRESS_NODE)(Process->CloneRoot));
    00540
    00541             } except (EXCEPTION_EXECUTE_HANDLER) {
    00542                 Status = GetExceptionCode();
    00543                 goto ErrorReturn;
    00544             }
    00545
    00546             //
    00547             // Calculate the ending address based on the top address.
    00548             //
    00549
    00550             EndingAddress = (PVOID64)(((ULONGLONG)StartingAddress +
    00551                                   CapturedRegionSize - 1L) | (PAGE_SIZE - 1L));
    00552
    00553         } else {
    00554
    00555             //
    00556             // A non-NULL base address was specified. Check to make sure
    00557             // the specified base address to ending address is currently
    00558             // unused.
    00559             //
    00560
    00561             EndingAddress = (PVOID64)(((ULONGLONG)CapturedBase +
    00562                                   CapturedRegionSize - 1L) | (PAGE_SIZE - 1L));
    00563
    00564             //
    00565             // Align the starting address on a 64k boundary.
    00566             //
    00567
    00568             StartingAddress = MI_64K_ALIGN64(CapturedBase);
    00569
    00570             //
    00571             // See if a VAD overlaps with this starting/ending address pair.
    00572             //
    00573
    00574             if (MiCheckForConflictingVad64 (StartingAddress, EndingAddress) !=
    00575                     (PMMVAD)NULL) {
    00576
    00577                 Status = STATUS_CONFLICTING_ADDRESSES;
    00578                 goto ErrorReturn;
    00579             }
    00580         }
    00581
    00582         if (AllocationType & MEM_COMMIT) {
    00583             StartingPte = MiGetPteAddress64 (StartingAddress);
    00584             ASSERT (MiGetPdeAddress64(StartingAddress) == MiGetPteAddress (StartingPte));
    00585             LastPte = MiGetPteAddress64 (EndingAddress);
    00586             QuotaCharge = 1 + LastPte - StartingPte;
    00587         }
    00588         else {
    00589             QuotaCharge = 0;
    00590         }
    00591
    00592         //
    00593         // An unoccupied address range has been found, build the virtual
    00594         // address descriptor to describe this range.
    00595         //
    00596
    00597         //
    00598         // Establish an exception handler and attempt to allocate
    00599         // the pool and charge quota.  Note that the InsertVad routine
    00600         // will also charge quota which could raise an exception.
    00601         //
    00602
    00603         try  {
    00604
    00605             if ((AllocationType & MEM_COMMIT) && (QuotaCharge + QuotaCharge / PTE_PER_PAGE + 2 >= MM_MAX_COMMIT)) {
    00606                 LargeVad = TRUE;
    00607                 Vad = (PMMVAD)ExAllocatePoolWithTag (NonPagedPool,
    00608                                                      sizeof(MMVAD),
    00609                                                      MMVADKEY);
    00610             }
    00611             else {
    00612                 LargeVad = FALSE;
    00613                 Vad = (PMMVAD)ExAllocatePoolWithTag (NonPagedPool,
    00614                                                      sizeof(MMVAD_SHORT),
    00615                                                      'SdaV');
    00616             }
    00617
    00618             //
    00619             // Faults are not allowed here since we are already holding the WS
    00620             // lock.  This means we must check pool allocations explicitly.
    00621             //
    00622
    00623             if (Vad == (PMMVAD)0) {
    00624                 ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
    00625             }
    00626
    00627             Vad->StartingVpn = MI_VA_TO_VPN64 (StartingAddress);
    00628             Vad->EndingVpn = MI_VA_TO_VPN64 (EndingAddress);
    00629
    00630             Vad->u.LongFlags = 0;
    00631             if (AllocationType & MEM_COMMIT) {
    00632                 Vad->u.VadFlags.MemCommit = 1;
    00633
    00634                 if (LargeVad == TRUE) {
    00635                     Vad->u.VadFlags.ImageMap = 1;       // Signify large commit
    00636                     Vad->u.VadFlags.CommitCharge = 0;
    00637                     Vad->u3.List.Flink = (PLIST_ENTRY)QuotaCharge;
    00638                 }
    00639                 else {
    00640                     Vad->u.VadFlags.CommitCharge = QuotaCharge;
    00641                 }
    00642             }
    00643
    00644             Vad->u.VadFlags.Protection = ProtectionMask;
    00645             Vad->u.VadFlags.PrivateMemory = 1;
    00646
    00647             MiInsertVad64 ((PVOID)Vad);
    00648
    00649         } except (EXCEPTION_EXECUTE_HANDLER) {
    00650
    00651             if (Vad != (PMMVAD)NULL) {
    00652
    00653                 //
    00654                 // The pool allocation succeeded, but the quota charge
    00655                 // in InsertVad failed, deallocate the pool and return
    00656                 // an error.
    00657                 //
    00658
    00659                 ExFreePool (Vad);
    00660                 Status = GetExceptionCode();
    00661             } else {
    00662                 Status = STATUS_INSUFFICIENT_RESOURCES;
    00663             }
    00664
    00665             goto ErrorReturn;
    00666         }
    00667
    00668         if (AllocationType & MEM_COMMIT) {
    00669
    00670             //
    00671             // Check to ensure these pages can be committed.
    00672             // Charge quota and commitment for the range.  Establish an
    00673             // exception handler as this could raise an exception.
    00674             //
    00675
    00676             QuotaFree = 1;
    00677             Status = STATUS_SUCCESS;
    00678
    00679             LOCK_PFN (OldIrql);
    00680
    00681             if (MI_NONPAGABLE_MEMORY_AVAILABLE (QuotaCharge)) {
    00682                 MmResidentAvailablePages -= (PFN_NUMBER)QuotaCharge;
    00683                 MM_BUMP_COUNTER(22, QuotaCharge);
    00684                 QuotaFree = 0;
    00685             }
    00686             UNLOCK_PFN (OldIrql);
    00687             if (QuotaFree == 1) {
    00688                 MiRemoveVad64 ((PMMVAD)Vad);
    00689                 ExFreePool (Vad);
    00690                 Status = STATUS_COMMITMENT_LIMIT;
    00691                 goto ErrorReturn;
    00692             }
    00693
    00694             CommitSucceeded = MiCommitPages64 (StartingPte,
    00695                                                LastPte,
    00696                                                ProtectionMask,
    00697                                                Process,
    00698                                                &QuotaFree);
    00699
    00700             if (CommitSucceeded == FALSE) {
    00701
    00702                 //
    00703                 // Nothing has been committed so just adjust counts and bail.
    00704                 //
    00705
    00706                 LOCK_PFN (OldIrql);
    00707                 MmResidentAvailablePages += (PFN_NUMBER) QuotaCharge;
    00708                 MM_BUMP_COUNTER(22, -QuotaCharge);
    00709                 UNLOCK_PFN (OldIrql);
    00710                 MiRemoveVad64 ((PMMVAD)Vad);
    00711                 ExFreePool (Vad);
    00712                 Status = STATUS_INSUFFICIENT_RESOURCES;
    00713                 goto ErrorReturn;
    00714             }
    00715
    00716             if (QuotaFree != 0) {
    00717                 LOCK_PFN (OldIrql);
    00718                 MmResidentAvailablePages += (PFN_NUMBER) QuotaFree;
    00719                 MM_BUMP_COUNTER(23, QuotaFree);
    00720                 UNLOCK_PFN (OldIrql);
    00721             }
    00722
    00723             VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long);
    00724             VlmInfo->CommitCharge += (QuotaCharge - QuotaFree);
    00725             if (VlmInfo->CommitCharge > VlmInfo->CommitChargePeak) {
    00726                 VlmInfo->CommitChargePeak = VlmInfo->CommitCharge;
    00727             }
    00728         }
    00729         else {
    00730
    00731             //
    00732             // The top level PDE map page is allocated here (it it is not
    00733             // already) even though this is only a reserve.  Because data like
    00734             // the virtual size is saved in a pool allocation whose pointer is
    00735             // in the top level PDE map page.
    00736             //
    00737
    00738             CommitSucceeded = MiMakePdeExistAndMakeValid64 (
    00739                                         MiGetPdeAddress64 (StartingAddress),
    00740                                         Process,
    00741                                         FALSE,
    00742                                         FALSE);
    00743
    00744             if (CommitSucceeded == FALSE) {
    00745                 MiRemoveVad64 ((PMMVAD)Vad);
    00746                 ExFreePool (Vad);
    00747                 Status = STATUS_INSUFFICIENT_RESOURCES;
    00748                 goto ErrorReturn;
    00749             }
    00750             QuotaCharge = 0;
    00751         }
    00752
    00753         //
    00754         // Unlock the working set lock, page faults can now be taken.
    00755         //
    00756
    00757         UNLOCK_WS (Process);
    00758
    00759         //
    00760         // Update the current virtual size in the process header, the
    00761         // address space lock protects this operation.
    00762         //
    00763
    00764         CapturedRegionSize = (ULONGLONG)EndingAddress - (ULONGLONG)StartingAddress + 1;
    00765
    00766         VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long);
    00767         VlmInfo->VirtualSize += CapturedRegionSize;
    00768         if (VlmInfo->VirtualSize > VlmInfo->VirtualSizePeak) {
    00769             VlmInfo->VirtualSizePeak = VlmInfo->VirtualSize;
    00770         }
    00771
    00772         ExAcquireFastLock (&MiVlmStatisticsLock, &OldIrql);
    00773
    00774         if (AllocationType & MEM_COMMIT) {
    00775             MiVlmCommitChargeInPages += (QuotaCharge - QuotaFree);
    00776             if (MiVlmCommitChargeInPages > MiVlmCommitChargeInPagesPeak) {
    00777                 MiVlmCommitChargeInPagesPeak = MiVlmCommitChargeInPages;
    00778             }
    00779         }
    00780
    00781         ExReleaseFastLock (&MiVlmStatisticsLock, OldIrql);
    00782
    00783         //
    00784         // Release the address space lock, lower IRQL, detach, and dereference
    00785         // the process object.
    00786         //
    00787
    00788         UNLOCK_ADDRESS_SPACE(Process);
    00789         if (Attached) {
    00790             KeDetachProcess();
    00791         }
    00792
    00793         if ( ProcessHandle != NtCurrentProcess() ) {
    00794             ObDereferenceObject (Process);
    00795         }
    00796
    00797         //
    00798         // Establish an exception handler and write the size and base
    00799         // address.
    00800         //
    00801         try {
    00802
    00803             *RegionSize = CapturedRegionSize;
    00804             *BaseAddress = StartingAddress;
    00805
    00806         } except (EXCEPTION_EXECUTE_HANDLER) {
    00807
    00808             //
    00809             // Return success at this point even if the results
    00810             // cannot be written.
    00811             //
    00812
    00813             NOTHING;
    00814         }
    00815
    00816 #if 0
    00817         if (MmDebug & MM_DBG_SHOW_NT_CALLS) {
    00818             if ( MmWatchProcess ) {
    00819                 if ( MmWatchProcess == PsGetCurrentProcess() ) {
    00820                     DbgPrint("\n+++ ALLOC Type %lx Base %p Size %p\n",
    00821                         AllocationType,StartingAddress, CapturedRegionSize);
    00822                     MmFooBar();
    00823                 }
    00824             } else {
    00825                 DbgPrint("return allocvm status %lx baseaddr %p size %p\n",
    00826                     Status, StartingAddress, CapturedRegionSize);
    00827             }
    00828         }
    00829 #endif
    00830
    00831         return STATUS_SUCCESS;
    00832
    00833     } else {
    00834
    00835         //
    00836         // Commit previously reserved pages.  Note that these pages could
    00837         // be either private or a section.
    00838         //
    00839
    00840         if (AllocationType == MEM_RESET) {
    00841
    00842             //
    00843             // Don't do anything for the mem reset case as the pages are
    00844             // all valid.
    00845             //
    00846
    00847             Status = STATUS_SUCCESS;
    00848             goto ErrorReturn;
    00849
    00850         } else {
    00851             EndingAddress = (PVOID64)(((ULONGLONG)CapturedBase +
    00852                                     CapturedRegionSize - 1) | (PAGE_SIZE - 1));
    00853             StartingAddress = (PVOID64)PAGE_ALIGN64(CapturedBase);
    00854         }
    00855
    00856         CapturedRegionSize = (ULONGLONG)EndingAddress - (ULONGLONG)StartingAddress + 1;
    00857
    00858         FoundVad = MiCheckForConflictingVad64 (StartingAddress, EndingAddress);
    00859
    00860         if (FoundVad == (PMMVAD)NULL) {
    00861
    00862             //
    00863             // No virtual address is reserved at the specified base address,
    00864             // return an error.
    00865             //
    00866
    00867             Status = STATUS_CONFLICTING_ADDRESSES;
    00868             goto ErrorReturn;
    00869         }
    00870
    00871         //
    00872         // Ensure that the starting and ending addresses are all within
    00873         // the same virtual address descriptor.
    00874         //
    00875
    00876         if ((MI_VA_TO_VPN64 (StartingAddress) < FoundVad->StartingVpn) ||
    00877             (MI_VA_TO_VPN64 (EndingAddress) > FoundVad->EndingVpn)) {
    00878
    00879             //
    00880             // Not within the section virtual address descriptor,
    00881             // return an error.
    00882             //
    00883
    00884             Status = STATUS_CONFLICTING_ADDRESSES;
    00885             goto ErrorReturn;
    00886         }
    00887
    00888
    00889         if (FoundVad->u.VadFlags.PrivateMemory == 1) {
    00890
    00891             //
    00892             // PAGE_WRITECOPY is not valid for private pages.
    00893             //
    00894
    00895             if ((Protect & PAGE_WRITECOPY) ||
    00896                 (Protect & PAGE_EXECUTE_WRITECOPY)) {
    00897                 Status = STATUS_INVALID_PAGE_PROTECTION;
    00898                 goto ErrorReturn;
    00899             }
    00900
    00901             //
    00902             // Ensure none of the pages are already committed as described
    00903             // in the virtual address descriptor.
    00904             //
    00905 #if 0
    00906             if (AllocationType & MEM_CHECK_COMMIT_STATE) {
    00907                 if ( !MiIsEntireRangeDecommitted(StartingAddress,
    00908                                                  EndingAddress,
    00909                                                  FoundVad,
    00910                                                  Process)) {
    00911
    00912                     //
    00913                     // Previously reserved pages have been committed, or
    00914                     // an error occurred, release mutex and return status.
    00915                     //
    00916
    00917                     Status = STATUS_ALREADY_COMMITTED;
    00918                     goto ErrorReturn;
    00919                 }
    00920             }
    00921 #endif //0
    00922
    00923             //
    00924             // The address range has not been committed, commit it now.
    00925             // Note, that for private pages, commitment is handled by
    00926             // explicitly updating PTEs to contain Demand Zero entries.
    00927             //
    00928
    00929             StartingPte = MiGetPteAddress64 (StartingAddress);
    00930             ASSERT (MiGetPdeAddress64(StartingAddress) == MiGetPteAddress (StartingPte));
    00931             LastPte = MiGetPteAddress64 (EndingAddress);
    00932
    00933             //
    00934             // Check to ensure these pages can be committed.
    00935             //
    00936
    00937             QuotaCharge = 1 + LastPte - StartingPte;
    00938
    00939             //
    00940             // Charge quota and commitment for the range.  Establish an
    00941             // exception handler as this could raise an exception.
    00942             //
    00943
    00944             QuotaFree = 1;
    00945             Status = STATUS_SUCCESS;
    00946
    00947             LOCK_PFN (OldIrql);
    00948             if (MI_NONPAGABLE_MEMORY_AVAILABLE (QuotaCharge)) {
    00949                 MmResidentAvailablePages -= (PFN_NUMBER) QuotaCharge;
    00950                 MM_BUMP_COUNTER(24, QuotaCharge);
    00951                 QuotaFree = 0;
    00952             }
    00953             UNLOCK_PFN (OldIrql);
    00954             if (QuotaFree == 1) {
    00955                 Status = STATUS_COMMITMENT_LIMIT;
    00956                 goto ErrorReturn;
    00957             }
    00958
    00959             if (Process->CommitChargeLimit) {
    00960                 if (Process->CommitCharge + QuotaCharge > Process->CommitChargeLimit) {
    00961                     Status = STATUS_COMMITMENT_LIMIT;
    00962                     LOCK_PFN (OldIrql);
    00963                     MmResidentAvailablePages += (PFN_NUMBER) QuotaCharge;
    00964                     MM_BUMP_COUNTER(24, -QuotaCharge);
    00965                     UNLOCK_PFN (OldIrql);
    00966                     if (Process->Job) {
    00967                         PsReportProcessMemoryLimitViolation ();
    00968                     }
    00969                     goto ErrorReturn;
    00970                 }
    00971             }
    00972             if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) {
    00973                 if (PsChangeJobMemoryUsage(QuotaCharge) == FALSE) {
    00974                     Status = STATUS_COMMITMENT_LIMIT;
    00975                     LOCK_PFN (OldIrql);
    00976                     MmResidentAvailablePages += (PFN_NUMBER) QuotaCharge;
    00977                     MM_BUMP_COUNTER(24, -QuotaCharge);
    00978                     UNLOCK_PFN (OldIrql);
    00979                     goto ErrorReturn;
    00980                 }
    00981             }
    00982
    00983             try {
    00984                 MiChargeCommitment (QuotaCharge, Process);
    00985             } except (EXCEPTION_EXECUTE_HANDLER) {
    00986
    00987                 Status = GetExceptionCode();
    00988                 LOCK_PFN (OldIrql);
    00989                 MmResidentAvailablePages += (PFN_NUMBER) QuotaCharge;
    00990                 MM_BUMP_COUNTER(24, -QuotaCharge);
    00991                 UNLOCK_PFN (OldIrql);
    00992                 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) {
    00993
    00994                     //
    00995                     // Temporarily up the process commit charge as the
    00996                     // job code will be referencing it as though everything
    00997                     // has succeeded.
    00998                     //
    00999
    01000                     Process->CommitCharge += QuotaCharge;
    01001                     PsChangeJobMemoryUsage (-(SSIZE_T)QuotaCharge);
    01002                     Process->CommitCharge -= QuotaCharge;
    01003                 }
    01004                 goto ErrorReturn;
    01005             }
    01006
    01007             MM_TRACK_COMMIT (MM_DBG_COMMIT_ALLOCVM1_VLM, QuotaCharge);
    01008
    01009             CommitSucceeded = MiCommitPages64 (StartingPte,
    01010                                                LastPte,
    01011                                                ProtectionMask,
    01012                                                Process,
    01013                                                &QuotaFree);
    01014
    01015             if (CommitSucceeded == FALSE) {
    01016                 Status = STATUS_INSUFFICIENT_RESOURCES;
    01017                 LOCK_PFN (OldIrql);
    01018                 MmResidentAvailablePages += (PFN_NUMBER) QuotaCharge;
    01019                 MM_BUMP_COUNTER(24, -QuotaCharge);
    01020                 UNLOCK_PFN (OldIrql);
    01021                 MiReturnCommitment (QuotaCharge);
    01022                 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) {
    01023
    01024                     //
    01025                     // Temporarily up the process commit charge as the
    01026                     // job code will be referencing it as though everything
    01027                     // has succeeded.
    01028                     //
    01029
    01030                     Process->CommitCharge += QuotaCharge;
    01031                     PsChangeJobMemoryUsage (-(SSIZE_T)QuotaCharge);
    01032                     Process->CommitCharge -= QuotaCharge;
    01033                 }
    01034                 goto ErrorReturn;
    01035             }
    01036
    01037             NewPages = QuotaCharge - QuotaFree;
    01038
    01039             //
    01040             // Excess charging of commit is returned below.
    01041             //
    01042
    01043             if (FoundVad->u.VadFlags.ImageMap == 1) {
    01044                 ASSERT (FoundVad->u.VadFlags.CommitCharge == 0);
    01045                 CommitCharge = (ULONG)FoundVad->u3.List.Flink;
    01046             }
    01047             else {
    01048                 CommitCharge = FoundVad->u.VadFlags.CommitCharge;
    01049             }
    01050
    01051             ASSERT (CommitCharge + NewPages >= CommitCharge);
    01052             CommitCharge += NewPages;
    01053
    01054             if (QuotaFree) {
    01055                 MiReturnCommitment (QuotaFree);
    01056                 MM_TRACK_COMMIT (MM_DBG_COMMIT_ALLOCVM1_VLM, -QuotaFree);
    01057                 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) {
    01058
    01059                     //
    01060                     // Temporarily up the process commit charge as the
    01061                     // job code will be referencing it as though everything
    01062                     // has succeeded.
    01063                     //
    01064
    01065                     Process->CommitCharge += QuotaFree;
    01066                     PsChangeJobMemoryUsage (-(SSIZE_T)QuotaFree);
    01067                     Process->CommitCharge -= QuotaFree;
    01068                 }
    01069             }
    01070
    01071             if (FoundVad->u.VadFlags.ImageMap == 1) {
    01072                 ASSERT (FoundVad->u.VadFlags.CommitCharge == 0);
    01073                 FoundVad->u3.List.Flink = (PLIST_ENTRY)CommitCharge;
    01074             }
    01075             else {
    01076                 FoundVad->u.VadFlags.CommitCharge = CommitCharge;
    01077             }
    01078
    01079             Process->CommitCharge += NewPages;
    01080             if (Process->CommitCharge > Process->CommitChargePeak) {
    01081                 Process->CommitChargePeak = Process->CommitCharge;
    01082             }
    01083
    01084             VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long);
    01085             VlmInfo->CommitCharge += NewPages;
    01086             if (VlmInfo->CommitCharge > VlmInfo->CommitChargePeak) {
    01087                 VlmInfo->CommitChargePeak = VlmInfo->CommitCharge;
    01088             }
    01089
    01090             ExAcquireFastLock (&MiVlmStatisticsLock, &OldIrql);
    01091
    01092             MiVlmCommitChargeInPages += NewPages;
    01093             if (MiVlmCommitChargeInPages > MiVlmCommitChargeInPagesPeak) {
    01094                 MiVlmCommitChargeInPagesPeak = MiVlmCommitChargeInPages;
    01095             }
    01096
    01097             ExReleaseFastLock (&MiVlmStatisticsLock, OldIrql);
    01098
    01099         } else {
    01100
    01101             //
    01102             // The no cache option is not allowed for sections.
    01103             //
    01104
    01105             if (Protect & PAGE_NOCACHE) {
    01106                 Status = STATUS_INVALID_PAGE_PROTECTION;
    01107                 goto ErrorReturn;
    01108             }
    01109
    01110             ASSERT (FoundVad->u.VadFlags.NoChange == 0);
    01111
    01112             ASSERT (FoundVad->ControlArea->FilePointer == NULL);
    01113
    01114             StartingPte = MiGetProtoPteAddress (FoundVad,
    01115                                     MI_VA_TO_VPN64 (StartingAddress));
    01116             PointerPte = StartingPte;
    01117             LastPte = MiGetProtoPteAddress (FoundVad,
    01118                                     MI_VA_TO_VPN64 (EndingAddress));
    01119
    01120             UNLOCK_WS (Process);
    01121
    01122             ExAcquireFastMutex (&MmSectionCommitMutex);
    01123
    01124             PointerPte = StartingPte;
    01125
    01126             //
    01127             // Check to ensure these pages can be committed if this
    01128             // is a page file backed segment.  Note that page file quota
    01129             // has already been charged for this.
    01130             //
    01131
    01132             QuotaCharge = 1 + LastPte - StartingPte;
    01133
    01134             //
    01135             // Charge commitment for the range.  Establish an
    01136             // exception handler as this could raise an exception.
    01137             //
    01138
    01139             QuotaFree = 0;
    01140
    01141             Status = STATUS_INVALID_VLM_OPERATION;
    01142             ChargedExactQuota = FALSE;
    01143
    01144             for (; ; ) {
    01145                 GotResidentAvail = FALSE;
    01146                 LOCK_PFN (OldIrql);
    01147                 if (MI_NONPAGABLE_MEMORY_AVAILABLE (QuotaCharge)) {
    01148                     MmResidentAvailablePages -= (PFN_NUMBER) QuotaCharge;
    01149                     MM_BUMP_COUNTER(36, QuotaCharge);
    01150                     Status = STATUS_SUCCESS;
    01151                     GotResidentAvail = TRUE;
    01152                 }
    01153                 UNLOCK_PFN (OldIrql);
    01154
    01155                 if (Status == STATUS_SUCCESS) {
    01156
    01157                     try {
    01158                         MiChargeCommitment (QuotaCharge, NULL);
    01159                     } except (EXCEPTION_EXECUTE_HANDLER) {
    01160                         Status = GetExceptionCode();
    01161                     }
    01162                     if (Status == STATUS_SUCCESS) {
    01163                         LOCK_PFN (OldIrql);
    01164                         MmSharedCommitVlm += QuotaCharge;
    01165                         UNLOCK_PFN (OldIrql);
    01166                         break;
    01167                     }
    01168                 }
    01169
    01170                 //
    01171                 // Not enough resident pages or commmit for the commitment,
    01172                 // If we've already backed out the previously committed
    01173                 // pages from the charge, just return an error.
    01174                 //
    01175
    01176                 if (GotResidentAvail == TRUE) {
    01177                     LOCK_PFN (OldIrql);
    01178                     MmResidentAvailablePages += (PFN_NUMBER) QuotaCharge;
    01179                     MM_BUMP_COUNTER(36, -QuotaCharge);
    01180                     UNLOCK_PFN (OldIrql);
    01181                 }
    01182
    01183                 if (Status != STATUS_INVALID_VLM_OPERATION) {
    01184
    01185                     //
    01186                     // We have already tried for the precise charge,
    01187                     // return an error.
    01188                     //
    01189
    01190                     ExReleaseFastMutex (&MmSectionCommitMutex);
    01191                     goto ErrorReturn1;
    01192                 }
    01193
    01194                 //
    01195                 // Quota charge failed, calculate the exact quota
    01196                 // taking into account pages that may already be
    01197                 // committed and retry the operation.
    01198                 //
    01199
    01200                 while (PointerPte <= LastPte) {
    01201
    01202                     //
    01203                     // Check to see if the prototype PTE is committed.
    01204                     // Note that prototype PTEs cannot be decommitted so
    01205                     // PTE only needs to be checked for zeroes.
    01206                     //
    01207                     //
    01208
    01209                     if (PointerPte->u.Long != 0) {
    01210                         QuotaFree += 1;
    01211                     }
    01212                     PointerPte += 1;
    01213                 }
    01214
    01215                 if (QuotaFree) {
    01216                     PointerPte = StartingPte;
    01217                     QuotaCharge -= QuotaFree;
    01218                     Status = STATUS_COMMITMENT_LIMIT;
    01219                     ChargedExactQuota = TRUE;
    01220                 }
    01221                 else {
    01222                     ExReleaseFastMutex (&MmSectionCommitMutex);
    01223                     goto ErrorReturn1;
    01224                 }
    01225             }
    01226
    01227             //
    01228             // Commit all the pages.
    01229             //
    01230
    01231             QuotaFree = 0;
    01232             TempPte = FoundVad->ControlArea->Segment->SegmentPteTemplate;
    01233
    01234             FoundVad->ControlArea->Segment->NumberOfCommittedPages +=
    01235                                                         QuotaCharge;
    01236
    01237             while (PointerPte <= LastPte) {
    01238
    01239                 if (PointerPte->u.Long != 0) {
    01240
    01241                     //
    01242                     // Page is already committed, back out commitment.
    01243                     //
    01244
    01245                     QuotaFree += 1;
    01246                 } else {
    01247                     *PointerPte = TempPte;
    01248                 }
    01249                 PointerPte += 1;
    01250             }
    01251
    01252             if (ChargedExactQuota == TRUE) {
    01253                 QuotaFree = 0;
    01254             }
    01255             else {
    01256                 LOCK_PFN (OldIrql);
    01257                 MmSharedCommitVlm -= QuotaFree;
    01258                 UNLOCK_PFN (OldIrql);
    01259                 FoundVad->ControlArea->Segment->NumberOfCommittedPages -=
    01260                                                         QuotaFree;
    01261             }
    01262
    01263             ExReleaseFastMutex (&MmSectionCommitMutex);
    01264             ASSERT ((LONG)QuotaFree >= 0);
    01265
    01266             //
    01267             // Change all the protections to be protected as specified.
    01268             //
    01269
    01270             LOCK_WS (Process);
    01271
    01272 #if 0 //fixfix charge and update protection.
    01273             MiSetProtectionOnSection (Process,
    01274                                       FoundVad,
    01275                                       StartingAddress,
    01276                                       EndingAddress,
    01277                                       Protect,
    01278                                       &OldProtect,
    01279                                       TRUE);
    01280
    01281 #endif //0
    01282         }
    01283
    01284         UNLOCK_WS (Process);
    01285
    01286         if (QuotaFree != 0) {
    01287             LOCK_PFN (OldIrql);
    01288             MmResidentAvailablePages += (PFN_NUMBER) QuotaFree;
    01289             MM_BUMP_COUNTER(25, QuotaFree);
    01290             UNLOCK_PFN (OldIrql);
    01291         }
    01292
    01293         //
    01294         // Previously reserved pages have been committed, or an error occurred,
    01295         // release working set lock, address creation lock, detach,
    01296         // dereference process and return status.
    01297         //
    01298
    01299         UNLOCK_ADDRESS_SPACE(Process);
    01300
    01301         if (Attached) {
    01302             KeDetachProcess();
    01303         }
    01304         if ( ProcessHandle != NtCurrentProcess() ) {
    01305             ObDereferenceObject (Process);
    01306         }
    01307
    01308         //
    01309         // Establish an exception handler and write the size and base
    01310         // address.
    01311         //
    01312
    01313         try {
    01314
    01315             *RegionSize = CapturedRegionSize;
    01316             *BaseAddress = StartingAddress;
    01317
    01318         } except (EXCEPTION_EXECUTE_HANDLER) {
    01319             return GetExceptionCode();
    01320         }
    01321
    01322 #if 0
    01323         if (MmDebug & MM_DBG_SHOW_NT_CALLS) {
    01324             if ( MmWatchProcess ) {
    01325                 if ( MmWatchProcess == PsGetCurrentProcess() ) {
    01326                     DbgPrint("\n+++ ALLOC Type %lx Base %p Size %p\n",
    01327                         AllocationType,StartingAddress, CapturedRegionSize);
    01328                     MmFooBar();
    01329                 }
    01330             } else {
    01331                 DbgPrint("return allocvm status %lx baseaddr %p size %p\n",
    01332                     Status, CapturedRegionSize, StartingAddress);
    01333             }
    01334         }
    01335 #endif
    01336
    01337         return STATUS_SUCCESS;
    01338     }
    01339
    01340 ErrorReturn:
    01341     UNLOCK_WS (Process);
    01342
    01343 ErrorReturn1:
    01344
    01345     UNLOCK_ADDRESS_SPACE (Process);
    01346     if (Attached) {
    01347         KeDetachProcess();
    01348     }
    01349     if (ProcessHandle != NtCurrentProcess()) {
    01350         ObDereferenceObject (Process);
    01351     }
    01352     return Status;
    01353 }
    01354
    01355 NTSTATUS
    01356 NtFreeVirtualMemory64(
    01357     IN HANDLE ProcessHandle,
    01358     IN OUT PVOID64 *BaseAddress,
    01359     IN OUT PULONGLONG RegionSize,
    01360     IN ULONG FreeType
    01361     )
    01362
    01363 /*++
    01364
    01365 Routine Description:
    01366
    01367     This function deletes a region of pages within the virtual address
    01368     space of a subject process.
    01369
    01370 Arguments:
    01371
    01372    ProcessHandle - An open handle to a process object.
    01373
    01374    BaseAddress - The base address of the region of pages
    01375                  to be freed. This value is rounded down to the
    01376                  next host page address boundary.
    01377
    01378    RegionSize - A pointer to a variable that will receive
    01379                 the actual size in bytes of the freed region of
    01380                 pages. The initial value of this argument is
    01381                 rounded up to the next host page size boundary.
    01382
    01383    FreeType - A set of flags that describe the type of free that is to
    01384               be performed for the specified region of pages.
    01385
    01386
    01387        FreeType Flags
    01388
    01389
    01390         MEM_DECOMMIT - The specified region of pages is to
    01391                        be decommitted.
    01392
    01393         MEM_RELEASE - The specified region of pages is to
    01394                       be released.
    01395
    01396
    01397 Return Value:
    01398
    01399     Returns the status
    01400
    01401     TBS
    01402
    01403
    01404 --*/
    01405
    01406 {
    01407     PMMVAD_SHORT Vad;
    01408     PMMVAD_SHORT NewVad;
    01409     PMMVAD PreviousVad;
    01410     PMMVAD NextVad;
    01411     PEPROCESS Process;
    01412     KPROCESSOR_MODE PreviousMode;
    01413     PVOID64 StartingAddress;
    01414     PVOID64 EndingAddress;
    01415     NTSTATUS Status;
    01416     LOGICAL Attached;
    01417     ULONGLONG CapturedRegionSize;
    01418     PVOID64 CapturedBase;
    01419     PMMPTE StartingPte;
    01420     PMMPTE EndingPte;
    01421     SIZE_T OldQuota;
    01422     SIZE_T QuotaCharge;
    01423     SIZE_T CommitReduction;
    01424     ULONG OldEnd;
    01425     KIRQL OldIrql;
    01426     PMI_PROCESS_VLM_INFO VlmInfo;
    01427
    01428     PAGED_CODE();
    01429
    01430     Attached = FALSE;
    01431
    01432     if (MI_VLM_ENABLED() == FALSE) {
    01433         return STATUS_NOT_IMPLEMENTED;
    01434     }
    01435
    01436     //
    01437     // Check to make sure FreeType is good.
    01438     //
    01439
    01440     if ((FreeType & ~(MEM_DECOMMIT | MEM_RELEASE)) != 0) {
    01441         return STATUS_INVALID_PARAMETER_4;
    01442     }
    01443
    01444     //
    01445     // One of MEM_DECOMMIT or MEM_RELEASE must be specified, but not both.
    01446     //
    01447
    01448     if (((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) == 0) ||
    01449         ((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) ==
    01450                             (MEM_DECOMMIT | MEM_RELEASE))) {
    01451         return STATUS_INVALID_PARAMETER_4;
    01452     }
    01453
    01454     PreviousMode = KeGetPreviousMode();
    01455
    01456     //
    01457     // Establish an exception handler, probe the specified addresses
    01458     // for write access and capture the initial values.
    01459     //
    01460
    01461     try {
    01462
    01463         if (PreviousMode != KernelMode) {
    01464
    01465             ProbeForWrite (BaseAddress, sizeof(PVOID64), sizeof(PVOID64));
    01466             ProbeForWrite (RegionSize, sizeof(ULONGLONG), sizeof(ULONGLONG));
    01467         }
    01468
    01469         //
    01470         // Capture the base address.
    01471         //
    01472
    01473         CapturedBase = *BaseAddress;
    01474
    01475         //
    01476         // Capture the region size.
    01477         //
    01478
    01479         CapturedRegionSize = *RegionSize;
    01480
    01481     } except (ExSystemExceptionFilter()) {
    01482
    01483         //
    01484         // If an exception occurs during the probe or capture
    01485         // of the initial values, then handle the exception and
    01486         // return the exception code as the status value.
    01487         //
    01488
    01489         return GetExceptionCode();
    01490     }
    01491
    01492 #if 0
    01493     if (MmDebug & MM_DBG_SHOW_NT_CALLS) {
    01494         if ( !MmWatchProcess ) {
    01495             DbgPrint("freevm processhandle %lx base %p size %p type %lx\n",
    01496                     ProcessHandle, CapturedBase, CapturedRegionSize, FreeType);
    01497         }
    01498     }
    01499 #endif
    01500
    01501     if ((CapturedRegionSize != 0) && (FreeType & MEM_RELEASE)) {
    01502         return STATUS_FREE_VM_NOT_AT_BASE;
    01503     }
    01504
    01505     //
    01506     // Make sure the specified starting and ending addresses are
    01507     // within the user part of the virtual address space.
    01508     //
    01509
    01510     if (CapturedBase > (PVOID64)MM_HIGHEST_USER_ADDRESS64) {
    01511
    01512         //
    01513         // Invalid base address.
    01514         //
    01515
    01516         return STATUS_INVALID_PARAMETER_2;
    01517     }
    01518
    01519     if ((ULONGLONG)MM_HIGHEST_USER_ADDRESS64 - (ULONGLONG)CapturedBase <
    01520                                                         CapturedRegionSize) {
    01521
    01522         //
    01523         // Invalid region size;
    01524         //
    01525
    01526         return STATUS_INVALID_PARAMETER_3;
    01527
    01528     }
    01529
    01530     EndingAddress = (PVOID64)(((ULONGLONG)CapturedBase + CapturedRegionSize - 1) |
    01531                         (PAGE_SIZE - 1));
    01532
    01533     StartingAddress = (PVOID64)PAGE_ALIGN64(CapturedBase);
    01534
    01535     if ( ProcessHandle == NtCurrentProcess() ) {
    01536         Process = PsGetCurrentProcess();
    01537     } else {
    01538
    01539         //
    01540         // Reference the specified process handle for VM_OPERATION access.
    01541         //
    01542
    01543         Status = ObReferenceObjectByHandle ( ProcessHandle,
    01544                                              PROCESS_VM_OPERATION,
    01545                                              PsProcessType,
    01546                                              PreviousMode,
    01547                                              (PVOID *)&Process,
    01548                                              NULL );
    01549         if (!NT_SUCCESS(Status)) {
    01550             return Status;
    01551         }
    01552     }
    01553
    01554     //
    01555     // If the specified process is not the current process, attach
    01556     // to the specified process.
    01557     //
    01558
    01559     if (PsGetCurrentProcess() != Process) {
    01560         KeAttachProcess (&Process->Pcb);
    01561         Attached = TRUE;
    01562     }
    01563
    01564
    01565     //
    01566     // Get the address creation mutex to block multiple threads from
    01567     // creating or deleting address space at the same time and
    01568     // get the working set mutex so virtual address descriptors can
    01569     // be inserted and walked.  Block APCs to prevent page faults while
    01570     // we own the working set mutex.
    01571     //
    01572
    01573     LOCK_WS_AND_ADDRESS_SPACE (Process);
    01574
    01575     //
    01576     // Make sure the address space was not deleted.
    01577     //
    01578
    01579     if (Process->AddressSpaceDeleted != 0) {
    01580         Status = STATUS_PROCESS_IS_TERMINATING;
    01581         goto ErrorReturn;
    01582     }
    01583
    01584     if (Process->ForkWasSuccessful != MM_NO_FORK_ALLOWED) {
    01585         Status = STATUS_MEMORY_NOT_ALLOCATED;
    01586         goto ErrorReturn;
    01587     }
    01588
    01589     Vad = (PMMVAD_SHORT)MiLocateAddress64 (MI_VA_TO_VPN64 (StartingAddress));
    01590
    01591     if (Vad == NULL) {
    01592
    01593         //
    01594         // No Virtual Address Descriptor located for Base Address.
    01595         //
    01596
    01597         Status = STATUS_MEMORY_NOT_ALLOCATED;
    01598         goto ErrorReturn;
    01599     }
    01600
    01601     //
    01602     // Found the associated Virtual Address Descriptor.
    01603     //
    01604
    01605     if (Vad->EndingVpn < MI_VA_TO_VPN64 (EndingAddress)) {
    01606
    01607         //
    01608         // The entire range to delete is not contained within a single
    01609         // virtual address descriptor.  Return an error.
    01610         //
    01611
    01612         Status = STATUS_UNABLE_TO_FREE_VM;
    01613         goto ErrorReturn;
    01614     }
    01615
    01616     //
    01617     // Check to ensure this Vad is deletable.  Delete is required
    01618     // for both decommit and release.
    01619     //
    01620
    01621     if ((Vad->u.VadFlags.PrivateMemory == 0) ||
    01622         (Vad->u.VadFlags.PhysicalMapping == 1)) {
    01623         Status = STATUS_UNABLE_TO_DELETE_SECTION;
    01624         goto ErrorReturn;
    01625     }
    01626
    01627     ASSERT (Vad->u.VadFlags.NoChange == 0);
    01628
    01629     if (FreeType & MEM_RELEASE) {
    01630
    01631         //
    01632         // *****************************************************************
    01633         // MEM_RELEASE was specified.
    01634         // *****************************************************************
    01635         //
    01636
    01637         //
    01638         // The descriptor for the address range is deletable.  Remove the
    01639         // the descriptor.
    01640         //
    01641
    01642         ASSERT (CapturedRegionSize == 0);
    01643
    01644         //
    01645         // If the region size is specified as 0, the base address
    01646         // must be the starting address for the region.
    01647         //
    01648
    01649         if (MI_VA_TO_VPN64 (CapturedBase) != Vad->StartingVpn) {
    01650             Status = STATUS_FREE_VM_NOT_AT_BASE;
    01651             goto ErrorReturn;
    01652         }
    01653
    01654         //
    01655         // This Virtual Address Descriptor has been deleted.
    01656         //
    01657
    01658         StartingAddress = MI_VPN_TO_VA64 (Vad->StartingVpn);
    01659         StartingPte = MiGetPteAddress64 (StartingAddress);
    01660         EndingAddress = MI_VPN_TO_VA64 (Vad->EndingVpn);
    01661         EndingPte = MiGetPteAddress64 (EndingAddress);
    01662         CapturedRegionSize = ((EndingPte - StartingPte + 1) << PAGE_SHIFT);
    01663         MiRemoveVad64 ((PMMVAD)Vad);
    01664         ExFreePool (Vad);
    01665
    01666         //
    01667         // Get the PFN mutex so that MiDeleteVirtualAddresses can be called.
    01668         //
    01669
    01670         CommitReduction = MiDecommitOrDeletePages64 (StartingPte,
    01671                                                      EndingPte,
    01672                                                      Process,
    01673                                                      DELETE_TYPE_PRIVATE,
    01674                                                      TRUE);
    01675         UNLOCK_WS (Process);
    01676
    01677         //
    01678         // Update the virtual size in the process header.
    01679         //
    01680
    01681         VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long);
    01682         VlmInfo->VirtualSize -= CapturedRegionSize;
    01683         VlmInfo->CommitCharge -= CommitReduction;
    01684
    01685         ExAcquireFastLock (&MiVlmStatisticsLock, &OldIrql);
    01686         MiVlmCommitChargeInPages -= CommitReduction;
    01687         ExReleaseFastLock (&MiVlmStatisticsLock, OldIrql);
    01688
    01689         UNLOCK_ADDRESS_SPACE (Process);
    01690
    01691         if (Attached) {
    01692             KeDetachProcess();
    01693         }
    01694
    01695         if ( ProcessHandle != NtCurrentProcess() ) {
    01696             ObDereferenceObject (Process);
    01697         }
    01698         //
    01699         // Establish an exception handler and write the size and base
    01700         // address.
    01701         //
    01702
    01703         try {
    01704
    01705             *RegionSize = CapturedRegionSize;
    01706             *BaseAddress = StartingAddress;
    01707
    01708         } except (EXCEPTION_EXECUTE_HANDLER) {
    01709
    01710             //
    01711             // An exception occurred, don't take any action (just handle
    01712             // the exception and return success.
    01713
    01714         }
    01715
    01716 #if 0
    01717         if (MmDebug & MM_DBG_SHOW_NT_CALLS) {
    01718             if ( MmWatchProcess ) {
    01719                 if ( MmWatchProcess == PsGetCurrentProcess() ) {
    01720                     DbgPrint("\n--- FREE Type 0x%lx Base %p Size %p\n",
    01721                             FreeType, StartingAddress, CapturedRegionSize);
    01722                     MmFooBar();
    01723                 }
    01724             }
    01725         }
    01726 #endif
    01727
    01728         return STATUS_SUCCESS;
    01729     }
    01730
    01731     //
    01732     // **************************************************************
    01733     //
    01734     // MEM_DECOMMIT was specified.
    01735     //
    01736     // **************************************************************
    01737     //
    01738
    01739     //
    01740     // Check to ensure the complete range of pages is already committed.
    01741     //
    01742
    01743     if (CapturedRegionSize == 0) {
    01744
    01745         if (MI_VA_TO_VPN64 (CapturedBase) != Vad->StartingVpn) {
    01746             Status = STATUS_FREE_VM_NOT_AT_BASE;
    01747             goto ErrorReturn;
    01748         }
    01749         EndingAddress = MI_VPN_TO_VA_ENDING64 (Vad->EndingVpn);
    01750     }
    01751
    01752     //
    01753     // Calculate the initial quotas and commit charges for this VAD.
    01754     //
    01755
    01756     StartingPte = MiGetPteAddress64 (StartingAddress);
    01757     EndingPte = MiGetPteAddress64 (EndingAddress);
    01758
    01759     CapturedRegionSize = 1 + (ULONGLONG)EndingAddress - (ULONGLONG)StartingAddress;
    01760
    01761     CommitReduction = MiDecommitOrDeletePages64 (StartingPte,
    01762                                                  EndingPte,
    01763                                                  Process,
    01764                                                  DELETE_TYPE_PRIVATE,
    01765                                                  TRUE);
    01766
    01767     VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long);
    01768     VlmInfo->CommitCharge -= CommitReduction;
    01769
    01770     ExAcquireFastLock (&MiVlmStatisticsLock, &OldIrql);
    01771     MiVlmCommitChargeInPages -= CommitReduction;
    01772     ExReleaseFastLock (&MiVlmStatisticsLock, OldIrql);
    01773
    01774     UNLOCK_WS (Process);
    01775     UNLOCK_ADDRESS_SPACE (Process);
    01776
    01777     if (Attached) {
    01778         KeDetachProcess();
    01779     }
    01780     if (ProcessHandle != NtCurrentProcess()) {
    01781         ObDereferenceObject (Process);
    01782     }
    01783
    01784     //
    01785     // Establish an exception handler and write the size and base
    01786     // address.
    01787     //
    01788
    01789     try {
    01790
    01791         *RegionSize = CapturedRegionSize;
    01792         *BaseAddress = StartingAddress;
    01793
    01794     } except (EXCEPTION_EXECUTE_HANDLER) {
    01795         NOTHING;
    01796     }
    01797
    01798     return STATUS_SUCCESS;
    01799
    01800 ErrorReturn:
    01801
    01802     UNLOCK_WS (Process);
    01803     UNLOCK_ADDRESS_SPACE (Process);
    01804
    01805     if (Attached) {
    01806         KeDetachProcess();
    01807     }
    01808
    01809     if (ProcessHandle != NtCurrentProcess()) {
    01810        ObDereferenceObject (Process);
    01811     }
    01812
    01813     return Status;
    01814 }
    01815
    01816
    01817 PVOID64
    01818 MiFindEmptyAddressRangeInTree64 (
    01819     IN ULONGLONG SizeOfRange64,
    01820     IN ULONG_PTR Alignment,
    01821     IN PMMADDRESS_NODE Root
    01822     )
    01823
    01824 /*++
    01825
    01826 Routine Description:
    01827
    01828     The function examines the virtual address descriptors to locate
    01829     an unused range of the specified size and returns the starting
    01830     address of the range.
    01831
    01832 Arguments:
    01833
    01834     SizeOfRange - Supplies the size in bytes of the range to locate.
    01835
    01836     Alignment - Supplies the alignment for the address.  Must be
    01837                  a power of 2 and greater than the page_size.
    01838
    01839     Root - Supplies the root of the tree to search through.
    01840
    01841
    01842 Return Value:
    01843
    01844     Returns the starting address of a suitable range.
    01845
    01846 --*/
    01847
    01848 {
    01849     PMMADDRESS_NODE Node;
    01850     PMMADDRESS_NODE NextNode;
    01851     ULONG_PTR AlignmentVpn;
    01852     ULONG SizeOfRange;
    01853     PVOID64 Start;
    01854
    01855     AlignmentVpn = Alignment >> PAGE_SHIFT;
    01856
    01857     //
    01858     // Locate the Node with the lowest starting address.
    01859     //
    01860
    01861     SizeOfRange = (ULONG)((SizeOfRange64 + (PAGE_SIZE - 1)) >> PAGE_SHIFT);
    01862     ASSERT (SizeOfRange != 0);
    01863
    01864     Node = Root;
    01865
    01866     if (Node == (PMMADDRESS_NODE)NULL) {
    01867         return (PVOID64)MM_LOWEST_USER_ADDRESS64;
    01868     }
    01869     while (Node->LeftChild != (PMMADDRESS_NODE)NULL) {
    01870         Node = Node->LeftChild;
    01871     }
    01872
    01873     //
    01874     // Check to see if a range exists between the lowest address VAD
    01875     // and lowest user address.
    01876     //
    01877
    01878     if (Node->StartingVpn > MI_VA_TO_VPN64 (MM_LOWEST_USER_ADDRESS64)) {
    01879         if ( SizeOfRange <
    01880             (Node->StartingVpn - MI_VA_TO_VPN64 (MM_LOWEST_USER_ADDRESS64))) {
    01881
    01882             return (PVOID64)MM_LOWEST_USER_ADDRESS64;
    01883         }
    01884     }
    01885
    01886     for (;;) {
    01887
    01888         NextNode = MiGetNextNode (Node);
    01889
    01890         if (NextNode != (PMMADDRESS_NODE)NULL) {
    01891
    01892             if (SizeOfRange <=
    01893                 ((ULONG_PTR)NextNode->StartingVpn -
    01894                                 MI_ROUND_TO_SIZE(1 + Node->EndingVpn,
    01895                                                  AlignmentVpn))) {
    01896
    01897                 //
    01898                 // Check to ensure that the ending address aligned upwards
    01899                 // is not greater than the starting address.
    01900                 //
    01901
    01902                 if ((ULONG_PTR)NextNode->StartingVpn >
    01903                         MI_ROUND_TO_SIZE(1 + Node->EndingVpn,
    01904                                          AlignmentVpn)) {
    01905
    01906                     return (PVOID64)MI_ROUND_TO_SIZE(
    01907                             (ULONGLONG)(MI_VPN_TO_VA_ENDING64(Node->EndingVpn)),
    01908                             (ULONGLONG)Alignment);
    01909                 }
    01910             }
    01911
    01912         } else {
    01913
    01914             //
    01915             // No more descriptors, check to see if this fits into the remainder
    01916             // of the address space.
    01917             //
    01918
    01919             if ((((ULONG_PTR)Node->EndingVpn + MI_VA_TO_VPN(X64K)) <
    01920                     MI_VA_TO_VPN64 (MM_HIGHEST_VAD_ADDRESS64))
    01921                         &&
    01922                 (SizeOfRange64 <=
    01923                     ((ULONGLONG)MM_HIGHEST_VAD_ADDRESS64 - X64K -
    01924                             MI_ROUND_TO_SIZE(
    01925                              (ULONGLONG)(MI_VPN_TO_VA64(Node->EndingVpn)),
    01926                              (ULONGLONG)Alignment)))) {
    01927
    01928                 Start = MI_VPN_TO_VA_ENDING64 (Node->EndingVpn);
    01929                 ASSERT (MI_VA_TO_VPN64 (Start) == Node->EndingVpn);
    01930
    01931                 Start = (PVOID64)MI_ROUND_TO_SIZE((ULONGLONG)Start,
    01932                                                   (ULONGLONG)Alignment);
    01933                 ASSERT (MI_VA_TO_VPN64 (Start) > Node->EndingVpn);
    01934                 return Start;
    01935             } else {
    01936                 ExRaiseStatus (STATUS_NO_MEMORY);
    01937             }
    01938         }
    01939         Node = NextNode;
    01940     }
    01941 }
    01942
    01943 LOGICAL
    01944 MiCommitPages64 (
    01945     IN PMMPTE StartPte,
    01946     IN PMMPTE LastPte,
    01947     IN ULONG ProtectionMask,
    01948     IN PEPROCESS Process,
    01949     OUT PSIZE_T PtesCommitted
    01950     )
    01951
    01952 /*++
    01953
    01954 Routine Description:
    01955
    01956     This function commits by making each page valid in the specified range of
    01957     PTEs.  It also changes the protection of any existing valid PTEs in
    01958     the specified range.
    01959
    01960 Arguments:
    01961
    01962     StartPte - First PTE in the range.
    01963
    01964     LastPte - Last PTE in the range.
    01965
    01966     ProtectionMask - Protection mask to set in the valid PTEs.
    01967
    01968     Process - Pointer to the process object of the subject process.
    01969
    01970     PtesCommitted - Supplies a pointer to receive the number of valid PTEs
    01971                     encountered in the range.
    01972
    01973 Return Value:
    01974
    01975     TRUE if the pages were committed, FALSE if not.
    01976
    01977 Environment:
    01978
    01979     Process Working Set Lock held.
    01980
    01981 --*/
    01982
    01983 {
    01984     PMMPTE PointerPte;
    01985     PMMPTE PointerPde;
    01986     MMPTE TempPte;
    01987     PFN_NUMBER PageFrameIndex;
    01988     PMMPFN Pfn1;
    01989     ULONG PageColor;
    01990     KIRQL OldIrql;
    01991     ULONG BarrierStamp;
    01992     LOGICAL TopPdeBuilt;
    01993     LOGICAL PdeBuilt;
    01994     PUSHORT UsedPde64Handle;
    01995
    01996     *PtesCommitted = 0;
    01997     PointerPde = MiGetPteAddress (StartPte);
    01998
    01999     //
    02000     // Fill in all the page table pages with the valid PTEs.
    02001     //
    02002
    02003     TopPdeBuilt = MiMakePdeExistAndMakeValid64 (PointerPde, Process, FALSE, TRUE);
    02004     if (TopPdeBuilt == FALSE) {
    02005         return FALSE;
    02006     }
    02007
    02008     UsedPde64Handle = MI_GET_USED_PDE64_HANDLE (PointerPde);
    02009
    02010     PointerPte = StartPte;
    02011     while (PointerPte <= LastPte) {
    02012
    02013         if (MiIsPteOnPdeBoundary(PointerPte)) {
    02014
    02015             //
    02016             // Pointing to the next page table page, make
    02017             // a page table page exist and make it valid.
    02018             //
    02019
    02020             PointerPde = MiGetPteAddress (PointerPte);
    02021             UsedPde64Handle = MI_GET_USED_PDE64_HANDLE (PointerPde);
    02022
    02023             //
    02024             // This call will always succeed since the top level PDE already
    02025             // exists.
    02026             //
    02027
    02028             PdeBuilt = MiMakePdeExistAndMakeValid64 (PointerPde, Process, FALSE, TRUE);
    02029             ASSERT (PdeBuilt == TRUE);
    02030         }
    02031
    02032         if (PointerPte->u.Long == 0) {
    02033
    02034             PageColor = MI_PAGE_COLOR_PTE_PROCESS (PointerPte,
    02035                                                    &Process->NextPageColor);
    02036             PointerPte->u.Soft.Protection = ProtectionMask;
    02037             LOCK_PFN (OldIrql);
    02038
    02039             //
    02040             // There can be no races on private PTEs (just PDEs) so even
    02041             // if a wait state occurs, nothing needs to be rechecked.
    02042             //
    02043
    02044             MiEnsureAvailablePageOrWait (Process, NULL);
    02045
    02046             PageFrameIndex = MiRemoveZeroPage (PageColor);
    02047
    02048             BarrierStamp = MI_PFN_ELEMENT(PageFrameIndex)->PteFrame;
    02049
    02050             MiInitializePfn (PageFrameIndex, PointerPte, 1);
    02051             UNLOCK_PFN (OldIrql);
    02052
    02053             MI_MAKE_VALID_PTE (TempPte,
    02054                                PageFrameIndex,
    02055                                ProtectionMask,
    02056                                NULL);
    02057
    02058             if (TempPte.u.Hard.Write) {
    02059                 MI_SET_PTE_DIRTY (TempPte);
    02060             }
    02061
    02062             MI_BARRIER_SYNCHRONIZE (BarrierStamp);
    02063
    02064             *PointerPte = TempPte;
    02065             (*UsedPde64Handle) += 1;
    02066
    02067         } else {
    02068             ASSERT (PointerPte->u.Hard.Valid == 1);
    02069             (*PtesCommitted) += 1;
    02070
    02071             Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    02072
    02073             if (Pfn1->OriginalPte.u.Soft.Protection != ProtectionMask) {
    02074
    02075                 //
    02076                 // Change protection to match specified protection.
    02077                 //
    02078
    02079                 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
    02080                 MI_MAKE_VALID_PTE (TempPte,
    02081                                    PointerPte->u.Hard.PageFrameNumber,
    02082                                    ProtectionMask,
    02083                                    NULL);
    02084                 if (TempPte.u.Hard.Write) {
    02085                     MI_SET_PTE_DIRTY (TempPte);
    02086                 }
    02087
    02088                 //
    02089                 // Flush the TB as we have changed the protection
    02090                 // of a valid PTE.
    02091                 //
    02092
    02093                 MiFlushTbAndCapture (PointerPte,
    02094                                      TempPte.u.Flush,
    02095                                      Pfn1);
    02096             }
    02097         }
    02098         PointerPte += 1;
    02099     }
    02100     return TRUE;
    02101 }
    02102
    02103 LOGICAL
    02104 MiMakePdeExistAndMakeValid64 (
    02105     IN PMMPTE PointerPde,
    02106     IN PEPROCESS TargetProcess,
    02107     IN LOGICAL PfnLockHeld,
    02108     IN LOGICAL MakePageTablePage
    02109     )
    02110
    02111 /*++
    02112
    02113 Routine Description:
    02114
    02115     This routine examines the specified Page Directory Entry to determine
    02116     if the page table page mapped by the PDE exists.
    02117
    02118     If the page table page exists and is not currently in memory, the
    02119     working set mutex and, if held, the PFN mutex are released and the
    02120     page table page is faulted into the working set.  The mutexes are
    02121     required.
    02122
    02123     If the PDE exists, the function returns TRUE.
    02124
    02125     If the PDE does not exist, a zero filled PTE is created and it
    02126     too is brought into the working set.  In this case the return
    02127     value is FALSE.
    02128
    02129 Arguments:
    02130
    02131     PointerPde - Supplies a pointer to the PDE to examine and bring
    02132                  into the working set.
    02133
    02134     TargetProcess - Supplies a pointer to the current process.
    02135
    02136     PfnLockHeld - Supplies the value TRUE if the PFN mutex is held, FALSE
    02137                   otherwise.
    02138
    02139     MakePageTablePage - Supplies the value TRUE if the PDE is to be created.
    02140                         FALSE if not - meaning just the top level Base is
    02141                         to be created.
    02142
    02143 Return Value:
    02144
    02145     TRUE if the PDE exists, FALSE if the PDE was created.
    02146
    02147 Environment:
    02148
    02149     Kernel mode, APCs disabled, WorkingSetLock and AddressSpace locks held.
    02150
    02151 --*/
    02152
    02153 {
    02154     PMMPTE PointerPte;
    02155     KIRQL OldIrql;
    02156     MMPTE TempPte;
    02157     ULONG PageColor;
    02158     PFN_NUMBER PageFrameIndex;
    02159     ULONG BarrierStamp;
    02160     PMI_PROCESS_VLM_INFO VlmInfo;
    02161     PMMPTE PdeBase;
    02162
    02163     VlmInfo = NULL;
    02164
    02165     //
    02166     // Make sure the Page Directory Page for this 32GB region exists.
    02167     //
    02168
    02169     PointerPte = MiGetPteAddress (PointerPde);
    02170
    02171 redo:
    02172
    02173     if (PointerPte->u.Long == 0) {
    02174
    02175         //
    02176         // Make a page directory page.
    02177         //
    02178
    02179         if (VlmInfo == NULL) {
    02180
    02181             if (PfnLockHeld) {
    02182                 UNLOCK_PFN (OldIrql);
    02183             }
    02184
    02185             UNLOCK_WS (TargetProcess);
    02186
    02187             VlmInfo = (PMI_PROCESS_VLM_INFO) ExAllocatePoolWithTag (
    02188                                                 NonPagedPool,
    02189                                                 sizeof (MI_PROCESS_VLM_INFO),
    02190                                                 'lVmM');
    02191
    02192             if (VlmInfo) {
    02193                 RtlZeroMemory (VlmInfo,
    02194                                sizeof (MI_PROCESS_VLM_INFO));
    02195             }
    02196
    02197             LOCK_WS (TargetProcess);
    02198
    02199             if (PfnLockHeld) {
    02200                 LOCK_PFN (OldIrql);
    02201             }
    02202
    02203             if (VlmInfo == NULL) {
    02204                 return FALSE;
    02205             }
    02206
    02207             //
    02208             // Since locks were released, everything must be rechecked.
    02209             // Note the VAD cannot disappear as the address space lock was
    02210             // held all the way through.
    02211             //
    02212
    02213             goto redo;
    02214         }
    02215
    02216         PageColor = MI_PAGE_COLOR_PTE_PROCESS (PointerPte,
    02217                                                &TargetProcess->NextPageColor);
    02218         if (!PfnLockHeld) {
    02219             LOCK_PFN (OldIrql);
    02220         }
    02221
    02222         if (MiEnsureAvailablePageOrWait (TargetProcess, NULL) == TRUE) {
    02223
    02224             //
    02225             // A wait state occurred, everything must be rechecked.
    02226             //
    02227
    02228             goto redo;
    02229         }
    02230
    02231         PageFrameIndex = MiRemoveZeroPage (PageColor);
    02232         BarrierStamp = MI_PFN_ELEMENT(PageFrameIndex)->PteFrame;
    02233         MiInitializePfn (PageFrameIndex, PointerPte, 1);
    02234
    02235         if (!PfnLockHeld) {
    02236             UNLOCK_PFN (OldIrql);
    02237         }
    02238
    02239         MI_MAKE_VALID_PTE (TempPte,
    02240                            PageFrameIndex,
    02241                            MM_READWRITE,
    02242                            NULL);
    02243
    02244         MI_SET_PTE_DIRTY (TempPte);
    02245
    02246         MI_BARRIER_SYNCHRONIZE (BarrierStamp);
    02247
    02248         *PointerPte = TempPte;
    02249
    02250         //
    02251         // Stash the used page table page counts pointer in the PDE_BASE64.
    02252         //
    02253
    02254         PdeBase = MiGetVirtualAddressMappedByPte (PointerPte);
    02255
    02256         //
    02257         // This will always be true unless VLM is expanded past 32GB.
    02258         //
    02259
    02260         ASSERT (PdeBase == (PMMPTE)PDE_BASE64);
    02261
    02262         PdeBase->u.Long = (ULONG)VlmInfo;
    02263     }
    02264     else {
    02265         if (VlmInfo) {
    02266             ExFreePool (VlmInfo);
    02267         }
    02268     }
    02269
    02270     ASSERT (PointerPte->u.Hard.Valid == 1);
    02271
    02272     if (MakePageTablePage == FALSE) {
    02273         return TRUE;
    02274     }
    02275
    02276 redo2:
    02277
    02278     if (PointerPde->u.Hard.Valid == 1) {
    02279
    02280         //
    02281         // Already valid.
    02282         //
    02283
    02284         return TRUE;
    02285     }
    02286
    02287     //
    02288     // Page directory entry not valid, make it valid.
    02289     //
    02290
    02291     PageColor = MI_PAGE_COLOR_PTE_PROCESS (PointerPde,
    02292                                            &TargetProcess->NextPageColor);
    02293     if (!PfnLockHeld) {
    02294         LOCK_PFN (OldIrql);
    02295     }
    02296
    02297     if (MiEnsureAvailablePageOrWait (TargetProcess, NULL) == TRUE) {
    02298
    02299         //
    02300         // A wait state occurred, everything from the PDE down must
    02301         // be rechecked.
    02302         //
    02303
    02304         if (!PfnLockHeld) {
    02305             UNLOCK_PFN (OldIrql);
    02306         }
    02307         goto redo2;
    02308     }
    02309
    02310     PageFrameIndex = MiRemoveZeroPage (PageColor);
    02311     BarrierStamp = MI_PFN_ELEMENT(PageFrameIndex)->PteFrame;
    02312     MiInitializePfn (PageFrameIndex, PointerPde, 1);
    02313
    02314     if (!PfnLockHeld) {
    02315         UNLOCK_PFN (OldIrql);
    02316     }
    02317
    02318     MI_MAKE_VALID_PTE (TempPte,
    02319                        PageFrameIndex,
    02320                        MM_READWRITE,
    02321                        NULL);
    02322
    02323     MI_SET_PTE_DIRTY (TempPte);
    02324
    02325     MI_BARRIER_SYNCHRONIZE (BarrierStamp);
    02326
    02327     *PointerPde = TempPte;
    02328
    02329     return TRUE;
    02330 }
    02331
    02332 ULONG
    02333 MiDoesPdeExist64 (
    02334     IN PMMPTE PointerPde
    02335     )
    02336
    02337 /*++
    02338
    02339 Routine Description:
    02340
    02341     This routine examines the specified Page Directory Entry to determine
    02342     if the page table page mapped by the PDE exists.
    02343
    02344     If the page table page exists and is not currently in memory, the
    02345     working set mutex and, if held, the PFN mutex are released and the
    02346     page table page is faulted into the working set.  The mutexes are
    02347     required.
    02348
    02349     If the PDE exists, the function returns true.
    02350
    02351 Arguments:
    02352
    02353     PointerPde - Supplies a pointer to the PDE to examine and potentially
    02354                  bring into the working set.
    02355
    02356     TargetProcess - Supplies a pointer to the current process.
    02357
    02358     PfnMutexHeld - Supplies the value TRUE if the PFN mutex is held, FALSE
    02359                    otherwise.
    02360
    02361 Return Value:
    02362
    02363     TRUE if the PDE exists, FALSE if the PDE is zero.
    02364
    02365 Environment:
    02366
    02367     Kernel mode, APCs disabled, WorkingSetLock held.
    02368
    02369 --*/
    02370
    02371 {
    02372     PMMPTE PointerPte;
    02373     PMI_PROCESS_VLM_INFO VlmInfo;
    02374
    02375     PointerPte = MiGetPteAddress(PointerPde);
    02376     if (PointerPte->u.Long == 0) {
    02377
    02378         //
    02379         // This page directory entry doesn't exist, return FALSE.
    02380         //
    02381
    02382         return FALSE;
    02383     }
    02384
    02385     if (PointerPde->u.Long == 0) {
    02386
    02387         //
    02388         // This page directory entry doesn't exist, return FALSE.
    02389         //
    02390
    02391         return FALSE;
    02392     }
    02393
    02394     ASSERT (PointerPde->u.Hard.Valid == 1);
    02395
    02396     VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long);
    02397     ASSERT (VlmInfo != NULL);
    02398
    02399     return TRUE;
    02400 }
    02401
    02402 ULONG
    02403 MiDecommitOrDeletePages64 (
    02404     IN PMMPTE StartingPte,
    02405     IN PMMPTE EndingPte,
    02406     IN PEPROCESS Process,
    02407     IN ULONG Type,
    02408     IN LOGICAL FlushTb
    02409     )
    02410
    02411 /*++
    02412
    02413 Routine Description:
    02414
    02415     This routine decommits the specified range of pages.
    02416
    02417 Arguments:
    02418
    02419     StartingAddress - Supplies the starting address of the range.
    02420
    02421     EndingPte - Supplies the ending PTE of the range.
    02422
    02423     Process - Supplies the current process.
    02424
    02425     Type - One of: DELETE_TYPE_PRIVATE for private memory or DELETE_TYPE_SHARED
    02426            for shared memory.
    02427
    02428     FlushTb - Supplies TRUE if the TB needs to be flushed, FALSE if not.
    02429
    02430 Return Value:
    02431
    02432     Value to reduce commitment by for the VAD.
    02433
    02434 Environment:
    02435
    02436     Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes
    02437     held.
    02438
    02439 --*/
    02440
    02441 {
    02442     PMMPTE PointerPde;
    02443     PMMPTE PointerPte;
    02444     ULONG PdeOffset;
    02445     PFN_NUMBER CommitReduction;
    02446     PMMPTE CommitLimitPte;
    02447     KIRQL OldIrql;
    02448     PMMPTE ValidPteList[MM_VALID_PTE_SIZE];
    02449     ULONG count;
    02450     ULONG WorkingSetIndex;
    02451     PMMPFN Pfn1;
    02452     PMMPFN Pfn2;
    02453     PVOID SwapVa;
    02454     ULONG Entry;
    02455     MMPTE PteContents;
    02456     MMPTE NewPte;
    02457     ULONG PfnLockHeld;
    02458     PMMPTE LowestPde;
    02459     PMI_PROCESS_VLM_INFO VlmInfo;
    02460
    02461     count = 0;
    02462     PfnLockHeld = FALSE;
    02463     CommitReduction = 0;
    02464
    02465     //
    02466     // Decommit each page by setting the PTE to be explicitly
    02467     // decommitted.  The PTEs cannot be deleted all at once as
    02468     // this would set the PTEs to zero which would auto-evaluate
    02469     // as committed if referenced by another thread when a page
    02470     // table page is being in-paged.
    02471     //
    02472
    02473     PointerPte = StartingPte;
    02474     PointerPde = MiGetPteAddress (StartingPte);
    02475
    02476     VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long);
    02477     LowestPde = MiGetPdeAddress64 (MM_LOWEST_USER_ADDRESS64);
    02478
    02479     //
    02480     // Loop through all the PDEs which map this region and ensure that
    02481     // they exist.  If they don't exist create them by touching a
    02482     // PTE mapped by the PDE.
    02483     //
    02484
    02485     if (!MiDoesPdeExist64 (PointerPde)) {
    02486         PointerPte = (PMMPTE)PAGE_ALIGN (PointerPte);
    02487         PointerPte += PTE_PER_PAGE;
    02488     }
    02489
    02490     while (PointerPte <= EndingPte) {
    02491
    02492         if (MiIsPteOnPdeBoundary(PointerPte)) {
    02493
    02494             if (count != 0) {
    02495                 MiProcessValidPteList64 (&ValidPteList[0], count, FlushTb);
    02496                 count = 0;
    02497             }
    02498
    02499             if (PfnLockHeld) {
    02500                 UNLOCK_PFN (OldIrql);
    02501             }
    02502
    02503             MiCheckPdeForDeletion (PointerPde, FlushTb);
    02504             PointerPde = MiGetPteAddress (PointerPte);
    02505
    02506             if (!MiDoesPdeExist64 (PointerPde)) {
    02507                 PointerPte += PTE_PER_PAGE;
    02508                 continue;
    02509             }
    02510             if (PfnLockHeld) {
    02511                 LOCK_PFN (OldIrql);
    02512             }
    02513         }
    02514
    02515         //
    02516         // The working set lock is held.  No PTEs can go from
    02517         // invalid to valid or valid to invalid.  Transition
    02518         // PTEs can go from transition to pagefile.
    02519         //
    02520
    02521         PteContents = *PointerPte;
    02522
    02523         if (PteContents.u.Long != 0) {
    02524
    02525             VlmInfo->UsedPageTableEntries[PointerPde - LowestPde] -= 1;
    02526
    02527             if (PteContents.u.Hard.Valid == 1) {
    02528                 if (Type == DELETE_TYPE_PRIVATE) {
    02529                     CommitReduction += 1;
    02530                 }
    02531
    02532                 //
    02533                 // Pte is valid, process later when PFN lock is held.
    02534                 //
    02535
    02536                 if (count == MM_VALID_PTE_SIZE) {
    02537                     MiProcessValidPteList64 (&ValidPteList[0], count, FlushTb);
    02538                     count = 0;
    02539                 }
    02540                 ValidPteList[count] = PointerPte;
    02541                 count += 1;
    02542             } else if (PteContents.u.Soft.Prototype == 1) {
    02543                 NOTHING;
    02544
    02545             } else if (PteContents.u.Soft.Transition == 1) {
    02546
    02547                 //
    02548                 // This is a transition PTE. (Page is private)
    02549                 //
    02550                 // Get the PFN mutex so that MiDeletePte can be called.
    02551                 //
    02552
    02553                 if (!PfnLockHeld) {
    02554                     LOCK_PFN (OldIrql);
    02555                     PfnLockHeld = TRUE;
    02556                     continue;
    02557                 }
    02558                 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Trans.PageFrameNumber);
    02559
    02560                 MI_SET_PFN_DELETED (Pfn1);
    02561
    02562                 MiDecrementShareCount (Pfn1->PteFrame);
    02563
    02564                 //
    02565                 // Check the reference count for the page, if the reference
    02566                 // count is zero, move the page to the free list, if the
    02567                 // reference count is not zero, ignore this page.  When the
    02568                 // reference count goes to zero, it will be placed on the
    02569                 // free list.
    02570                 //
    02571
    02572                 if (Pfn1->u3.e2.ReferenceCount == 0) {
    02573                     MiUnlinkPageFromList (Pfn1);
    02574                     MiReleasePageFileSpace (Pfn1->OriginalPte);
    02575                     MiInsertPageInList (MmPageLocationList[FreePageList],
    02576                                         MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE(&PteContents));
    02577                 }
    02578             } else {
    02579                 ASSERT (PteContents.u.Soft.PageFileHigh == 0);
    02580             }
    02581         }
    02582
    02583         if (PfnLockHeld) {
    02584             UNLOCK_PFN (OldIrql);
    02585             PfnLockHeld = FALSE;
    02586         }
    02587         PointerPte += 1;
    02588     }
    02589     if (count != 0) {
    02590         MiProcessValidPteList64 (&ValidPteList[0], count, FlushTb);
    02591     }
    02592
    02593     MiCheckPdeForDeletion (PointerPde, FlushTb);
    02594
    02595     MiReturnAvailablePages (CommitReduction);
    02596
    02597     return CommitReduction;
    02598 }
    02599 VOID
    02600 MiProcessValidPteList64 (
    02601     IN PMMPTE *ValidPteList,
    02602     IN ULONG Count,
    02603     IN LOGICAL FlushTb
    02604     )
    02605
    02606 /*++
    02607
    02608 Routine Description:
    02609
    02610     This routine flushes the specified range of valid PTEs.
    02611
    02612 Arguments:
    02613
    02614     ValidPteList - Supplies a pointer to an array of PTEs to flush.
    02615
    02616     Count - Supplies the count of the number of elements in the array.
    02617
    02618     FlushTb - Supplies TRUE if the TB needs to be flushed, FALSE if not.
    02619
    02620 Return Value:
    02621
    02622     none.
    02623
    02624 Environment:
    02625
    02626     Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes
    02627     held.
    02628
    02629 --*/
    02630
    02631 {
    02632     ULONG i = 0;
    02633     MMPTE_FLUSH_LIST64 PteFlushList;
    02634     MMPTE PteContents;
    02635     PMMPFN Pfn1;
    02636     KIRQL OldIrql;
    02637     PMMPTE PointerPde;
    02638
    02639     PteFlushList.Count = Count;
    02640
    02641     LOCK_PFN (OldIrql);
    02642
    02643     do {
    02644         PteContents = *ValidPteList[i];
    02645         ASSERT (PteContents.u.Hard.Valid == 1);
    02646         Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber);
    02647
    02648         if (Pfn1->u3.e1.PrototypePte == 1) {
    02649
    02650             //
    02651             // Capture the state of the modified bit for this
    02652             // pte.
    02653             //
    02654
    02655             MI_CAPTURE_DIRTY_BIT_TO_PFN (&PteContents, Pfn1);
    02656
    02657             //
    02658             // Decrement the share and valid counts of the page table
    02659             // page which maps this PTE.
    02660             //
    02661
    02662             PointerPde = MiGetPteAddress (ValidPteList[i]);
    02663             MiDecrementShareAndValidCount (MI_GET_PAGE_FRAME_FROM_PTE(PointerPde));
    02664
    02665             //
    02666             // Decrement the share count for the physical page.
    02667             //
    02668
    02669             MiDecrementShareCount (MI_GET_PAGE_FRAME_FROM_PTE(&PteContents));
    02670
    02671         } else {
    02672
    02673             //
    02674             // Decrement the share and valid counts of the page table
    02675             // page which maps this PTE.
    02676             //
    02677
    02678             MiDecrementShareAndValidCount (Pfn1->PteFrame);
    02679
    02680             MI_SET_PFN_DELETED (Pfn1);
    02681
    02682             //
    02683             // Decrement the share count for the physical page.  As the page
    02684             // is private it will be put on the free list.
    02685             //
    02686
    02687             MiDecrementShareCountOnly (MI_GET_PAGE_FRAME_FROM_PTE(&PteContents));
    02688         }
    02689
    02690         if (Count < MM_MAXIMUM_FLUSH_COUNT) {
    02691             PteFlushList.FlushPte[i] = ValidPteList[i];
    02692             PteFlushList.FlushVpn[i] =
    02693                  MiGetVirtualPageNumberMappedByPte64 (ValidPteList[i]) >> PAGE_SHIFT;
    02694         }
    02695         *ValidPteList[i] = ZeroPte;
    02696         i += 1;
    02697     } while (i != Count);
    02698
    02699     if (FlushTb) {
    02700         MiFlushPteList64 (&PteFlushList, FALSE, ZeroPte);
    02701     }
    02702
    02703     UNLOCK_PFN (OldIrql);
    02704     return;
    02705 }
    02706
    02707 VOID
    02708 MiReturnAvailablePages (
    02709     IN PFN_NUMBER Amount
    02710     )
    02711
    02712 /*++
    02713
    02714 Routine Description:
    02715
    02716     This routine returns the specified amount to the system resident pages list.
    02717
    02718 Arguments:
    02719
    02720     Amount - Supplies the amount to return.
    02721
    02722 Return Value:
    02723
    02724     none.
    02725
    02726 Environment:
    02727
    02728     Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes
    02729     held.
    02730
    02731 --*/
    02732
    02733 {
    02734     KIRQL OldIrql;
    02735
    02736     LOCK_PFN (OldIrql);
    02737     MmResidentAvailablePages += Amount;
    02738     MM_BUMP_COUNTER(26, Amount);
    02739     UNLOCK_PFN (OldIrql);
    02740     return;
    02741 }
    02742
    02743
    02744 LOGICAL
    02745 MiCheckPdeForDeletion (
    02746     IN PMMPTE PointerPde,
    02747     IN LOGICAL FlushTb
    02748     )
    02749
    02750 /*++
    02751
    02752 Routine Description:
    02753
    02754     This routine checks to see if the share count of the specified PDE is 1,
    02755     and if it is, the PDE is deleted.
    02756
    02757 Arguments:
    02758
    02759     PointerPde - Supplies the PDE to check.
    02760
    02761     FlushTb - Supplies TRUE if the TB needs to be flushed, FALSE if not.
    02762
    02763 Return Value:
    02764
    02765     TRUE if the PDE no longer exists upon return.
    02766     FALSE if the PDE still exists on return.
    02767
    02768 Environment:
    02769
    02770     Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes
    02771     held.
    02772
    02773 --*/
    02774
    02775 {
    02776     LOGICAL Status;
    02777     KIRQL OldIrql;
    02778     PFN_NUMBER PageFrameIndex;
    02779     PMMPFN Pfn1;
    02780     PMMPTE PointerPte;
    02781     PMI_PROCESS_VLM_INFO VlmInfo;
    02782     PMMPTE LowestPde;
    02783
    02784     PointerPte = MiGetPteAddress (PointerPde);
    02785     if (PointerPte->u.Hard.Valid == 0) {
    02786
    02787         //
    02788         // Page Directory does not exist.
    02789         //
    02790
    02791         return TRUE;
    02792     }
    02793
    02794     if (PointerPde->u.Hard.Valid == 0) {
    02795
    02796         //
    02797         // Page directory entry does not exist.
    02798         //
    02799
    02800         return TRUE;
    02801     }
    02802     PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE(PointerPde);
    02803     Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
    02804     Status = FALSE;
    02805     LOCK_PFN (OldIrql);
    02806
    02807     VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long);
    02808     LowestPde = MiGetPdeAddress64 (MM_LOWEST_USER_ADDRESS64);
    02809
    02810     PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
    02811
    02812     if (VlmInfo->UsedPageTableEntries[PointerPde - LowestPde] == 0) {
    02813         ASSERT (Pfn1->u2.ShareCount == 1);
    02814         MiDecrementShareAndValidCount (Pfn1->PteFrame);
    02815         MI_SET_PFN_DELETED (Pfn1);
    02816         MiDecrementShareCountOnly (PageFrameIndex);
    02817         if (FlushTb == TRUE) {
    02818             KeFlushSingleTb (PointerPte,
    02819                              TRUE,
    02820                              FALSE,
    02821                              (PHARDWARE_PTE)PointerPde,
    02822                              ZeroPte.u.Flush);
    02823         }
    02824         else {
    02825              *PointerPde = ZeroPte;
    02826         }
    02827         Status = TRUE;
    02828     }
    02829 #if DBG
    02830     else {
    02831         ULONG i;
    02832         ULONG count;
    02833         PULONG p;
    02834
    02835         count = 0;
    02836         p = (PULONG)PointerPte;
    02837
    02838         for (i = 0; i < PAGE_SIZE; i += sizeof(p)) {
    02839             p += 1;
    02840             count += 1;
    02841         }
    02842         ASSERT (count != 0);
    02843     }
    02844 #endif
    02845
    02846     UNLOCK_PFN (OldIrql);
    02847     return Status;
    02848 }
    02849
    02850 VOID
    02851 MiDeleteVlmAddressSpace (
    02852     IN PEPROCESS Process
    02853     )
    02854
    02855 /*++
    02856
    02857 Routine Description:
    02858
    02859     This routine flushes the specified range of valid PTEs.
    02860
    02861 Arguments:
    02862
    02863     ValidPteList - Supplies a pointer to an array of PTEs to flush.
    02864
    02865     Count - Supplies the count of the number of elements in the array.
    02866
    02867 Return Value:
    02868
    02869     none.
    02870
    02871 Environment:
    02872
    02873     Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes
    02874     held.
    02875
    02876 --*/
    02877
    02878 {
    02879     PMMVAD Vad;
    02880     PMMPTE PointerPde;
    02881     PMMPTE PointerPte1;
    02882     PMMPTE PointerPte2;
    02883     PMMPFN Pfn1;
    02884     MMPTE PteContents;
    02885     KIRQL OldIrql;
    02886     PCONTROL_AREA ControlArea;
    02887     ULONG Type;
    02888     PMI_PROCESS_VLM_INFO VlmInfo;
    02889     SIZE_T CommitReduction;
    02890     ULONGLONG RegionSize;
    02891
    02892     Vad = (PMMVAD)Process->CloneRoot;
    02893
    02894     if (Vad != (PMMVAD)NULL) {
    02895         VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long);
    02896
    02897         do {
    02898
    02899             MiRemoveVad64 (Vad);
    02900
    02901             Type = DELETE_TYPE_PRIVATE;
    02902             if (Vad->u.VadFlags.PrivateMemory == 0) {
    02903                 Type = DELETE_TYPE_SHARED;
    02904             }
    02905             CommitReduction = MiDecommitOrDeletePages64 (
    02906                            MiGetPteAddress64 (MI_VPN_TO_VA64 (Vad->StartingVpn)),
    02907                            MiGetPteAddress64 (MI_VPN_TO_VA_ENDING64 (Vad->EndingVpn)),
    02908                            Process,
    02909                            Type,
    02910                            FALSE);
    02911
    02912
    02913             RegionSize = (((ULONGLONG)(Vad->EndingVpn - Vad->StartingVpn + 1)) << PAGE_SHIFT);
    02914             VlmInfo->VirtualSize -= RegionSize;
    02915
    02916             ExAcquireFastLock (&MiVlmStatisticsLock, &OldIrql);
    02917             if (Type != DELETE_TYPE_SHARED) {
    02918                 MiVlmCommitChargeInPages -= CommitReduction;
    02919             }
    02920             ExReleaseFastLock (&MiVlmStatisticsLock, OldIrql);
    02921
    02922             if (Type == DELETE_TYPE_SHARED) {
    02923
    02924                 //
    02925                 // Decrement the count of the number of views for the
    02926                 // Segment object.  This requires the PFN mutex to be held (it is already).
    02927                 //
    02928
    02929                 ControlArea = Vad->ControlArea;
    02930
    02931                 LOCK_PFN (OldIrql);
    02932                 ControlArea->NumberOfMappedViews -= 1;
    02933                 ControlArea->NumberOfUserReferences -= 1;
    02934
    02935                 //
    02936                 // Check to see if the control area (segment) should be deleted.
    02937                 // This routine releases the PFN lock.
    02938                 //
    02939
    02940                 MiCheckControlArea (ControlArea, Process, OldIrql);
    02941             }
    02942             else {
    02943                 VlmInfo->CommitCharge -= CommitReduction;
    02944             }
    02945
    02946             ExFreePool (Vad);
    02947             Vad = (PMMVAD)Process->CloneRoot;
    02948
    02949         } while (Vad != (PMMVAD)NULL);
    02950     }
    02951
    02952     //
    02953     // Delete any page directory pages.
    02954     //
    02955
    02956     PointerPde = MiGetPdeAddress64 (MM_LOWEST_USER_ADDRESS64);
    02957     PointerPte1 = MiGetPteAddress (PointerPde);
    02958     PointerPde = MiGetPdeAddress64 (MM_HIGHEST_USER_ADDRESS64);
    02959     PointerPte2 = MiGetPteAddress (PointerPde);
    02960
    02961     //
    02962     // Free the use count allocation stashed in the PDE_BASE64.
    02963     //
    02964
    02965     if (PointerPte1->u.Hard.Valid) {
    02966         ASSERT (MiGetPteAddress (PDE_BASE64) == PointerPte1);
    02967         ASSERT ((PMMPTE)PDE_BASE64 != PointerPde);
    02968         VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long);
    02969
    02970 #if DBG
    02971         ASSERT (VlmInfo->CommitCharge == 0);
    02972         ASSERT (VlmInfo->VirtualSize == 0);
    02973
    02974         {
    02975             ULONG i;
    02976             PUSHORT UsedPageTableEntries;
    02977
    02978             UsedPageTableEntries = VlmInfo->UsedPageTableEntries;
    02979
    02980             for (i = 0; i < MM_USER_PAGE_TABLE_PAGES64; i += 1) {
    02981                 ASSERT ((*UsedPageTableEntries) == 0);
    02982                 UsedPageTableEntries += 1;
    02983             }
    02984         }
    02985 #endif
    02986
    02987         ExFreePool (VlmInfo);
    02988     }
    02989
    02990     do {
    02991
    02992         PteContents = *PointerPte1;
    02993         if (PteContents.u.Hard.Valid) {
    02994
    02995             Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber);
    02996
    02997             //
    02998             // Decrement the share and valid counts of the page table
    02999             // page which maps this PTE.
    03000             //
    03001
    03002             LOCK_PFN (OldIrql);
    03003             MiDecrementShareAndValidCount (Pfn1->PteFrame);
    03004
    03005             MI_SET_PFN_DELETED (Pfn1);
    03006
    03007             //
    03008             // Decrement the share count for the physical page.  As the page
    03009             // is private it will be put on the free list.
    03010             //
    03011
    03012             MiDecrementShareCountOnly(MI_GET_PAGE_FRAME_FROM_PTE(&PteContents));
    03013             ASSERT (Pfn1->u3.e2.ReferenceCount == 0);
    03014             UNLOCK_PFN (OldIrql);
    03015         }
    03016         PointerPte1 += 1;
    03017
    03018     } while (PointerPte1 <= PointerPte2);
    03019
    03020     return;
    03021 }
    03022
    03023 VOID
    03024 MiFlushPteList64 (
    03025     IN PMMPTE_FLUSH_LIST64 PteFlushList,
    03026     IN ULONG AllProcessors,
    03027     IN MMPTE FillPte
    03028     )
    03029
    03030 /*++
    03031
    03032 Routine Description:
    03033
    03034     This routine flushes all the PTEs in the pte flush list.
    03035     Is the list has overflowed, the entire TB is flushed.
    03036
    03037 Arguments:
    03038
    03039     PteFlushList - Supplies an optional pointer to the list to be flushed.
    03040
    03041     AllProcessors - Supplies TRUE if the flush occurs on all processors.
    03042
    03043     FillPte - Supplies the PTE to fill with.
    03044
    03045 Return Value:
    03046
    03047     None.
    03048
    03049 Environment:
    03050
    03051     Kernel mode, PFN lock held.
    03052
    03053 --*/
    03054
    03055 {
    03056     ULONG count;
    03057     ULONG i = 0;
    03058
    03059     ASSERT (ARGUMENT_PRESENT (PteFlushList));
    03060     MM_PFN_LOCK_ASSERT ();
    03061
    03062     count = PteFlushList->Count;
    03063
    03064     if (count != 0) {
    03065         if (count != 1) {
    03066             if (count < MM_MAXIMUM_FLUSH_COUNT) {
    03067                 KeFlushMultipleTb64 (count,
    03068                                      &PteFlushList->FlushVpn[0],
    03069                                      TRUE,
    03070                                      (BOOLEAN)AllProcessors,
    03071                                      &((PHARDWARE_PTE)PteFlushList->FlushPte[0]),
    03072                                      FillPte.u.Flush);
    03073             } else {
    03074
    03075                 //
    03076                 // Array has overflowed, flush the entire TB.
    03077                 //
    03078
    03079                 if (AllProcessors == TRUE) {
    03080                     MiLockSystemSpaceAtDpcLevel();
    03081                     KeFlushEntireTb (TRUE, TRUE);
    03082                     MmFlushCounter = (MmFlushCounter + 1) & MM_FLUSH_COUNTER_MASK;
    03083                     MiUnlockSystemSpaceFromDpcLevel();
    03084                 } else {
    03085                     KeFlushEntireTb (TRUE, FALSE);
    03086                 }
    03087             }
    03088         } else {
    03089             KeFlushSingleTb64 (PteFlushList->FlushVpn[0],
    03090                                TRUE,
    03091                                (BOOLEAN)AllProcessors,
    03092                                (PHARDWARE_PTE)PteFlushList->FlushPte[0],
    03093                                FillPte.u.Flush);
    03094         }
    03095         PteFlushList->Count = 0;
    03096     }
    03097     return;
    03098 }
    03099
    03100 BOOLEAN
    03101 MmIsAddressValid64 (
    03102     IN PVOID64 VirtualAddress
    03103     )
    03104
    03105 /*++
    03106
    03107 Routine Description:
    03108
    03109     For a given virtual address this function returns TRUE if no page fault
    03110     will occur for a read operation on the address, FALSE otherwise.
    03111
    03112     Note that after this routine was called, if appropriate locks are not
    03113     held, a non-faulting address could fault.
    03114
    03115 Arguments:
    03116
    03117     VirtualAddress - Supplies the virtual address to check.
    03118
    03119 Return Value:
    03120
    03121     TRUE if a no page fault would be generated reading the virtual address,
    03122     FALSE otherwise.
    03123
    03124 Environment:
    03125
    03126     Kernel mode.
    03127
    03128 --*/
    03129
    03130 {
    03131     PMMPTE PointerPte;
    03132     PMMPTE PointerPde;
    03133
    03134     PointerPde = MiGetPdeAddress64 (VirtualAddress);
    03135
    03136     //
    03137     // Get Page Directory Page.
    03138     //
    03139
    03140     PointerPte = MiGetPteAddress (PointerPde);
    03141     if (PointerPte->u.Hard.Valid == 0) {
    03142         return FALSE;
    03143     }
    03144
    03145     if (PointerPde->u.Hard.Valid == 0) {
    03146         return FALSE;
    03147     }
    03148
    03149     PointerPte = MiGetPteAddress64 (VirtualAddress);
    03150     if (PointerPte->u.Hard.Valid == 0) {
    03151         return FALSE;
    03152     }
    03153     return TRUE;
    03154 }
    03155
    03156 NTSTATUS
    03157 NtMapViewOfVlmSection (
    03158     IN HANDLE SectionHandle,
    03159     IN HANDLE ProcessHandle,
    03160     IN OUT PVOID64 *BaseAddress,
    03161     IN OUT PULONGLONG SectionOffset OPTIONAL,
    03162     IN OUT PULONGLONG ViewSize,
    03163     IN ULONG AllocationType,
    03164     IN ULONG Protect
    03165     )
    03166
    03167 /*++
    03168
    03169 Routine Description:
    03170
    03171     This function maps a view in the specified subject process to
    03172     the section object.
    03173
    03174 Arguments:
    03175
    03176     SectionHandle - Supplies an open handle to a section object.
    03177
    03178     ProcessHandle - Supplies an open handle to a process object.
    03179
    03180     BaseAddress - Supplies a pointer to a variable that will receive
    03181                   the base address of the view. If the initial value
    03182                   of this argument is not null, then the view will
    03183                   be allocated starting at the specified virtual
    03184                   address rounded down to the next 64kb address
    03185                   boundary. If the initial value of this argument is
    03186                   null, then the operating system will determine
    03187                   where to allocate the view using the information
    03188                   specified by the ZeroBits argument value and the
    03189                   section allocation attributes (i.e. based and
    03190                   tiled).
    03191
    03192     SectionOffset - Supplies the offset from the beginning of the
    03193                     section to the view in bytes. This value is
    03194                     rounded down to the next host page size boundary.
    03195
    03196     ViewSize - Supplies a pointer to a variable that will receive
    03197                the actual size in bytes of the view. If the value
    03198                of this argument is zero, then a view of the
    03199                section will be mapped starting at the specified
    03200                section offset and continuing to the end of the
    03201                section. Otherwise the initial value of this
    03202                argument specifies the size of the view in bytes
    03203                and is rounded up to the next host page size
    03204                boundary.
    03205
    03206     AllocationType - Supplies the type of allocation.  Only 0 is valid.
    03207
    03208     Protect - Supplies the protection desired for the region of
    03209               initially committed pages.
    03210
    03211         Protect Values
    03212
    03213          PAGE_NOACCESS - No access to the committed region
    03214                          of pages is allowed. An attempt to read,
    03215                          write, or execute the committed region
    03216                          results in an access violation (i.e. a GP
    03217                          fault).
    03218
    03219          PAGE_READONLY - Read only and execute access to the
    03220                          committed region of pages is allowed. An
    03221                          attempt to write the committed region results
    03222                          in an access violation.
    03223
    03224          PAGE_READWRITE - Read, write, and execute access to
    03225                           the region of committed pages is allowed. If
    03226                           write access to the underlying section is
    03227                           allowed, then a single copy of the pages are
    03228                           shared. Otherwise the pages are shared read
    03229                           only/copy on write.
    03230
    03231 Return Value:
    03232
    03233     Returns the status.
    03234
    03235 --*/
    03236
    03237 {
    03238     PSECTION Section;
    03239     PEPROCESS Process;
    03240     KPROCESSOR_MODE PreviousMode;
    03241     NTSTATUS Status;
    03242     PVOID64 CapturedBase;
    03243     ULONGLONG CapturedViewSize;
    03244     ULONGLONG TempViewSize;
    03245     ULONGLONG CapturedOffset;
    03246     ACCESS_MASK DesiredSectionAccess;
    03247     ULONG ProtectMaskForAccess;
    03248     PCONTROL_AREA ControlArea;
    03249     LOGICAL Attached;
    03250     ULONG ReleasedWsMutex;
    03251
    03252     PAGED_CODE();
    03253
    03254     Attached = FALSE;
    03255
    03256     if (MI_VLM_ENABLED() == FALSE) {
    03257         return STATUS_NOT_IMPLEMENTED;
    03258     }
    03259
    03260     //
    03261     // Check the allocation type field.
    03262     //
    03263
    03264     if (AllocationType != 0) {
    03265         return STATUS_INVALID_PARAMETER_6;
    03266     }
    03267
    03268     //
    03269     // Check the protection field.  This could raise an exception.
    03270     //
    03271
    03272     try {
    03273         ProtectMaskForAccess = MiMakeProtectionMask (Protect) & 0x7;
    03274     } except (EXCEPTION_EXECUTE_HANDLER) {
    03275         return GetExceptionCode();
    03276     }
    03277
    03278     DesiredSectionAccess = MmMakeSectionAccess[ProtectMaskForAccess];
    03279
    03280     PreviousMode = KeGetPreviousMode();
    03281
    03282     //
    03283     // Establish an exception handler, probe the specified addresses
    03284     // for write access and capture the initial values.
    03285     //
    03286
    03287     CapturedOffset = 0;
    03288     try {
    03289         if (PreviousMode != KernelMode) {
    03290             ProbeForWrite (BaseAddress, sizeof(PVOID64), sizeof(PVOID64));
    03291             ProbeForWrite (ViewSize, sizeof(ULONGLONG), sizeof(ULONGLONG));
    03292             if (ARGUMENT_PRESENT (SectionOffset)) {
    03293                 if (PreviousMode != KernelMode) {
    03294                     ProbeForWrite (SectionOffset,
    03295                                    sizeof(ULONGLONG),
    03296                                    sizeof(ULONGLONG));
    03297                 }
    03298             }
    03299         }
    03300
    03301         if (ARGUMENT_PRESENT (SectionOffset)) {
    03302             CapturedOffset = *SectionOffset;
    03303         }
    03304
    03305         //
    03306         // Capture the base address.
    03307         //
    03308
    03309         CapturedBase = *BaseAddress;
    03310
    03311         //
    03312         // Capture the region size.
    03313         //
    03314
    03315         CapturedViewSize = *ViewSize;
    03316
    03317     } except (ExSystemExceptionFilter()) {
    03318
    03319         //
    03320         // If an exception occurs during the probe or capture
    03321         // of the initial values, then handle the exception and
    03322         // return the exception code as the status value.
    03323         //
    03324
    03325         return GetExceptionCode();
    03326     }
    03327
    03328     if ((ARGUMENT_PRESENT (SectionOffset)) &&
    03329         ((CapturedOffset & (X64K - 1)) != 0)) {
    03330         return STATUS_MAPPED_ALIGNMENT;
    03331     }
    03332
    03333     if (((ULONGLONG)CapturedBase & (X64K - 1)) != 0) {
    03334         return STATUS_MAPPED_ALIGNMENT;
    03335     }
    03336
    03337     //
    03338     // Make sure the specified starting and ending addresses are
    03339     // within the user part of the virtual address space.
    03340     //
    03341
    03342     if ((CapturedBase != NULL ) &&
    03343         ((CapturedBase > (PVOID64)MM_HIGHEST_USER_ADDRESS64) ||
    03344         (CapturedBase < (PVOID64)MM_LOWEST_USER_ADDRESS64))) {
    03345
    03346         //
    03347         // Invalid base address.
    03348         //
    03349
    03350         return STATUS_INVALID_PARAMETER_3;
    03351     }
    03352
    03353     if (CapturedBase != NULL) {
    03354
    03355         if ((ULONGLONG)CapturedBase + CapturedViewSize < (ULONGLONG)CapturedBase) {
    03356
    03357             //
    03358             // the requested region wraps
    03359             //
    03360
    03361             return STATUS_INVALID_PARAMETER_5;
    03362         }
    03363
    03364
    03365         if ((ULONGLONG)CapturedBase + CapturedViewSize > (ULONGLONG)MM_HIGHEST_USER_ADDRESS64 - X64K) {
    03366
    03367             //
    03368             // the requested region goes beyond the end of user memory - flag it
    03369             //
    03370
    03371             return STATUS_INVALID_PARAMETER_5;
    03372         }
    03373     }
    03374     else if (CapturedViewSize > (ULONGLONG)MM_LARGEST_VLM_RANGE - X64K) {
    03375
    03376         //
    03377         // Invalid view size;
    03378         //
    03379
    03380         return STATUS_INVALID_PARAMETER_5;
    03381     }
    03382
    03383
    03384     Status = ObReferenceObjectByHandle ( ProcessHandle,
    03385                                          PROCESS_VM_OPERATION,
    03386                                          PsProcessType,
    03387                                          PreviousMode,
    03388                                          (PVOID *)&Process,
    03389                                          NULL );
    03390     if (!NT_SUCCESS(Status)) {
    03391         return Status;
    03392     }
    03393
    03394     //
    03395     // Reference the section object, if a view is mapped to the section
    03396     // object, the object is not dereferenced as the virtual address
    03397     // descriptor contains a pointer to the section object.
    03398     //
    03399
    03400     Status = ObReferenceObjectByHandle ( SectionHandle,
    03401                                          DesiredSectionAccess,
    03402                                          MmSectionObjectType,
    03403                                          PreviousMode,
    03404                                          (PVOID *)&Section,
    03405                                          NULL );
    03406
    03407     if (!NT_SUCCESS(Status)) {
    03408         goto ErrorReturn1;
    03409     }
    03410
    03411     if (Section->Segment->ControlArea->u.Flags.Vlm == 0) {
    03412
    03413         //
    03414         // This is not a VLM section.
    03415         //
    03416
    03417         Status = STATUS_INVALID_VLM_OPERATION;
    03418         goto ErrorReturn;
    03419     }
    03420
    03421     //
    03422     // Check to make sure the section offset is within the section.
    03423     //
    03424
    03425     if ((CapturedOffset + CapturedViewSize) >
    03426                                 (ULONGLONG)Section->SizeOfSection.QuadPart) {
    03427         Status = STATUS_INVALID_VIEW_SIZE;
    03428         goto ErrorReturn;
    03429     }
    03430
    03431     if (CapturedViewSize == 0) {
    03432
    03433         //
    03434         // Set the view size to be size of the section less the offset.
    03435         //
    03436
    03437         TempViewSize = Section->SizeOfSection.QuadPart -
    03438                                                 CapturedOffset;
    03439
    03440         CapturedViewSize = TempViewSize;
    03441
    03442         if ((TempViewSize == 0) ||
    03443             (((ULONGLONG)MM_HIGHEST_VAD_ADDRESS64 - (ULONGLONG)CapturedBase) <
    03444                                                         CapturedViewSize)) {
    03445
    03446             //
    03447             // Invalid region size;
    03448             //
    03449
    03450             Status = STATUS_INVALID_VIEW_SIZE;
    03451             goto ErrorReturn;
    03452         }
    03453
    03454     } else {
    03455
    03456         //
    03457         // Check to make sure the view size plus the offset is less
    03458         // than the size of the section.
    03459         //
    03460
    03461         if ((CapturedViewSize + CapturedOffset) >
    03462                      (ULONGLONG)Section->SizeOfSection.QuadPart) {
    03463
    03464             Status = STATUS_INVALID_VIEW_SIZE;
    03465             goto ErrorReturn;
    03466         }
    03467     }
    03468
    03469     ControlArea = Section->Segment->ControlArea;
    03470
    03471     if (PsGetCurrentProcess() != Process) {
    03472         KeAttachProcess (&Process->Pcb);
    03473         Attached = TRUE;
    03474     }
    03475
    03476     //
    03477     // Get the address creation mutex to block multiple threads
    03478     // creating or deleting address space at the same time.
    03479     //
    03480
    03481     LOCK_ADDRESS_SPACE (Process);
    03482
    03483     //
    03484     // Make sure the address space was not deleted, if so, return an error.
    03485     //
    03486
    03487     if (Process->AddressSpaceDeleted != 0) {
    03488         UNLOCK_ADDRESS_SPACE (Process);
    03489         Status = STATUS_PROCESS_IS_TERMINATING;
    03490         goto ErrorReturn;
    03491     }
    03492
    03493     //
    03494     // Don't allow POSIX apps to do VLM operations.
    03495     //
    03496
    03497     if ((Process->CloneRoot != NULL) &&
    03498          (Process->ForkWasSuccessful != MM_NO_FORK_ALLOWED)) {
    03499         UNLOCK_ADDRESS_SPACE (Process);
    03500         Status = STATUS_INVALID_VLM_OPERATION;
    03501         goto ErrorReturn;
    03502     }
    03503     Process->ForkWasSuccessful = MM_NO_FORK_ALLOWED;
    03504
    03505     ReleasedWsMutex = FALSE;
    03506
    03507     Status = MiMapViewOfVlmDataSection (ControlArea,
    03508                                      Process,
    03509                                      &CapturedBase,
    03510                                      &CapturedOffset,
    03511                                      &CapturedViewSize,
    03512                                      Section,
    03513                                      ProtectMaskForAccess,
    03514                                      AllocationType,
    03515                                      &ReleasedWsMutex);
    03516
    03517     if (!ReleasedWsMutex) {
    03518         UNLOCK_WS (Process);
    03519     }
    03520     UNLOCK_ADDRESS_SPACE (Process);
    03521
    03522     if (Attached == TRUE) {
    03523         KeDetachProcess();
    03524         Attached = FALSE;
    03525     }
    03526
    03527     if (!NT_SUCCESS(Status) ) {
    03528         goto ErrorReturn;
    03529     }
    03530
    03531     //
    03532     // Establish an exception handler and write the size and base
    03533     // address.
    03534     //
    03535
    03536     try {
    03537
    03538         *ViewSize = CapturedViewSize;
    03539         *BaseAddress = CapturedBase;
    03540
    03541         if (ARGUMENT_PRESENT(SectionOffset)) {
    03542             *SectionOffset = CapturedOffset;
    03543         }
    03544
    03545     } except (EXCEPTION_EXECUTE_HANDLER) {
    03546         NOTHING;
    03547     }
    03548
    03549 ErrorReturn:
    03550     if (Attached == TRUE) {
    03551         KeDetachProcess();
    03552         Attached = FALSE;
    03553     }
    03554
    03555     ObDereferenceObject (Section);
    03556 ErrorReturn1:
    03557     ObDereferenceObject (Process);
    03558     return Status;
    03559 }
    03560
    03561 NTSTATUS
    03562 MiMapViewOfVlmDataSection (
    03563     IN PCONTROL_AREA ControlArea,
    03564     IN PEPROCESS Process,
    03565     IN PVOID64 *CapturedBase,
    03566     IN PULONGLONG SectionOffset,
    03567     IN PULONGLONG CapturedViewSize,
    03568     IN PSECTION Section,
    03569     IN ULONG ProtectionMask,
    03570     IN ULONG AllocationType,
    03571     IN PULONG ReleasedWsMutex
    03572     )
    03573
    03574 /*++
    03575
    03576 Routine Description:
    03577
    03578     This routine maps the specified physical section into the
    03579     specified process's address space.
    03580
    03581 Arguments:
    03582
    03583     See NtMapViewOfVlmSection above...
    03584
    03585     ControlArea - Supplies the control area for the section.
    03586
    03587     Process - Supplies the process pointer which is receiving the section.
    03588
    03589     ProtectionMask - Supplies the initial page protection-mask.
    03590
    03591     ReleasedWsMutex - Supplies FALSE. If the working set mutex is
    03592                       not held when returning this must be set to TRUE
    03593                       so the caller will release the mutex.
    03594
    03595 Return Value:
    03596
    03597     Status of the map view operation.
    03598
    03599 Environment:
    03600
    03601     Kernel Mode, working set mutex and address creation mutex held.
    03602
    03603 --*/
    03604
    03605 {
    03606     PMMVAD Vad;
    03607     volatile PVOID64 Va;
    03608     PVOID64 StartingAddress;
    03609     PVOID64 EndingAddress;
    03610     KIRQL OldIrql;
    03611     PSUBSECTION Subsection;
    03612     ULONG PteOffset;
    03613     PMMPTE PointerPte;
    03614     PMMPTE LastPte;
    03615     MMPTE TempPte;
    03616     ULONG QuotaCharge;
    03617     PMMPTE TheFirstPrototypePte;
    03618     PMMPTE Pde;
    03619     PMMPTE LastPde;
    03620     LOGICAL PdeBuilt;
    03621     NTSTATUS ReturnStatus;
    03622     PMI_PROCESS_VLM_INFO VlmInfo;
    03623
    03624     //
    03625     // Check to see if a purge operation is in progress and if so, wait
    03626     // for the purge to complete.  In addition, up the count of mapped
    03627     // views for this control area.
    03628     //
    03629
    03630     if ((Process->CloneRoot != NULL) &&
    03631          (Process->ForkWasSuccessful != MM_NO_FORK_ALLOWED)) {
    03632         *ReleasedWsMutex = TRUE;
    03633         return STATUS_INVALID_VLM_OPERATION;
    03634     }
    03635
    03636     QuotaCharge = 0;
    03637
    03638     Process->ForkWasSuccessful = MM_NO_FORK_ALLOWED;
    03639
    03640     MiCheckPurgeAndUpMapCount (ControlArea);
    03641
    03642     //
    03643     // Calculate the first prototype PTE field in the Vad.
    03644     //
    03645
    03646     ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0);
    03647
    03648     Subsection = (PSUBSECTION)(ControlArea + 1);
    03649
    03650     *SectionOffset = (ULONGLONG)MI_ALIGN_TO_SIZE64 (*SectionOffset, X64K);
    03651     PteOffset = (ULONG)(*SectionOffset >> PAGE_SHIFT);
    03652
    03653     //
    03654     // Make sure the PTEs are not in the extended part of the
    03655     // segment.
    03656     //
    03657
    03658     while (PteOffset >= Subsection->PtesInSubsection) {
    03659         PteOffset -= Subsection->PtesInSubsection;
    03660         Subsection = Subsection->NextSubsection;
    03661         ASSERT (Subsection != NULL);
    03662     }
    03663
    03664     TheFirstPrototypePte = &Subsection->SubsectionBase[PteOffset];
    03665
    03666 //fixfix - make copy on write invalid    CapturedCopyOnWrite = Section->u.Flags.CopyOnWrite;
    03667
    03668     LOCK_WS (Process);
    03669
    03670     if (*CapturedBase == NULL) {
    03671
    03672         //
    03673         // The section is not based, find an empty range.
    03674         // This could raise an exception.
    03675
    03676         try {
    03677
    03678             //
    03679             // Find a starting address on a 64k boundary.
    03680             //
    03681
    03682             StartingAddress = MiFindEmptyAddressRangeInTree64 (
    03683                                *CapturedViewSize,
    03684                                X64K,
    03685                                (PMMADDRESS_NODE)(Process->CloneRoot));
    03686
    03687         } except (EXCEPTION_EXECUTE_HANDLER) {
    03688
    03689             LOCK_PFN (OldIrql);
    03690             ControlArea->NumberOfMappedViews -= 1;
    03691             ControlArea->NumberOfUserReferences -= 1;
    03692             UNLOCK_PFN (OldIrql);
    03693             return GetExceptionCode();
    03694         }
    03695
    03696         EndingAddress = (PVOID64)(((ULONGLONG)StartingAddress +
    03697                                    *CapturedViewSize - 1L) | (PAGE_SIZE - 1L));
    03698
    03699     } else {
    03700
    03701         StartingAddress = MI_ALIGN_TO_SIZE64 (*CapturedBase, X64K);
    03702
    03703         //
    03704         // Check to make sure the specified base address to ending address
    03705         // is currently unused.
    03706         //
    03707
    03708         EndingAddress = (PVOID64)(((ULONGLONG)StartingAddress +
    03709                                    *CapturedViewSize - 1L) | (PAGE_SIZE - 1L));
    03710
    03711         Vad = MiCheckForConflictingVad64 (StartingAddress, EndingAddress);
    03712         if (Vad != (PMMVAD)NULL) {
    03713             LOCK_PFN (OldIrql);
    03714             ControlArea->NumberOfMappedViews -= 1;
    03715             ControlArea->NumberOfUserReferences -= 1;
    03716             UNLOCK_PFN (OldIrql);
    03717             return STATUS_CONFLICTING_ADDRESSES;
    03718         }
    03719     }
    03720
    03721     //
    03722     // An unoccupied address range has been found, build the virtual
    03723     // address descriptor to describe this range.
    03724     //
    03725
    03726     try  {
    03727
    03728         Vad = ExAllocatePoolWithTag (NonPagedPool,
    03729                                      sizeof(MMVAD),
    03730                                      MMVADKEY);
    03731         if (Vad == NULL) {
    03732             ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
    03733         }
    03734         RtlZeroMemory (Vad, sizeof(MMVAD));
    03735
    03736         Vad->StartingVpn = MI_VA_TO_VPN64 (StartingAddress);
    03737         Vad->EndingVpn = MI_VA_TO_VPN64 (EndingAddress);
    03738         Vad->FirstPrototypePte = TheFirstPrototypePte;
    03739
    03740         //
    03741         // The protection is in the PTE template field of the VAD.
    03742         //
    03743
    03744         Vad->ControlArea = ControlArea;
    03745
    03746         Vad->u2.VadFlags2.Inherit = 0;
    03747         Vad->u.VadFlags.Protection = ProtectionMask;
    03748         Vad->u2.VadFlags2.CopyOnWrite = 0; //fixfix
    03749
    03750         Vad->u2.VadFlags2.FileOffset = (ULONG)(*SectionOffset >> 16);
    03751
    03752         PteOffset += (ULONG) (Vad->EndingVpn - Vad->StartingVpn);
    03753
    03754         if (PteOffset < Subsection->PtesInSubsection ) {
    03755             Vad->LastContiguousPte = &Subsection->SubsectionBase[PteOffset];
    03756
    03757         } else {
    03758             Vad->LastContiguousPte = &Subsection->SubsectionBase[
    03759                                         (Subsection->PtesInSubsection - 1) +
    03760                                         Subsection->UnusedPtes];
    03761         }
    03762
    03763         ASSERT (Vad->FirstPrototypePte <= Vad->LastContiguousPte);
    03764         MiInsertVad64 (Vad);
    03765
    03766     } except (EXCEPTION_EXECUTE_HANDLER) {
    03767
    03768         LOCK_PFN (OldIrql);
    03769         ControlArea->NumberOfMappedViews -= 1;
    03770         ControlArea->NumberOfUserReferences -= 1;
    03771         UNLOCK_PFN (OldIrql);
    03772
    03773         if (Vad != (PMMVAD)NULL) {
    03774
    03775             //
    03776             // The pool allocation succeeded, but the quota charge
    03777             // in InsertVad failed, deallocate the pool and return
    03778             // an error.
    03779             //
    03780
    03781             ExFreePool (Vad);
    03782             return GetExceptionCode();
    03783         }
    03784         return STATUS_INSUFFICIENT_RESOURCES;
    03785     }
    03786
    03787     //
    03788     // Build the top level page directory page to describe this range.
    03789     // The individual page table pages are materialized when the process
    03790     // faults.
    03791     //
    03792
    03793     Pde = MiGetPdeAddress64 (StartingAddress);
    03794     PdeBuilt = MiMakePdeExistAndMakeValid64 (Pde, Process, FALSE, FALSE);
    03795
    03796     if (PdeBuilt == FALSE) {
    03797         ASSERT (Pde == MiGetPdeAddress64 (StartingAddress));
    03798         LOCK_PFN (OldIrql);
    03799         ControlArea->NumberOfMappedViews -= 1;
    03800         ControlArea->NumberOfUserReferences -= 1;
    03801         UNLOCK_PFN (OldIrql);
    03802         MiRemoveVad64 (Vad);
    03803         ExFreePool (Vad);
    03804         return STATUS_INSUFFICIENT_RESOURCES;
    03805     }
    03806
    03807     *ReleasedWsMutex = TRUE;
    03808     UNLOCK_WS (Process);
    03809
    03810     //
    03811     // Update the current virtual size in the process header.
    03812     //
    03813
    03814     *CapturedViewSize = (char * POINTER_64)EndingAddress - (char * POINTER_64)StartingAddress + 1L;
    03815
    03816     VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long);
    03817     VlmInfo->VirtualSize += *CapturedViewSize;
    03818     if (VlmInfo->VirtualSize > VlmInfo->VirtualSizePeak) {
    03819         VlmInfo->VirtualSizePeak = VlmInfo->VirtualSize;
    03820     }
    03821
    03822     *CapturedBase = StartingAddress;
    03823
    03824     return STATUS_SUCCESS;
    03825 }
    03826
    03827 NTSTATUS
    03828 NtUnmapViewOfVlmSection(
    03829     IN HANDLE ProcessHandle,
    03830     IN OUT PVOID64 *BaseAddress
    03831     )
    03832
    03833 /*++
    03834
    03835 Routine Description:
    03836
    03837     This function unmaps a previously created view to a section.
    03838
    03839 Arguments:
    03840
    03841     ProcessHandle - Supplies an open handle to a process object.
    03842
    03843     BaseAddress - Supplies the base address of the view.
    03844
    03845 Return Value:
    03846
    03847     Returns the status
    03848
    03849     TBS
    03850
    03851
    03852 --*/
    03853
    03854 {
    03855     PEPROCESS Process;
    03856     KPROCESSOR_MODE PreviousMode;
    03857     PMMVAD Vad;
    03858     ULONGLONG RegionSize;
    03859     PVOID64 UnMapImageBase;
    03860     PVOID64 CapturedBase;
    03861     NTSTATUS status;
    03862     PMMPTE StartingPte;
    03863     PMMPTE EndingPte;
    03864     PCONTROL_AREA ControlArea;
    03865     KIRQL OldIrql;
    03866     ULONG CommitReduction;
    03867     PMI_PROCESS_VLM_INFO VlmInfo;
    03868
    03869     if (MI_VLM_ENABLED() == FALSE) {
    03870         return STATUS_NOT_IMPLEMENTED;
    03871     }
    03872
    03873     PreviousMode = KeGetPreviousMode();
    03874
    03875     status = ObReferenceObjectByHandle ( ProcessHandle,
    03876                                          PROCESS_VM_OPERATION,
    03877                                          PsProcessType,
    03878                                          PreviousMode,
    03879                                          (PVOID *)&Process,
    03880                                          NULL );
    03881     if (!NT_SUCCESS(status)) {
    03882         return status;
    03883     }
    03884
    03885     UnMapImageBase = NULL;
    03886
    03887     //
    03888     // If the specified process is not the current process, attach
    03889     // to the specified process.
    03890     //
    03891
    03892     KeAttachProcess (&Process->Pcb);
    03893
    03894     //
    03895     // Probe and capture the specified address
    03896     //
    03897
    03898     PreviousMode = KeGetPreviousMode();
    03899
    03900     if (PreviousMode != KernelMode) {
    03901         try {
    03902             ProbeForRead (BaseAddress, sizeof(PVOID64), sizeof(PVOID64));
    03903
    03904             //
    03905             // Capture the base address.
    03906             //
    03907
    03908             CapturedBase = *BaseAddress;
    03909         } except (ExSystemExceptionFilter()) {
    03910
    03911             //
    03912             // If an exception occurs during the probe or capture
    03913             // of the initial value, then handle the exception and
    03914             // return the exception code as the status value.
    03915             //
    03916
    03917             KeDetachProcess();
    03918             ObDereferenceObject (Process);
    03919             return GetExceptionCode();
    03920         }
    03921     }
    03922     else {
    03923         CapturedBase = *BaseAddress;
    03924     }
    03925
    03926     //
    03927     // Get the address creation mutex to block multiple threads from
    03928     // creating or deleting address space at the same time and
    03929     // get the working set mutex so virtual address descriptors can
    03930     // be inserted and walked.  Raise IRQL to block APCs.
    03931     //
    03932     // Get the working set mutex, no page faults allowed for now until
    03933     // working set mutex released.
    03934     //
    03935
    03936     LOCK_WS_AND_ADDRESS_SPACE (Process);
    03937
    03938     //
    03939     // Make sure the address space was not deleted, if so, return an error.
    03940     //
    03941
    03942     if (Process->AddressSpaceDeleted != 0) {
    03943         status = STATUS_PROCESS_IS_TERMINATING;
    03944         goto ErrorReturn;
    03945     }
    03946
    03947     if (Process->ForkWasSuccessful != MM_NO_FORK_ALLOWED) {
    03948         status = STATUS_NOT_MAPPED_VIEW;
    03949         goto ErrorReturn;
    03950     }
    03951
    03952     //
    03953     // Find the associated Vad.
    03954     //
    03955
    03956     Vad = (PMMVAD)MiLocateAddress64 (MI_VA_TO_VPN64 (CapturedBase));
    03957
    03958     if ((Vad == (PMMVAD)NULL) || (Vad->u.VadFlags.PrivateMemory)) {
    03959
    03960         //
    03961         // No Virtual Address Descriptor located for Base Address.
    03962         //
    03963
    03964         status = STATUS_NOT_MAPPED_VIEW;
    03965         goto ErrorReturn;
    03966     }
    03967
    03968     ASSERT (Vad->u.VadFlags.NoChange == 0);
    03969
    03970     RegionSize = PAGE_SIZE + (((ULONGLONG)(Vad->EndingVpn - Vad->StartingVpn)) << PAGE_SHIFT);
    03971
    03972     MiRemoveVad64 (Vad);
    03973
    03974 #if 0
    03975     //
    03976     // Return commitment for page table pages if possible.
    03977     //
    03978
    03979     MiReturnPageTablePageCommitment (MI_VPN_TO_VA (Vad->StartingVpn),
    03980                                      MI_VPN_TO_VA_ENDING (Vad->EndingVpn),
    03981                                      Process,
    03982                                      PreviousVad,
    03983                                      NextVad);
    03984 #endif //0
    03985
    03986     StartingPte = MiGetPteAddress64 (MI_VPN_TO_VA64 (Vad->StartingVpn));
    03987     EndingPte = MiGetPteAddress64 (MI_VPN_TO_VA64 (Vad->EndingVpn));
    03988
    03989     CommitReduction = MiDecommitOrDeletePages64 (StartingPte,
    03990                                                  EndingPte,
    03991                                                  Process,
    03992                                                  DELETE_TYPE_SHARED,
    03993                                                  TRUE);
    03994
    03995
    03996     //
    03997     // Decrement the count of the number of views for the
    03998     // Segment object.  This requires the PFN mutex to be held (it is already).
    03999     //
    04000
    04001     ControlArea = Vad->ControlArea;
    04002     LOCK_PFN (OldIrql);
    04003     ControlArea->NumberOfMappedViews -= 1;
    04004     ControlArea->NumberOfUserReferences -= 1;
    04005
    04006     //
    04007     // Check to see if the control area (segment) should be deleted.
    04008     // This routine releases the PFN lock.
    04009     //
    04010
    04011     MiCheckControlArea (ControlArea, Process, OldIrql);
    04012
    04013     ExFreePool (Vad);
    04014
    04015     //
    04016     // Update the current virtual size in the process header.
    04017     //
    04018
    04019     VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long);
    04020     VlmInfo->VirtualSize -= RegionSize;
    04021
    04022     status = STATUS_SUCCESS;
    04023
    04024 ErrorReturn:
    04025
    04026     UNLOCK_WS (Process);
    04027     UNLOCK_ADDRESS_SPACE (Process);
    04028
    04029     KeDetachProcess();
    04030     ObDereferenceObject (Process);
    04031
    04032     return status;
    04033 }
    04034
    04035
    04036 NTSTATUS
    04037 NtProtectVirtualMemory64(
    04038     IN HANDLE ProcessHandle,
    04039     IN OUT PVOID64 *BaseAddress,
    04040     IN OUT PULONGLONG RegionSize,
    04041     IN ULONG NewProtect,
    04042     OUT PULONG OldProtect
    04043     )
    04044
    04045 {
    04046     PEPROCESS Process;
    04047     KPROCESSOR_MODE PreviousMode;
    04048     NTSTATUS Status;
    04049     LOGICAL Attached;
    04050     PVOID64 CapturedBase;
    04051     ULONGLONG CapturedRegionSize;
    04052     ULONG ProtectionMask;
    04053     PMMVAD FoundVad;
    04054     PVOID64 StartingAddress;
    04055     PVOID64 EndingAddress;
    04056     PMMPTE PointerPte;
    04057     PMMPTE LastPte;
    04058     PMMPTE PointerPde;
    04059     PMMPTE PointerProtoPte;
    04060     PMMPTE LastProtoPte;
    04061     PMMPFN Pfn1;
    04062     ULONG CapturedOldProtect;
    04063     MMPTE TempPte;
    04064     MMPTE PteContents;
    04065     PVOID64 Va;
    04066     ULONG DoAgain;
    04067     PMI_PROCESS_VLM_INFO VlmInfo;
    04068     PMMPTE LowestPde;
    04069
    04070     PAGED_CODE();
    04071
    04072     Attached = FALSE;
    04073
    04074     //
    04075     // Check the protection field.  This could raise an exception.
    04076     //
    04077
    04078     if ((NewProtect & PAGE_GUARD) ||
    04079         (NewProtect & PAGE_NOCACHE)) {
    04080         return STATUS_INVALID_PAGE_PROTECTION;
    04081     }
    04082
    04083     try {
    04084         ProtectionMask = MiMakeProtectionMask (NewProtect);
    04085     } except (EXCEPTION_EXECUTE_HANDLER) {
    04086         return GetExceptionCode();
    04087     }
    04088
    04089     PreviousMode = KeGetPreviousMode();
    04090
    04091     if (PreviousMode != KernelMode) {
    04092
    04093         //
    04094         // Capture the region size and base address under an exception handler.
    04095         //
    04096
    04097         try {
    04098
    04099             ProbeForWrite (BaseAddress, sizeof(PVOID64), sizeof(PVOID64));
    04100             ProbeForWrite (RegionSize, sizeof(ULONGLONG), sizeof(ULONGLONG));
    04101             ProbeForWriteUlong (OldProtect);
    04102
    04103             //
    04104             // Capture the region size and base address.
    04105             //
    04106
    04107             CapturedBase = *BaseAddress;
    04108             CapturedRegionSize = *RegionSize;
    04109
    04110         } except (EXCEPTION_EXECUTE_HANDLER) {
    04111
    04112             //
    04113             // If an exception occurs during the probe or capture
    04114             // of the initial values, then handle the exception and
    04115             // return the exception code as the status value.
    04116             //
    04117
    04118             return GetExceptionCode();
    04119         }
    04120
    04121     } else {
    04122
    04123         //
    04124         // Capture the region size and base address.
    04125         //
    04126
    04127         CapturedRegionSize = *RegionSize;
    04128         CapturedBase = *BaseAddress;
    04129     }
    04130
    04131     //
    04132     // Make sure the specified starting and ending addresses are
    04133     // within the user part of the virtual address space.
    04134     //
    04135
    04136     if (CapturedBase > (PVOID64)MM_HIGHEST_USER_ADDRESS64) {
    04137
    04138         //
    04139         // Invalid base address.
    04140         //
    04141
    04142         return STATUS_INVALID_PARAMETER_2;
    04143     }
    04144
    04145     if ((ULONGLONG)MM_HIGHEST_USER_ADDRESS64 - (ULONGLONG)CapturedBase <
    04146                                                         CapturedRegionSize) {
    04147
    04148         //
    04149         // Invalid region size;
    04150         //
    04151
    04152         return STATUS_INVALID_PARAMETER_3;
    04153     }
    04154
    04155     if (CapturedRegionSize == 0) {
    04156         return STATUS_INVALID_PARAMETER_3;
    04157     }
    04158
    04159     Status = ObReferenceObjectByHandle ( ProcessHandle,
    04160                                          PROCESS_VM_OPERATION,
    04161                                          PsProcessType,
    04162                                          PreviousMode,
    04163                                          (PVOID *)&Process,
    04164                                          NULL );
    04165
    04166     if (!NT_SUCCESS(Status)) {
    04167         return Status;
    04168     }
    04169
    04170     //
    04171     // If the specified process is not the current process, attach
    04172     // to the specified process.
    04173     //
    04174
    04175     if (PsGetCurrentProcess() != Process) {
    04176         KeAttachProcess (&Process->Pcb);
    04177         Attached = TRUE;
    04178     }
    04179
    04180
    04181     //
    04182     // Get the address creation mutex to block multiple threads from
    04183     // creating or deleting address space at the same time.
    04184     // Get the working set mutex so PTEs can be modified.
    04185     // Block APCs so an APC which takes a page
    04186     // fault does not corrupt various structures.
    04187     //
    04188
    04189     LOCK_WS_AND_ADDRESS_SPACE (Process);
    04190
    04191     //
    04192     // Make sure the address space was not deleted, if so, return an error.
    04193     //
    04194
    04195     if (Process->AddressSpaceDeleted != 0) {
    04196         Status = STATUS_PROCESS_IS_TERMINATING;
    04197         goto ErrorFound;
    04198     }
    04199
    04200     EndingAddress = (PVOID64)(((ULONGLONG)CapturedBase + CapturedRegionSize - 1) |
    04201                         (PAGE_SIZE - 1));
    04202     StartingAddress = (PVOID64)PAGE_ALIGN64(CapturedBase);
    04203
    04204     FoundVad = MiCheckForConflictingVad64 (StartingAddress, EndingAddress);
    04205
    04206     if (FoundVad == NULL) {
    04207
    04208         //
    04209         // No virtual address is reserved at the specified base address,
    04210         // return an error.
    04211         //
    04212
    04213         Status = STATUS_CONFLICTING_ADDRESSES;
    04214         goto ErrorFound;
    04215     }
    04216
    04217     //
    04218     // Ensure that the starting and ending addresses are all within
    04219     // the same virtual address descriptor.
    04220     //
    04221
    04222     if ((MI_VA_TO_VPN64 (StartingAddress) < FoundVad->StartingVpn) ||
    04223         (MI_VA_TO_VPN64 (EndingAddress) > FoundVad->EndingVpn)) {
    04224
    04225         //
    04226         // Not within the section virtual address descriptor,
    04227         // return an error.
    04228         //
    04229
    04230         Status = STATUS_CONFLICTING_ADDRESSES;
    04231         goto ErrorFound;
    04232     }
    04233
    04234     ASSERT (FoundVad->u.VadFlags.PhysicalMapping == 0);
    04235     ASSERT (FoundVad->u.VadFlags.NoChange == 0);
    04236
    04237     if (FoundVad->u.VadFlags.PrivateMemory == 0) {
    04238
    04239
    04240         //
    04241         // For mapped sections, the NO_CACHE and the COPY_ON_WRITE attribute
    04242         // are not allowed.
    04243         //
    04244
    04245         if ((NewProtect & PAGE_NOCACHE) ||
    04246             (ProtectionMask & MM_COPY_ON_WRITE_MASK)) {
    04247
    04248             //
    04249             // Not allowed.
    04250             //
    04251
    04252             Status = STATUS_INVALID_PARAMETER_4;
    04253             goto ErrorFound;
    04254         }
    04255
    04256         //
    04257         // If this is a file mapping, then all pages must be
    04258         // committed as there can be no sparse file maps. Images
    04259         // can have non-committed pages if the alignment is greater
    04260         // than the page size.
    04261         //
    04262
    04263         if ((FoundVad->ControlArea->u.Flags.File == 0) ||
    04264             (FoundVad->ControlArea->u.Flags.Image == 1)) {
    04265
    04266             PointerProtoPte = MiGetProtoPteAddress (FoundVad,
    04267                                         MI_VA_TO_VPN64 (StartingAddress));
    04268             LastProtoPte = MiGetProtoPteAddress (FoundVad,
    04269                                         MI_VA_TO_VPN64 (EndingAddress));
    04270
    04271             //
    04272             // Release the working set mutex and acquire the section
    04273             // commit mutex.  Check all the prototype PTEs described by
    04274             // the virtual address range to ensure they are committed.
    04275             //
    04276
    04277             UNLOCK_WS (Process);
    04278             ExAcquireFastMutex (&MmSectionCommitMutex);
    04279
    04280             while (PointerProtoPte <= LastProtoPte) {
    04281
    04282                 //
    04283                 // Check to see if the prototype PTE is committed, if
    04284                 // not return an error.
    04285                 //
    04286
    04287                 if (PointerProtoPte->u.Long == 0) {
    04288
    04289                     //
    04290                     // Error, this prototype PTE is not committed.
    04291                     //
    04292
    04293                     ExReleaseFastMutex (&MmSectionCommitMutex);
    04294                     Status = STATUS_NOT_COMMITTED;
    04295                     goto ErrorFoundNoWs;
    04296                 }
    04297                 PointerProtoPte += 1;
    04298             }
    04299
    04300             //
    04301             // The range is committed, release the section commitment
    04302             // mutex, acquire the working set mutex and update the local PTEs.
    04303             //
    04304
    04305             ExReleaseFastMutex (&MmSectionCommitMutex);
    04306
    04307             //
    04308             // Set the protection on the section pages.  This could
    04309             // get a quota exceeded exception.
    04310             //
    04311
    04312             LOCK_WS (Process);
    04313         }
    04314
    04315         //
    04316         // Set the protection on the pages.
    04317         //
    04318
    04319         //
    04320         // The address range is committed, change the protection.
    04321         //
    04322
    04323         PointerPde = MiGetPdeAddress64 (StartingAddress);
    04324         PointerPte = MiGetPteAddress64 (StartingAddress);
    04325         LastPte = MiGetPteAddress64 (EndingAddress);
    04326
    04327         MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE);
    04328
    04329         //
    04330         // Capture the protection for the first page.
    04331         //
    04332
    04333         if (PointerPte->u.Long != 0) {
    04334
    04335             CapturedOldProtect = PAGE_READWRITE;
    04336             if (PointerPte->u.Hard.Valid == 1) {
    04337                 if (PointerPte->u.Hard.Write == 0) {
    04338                     CapturedOldProtect = PAGE_READONLY;
    04339                 }
    04340             } else {
    04341                 ASSERT (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED);
    04342                 ASSERT (PointerPte->u.Soft.Prototype == 1);
    04343                 CapturedOldProtect =
    04344                     MI_CONVERT_FROM_PTE_PROTECTION (PointerPte->u.Soft.Protection);
    04345             }
    04346
    04347         } else {
    04348
    04349             //
    04350             // Get the protection from the VAD.
    04351             //
    04352
    04353             CapturedOldProtect =
    04354                MI_CONVERT_FROM_PTE_PROTECTION(FoundVad->u.VadFlags.Protection);
    04355         }
    04356
    04357         LowestPde = MiGetPdeAddress64 (MM_LOWEST_USER_ADDRESS64);
    04358         VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long);
    04359
    04360         //
    04361         // For all the PTEs in the specified address range, set the
    04362         // protection depending on the state of the PTE.
    04363         //
    04364
    04365         while (PointerPte <= LastPte) {
    04366
    04367             if (MiIsPteOnPdeBoundary(PointerPte)) {
    04368
    04369                 PointerPde = MiGetPteAddress (PointerPte);
    04370
    04371                 MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE);
    04372             }
    04373
    04374             PteContents = *PointerPte;
    04375
    04376             if (PteContents.u.Hard.Valid == 1) {
    04377
    04378                 if (ProtectionMask != MM_NOACCESS) {
    04379
    04380                     //
    04381                     // Set the protection into both the PTE and the original PTE
    04382                     // in the PFN database.
    04383                     //
    04384
    04385                     Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber);
    04386
    04387                     ASSERT (Pfn1->u3.e1.PrototypePte == 1);
    04388
    04389                     //
    04390                     // The PTE is a private page which is valid, if the
    04391                     // specified protection is no-access or guard page
    04392                     // remove the PTE from the working set.
    04393                     //
    04394
    04395                     MI_MAKE_VALID_PTE (TempPte,
    04396                                        PointerPte->u.Hard.PageFrameNumber,
    04397                                        ProtectionMask,
    04398                                        NULL);
    04399                     if (TempPte.u.Hard.Write) {
    04400                         MI_SET_PTE_DIRTY (TempPte);
    04401                     }
    04402
    04403                     //
    04404                     // Flush the TB as we have changed the protection
    04405                     // of a valid PTE.
    04406                     //
    04407
    04408                     MiFlushTbAndCapture (PointerPte,
    04409                                          TempPte.u.Flush,
    04410                                          Pfn1);
    04411                 } else {
    04412
    04413                     //
    04414                     // No access, remove page from memory.
    04415                     //
    04416
    04417                     MiMakeValidPageNoAccess64 (PointerPte);
    04418                 }
    04419
    04420             } else {
    04421
    04422                 if (PointerPte->u.Long == ZeroPte.u.Long) {
    04423                     *PointerPte = PrototypePte;
    04424                     PointerPte->u.Soft.Protection = ProtectionMask;
    04425
    04426                     VlmInfo->UsedPageTableEntries[PointerPde - LowestPde] += 1;
    04427
    04428                 } else {
    04429                     ASSERT (PointerPte->u.Soft.Prototype == 1);
    04430                     ASSERT (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED);
    04431                     PointerPte->u.Soft.Protection = ProtectionMask;
    04432                 }
    04433             }
    04434             PointerPte += 1;
    04435         } //end while
    04436
    04437     } else {
    04438
    04439         //
    04440         // Not a section, private.
    04441         // For private pages, the WRITECOPY attribute is not allowed.
    04442         //
    04443
    04444         if ((NewProtect & PAGE_WRITECOPY) ||
    04445             (NewProtect & PAGE_EXECUTE_WRITECOPY)) {
    04446
    04447             //
    04448             // Not allowed.
    04449             //
    04450
    04451             Status = STATUS_INVALID_PARAMETER_4;
    04452             goto ErrorFound;
    04453         }
    04454
    04455         //
    04456         // Ensure all of the pages are already committed as described
    04457         // in the virtual address descriptor.
    04458         //
    04459
    04460         if ( !MiIsEntireRangeCommitted64 (StartingAddress,
    04461                                           EndingAddress,
    04462                                           FoundVad,
    04463                                           Process)) {
    04464
    04465             //
    04466             // Previously reserved pages have been decommitted, or an error
    04467             // occurred, release mutex and return status.
    04468             //
    04469
    04470             Status = STATUS_NOT_COMMITTED;
    04471             goto ErrorFound;
    04472         }
    04473
    04474         //
    04475         // The address range is committed, change the protection.
    04476         //
    04477
    04478         PointerPde = MiGetPdeAddress64 (StartingAddress);
    04479         PointerPte = MiGetPteAddress64 (StartingAddress);
    04480         LastPte = MiGetPteAddress64 (EndingAddress);
    04481
    04482         MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE);
    04483
    04484         //
    04485         // Capture the protection for the first page.
    04486         //
    04487
    04488         if (PointerPte->u.Long != 0) {
    04489
    04490             CapturedOldProtect = MiGetPageProtection (PointerPte, Process);
    04491
    04492         } else {
    04493
    04494             //
    04495             // Get the protection from the VAD.
    04496             //
    04497
    04498             CapturedOldProtect =
    04499                MI_CONVERT_FROM_PTE_PROTECTION(FoundVad->u.VadFlags.Protection);
    04500         }
    04501
    04502         //
    04503         // For all the PTEs in the specified address range, set the
    04504         // protection depending on the state of the PTE.
    04505         //
    04506
    04507         while (PointerPte <= LastPte) {
    04508
    04509             if (MiIsPteOnPdeBoundary(PointerPte)) {
    04510
    04511                 PointerPde = MiGetPteAddress (PointerPte);
    04512
    04513                 MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE);
    04514             }
    04515
    04516             PteContents = *PointerPte;
    04517
    04518             if (PteContents.u.Hard.Valid == 1) {
    04519
    04520                 if (ProtectionMask != MM_NOACCESS) {
    04521
    04522                     //
    04523                     // Set the protection into both the PTE and the original PTE
    04524                     // in the PFN database.
    04525                     //
    04526
    04527                     Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber);
    04528
    04529                     Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
    04530                     MI_MAKE_VALID_PTE (TempPte,
    04531                                        PointerPte->u.Hard.PageFrameNumber,
    04532                                        ProtectionMask,
    04533                                        NULL);
    04534                     if (TempPte.u.Hard.Write) {
    04535                         MI_SET_PTE_DIRTY (TempPte);
    04536                     }
    04537
    04538                     //
    04539                     // Flush the TB as we have changed the protection
    04540                     // of a valid PTE.
    04541                     //
    04542
    04543                     MiFlushTbAndCapture (PointerPte,
    04544                                          TempPte.u.Flush,
    04545                                          Pfn1);
    04546                 } else {
    04547
    04548                     //
    04549                     // No access, remove page from memory, make it transition.
    04550                     //
    04551
    04552                     MiMakeValidPageNoAccess64 (PointerPte);
    04553                 }
    04554             } else {
    04555
    04556                 //
    04557                 // the page is not present.
    04558                 //
    04559
    04560                 if (PteContents.u.Soft.Transition == 1) {
    04561
    04562                     //
    04563                     // The only reason a PTE would be transition is if it has
    04564                     // been made no access.  If the protection is not no access,
    04565                     // make it valid with the right protection.  otherwise, it
    04566                     // is already in the desired state, so don't do anything.
    04567                     //
    04568
    04569                     if (ProtectionMask != MM_NOACCESS) {
    04570                         MiMakeNoAccessPageValid64 (PointerPte, ProtectionMask);
    04571                     }
    04572
    04573                 } else {
    04574
    04575                     //
    04576                     // Must be page file space or demand zero.
    04577                     //
    04578
    04579                     PointerPte->u.Soft.Protection = ProtectionMask;
    04580                     ASSERT (PointerPte->u.Long != 0);
    04581                 }
    04582             }
    04583             PointerPte += 1;
    04584         } //end while
    04585     }
    04586
    04587     //
    04588     // Common completion code.
    04589     //
    04590
    04591     CapturedRegionSize = (char * POINTER_64)EndingAddress - (char * POINTER_64)StartingAddress + 1L;
    04592
    04593     Status = STATUS_SUCCESS;
    04594
    04595 ErrorFound:
    04596
    04597     UNLOCK_WS (Process);
    04598 ErrorFoundNoWs:
    04599
    04600     UNLOCK_ADDRESS_SPACE (Process);
    04601
    04602     if (Attached) {
    04603         KeDetachProcess();
    04604     }
    04605
    04606     ObDereferenceObject (Process);
    04607
    04608     //
    04609     // Establish an exception handler and write the size and base
    04610     // address.
    04611     //
    04612
    04613     try {
    04614
    04615         //
    04616         // Reprobe the addresses as certain architectures (intel 386 for one)
    04617         // do not trap kernel writes.  This is the one service which allows
    04618         // the protection of the page to change between the initial probe
    04619         // and the final argument update.
    04620         //
    04621
    04622         if (PreviousMode != KernelMode) {
    04623
    04624             ProbeForWrite (BaseAddress, sizeof(PVOID64), sizeof(PVOID64));
    04625             ProbeForWrite (RegionSize, sizeof(ULONGLONG), sizeof(ULONGLONG));
    04626             ProbeForWriteUlong (OldProtect);
    04627         }
    04628
    04629         *RegionSize = CapturedRegionSize;
    04630         *BaseAddress = StartingAddress;
    04631         *OldProtect = CapturedOldProtect;
    04632
    04633     } except (EXCEPTION_EXECUTE_HANDLER) {
    04634         NOTHING;
    04635     }
    04636
    04637     return Status;
    04638 }
    04639
    04640 ULONG
    04641 MiIsEntireRangeCommitted64 (
    04642     IN PVOID64 StartingAddress,
    04643     IN PVOID64 EndingAddress,
    04644     IN PMMVAD Vad,
    04645     IN PEPROCESS Process
    04646     )
    04647
    04648 /*++
    04649
    04650 Routine Description:
    04651
    04652     This routine examines the range of pages from the starting address
    04653     up to and including the ending address and returns TRUE if every
    04654     page in the range is committed, FALSE otherwise.
    04655
    04656 Arguments:
    04657
    04658     StartingAddress - Supplies the starting address of the range.
    04659
    04660     EndingAddress - Supplies the ending address of the range.
    04661
    04662     Vad - Supplies the virtual address descriptor which describes the range.
    04663
    04664     Process - Supplies the current process.
    04665
    04666 Return Value:
    04667
    04668     TRUE if the entire range is committed.
    04669     FALSE if any page within the range is not committed.
    04670
    04671 Environment:
    04672
    04673     Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes
    04674     held.
    04675
    04676 --*/
    04677
    04678 {
    04679     PMMPTE PointerPte;
    04680     PMMPTE LastPte;
    04681     PMMPTE PointerPde;
    04682     LOGICAL FirstTime;
    04683     PVOID64 Va;
    04684
    04685     PAGED_CODE();
    04686
    04687     FirstTime = TRUE;
    04688
    04689     PointerPde = MiGetPdeAddress64 (StartingAddress);
    04690     PointerPte = MiGetPteAddress64 (StartingAddress);
    04691     LastPte = MiGetPteAddress64 (EndingAddress);
    04692
    04693     ASSERT (Vad->u.VadFlags.PrivateMemory == 1);
    04694
    04695     Va = StartingAddress;
    04696
    04697     while (PointerPte <= LastPte) {
    04698
    04699         if (MiIsPteOnPdeBoundary(PointerPte) || FirstTime) {
    04700
    04701             //
    04702             // This is a PDE boundary, check to see if the entire
    04703             // PDE page exists.
    04704             //
    04705
    04706             FirstTime = FALSE;
    04707             PointerPde = MiGetPteAddress (PointerPte);
    04708
    04709             if (PointerPde->u.Long == 0) {
    04710
    04711                 //
    04712                 // No page directory entry for private memory means
    04713                 // we're not committed.
    04714                 //
    04715
    04716                 ASSERT (Vad->u.VadFlags.PrivateMemory == 1);
    04717                 return FALSE;
    04718             }
    04719 #if 0
    04720             while (!MiDoesPdeExistAndMakeValid(PointerPde, Process, FALSE)) {
    04721
    04722                 //
    04723                 // No PDE exists for the starting address, check the VAD
    04724                 // to see if the pages are committed.
    04725                 //
    04726
    04727                 PointerPde += 1;
    04728
    04729                 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
    04730                 Va = MiGetVirtualAddressMappedByPte (PointerPte);
    04731
    04732                 if (PointerPte > LastPte) {
    04733
    04734                     //
    04735                     // Make sure the entire range is committed.
    04736                     //
    04737
    04738                     if (Vad->u.VadFlags.MemCommit == 0) {
    04739
    04740                         //
    04741                         // The entire range to be decommitted is not committed,
    04742                         // return an error.
    04743                         //
    04744
    04745                         return FALSE;
    04746                     } else {
    04747                         return TRUE;
    04748                     }
    04749                 }
    04750
    04751                 //
    04752                 // Make sure the range thus far is committed.
    04753                 //
    04754
    04755                 if (Vad->u.VadFlags.MemCommit == 0) {
    04756
    04757                     //
    04758                     // The entire range to be decommitted is not committed,
    04759                     // return an error.
    04760                     //
    04761
    04762                     return FALSE;
    04763                 }
    04764             }
    04765 #endif //0
    04766         }
    04767
    04768         //
    04769         // The page table page exists, check each PTE for commitment.
    04770         //
    04771
    04772         if (PointerPte->u.Long == 0) {
    04773
    04774             //
    04775             // This page has not been committed, check the VAD.
    04776             //
    04777
    04778 #if 0
    04779             if (Vad->u.VadFlags.MemCommit == 0) {
    04780 #endif
    04781
    04782                 //
    04783                 // The entire range to be decommitted is not committed,
    04784                 // return an error.
    04785                 //
    04786
    04787                 return FALSE;
    04788 #if 0
    04789             }
    04790 #endif
    04791         } else {
    04792
    04793             //
    04794             // Has this page been explicitly decommitted?
    04795             //
    04796
    04797             if (MiIsPteDecommittedPage (PointerPte)) {
    04798
    04799                 //
    04800                 // This page has been explicitly decommitted, return an error.
    04801                 //
    04802
    04803                 return FALSE;
    04804             }
    04805         }
    04806         PointerPte += 1;
    04807         Va = (PVOID64)((ULONGLONG)Va + PAGE_SIZE);
    04808     }
    04809     return TRUE;
    04810 }
    04811
    04812
    04813 VOID
    04814 MiMakeValidPageNoAccess64 (
    04815     IN PMMPTE PointerPte
    04816     )
    04817 {
    04818     PMMPFN Pfn1;
    04819     PMMPTE PointerPde;
    04820     MMPTE PteContents;
    04821     KIRQL OldIrql;
    04822     MMPTE TempPte;
    04823     ULONG_PTR Vpn;
    04824
    04825     Vpn = (ULONG_PTR)((ULONGLONG)MiGetVirtualAddressMappedByPte64(PointerPte) >>
    04826                     PAGE_SHIFT);
    04827
    04828     TempPte = PrototypePte;
    04829     TempPte.u.Soft.Protection = MM_NOACCESS;
    04830
    04831     PointerPde = MiGetPteAddress (PointerPte);
    04832     LOCK_PFN (OldIrql);
    04833
    04834     PteContents = *PointerPte;
    04835     Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber);
    04836
    04837     if (Pfn1->u3.e1.PrototypePte == 1) {
    04838
    04839         //
    04840         // Capture the state of the modified bit for this pte.
    04841         //
    04842
    04843         MI_CAPTURE_DIRTY_BIT_TO_PFN (&PteContents, Pfn1);
    04844
    04845         //
    04846         // Decrement the share and valid counts of the page table
    04847         // page which maps this PTE.
    04848         //
    04849
    04850         MiDecrementShareAndValidCount (MI_GET_PAGE_FRAME_FROM_PTE(PointerPde));
    04851
    04852         //
    04853         // Decrement the share count for the physical page.
    04854         //
    04855
    04856         MiDecrementShareCount (MI_GET_PAGE_FRAME_FROM_PTE(&PteContents));
    04857
    04858     } else {
    04859
    04860         //
    04861         // Make the PTE transition, but don't decrement the reference count
    04862         // only the share count.
    04863         //
    04864
    04865         ASSERT (Pfn1->u3.e2.ReferenceCount != 0);
    04866         Pfn1->u3.e2.ReferenceCount += 1;
    04867         MiDecrementShareCount (MI_GET_PAGE_FRAME_FROM_PTE(&PteContents));
    04868         TempPte = PteContents;
    04869         MI_MAKE_VALID_PTE_TRANSITION (TempPte, MM_NOACCESS);
    04870     }
    04871
    04872     KeFlushSingleTb64 (Vpn,
    04873                      TRUE,
    04874                      FALSE,
    04875                      (PHARDWARE_PTE)PointerPte,
    04876                      TempPte.u.Flush);
    04877     UNLOCK_PFN (OldIrql);
    04878     return;
    04879 }
    04880
    04881 VOID
    04882 MiMakeNoAccessPageValid64 (
    04883     IN PMMPTE PointerPte,
    04884     IN ULONG Protect
    04885     )
    04886
    04887 {
    04888     MMPTE PteContents;
    04889     MMPTE TempPte;
    04890     KIRQL OldIrql;
    04891     PMMPFN Pfn1;
    04892     PFN_NUMBER PageFrameIndex;
    04893
    04894     LOCK_PFN (OldIrql);
    04895     PteContents = *PointerPte;
    04896     PageFrameIndex = MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE(&PteContents);
    04897     Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
    04898     MI_MAKE_VALID_PTE (TempPte,
    04899                        PageFrameIndex,
    04900                        Protect,
    04901                        NULL);
    04902     if (TempPte.u.Hard.Write) {
    04903         MI_SET_PTE_DIRTY (TempPte);
    04904     }
    04905
    04906     //
    04907     // Note that VLM no access pages are marked as transition pages and
    04908     // are not in any page tables.  Therefore their sharecount is zero.
    04909     //
    04910     // The subtlety is that the reference count on this VLM no access page
    04911     // should never go to 0 because then the page will actually be freed
    04912     // to the standby list - and we'd only want to do that if we were actually
    04913     // getting rid of the page (as opposed to making it no-access).
    04914     //
    04915     // Thus, the ASSERT below cannot be turned on.
    04916     //
    04917     // ASSERT (Pfn1->u2.ShareCount == 1);
    04918     //
    04919
    04920     ASSERT (Pfn1->u3.e2.ReferenceCount != 0);
    04921     Pfn1->u2.ShareCount += 1;
    04922     *PointerPte = TempPte;
    04923     UNLOCK_PFN (OldIrql);
    04924     return;
    04925 }
    04926
    04927 NTSTATUS
    04928 MiGetVlmInfo (
    04929     IN PMEMORY_VLM_COUNTERS VlmUserInfo
    04930     )
    04931
    04932 /*++
    04933
    04934 Routine Description:
    04935
    04936     This function returns the various VLM information values.
    04937
    04938 Arguments:
    04939
    04940     VlmInfo - Supplies a VLM information structure to fill in.
    04941
    04942 Return Value:
    04943
    04944     Returns the status.
    04945
    04946 Environment:
    04947
    04948     Kernel mode.  The caller is responsible for ensuring that VLM is enabled.
    04949
    04950 --*/
    04951
    04952 {
    04953     PMMPTE PointerPte;
    04954     PEPROCESS TargetProcess;
    04955     PMI_PROCESS_VLM_INFO VlmInfo;
    04956
    04957     RtlZeroMemory (VlmUserInfo, sizeof (*VlmUserInfo));
    04958
    04959     VlmUserInfo->SystemCommitCharge = MiVlmCommitChargeInPages;
    04960     VlmUserInfo->SystemPeakCommitCharge = MiVlmCommitChargeInPagesPeak;
    04961     VlmUserInfo->SystemSharedCommitCharge = MmSharedCommitVlm;
    04962     VlmUserInfo->VirtualSizeAvailable =
    04963         MM_HIGHEST_USER_ADDRESS64 - MM_LOWEST_USER_ADDRESS64 + 1;
    04964
    04965
    04966     TargetProcess = PsGetCurrentProcess();
    04967
    04968     LOCK_WS (TargetProcess);
    04969
    04970     if (TargetProcess->AddressSpaceDeleted != 0) {
    04971         UNLOCK_WS (TargetProcess);
    04972         return STATUS_PROCESS_IS_TERMINATING;
    04973     }
    04974
    04975     PointerPte = MiGetPteAddress (PDE_BASE64);
    04976
    04977     if (PointerPte->u.Long != 0) {
    04978
    04979         ASSERT (PointerPte->u.Hard.Valid == 1);
    04980
    04981         VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long);
    04982
    04983         VlmUserInfo->VirtualSize = VlmInfo->VirtualSize;
    04984         VlmUserInfo->PeakVirtualSize = VlmInfo->VirtualSizePeak;
    04985
    04986         VlmUserInfo->VirtualSizeAvailable -= VlmInfo->VirtualSize;
    04987
    04988         VlmUserInfo->CommitCharge = VlmInfo->CommitCharge;
    04989         VlmUserInfo->PeakCommitCharge = VlmInfo->CommitChargePeak;
    04990     }
    04991
    04992     UNLOCK_WS (TargetProcess);
    04993
    04994     return STATUS_SUCCESS;
    04995 }
    04996
    04997 NTSTATUS
    04998 NtQueryVirtualMemory64(
    04999     IN HANDLE ProcessHandle,
    05000     IN PVOID64 *pBaseAddress,
    05001     IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
    05002     OUT PVOID MemoryInformation,
    05003     IN ULONG MemoryInformationLength,
    05004     OUT PULONG ReturnLength OPTIONAL
    05005     )
    05006
    05007 /*++
    05008
    05009 Routine Description:
    05010
    05011     This function provides the capability to determine the state,
    05012     protection, and type of a region of pages within the virtual address
    05013     space of the subject process.
    05014
    05015     The state of the first page within the region is determined  and then
    05016     subsequent entries in the process address map are scanned from the
    05017     base address upward until either the entire range of pages has been
    05018     scanned or until a page with a nonmatching set of attributes is
    05019     encountered. The region attributes, the length of the region of pages
    05020     with matching attributes, and an appropriate status value are
    05021     returned.
    05022
    05023     If the entire region of pages does not have a matching set of
    05024     attributes, then the returned length parameter value can be used to
    05025     calculate the address and length of the region of pages that was not
    05026     scanned.
    05027
    05028 Arguments:
    05029
    05030
    05031     ProcessHandle - An open handle to a process object.
    05032
    05033     pBaseAddress - Pointer to the base address of the region of pages to be
    05034         queried. This value is rounded down to the next host-page-
    05035         address boundary.
    05036
    05037         Note this is a 32-bit pointer to a 64-bit pointer. This is
    05038         necessary because all system service arguments are canonicalized
    05039         to 32 bits.
    05040
    05041     MemoryInformationClass - The memory information class about which
    05042         to retrieve information.
    05043
    05044     MemoryInformation - A pointer to a buffer that receives the
    05045         specified information.  The format and content of the buffer
    05046         depend on the specified information class.
    05047
    05048
    05049         MemoryBasicInformation - Data type is PMEMORY_BASIC_INFORMATION.
    05050
    05051             MEMORY_BASIC_INFORMATION Structure
    05052
    05053
    05054             ULONG RegionSize - The size of the region in bytes
    05055                 beginning at the base address in which all pages have
    05056                 identical attributes.
    05057
    05058             ULONG State - The state of the pages within the region.
    05059
    05060                 State Values                        State Values
    05061
    05062                 MEM_COMMIT - The state of the pages within the region
    05063                     is committed.
    05064
    05065                 MEM_FREE - The state of the pages within the region
    05066                     is free.
    05067
    05068                 MEM_RESERVE - The state of the pages within the
    05069                     region is reserved.
    05070
    05071             ULONG Protect - The protection of the pages within the
    05072                 region.
    05073
    05074
    05075                 Protect Values                        Protect Values
    05076
    05077                 PAGE_NOACCESS - No access to the region of pages is
    05078                     allowed. An attempt to read, write, or execute
    05079                     within the region results in an access violation
    05080                     (i.e., a GP fault).
    05081
    05082                 PAGE_EXECUTE - Execute access to the region of pages
    05083                     is allowed. An attempt to read or write within
    05084                     the region results in an access violation.
    05085
    05086                 PAGE_READONLY - Read-only and execute access to the
    05087                     region of pages is allowed. An attempt to write
    05088                     within the region results in an access violation.
    05089
    05090                 PAGE_READWRITE - Read, write, and execute access to
    05091                     the region of pages is allowed. If write access
    05092                     to the underlying section is allowed, then a
    05093                     single copy of the pages are shared. Otherwise,
    05094                     the pages are shared read-only/copy-on-write.
    05095
    05096                 PAGE_GUARD - Read, write, and execute access to the
    05097                     region of pages is allowed; however, access to
    05098                     the region causes a "guard region entered"
    05099                     condition to be raised in the subject process.
    05100
    05101                 PAGE_NOCACHE - Disable the placement of committed
    05102                     pages into the data cache.
    05103
    05104             ULONG Type - The type of pages within the region.
    05105
    05106
    05107                 Type Values
    05108
    05109                 MEM_PRIVATE - The pages within the region are
    05110                     private.
    05111
    05112                 MEM_MAPPED - The pages within the region are mapped
    05113                     into the view of a section.
    05114
    05115                 MEM_IMAGE - The pages within the region are mapped
    05116                     into the view of an image section.
    05117
    05118     MemoryInformationLength - Specifies the length in bytes  of
    05119         the memory information buffer.
    05120
    05121     ReturnLength - An optional pointer which, if specified,
    05122         receives the number of bytes placed in the process
    05123         information buffer.
    05124
    05125
    05126 Return Value:
    05127
    05128     Returns the status
    05129
    05130     TBS
    05131
    05132
    05133 Environment:
    05134
    05135     Kernel mode.
    05136
    05137 --*/
    05138
    05139 {
    05140     KPROCESSOR_MODE PreviousMode;
    05141     PEPROCESS TargetProcess;
    05142     NTSTATUS Status;
    05143     PMMVAD Vad;
    05144     PVOID64 Va;
    05145     BOOLEAN Found = FALSE;
    05146     ULONGLONG TheRegionSize;
    05147     ULONG NewProtect;
    05148     ULONG NewState;
    05149     ULONG_PTR BaseVpn;
    05150     PVOID64 BaseAddress;
    05151
    05152     MEMORY_BASIC_INFORMATION_VLM Info;
    05153
    05154     if (MI_VLM_ENABLED() == FALSE) {
    05155         return STATUS_NOT_IMPLEMENTED;
    05156     }
    05157
    05158     //
    05159     // The only supported option is MEMORY_BASIC_INFORMATION_VLM, make
    05160     // sure the user's buffer is large enough for this.
    05161     //
    05162
    05163     //
    05164     // Check argument validity.
    05165     //
    05166     switch (MemoryInformationClass) {
    05167         case MemoryBasicInformation:
    05168                 if (MemoryInformationLength < sizeof(MEMORY_BASIC_INFORMATION_VLM)) {
    05169                     return STATUS_INFO_LENGTH_MISMATCH;
    05170                 }
    05171                 break;
    05172
    05173         default:
    05174             return STATUS_INVALID_INFO_CLASS;
    05175     }
    05176
    05177     PreviousMode = KeGetPreviousMode();
    05178
    05179     if (PreviousMode != KernelMode) {
    05180
    05181         //
    05182         // Check arguments.
    05183         //
    05184
    05185         try {
    05186             ProbeForRead(pBaseAddress, sizeof(PVOID64), sizeof(ULONG));
    05187             BaseAddress = *pBaseAddress;
    05188
    05189             ProbeForWrite(MemoryInformation,
    05190                           MemoryInformationLength,
    05191                           sizeof(ULONGLONG));
    05192
    05193             if (ARGUMENT_PRESENT(ReturnLength)) {
    05194                 ProbeForWriteUlong(ReturnLength);
    05195             }
    05196
    05197         } except (EXCEPTION_EXECUTE_HANDLER) {
    05198
    05199             //
    05200             // If an exception occurs during the probe or capture
    05201             // of the initial values, then handle the exception and
    05202             // return the exception code as the status value.
    05203             //
    05204
    05205             return GetExceptionCode();
    05206         }
    05207     } else {
    05208         BaseAddress = *pBaseAddress;
    05209     }
    05210
    05211     if (BaseAddress == (PVOID64)NULL) {
    05212         BaseAddress = (PVOID64)MM_LOWEST_USER_ADDRESS64;
    05213     }
    05214
    05215     if ((BaseAddress > (PVOID64)MM_HIGHEST_USER_ADDRESS64) ||
    05216         (BaseAddress < (PVOID64)MM_LOWEST_USER_ADDRESS64)) {
    05217         return STATUS_INVALID_PARAMETER;
    05218     }
    05219
    05220     if ( ProcessHandle == NtCurrentProcess() ) {
    05221         TargetProcess = PsGetCurrentProcess();
    05222     } else {
    05223         Status = ObReferenceObjectByHandle ( ProcessHandle,
    05224                                              PROCESS_QUERY_INFORMATION,
    05225                                              PsProcessType,
    05226                                              PreviousMode,
    05227                                              (PVOID *)&TargetProcess,
    05228                                              NULL );
    05229
    05230         if (!NT_SUCCESS(Status)) {
    05231             return Status;
    05232         }
    05233     }
    05234
    05235     //
    05236     // If the specified process is not the current process, attach
    05237     // to the specified process.
    05238     //
    05239
    05240     KeAttachProcess (&TargetProcess->Pcb);
    05241
    05242     //
    05243     // Get working set mutex and block APCs.
    05244     //
    05245
    05246     LOCK_WS_AND_ADDRESS_SPACE (TargetProcess);
    05247
    05248     //
    05249     // Make sure the address space was not deleted, if so, return an error.
    05250     //
    05251
    05252     if (TargetProcess->AddressSpaceDeleted != 0) {
    05253         UNLOCK_WS (TargetProcess);
    05254         UNLOCK_ADDRESS_SPACE (TargetProcess);
    05255         KeDetachProcess();
    05256         if ( ProcessHandle != NtCurrentProcess() ) {
    05257             ObDereferenceObject (TargetProcess);
    05258         }
    05259         return STATUS_PROCESS_IS_TERMINATING;
    05260     }
    05261
    05262     if (TargetProcess->ForkWasSuccessful != MM_NO_FORK_ALLOWED) {
    05263         Vad = NULL;
    05264     } else {
    05265         Vad = TargetProcess->CloneRoot;
    05266     }
    05267
    05268     //
    05269     // Locate the VAD that contains the base address or the VAD
    05270     // which follows the base address.
    05271     //
    05272
    05273     BaseVpn = MI_VA_TO_VPN64 (BaseAddress);
    05274
    05275     for (;;) {
    05276
    05277         if (Vad == (PMMVAD)NULL) {
    05278             break;
    05279         }
    05280
    05281         if ((BaseVpn >= Vad->StartingVpn) &&
    05282             (BaseVpn <= Vad->EndingVpn)) {
    05283             Found = TRUE;
    05284             break;
    05285         }
    05286
    05287         if (BaseVpn < Vad->StartingVpn) {
    05288             if (Vad->LeftChild == (PMMVAD)NULL) {
    05289                 break;
    05290             }
    05291             Vad = Vad->LeftChild;
    05292
    05293         } else {
    05294             if (BaseVpn < Vad->EndingVpn) {
    05295                 break;
    05296             }
    05297             if (Vad->RightChild == (PMMVAD)NULL) {
    05298                 break;
    05299             }
    05300             Vad = Vad->RightChild;
    05301         }
    05302     }
    05303
    05304     if (!Found) {
    05305
    05306         //
    05307         // There is no virtual address allocated at the base
    05308         // address.  Return the size of the hole starting at
    05309         // the base address.
    05310         //
    05311
    05312         if (Vad == NULL) {
    05313             TheRegionSize = MM_LARGEST_VLM_RANGE + 1;
    05314         } else {
    05315             if (Vad->StartingVpn < BaseVpn) {
    05316
    05317                 //
    05318                 // We are looking at the Vad which occupies the range
    05319                 // just before the desired range.  Get the next Vad.
    05320                 //
    05321
    05322                 Vad = MiGetNextVad (Vad);
    05323                 if (Vad == NULL) {
    05324                     TheRegionSize = (ULONGLONG)MM_HIGHEST_VAD_ADDRESS64 -
    05325                                                 (ULONGLONG)PAGE_ALIGN64(BaseAddress);
    05326                 } else {
    05327                     TheRegionSize = (ULONGLONG)MI_VPN_TO_VA64 (Vad->StartingVpn) -
    05328                                                 (ULONGLONG)PAGE_ALIGN64(BaseAddress);
    05329                 }
    05330             } else {
    05331                 TheRegionSize = (ULONGLONG)MI_VPN_TO_VA64 (Vad->StartingVpn) -
    05332                                                 (ULONGLONG)PAGE_ALIGN64(BaseAddress);
    05333             }
    05334         }
    05335
    05336         UNLOCK_WS (TargetProcess);
    05337         UNLOCK_ADDRESS_SPACE (TargetProcess);
    05338         KeDetachProcess();
    05339
    05340         if (ProcessHandle != NtCurrentProcess()) {
    05341             ObDereferenceObject (TargetProcess);
    05342         }
    05343
    05344         //
    05345         // Establish an exception handler and write the information and
    05346         // returned length.
    05347         //
    05348
    05349         if (MemoryInformationClass == MemoryBasicInformation) {
    05350             try {
    05351
    05352                 ((PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation)->AllocationBase =
    05353                                          (PVOID64)MM_LOWEST_USER_ADDRESS64;
    05354                 ((PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation)->AllocationProtect =
    05355                                                                             0;
    05356                 ((PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation)->BaseAddressAsUlongLong =
    05357                                          (ULONGLONG)PAGE_ALIGN64(BaseAddress);
    05358                 ((PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation)->RegionSize =
    05359                                                                     TheRegionSize;
    05360                 ((PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation)->State = MEM_FREE;
    05361                 ((PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation)->Protect = PAGE_NOACCESS;
    05362                 ((PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation)->Type = 0;
    05363
    05364                 if (ARGUMENT_PRESENT(ReturnLength)) {
    05365                     *ReturnLength = sizeof(MEMORY_BASIC_INFORMATION_VLM);
    05366                 }
    05367
    05368             } except (EXCEPTION_EXECUTE_HANDLER) {
    05369
    05370                 //
    05371                 // Just return success.
    05372                 //
    05373             }
    05374
    05375             return STATUS_SUCCESS;
    05376         }
    05377         return STATUS_INVALID_ADDRESS;
    05378     }
    05379
    05380     //
    05381     // Found a vad.
    05382     //
    05383
    05384     Va = PAGE_ALIGN64(BaseAddress);
    05385     Info.BaseAddress = Va;
    05386
    05387     //
    05388     //
    05389     // There is a page mapped at the base address.
    05390     //
    05391
    05392     if (Vad->u.VadFlags.PrivateMemory) {
    05393         Info.Type = MEM_PRIVATE;
    05394     } else {
    05395         Info.Type = MEM_MAPPED;
    05396     }
    05397
    05398     Info.State = MiQueryAddressState64 (Va, Vad, TargetProcess, &Info.Protect);
    05399
    05400     Va = (PVOID64)((ULONGLONG)Va + PAGE_SIZE);
    05401
    05402     while (MI_VA_TO_VPN64 (Va) <= Vad->EndingVpn) {
    05403
    05404         NewState = MiQueryAddressState64 (Va,
    05405                                         Vad,
    05406                                         TargetProcess,
    05407                                         &NewProtect);
    05408
    05409         if ((NewState != Info.State) || (NewProtect != Info.Protect)) {
    05410
    05411             //
    05412             // The state for this address does not match, calculate
    05413             // size and return.
    05414             //
    05415
    05416             break;
    05417         }
    05418         Va = (PVOID64)((ULONGLONG)Va + PAGE_SIZE);
    05419     } // end while
    05420
    05421     Info.RegionSize = ((ULONGLONG)Va - (ULONGLONG)Info.BaseAddress);
    05422     Info.AllocationBase = MI_VPN_TO_VA64 (Vad->StartingVpn);
    05423     Info.AllocationProtect = MI_CONVERT_FROM_PTE_PROTECTION (
    05424                                              Vad->u.VadFlags.Protection);
    05425
    05426     //
    05427     // A range has been found, release the mutexes, detach from the
    05428     // target process and return the information.
    05429     //
    05430
    05431     UNLOCK_WS (TargetProcess);
    05432     UNLOCK_ADDRESS_SPACE (TargetProcess);
    05433     KeDetachProcess();
    05434
    05435     if ( ProcessHandle != NtCurrentProcess() ) {
    05436         ObDereferenceObject (TargetProcess);
    05437     }
    05438
    05439
    05440     if ( MemoryInformationClass == MemoryBasicInformation ) {
    05441         try {
    05442
    05443             *(PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation = Info;
    05444
    05445             if (ARGUMENT_PRESENT(ReturnLength)) {
    05446                 *ReturnLength = sizeof(MEMORY_BASIC_INFORMATION_VLM);
    05447             }
    05448
    05449         } except (EXCEPTION_EXECUTE_HANDLER) {
    05450             NOTHING;
    05451         }
    05452         return STATUS_SUCCESS;
    05453     }
    05454     return Status;
    05455 }
    05456
    05457
    05458
    05459 ULONG
    05460 MiQueryAddressState64 (
    05461     IN PVOID64 Va,
    05462     IN PMMVAD Vad,
    05463     IN PEPROCESS TargetProcess,
    05464     OUT PULONG ReturnedProtect
    05465     )
    05466
    05467 /*++
    05468
    05469 Routine Description:
    05470
    05471
    05472 Arguments:
    05473
    05474 Return Value:
    05475
    05476     Returns the state (MEM_COMMIT, MEM_RESERVE, MEM_PRIVATE).
    05477
    05478 Environment:
    05479
    05480     Kernel mode.  Working set lock and address creation lock held.
    05481
    05482 --*/
    05483
    05484 {
    05485     PMMPTE PointerPte;
    05486     PMMPTE PointerPde;
    05487     MMPTE CapturedProtoPte;
    05488     PMMPTE ProtoPte;
    05489     LOGICAL PteIsZero;
    05490     ULONG State;
    05491     ULONG Protect;
    05492     ULONG VadProtect;
    05493
    05494     VadProtect = MI_CONVERT_FROM_PTE_PROTECTION (Vad->u.VadFlags.Protection);
    05495 #ifdef LARGE_PAGES
    05496     if (Vad->u.VadFlags.LargePages) {
    05497         *ReturnedProtect = VadProtect;
    05498         return MEM_COMMIT;
    05499     }
    05500 #endif //LARGE_PAGES
    05501
    05502     PointerPde = MiGetPdeAddress64 (Va);
    05503     PointerPte = MiGetPteAddress64 (Va);
    05504
    05505     ASSERT ((Vad->StartingVpn <= MI_VA_TO_VPN64 (Va)) &&
    05506             (Vad->EndingVpn >= MI_VA_TO_VPN64 (Va)));
    05507
    05508     PteIsZero = TRUE;
    05509
    05510     //
    05511     // Note that if the PDE and PTE are not valid, then we must be
    05512     // in a no-access guard page type VAD.
    05513     //
    05514     if (MmIsAddressValid (PointerPde) && MmIsAddressValid(PointerPte)) {
    05515
    05516         //
    05517         // A PTE exists at this address, see if it is zero.
    05518         //
    05519
    05520         if (PointerPte->u.Long != 0) {
    05521
    05522             PteIsZero = FALSE;
    05523
    05524             //
    05525             // There is a non-zero PTE at this address, use
    05526             // it to build the information block.
    05527             //
    05528
    05529             if (MiIsPteDecommittedPage (PointerPte)) {
    05530                 Protect = 0;
    05531                 State = MEM_RESERVE;
    05532             } else {
    05533
    05534                 State = MEM_COMMIT;
    05535
    05536                 Protect = PAGE_READWRITE;
    05537                 if (PointerPte->u.Hard.Valid == 1) {
    05538                     if (PointerPte->u.Hard.Write == 0) {
    05539                         Protect = PAGE_READONLY;
    05540                     }
    05541                 } else if (PointerPte->u.Soft.Prototype) {
    05542                     Protect = VadProtect;
    05543
    05544                     if (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED) {
    05545                         Protect = MI_CONVERT_FROM_PTE_PROTECTION (PointerPte->u.Soft.Protection);
    05546                     }
    05547
    05548                     ProtoPte = MiGetProtoPteAddress(Vad,
    05549                                                 MI_VA_TO_VPN64 (Va));
    05550                     CapturedProtoPte.u.Long = 0;
    05551                     if (ProtoPte) {
    05552                         CapturedProtoPte = MiCaptureSystemPte (ProtoPte,
    05553                                                            TargetProcess);
    05554                     }
    05555                     if (CapturedProtoPte.u.Long == 0) {
    05556                         State = MEM_RESERVE;
    05557                         Protect = 0;
    05558                     }
    05559
    05560                 } else {
    05561                     Protect = MI_CONVERT_FROM_PTE_PROTECTION (PointerPte->u.Soft.Protection);
    05562                 }
    05563             }
    05564         }
    05565     }
    05566
    05567     if (PteIsZero == TRUE) {
    05568
    05569         //
    05570         // There is no PDE at this address, the template from
    05571         // the VAD supplies the information unless the VAD is
    05572         // for an image file.  For image files the individual
    05573         // protection is on the prototype PTE.
    05574         //
    05575
    05576         //
    05577         // Get the default protection information.
    05578         //
    05579
    05580         State = MEM_RESERVE;
    05581         Protect = 0;
    05582
    05583         if ((Vad->u.VadFlags.PrivateMemory == 0) &&
    05584             (Vad->ControlArea != (PCONTROL_AREA)NULL)) {
    05585
    05586             //
    05587             // This VAD refers to a section.  Even though the PTE is
    05588             // zero, the actual page may be committed in the section.
    05589             //
    05590
    05591             ProtoPte = MiGetProtoPteAddress(Vad, MI_VA_TO_VPN64 (Va));
    05592
    05593             CapturedProtoPte.u.Long = 0;
    05594             if (ProtoPte) {
    05595                 CapturedProtoPte = MiCaptureSystemPte (ProtoPte,
    05596                                                        TargetProcess);
    05597             }
    05598
    05599             if (CapturedProtoPte.u.Long != 0) {
    05600                 State = MEM_COMMIT;
    05601                 Protect = VadProtect;
    05602             }
    05603
    05604         } else {
    05605
    05606             //
    05607             // Get the protection from the corresponding VAD.
    05608             //
    05609
    05610             if (Vad->u.VadFlags.MemCommit) {
    05611                 State = MEM_COMMIT;
    05612                 Protect = VadProtect;
    05613             }
    05614         }
    05615     }
    05616
    05617     *ReturnedProtect = Protect;
    05618     return State;
    05619 }
    05620
    05621
    05622 #else
    05623
    05624 NTSTATUS
    05625 NtAllocateVirtualMemory64 (
    05626     IN HANDLE ProcessHandle,
    05627     IN OUT PVOID64 *BaseAddress,
    05628     IN ULONG ZeroBits,
    05629     IN OUT PULONGLONG RegionSize,
    05630     IN ULONG AllocationType,
    05631     IN ULONG Protect
    05632     )
    05633 {
    05634     return STATUS_NOT_IMPLEMENTED;
    05635 }
    05636
    05637 NTSTATUS
    05638 NtFreeVirtualMemory64(
    05639     IN HANDLE ProcessHandle,
    05640     IN OUT PVOID64 *BaseAddress,
    05641     IN OUT PULONGLONG RegionSize,
    05642     IN ULONG FreeType
    05643     )
    05644 {
    05645     return STATUS_NOT_IMPLEMENTED;
    05646 }
    05647
    05648 NTSTATUS
    05649 NtMapViewOfVlmSection (
    05650     IN HANDLE SectionHandle,
    05651     IN HANDLE ProcessHandle,
    05652     IN OUT PVOID64 *BaseAddress,
    05653     IN OUT PULONGLONG SectionOffset OPTIONAL,
    05654     IN OUT PULONGLONG ViewSize,
    05655     IN ULONG AllocationType,
    05656     IN ULONG Protect
    05657     )
    05658 {
    05659     return STATUS_NOT_IMPLEMENTED;
    05660 }
    05661
    05662 NTSTATUS
    05663 NtUnmapViewOfVlmSection(
    05664     IN HANDLE ProcessHandle,
    05665     IN OUT PVOID64 *BaseAddress
    05666     )
    05667 {
    05668     return STATUS_NOT_IMPLEMENTED;
    05669 }
    05670
    05671 NTSTATUS
    05672 NtQueryVirtualMemory64(
    05673     IN HANDLE ProcessHandle,
    05674     IN PVOID64 *pBaseAddress,
    05675     IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
    05676     OUT PVOID MemoryInformation,
    05677     IN ULONG MemoryInformationLength,
    05678     OUT PULONG ReturnLength OPTIONAL
    05679     )
    05680 {
    05681     return STATUS_NOT_IMPLEMENTED;
    05682 }
    05683
    05684 NTSTATUS
    05685 NtProtectVirtualMemory64(
    05686     IN HANDLE ProcessHandle,
    05687     IN OUT PVOID64 *BaseAddress,
    05688     IN OUT PULONGLONG RegionSize,
    05689     IN ULONG NewProtect,
    05690     OUT PULONG OldProtect
    05691     )
    05692
    05693 {
    05694     return STATUS_NOT_IMPLEMENTED;
    05695 }
    05696
    05697 #endif //VLM_SUPPORT