test: mapview.c Source File

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

# mapview.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007    mapview.c
    00008
    00009 Abstract:
    00010
    00011     This module contains the routines which implement the
    00012     NtMapViewOfSection service.
    00013
    00014 Author:
    00015
    00016     Lou Perazzoli (loup) 22-May-1989
    00017     Landy Wang (landyw) 02-June-1997
    00018
    00019 Revision History:
    00020
    00021 --*/
    00022
    00023 #include "mi.h"
    00024
    00025 ULONG MMPPTE_NAME = 'tPmM'; //MmPt
    00026 ULONG MMDB = 'bDmM';
    00027 extern ULONG MMVADKEY;
    00028
    00029 VOID
    00030 MiSetPageModified (
    00031     IN PVOID Address
    00032     );
    00033
    00034 extern LIST_ENTRY MmLoadedUserImageList;
    00035
    00036 #define X256MEG (256*1024*1024)
    00037
    00038 #if DBG
    00039 extern PEPROCESS MmWatchProcess;
    00040 #endif // DBG
    00041
    00042 #define ROUND_TO_PAGES64(Size)  (((UINT64)(Size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
    00043
    00044 MMSESSION   MmSession;
    00045
    00046 NTSTATUS
    00047 MiMapViewOfImageSection (
    00048     IN PCONTROL_AREA ControlArea,
    00049     IN PEPROCESS Process,
    00050     IN PVOID *CapturedBase,
    00051     IN PLARGE_INTEGER SectionOffset,
    00052     IN PSIZE_T CapturedViewSize,
    00053     IN PSECTION Section,
    00054     IN SECTION_INHERIT InheritDisposition,
    00055     IN ULONG_PTR ZeroBits,
    00056     IN SIZE_T ImageCommitment,
    00057     OUT PBOOLEAN ReleasedWsMutex
    00058     );
    00059
    00060 NTSTATUS
    00061 MiMapViewOfDataSection (
    00062     IN PCONTROL_AREA ControlArea,
    00063     IN PEPROCESS Process,
    00064     IN PVOID *CapturedBase,
    00065     IN PLARGE_INTEGER SectionOffset,
    00066     IN PSIZE_T CapturedViewSize,
    00067     IN PSECTION Section,
    00068     IN SECTION_INHERIT InheritDisposition,
    00069     IN ULONG ProtectionMask,
    00070     IN SIZE_T CommitSize,
    00071     IN ULONG_PTR ZeroBits,
    00072     IN ULONG AllocationType,
    00073     OUT PBOOLEAN ReleasedWsMutex
    00074     );
    00075
    00076 VOID
    00077 MiRemoveMappedPtes (
    00078     IN PVOID BaseAddress,
    00079     IN ULONG NumberOfPtes,
    00080     IN PCONTROL_AREA ControlArea,
    00081     IN PMMSUPPORT WorkingSetInfo
    00082     );
    00083
    00084 NTSTATUS
    00085 MiMapViewInSystemSpace (
    00086     IN PVOID Section,
    00087     IN PMMSESSION Session,
    00088     OUT PVOID *MappedBase,
    00089     IN OUT PSIZE_T ViewSize
    00090     );
    00091
    00092 NTSTATUS
    00093 MiUnmapViewInSystemSpace (
    00094     IN PMMSESSION Session,
    00095     IN PVOID MappedBase
    00096     );
    00097
    00098 BOOLEAN
    00099 MiFillSystemPageDirectory (
    00100     PVOID Base,
    00101     SIZE_T NumberOfBytes
    00102     );
    00103
    00104 VOID
    00105 VadTreeWalk (
    00106     PMMVAD Start
    00107     );
    00108
    00109 #if DBG
    00110 VOID
    00111 MiDumpConflictingVad(
    00112     IN PVOID StartingAddress,
    00113     IN PVOID EndingAddress,
    00114     IN PMMVAD Vad
    00115     );
    00116
    00117
    00118 VOID
    00119 MiDumpConflictingVad(
    00120     IN PVOID StartingAddress,
    00121     IN PVOID EndingAddress,
    00122     IN PMMVAD Vad
    00123     )
    00124 {
    00125     if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS) {
    00126         DbgPrint( "MM: [%p ... %p) conflicted with Vad %p\n",
    00127                   StartingAddress, EndingAddress, Vad);
    00128         if ((Vad->u.VadFlags.PrivateMemory == 1) ||
    00129             (Vad->ControlArea == NULL)) {
    00130             return;
    00131         }
    00132         if (Vad->ControlArea->u.Flags.Image)
    00133             DbgPrint( "    conflict with %Z image at [%p .. %p)\n",
    00134                       &Vad->ControlArea->FilePointer->FileName,
    00135                       MI_VPN_TO_VA (Vad->StartingVpn),
    00136                       MI_VPN_TO_VA_ENDING (Vad->EndingVpn)
    00137                     );
    00138         else
    00139         if (Vad->ControlArea->u.Flags.File)
    00140             DbgPrint( "    conflict with %Z file at [%p .. %p)\n",
    00141                       &Vad->ControlArea->FilePointer->FileName,
    00142                       MI_VPN_TO_VA (Vad->StartingVpn),
    00143                       MI_VPN_TO_VA_ENDING (Vad->EndingVpn)
    00144                     );
    00145         else
    00146             DbgPrint( "    conflict with section at [%p .. %p)\n",
    00147                       MI_VPN_TO_VA (Vad->StartingVpn),
    00148                       MI_VPN_TO_VA_ENDING (Vad->EndingVpn)
    00149                     );
    00150     }
    00151 }
    00152 #endif //DBG
    00153
    00154
    00155 ULONG
    00156 CacheImageSymbols(
    00157     IN PVOID ImageBase
    00158     );
    00159
    00160 PVOID
    00161 MiInsertInSystemSpace (
    00162     IN PMMSESSION Session,
    00163     IN ULONG SizeIn64k,
    00164     IN PCONTROL_AREA ControlArea
    00165     );
    00166
    00167 ULONG
    00168 MiRemoveFromSystemSpace (
    00169     IN PMMSESSION Session,
    00170     IN PVOID Base,
    00171     OUT PCONTROL_AREA *ControlArea
    00172     );
    00173
    00174 #ifdef ALLOC_PRAGMA
    00175 #pragma alloc_text(PAGE,NtMapViewOfSection)
    00176 #pragma alloc_text(PAGE,MmMapViewOfSection)
    00177 #pragma alloc_text(PAGE,MmSecureVirtualMemory)
    00178 #pragma alloc_text(PAGE,MmUnsecureVirtualMemory)
    00179 #pragma alloc_text(PAGE,CacheImageSymbols)
    00180 #pragma alloc_text(PAGE,NtAreMappedFilesTheSame)
    00181
    00182 #pragma alloc_text(PAGELK,MiMapViewOfPhysicalSection)
    00183 #pragma alloc_text(PAGELK,MiMapViewInSystemSpace)
    00184 #pragma alloc_text(PAGELK,MmMapViewInSystemSpace)
    00185 #pragma alloc_text(PAGELK,MmMapViewInSessionSpace)
    00186 #pragma alloc_text(PAGELK,MiUnmapViewInSystemSpace)
    00187 #pragma alloc_text(PAGELK,MmUnmapViewInSystemSpace)
    00188 #pragma alloc_text(PAGELK,MmUnmapViewInSessionSpace)
    00189 #pragma alloc_text(PAGELK,MiFillSystemPageDirectory)
    00190 #pragma alloc_text(PAGELK,MiInsertInSystemSpace)
    00191 #pragma alloc_text(PAGELK,MiRemoveFromSystemSpace)
    00192
    00193 #pragma alloc_text(PAGEHYDRA,MiInitializeSystemSpaceMap)
    00194 #pragma alloc_text(PAGEHYDRA, MiFreeSessionSpaceMap)
    00195 #endif
    00196
    00197
    00198 NTSTATUS
    00199 NtMapViewOfSection(
    00200     IN HANDLE SectionHandle,
    00201     IN HANDLE ProcessHandle,
    00202     IN OUT PVOID *BaseAddress,
    00203     IN ULONG_PTR ZeroBits,
    00204     IN SIZE_T CommitSize,
    00205     IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
    00206     IN OUT PSIZE_T ViewSize,
    00207     IN SECTION_INHERIT InheritDisposition,
    00208     IN ULONG AllocationType,
    00209     IN ULONG Protect
    00210     )
    00211
    00212 /*++
    00213
    00214 Routine Description:
    00215
    00216     This function maps a view in the specified subject process to
    00217     the section object.
    00218
    00219 Arguments:
    00220
    00221     SectionHandle - Supplies an open handle to a section object.
    00222
    00223     ProcessHandle - Supplies an open handle to a process object.
    00224
    00225     BaseAddress - Supplies a pointer to a variable that will receive
    00226                   the base address of the view. If the initial value
    00227                   of this argument is not null, then the view will
    00228                   be allocated starting at the specified virtual
    00229                   address rounded down to the next 64kb address
    00230                   boundary. If the initial value of this argument is
    00231                   null, then the operating system will determine
    00232                   where to allocate the view using the information
    00233                   specified by the ZeroBits argument value and the
    00234                   section allocation attributes (i.e. based and
    00235                   tiled).
    00236
    00237     ZeroBits - Supplies the number of high order address bits that
    00238                must be zero in the base address of the section
    00239                view. The value of this argument must be less than
    00240                or equal to the maximum number of zero bits and is only
    00241                used when memory management determines where to allocate
    00242                the view (i.e. when BaseAddress is null).
    00243
    00244                If ZeroBits is zero, then no zero bit constraints are applied.
    00245
    00246                If ZeroBits is greater than 0 and less than 32, then it is
    00247                the number of leading zero bits from bit 31.  Bits 63:32 are
    00248                also required to be zero.  This retains compatibility
    00249                with 32-bit systems.
    00250
    00251                If ZeroBits is greater than 32, then it is considered as
    00252                a mask and then number of leading zero are counted out
    00253                in the mask.  This then becomes the zero bits argument.
    00254
    00255     CommitSize - Supplies the size of the initially committed region
    00256                  of the view in bytes. This value is rounded up to
    00257                  the next host page size boundary.
    00258
    00259     SectionOffset - Supplies the offset from the beginning of the
    00260                     section to the view in bytes. This value is
    00261                     rounded down to the next host page size boundary.
    00262
    00263     ViewSize - Supplies a pointer to a variable that will receive
    00264                the actual size in bytes of the view. If the value
    00265                of this argument is zero, then a view of the
    00266                section will be mapped starting at the specified
    00267                section offset and continuing to the end of the
    00268                section. Otherwise the initial value of this
    00269                argument specifies the size of the view in bytes
    00270                and is rounded up to the next host page size
    00271                boundary.
    00272
    00273     InheritDisposition - Supplies a value that specifies how the
    00274                          view is to be shared by a child process created
    00275                          with a create process operation.
    00276
    00277         InheritDisposition Values
    00278
    00279          ViewShare - Inherit view and share a single copy
    00280               of the committed pages with a child process
    00281               using the current protection value.
    00282
    00283          ViewUnmap - Do not map the view into a child process.
    00284
    00285     AllocationType - Supplies the type of allocation.
    00286
    00287          MEM_TOP_DOWN
    00288          MEM_DOS_LIM
    00289          MEM_LARGE_PAGES
    00290          MEM_RESERVE - for file mapped sections only.
    00291
    00292     Protect - Supplies the protection desired for the region of
    00293               initially committed pages.
    00294
    00295         Protect Values
    00296
    00297
    00298          PAGE_NOACCESS - No access to the committed region
    00299               of pages is allowed. An attempt to read,
    00300               write, or execute the committed region
    00301               results in an access violation (i.e. a GP
    00302               fault).
    00303
    00304          PAGE_EXECUTE - Execute access to the committed
    00305               region of pages is allowed. An attempt to
    00306               read or write the committed region results in
    00307               an access violation.
    00308
    00309          PAGE_READONLY - Read only and execute access to the
    00310               committed region of pages is allowed. An
    00311               attempt to write the committed region results
    00312               in an access violation.
    00313
    00314          PAGE_READWRITE - Read, write, and execute access to
    00315               the region of committed pages is allowed. If
    00316               write access to the underlying section is
    00317               allowed, then a single copy of the pages are
    00318               shared. Otherwise the pages are shared read
    00319               only/copy on write.
    00320
    00321 Return Value:
    00322
    00323     Various NTSTATUS codes.
    00324
    00325 --*/
    00326
    00327 {
    00328     PSECTION Section;
    00329     PEPROCESS Process;
    00330     KPROCESSOR_MODE PreviousMode;
    00331     NTSTATUS Status;
    00332     PVOID CapturedBase;
    00333     SIZE_T CapturedViewSize;
    00334     LARGE_INTEGER TempViewSize;
    00335     LARGE_INTEGER CapturedOffset;
    00336     ULONGLONG HighestPhysicalAddressInPfnDatabase;
    00337     ACCESS_MASK DesiredSectionAccess;
    00338     ULONG ProtectMaskForAccess;
    00339     BOOLEAN WriteCombined;
    00340
    00341     PAGED_CODE();
    00342
    00343     //
    00344     // Check the zero bits argument for correctness.
    00345     //
    00346
    00347 #if defined (_WIN64)
    00348
    00349     if (ZeroBits >= 32) {
    00350
    00351         //
    00352         // ZeroBits is a mask instead of a count.  Translate it to a count now.
    00353         //
    00354
    00355         ZeroBits = 64 - RtlFindMostSignificantBit (ZeroBits);
    00356     }
    00357     else if (ZeroBits) {
    00358         ZeroBits += 32;
    00359     }
    00360
    00361 #endif
    00362
    00363     if (ZeroBits > MM_MAXIMUM_ZERO_BITS) {
    00364         return STATUS_INVALID_PARAMETER_4;
    00365     }
    00366
    00367     //
    00368     // Check the inherit disposition flags.
    00369     //
    00370
    00371     if ((InheritDisposition > ViewUnmap) ||
    00372         (InheritDisposition < ViewShare)) {
    00373         return STATUS_INVALID_PARAMETER_8;
    00374     }
    00375
    00376     //
    00377     // Check the allocation type field.
    00378     //
    00379
    00380 #ifdef i386
    00381
    00382     //
    00383     // Only allow DOS_LIM support for i386.  The MEM_DOS_LIM flag allows
    00384     // map views of data sections to be done on 4k boundaries rather
    00385     // than 64k boundaries.
    00386     //
    00387
    00388     if ((AllocationType & ~(MEM_TOP_DOWN | MEM_LARGE_PAGES | MEM_DOS_LIM |
    00389            SEC_NO_CHANGE | MEM_RESERVE)) != 0) {
    00390         return STATUS_INVALID_PARAMETER_9;
    00391     }
    00392 #else
    00393     if ((AllocationType & ~(MEM_TOP_DOWN | MEM_LARGE_PAGES |
    00394            SEC_NO_CHANGE | MEM_RESERVE)) != 0) {
    00395         return STATUS_INVALID_PARAMETER_9;
    00396     }
    00397
    00398 #endif //i386
    00399
    00400     //
    00401     // Check the protection field.  This could raise an exception.
    00402     //
    00403
    00404     if (Protect & PAGE_WRITECOMBINE) {
    00405         Protect &= ~PAGE_WRITECOMBINE;
    00406         WriteCombined = TRUE;
    00407     }
    00408     else {
    00409         WriteCombined = FALSE;
    00410     }
    00411
    00412     try {
    00413         ProtectMaskForAccess = MiMakeProtectionMask (Protect) & 0x7;
    00414     } except (EXCEPTION_EXECUTE_HANDLER) {
    00415         return GetExceptionCode();
    00416     }
    00417
    00418     DesiredSectionAccess = MmMakeSectionAccess[ProtectMaskForAccess];
    00419
    00420     PreviousMode = KeGetPreviousMode();
    00421
    00422     //
    00423     // Establish an exception handler, probe the specified addresses
    00424     // for write access and capture the initial values.
    00425     //
    00426
    00427     try {
    00428         if (PreviousMode != KernelMode) {
    00429             ProbeForWritePointer ((PULONG)BaseAddress);
    00430             ProbeForWriteUlong_ptr (ViewSize);
    00431
    00432         }
    00433
    00434         if (ARGUMENT_PRESENT (SectionOffset)) {
    00435             if (PreviousMode != KernelMode) {
    00436                 ProbeForWrite (SectionOffset,
    00437                                sizeof(LARGE_INTEGER),
    00438                                sizeof(ULONG_PTR));
    00439             }
    00440             CapturedOffset = *SectionOffset;
    00441         } else {
    00442             ZERO_LARGE (CapturedOffset);
    00443         }
    00444
    00445         //
    00446         // Capture the base address.
    00447         //
    00448
    00449         CapturedBase = *BaseAddress;
    00450
    00451         //
    00452         // Capture the region size.
    00453         //
    00454
    00455         CapturedViewSize = *ViewSize;
    00456
    00457     } except (ExSystemExceptionFilter()) {
    00458
    00459         //
    00460         // If an exception occurs during the probe or capture
    00461         // of the initial values, then handle the exception and
    00462         // return the exception code as the status value.
    00463         //
    00464
    00465         return GetExceptionCode();
    00466     }
    00467
    00468 #if DBG
    00469     if (MmDebug & MM_DBG_SHOW_NT_CALLS) {
    00470         if ( !MmWatchProcess ) {
    00471             DbgPrint("mapview process handle %lx section %lx base address %p zero bits %lx\n",
    00472                 ProcessHandle, SectionHandle, CapturedBase, ZeroBits);
    00473             DbgPrint("    view size %p offset %p commitsize %p  protect %lx\n",
    00474                 CapturedViewSize, CapturedOffset, CommitSize, Protect);
    00475             DbgPrint("    Inheritdisp %lx  Allocation type %lx\n",
    00476                 InheritDisposition, AllocationType);
    00477         }
    00478     }
    00479 #endif
    00480
    00481     //
    00482     // Make sure the specified starting and ending addresses are
    00483     // within the user part of the virtual address space.
    00484     //
    00485
    00486     if (CapturedBase > MM_HIGHEST_VAD_ADDRESS) {
    00487
    00488         //
    00489         // Invalid base address.
    00490         //
    00491
    00492         return STATUS_INVALID_PARAMETER_3;
    00493     }
    00494
    00495     if (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)CapturedBase) <
    00496                                                         CapturedViewSize) {
    00497
    00498         //
    00499         // Invalid region size;
    00500         //
    00501
    00502         return STATUS_INVALID_PARAMETER_3;
    00503
    00504     }
    00505
    00506     if (((ULONG_PTR)CapturedBase + CapturedViewSize) > ((ULONG_PTR)MM_USER_ADDRESS_RANGE_LIMIT >> ZeroBits)) {
    00507
    00508         //
    00509         // Desired Base and zero_bits conflict.
    00510         //
    00511
    00512         return STATUS_INVALID_PARAMETER_4;
    00513     }
    00514
    00515     Status = ObReferenceObjectByHandle ( ProcessHandle,
    00516                                          PROCESS_VM_OPERATION,
    00517                                          PsProcessType,
    00518                                          PreviousMode,
    00519                                          (PVOID *)&Process,
    00520                                          NULL );
    00521     if (!NT_SUCCESS(Status)) {
    00522         return Status;
    00523     }
    00524
    00525     //
    00526     // Reference the section object, if a view is mapped to the section
    00527     // object, the object is not dereferenced as the virtual address
    00528     // descriptor contains a pointer to the section object.
    00529     //
    00530
    00531     Status = ObReferenceObjectByHandle ( SectionHandle,
    00532                                          DesiredSectionAccess,
    00533                                          MmSectionObjectType,
    00534                                          PreviousMode,
    00535                                          (PVOID *)&Section,
    00536                                          NULL );
    00537
    00538     if (!NT_SUCCESS(Status)) {
    00539         goto ErrorReturn1;
    00540     }
    00541
    00542     if (Section->u.Flags.Image == 0) {
    00543
    00544         //
    00545         // This is not an image section, make sure the section page
    00546         // protection is compatible with the specified page protection.
    00547         //
    00548
    00549         if (!MiIsProtectionCompatible (Section->InitialPageProtection,
    00550                                        Protect)) {
    00551             Status = STATUS_SECTION_PROTECTION;
    00552             goto ErrorReturn;
    00553         }
    00554     }
    00555
    00556     //
    00557     // Check to see if this the section backs physical memory, if
    00558     // so DON'T align the offset on a 64K boundary, just a 4k boundary.
    00559     //
    00560
    00561     if (Section->Segment->ControlArea->u.Flags.PhysicalMemory) {
    00562         HighestPhysicalAddressInPfnDatabase = (ULONGLONG)MmHighestPhysicalPage << PAGE_SHIFT;
    00563         CapturedOffset.LowPart = CapturedOffset.LowPart & ~(PAGE_SIZE - 1);
    00564
    00565         //
    00566         // No usermode mappings past the end of the PFN database are allowed.
    00567         // Address wrap is checked in the common path.
    00568         //
    00569
    00570         if (PreviousMode != KernelMode) {
    00571
    00572             if ((ULONGLONG)(CapturedOffset.QuadPart + CapturedViewSize) > HighestPhysicalAddressInPfnDatabase) {
    00573                 Status = STATUS_INVALID_PARAMETER_6;
    00574                 goto ErrorReturn;
    00575             }
    00576         }
    00577
    00578     } else {
    00579
    00580         //
    00581         // Make sure alignments are correct for specified address
    00582         // and offset into the file.
    00583         //
    00584
    00585         if ((AllocationType & MEM_DOS_LIM) == 0) {
    00586             if (((ULONG_PTR)CapturedBase & (X64K - 1)) != 0) {
    00587                 Status = STATUS_MAPPED_ALIGNMENT;
    00588                 goto ErrorReturn;
    00589             }
    00590
    00591             if ((ARGUMENT_PRESENT (SectionOffset)) &&
    00592                 ((CapturedOffset.LowPart & (X64K - 1)) != 0)) {
    00593                 Status = STATUS_MAPPED_ALIGNMENT;
    00594                 goto ErrorReturn;
    00595             }
    00596         }
    00597     }
    00598
    00599     //
    00600     // Check to make sure the view size plus the offset is less
    00601     // than the size of the section.
    00602     //
    00603
    00604     if ((ULONGLONG) (CapturedOffset.QuadPart + CapturedViewSize) <
    00605         (ULONGLONG)CapturedOffset.QuadPart) {
    00606
    00607         Status = STATUS_INVALID_VIEW_SIZE;
    00608         goto ErrorReturn;
    00609     }
    00610
    00611     if (((ULONGLONG) (CapturedOffset.QuadPart + CapturedViewSize) >
    00612                  (ULONGLONG)Section->SizeOfSection.QuadPart) &&
    00613         ((AllocationType & MEM_RESERVE) == 0)) {
    00614
    00615         Status = STATUS_INVALID_VIEW_SIZE;
    00616         goto ErrorReturn;
    00617     }
    00618
    00619     if (CapturedViewSize == 0) {
    00620
    00621         //
    00622         // Set the view size to be size of the section less the offset.
    00623         //
    00624
    00625         TempViewSize.QuadPart = Section->SizeOfSection.QuadPart -
    00626                                                 CapturedOffset.QuadPart;
    00627
    00628         CapturedViewSize = (SIZE_T)TempViewSize.QuadPart;
    00629
    00630         if (
    00631
    00632 #if !defined(_WIN64)
    00633
    00634             (TempViewSize.HighPart != 0) ||
    00635
    00636 #endif
    00637
    00638             (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)CapturedBase) <
    00639                                                         CapturedViewSize)) {
    00640
    00641             //
    00642             // Invalid region size;
    00643             //
    00644
    00645             Status = STATUS_INVALID_VIEW_SIZE;
    00646             goto ErrorReturn;
    00647         }
    00648     }
    00649
    00650     //
    00651     // Check commit size.
    00652     //
    00653
    00654     if ((CommitSize > CapturedViewSize) &&
    00655         ((AllocationType & MEM_RESERVE) == 0)) {
    00656         Status = STATUS_INVALID_PARAMETER_5;
    00657         goto ErrorReturn;
    00658     }
    00659
    00660     if (WriteCombined == TRUE) {
    00661         Protect |= PAGE_WRITECOMBINE;
    00662     }
    00663
    00664     Status = MmMapViewOfSection ( (PVOID)Section,
    00665                                   Process,
    00666                                   &CapturedBase,
    00667                                   ZeroBits,
    00668                                   CommitSize,
    00669                                   &CapturedOffset,
    00670                                   &CapturedViewSize,
    00671                                   InheritDisposition,
    00672                                   AllocationType,
    00673                                   Protect);
    00674
    00675     if (!NT_SUCCESS(Status) ) {
    00676         if ( (Section->Segment->ControlArea->u.Flags.Image) &&
    00677              Process == PsGetCurrentProcess() ) {
    00678             if (Status == STATUS_CONFLICTING_ADDRESSES ) {
    00679                 DbgkMapViewOfSection(
    00680                     SectionHandle,
    00681                     CapturedBase,
    00682                     CapturedOffset.LowPart,
    00683                     CapturedViewSize
    00684                     );
    00685             }
    00686         }
    00687         goto ErrorReturn;
    00688     }
    00689
    00690     //
    00691     // Anytime the current process maps an image file,
    00692     // a potential debug event occurs. DbgkMapViewOfSection
    00693     // handles these events.
    00694     //
    00695
    00696     if ( (Section->Segment->ControlArea->u.Flags.Image) &&
    00697          Process == PsGetCurrentProcess() ) {
    00698         if (Status != STATUS_IMAGE_NOT_AT_BASE ) {
    00699             DbgkMapViewOfSection(
    00700                 SectionHandle,
    00701                 CapturedBase,
    00702                 CapturedOffset.LowPart,
    00703                 CapturedViewSize
    00704                 );
    00705         }
    00706     }
    00707
    00708     //
    00709     // Establish an exception handler and write the size and base
    00710     // address.
    00711     //
    00712
    00713     try {
    00714
    00715         *ViewSize = CapturedViewSize;
    00716         *BaseAddress = CapturedBase;
    00717
    00718         if (ARGUMENT_PRESENT(SectionOffset)) {
    00719             *SectionOffset = CapturedOffset;
    00720         }
    00721
    00722     } except (EXCEPTION_EXECUTE_HANDLER) {
    00723         goto ErrorReturn;
    00724     }
    00725
    00726 #if 0 // test code...
    00727     if ((Status == STATUS_SUCCESS) &&
    00728         (Section->u.Flags.Image == 0)) {
    00729
    00730         PVOID Base;
    00731         ULONG Size = 0;
    00732         NTSTATUS Status;
    00733
    00734         Status = MmMapViewInSystemSpace ((PVOID)Section,
    00735                                         &Base,
    00736                                         &Size);
    00737         if (Status == STATUS_SUCCESS) {
    00738             MmUnmapViewInSystemSpace (Base);
    00739         }
    00740     }
    00741 #endif //0
    00742
    00743     {
    00744 ErrorReturn:
    00745         ObDereferenceObject (Section);
    00746 ErrorReturn1:
    00747         ObDereferenceObject (Process);
    00748         return Status;
    00749     }
    00750 }
    00751
    00752 NTSTATUS
    00753 MmMapViewOfSection(
    00754     IN PVOID SectionToMap,
    00755     IN PEPROCESS Process,
    00756     IN OUT PVOID *CapturedBase,
    00757     IN ULONG_PTR ZeroBits,
    00758     IN SIZE_T CommitSize,
    00759     IN OUT PLARGE_INTEGER SectionOffset,
    00760     IN OUT PSIZE_T CapturedViewSize,
    00761     IN SECTION_INHERIT InheritDisposition,
    00762     IN ULONG AllocationType,
    00763     IN ULONG Protect
    00764     )
    00765
    00766 /*++
    00767
    00768 Routine Description:
    00769
    00770     This function maps a view in the specified subject process to
    00771     the section object.
    00772
    00773     This function is a kernel mode interface to allow LPC to map
    00774     a section given the section pointer to map.
    00775
    00776     This routine assumes all arguments have been probed and captured.
    00777
    00778     ********************************************************************
    00779     ********************************************************************
    00780     ********************************************************************
    00781
    00782     NOTE:
    00783
    00784     CapturedViewSize, SectionOffset, and CapturedBase must be
    00785     captured in non-paged system space (i.e., kernel stack).
    00786
    00787     ********************************************************************
    00788     ********************************************************************
    00789     ********************************************************************
    00790
    00791 Arguments:
    00792
    00793     SectionToMap - Supplies a pointer to the section object.
    00794
    00795     Process - Supplies a pointer to the process object.
    00796
    00797     BaseAddress - Supplies a pointer to a variable that will receive
    00798          the base address of the view. If the initial value
    00799          of this argument is not null, then the view will
    00800          be allocated starting at the specified virtual
    00801          address rounded down to the next 64kb address
    00802          boundary. If the initial value of this argument is
    00803          null, then the operating system will determine
    00804          where to allocate the view using the information
    00805          specified by the ZeroBits argument value and the
    00806          section allocation attributes (i.e. based and
    00807          tiled).
    00808
    00809     ZeroBits - Supplies the number of high order address bits that
    00810          must be zero in the base address of the section
    00811          view. The value of this argument must be less than
    00812          21 and is only used when the operating system
    00813          determines where to allocate the view (i.e. when
    00814          BaseAddress is null).
    00815
    00816     CommitSize - Supplies the size of the initially committed region
    00817          of the view in bytes. This value is rounded up to
    00818          the next host page size boundary.
    00819
    00820     SectionOffset - Supplies the offset from the beginning of the
    00821          section to the view in bytes. This value is
    00822          rounded down to the next host page size boundary.
    00823
    00824     ViewSize - Supplies a pointer to a variable that will receive
    00825          the actual size in bytes of the view. If the value
    00826          of this argument is zero, then a view of the
    00827          section will be mapped starting at the specified
    00828          section offset and continuing to the end of the
    00829          section. Otherwise the initial value of this
    00830          argument specifies the size of the view in bytes
    00831          and is rounded up to the next host page size
    00832          boundary.
    00833
    00834     InheritDisposition - Supplies a value that specifies how the
    00835          view is to be shared by a child process created
    00836          with a create process operation.
    00837
    00838     AllocationType - Supplies the type of allocation.
    00839
    00840     Protect - Supplies the protection desired for the region of
    00841          initially committed pages.
    00842
    00843 Return Value:
    00844
    00845     Returns the status
    00846
    00847     TBS
    00848
    00849
    00850 --*/
    00851 {
    00852     BOOLEAN Attached;
    00853     PSECTION Section;
    00854     PCONTROL_AREA ControlArea;
    00855     ULONG ProtectionMask;
    00856     NTSTATUS status;
    00857     BOOLEAN ReleasedWsMutex;
    00858     BOOLEAN WriteCombined;
    00859     SIZE_T ImageCommitment;
    00860
    00861     PAGED_CODE();
    00862
    00863     Attached = FALSE;
    00864     ReleasedWsMutex = TRUE;
    00865
    00866     Section = (PSECTION)SectionToMap;
    00867
    00868     //
    00869     // Check to make sure the section is not smaller than the view size.
    00870     //
    00871
    00872     if ((LONGLONG)*CapturedViewSize > Section->SizeOfSection.QuadPart) {
    00873         if ((AllocationType & MEM_RESERVE) == 0) {
    00874             return STATUS_INVALID_VIEW_SIZE;
    00875         }
    00876     }
    00877
    00878     if (AllocationType & MEM_RESERVE) {
    00879         if (((Section->InitialPageProtection & PAGE_READWRITE) |
    00880             (Section->InitialPageProtection & PAGE_EXECUTE_READWRITE)) == 0) {
    00881
    00882             return STATUS_SECTION_PROTECTION;
    00883         }
    00884     }
    00885
    00886     if (Section->u.Flags.NoCache) {
    00887         Protect |= PAGE_NOCACHE;
    00888     }
    00889
    00890     //
    00891     // Note that write combining is only relevant to physical memory sections
    00892     // because they are never trimmed - the write combining bits in a PTE entry
    00893     // are not preserved across trims.
    00894     //
    00895
    00896     if (Protect & PAGE_WRITECOMBINE) {
    00897         Protect &= ~PAGE_WRITECOMBINE;
    00898         WriteCombined = TRUE;
    00899     }
    00900     else {
    00901         WriteCombined = FALSE;
    00902     }
    00903
    00904     //
    00905     // Check the protection field.  This could raise an exception.
    00906     //
    00907
    00908     try {
    00909         ProtectionMask = MiMakeProtectionMask (Protect);
    00910     } except (EXCEPTION_EXECUTE_HANDLER) {
    00911         return GetExceptionCode();
    00912     }
    00913
    00914     ControlArea = Section->Segment->ControlArea;
    00915     ImageCommitment = Section->Segment->ImageCommitment;
    00916
    00917     //
    00918     // If the specified process is not the current process, attach
    00919     // to the specified process.
    00920     //
    00921
    00922     if (PsGetCurrentProcess() != Process) {
    00923         KeAttachProcess (&Process->Pcb);
    00924         Attached = TRUE;
    00925     }
    00926
    00927     //
    00928     // Get the address creation mutex to block multiple threads
    00929     // creating or deleting address space at the same time.
    00930     //
    00931
    00932     LOCK_ADDRESS_SPACE (Process);
    00933
    00934     //
    00935     // Make sure the address space was not deleted, if so, return an error.
    00936     //
    00937
    00938     if (Process->AddressSpaceDeleted != 0) {
    00939         status = STATUS_PROCESS_IS_TERMINATING;
    00940         goto ErrorReturn;
    00941     }
    00942
    00943     //
    00944     // Map the view base on the type.
    00945     //
    00946
    00947     ReleasedWsMutex = FALSE;
    00948
    00949     if (ControlArea->u.Flags.PhysicalMemory) {
    00950
    00951         MmLockPagableSectionByHandle(ExPageLockHandle);
    00952         status = MiMapViewOfPhysicalSection (ControlArea,
    00953                                              Process,
    00954                                              CapturedBase,
    00955                                              SectionOffset,
    00956                                              CapturedViewSize,
    00957                                              ProtectionMask,
    00958                                              ZeroBits,
    00959                                              AllocationType,
    00960                                              WriteCombined,
    00961                                              &ReleasedWsMutex);
    00962         MmUnlockPagableImageSection(ExPageLockHandle);
    00963
    00964     } else if (ControlArea->u.Flags.Image) {
    00965         if (AllocationType & MEM_RESERVE) {
    00966             status = STATUS_INVALID_PARAMETER_9;
    00967         }
    00968         else if (WriteCombined == TRUE) {
    00969             status = STATUS_INVALID_PARAMETER_10;
    00970         } else {
    00971
    00972             status = MiMapViewOfImageSection (ControlArea,
    00973                                               Process,
    00974                                               CapturedBase,
    00975                                               SectionOffset,
    00976                                               CapturedViewSize,
    00977                                               Section,
    00978                                               InheritDisposition,
    00979                                               ZeroBits,
    00980                                               ImageCommitment,
    00981                                               &ReleasedWsMutex);
    00982         }
    00983
    00984     } else {
    00985
    00986         //
    00987         // Not an image section, therefore it is a data section.
    00988         //
    00989
    00990         if (WriteCombined == TRUE) {
    00991             status = STATUS_INVALID_PARAMETER_10;
    00992         }
    00993         else {
    00994             status = MiMapViewOfDataSection (ControlArea,
    00995                                          Process,
    00996                                          CapturedBase,
    00997                                          SectionOffset,
    00998                                          CapturedViewSize,
    00999                                          Section,
    01000                                          InheritDisposition,
    01001                                          ProtectionMask,
    01002                                          CommitSize,
    01003                                          ZeroBits,
    01004                                          AllocationType,
    01005                                          &ReleasedWsMutex
    01006                                         );
    01007         }
    01008     }
    01009
    01010 ErrorReturn:
    01011     if (!ReleasedWsMutex) {
    01012         UNLOCK_WS_AND_ADDRESS_SPACE (Process);
    01013     }
    01014     else {
    01015         UNLOCK_ADDRESS_SPACE (Process);
    01016     }
    01017
    01018     if (Attached) {
    01019         KeDetachProcess();
    01020     }
    01021
    01022     return status;
    01023 }
    01024
    01025 #ifndef _ALPHA_
    01026
    01027 NTSTATUS
    01028 MiMapViewOfPhysicalSection (
    01029     IN PCONTROL_AREA ControlArea,
    01030     IN PEPROCESS Process,
    01031     IN PVOID *CapturedBase,
    01032     IN PLARGE_INTEGER SectionOffset,
    01033     IN PSIZE_T CapturedViewSize,
    01034     IN ULONG ProtectionMask,
    01035     IN ULONG_PTR ZeroBits,
    01036     IN ULONG AllocationType,
    01037     IN BOOLEAN WriteCombined,
    01038     OUT PBOOLEAN ReleasedWsMutex
    01039     )
    01040
    01041 /*++
    01042
    01043 Routine Description:
    01044
    01045     This routine maps the specified physical section into the
    01046     specified process's address space.
    01047
    01048 Arguments:
    01049
    01050     see MmMapViewOfSection above...
    01051
    01052     ControlArea - Supplies the control area for the section.
    01053
    01054     Process - Supplies the process pointer which is receiving the section.
    01055
    01056     ProtectionMask - Supplies the initial page protection-mask.
    01057
    01058     ReleasedWsMutex - Supplies FALSE. If the working set mutex is
    01059                       not held when returning this must be set to TRUE
    01060                       so the caller will not release the unheld mutex.
    01061
    01062                       Note if this routine acquires the working set mutex
    01063                       it is always done unsafely as the address space mutex
    01064                       must be held on entry regardless.
    01065
    01066 Return Value:
    01067
    01068     Status of the map view operation.
    01069
    01070 Environment:
    01071
    01072     Kernel Mode, address creation mutex held.
    01073
    01074 --*/
    01075
    01076 {
    01077     PMMVAD Vad;
    01078     PVOID StartingAddress;
    01079     PVOID EndingAddress;
    01080     KIRQL OldIrql;
    01081     KIRQL OldIrql2;
    01082     PMMPTE PointerPpe;
    01083     PMMPTE PointerPde;
    01084     PMMPTE PointerPte;
    01085     PMMPTE LastPte;
    01086     MMPTE TempPte;
    01087     PMMPFN Pfn2;
    01088     SIZE_T PhysicalViewSize;
    01089     ULONG_PTR Alignment;
    01090     PVOID UsedPageTableHandle;
    01091     PVOID UsedPageDirectoryHandle;
    01092     PMI_PHYSICAL_VIEW PhysicalView;
    01093 #ifdef LARGE_PAGES
    01094     ULONG size;
    01095     PMMPTE protoPte;
    01096     ULONG pageSize;
    01097     PSUBSECTION Subsection;
    01098     ULONG EmPageSize;
    01099 #endif //LARGE_PAGES
    01100
    01101     //
    01102     // Physical memory section.
    01103     //
    01104
    01105     //
    01106     // If running on an R4000 and MEM_LARGE_PAGES is specified,
    01107     // set up the PTEs as a series of  pointers to the same
    01108     // prototype PTE.  This prototype PTE will reference a subsection
    01109     // that indicates large pages should be used.
    01110     //
    01111     // The R4000 supports pages of 4k, 16k, 64k, etc (powers of 4).
    01112     // Since the TB supports 2 entries, sizes of 8k, 32k etc can
    01113     // be mapped by 2 LargePages in a single TB entry.  These 2 entries
    01114     // are maintained in the subsection structure pointed to by the
    01115     // prototype PTE.
    01116     //
    01117
    01118     if (AllocationType & MEM_RESERVE) {
    01119         *ReleasedWsMutex = TRUE;
    01120         return STATUS_INVALID_PARAMETER_9;
    01121     }
    01122     Alignment = X64K;
    01123     LOCK_WS_UNSAFE (Process);
    01124
    01125 #ifdef LARGE_PAGES
    01126     if (AllocationType & MEM_LARGE_PAGES) {
    01127
    01128         //
    01129         // Determine the page size and the required alignment.
    01130         //
    01131
    01132         if ((SectionOffset->LowPart & (X64K - 1)) != 0) {
    01133             return STATUS_INVALID_PARAMETER_9;
    01134         }
    01135
    01136         size = (*CapturedViewSize - 1) >> (PAGE_SHIFT + 1);
    01137         pageSize = PAGE_SIZE;
    01138
    01139         while (size != 0) {
    01140             size = size >> 2;
    01141             pageSize = pageSize << 2;
    01142         }
    01143
    01144         Alignment = pageSize << 1;
    01145         if (Alignment < MM_VA_MAPPED_BY_PDE) {
    01146             Alignment = MM_VA_MAPPED_BY_PDE;
    01147         }
    01148
    01149 #if defined(_IA64_)
    01150
    01151         //
    01152         // Convert pageSize to the EM page-size field format.
    01153         //
    01154
    01155         EmPageSize = 0;
    01156         size = pageSize - 1 ;
    01157
    01158         while (size) {
    01159             size = size >> 1;
    01160             EmPageSize += 1;
    01161         }
    01162
    01163         if (*CapturedViewSize > pageSize) {
    01164
    01165             if (MmPageSizeInfo & (pageSize << 1)) {
    01166
    01167                 //
    01168                 // if larger page size is supported in the implementation
    01169                 //
    01170
    01171                 pageSize = pageSize << 1;
    01172                 EmPageSize += 1;
    01173
    01174             }
    01175             else {
    01176
    01177                 EmPageSize = EmPageSize | pageSize;
    01178
    01179             }
    01180         }
    01181
    01182         pageSize = EmPageSize;
    01183 #endif
    01184
    01185     }
    01186 #endif //LARGE_PAGES
    01187
    01188     if (*CapturedBase == NULL) {
    01189
    01190         //
    01191         // Attempt to locate address space.  This could raise an
    01192         // exception.
    01193         //
    01194
    01195         try {
    01196
    01197             //
    01198             // Find a starting address on a 64k boundary.
    01199             //
    01200 #ifdef i386
    01201             ASSERT (SectionOffset->HighPart == 0);
    01202 #endif
    01203
    01204 #ifdef LARGE_PAGES
    01205             if (AllocationType & MEM_LARGE_PAGES) {
    01206                 PhysicalViewSize = Alignment;
    01207             } else {
    01208 #endif //LARGE_PAGES
    01209
    01210                 PhysicalViewSize = *CapturedViewSize +
    01211                                        (SectionOffset->LowPart & (X64K - 1));
    01212 #ifdef LARGE_PAGES
    01213             }
    01214 #endif //LARGE_PAGES
    01215
    01216             StartingAddress = MiFindEmptyAddressRange (PhysicalViewSize,
    01217                                                        Alignment,
    01218                                                        (ULONG)ZeroBits);
    01219
    01220         } except (EXCEPTION_EXECUTE_HANDLER) {
    01221
    01222             return GetExceptionCode();
    01223         }
    01224
    01225         EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
    01226                                 PhysicalViewSize - 1L) | (PAGE_SIZE - 1L));
    01227         StartingAddress = (PVOID)((ULONG_PTR)StartingAddress +
    01228                                      (SectionOffset->LowPart & (X64K - 1)));
    01229
    01230         if (ZeroBits > 0) {
    01231             if (EndingAddress > (PVOID)((ULONG_PTR)MM_USER_ADDRESS_RANGE_LIMIT >> ZeroBits)) {
    01232                 return STATUS_NO_MEMORY;
    01233             }
    01234         }
    01235
    01236     } else {
    01237
    01238         //
    01239         // Check to make sure the specified base address to ending address
    01240         // is currently unused.
    01241         //
    01242
    01243         StartingAddress = (PVOID)((ULONG_PTR)MI_64K_ALIGN(*CapturedBase) +
    01244                                     (SectionOffset->LowPart & (X64K - 1)));
    01245         EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
    01246                                 *CapturedViewSize - 1L) | (PAGE_SIZE - 1L));
    01247
    01248 #ifdef LARGE_PAGES
    01249         if (AllocationType & MEM_LARGE_PAGES) {
    01250             if (((ULONG_PTR)StartingAddress & (Alignment - 1)) != 0) {
    01251                 return STATUS_CONFLICTING_ADDRESSES;
    01252             }
    01253             EndingAddress = (PVOID)((PCHAR)StartingAddress + Alignment);
    01254         }
    01255 #endif //LARGE_PAGES
    01256
    01257         Vad = MiCheckForConflictingVad (StartingAddress, EndingAddress);
    01258
    01259         if (Vad != (PMMVAD)NULL) {
    01260 #if DBG
    01261             MiDumpConflictingVad (StartingAddress, EndingAddress, Vad);
    01262 #endif
    01263
    01264             return STATUS_CONFLICTING_ADDRESSES;
    01265         }
    01266     }
    01267
    01268     //
    01269     // An unoccupied address range has been found, build the virtual
    01270     // address descriptor to describe this range.
    01271     //
    01272
    01273 #ifdef LARGE_PAGES
    01274     if (AllocationType & MEM_LARGE_PAGES) {
    01275         //
    01276         // Allocate a subsection and 4 prototype PTEs to hold
    01277         // the information for the large pages.
    01278         //
    01279
    01280         Subsection = ExAllocatePoolWithTag (NonPagedPool,
    01281                                      sizeof(SUBSECTION) + (4 * sizeof(MMPTE)),
    01282                                      MMPPTE_NAME);
    01283         if (Subsection == NULL) {
    01284             return STATUS_INSUFFICIENT_RESOURCES;
    01285         }
    01286     }
    01287 #endif //LARGE_PAGES
    01288
    01289     //
    01290     // Establish an exception handler and attempt to allocate
    01291     // the pool and charge quota.  Note that the InsertVad routine
    01292     // will also charge quota which could raise an exception.
    01293     //
    01294
    01295     try  {
    01296
    01297         PhysicalView = (PMI_PHYSICAL_VIEW)ExAllocatePoolWithTag (NonPagedPool,
    01298                                                                  sizeof(MI_PHYSICAL_VIEW),
    01299                                                                  MI_PHYSICAL_VIEW_KEY);
    01300         if (PhysicalView == NULL) {
    01301             ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
    01302         }
    01303
    01304         Vad = (PMMVAD)ExAllocatePoolWithTag (NonPagedPool,
    01305                                              sizeof(MMVAD),
    01306                                              MMVADKEY);
    01307         if (Vad == NULL) {
    01308             ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
    01309         }
    01310
    01311         PhysicalView->Vad = Vad;
    01312         PhysicalView->StartVa = StartingAddress;
    01313         PhysicalView->EndVa = EndingAddress;
    01314
    01315         RtlZeroMemory (Vad, sizeof(MMVAD));
    01316         Vad->StartingVpn = MI_VA_TO_VPN (StartingAddress);
    01317         Vad->EndingVpn = MI_VA_TO_VPN (EndingAddress);
    01318         Vad->ControlArea = ControlArea;
    01319         Vad->u2.VadFlags2.Inherit = MM_VIEW_UNMAP;
    01320         Vad->u.VadFlags.PhysicalMapping = 1;
    01321         Vad->u.VadFlags.Protection = ProtectionMask;
    01322
    01323         //
    01324         // Set the last contiguous PTE field in the Vad to the page frame
    01325         // number of the starting physical page.
    01326         //
    01327
    01328         Vad->LastContiguousPte = (PMMPTE)(ULONG)(
    01329                             SectionOffset->QuadPart >> PAGE_SHIFT);
    01330 #ifdef LARGE_PAGES
    01331     if (AllocationType & MEM_LARGE_PAGES) {
    01332         Vad->u.VadFlags.LargePages = 1;
    01333         Vad->FirstPrototypePte = (PMMPTE)Subsection;
    01334     } else {
    01335 #endif //LARGE_PAGES
    01336         // Vad->u.VadFlags.LargePages = 0;
    01337         Vad->FirstPrototypePte = Vad->LastContiguousPte;
    01338 #ifdef LARGE_PAGES
    01339     }
    01340 #endif //LARGE_PAGES
    01341
    01342         //
    01343         // Insert the VAD.  This could get an exception.
    01344         //
    01345
    01346         ASSERT (Vad->FirstPrototypePte <= Vad->LastContiguousPte);
    01347         MiInsertVad (Vad);
    01348
    01349     } except (EXCEPTION_EXECUTE_HANDLER) {
    01350
    01351         if (PhysicalView != NULL) {
    01352             ExFreePool (PhysicalView);
    01353         }
    01354
    01355         if (Vad != (PMMVAD)NULL) {
    01356
    01357             //
    01358             // The pool allocation succeeded, but the quota charge
    01359             // in InsertVad failed, deallocate the pool and return
    01360             // an error.
    01361             //
    01362
    01363             ExFreePool (Vad);
    01364 #ifdef LARGE_PAGES
    01365     if (AllocationType & MEM_LARGE_PAGES) {
    01366             ExFreePool (Subsection);
    01367     }
    01368 #endif //LARGE_PAGES
    01369             return GetExceptionCode();
    01370         }
    01371         return STATUS_INSUFFICIENT_RESOURCES;
    01372     }
    01373
    01374     //
    01375     // Increment the count of the number of views for the
    01376     // section object.  This requires the PFN lock to be held.
    01377     //
    01378
    01379     LOCK_AWE (Process, OldIrql);
    01380     LOCK_PFN2 (OldIrql2);
    01381
    01382     InsertHeadList (&Process->PhysicalVadList, &PhysicalView->ListEntry);
    01383
    01384     ControlArea->NumberOfMappedViews += 1;
    01385     ControlArea->NumberOfUserReferences += 1;
    01386
    01387     ASSERT (ControlArea->NumberOfSectionReferences != 0);
    01388
    01389     UNLOCK_PFN2 (OldIrql2);
    01390     UNLOCK_AWE (Process, OldIrql);
    01391
    01392     //
    01393     // Build the PTEs in the address space.
    01394     //
    01395
    01396     PointerPpe = MiGetPpeAddress (StartingAddress);
    01397     PointerPde = MiGetPdeAddress (StartingAddress);
    01398     PointerPte = MiGetPteAddress (StartingAddress);
    01399     LastPte = MiGetPteAddress (EndingAddress);
    01400
    01401     MI_MAKE_VALID_PTE (TempPte,
    01402                        (ULONG_PTR)Vad->LastContiguousPte,
    01403                        ProtectionMask,
    01404                        PointerPte);
    01405
    01406     if (WriteCombined == TRUE) {
    01407         MI_SET_PTE_WRITE_COMBINE (TempPte);
    01408     }
    01409
    01410     if (TempPte.u.Hard.Write) {
    01411         MI_SET_PTE_DIRTY (TempPte);
    01412     }
    01413
    01414 #if defined(_IA64_)
    01415     if (MI_IS_CACHING_DISABLED(&TempPte) || (WriteCombined == TRUE)) {
    01416         KeFlushEntireTb(FALSE, TRUE);
    01417     }
    01418 #endif
    01419
    01420 #ifdef LARGE_PAGES
    01421     if (AllocationType & MEM_LARGE_PAGES) {
    01422         Subsection->StartingSector = pageSize;
    01423         Subsection->EndingSector = (ULONG_PTR)StartingAddress;
    01424         Subsection->u.LongFlags = 0;
    01425         Subsection->u.SubsectionFlags.LargePages = 1;
    01426         protoPte = (PMMPTE)(Subsection + 1);
    01427
    01428         //
    01429         // Build the first 2 PTEs as entries for the TLB to
    01430         // map the specified physical address.
    01431         //
    01432
    01433         *protoPte = TempPte;
    01434         protoPte += 1;
    01435
    01436         if (*CapturedViewSize > pageSize) {
    01437             *protoPte = TempPte;
    01438             protoPte->u.Hard.PageFrameNumber += (pageSize >> PAGE_SHIFT);
    01439         } else {
    01440             *protoPte = ZeroPte;
    01441         }
    01442         protoPte += 1;
    01443
    01444         //
    01445         // Build the first prototype PTE as a paging file format PTE
    01446         // referring to the subsection.
    01447         //
    01448
    01449         protoPte->u.Long = MiGetSubsectionAddressForPte (Subsection);
    01450         protoPte->u.Soft.Prototype = 1;
    01451         protoPte->u.Soft.Protection = ProtectionMask;
    01452
    01453         //
    01454         // Set the PTE up for all the user's PTE entries, proto pte
    01455         // format pointing to the 3rd prototype PTE.
    01456         //
    01457
    01458         TempPte.u.Long = MiProtoAddressForPte (protoPte);
    01459     }
    01460
    01461     if (!(AllocationType & MEM_LARGE_PAGES)) {
    01462 #endif //LARGE_PAGES
    01463
    01464 #if defined (_WIN64)
    01465         MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE);
    01466         if (PointerPde->u.Long == 0) {
    01467             UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte);
    01468             MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle);
    01469         }
    01470 #endif
    01471
    01472         MiMakePdeExistAndMakeValid (PointerPde, Process, FALSE);
    01473
    01474         Pfn2 = MI_PFN_ELEMENT (PointerPde->u.Hard.PageFrameNumber);
    01475
    01476         UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (StartingAddress);
    01477
    01478         while (PointerPte <= LastPte) {
    01479
    01480             if (MiIsPteOnPdeBoundary (PointerPte)) {
    01481
    01482                 PointerPde = MiGetPteAddress (PointerPte);
    01483
    01484                 if (MiIsPteOnPpeBoundary (PointerPte)) {
    01485                     PointerPpe = MiGetPteAddress (PointerPde);
    01486                     MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE);
    01487                 }
    01488
    01489 #if defined (_WIN64)
    01490                 if (PointerPde->u.Long == 0) {
    01491                     UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte);
    01492                     MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle);
    01493                 }
    01494 #endif
    01495
    01496                 MiMakePdeExistAndMakeValid (PointerPde, Process, FALSE);
    01497                 Pfn2 = MI_PFN_ELEMENT (PointerPde->u.Hard.PageFrameNumber);
    01498                 UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (MiGetVirtualAddressMappedByPte (PointerPte));
    01499             }
    01500
    01501             ASSERT (PointerPte->u.Long == 0);
    01502
    01503             MI_WRITE_VALID_PTE (PointerPte, TempPte);
    01504
    01505             CONSISTENCY_LOCK_PFN (OldIrql);
    01506
    01507             Pfn2->u2.ShareCount += 1;
    01508
    01509             CONSISTENCY_UNLOCK_PFN (OldIrql);
    01510
    01511             //
    01512             // Increment the count of non-zero page table entries for this
    01513             // page table and the number of private pages for the process.
    01514             //
    01515
    01516             MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableHandle);
    01517
    01518             PointerPte += 1;
    01519             TempPte.u.Hard.PageFrameNumber += 1;
    01520         }
    01521 #ifdef LARGE_PAGES
    01522     }
    01523 #endif //LARGE_PAGES
    01524
    01525 #if defined(i386)
    01526     //
    01527     // If write combined was specified then flush all caches and TBs.
    01528     //
    01529
    01530     if (WriteCombined == TRUE && MiWriteCombiningPtes == TRUE) {
    01531         KeFlushEntireTb (FALSE, TRUE);
    01532         KeInvalidateAllCaches (TRUE);
    01533     }
    01534 #endif
    01535
    01536 #if defined(_IA64_)
    01537     if (MI_IS_CACHING_DISABLED(&TempPte) || (WriteCombined == TRUE)) {
    01538         MiSweepCacheMachineDependent(StartingAddress,
    01539                                      (PCHAR)EndingAddress - (PCHAR)StartingAddress + 1L,
    01540                                      MmWriteCombined);
    01541     }
    01542 #endif
    01543
    01544     UNLOCK_WS_UNSAFE (Process);
    01545     *ReleasedWsMutex = TRUE;
    01546
    01547     //
    01548     // Update the current virtual size in the process header.
    01549     //
    01550
    01551     *CapturedViewSize = (PCHAR)EndingAddress - (PCHAR)StartingAddress + 1L;
    01552     Process->VirtualSize += *CapturedViewSize;
    01553
    01554     if (Process->VirtualSize > Process->PeakVirtualSize) {
    01555         Process->PeakVirtualSize = Process->VirtualSize;
    01556     }
    01557
    01558     *CapturedBase = StartingAddress;
    01559
    01560     return STATUS_SUCCESS;
    01561 }
    01562
    01563 #endif
    01564
    01565
    01566 NTSTATUS
    01567 MiMapViewOfImageSection (
    01568     IN PCONTROL_AREA ControlArea,
    01569     IN PEPROCESS Process,
    01570     IN PVOID *CapturedBase,
    01571     IN PLARGE_INTEGER SectionOffset,
    01572     IN PSIZE_T CapturedViewSize,
    01573     IN PSECTION Section,
    01574     IN SECTION_INHERIT InheritDisposition,
    01575     IN ULONG_PTR ZeroBits,
    01576     IN SIZE_T ImageCommitment,
    01577     IN OUT PBOOLEAN ReleasedWsMutex
    01578     )
    01579
    01580 /*++
    01581
    01582 Routine Description:
    01583
    01584     This routine maps the specified Image section into the
    01585     specified process's address space.
    01586
    01587 Arguments:
    01588
    01589     see MmMapViewOfSection above...
    01590
    01591     ControlArea - Supplies the control area for the section.
    01592
    01593     Process - Supplies the process pointer which is receiving the section.
    01594
    01595     ReleasedWsMutex - Supplies FALSE. If the working set mutex is
    01596                       not held when returning this must be set to TRUE
    01597                       so the caller will not release the unheld mutex.
    01598
    01599                       Note if this routine acquires the working set mutex
    01600                       it is always done unsafely as the address space mutex
    01601                       must be held on entry regardless.
    01602
    01603 Return Value:
    01604
    01605     Status of the map view operation.
    01606
    01607 Environment:
    01608
    01609     Kernel Mode, address creation mutex held.
    01610
    01611 --*/
    01612
    01613 {
    01614     PMMVAD Vad;
    01615     PVOID StartingAddress;
    01616     PVOID EndingAddress;
    01617     BOOLEAN Attached;
    01618     KIRQL OldIrql;
    01619     PSUBSECTION Subsection;
    01620     ULONG PteOffset;
    01621     NTSTATUS ReturnedStatus;
    01622     PMMPTE ProtoPte;
    01623     PVOID BasedAddress;
    01624     SIZE_T NeededViewSize;
    01625 #if defined(_ALPHA_)
    01626     ULONG_PTR Starting2gb;
    01627     ULONG_PTR Ending2gb;
    01628     ULONG_PTR BoundaryMask;
    01629     LOGICAL AlignmentOk;
    01630 #endif
    01631 #if defined(_MIALT4K_)
    01632     PMMPTE PointerAltPte;
    01633     PMMPTE ProtoAltPte;
    01634     MMPTE TempAltPte;
    01635     PIMAGE_NT_HEADERS NtHeaders;
    01636     ULONG ImageAlignment;
    01637 #endif
    01638
    01639     Attached = FALSE;
    01640
    01641     //
    01642     // Image file.
    01643     //
    01644     // Locate the first subsection (text) and create a virtual
    01645     // address descriptor to map the entire image here.
    01646     //
    01647
    01648     if (ControlArea->u.Flags.GlobalOnlyPerSession == 0) {
    01649         Subsection = (PSUBSECTION)(ControlArea + 1);
    01650     }
    01651     else {
    01652         Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
    01653     }
    01654
    01655     if (ControlArea->u.Flags.ImageMappedInSystemSpace) {
    01656
    01657         if (KeGetPreviousMode() != KernelMode) {
    01658
    01659             //
    01660             // Mapping in system space as a driver, hence copy on write does
    01661             // not work.  Don't allow user processes to map the image.
    01662             //
    01663
    01664             *ReleasedWsMutex = TRUE;
    01665             return STATUS_CONFLICTING_ADDRESSES;
    01666         }
    01667     }
    01668
    01669     //
    01670     // Check to see if a purge operation is in progress and if so, wait
    01671     // for the purge to complete.  In addition, up the count of mapped
    01672     // views for this control area.
    01673     //
    01674
    01675     if (MiCheckPurgeAndUpMapCount (ControlArea) == FALSE) {
    01676         *ReleasedWsMutex = TRUE;
    01677         return STATUS_INSUFFICIENT_RESOURCES;
    01678     }
    01679
    01680     //
    01681     // Capture the based address to the stack, to prevent page faults.
    01682     //
    01683
    01684     BasedAddress = ControlArea->Segment->BasedAddress;
    01685
    01686     if (*CapturedViewSize == 0) {
    01687         *CapturedViewSize =
    01688             (ULONG_PTR)(Section->SizeOfSection.QuadPart - SectionOffset->QuadPart);
    01689     }
    01690
    01691     LOCK_WS_UNSAFE (Process);
    01692
    01693     ReturnedStatus = STATUS_SUCCESS;
    01694
    01695     //
    01696     // Determine if a specific base was specified.
    01697     //
    01698
    01699     if (*CapturedBase != NULL) {
    01700
    01701         //
    01702         // Captured base is not NULL.
    01703         //
    01704         // Check to make sure the specified address range is currently unused
    01705         // and within the user address space.
    01706         //
    01707
    01708         Vad = (PMMVAD)1;
    01709         StartingAddress = MI_64K_ALIGN(*CapturedBase);
    01710         EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
    01711                                        *CapturedViewSize - 1) | (PAGE_SIZE - 1));
    01712
    01713         if ((StartingAddress <=  MM_HIGHEST_VAD_ADDRESS) &&
    01714             (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) -
    01715                                 (ULONG_PTR)StartingAddress >= *CapturedViewSize) &&
    01716
    01717             (EndingAddress <= MM_HIGHEST_VAD_ADDRESS)) {
    01718
    01719             Vad = MiCheckForConflictingVad (StartingAddress, EndingAddress);
    01720         }
    01721
    01722         if (Vad != NULL) {
    01723 #if DBG
    01724             if (Vad != (PMMVAD)1) {
    01725                 MiDumpConflictingVad (StartingAddress, EndingAddress, Vad);
    01726             }
    01727 #endif
    01728
    01729             LOCK_PFN (OldIrql);
    01730             ControlArea->NumberOfMappedViews -= 1;
    01731             ControlArea->NumberOfUserReferences -= 1;
    01732
    01733             //
    01734             // Check to see if the control area (segment) should be deleted.
    01735             // This routine releases the PFN lock.
    01736             //
    01737
    01738             MiCheckControlArea (ControlArea, Process, OldIrql);
    01739             return STATUS_CONFLICTING_ADDRESSES;
    01740         }
    01741
    01742         //
    01743         // A conflicting VAD was not found and the specified address range is
    01744         // within the user address space. If the image will not reside at its
    01745         // base address, then set a special return status.
    01746         //
    01747
    01748         if (((ULONG_PTR)StartingAddress +
    01749             (ULONG_PTR)MI_64K_ALIGN(SectionOffset->LowPart)) != (ULONG_PTR)BasedAddress) {
    01750             ReturnedStatus = STATUS_IMAGE_NOT_AT_BASE;
    01751         }
    01752
    01753     } else {
    01754
    01755         //
    01756         // Captured base is NULL.
    01757         //
    01758         // If the captured view size is greater than the largest size that
    01759         // can fit in the user address space, then it is not possible to map
    01760         // the image.
    01761         //
    01762
    01763         if ((PVOID)*CapturedViewSize > MM_HIGHEST_VAD_ADDRESS) {
    01764             LOCK_PFN (OldIrql);
    01765             ControlArea->NumberOfMappedViews -= 1;
    01766             ControlArea->NumberOfUserReferences -= 1;
    01767
    01768             //
    01769             // Check to see if the control area (segment) should be deleted.
    01770             // This routine releases the PFN lock.
    01771             //
    01772
    01773             MiCheckControlArea (ControlArea, Process, OldIrql);
    01774             return STATUS_NO_MEMORY;
    01775         }
    01776
    01777         //
    01778         // Check to make sure the specified address range is currently unused
    01779         // and within the user address space.
    01780         //
    01781
    01782         StartingAddress = (PVOID)((ULONG_PTR)BasedAddress +
    01783                                     (ULONG_PTR)MI_64K_ALIGN(SectionOffset->LowPart));
    01784
    01785         EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
    01786                                     *CapturedViewSize - 1) | (PAGE_SIZE - 1));
    01787
    01788         Vad = (PMMVAD)1;
    01789         NeededViewSize = *CapturedViewSize;
    01790
    01791 #if defined(_ALPHA_)
    01792
    01793 #if defined(_AXP64_)
    01794 #define BOUNDARY ((LONG_PTR)_2gb)
    01795 #else
    01796 #define BOUNDARY ((ULONG_PTR)_2gb)
    01797 #endif
    01798
    01799         //
    01800         // Alpha images cannot span 2GB boundaries with the current compiler
    01801         // generated branch instructions.  If a spanning image is detected, it
    01802         // must be relocated.
    01803         //
    01804
    01805         BoundaryMask = (ULONG_PTR)~(BOUNDARY-1);
    01806
    01807         Starting2gb = (ULONG_PTR)StartingAddress & BoundaryMask;
    01808         Ending2gb = (ULONG_PTR)EndingAddress & BoundaryMask;
    01809
    01810         AlignmentOk = TRUE;
    01811
    01812         if (Starting2gb != Ending2gb) {
    01813             AlignmentOk = FALSE;
    01814             if (Starting2gb + 1 == Ending2gb) {
    01815                 if (((ULONG_PTR)EndingAddress & (BOUNDARY-1)) == 0) {
    01816                     AlignmentOk = TRUE;
    01817                 }
    01818             }
    01819         }
    01820
    01821         if (AlignmentOk == FALSE) {
    01822
    01823             //
    01824             // Find twice the required size so that it can be placed correctly.
    01825             //
    01826
    01827             NeededViewSize = *CapturedViewSize * 2 + X64K;
    01828         }
    01829         else
    01830 #endif
    01831
    01832         if ((StartingAddress >= MM_LOWEST_USER_ADDRESS) &&
    01833             (StartingAddress <= MM_HIGHEST_VAD_ADDRESS) &&
    01834             (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) -
    01835                                 (ULONG_PTR)StartingAddress >= *CapturedViewSize) &&
    01836
    01837             (EndingAddress <= MM_HIGHEST_VAD_ADDRESS)) {
    01838
    01839             Vad = MiCheckForConflictingVad (StartingAddress, EndingAddress);
    01840         }
    01841
    01842         //
    01843         // If the VAD address is not NULL, then a conflict was discovered.
    01844         // Attempt to select another address range in which to map the image.
    01845         //
    01846
    01847         if (Vad != (PMMVAD)NULL) {
    01848
    01849             //
    01850             // The image could not be mapped at its natural base address
    01851             // try to find another place to map it.
    01852             //
    01853 #if DBG
    01854             if (Vad != (PMMVAD)1) {
    01855                 MiDumpConflictingVad (StartingAddress, EndingAddress, Vad);
    01856             }
    01857 #endif
    01858
    01859             //
    01860             // If the system has been biased to an alternate base address to
    01861             // allow 3gb of user address space, then make sure the high order
    01862             // address bit is zero.
    01863             //
    01864
    01865 #if defined(_X86_)
    01866
    01867             if ((MmVirtualBias != 0) &&
    01868                 (ZeroBits == 0)) {
    01869                 ZeroBits = 1;
    01870             }
    01871 #endif
    01872
    01873             ReturnedStatus = STATUS_IMAGE_NOT_AT_BASE;
    01874             try {
    01875
    01876                 //
    01877                 // Find a starting address on a 64k boundary.
    01878                 //
    01879
    01880                 StartingAddress = MiFindEmptyAddressRange (NeededViewSize,
    01881                                                            X64K,
    01882                                                            (ULONG)ZeroBits);
    01883
    01884
    01885             } except (EXCEPTION_EXECUTE_HANDLER) {
    01886                 LOCK_PFN (OldIrql);
    01887                 ControlArea->NumberOfMappedViews -= 1;
    01888                 ControlArea->NumberOfUserReferences -= 1;
    01889
    01890                 //
    01891                 // Check to see if the control area (segment) should be deleted.
    01892                 // This routine releases the PFN lock.
    01893                 //
    01894
    01895                 MiCheckControlArea (ControlArea, Process, OldIrql);
    01896
    01897                 return GetExceptionCode();
    01898             }
    01899
    01900             EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
    01901                                         *CapturedViewSize - 1) | (PAGE_SIZE - 1));
    01902
    01903 #if defined(_ALPHA_)
    01904
    01905             if (AlignmentOk == FALSE) {
    01906                 Starting2gb = (ULONG_PTR)StartingAddress & ~(BOUNDARY-1);
    01907                 Ending2gb = (ULONG_PTR)EndingAddress & ~(BOUNDARY-1);
    01908
    01909                 if (Starting2gb != Ending2gb) {
    01910
    01911                     //
    01912                     // Not in the same 2gb.  Up the start to a 2gb boundary.
    01913                     //
    01914
    01915                     StartingAddress = (PVOID)Ending2gb;
    01916                     EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
    01917                                         *CapturedViewSize - 1) | (PAGE_SIZE - 1));
    01918                 }
    01919             }
    01920 #endif
    01921
    01922         }
    01923     }
    01924
    01925     //
    01926     // Allocate and initialize a VAD for the specified address range.
    01927     //
    01928
    01929     Vad = ExAllocatePoolWithTag (NonPagedPool, sizeof(MMVAD), MMVADKEY);
    01930     try  {
    01931         if (Vad == NULL) {
    01932             ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
    01933         }
    01934
    01935         RtlZeroMemory (Vad, sizeof(MMVAD));
    01936         Vad->StartingVpn = MI_VA_TO_VPN (StartingAddress);
    01937         Vad->EndingVpn = MI_VA_TO_VPN (EndingAddress);
    01938         Vad->u2.VadFlags2.Inherit = (InheritDisposition == ViewShare);
    01939         Vad->u.VadFlags.ImageMap = 1;
    01940
    01941         //
    01942         // Set the protection in the VAD as EXECUTE_WRITE_COPY.
    01943         //
    01944
    01945         Vad->u.VadFlags.Protection = MM_EXECUTE_WRITECOPY;
    01946         Vad->ControlArea = ControlArea;
    01947
    01948         //
    01949         // Set the first prototype PTE field in the Vad.
    01950         //
    01951
    01952         SectionOffset->LowPart = SectionOffset->LowPart & ~(X64K - 1);
    01953         PteOffset = (ULONG)(SectionOffset->QuadPart >> PAGE_SHIFT);
    01954
    01955         Vad->FirstPrototypePte = &Subsection->SubsectionBase[PteOffset];
    01956         Vad->LastContiguousPte = MM_ALLOCATION_FILLS_VAD;
    01957
    01958         //
    01959         // NOTE: the full commitment is charged even if a partial map of an
    01960         // image is being done.  This saves from having to run through the
    01961         // entire image (via prototype PTEs) and calculate the charge on
    01962         // a per page basis for the partial map.
    01963         //
    01964
    01965         Vad->u.VadFlags.CommitCharge = (SIZE_T)ImageCommitment; // ****** temp
    01966
    01967         ASSERT (Vad->FirstPrototypePte <= Vad->LastContiguousPte);
    01968
    01969         MiInsertVad (Vad);
    01970
    01971     } except (EXCEPTION_EXECUTE_HANDLER) {
    01972         LOCK_PFN (OldIrql);
    01973         ControlArea->NumberOfMappedViews -= 1;
    01974         ControlArea->NumberOfUserReferences -= 1;
    01975
    01976         //
    01977         // Check to see if the control area (segment) should be deleted.
    01978         // This routine releases the PFN lock.
    01979         //
    01980
    01981         MiCheckControlArea (ControlArea, Process, OldIrql);
    01982
    01983         if (Vad != (PMMVAD)NULL) {
    01984
    01985             //
    01986             // The pool allocation succeeded, but the quota charge
    01987             // in InsertVad failed, deallocate the pool and return
    01988             // an error.
    01989             //
    01990
    01991             ExFreePool (Vad);
    01992             return GetExceptionCode();
    01993         }
    01994
    01995         return STATUS_INSUFFICIENT_RESOURCES;
    01996     }
    01997
    01998     *CapturedViewSize = (PCHAR)EndingAddress - (PCHAR)StartingAddress + 1L;
    01999     *CapturedBase = StartingAddress;
    02000
    02001 #if DBG
    02002     if (MmDebug & MM_DBG_WALK_VAD_TREE) {
    02003         DbgPrint("mapped image section vads\n");
    02004         VadTreeWalk(Process->VadRoot);
    02005     }
    02006 #endif
    02007
    02008     //
    02009     // Update the current virtual size in the process header.
    02010     //
    02011
    02012     Process->VirtualSize += *CapturedViewSize;
    02013
    02014     if (Process->VirtualSize > Process->PeakVirtualSize) {
    02015         Process->PeakVirtualSize = Process->VirtualSize;
    02016     }
    02017
    02018     if (ControlArea->u.Flags.FloppyMedia) {
    02019
    02020         *ReleasedWsMutex = TRUE;
    02021         UNLOCK_WS_UNSAFE (Process);
    02022
    02023         //
    02024         // The image resides on a floppy disk, in-page all
    02025         // pages from the floppy and mark them as modified so
    02026         // they migrate to the paging file rather than reread
    02027         // them from the floppy disk which may have been removed.
    02028         //
    02029
    02030         ProtoPte = Vad->FirstPrototypePte;
    02031
    02032         //
    02033         // This could get an in-page error from the floppy.
    02034         //
    02035
    02036         while (StartingAddress < EndingAddress) {
    02037
    02038             //
    02039             // If the prototype PTE is valid, transition or
    02040             // in prototype PTE format, bring the page into
    02041             // memory and set the modified bit.
    02042             //
    02043
    02044             if ((ProtoPte->u.Hard.Valid == 1) ||
    02045                 (ProtoPte->u.Soft.Prototype == 1) ||
    02046                 (ProtoPte->u.Soft.Transition == 1)) {
    02047
    02048                 try {
    02049
    02050                     MiSetPageModified (StartingAddress);
    02051
    02052                 } except (EXCEPTION_EXECUTE_HANDLER) {
    02053
    02054                     //
    02055                     // An in page error must have occurred touching the image,
    02056                     // ignore the error and continue to the next page.
    02057                     //
    02058
    02059                     NOTHING;
    02060                 }
    02061             }
    02062             ProtoPte += 1;
    02063             StartingAddress = (PVOID)((PCHAR)StartingAddress + PAGE_SIZE);
    02064         }
    02065     }
    02066
    02067     if (!*ReleasedWsMutex) {
    02068         *ReleasedWsMutex = TRUE;
    02069         UNLOCK_WS_UNSAFE (Process);
    02070     }
    02071
    02072     if (NT_SUCCESS(ReturnedStatus)) {
    02073
    02074
    02075         //
    02076         // Check to see if this image is for the architecture of the current
    02077         // machine.
    02078         //
    02079
    02080         if (ControlArea->Segment->ImageInformation->ImageContainsCode &&
    02081             ((ControlArea->Segment->ImageInformation->Machine <
    02082                                           USER_SHARED_DATA->ImageNumberLow) ||
    02083              (ControlArea->Segment->ImageInformation->Machine >
    02084                                           USER_SHARED_DATA->ImageNumberHigh)
    02085             )
    02086            ) {
    02087 #if defined (_WIN64)
    02088
    02089             //
    02090             // If this is a wow64 process, allow i386 images
    02091             //
    02092
    02093             if (!Process->Wow64Process ||
    02094                 ControlArea->Segment->ImageInformation->Machine != IMAGE_FILE_MACHINE_I386) {
    02095                 return STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
    02096             }
    02097 #else
    02098             return STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
    02099 #endif
    02100         }
    02101
    02102         StartingAddress = MI_VPN_TO_VA (Vad->StartingVpn);
    02103
    02104         if (PsImageNotifyEnabled) {
    02105
    02106             IMAGE_INFO ImageInfo;
    02107
    02108             if ( (StartingAddress < MmHighestUserAddress) &&
    02109                  Process->UniqueProcessId &&
    02110                  Process != PsInitialSystemProcess ) {
    02111
    02112                 ImageInfo.Properties = 0;
    02113                 ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
    02114                 ImageInfo.ImageBase = StartingAddress;
    02115                 ImageInfo.ImageSize = *CapturedViewSize;
    02116                 ImageInfo.ImageSelector = 0;
    02117                 ImageInfo.ImageSectionNumber = 0;
    02118                 PsCallImageNotifyRoutines(
    02119                             (PUNICODE_STRING) &ControlArea->FilePointer->FileName,
    02120                             Process->UniqueProcessId,
    02121                             &ImageInfo
    02122                             );
    02123             }
    02124         }
    02125
    02126         if ((NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD) &&
    02127             (ControlArea->u.Flags.Image) &&
    02128             (ReturnedStatus != STATUS_IMAGE_NOT_AT_BASE)) {
    02129             if (ControlArea->u.Flags.DebugSymbolsLoaded == 0) {
    02130                 if (CacheImageSymbols (StartingAddress)) {
    02131
    02132                     //
    02133                     //  TEMP TEMP TEMP rip out when debugger converted
    02134                     //
    02135
    02136                     PUNICODE_STRING FileName;
    02137                     ANSI_STRING AnsiName;
    02138                     NTSTATUS Status;
    02139
    02140                     LOCK_PFN (OldIrql);
    02141                     ControlArea->u.Flags.DebugSymbolsLoaded = 1;
    02142                     UNLOCK_PFN (OldIrql);
    02143
    02144                     FileName = (PUNICODE_STRING)&ControlArea->FilePointer->FileName;
    02145                     if (FileName->Length != 0 && (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)) {
    02146                         PLIST_ENTRY Head, Next;
    02147                         PLDR_DATA_TABLE_ENTRY Entry;
    02148
    02149                         KeEnterCriticalRegion();
    02150                         ExAcquireResourceExclusive (&PsLoadedModuleResource, TRUE);
    02151                         Head = &MmLoadedUserImageList;
    02152                         Next = Head->Flink;
    02153                         while (Next != Head) {
    02154                             Entry = CONTAINING_RECORD( Next,
    02155                                                        LDR_DATA_TABLE_ENTRY,
    02156                                                        InLoadOrderLinks
    02157                                                      );
    02158                             if (Entry->DllBase == StartingAddress) {
    02159                                 Entry->LoadCount += 1;
    02160                                 break;
    02161                             }
    02162                             Next = Next->Flink;
    02163                         }
    02164
    02165                         if (Next == Head) {
    02166                             Entry = ExAllocatePoolWithTag( NonPagedPool,
    02167                                                     sizeof( *Entry ) +
    02168                                                         FileName->Length +
    02169                                                         sizeof( UNICODE_NULL ),
    02170                                                         MMDB
    02171                                                   );
    02172                             if (Entry != NULL) {
    02173                                 PIMAGE_NT_HEADERS NtHeaders;
    02174
    02175                                 RtlZeroMemory (Entry, sizeof(*Entry));
    02176
    02177                                 try {
    02178                                     NtHeaders = RtlImageNtHeader (StartingAddress);
    02179                                     if (NtHeaders != NULL) {
    02180 #if defined(_WIN64)
    02181                                         if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
    02182                                             Entry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;
    02183                                             Entry->CheckSum = NtHeaders->OptionalHeader.CheckSum;
    02184                                         }
    02185                                         else {
    02186                                             PIMAGE_NT_HEADERS32 NtHeaders32 = (PIMAGE_NT_HEADERS32)NtHeaders;
    02187
    02188                                             Entry->SizeOfImage = NtHeaders32->OptionalHeader.SizeOfImage;
    02189                                             Entry->CheckSum = NtHeaders32->OptionalHeader.CheckSum;
    02190                                         }
    02191 #else
    02192                                         Entry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;
    02193                                         Entry->CheckSum = NtHeaders->OptionalHeader.CheckSum;
    02194 #endif
    02195                                     }
    02196                                 } except (EXCEPTION_EXECUTE_HANDLER) {
    02197                                     NOTHING;
    02198                                 }
    02199
    02200                                 Entry->DllBase = StartingAddress;
    02201                                 Entry->FullDllName.Buffer = (PWSTR)(Entry+1);
    02202                                 Entry->FullDllName.Length = FileName->Length;
    02203                                 Entry->FullDllName.MaximumLength = (USHORT)
    02204                                     (Entry->FullDllName.Length + sizeof( UNICODE_NULL ));
    02205                                 RtlMoveMemory( Entry->FullDllName.Buffer,
    02206                                                FileName->Buffer,
    02207                                                FileName->Length
    02208                                              );
    02209                                 Entry->FullDllName.Buffer[ Entry->FullDllName.Length / sizeof( WCHAR )] = UNICODE_NULL;
    02210                                 Entry->LoadCount = 1;
    02211                                 InsertTailList( &MmLoadedUserImageList,
    02212                                                 &Entry->InLoadOrderLinks
    02213                                               );
    02214                                 InitializeListHead( &Entry->InInitializationOrderLinks );
    02215                                 InitializeListHead( &Entry->InMemoryOrderLinks );
    02216                             }
    02217                         }
    02218
    02219                         ExReleaseResource (&PsLoadedModuleResource);
    02220                         KeLeaveCriticalRegion();
    02221                     }
    02222
    02223                     Status = RtlUnicodeStringToAnsiString( &AnsiName,
    02224                                                            FileName,
    02225                                                            TRUE );
    02226
    02227                     if (NT_SUCCESS( Status)) {
    02228                         DbgLoadImageSymbols( &AnsiName,
    02229                                              StartingAddress,
    02230                                              (ULONG_PTR)Process
    02231                                            );
    02232                         RtlFreeAnsiString( &AnsiName );
    02233                     }
    02234                 }
    02235             }
    02236         }
    02237     }
    02238
    02239 #if defined(_MIALT4K_)
    02240
    02241     if (Process->Wow64Process != NULL) {
    02242
    02243         MiProtectImageFileFor4kPage(StartingAddress,
    02244                                     *CapturedViewSize,
    02245                                     Vad->FirstPrototypePte,
    02246                                     Process);
    02247     }
    02248
    02249 #endif
    02250
    02251     return ReturnedStatus;
    02252
    02253 }
    02254
    02255 NTSTATUS
    02256 MiMapViewOfDataSection (
    02257     IN PCONTROL_AREA ControlArea,
    02258     IN PEPROCESS Process,
    02259     IN PVOID *CapturedBase,
    02260     IN PLARGE_INTEGER SectionOffset,
    02261     IN PSIZE_T CapturedViewSize,
    02262     IN PSECTION Section,
    02263     IN SECTION_INHERIT InheritDisposition,
    02264     IN ULONG ProtectionMask,
    02265     IN SIZE_T CommitSize,
    02266     IN ULONG_PTR ZeroBits,
    02267     IN ULONG AllocationType,
    02268     IN PBOOLEAN ReleasedWsMutex
    02269     )
    02270
    02271 /*++
    02272
    02273 Routine Description:
    02274
    02275     This routine maps the specified physical section into the
    02276     specified process's address space.
    02277
    02278 Arguments:
    02279
    02280     see MmMapViewOfSection above...
    02281
    02282     ControlArea - Supplies the control area for the section.
    02283
    02284     Process - Supplies the process pointer which is receiving the section.
    02285
    02286     ProtectionMask - Supplies the initial page protection-mask.
    02287
    02288     ReleasedWsMutex - Supplies FALSE. If the working set mutex is
    02289                       not held when returning this must be set to TRUE
    02290                       so the caller will not release the unheld mutex.
    02291
    02292                       Note if this routine acquires the working set mutex
    02293                       it is always done unsafely as the address space mutex
    02294                       must be held on entry regardless.
    02295
    02296 Return Value:
    02297
    02298     Status of the map view operation.
    02299
    02300 Environment:
    02301
    02302     Kernel Mode, address creation mutex held.
    02303
    02304 --*/
    02305
    02306 {
    02307     PMMVAD Vad;
    02308     PVOID StartingAddress;
    02309     PVOID EndingAddress;
    02310     BOOLEAN Attached;
    02311     KIRQL OldIrql;
    02312     PSUBSECTION Subsection;
    02313     ULONG PteOffset;
    02314     PMMPTE PointerPte;
    02315     PMMPTE LastPte;
    02316     MMPTE TempPte;
    02317     ULONG_PTR Alignment;
    02318     SIZE_T QuotaCharge;
    02319     BOOLEAN ChargedQuota;
    02320     PMMPTE TheFirstPrototypePte;
    02321     PVOID CapturedStartingVa;
    02322     ULONG CapturedCopyOnWrite;
    02323 #if defined(_MIALT4K_)
    02324     SIZE_T ViewSizeFor4k;
    02325 #endif
    02326
    02327     Attached = FALSE;
    02328     QuotaCharge = 0;
    02329     ChargedQuota = FALSE;
    02330
    02331     if ((AllocationType & MEM_RESERVE) &&
    02332         (ControlArea->FilePointer == NULL)) {
    02333         *ReleasedWsMutex = TRUE;
    02334         return STATUS_INVALID_PARAMETER_9;
    02335     }
    02336
    02337     //
    02338     // Check to see if there is a purge operation ongoing for
    02339     // this segment.
    02340     //
    02341
    02342     if ((AllocationType & MEM_DOS_LIM) != 0) {
    02343         if ((*CapturedBase == NULL) ||
    02344             (AllocationType & MEM_RESERVE)) {
    02345
    02346             //
    02347             // If MEM_DOS_LIM is specified, the address to map the
    02348             // view MUST be specified as well.
    02349             //
    02350
    02351             *ReleasedWsMutex = TRUE;
    02352             return STATUS_INVALID_PARAMETER_3;
    02353         }
    02354         Alignment = PAGE_SIZE;
    02355     } else {
    02356        Alignment = X64K;
    02357     }
    02358
    02359     //
    02360     // Check to see if a purge operation is in progress and if so, wait
    02361     // for the purge to complete.  In addition, up the count of mapped
    02362     // views for this control area.
    02363     //
    02364
    02365     if (MiCheckPurgeAndUpMapCount (ControlArea) == FALSE) {
    02366         *ReleasedWsMutex = TRUE;
    02367         return STATUS_INSUFFICIENT_RESOURCES;
    02368     }
    02369
    02370     if (*CapturedViewSize == 0) {
    02371
    02372         SectionOffset->LowPart = SectionOffset->LowPart & ~((ULONG)Alignment - 1);
    02373         *CapturedViewSize = (ULONG_PTR)(Section->SizeOfSection.QuadPart -
    02374                                     SectionOffset->QuadPart);
    02375     } else {
    02376         *CapturedViewSize += SectionOffset->LowPart & (Alignment - 1);
    02377         SectionOffset->LowPart = SectionOffset->LowPart & ~((ULONG)Alignment - 1);
    02378     }
    02379
    02380     if ((LONG_PTR)*CapturedViewSize <= 0) {
    02381
    02382         //
    02383         // Section offset or view size past size of section.
    02384         //
    02385
    02386         LOCK_PFN (OldIrql);
    02387         ControlArea->NumberOfMappedViews -= 1;
    02388         ControlArea->NumberOfUserReferences -= 1;
    02389
    02390         //
    02391         // Check to see if the control area (segment) should be deleted.
    02392         // This routine releases the PFN lock.
    02393         //
    02394
    02395         MiCheckControlArea (ControlArea, NULL, OldIrql);
    02396
    02397         *ReleasedWsMutex = TRUE;
    02398         return STATUS_INVALID_VIEW_SIZE;
    02399     }
    02400
    02401     //
    02402     // Calculate the first prototype PTE field in the Vad.
    02403     //
    02404
    02405     ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0);
    02406
    02407     Subsection = (PSUBSECTION)(ControlArea + 1);
    02408
    02409     SectionOffset->LowPart = SectionOffset->LowPart & ~((ULONG)Alignment - 1);
    02410     PteOffset = (ULONG)(SectionOffset->QuadPart >> PAGE_SHIFT);
    02411
    02412     //
    02413     // Make sure the PTEs are not in the extended part of the
    02414     // segment.
    02415     //
    02416
    02417     if (PteOffset >= ControlArea->Segment->TotalNumberOfPtes) {
    02418         LOCK_PFN (OldIrql);
    02419         ControlArea->NumberOfMappedViews -= 1;
    02420         ControlArea->NumberOfUserReferences -= 1;
    02421
    02422         //
    02423         // Check to see if the control area (segment) should be deleted.
    02424         // This routine releases the PFN lock.
    02425         //
    02426
    02427         MiCheckControlArea (ControlArea, NULL, OldIrql);
    02428
    02429         *ReleasedWsMutex = TRUE;
    02430         return STATUS_INVALID_VIEW_SIZE;
    02431     }
    02432
    02433     while (PteOffset >= Subsection->PtesInSubsection) {
    02434         PteOffset -= Subsection->PtesInSubsection;
    02435         Subsection = Subsection->NextSubsection;
    02436         ASSERT (Subsection != NULL);
    02437     }
    02438
    02439     TheFirstPrototypePte = &Subsection->SubsectionBase[PteOffset];
    02440
    02441     //
    02442     // Calculate the quota for the specified pages.
    02443     //
    02444
    02445     if ((ControlArea->FilePointer == NULL) &&
    02446         (CommitSize != 0) &&
    02447         (ControlArea->Segment->NumberOfCommittedPages <
    02448                 ControlArea->Segment->TotalNumberOfPtes)) {
    02449
    02450
    02451         ExAcquireFastMutexUnsafe (&MmSectionCommitMutex);
    02452
    02453         PointerPte = TheFirstPrototypePte;
    02454         LastPte = PointerPte + BYTES_TO_PAGES(CommitSize);
    02455
    02456         while (PointerPte < LastPte) {
    02457             if (PointerPte->u.Long == 0) {
    02458                 QuotaCharge += 1;
    02459             }
    02460             PointerPte += 1;
    02461         }
    02462         ExReleaseFastMutexUnsafe (&MmSectionCommitMutex);
    02463     }
    02464
    02465     CapturedStartingVa = (PVOID)Section->Address.StartingVpn;
    02466     CapturedCopyOnWrite = Section->u.Flags.CopyOnWrite;
    02467     LOCK_WS_UNSAFE (Process);
    02468
    02469     if ((*CapturedBase == NULL) && (CapturedStartingVa == NULL)) {
    02470
    02471         //
    02472         // The section is not based, find an empty range.
    02473         // This could raise an exception.
    02474
    02475         try {
    02476
    02477             //
    02478             // Find a starting address on a 64k boundary.
    02479             //
    02480
    02481             if ( AllocationType & MEM_TOP_DOWN ) {
    02482                 StartingAddress = MiFindEmptyAddressRangeDown (
    02483                                     *CapturedViewSize,
    02484                                     (PVOID)((PCHAR)MM_HIGHEST_VAD_ADDRESS + 1),
    02485                                     Alignment
    02486                                     );
    02487             } else {
    02488                 StartingAddress = MiFindEmptyAddressRange (*CapturedViewSize,
    02489                                                            Alignment,
    02490                                                            (ULONG)ZeroBits);
    02491             }
    02492
    02493         } except (EXCEPTION_EXECUTE_HANDLER) {
    02494
    02495             LOCK_PFN (OldIrql);
    02496             ControlArea->NumberOfMappedViews -= 1;
    02497             ControlArea->NumberOfUserReferences -= 1;
    02498
    02499             //
    02500             // Check to see if the control area (segment) should be deleted.
    02501             // This routine releases the PFN lock.
    02502             //
    02503
    02504             MiCheckControlArea (ControlArea, Process, OldIrql);
    02505
    02506             return GetExceptionCode();
    02507         }
    02508
    02509         EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
    02510                                     *CapturedViewSize - 1L) | (PAGE_SIZE - 1L));
    02511
    02512         if (ZeroBits > 0) {
    02513             if (EndingAddress > (PVOID)((ULONG_PTR)MM_USER_ADDRESS_RANGE_LIMIT >> ZeroBits)) {
    02514                 LOCK_PFN (OldIrql);
    02515                 ControlArea->NumberOfMappedViews -= 1;
    02516                 ControlArea->NumberOfUserReferences -= 1;
    02517
    02518                 //
    02519                 // Check to see if the control area (segment) should be deleted.
    02520                 // This routine releases the PFN lock.
    02521                 //
    02522
    02523                 MiCheckControlArea (ControlArea, Process, OldIrql);
    02524
    02525                 return STATUS_NO_MEMORY;
    02526             }
    02527         }
    02528
    02529     } else {
    02530
    02531         if (*CapturedBase == NULL) {
    02532
    02533             //
    02534             // The section is based.
    02535             //
    02536
    02537             StartingAddress = (PVOID)((PCHAR)CapturedStartingVa +
    02538                                                      SectionOffset->LowPart);
    02539         } else {
    02540
    02541             StartingAddress = MI_ALIGN_TO_SIZE (*CapturedBase, Alignment);
    02542
    02543         }
    02544
    02545         //
    02546         // Check to make sure the specified base address to ending address
    02547         // is currently unused.
    02548         //
    02549
    02550         EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
    02551                                    *CapturedViewSize - 1L) | (PAGE_SIZE - 1L));
    02552
    02553         Vad = MiCheckForConflictingVad (StartingAddress, EndingAddress);
    02554         if (Vad != (PMMVAD)NULL) {
    02555 #if DBG
    02556                 MiDumpConflictingVad (StartingAddress, EndingAddress, Vad);
    02557 #endif
    02558
    02559             LOCK_PFN (OldIrql);
    02560             ControlArea->NumberOfMappedViews -= 1;
    02561             ControlArea->NumberOfUserReferences -= 1;
    02562
    02563             //
    02564             // Check to see if the control area (segment) should be deleted.
    02565             // This routine releases the PFN lock.
    02566             //
    02567
    02568             MiCheckControlArea (ControlArea, Process, OldIrql);
    02569
    02570             return STATUS_CONFLICTING_ADDRESSES;
    02571         }
    02572     }
    02573
    02574     //
    02575     // An unoccupied address range has been found, build the virtual
    02576     // address descriptor to describe this range.
    02577     //
    02578
    02579     try  {
    02580
    02581         Vad = ExAllocatePoolWithTag (NonPagedPool,
    02582                                      sizeof(MMVAD),
    02583                                      MMVADKEY);
    02584         if (Vad == NULL) {
    02585             ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
    02586         }
    02587         RtlZeroMemory (Vad, sizeof(MMVAD));
    02588
    02589         Vad->StartingVpn = MI_VA_TO_VPN (StartingAddress);
    02590         Vad->EndingVpn = MI_VA_TO_VPN (EndingAddress);
    02591         Vad->FirstPrototypePte = TheFirstPrototypePte;
    02592
    02593         //
    02594         // Set the protection in the PTE template field of the VAD.
    02595         //
    02596
    02597         Vad->ControlArea = ControlArea;
    02598
    02599         Vad->u2.VadFlags2.Inherit = (InheritDisposition == ViewShare);
    02600         Vad->u.VadFlags.Protection = ProtectionMask;
    02601         Vad->u2.VadFlags2.CopyOnWrite = CapturedCopyOnWrite;
    02602
    02603         //
    02604         // Note that for MEM_DOS_LIM significance is lost here, but those
    02605         // files are not mapped MEM_RESERVE.
    02606         //
    02607
    02608         Vad->u2.VadFlags2.FileOffset = (ULONG)(SectionOffset->QuadPart >> 16);
    02609
    02610         if ((AllocationType & SEC_NO_CHANGE) || (Section->u.Flags.NoChange)) {
    02611             Vad->u.VadFlags.NoChange = 1;
    02612             Vad->u2.VadFlags2.SecNoChange = 1;
    02613         }
    02614         if (AllocationType & MEM_RESERVE) {
    02615             PMMEXTEND_INFO ExtendInfo;
    02616
    02617             ExAcquireFastMutexUnsafe (&MmSectionBasedMutex);
    02618             ExtendInfo = ControlArea->Segment->ExtendInfo;
    02619             if (ExtendInfo) {
    02620                 ExtendInfo->ReferenceCount += 1;
    02621                 if (ExtendInfo->CommittedSize < (UINT64)Section->SizeOfSection.QuadPart) {
    02622                     ExtendInfo->CommittedSize = (UINT64)Section->SizeOfSection.QuadPart;
    02623                 }
    02624             } else {
    02625
    02626                 ExtendInfo = ExAllocatePoolWithTag (NonPagedPool,
    02627                                                     sizeof(MMEXTEND_INFO),
    02628                                                     'xCmM');
    02629                 if (ExtendInfo == NULL) {
    02630                     ExReleaseFastMutexUnsafe (&MmSectionBasedMutex);
    02631                     ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
    02632                 }
    02633                 ExtendInfo->ReferenceCount = 1;
    02634                 ExtendInfo->CommittedSize = ControlArea->Segment->SizeOfSegment;
    02635                 if (ExtendInfo->CommittedSize < (UINT64)Section->SizeOfSection.QuadPart) {
    02636                     ExtendInfo->CommittedSize = (UINT64)Section->SizeOfSection.QuadPart;
    02637                 }
    02638                 ControlArea->Segment->ExtendInfo = ExtendInfo;
    02639             }
    02640             ExReleaseFastMutexUnsafe (&MmSectionBasedMutex);
    02641             Vad->u2.VadFlags2.ExtendableFile = 1;
    02642             ASSERT (Vad->u4.ExtendedInfo == NULL);
    02643             Vad->u4.ExtendedInfo = ExtendInfo;
    02644         }
    02645
    02646         //
    02647         // If the page protection is write-copy or execute-write-copy
    02648         // charge for each page in the view as it may become private.
    02649         //
    02650
    02651         if (MI_IS_PTE_PROTECTION_COPY_WRITE(ProtectionMask)) {
    02652             Vad->u.VadFlags.CommitCharge = (BYTES_TO_PAGES ((PCHAR) EndingAddress -
    02653                                (PCHAR) StartingAddress));
    02654         }
    02655
    02656         //
    02657         // If this is a page file backed section, charge the process's page
    02658         // file quota as if all the pages have been committed.  This solves
    02659         // the problem when other processes commit all the pages and leave
    02660         // only one process around who may not have been charged the proper
    02661         // quota.  This is solved by charging everyone the maximum quota.
    02662         //
    02663 //
    02664 // commented out for commitment charging.
    02665 //
    02666
    02667 #if 0
    02668         if (ControlArea->FilePointer == NULL) {
    02669
    02670             //
    02671             // This is a page file backed section.  Charge for all the pages.
    02672             //
    02673
    02674             Vad->CommitCharge += (BYTES_TO_PAGES ((PCHAR)EndingAddress -
    02675                                (PCHAR)StartingAddress));
    02676         }
    02677 #endif
    02678
    02679
    02680         PteOffset += (ULONG)(Vad->EndingVpn - Vad->StartingVpn);
    02681
    02682         if (PteOffset < Subsection->PtesInSubsection ) {
    02683             Vad->LastContiguousPte = &Subsection->SubsectionBase[PteOffset];
    02684
    02685         } else {
    02686             Vad->LastContiguousPte = &Subsection->SubsectionBase[
    02687                                         (Subsection->PtesInSubsection - 1) +
    02688                                         Subsection->UnusedPtes];
    02689         }
    02690
    02691         if (QuotaCharge != 0) {
    02692             if (MiChargeCommitment (QuotaCharge, Process) == FALSE) {
    02693                 ExRaiseStatus (STATUS_COMMITMENT_LIMIT);
    02694             }
    02695             ChargedQuota = TRUE;
    02696             MM_TRACK_COMMIT (MM_DBG_COMMIT_MAPVIEW_DATA, QuotaCharge);
    02697         }
    02698
    02699         ASSERT (Vad->FirstPrototypePte <= Vad->LastContiguousPte);
    02700         MiInsertVad (Vad);
    02701
    02702     } except (EXCEPTION_EXECUTE_HANDLER) {
    02703
    02704         LOCK_PFN (OldIrql);
    02705         ControlArea->NumberOfMappedViews -= 1;
    02706         ControlArea->NumberOfUserReferences -= 1;
    02707
    02708         //
    02709         // Check to see if the control area (segment) should be deleted.
    02710         // This routine releases the PFN lock.
    02711         //
    02712
    02713         MiCheckControlArea (ControlArea, Process, OldIrql);
    02714
    02715         if (Vad != (PMMVAD)NULL) {
    02716
    02717             //
    02718             // The pool allocation succeeded, but the quota charge
    02719             // in InsertVad failed, deallocate the pool and return
    02720             // an error.
    02721             //
    02722
    02723             ExFreePool (Vad);
    02724             if (ChargedQuota) {
    02725                 MiReturnCommitment (QuotaCharge);
    02726                 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_MAPVIEW_DATA, QuotaCharge);
    02727             }
    02728             return GetExceptionCode();
    02729         }
    02730         return STATUS_INSUFFICIENT_RESOURCES;
    02731     }
    02732
    02733     *ReleasedWsMutex = TRUE;
    02734
    02735 #if DBG
    02736     if (!(AllocationType & MEM_RESERVE)) {
    02737         ASSERT(((ULONG_PTR)EndingAddress - (ULONG_PTR)StartingAddress) <=
    02738                 ROUND_TO_PAGES64(Section->Segment->SizeOfSegment));
    02739     }
    02740 #endif //DBG
    02741
    02742     UNLOCK_WS_UNSAFE (Process);
    02743
    02744     //
    02745     // If a commit size was specified, make sure those pages are committed.
    02746     //
    02747
    02748     if (QuotaCharge != 0) {
    02749
    02750         ExAcquireFastMutexUnsafe (&MmSectionCommitMutex);
    02751
    02752         PointerPte = Vad->FirstPrototypePte;
    02753         LastPte = PointerPte + BYTES_TO_PAGES(CommitSize);
    02754         TempPte = ControlArea->Segment->SegmentPteTemplate;
    02755
    02756         while (PointerPte < LastPte) {
    02757
    02758             if (PointerPte->u.Long == 0) {
    02759
    02760                 MI_WRITE_INVALID_PTE (PointerPte, TempPte);
    02761             }
    02762             PointerPte += 1;
    02763         }
    02764
    02765         ControlArea->Segment->NumberOfCommittedPages += QuotaCharge;
    02766
    02767         ASSERT (ControlArea->Segment->NumberOfCommittedPages <=
    02768                 ControlArea->Segment->TotalNumberOfPtes);
    02769         MmSharedCommit += QuotaCharge;
    02770
    02771         ExReleaseFastMutexUnsafe (&MmSectionCommitMutex);
    02772     }
    02773
    02774 #if defined(_MIALT4K_)
    02775
    02776     if (Process->Wow64Process != NULL) {
    02777
    02778
    02779         EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
    02780                                  *CapturedViewSize - 1L) | (PAGE_4K - 1L));
    02781
    02782         ViewSizeFor4k = (PCHAR)EndingAddress - (PCHAR)StartingAddress + 1L;
    02783
    02784         MiProtectMapFileFor4kPage (StartingAddress,
    02785                                    ViewSizeFor4k,
    02786                                    ProtectionMask,
    02787                                    Vad->FirstPrototypePte,
    02788                                    Process);
    02789     }
    02790 #endif
    02791
    02792     //
    02793     // Update the current virtual size in the process header.
    02794     //
    02795
    02796     *CapturedViewSize = (PCHAR)EndingAddress - (PCHAR)StartingAddress + 1L;
    02797     Process->VirtualSize += *CapturedViewSize;
    02798
    02799     if (Process->VirtualSize > Process->PeakVirtualSize) {
    02800         Process->PeakVirtualSize = Process->VirtualSize;
    02801     }
    02802
    02803     *CapturedBase = StartingAddress;
    02804
    02805     return STATUS_SUCCESS;
    02806 }
    02807
    02808 LOGICAL
    02809 MiCheckPurgeAndUpMapCount (
    02810     IN PCONTROL_AREA ControlArea
    02811     )
    02812
    02813 /*++
    02814
    02815 Routine Description:
    02816
    02817     This routine synchronizes with any on going purge operations
    02818     on the same segment (identified via the control area).  If
    02819     another purge operation is occurring, the function blocks until
    02820     it is completed.
    02821
    02822     When this function returns the MappedView and the NumberOfUserReferences
    02823     count for the control area will be incremented thereby referencing
    02824     the control area.
    02825
    02826 Arguments:
    02827
    02828     ControlArea - Supplies the control area for the segment to be purged.
    02829
    02830 Return Value:
    02831
    02832     TRUE if the synchronization was successful.
    02833     FALSE if the synchronization did not occur due to low resources, etc.
    02834
    02835 Environment:
    02836
    02837     Kernel Mode.
    02838
    02839 --*/
    02840
    02841 {
    02842     KIRQL OldIrql;
    02843     PEVENT_COUNTER PurgedEvent;
    02844     PEVENT_COUNTER WaitEvent;
    02845     ULONG OldRef;
    02846
    02847     PurgedEvent = NULL;
    02848     OldRef = 1;
    02849
    02850     LOCK_PFN (OldIrql);
    02851
    02852     while (ControlArea->u.Flags.BeingPurged != 0) {
    02853
    02854         //
    02855         // A purge operation is in progress.
    02856         //
    02857
    02858         if (PurgedEvent == NULL) {
    02859
    02860             //
    02861             // Release the locks and allocate pool for the event.
    02862             //
    02863
    02864             PurgedEvent = MiGetEventCounter ();
    02865             if (PurgedEvent == NULL) {
    02866                 UNLOCK_PFN (OldIrql);
    02867                 return FALSE;
    02868             }
    02869
    02870             continue;
    02871         }
    02872
    02873         if (ControlArea->WaitingForDeletion == NULL) {
    02874             ControlArea->WaitingForDeletion = PurgedEvent;
    02875             WaitEvent = PurgedEvent;
    02876             PurgedEvent = NULL;
    02877         } else {
    02878             WaitEvent = ControlArea->WaitingForDeletion;
    02879             WaitEvent->RefCount += 1;
    02880         }
    02881
    02882         //
    02883         // Release the pfn lock and wait for the event.
    02884         //
    02885
    02886         KeEnterCriticalRegion();
    02887         UNLOCK_PFN_AND_THEN_WAIT(OldIrql);
    02888
    02889         KeWaitForSingleObject(&WaitEvent->Event,
    02890                               WrVirtualMemory,
    02891                               KernelMode,
    02892                               FALSE,
    02893                               (PLARGE_INTEGER)NULL);
    02894         LOCK_PFN (OldIrql);
    02895         KeLeaveCriticalRegion();
    02896         MiFreeEventCounter (WaitEvent, FALSE);
    02897     }
    02898
    02899     //
    02900     // Indicate another file is mapped for the segment.
    02901     //
    02902
    02903     ControlArea->NumberOfMappedViews += 1;
    02904     ControlArea->NumberOfUserReferences += 1;
    02905     ControlArea->u.Flags.HadUserReference = 1;
    02906     ASSERT (ControlArea->NumberOfSectionReferences != 0);
    02907
    02908     if (PurgedEvent != NULL) {
    02909         MiFreeEventCounter (PurgedEvent, TRUE);
    02910     }
    02911     UNLOCK_PFN (OldIrql);
    02912
    02913     return TRUE;
    02914 }
    02915
    02916 typedef struct _NTSYM {
    02917     struct _NTSYM *Next;
    02918     PVOID SymbolTable;
    02919     ULONG NumberOfSymbols;
    02920     PVOID StringTable;
    02921     USHORT Flags;
    02922     USHORT EntrySize;
    02923     ULONG MinimumVa;
    02924     ULONG MaximumVa;
    02925     PCHAR MapName;
    02926     ULONG MapNameLen;
    02927 } NTSYM, *PNTSYM;
    02928
    02929 ULONG
    02930 CacheImageSymbols(
    02931     IN PVOID ImageBase
    02932     )
    02933 {
    02934     PIMAGE_DEBUG_DIRECTORY DebugDirectory;
    02935     ULONG DebugSize;
    02936
    02937     PAGED_CODE();
    02938
    02939     try {
    02940         DebugDirectory = (PIMAGE_DEBUG_DIRECTORY)
    02941         RtlImageDirectoryEntryToData( ImageBase,
    02942                                       TRUE,
    02943                                       IMAGE_DIRECTORY_ENTRY_DEBUG,
    02944                                       &DebugSize
    02945                                     );
    02946         if (!DebugDirectory) {
    02947             return FALSE;
    02948         }
    02949
    02950         //
    02951         // If using remote KD, ImageBase is what it wants to see.
    02952         //
    02953
    02954     } except (EXCEPTION_EXECUTE_HANDLER) {
    02955         return FALSE;
    02956     }
    02957
    02958     return TRUE;
    02959 }
    02960
    02961
    02962 NTSYSAPI
    02963 NTSTATUS
    02964 NTAPI
    02965 NtAreMappedFilesTheSame (
    02966     IN PVOID File1MappedAsAnImage,
    02967     IN PVOID File2MappedAsFile
    02968     )
    02969
    02970 /*++
    02971
    02972 Routine Description:
    02973
    02974     This routine compares the two files mapped at the specified
    02975     addresses to see if they are both the same file.
    02976
    02977 Arguments:
    02978
    02979     File1MappedAsAnImage - Supplies an address within the first file which
    02980         is mapped as an image file.
    02981
    02982     File2MappedAsFile - Supplies an address within the second file which
    02983         is mapped as either an image file or a data file.
    02984
    02985 Return Value:
    02986
    02987
    02988     STATUS_SUCCESS is returned if the two files are the same.
    02989
    02990     STATUS_NOT_SAME_DEVICE is returned if the files are different.
    02991
    02992     Other status values can be returned if the addresses are not mapped as
    02993     files, etc.
    02994
    02995 Environment:
    02996
    02997     User mode callable system service.
    02998
    02999 --*/
    03000
    03001 {
    03002     PMMVAD FoundVad1;
    03003     PMMVAD FoundVad2;
    03004     NTSTATUS Status;
    03005
    03006     LOCK_ADDRESS_SPACE (PsGetCurrentProcess());
    03007     FoundVad1 = MiLocateAddress (File1MappedAsAnImage);
    03008     FoundVad2 = MiLocateAddress (File2MappedAsFile);
    03009
    03010     if ((FoundVad1 == NULL) ||
    03011         (FoundVad2 == NULL)) {
    03012
    03013         //
    03014         // No virtual address is allocated at the specified base address,
    03015         // return an error.
    03016         //
    03017
    03018         Status = STATUS_INVALID_ADDRESS;
    03019         goto ErrorReturn;
    03020     }
    03021
    03022     //
    03023     // Check file names.
    03024     //
    03025
    03026     if ((FoundVad1->u.VadFlags.PrivateMemory == 1) ||
    03027         (FoundVad2->u.VadFlags.PrivateMemory == 1)) {
    03028         Status = STATUS_CONFLICTING_ADDRESSES;
    03029         goto ErrorReturn;
    03030     }
    03031
    03032     if ((FoundVad1->ControlArea == NULL) ||
    03033         (FoundVad2->ControlArea == NULL)) {
    03034         Status = STATUS_CONFLICTING_ADDRESSES;
    03035         goto ErrorReturn;
    03036     }
    03037
    03038     if ((FoundVad1->ControlArea->FilePointer == NULL) ||
    03039         (FoundVad2->ControlArea->FilePointer == NULL)) {
    03040         Status = STATUS_CONFLICTING_ADDRESSES;
    03041         goto ErrorReturn;
    03042     }
    03043
    03044     Status = STATUS_NOT_SAME_DEVICE;
    03045
    03046     if ((PVOID)FoundVad1->ControlArea ==
    03047             FoundVad2->ControlArea->FilePointer->SectionObjectPointer->ImageSectionObject) {
    03048         Status = STATUS_SUCCESS;
    03049     }
    03050
    03051 ErrorReturn:
    03052
    03053     UNLOCK_ADDRESS_SPACE (PsGetCurrentProcess());
    03054     return Status;
    03055 }
    03056
    03057
    03058
    03059 VOID
    03060 MiSetPageModified (
    03061     IN PVOID Address
    03062     )
    03063
    03064 /*++
    03065
    03066 Routine Description:
    03067
    03068     This routine sets the modified bit in the PFN database for the
    03069     pages that correspond to the specified address range.
    03070
    03071     Note that the dirty bit in the PTE is cleared by this operation.
    03072
    03073 Arguments:
    03074
    03075     Address - Supplies the address of the start of the range.  This
    03076               range must reside within the system cache.
    03077
    03078 Return Value:
    03079
    03080     None.
    03081
    03082 Environment:
    03083
    03084     Kernel mode.  APC_LEVEL and below for pagable addresses,
    03085                   DISPATCH_LEVEL and below for non-pagable addresses.
    03086
    03087 --*/
    03088
    03089 {
    03090     volatile PMMPTE PointerPpe;
    03091     volatile PMMPTE PointerPde;
    03092     volatile PMMPTE PointerPte;
    03093     PMMPFN Pfn1;
    03094     MMPTE PteContents;
    03095     KIRQL OldIrql;
    03096
    03097     //
    03098     // Loop on the copy on write case until the page is only
    03099     // writable.
    03100     //
    03101
    03102     PointerPte = MiGetPteAddress (Address);
    03103     PointerPde = MiGetPdeAddress (Address);
    03104     PointerPpe = MiGetPpeAddress (Address);
    03105
    03106     *(volatile CCHAR *)Address;
    03107
    03108     LOCK_PFN (OldIrql);
    03109
    03110 #if defined (_WIN64)
    03111     while ((PointerPpe->u.Hard.Valid == 0) ||
    03112            (PointerPde->u.Hard.Valid == 0) ||
    03113            (PointerPte->u.Hard.Valid == 0))
    03114 #else
    03115     while ((PointerPde->u.Hard.Valid == 0) ||
    03116            (PointerPte->u.Hard.Valid == 0))
    03117 #endif
    03118     {
    03119
    03120         //
    03121         // Page is no longer valid.
    03122         //
    03123
    03124         UNLOCK_PFN (OldIrql);
    03125         *(volatile CCHAR *)Address;
    03126         LOCK_PFN (OldIrql);
    03127     }
    03128
    03129     PteContents = *PointerPte;
    03130
    03131     Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber);
    03132     Pfn1->u3.e1.Modified = 1;
    03133
    03134     if ((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
    03135                  (Pfn1->u3.e1.WriteInProgress == 0)) {
    03136         MiReleasePageFileSpace (Pfn1->OriginalPte);
    03137         Pfn1->OriginalPte.u.Soft.PageFileHigh = 0;
    03138     }
    03139
    03140 #ifdef NT_UP
    03141     if (MI_IS_PTE_DIRTY (PteContents)) {
    03142 #endif //NT_UP
    03143         MI_SET_PTE_CLEAN (PteContents);
    03144
    03145         //
    03146         // Clear the dirty bit in the PTE so new writes can be tracked.
    03147         //
    03148
    03149         (VOID)KeFlushSingleTb (Address,
    03150                                FALSE,
    03151                                TRUE,
    03152                                (PHARDWARE_PTE)PointerPte,
    03153                                PteContents.u.Flush);
    03154 #ifdef NT_UP
    03155     }
    03156 #endif //NT_UP
    03157
    03158     UNLOCK_PFN (OldIrql);
    03159     return;
    03160 }
    03161
    03162
    03163 NTSTATUS
    03164 MmMapViewInSystemSpace (
    03165     IN PVOID Section,
    03166     OUT PVOID *MappedBase,
    03167     IN OUT PSIZE_T ViewSize
    03168     )
    03169
    03170 /*++
    03171
    03172 Routine Description:
    03173
    03174     This routine maps the specified section into the system's address space.
    03175
    03176 Arguments:
    03177
    03178     Section - Supplies a pointer to the section to map.
    03179
    03180     *MappedBase - Returns the address where the section was mapped.
    03181
    03182     ViewSize - Supplies the size of the view to map.  If this
    03183                is specified as zero, the whole section is mapped.
    03184                Returns the actual size mapped.
    03185
    03186 Return Value:
    03187
    03188     Status of the map view operation.
    03189
    03190 Environment:
    03191
    03192     Kernel Mode, IRQL of dispatch level.
    03193
    03194 --*/
    03195
    03196 {
    03197     PMMSESSION  Session;
    03198
    03199     PAGED_CODE();
    03200
    03201     Session = &MmSession;
    03202
    03203     return MiMapViewInSystemSpace (Section,
    03204                                    Session,
    03205                                    MappedBase,
    03206                                    ViewSize);
    03207 }
    03208
    03209
    03210 NTSTATUS
    03211 MmMapViewInSessionSpace (
    03212     IN PVOID Section,
    03213     OUT PVOID *MappedBase,
    03214     IN OUT PSIZE_T ViewSize
    03215     )
    03216
    03217 /*++
    03218
    03219 Routine Description:
    03220
    03221     This routine maps the specified section into the current process's
    03222     session address space.
    03223
    03224 Arguments:
    03225
    03226     Section - Supplies a pointer to the section to map.
    03227
    03228     *MappedBase - Returns the address where the section was mapped.
    03229
    03230     ViewSize - Supplies the size of the view to map.  If this
    03231                is specified as zero, the whole section is mapped.
    03232                Returns the actual size mapped.
    03233
    03234 Return Value:
    03235
    03236     Status of the map view operation.
    03237
    03238 Environment:
    03239
    03240     Kernel Mode, IRQL of dispatch level.
    03241
    03242 --*/
    03243
    03244 {
    03245     PMMSESSION  Session;
    03246
    03247     PAGED_CODE();
    03248
    03249     if (MiHydra == TRUE) {
    03250         if (PsGetCurrentProcess()->Vm.u.Flags.ProcessInSession == 0) {
    03251             return STATUS_NOT_MAPPED_VIEW;
    03252         }
    03253         ASSERT (MmIsAddressValid(MmSessionSpace) == TRUE);
    03254         Session = &MmSessionSpace->Session;
    03255     }
    03256     else {
    03257         Session = &MmSession;
    03258     }
    03259
    03260     return MiMapViewInSystemSpace (Section,
    03261                                    Session,
    03262                                    MappedBase,
    03263                                    ViewSize);
    03264 }
    03265
    03266
    03267 NTSTATUS
    03268 MiMapViewInSystemSpace (
    03269     IN PVOID Section,
    03270     IN PMMSESSION Session,
    03271     OUT PVOID *MappedBase,
    03272     IN OUT PSIZE_T ViewSize
    03273     )
    03274
    03275 /*++
    03276
    03277 Routine Description:
    03278
    03279     This routine maps the specified section into the system's address space.
    03280
    03281 Arguments:
    03282
    03283     Section - Supplies a pointer to the section to map.
    03284
    03285     Session - Supplies the session data structure for this view.
    03286
    03287     *MappedBase - Returns the address where the section was mapped.
    03288
    03289     ViewSize - Supplies the size of the view to map.  If this
    03290                is specified as zero, the whole section is mapped.
    03291                Returns the actual size mapped.
    03292
    03293     Protect - Supplies the protection for the view.  Must be
    03294               either PAGE_READWRITE or PAGE_READONLY.
    03295
    03296 Return Value:
    03297
    03298     Status of the map view operation.
    03299
    03300 Environment:
    03301
    03302     Kernel Mode, IRQL of APC_LEVEL or below.
    03303
    03304 --*/
    03305
    03306 {
    03307     PVOID Base;
    03308     KIRQL OldIrql;
    03309     PSUBSECTION Subsection;
    03310     PCONTROL_AREA ControlArea;
    03311     PCONTROL_AREA NewControlArea;
    03312     ULONG StartBit;
    03313     ULONG SizeIn64k;
    03314     ULONG NewSizeIn64k;
    03315     PMMPTE BasePte;
    03316     ULONG NumberOfPtes;
    03317     ULONG NumberOfBytes;
    03318     BOOLEAN status;
    03319     KIRQL WsIrql;
    03320
    03321     PAGED_CODE();
    03322
    03323     //
    03324     // Check to see if a purge operation is in progress and if so, wait
    03325     // for the purge to complete.  In addition, up the count of mapped
    03326     // views for this control area.
    03327     //
    03328
    03329     ControlArea = ((PSECTION)Section)->Segment->ControlArea;
    03330
    03331     if (ControlArea->u.Flags.GlobalOnlyPerSession == 0) {
    03332         Subsection = (PSUBSECTION)(ControlArea + 1);
    03333     }
    03334     else {
    03335         Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
    03336     }
    03337
    03338     MmLockPagableSectionByHandle(ExPageLockHandle);
    03339
    03340     if (MiCheckPurgeAndUpMapCount (ControlArea) == FALSE) {
    03341         MmUnlockPagableImageSection(ExPageLockHandle);
    03342         return STATUS_INSUFFICIENT_RESOURCES;
    03343     }
    03344
    03345     if (*ViewSize == 0) {
    03346
    03347         *ViewSize = ((PSECTION)Section)->SizeOfSection.LowPart;
    03348
    03349     } else if (*ViewSize > ((PSECTION)Section)->SizeOfSection.LowPart) {
    03350
    03351         //
    03352         // Section offset or view size past size of section.
    03353         //
    03354
    03355         LOCK_PFN (OldIrql);
    03356         ControlArea->NumberOfMappedViews -= 1;
    03357         ControlArea->NumberOfUserReferences -= 1;
    03358
    03359         //
    03360         // Check to see if the control area (segment) should be deleted.
    03361         // This routine releases the PFN lock.
    03362         //
    03363
    03364         MiCheckControlArea (ControlArea, NULL, OldIrql);
    03365
    03366         MmUnlockPagableImageSection(ExPageLockHandle);
    03367         return STATUS_INVALID_VIEW_SIZE;
    03368     }
    03369
    03370     //
    03371     // Calculate the first prototype PTE field in the Vad.
    03372     //
    03373
    03374     SizeIn64k = (ULONG)((*ViewSize / X64K) + ((*ViewSize & (X64K - 1)) != 0));
    03375
    03376     Base = MiInsertInSystemSpace (Session, SizeIn64k, ControlArea);
    03377
    03378     if (Base == NULL) {
    03379         LOCK_PFN (OldIrql);
    03380         ControlArea->NumberOfMappedViews -= 1;
    03381         ControlArea->NumberOfUserReferences -= 1;
    03382
    03383         //
    03384         // Check to see if the control area (segment) should be deleted.
    03385         // This routine releases the PFN lock.
    03386         //
    03387
    03388         MiCheckControlArea (ControlArea, NULL, OldIrql);
    03389
    03390         MmUnlockPagableImageSection(ExPageLockHandle);
    03391         return STATUS_NO_MEMORY;
    03392     }
    03393
    03394     NumberOfBytes = SizeIn64k * X64K;
    03395
    03396     if (Session == &MmSession) {
    03397         status = MiFillSystemPageDirectory (Base, NumberOfBytes);
    03398     }
    03399     else {
    03400         LOCK_SESSION_SPACE_WS (WsIrql);
    03401         if (NT_SUCCESS(MiSessionCommitPageTables (Base,
    03402                 (PVOID)((ULONG_PTR)Base + NumberOfBytes - 1)))) {
    03403                     status = TRUE;
    03404         }
    03405         else {
    03406                     status = FALSE;
    03407         }
    03408     }
    03409
    03410     if (status == FALSE) {
    03411         if (Session != &MmSession) {
    03412             UNLOCK_SESSION_SPACE_WS (WsIrql);
    03413         }
    03414
    03415         LOCK_PFN (OldIrql);
    03416         ControlArea->NumberOfMappedViews -= 1;
    03417         ControlArea->NumberOfUserReferences -= 1;
    03418
    03419         //
    03420         // Check to see if the control area (segment) should be deleted.
    03421         // This routine releases the PFN lock.
    03422         //
    03423
    03424         MiCheckControlArea (ControlArea, NULL, OldIrql);
    03425
    03426         StartBit = (ULONG) (((ULONG_PTR)Base - (ULONG_PTR)Session->SystemSpaceViewStart) >> 16);
    03427
    03428         LOCK_SYSTEM_VIEW_SPACE (Session);
    03429
    03430         NewSizeIn64k = MiRemoveFromSystemSpace (Session, Base, &NewControlArea);
    03431
    03432         ASSERT (ControlArea == NewControlArea);
    03433         ASSERT (SizeIn64k == NewSizeIn64k);
    03434
    03435         RtlClearBits (Session->SystemSpaceBitMap, StartBit, SizeIn64k);
    03436
    03437         UNLOCK_SYSTEM_VIEW_SPACE (Session);
    03438
    03439         MmUnlockPagableImageSection(ExPageLockHandle);
    03440         return STATUS_NO_MEMORY;
    03441     }
    03442
    03443     //
    03444     // Setup PTEs to point to prototype PTEs.
    03445     //
    03446
    03447     if (((PSECTION)Section)->u.Flags.Image) {
    03448
    03449 #if DBG
    03450         //
    03451         // The only reason this ASSERT isn't done for Hydra is because
    03452         // the session space working set lock is currently held so faults
    03453         // are not allowed.
    03454         //
    03455
    03456         if (Session == &MmSession) {
    03457             ASSERT (((PSECTION)Section)->Segment->ControlArea == ControlArea);
    03458         }
    03459 #endif
    03460
    03461         LOCK_PFN (OldIrql);
    03462         ControlArea->u.Flags.ImageMappedInSystemSpace = 1;
    03463         UNLOCK_PFN (OldIrql);
    03464     }
    03465
    03466     BasePte = MiGetPteAddress (Base);
    03467     NumberOfPtes = BYTES_TO_PAGES (*ViewSize);
    03468
    03469     MiAddMappedPtes (BasePte,
    03470                      NumberOfPtes,
    03471                      ControlArea);
    03472
    03473     if (Session != &MmSession) {
    03474         UNLOCK_SESSION_SPACE_WS (WsIrql);
    03475     }
    03476
    03477     *MappedBase = Base;
    03478
    03479     MmUnlockPagableImageSection(ExPageLockHandle);
    03480     return STATUS_SUCCESS;
    03481 }
    03482
    03483 BOOLEAN
    03484 MiFillSystemPageDirectory (
    03485     PVOID Base,
    03486     SIZE_T NumberOfBytes
    03487     )
    03488
    03489 /*++
    03490
    03491 Routine Description:
    03492
    03493     This routine allocates page tables and fills the system page directory
    03494     entries for the specified virtual address range.
    03495
    03496 Arguments:
    03497
    03498     Base - Supplies the virtual address of the view.
    03499
    03500     NumberOfBytes - Supplies the number of bytes the view spans.
    03501
    03502 Return Value:
    03503
    03504     TRUE on success, FALSE on failure.
    03505
    03506 Environment:
    03507
    03508     Kernel Mode, IRQL of dispatch level.
    03509
    03510 --*/
    03511
    03512 {
    03513     PMMPTE FirstPde;
    03514     PMMPTE LastPde;
    03515     PMMPTE FirstSystemPde;
    03516     MMPTE TempPte;
    03517     PFN_NUMBER PageFrameIndex;
    03518     KIRQL OldIrql;
    03519     ULONG i;
    03520
    03521     PAGED_CODE();
    03522
    03523     //
    03524     // CODE IS ALREADY LOCKED BY CALLER.
    03525     //
    03526
    03527     FirstPde = MiGetPdeAddress (Base);
    03528     LastPde = MiGetPdeAddress ((PVOID)(((PCHAR)Base) + NumberOfBytes - 1));
    03529
    03530 #if defined (_WIN64)
    03531     FirstSystemPde = FirstPde;
    03532 #else
    03533 #if !defined (_X86PAE_)
    03534     FirstSystemPde = &MmSystemPagePtes[((ULONG_PTR)FirstPde &
    03535                      ((PDE_PER_PAGE * sizeof(MMPTE)) - 1)) / sizeof(MMPTE) ];
    03536 #else
    03537     FirstSystemPde = &MmSystemPagePtes[((ULONG_PTR)FirstPde &
    03538                      (PD_PER_SYSTEM * (PDE_PER_PAGE * sizeof(MMPTE)) - 1)) / sizeof(MMPTE) ];
    03539 #endif
    03540 #endif
    03541
    03542     do {
    03543         if (FirstSystemPde->u.Hard.Valid == 0) {
    03544
    03545             //
    03546             // No page table page exists, get a page and map it in.
    03547             //
    03548
    03549             TempPte = ValidKernelPde;
    03550
    03551             LOCK_PFN (OldIrql);
    03552
    03553             if (((volatile MMPTE *)FirstSystemPde)->u.Hard.Valid == 0) {
    03554
    03555                 if (MiEnsureAvailablePageOrWait (NULL, FirstPde)) {
    03556
    03557                     //
    03558                     // PFN_LOCK was dropped, redo this loop as another process
    03559                     // could have made this PDE valid.
    03560                     //
    03561
    03562                     UNLOCK_PFN (OldIrql);
    03563                     continue;
    03564                 }
    03565
    03566                 MiChargeCommitmentCantExpand (1, TRUE);
    03567                 MM_TRACK_COMMIT (MM_DBG_COMMIT_FILL_SYSTEM_DIRECTORY, 1);
    03568                 PageFrameIndex = MiRemoveAnyPage (
    03569                                     MI_GET_PAGE_COLOR_FROM_PTE (FirstSystemPde));
    03570                 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
    03571                 MI_WRITE_VALID_PTE (FirstSystemPde, TempPte);
    03572                 MI_WRITE_VALID_PTE (FirstPde, TempPte);
    03573
    03574 #if defined (_WIN64)
    03575                 MiInitializePfn (PageFrameIndex,
    03576                                  FirstPde,
    03577                                  1);
    03578 #else
    03579
    03580 #if !defined (_X86PAE_)
    03581                 MiInitializePfnForOtherProcess (PageFrameIndex,
    03582                                                 FirstPde,
    03583                                                 MmSystemPageDirectory);
    03584 #else
    03585                 i = (FirstPde - MiGetPdeAddress(0)) / PDE_PER_PAGE;
    03586                 MiInitializePfnForOtherProcess (PageFrameIndex,
    03587                                                 FirstPde,
    03588                                                 MmSystemPageDirectory[i]);
    03589 #endif
    03590
    03591 #endif
    03592
    03593                 MiFillMemoryPte (MiGetVirtualAddressMappedByPte (FirstPde),
    03594                                  PAGE_SIZE,
    03595                                  MM_ZERO_KERNEL_PTE);
    03596             }
    03597             UNLOCK_PFN (OldIrql);
    03598         }
    03599
    03600         FirstSystemPde += 1;
    03601         FirstPde += 1;
    03602     } while (FirstPde <= LastPde  );
    03603
    03604     return TRUE;
    03605 }
    03606
    03607 NTSTATUS
    03608 MmUnmapViewInSystemSpace (
    03609     IN PVOID MappedBase
    03610     )
    03611
    03612 /*++
    03613
    03614 Routine Description:
    03615
    03616     This routine unmaps the specified section from the system's address space.
    03617
    03618 Arguments:
    03619
    03620     MappedBase - Supplies the address of the view to unmap.
    03621
    03622 Return Value:
    03623
    03624     Status of the map view operation.
    03625
    03626 Environment:
    03627
    03628     Kernel Mode, IRQL of dispatch level.
    03629
    03630 --*/
    03631
    03632 {
    03633     PAGED_CODE();
    03634
    03635     return MiUnmapViewInSystemSpace (&MmSession, MappedBase);
    03636 }
    03637
    03638 NTSTATUS
    03639 MmUnmapViewInSessionSpace (
    03640     IN PVOID MappedBase
    03641     )
    03642
    03643 /*++
    03644
    03645 Routine Description:
    03646
    03647     This routine unmaps the specified section from the system's address space.
    03648
    03649 Arguments:
    03650
    03651     MappedBase - Supplies the address of the view to unmap.
    03652
    03653 Return Value:
    03654
    03655     Status of the map view operation.
    03656
    03657 Environment:
    03658
    03659     Kernel Mode, IRQL of dispatch level.
    03660
    03661 --*/
    03662
    03663 {
    03664     PMMSESSION Session;
    03665
    03666     PAGED_CODE();
    03667
    03668     if (MiHydra == TRUE) {
    03669         if (PsGetCurrentProcess()->Vm.u.Flags.ProcessInSession == 0) {
    03670             return STATUS_NOT_MAPPED_VIEW;
    03671         }
    03672         ASSERT (MmIsAddressValid(MmSessionSpace) == TRUE);
    03673         Session = &MmSessionSpace->Session;
    03674     }
    03675     else {
    03676         Session = &MmSession;
    03677     }
    03678
    03679     return MiUnmapViewInSystemSpace (Session, MappedBase);
    03680 }
    03681
    03682 NTSTATUS
    03683 MiUnmapViewInSystemSpace (
    03684     IN PMMSESSION Session,
    03685     IN PVOID MappedBase
    03686     )
    03687
    03688 /*++
    03689
    03690 Routine Description:
    03691
    03692     This routine unmaps the specified section from the system's address space.
    03693
    03694 Arguments:
    03695
    03696     Session - Supplies the session data structure for this view.
    03697
    03698     MappedBase - Supplies the address of the view to unmap.
    03699
    03700 Return Value:
    03701
    03702     Status of the map view operation.
    03703
    03704 Environment:
    03705
    03706     Kernel Mode, IRQL of dispatch level.
    03707
    03708 --*/
    03709
    03710 {
    03711     ULONG StartBit;
    03712     ULONG Size;
    03713     PCONTROL_AREA ControlArea;
    03714     PMMSUPPORT Ws;
    03715     KIRQL WsIrql;
    03716
    03717     PAGED_CODE();
    03718
    03719     MmLockPagableSectionByHandle(ExPageLockHandle);
    03720     StartBit =  (ULONG) (((ULONG_PTR)MappedBase - (ULONG_PTR)Session->SystemSpaceViewStart) >> 16);
    03721
    03722     LOCK_SYSTEM_VIEW_SPACE (Session);
    03723
    03724     Size = MiRemoveFromSystemSpace (Session, MappedBase, &ControlArea);
    03725
    03726     RtlClearBits (Session->SystemSpaceBitMap, StartBit, Size);
    03727
    03728     //
    03729     // Zero PTEs.
    03730     //
    03731
    03732     Size = Size * (X64K >> PAGE_SHIFT);
    03733
    03734     if (Session == &MmSession) {
    03735         Ws = &MmSystemCacheWs;
    03736     }
    03737     else {
    03738         Ws = &MmSessionSpace->Vm;
    03739         LOCK_SESSION_SPACE_WS(WsIrql);
    03740     }
    03741
    03742     MiRemoveMappedPtes (MappedBase, Size, ControlArea, Ws);
    03743
    03744     if (Session != &MmSession) {
    03745         UNLOCK_SESSION_SPACE_WS(WsIrql);
    03746     }
    03747
    03748     UNLOCK_SYSTEM_VIEW_SPACE (Session);
    03749
    03750     MmUnlockPagableImageSection(ExPageLockHandle);
    03751
    03752     return STATUS_SUCCESS;
    03753 }
    03754
    03755
    03756 PVOID
    03757 MiInsertInSystemSpace (
    03758     IN PMMSESSION Session,
    03759     IN ULONG SizeIn64k,
    03760     IN PCONTROL_AREA ControlArea
    03761     )
    03762
    03763 /*++
    03764
    03765 Routine Description:
    03766
    03767     This routine creates a view in system space for the specified control
    03768     area (file mapping).
    03769
    03770 Arguments:
    03771
    03772     SizeIn64k - Supplies the size of the view to be created.
    03773
    03774     ControlArea - Supplies a pointer to the control area for this view.
    03775
    03776 Return Value:
    03777
    03778     Base address where the view was mapped, NULL if the view could not be
    03779     mapped.
    03780
    03781 Environment:
    03782
    03783     Kernel Mode.
    03784
    03785 --*/
    03786
    03787 {
    03788
    03789     PVOID Base;
    03790     ULONG_PTR Entry;
    03791     ULONG Hash;
    03792     ULONG i;
    03793     ULONG AllocSize;
    03794     PMMVIEW OldTable;
    03795     ULONG StartBit;
    03796     ULONG NewHashSize;
    03797
    03798     PAGED_CODE();
    03799
    03800     //
    03801     // CODE IS ALREADY LOCKED BY CALLER.
    03802     //
    03803
    03804     LOCK_SYSTEM_VIEW_SPACE (Session);
    03805
    03806     if (Session->SystemSpaceHashEntries + 8 > Session->SystemSpaceHashSize) {
    03807
    03808         //
    03809         // Less than 8 free slots, reallocate and rehash.
    03810         //
    03811
    03812         NewHashSize = Session->SystemSpaceHashSize << 1;
    03813
    03814         AllocSize = sizeof(MMVIEW) * NewHashSize;
    03815         ASSERT (AllocSize < PAGE_SIZE);
    03816
    03817         OldTable = Session->SystemSpaceViewTable;
    03818
    03819         Session->SystemSpaceViewTable = ExAllocatePoolWithTag (PagedPool,
    03820                                                                AllocSize,
    03821                                                                '  mM');
    03822
    03823         if (Session->SystemSpaceViewTable == NULL) {
    03824             Session->SystemSpaceViewTable = OldTable;
    03825         }
    03826         else {
    03827             RtlZeroMemory (Session->SystemSpaceViewTable, AllocSize);
    03828
    03829             Session->SystemSpaceHashSize = NewHashSize;
    03830             Session->SystemSpaceHashKey = Session->SystemSpaceHashSize - 1;
    03831
    03832             for (i = 0; i < (Session->SystemSpaceHashSize / 2); i += 1) {
    03833                 if (OldTable[i].Entry != 0) {
    03834                     Hash = (ULONG) ((OldTable[i].Entry >> 16) % Session->SystemSpaceHashKey);
    03835
    03836                     while (Session->SystemSpaceViewTable[Hash].Entry != 0) {
    03837                         Hash += 1;
    03838                         if (Hash >= Session->SystemSpaceHashSize) {
    03839                             Hash = 0;
    03840                         }
    03841                     }
    03842                     Session->SystemSpaceViewTable[Hash] = OldTable[i];
    03843                 }
    03844             }
    03845             ExFreePool (OldTable);
    03846         }
    03847     }
    03848
    03849     if (Session->SystemSpaceHashEntries == Session->SystemSpaceHashSize) {
    03850
    03851         //
    03852         // There are no free hash slots to place a new entry into even
    03853         // though there may still be unused virtual address space.
    03854         //
    03855
    03856         UNLOCK_SYSTEM_VIEW_SPACE (Session);
    03857         return NULL;
    03858     }
    03859
    03860     StartBit = RtlFindClearBitsAndSet (Session->SystemSpaceBitMap,
    03861                                        SizeIn64k,
    03862                                        0);
    03863
    03864     if (StartBit == 0xFFFFFFFF) {
    03865         UNLOCK_SYSTEM_VIEW_SPACE (Session);
    03866         return NULL;
    03867     }
    03868
    03869     Base = (PVOID)((PCHAR)Session->SystemSpaceViewStart + (StartBit * X64K));
    03870
    03871     Entry = (ULONG_PTR) MI_64K_ALIGN(Base) + SizeIn64k;
    03872
    03873     Hash = (ULONG) ((Entry >> 16) % Session->SystemSpaceHashKey);
    03874
    03875     while (Session->SystemSpaceViewTable[Hash].Entry != 0) {
    03876         Hash += 1;
    03877         if (Hash >= Session->SystemSpaceHashSize) {
    03878             Hash = 0;
    03879         }
    03880     }
    03881
    03882     Session->SystemSpaceHashEntries += 1;
    03883
    03884     Session->SystemSpaceViewTable[Hash].Entry = Entry;
    03885     Session->SystemSpaceViewTable[Hash].ControlArea = ControlArea;
    03886
    03887     UNLOCK_SYSTEM_VIEW_SPACE (Session);
    03888     return Base;
    03889 }
    03890
    03891
    03892 ULONG
    03893 MiRemoveFromSystemSpace (
    03894     IN PMMSESSION Session,
    03895     IN PVOID Base,
    03896     OUT PCONTROL_AREA *ControlArea
    03897     )
    03898
    03899 /*++
    03900
    03901 Routine Description:
    03902
    03903     This routine looks up the specified view in the system space hash
    03904     table and unmaps the view from system space and the table.
    03905
    03906 Arguments:
    03907
    03908     Session - Supplies the session data structure for this view.
    03909
    03910     Base - Supplies the base address for the view.  If this address is
    03911            NOT found in the hash table, the system bugchecks.
    03912
    03913     ControlArea - Returns the control area corresponding to the base
    03914                   address.
    03915
    03916 Return Value:
    03917
    03918     Size of the view divided by 64k.
    03919
    03920 Environment:
    03921
    03922     Kernel Mode, system view hash table locked.
    03923
    03924 --*/
    03925
    03926 {
    03927     ULONG_PTR Base16;
    03928     ULONG Hash;
    03929     ULONG Size;
    03930     ULONG count;
    03931
    03932     PAGED_CODE();
    03933
    03934     count = 0;
    03935
    03936     //
    03937     // CODE IS ALREADY LOCKED BY CALLER.
    03938     //
    03939
    03940     Base16 = (ULONG_PTR)Base >> 16;
    03941     Hash = (ULONG)(Base16 % Session->SystemSpaceHashKey);
    03942
    03943     while ((Session->SystemSpaceViewTable[Hash].Entry >> 16) != Base16) {
    03944         Hash += 1;
    03945         if (Hash >= Session->SystemSpaceHashSize) {
    03946             Hash = 0;
    03947             count += 1;
    03948             if (count == 2) {
    03949                 KeBugCheckEx (DRIVER_UNMAPPING_INVALID_VIEW,
    03950                               (ULONG_PTR)Base,
    03951                               MiHydra,
    03952                               0,
    03953                               0);
    03954             }
    03955         }
    03956     }
    03957
    03958     Session->SystemSpaceHashEntries -= 1;
    03959     Size = (ULONG) (Session->SystemSpaceViewTable[Hash].Entry & 0xFFFF);
    03960     Session->SystemSpaceViewTable[Hash].Entry = 0;
    03961     *ControlArea = Session->SystemSpaceViewTable[Hash].ControlArea;
    03962     return Size;
    03963 }
    03964
    03965
    03966 BOOLEAN
    03967 MiInitializeSystemSpaceMap (
    03968     PVOID   InputSession OPTIONAL
    03969     )
    03970
    03971 /*++
    03972
    03973 Routine Description:
    03974
    03975     This routine initializes the tables for mapping views into system space.
    03976     Views are kept in a multiple of 64k bytes in a growable hashed table.
    03977
    03978 Arguments:
    03979
    03980     NULL if this is the initial system session (non-Hydra), a valid session
    03981     pointer (the pointer must be in global space, not session space) for
    03982     Hydra session initialization.
    03983
    03984 Return Value:
    03985
    03986     TRUE on success, FALSE on failure.
    03987
    03988 Environment:
    03989
    03990     Kernel Mode, initialization.
    03991
    03992 --*/
    03993
    03994 {
    03995     ULONG AllocSize;
    03996     ULONG Size;
    03997     PCHAR ViewStart;
    03998     PMMSESSION Session;
    03999
    04000     if (ARGUMENT_PRESENT (InputSession)) {
    04001         Session = (PMMSESSION)InputSession;
    04002         ViewStart = (PCHAR)MI_SESSION_VIEW_START;
    04003         Size = MI_SESSION_VIEW_SIZE;
    04004     }
    04005     else {
    04006         Session = &MmSession;
    04007         ViewStart = (PCHAR)MiSystemViewStart;
    04008         if (MiHydra == TRUE) {
    04009             Size = MM_SYSTEM_VIEW_SIZE_IF_HYDRA;
    04010         }
    04011         else {
    04012             Size = MM_SYSTEM_VIEW_SIZE;
    04013         }
    04014     }
    04015
    04016     //
    04017     // We are passed a system global address for the address of the session.
    04018     // Save a global pointer to the mutex below because multiple sessions will
    04019     // generally give us a session-space (not a global space) pointer to the
    04020     // MMSESSION in subsequent calls.  We need the global pointer for the mutex
    04021     // field for the kernel primitives to work properly.
    04022     //
    04023
    04024     Session->SystemSpaceViewLockPointer = &Session->SystemSpaceViewLock;
    04025     ExInitializeFastMutex(Session->SystemSpaceViewLockPointer);
    04026
    04027     //
    04028     // If the kernel image has not been biased to allow for 3gb of user space,
    04029     // then the system space view starts at the defined place. Otherwise, it
    04030     // starts 16mb above the kernel image.
    04031     //
    04032
    04033     Session->SystemSpaceViewStart = ViewStart;
    04034
    04035     MiCreateBitMap (&Session->SystemSpaceBitMap, Size / X64K, NonPagedPool);
    04036     if (Session->SystemSpaceBitMap == NULL) {
    04037         MM_BUMP_SESSION_FAILURES (MM_SESSION_FAILURE_NO_NONPAGED_POOL);
    04038         return FALSE;
    04039     }
    04040
    04041     RtlClearAllBits (Session->SystemSpaceBitMap);
    04042
    04043     //
    04044     // Build the view table.
    04045     //
    04046
    04047     Session->SystemSpaceHashSize = 31;
    04048     Session->SystemSpaceHashKey = Session->SystemSpaceHashSize - 1;
    04049     Session->SystemSpaceHashEntries = 0;
    04050
    04051     AllocSize = sizeof(MMVIEW) * Session->SystemSpaceHashSize;
    04052     ASSERT (AllocSize < PAGE_SIZE);
    04053
    04054     Session->SystemSpaceViewTable = ExAllocatePoolWithTag (PagedPool,
    04055                                                            AllocSize,
    04056                                                            '  mM');
    04057
    04058     if (Session->SystemSpaceViewTable == NULL) {
    04059         MM_BUMP_SESSION_FAILURES (MM_SESSION_FAILURE_NO_SESSION_PAGED_POOL);
    04060         MiRemoveBitMap (&Session->SystemSpaceBitMap);
    04061         return FALSE;
    04062     }
    04063
    04064     RtlZeroMemory (Session->SystemSpaceViewTable, AllocSize);
    04065
    04066     return TRUE;
    04067 }
    04068
    04069
    04070 VOID
    04071 MiFreeSessionSpaceMap (
    04072     VOID
    04073     )
    04074
    04075 /*++
    04076
    04077 Routine Description:
    04078
    04079     This routine frees the tables used for mapping session views.
    04080
    04081 Arguments:
    04082
    04083     None.
    04084
    04085 Return Value:
    04086
    04087     None.
    04088
    04089 Environment:
    04090
    04091     Kernel Mode.  The caller must be in the correct session context.
    04092
    04093 --*/
    04094
    04095 {
    04096     PMMSESSION Session;
    04097
    04098     PAGED_CODE();
    04099
    04100     Session = &MmSessionSpace->Session;
    04101
    04102     //
    04103     // Check for leaks of objects in the view table.
    04104     //
    04105
    04106     LOCK_SYSTEM_VIEW_SPACE (Session);
    04107
    04108     if (Session->SystemSpaceViewTable && Session->SystemSpaceHashEntries) {
    04109
    04110         KeBugCheckEx (SESSION_HAS_VALID_VIEWS_ON_EXIT,
    04111                       (ULONG_PTR)MmSessionSpace->SessionId,
    04112                       Session->SystemSpaceHashEntries,
    04113                       (ULONG_PTR)&Session->SystemSpaceViewTable[0],
    04114                       Session->SystemSpaceHashSize);
    04115
    04116 #if 0
    04117         ULONG Index;
    04118
    04119         for (Index = 0; Index < Session->SystemSpaceHashSize; Index += 1) {
    04120
    04121             PMMVIEW Table;
    04122             PVOID Base;
    04123
    04124             Table = &Session->SystemSpaceViewTable[Index];
    04125
    04126             if (Table->Entry) {
    04127
    04128 #if DBG
    04129                 DbgPrint ("MM: MiFreeSessionSpaceMap: view entry %d leak: ControlArea %p, Addr %p, Size %d\n",
    04130                     Index,
    04131                     Table->ControlArea,
    04132                     Table->Entry & ~0xFFFF,
    04133                     Table->Entry & 0x0000FFFF
    04134                 );
    04135 #endif
    04136
    04137                 Base = (PVOID)(Table->Entry & ~0xFFFF);
    04138
    04139                 //
    04140                 // MiUnmapViewInSystemSpace locks the ViewLock.
    04141                 //
    04142
    04143                 UNLOCK_SYSTEM_VIEW_SPACE(Session);
    04144
    04145                 MiUnmapViewInSystemSpace (Session, Base);
    04146
    04147                 LOCK_SYSTEM_VIEW_SPACE (Session);
    04148
    04149                 //
    04150                 // The view table may have been deleted while we let go of
    04151                 // the lock.
    04152                 //
    04153
    04154                 if (Session->SystemSpaceViewTable == NULL) {
    04155                     break;
    04156                 }
    04157             }
    04158         }
    04159 #endif
    04160
    04161     }
    04162
    04163     UNLOCK_SYSTEM_VIEW_SPACE (Session);
    04164
    04165     if (Session->SystemSpaceViewTable) {
    04166         ExFreePool (Session->SystemSpaceViewTable);
    04167         Session->SystemSpaceViewTable = NULL;
    04168     }
    04169
    04170     if (Session->SystemSpaceBitMap) {
    04171         MiRemoveBitMap (&Session->SystemSpaceBitMap);
    04172     }
    04173 }
    04174
    04175
    04176 HANDLE
    04177 MmSecureVirtualMemory (
    04178     IN PVOID Address,
    04179     IN SIZE_T Size,
    04180     IN ULONG ProbeMode
    04181     )
    04182
    04183 /*++
    04184
    04185 Routine Description:
    04186
    04187     This routine probes the requested address range and protects
    04188     the specified address range from having its protection made
    04189     more restricted and being deleted.
    04190
    04191     MmUnsecureVirtualMemory is used to allow the range to return
    04192     to a normal state.
    04193
    04194 Arguments:
    04195
    04196     Address - Supplies the base address to probe and secure.
    04197
    04198     Size - Supplies the size of the range to secure.
    04199
    04200     ProbeMode - Supplies one of PAGE_READONLY or PAGE_READWRITE.
    04201
    04202 Return Value:
    04203
    04204     Returns a handle to be used to unsecure the range.
    04205     If the range could not be locked because of protection
    04206     problems or noncommitted memory, the value (HANDLE)0
    04207     is returned.
    04208
    04209 Environment:
    04210
    04211     Kernel Mode.
    04212
    04213 --*/
    04214
    04215 {
    04216     ULONG_PTR EndAddress;
    04217     PVOID StartAddress;
    04218     CHAR Temp;
    04219     ULONG Probe;
    04220     HANDLE Handle;
    04221     PMMVAD Vad;
    04222     PMMVAD NewVad;
    04223     PMMSECURE_ENTRY Secure;
    04224     PEPROCESS Process;
    04225     PMMPTE PointerPpe;
    04226     PMMPTE PointerPde;
    04227     PMMPTE PointerPte;
    04228     PMMPTE LastPte;
    04229     MMLOCK_CONFLICT Conflict;
    04230     ULONG Waited;
    04231
    04232     PAGED_CODE();
    04233
    04234     if ((ULONG_PTR)Address + Size > (ULONG_PTR)MM_HIGHEST_USER_ADDRESS || (ULONG_PTR)Address + Size <= (ULONG_PTR)Address) {
    04235         return (HANDLE)0;
    04236     }
    04237
    04238     Handle = (HANDLE)0;
    04239
    04240     Probe = (ProbeMode == PAGE_READONLY);
    04241
    04242     Process = PsGetCurrentProcess();
    04243     StartAddress = Address;
    04244
    04245     LOCK_ADDRESS_SPACE (Process);
    04246
    04247     //
    04248     // Check for a private committed VAD first instead of probing to avoid all
    04249     // the page faults and zeroing.  If we find one, then we run the PTEs
    04250     // instead.
    04251     //
    04252
    04253     if (Size >= 64 * 1024) {
    04254         EndAddress = (ULONG_PTR)StartAddress + Size - 1;
    04255         Vad = MiLocateAddress (StartAddress);
    04256
    04257         if (Vad == NULL) {
    04258             goto Return1;
    04259         }
    04260
    04261         if (Vad->u.VadFlags.UserPhysicalPages == 1) {
    04262             goto Return1;
    04263         }
    04264
    04265         if (Vad->u.VadFlags.MemCommit == 0) {
    04266             goto LongWay;
    04267         }
    04268
    04269         if (Vad->u.VadFlags.PrivateMemory == 0) {
    04270             goto LongWay;
    04271         }
    04272
    04273         if (Vad->u.VadFlags.PhysicalMapping == 1) {
    04274             goto LongWay;
    04275         }
    04276
    04277         ASSERT (Vad->u.VadFlags.Protection);
    04278
    04279         if ((MI_VA_TO_VPN (StartAddress) < Vad->StartingVpn) ||
    04280             (MI_VA_TO_VPN (EndAddress) > Vad->EndingVpn)) {
    04281             goto Return1;
    04282         }
    04283
    04284         if (Vad->u.VadFlags.Protection == MM_NOACCESS) {
    04285             goto LongWay;
    04286         }
    04287
    04288         if (ProbeMode == PAGE_READONLY) {
    04289             if (Vad->u.VadFlags.Protection > MM_EXECUTE_WRITECOPY) {
    04290                 goto LongWay;
    04291             }
    04292         }
    04293         else {
    04294             if (Vad->u.VadFlags.Protection != MM_READWRITE &&
    04295                 Vad->u.VadFlags.Protection != MM_EXECUTE_READWRITE) {
    04296                     goto LongWay;
    04297             }
    04298         }
    04299
    04300         //
    04301         // Check individual page permissions.
    04302         //
    04303
    04304         PointerPde = MiGetPdeAddress (StartAddress);
    04305         PointerPpe = MiGetPteAddress (PointerPde);
    04306         PointerPte = MiGetPteAddress (StartAddress);
    04307         LastPte = MiGetPteAddress (EndAddress);
    04308
    04309         LOCK_WS_UNSAFE (Process);
    04310
    04311         do {
    04312
    04313             while (MiDoesPpeExistAndMakeValid (PointerPpe,
    04314                                                Process,
    04315                                                FALSE,
    04316                                                &Waited) == FALSE) {
    04317                 //
    04318                 // Page directory parent entry is empty, go to the next one.
    04319                 //
    04320
    04321                 PointerPpe += 1;
    04322                 PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
    04323                 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
    04324                 if (PointerPte > LastPte) {
    04325                     UNLOCK_WS_UNSAFE (Process);
    04326                     goto EditVad;
    04327                 }
    04328             }
    04329
    04330             Waited = 0;
    04331
    04332             while (MiDoesPdeExistAndMakeValid (PointerPde,
    04333                                                Process,
    04334                                                FALSE,
    04335                                                &Waited) == FALSE) {
    04336                 //
    04337                 // This page directory entry is empty, go to the next one.
    04338                 //
    04339
    04340                 PointerPde += 1;
    04341                 PointerPpe = MiGetPteAddress (PointerPde);
    04342                 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
    04343                 if (PointerPte > LastPte) {
    04344                     UNLOCK_WS_UNSAFE (Process);
    04345                     goto EditVad;
    04346                 }
    04347 #if defined (_WIN64)
    04348                 if (MiIsPteOnPdeBoundary (PointerPde)) {
    04349                     Waited = 1;
    04350                     break;
    04351                 }
    04352 #endif
    04353             }
    04354
    04355         } while (Waited != 0);
    04356
    04357         while (PointerPte <= LastPte) {
    04358
    04359             if (MiIsPteOnPdeBoundary (PointerPte)) {
    04360
    04361                 PointerPde = MiGetPteAddress (PointerPte);
    04362                 PointerPpe = MiGetPteAddress (PointerPde);
    04363
    04364                 do {
    04365
    04366                     while (MiDoesPpeExistAndMakeValid (PointerPpe,
    04367                                                        Process,
    04368                                                        FALSE,
    04369                                                        &Waited) == FALSE) {
    04370                         //
    04371                         // Page directory parent entry is empty, go to the next one.
    04372                         //
    04373
    04374                         PointerPpe += 1;
    04375                         PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
    04376                         PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
    04377
    04378                         if (PointerPte > LastPte) {
    04379                             UNLOCK_WS_UNSAFE (Process);
    04380                             goto EditVad;
    04381                         }
    04382                     }
    04383
    04384                     Waited = 0;
    04385
    04386                     while (MiDoesPdeExistAndMakeValid (PointerPde,
    04387                                                        Process,
    04388                                                        FALSE,
    04389                                                        &Waited) == FALSE) {
    04390                         //
    04391                         // This page directory entry is empty, go to the next one.
    04392                         //
    04393
    04394                         PointerPde += 1;
    04395                         PointerPpe = MiGetPteAddress (PointerPde);
    04396                         PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
    04397                         if (PointerPte > LastPte) {
    04398                             UNLOCK_WS_UNSAFE (Process);
    04399                             goto EditVad;
    04400                         }
    04401 #if defined (_WIN64)
    04402                         if (MiIsPteOnPdeBoundary (PointerPde)) {
    04403                             Waited = 1;
    04404                             break;
    04405                         }
    04406 #endif
    04407                     }
    04408
    04409                 } while (Waited != 0);
    04410             }
    04411             if (PointerPte->u.Long) {
    04412                 UNLOCK_WS_UNSAFE (Process);
    04413                 goto LongWay;
    04414             }
    04415             PointerPte += 1;
    04416         }
    04417         UNLOCK_WS_UNSAFE (Process);
    04418     }
    04419     else {
    04420 LongWay:
    04421
    04422         MiInsertConflictInList (&Conflict);
    04423
    04424         try {
    04425
    04426             if (ProbeMode == PAGE_READONLY) {
    04427
    04428                 EndAddress = (ULONG_PTR)Address + Size - 1;
    04429                 EndAddress = (EndAddress & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
    04430
    04431                 do {
    04432                     Temp = *(volatile CHAR *)Address;
    04433                     Address = (PVOID)(((ULONG_PTR)Address & ~(PAGE_SIZE - 1)) + PAGE_SIZE);
    04434                 } while ((ULONG_PTR)Address != EndAddress);
    04435             } else {
    04436                 ProbeForWrite (Address, (ULONG)Size, 1); // ****** temp ******
    04437             }
    04438
    04439         } except (EXCEPTION_EXECUTE_HANDLER) {
    04440             MiRemoveConflictFromList (&Conflict);
    04441             goto Return1;
    04442         }
    04443
    04444         MiRemoveConflictFromList (&Conflict);
    04445
    04446         //
    04447         // Locate VAD and add in secure descriptor.
    04448         //
    04449
    04450         EndAddress = (ULONG_PTR)StartAddress + Size - 1;
    04451         Vad = MiLocateAddress (StartAddress);
    04452
    04453         if (Vad == NULL) {
    04454             goto Return1;
    04455         }
    04456
    04457         if (Vad->u.VadFlags.UserPhysicalPages == 1) {
    04458             goto Return1;
    04459         }
    04460
    04461         if ((MI_VA_TO_VPN (StartAddress) < Vad->StartingVpn) ||
    04462             (MI_VA_TO_VPN (EndAddress) > Vad->EndingVpn)) {
    04463
    04464             //
    04465             // Not within the section virtual address descriptor,
    04466             // return an error.
    04467             //
    04468
    04469             goto Return1;
    04470         }
    04471     }
    04472
    04473 EditVad:
    04474
    04475     //
    04476     // If this is a short VAD, it needs to be reallocated as a large
    04477     // VAD.
    04478     //
    04479
    04480     if ((Vad->u.VadFlags.PrivateMemory) && (!Vad->u.VadFlags.NoChange)) {
    04481
    04482         NewVad = ExAllocatePoolWithTag (NonPagedPool,
    04483                                         sizeof(MMVAD),
    04484                                         MMVADKEY);
    04485         if (NewVad == NULL) {
    04486             goto Return1;
    04487         }
    04488
    04489         RtlZeroMemory (NewVad, sizeof(MMVAD));
    04490         RtlCopyMemory (NewVad, Vad, sizeof(MMVAD_SHORT));
    04491         NewVad->u.VadFlags.NoChange = 1;
    04492         NewVad->u2.VadFlags2.OneSecured = 1;
    04493         NewVad->u2.VadFlags2.StoredInVad = 1;
    04494         NewVad->u2.VadFlags2.ReadOnly = Probe;
    04495         NewVad->u3.Secured.StartVpn = (ULONG_PTR)StartAddress;
    04496         NewVad->u3.Secured.EndVpn = EndAddress;
    04497
    04498         //
    04499         // Replace the current VAD with this expanded VAD.
    04500         //
    04501
    04502         LOCK_WS_UNSAFE (Process);
    04503         if (Vad->Parent) {
    04504             if (Vad->Parent->RightChild == Vad) {
    04505                 Vad->Parent->RightChild = NewVad;
    04506             } else {
    04507                 ASSERT (Vad->Parent->LeftChild == Vad);
    04508                 Vad->Parent->LeftChild = NewVad;
    04509             }
    04510         } else {
    04511             Process->VadRoot = NewVad;
    04512         }
    04513         if (Vad->LeftChild) {
    04514             Vad->LeftChild->Parent = NewVad;
    04515         }
    04516         if (Vad->RightChild) {
    04517             Vad->RightChild->Parent = NewVad;
    04518         }
    04519         if (Process->VadHint == Vad) {
    04520             Process->VadHint = NewVad;
    04521         }
    04522         if (Process->VadFreeHint == Vad) {
    04523             Process->VadFreeHint = NewVad;
    04524         }
    04525
    04526         if ((Vad->u.VadFlags.PhysicalMapping == 1) ||
    04527             (Vad->u.VadFlags.WriteWatch == 1)) {
    04528
    04529             MiPhysicalViewAdjuster (Process, Vad, NewVad);
    04530         }
    04531
    04532         UNLOCK_WS_UNSAFE (Process);
    04533         ExFreePool (Vad);
    04534         Handle = (HANDLE)&NewVad->u2.LongFlags2;
    04535         goto Return1;
    04536     }
    04537
    04538     //
    04539     // This is already a large VAD, add the secure entry.
    04540     //
    04541
    04542     if (Vad->u2.VadFlags2.OneSecured) {
    04543
    04544         //
    04545         // This VAD already is secured.  Move the info out of the
    04546         // block into pool.
    04547         //
    04548
    04549         Secure = ExAllocatePoolWithTag (NonPagedPool,
    04550                                         sizeof (MMSECURE_ENTRY),
    04551                                         'eSmM');
    04552         if (Secure == NULL) {
    04553             goto Return1;
    04554         }
    04555
    04556         ASSERT (Vad->u.VadFlags.NoChange == 1);
    04557         Vad->u2.VadFlags2.OneSecured = 0;
    04558         Vad->u2.VadFlags2.MultipleSecured = 1;
    04559         Secure->u2.LongFlags2 = (ULONG) Vad->u.LongFlags;
    04560         Secure->u2.VadFlags2.StoredInVad = 0;
    04561         Secure->StartVpn = Vad->u3.Secured.StartVpn;
    04562         Secure->EndVpn = Vad->u3.Secured.EndVpn;
    04563
    04564         InitializeListHead (&Vad->u3.List);
    04565         InsertTailList (&Vad->u3.List,
    04566                         &Secure->List);
    04567     }
    04568
    04569     if (Vad->u2.VadFlags2.MultipleSecured) {
    04570
    04571         //
    04572         // This VAD already has a secured element in its list, allocate and
    04573         // add in the new secured element.
    04574         //
    04575
    04576         Secure = ExAllocatePoolWithTag (NonPagedPool,
    04577                                         sizeof (MMSECURE_ENTRY),
    04578                                         'eSmM');
    04579         if (Secure == NULL) {
    04580             goto Return1;
    04581         }
    04582
    04583         Secure->u2.LongFlags2 = 0;
    04584         Secure->u2.VadFlags2.ReadOnly = Probe;
    04585         Secure->StartVpn = (ULONG_PTR)StartAddress;
    04586         Secure->EndVpn = EndAddress;
    04587
    04588         InsertTailList (&Vad->u3.List,
    04589                         &Secure->List);
    04590         Handle = (HANDLE)Secure;
    04591
    04592     } else {
    04593
    04594         //
    04595         // This list does not have a secure element.  Put it in the VAD.
    04596         //
    04597
    04598         Vad->u.VadFlags.NoChange = 1;
    04599         Vad->u2.VadFlags2.OneSecured = 1;
    04600         Vad->u2.VadFlags2.StoredInVad = 1;
    04601         Vad->u2.VadFlags2.ReadOnly = Probe;
    04602         Vad->u3.Secured.StartVpn = (ULONG_PTR)StartAddress;
    04603         Vad->u3.Secured.EndVpn = EndAddress;
    04604         Handle = (HANDLE)&Vad->u2.LongFlags2;
    04605     }
    04606
    04607 Return1:
    04608     UNLOCK_ADDRESS_SPACE (Process);
    04609     return Handle;
    04610 }
    04611
    04612
    04613 VOID
    04614 MmUnsecureVirtualMemory (
    04615     IN HANDLE SecureHandle
    04616     )
    04617
    04618 /*++
    04619
    04620 Routine Description:
    04621
    04622     This routine unsecures memory previous secured via a call to
    04623     MmSecureVirtualMemory.
    04624
    04625 Arguments:
    04626
    04627     SecureHandle - Supplies the handle returned in MmSecureVirtualMemory.
    04628
    04629 Return Value:
    04630
    04631     None.
    04632
    04633 Environment:
    04634
    04635     Kernel Mode.
    04636
    04637 --*/
    04638
    04639 {
    04640     PMMSECURE_ENTRY Secure;
    04641     PEPROCESS Process;
    04642     PMMVAD Vad;
    04643
    04644     PAGED_CODE();
    04645
    04646     Secure = (PMMSECURE_ENTRY)SecureHandle;
    04647     Process = PsGetCurrentProcess ();
    04648     LOCK_ADDRESS_SPACE (Process);
    04649
    04650     if (Secure->u2.VadFlags2.StoredInVad) {
    04651         Vad = CONTAINING_RECORD( Secure,
    04652                                  MMVAD,
    04653                                  u2.LongFlags2);
    04654     } else {
    04655         Vad = MiLocateAddress ((PVOID)Secure->StartVpn);
    04656     }
    04657
    04658     ASSERT (Vad);
    04659     ASSERT (Vad->u.VadFlags.NoChange == 1);
    04660
    04661     if (Vad->u2.VadFlags2.OneSecured) {
    04662         ASSERT (Secure == (PMMSECURE_ENTRY)&Vad->u2.LongFlags2);
    04663         Vad->u2.VadFlags2.OneSecured = 0;
    04664         ASSERT (Vad->u2.VadFlags2.MultipleSecured == 0);
    04665         if (Vad->u2.VadFlags2.SecNoChange == 0) {
    04666
    04667             //
    04668             // No more secure entries in this list, remove the state.
    04669             //
    04670
    04671             Vad->u.VadFlags.NoChange = 0;
    04672         }
    04673     } else {
    04674         ASSERT (Vad->u2.VadFlags2.MultipleSecured == 1);
    04675
    04676         if (Secure == (PMMSECURE_ENTRY)&Vad->u2.LongFlags2) {
    04677
    04678             //
    04679             // This was a single block that got converted into a list.
    04680             // Reset the entry.
    04681             //
    04682
    04683             Secure = CONTAINING_RECORD (Vad->u3.List.Flink,
    04684                                         MMSECURE_ENTRY,
    04685                                         List);
    04686         }
    04687         RemoveEntryList (&Secure->List);
    04688         ExFreePool (Secure);
    04689         if (IsListEmpty (&Vad->u3.List)) {
    04690
    04691             //
    04692             // No more secure entries, reset the state.
    04693             //
    04694
    04695             Vad->u2.VadFlags2.MultipleSecured = 0;
    04696
    04697             if ((Vad->u2.VadFlags2.SecNoChange == 0) &&
    04698                (Vad->u.VadFlags.PrivateMemory == 0)) {
    04699
    04700                 //
    04701                 // No more secure entries in this list, remove the state
    04702                 // if and only if this VAD is not private.  If this VAD
    04703                 // is private, removing the state NoChange flag indicates
    04704                 // that this is a short VAD which it no longer is.
    04705                 //
    04706
    04707                 Vad->u.VadFlags.NoChange = 0;
    04708             }
    04709         }
    04710     }
    04711
    04712     UNLOCK_ADDRESS_SPACE (Process);
    04713     return;
    04714 }