ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

section.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         BSD - See COPYING.ARM in the top level directory
00004  * FILE:            ntoskrnl/mm/ARM3/sectopm.c
00005  * PURPOSE:         ARM Memory Manager Section Support
00006  * PROGRAMMERS:     ReactOS Portable Systems Group
00007  */
00008 
00009 /* INCLUDES *******************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 #define MODULE_INVOLVED_IN_ARM3
00016 #include "../ARM3/miarm.h"
00017 
00018 /* GLOBALS ********************************************************************/
00019 
00020 ACCESS_MASK MmMakeSectionAccess[8] =
00021 {
00022     SECTION_MAP_READ,
00023     SECTION_MAP_READ,
00024     SECTION_MAP_EXECUTE,
00025     SECTION_MAP_EXECUTE | SECTION_MAP_READ,
00026     SECTION_MAP_WRITE,
00027     SECTION_MAP_READ,
00028     SECTION_MAP_EXECUTE | SECTION_MAP_WRITE,
00029     SECTION_MAP_EXECUTE | SECTION_MAP_READ
00030 };
00031 
00032 ACCESS_MASK MmMakeFileAccess[8] =
00033 {
00034     FILE_READ_DATA,
00035     FILE_READ_DATA,
00036     FILE_EXECUTE,
00037     FILE_EXECUTE | FILE_READ_DATA,
00038     FILE_WRITE_DATA | FILE_READ_DATA,
00039     FILE_READ_DATA,
00040     FILE_EXECUTE | FILE_WRITE_DATA | FILE_READ_DATA,
00041     FILE_EXECUTE | FILE_READ_DATA
00042 };
00043 
00044 CHAR MmUserProtectionToMask1[16] =
00045 {
00046     0,
00047     MM_NOACCESS,
00048     MM_READONLY,
00049     (CHAR)MM_INVALID_PROTECTION,
00050     MM_READWRITE,
00051     (CHAR)MM_INVALID_PROTECTION,
00052     (CHAR)MM_INVALID_PROTECTION,
00053     (CHAR)MM_INVALID_PROTECTION,
00054     MM_WRITECOPY,
00055     (CHAR)MM_INVALID_PROTECTION,
00056     (CHAR)MM_INVALID_PROTECTION,
00057     (CHAR)MM_INVALID_PROTECTION,
00058     (CHAR)MM_INVALID_PROTECTION,
00059     (CHAR)MM_INVALID_PROTECTION,
00060     (CHAR)MM_INVALID_PROTECTION,
00061     (CHAR)MM_INVALID_PROTECTION
00062 };
00063 
00064 CHAR MmUserProtectionToMask2[16] =
00065 {
00066     0,
00067     MM_EXECUTE,
00068     MM_EXECUTE_READ,
00069     (CHAR)MM_INVALID_PROTECTION,
00070     MM_EXECUTE_READWRITE,
00071     (CHAR)MM_INVALID_PROTECTION,
00072     (CHAR)MM_INVALID_PROTECTION,
00073     (CHAR)MM_INVALID_PROTECTION,
00074     MM_EXECUTE_WRITECOPY,
00075     (CHAR)MM_INVALID_PROTECTION,
00076     (CHAR)MM_INVALID_PROTECTION,
00077     (CHAR)MM_INVALID_PROTECTION,
00078     (CHAR)MM_INVALID_PROTECTION,
00079     (CHAR)MM_INVALID_PROTECTION,
00080     (CHAR)MM_INVALID_PROTECTION,
00081     (CHAR)MM_INVALID_PROTECTION
00082 };
00083 
00084 MMSESSION MmSession;
00085 KGUARDED_MUTEX MmSectionCommitMutex;
00086 MM_AVL_TABLE MmSectionBasedRoot;
00087 KGUARDED_MUTEX MmSectionBasedMutex;
00088 PVOID MmHighSectionBase;
00089 
00090 /* PRIVATE FUNCTIONS **********************************************************/
00091 
00092 ACCESS_MASK
00093 NTAPI
00094 MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection)
00095 {
00096     ULONG ProtectionMask;
00097 
00098     /* Calculate the protection mask and make sure it's valid */
00099     ProtectionMask = MiMakeProtectionMask(SectionPageProtection);
00100     if (ProtectionMask == MM_INVALID_PROTECTION)
00101     {
00102         DPRINT1("Invalid protection mask\n");
00103         return STATUS_INVALID_PAGE_PROTECTION;
00104     }
00105 
00106     /* Now convert it to the required file access */
00107     return MmMakeFileAccess[ProtectionMask & 0x7];
00108 }
00109 
00110 ULONG
00111 NTAPI
00112 MiMakeProtectionMask(IN ULONG Protect)
00113 {
00114     ULONG Mask1, Mask2, ProtectMask;
00115 
00116     /* PAGE_EXECUTE_WRITECOMBINE is theoretically the maximum */
00117     if (Protect >= (PAGE_WRITECOMBINE * 2)) return MM_INVALID_PROTECTION;
00118 
00119     /*
00120      * Windows API protection mask can be understood as two bitfields, differing
00121      * by whether or not execute rights are being requested
00122      */
00123     Mask1 = Protect & 0xF;
00124     Mask2 = (Protect >> 4) & 0xF;
00125 
00126     /* Check which field is there */
00127     if (!Mask1)
00128     {
00129         /* Mask2 must be there, use it to determine the PTE protection */
00130         if (!Mask2) return MM_INVALID_PROTECTION;
00131         ProtectMask = MmUserProtectionToMask2[Mask2];
00132     }
00133     else
00134     {
00135         /* Mask2 should not be there, use Mask1 to determine the PTE mask */
00136         if (Mask2) return MM_INVALID_PROTECTION;
00137         ProtectMask = MmUserProtectionToMask1[Mask1];
00138     }
00139 
00140     /* Make sure the final mask is a valid one */
00141     if (ProtectMask == MM_INVALID_PROTECTION) return MM_INVALID_PROTECTION;
00142 
00143     /* Check for PAGE_GUARD option */
00144     if (Protect & PAGE_GUARD)
00145     {
00146         /* It's not valid on no-access, nocache, or writecombine pages */
00147         if ((ProtectMask == MM_NOACCESS) ||
00148             (Protect & (PAGE_NOCACHE | PAGE_WRITECOMBINE)))
00149         {
00150             /* Fail such requests */
00151             return MM_INVALID_PROTECTION;
00152         }
00153 
00154         /* This actually turns on guard page in this scenario! */
00155         ProtectMask |= MM_DECOMMIT;
00156     }
00157 
00158     /* Check for nocache option */
00159     if (Protect & PAGE_NOCACHE)
00160     {
00161         /* The earlier check should've eliminated this possibility */
00162         ASSERT((Protect & PAGE_GUARD) == 0);
00163 
00164         /* Check for no-access page or write combine page */
00165         if ((ProtectMask == MM_NOACCESS) || (Protect & PAGE_WRITECOMBINE))
00166         {
00167             /* Such a request is invalid */
00168             return MM_INVALID_PROTECTION;
00169         }
00170 
00171         /* Add the PTE flag */
00172         ProtectMask |= MM_NOCACHE;
00173     }
00174 
00175     /* Check for write combine option */
00176     if (Protect & PAGE_WRITECOMBINE)
00177     {
00178         /* The two earlier scenarios should've caught this */
00179         ASSERT((Protect & (PAGE_GUARD | PAGE_NOACCESS)) == 0);
00180 
00181         /* Don't allow on no-access pages */
00182         if (ProtectMask == MM_NOACCESS) return MM_INVALID_PROTECTION;
00183 
00184         /* This actually turns on write-combine in this scenario! */
00185         ProtectMask |= MM_NOACCESS;
00186     }
00187 
00188     /* Return the final MM PTE protection mask */
00189     return ProtectMask;
00190 }
00191 
00192 BOOLEAN
00193 NTAPI
00194 MiInitializeSystemSpaceMap(IN PVOID InputSession OPTIONAL)
00195 {
00196     SIZE_T AllocSize, BitmapSize;
00197     PMMSESSION Session;
00198 
00199     /* For now, always use the global session */
00200     ASSERT(InputSession == NULL);
00201     Session = &MmSession;
00202 
00203     /* Initialize the system space lock */
00204     Session->SystemSpaceViewLockPointer = &Session->SystemSpaceViewLock;
00205     KeInitializeGuardedMutex(Session->SystemSpaceViewLockPointer);
00206 
00207     /* Set the start address */
00208     Session->SystemSpaceViewStart = MiSystemViewStart;
00209 
00210     /* Create a bitmap to describe system space */
00211     BitmapSize = sizeof(RTL_BITMAP) + ((((MmSystemViewSize / MI_SYSTEM_VIEW_BUCKET_SIZE) + 31) / 32) * sizeof(ULONG));
00212     Session->SystemSpaceBitMap = ExAllocatePoolWithTag(NonPagedPool,
00213                                                        BitmapSize,
00214                                                        TAG_MM);
00215     ASSERT(Session->SystemSpaceBitMap);
00216     RtlInitializeBitMap(Session->SystemSpaceBitMap,
00217                         (PULONG)(Session->SystemSpaceBitMap + 1),
00218                         (ULONG)(MmSystemViewSize / MI_SYSTEM_VIEW_BUCKET_SIZE));
00219 
00220     /* Set system space fully empty to begin with */
00221     RtlClearAllBits(Session->SystemSpaceBitMap);
00222 
00223     /* Set default hash flags */
00224     Session->SystemSpaceHashSize = 31;
00225     Session->SystemSpaceHashKey = Session->SystemSpaceHashSize - 1;
00226     Session->SystemSpaceHashEntries = 0;
00227 
00228     /* Calculate how much space for the hash views we'll need */
00229     AllocSize = sizeof(MMVIEW) * Session->SystemSpaceHashSize;
00230     ASSERT(AllocSize < PAGE_SIZE);
00231 
00232     /* Allocate and zero the view table */
00233     Session->SystemSpaceViewTable = ExAllocatePoolWithTag(NonPagedPool,
00234                                                           AllocSize,
00235                                                           TAG_MM);
00236     ASSERT(Session->SystemSpaceViewTable != NULL);
00237     RtlZeroMemory(Session->SystemSpaceViewTable, AllocSize);
00238 
00239     /* Success */
00240     return TRUE;
00241 }
00242 
00243 PVOID
00244 NTAPI
00245 MiInsertInSystemSpace(IN PMMSESSION Session,
00246                       IN ULONG Buckets,
00247                       IN PCONTROL_AREA ControlArea)
00248 {
00249     PVOID Base;
00250     ULONG Entry, Hash, i, HashSize;
00251     PMMVIEW OldTable;
00252     PAGED_CODE();
00253 
00254     /* Only global mappings supported for now */
00255     ASSERT(Session == &MmSession);
00256 
00257     /* Stay within 4GB */
00258     ASSERT(Buckets < MI_SYSTEM_VIEW_BUCKET_SIZE);
00259 
00260     /* Lock system space */
00261     KeAcquireGuardedMutex(Session->SystemSpaceViewLockPointer);
00262 
00263     /* Check if we're going to exhaust hash entries */
00264     if ((Session->SystemSpaceHashEntries + 8) > Session->SystemSpaceHashSize)
00265     {
00266         /* Double the hash size */
00267         HashSize = Session->SystemSpaceHashSize * 2;
00268 
00269         /* Save the old table and allocate a new one */
00270         OldTable = Session->SystemSpaceViewTable;
00271         Session->SystemSpaceViewTable = ExAllocatePoolWithTag(NonPagedPool,
00272                                                               HashSize *
00273                                                               sizeof(MMVIEW),
00274                                                               '  mM');
00275         if (!Session->SystemSpaceViewTable)
00276         {
00277             /* Failed to allocate a new table, keep the old one for now */
00278             Session->SystemSpaceViewTable = OldTable;
00279         }
00280         else
00281         {
00282             /* Clear the new table and set the new ahsh and key */
00283             RtlZeroMemory(Session->SystemSpaceViewTable, HashSize * sizeof(MMVIEW));
00284             Session->SystemSpaceHashSize = HashSize;
00285             Session->SystemSpaceHashKey = Session->SystemSpaceHashSize - 1;
00286 
00287             /* Loop the old table */
00288             for (i = 0; i < Session->SystemSpaceHashSize / 2; i++)
00289             {
00290                 /* Check if the entry was valid */
00291                 if (OldTable[i].Entry)
00292                 {
00293                     /* Re-hash the old entry and search for space in the new table */
00294                     Hash = (OldTable[i].Entry >> 16) % Session->SystemSpaceHashKey;
00295                     while (Session->SystemSpaceViewTable[Hash].Entry)
00296                     {
00297                         /* Loop back at the beginning if we had an overflow */
00298                         if (++Hash >= Session->SystemSpaceHashSize) Hash = 0;
00299                     }
00300 
00301                     /* Write the old entry in the new table */
00302                     Session->SystemSpaceViewTable[Hash] = OldTable[i];
00303                 }
00304             }
00305 
00306             /* Free the old table */
00307             ExFreePool(OldTable);
00308         }
00309     }
00310 
00311     /* Check if we ran out */
00312     if (Session->SystemSpaceHashEntries == Session->SystemSpaceHashSize)
00313     {
00314         DPRINT1("Ran out of system view hash entries\n");
00315         KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer);
00316         return NULL;
00317     }
00318 
00319     /* Find space where to map this view */
00320     i = RtlFindClearBitsAndSet(Session->SystemSpaceBitMap, Buckets, 0);
00321     if (i == 0xFFFFFFFF)
00322     {
00323         /* Out of space, fail */
00324         Session->BitmapFailures++;
00325         DPRINT1("Out of system view space\n");
00326         KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer);
00327         return NULL;
00328     }
00329 
00330     /* Compute the base address */
00331     Base = (PVOID)((ULONG_PTR)Session->SystemSpaceViewStart + (i * MI_SYSTEM_VIEW_BUCKET_SIZE));
00332 
00333     /* Get the hash entry for this allocation */
00334     Entry = ((ULONG_PTR)Base & ~(MI_SYSTEM_VIEW_BUCKET_SIZE - 1)) + Buckets;
00335     Hash = (Entry >> 16) % Session->SystemSpaceHashKey;
00336 
00337     /* Loop hash entries until a free one is found */
00338     while (Session->SystemSpaceViewTable[Hash].Entry)
00339     {
00340         /* Unless we overflow, in which case loop back at hash o */
00341         if (++Hash >= Session->SystemSpaceHashSize) Hash = 0;
00342     }
00343 
00344     /* Add this entry into the hash table */
00345     Session->SystemSpaceViewTable[Hash].Entry = Entry;
00346     Session->SystemSpaceViewTable[Hash].ControlArea = ControlArea;
00347 
00348     /* Hash entry found, increment total and return the base address */
00349     Session->SystemSpaceHashEntries++;
00350     KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer);
00351     return Base;
00352 }
00353 
00354 NTSTATUS
00355 NTAPI
00356 MiAddMappedPtes(IN PMMPTE FirstPte,
00357                 IN PFN_NUMBER PteCount,
00358                 IN PCONTROL_AREA ControlArea)
00359 {
00360     MMPTE TempPte;
00361     PMMPTE PointerPte, ProtoPte, LastProtoPte, LastPte;
00362     PSUBSECTION Subsection;
00363 
00364     /* ARM3 doesn't support this yet */
00365     ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
00366     ASSERT(ControlArea->u.Flags.Rom == 0);
00367     ASSERT(ControlArea->FilePointer == NULL);
00368 
00369     /* Sanity checks */
00370     ASSERT(PteCount != 0);
00371     ASSERT(ControlArea->NumberOfMappedViews >= 1);
00372     ASSERT(ControlArea->NumberOfUserReferences >= 1);
00373     ASSERT(ControlArea->NumberOfSectionReferences != 0);
00374     ASSERT(ControlArea->u.Flags.BeingCreated == 0);
00375     ASSERT(ControlArea->u.Flags.BeingDeleted == 0);
00376     ASSERT(ControlArea->u.Flags.BeingPurged == 0);
00377 
00378     /* Get the PTEs for the actual mapping */
00379     PointerPte = FirstPte;
00380     LastPte = FirstPte + PteCount;
00381 
00382     /* Get the prototype PTEs that desribe the section mapping in the subsection */
00383     Subsection = (PSUBSECTION)(ControlArea + 1);
00384     ProtoPte = Subsection->SubsectionBase;
00385     LastProtoPte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
00386 
00387     /* Loop the PTEs for the mapping */
00388     while (PointerPte < LastPte)
00389     {
00390         /* We may have run out of prototype PTEs in this subsection */
00391         if (ProtoPte >= LastProtoPte)
00392         {
00393             /* But we don't handle this yet */
00394             ASSERT(FALSE);
00395         }
00396 
00397         /* The PTE should be completely clear */
00398         ASSERT(PointerPte->u.Long == 0);
00399 
00400         /* Build the prototype PTE and write it */
00401         MI_MAKE_PROTOTYPE_PTE(&TempPte, ProtoPte);
00402         MI_WRITE_INVALID_PTE(PointerPte, TempPte);
00403 
00404         /* Keep going */
00405         PointerPte++;
00406         ProtoPte++;
00407     }
00408 
00409     /* No failure path */
00410     return STATUS_SUCCESS;
00411 }
00412 
00413 VOID
00414 NTAPI
00415 MiFillSystemPageDirectory(IN PVOID Base,
00416                           IN SIZE_T NumberOfBytes)
00417 {
00418     PMMPDE PointerPde, LastPde, SystemMapPde;
00419     MMPDE TempPde;
00420     PFN_NUMBER PageFrameIndex, ParentPage;
00421     KIRQL OldIrql;
00422     PAGED_CODE();
00423 
00424     /* Find the PDEs needed for this mapping */
00425     PointerPde = MiAddressToPde(Base);
00426     LastPde = MiAddressToPde((PVOID)((ULONG_PTR)Base + NumberOfBytes - 1));
00427 
00428 #if (_MI_PAGING_LEVELS == 2)
00429     /* Find the system double-mapped PDE that describes this mapping */
00430     SystemMapPde = &MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)];
00431 #else
00432     /* We don't have a double mapping */
00433     SystemMapPde = PointerPde;
00434 #endif
00435 
00436     /* Use the PDE template and loop the PDEs */
00437     TempPde = ValidKernelPde;
00438     while (PointerPde <= LastPde)
00439     {
00440         /* Lock the PFN database */
00441         OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00442 
00443         /* Check if we don't already have this PDE mapped */
00444         if (SystemMapPde->u.Hard.Valid == 0)
00445         {
00446             /* Grab a page for it */
00447             MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
00448             MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
00449             PageFrameIndex = MiRemoveZeroPage(MI_GET_NEXT_COLOR());
00450             ASSERT(PageFrameIndex);
00451             TempPde.u.Hard.PageFrameNumber = PageFrameIndex;
00452 
00453 #if (_MI_PAGING_LEVELS == 2)
00454             ParentPage = MmSystemPageDirectory[(PointerPde - MiAddressToPde(NULL)) / PDE_COUNT];
00455 #else
00456             ParentPage = MiPdeToPpe(PointerPde)->u.Hard.PageFrameNumber;
00457 #endif
00458             /* Initialize its PFN entry, with the parent system page directory page table */
00459             MiInitializePfnForOtherProcess(PageFrameIndex,
00460                                            (PMMPTE)PointerPde,
00461                                            ParentPage);
00462 
00463             /* Make the system PDE entry valid */
00464             MI_WRITE_VALID_PDE(SystemMapPde, TempPde);
00465 
00466             /* The system PDE entry might be the PDE itself, so check for this */
00467             if (PointerPde->u.Hard.Valid == 0)
00468             {
00469                 /* It's different, so make the real PDE valid too */
00470                 MI_WRITE_VALID_PDE(PointerPde, TempPde);
00471             }
00472         }
00473 
00474         /* Release the lock and keep going with the next PDE */
00475         KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00476         SystemMapPde++;
00477         PointerPde++;
00478     }
00479 }
00480 
00481 NTSTATUS
00482 NTAPI
00483 MiCheckPurgeAndUpMapCount(IN PCONTROL_AREA ControlArea,
00484                           IN BOOLEAN FailIfSystemViews)
00485 {
00486     KIRQL OldIrql;
00487 
00488     /* Flag not yet supported */
00489     ASSERT(FailIfSystemViews == FALSE);
00490 
00491     /* Lock the PFN database */
00492     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00493 
00494     /* State not yet supported */
00495     ASSERT(ControlArea->u.Flags.BeingPurged == 0);
00496 
00497     /* Increase the reference counts */
00498     ControlArea->NumberOfMappedViews++;
00499     ControlArea->NumberOfUserReferences++;
00500     ASSERT(ControlArea->NumberOfSectionReferences != 0);
00501 
00502     /* Release the PFN lock and return success */
00503     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00504     return STATUS_SUCCESS;
00505 }
00506 
00507 PSUBSECTION
00508 NTAPI
00509 MiLocateSubsection(IN PMMVAD Vad,
00510                    IN ULONG_PTR Vpn)
00511 {
00512     PSUBSECTION Subsection;
00513     PCONTROL_AREA ControlArea;
00514     ULONG_PTR PteOffset;
00515 
00516     /* Get the control area */
00517     ControlArea = Vad->ControlArea;
00518     ASSERT(ControlArea->u.Flags.Rom == 0);
00519     ASSERT(ControlArea->u.Flags.Image == 0);
00520     ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
00521 
00522     /* Get the subsection */
00523     Subsection = (PSUBSECTION)(ControlArea + 1);
00524 
00525     /* We only support single-subsection segments */
00526     ASSERT(Subsection->SubsectionBase != NULL);
00527     ASSERT(Vad->FirstPrototypePte >= Subsection->SubsectionBase);
00528     ASSERT(Vad->FirstPrototypePte < &Subsection->SubsectionBase[Subsection->PtesInSubsection]);
00529 
00530     /* Compute the PTE offset */
00531     PteOffset = Vpn - Vad->StartingVpn;
00532     PteOffset += Vad->FirstPrototypePte - Subsection->SubsectionBase;
00533 
00534     /* Again, we only support single-subsection segments */
00535     ASSERT(PteOffset < 0xF0000000);
00536     ASSERT(PteOffset < Subsection->PtesInSubsection);
00537 
00538     /* Return the subsection */
00539     return Subsection;
00540 }
00541 
00542 VOID
00543 NTAPI
00544 MiSegmentDelete(IN PSEGMENT Segment)
00545 {
00546     PCONTROL_AREA ControlArea;
00547     SEGMENT_FLAGS SegmentFlags;
00548     PSUBSECTION Subsection;
00549     PMMPTE PointerPte, LastPte, PteForProto;
00550     MMPTE TempPte;
00551     KIRQL OldIrql;
00552 
00553     /* Capture data */
00554     SegmentFlags = Segment->SegmentFlags;
00555     ControlArea = Segment->ControlArea;
00556 
00557     /* Make sure control area is on the right delete path */
00558     ASSERT(ControlArea->u.Flags.BeingDeleted == 1);
00559     ASSERT(ControlArea->WritableUserReferences == 0);
00560 
00561     /* These things are not supported yet */
00562     ASSERT(ControlArea->DereferenceList.Flink == NULL);
00563     ASSERT(!(ControlArea->u.Flags.Image) & !(ControlArea->u.Flags.File));
00564     ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
00565     ASSERT(ControlArea->u.Flags.Rom == 0);
00566 
00567     /* Get the subsection and PTEs for this segment */
00568     Subsection = (PSUBSECTION)(ControlArea + 1);
00569     PointerPte = Subsection->SubsectionBase;
00570     LastPte = PointerPte + Segment->NonExtendedPtes;
00571 
00572     /* Lock the PFN database */
00573     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00574 
00575     /* Check if the master PTE is invalid */
00576     PteForProto = MiAddressToPte(PointerPte);
00577     if (!PteForProto->u.Hard.Valid)
00578     {
00579         /* Fault it in */
00580         MiMakeSystemAddressValidPfn(PointerPte, OldIrql);
00581     }
00582 
00583     /* Loop all the segment PTEs */
00584     while (PointerPte < LastPte)
00585     {
00586         /* Check if it's time to switch master PTEs if we passed a PDE boundary */
00587         if (!((ULONG_PTR)PointerPte & (PD_SIZE - 1)) &&
00588             (PointerPte != Subsection->SubsectionBase))
00589         {
00590             /* Check if the master PTE is invalid */
00591             PteForProto = MiAddressToPte(PointerPte);
00592             if (!PteForProto->u.Hard.Valid)
00593             {
00594                 /* Fault it in */
00595                 MiMakeSystemAddressValidPfn(PointerPte, OldIrql);
00596             }
00597         }
00598 
00599         /* This should be a prototype PTE */
00600         TempPte = *PointerPte;
00601         ASSERT(SegmentFlags.LargePages == 0);
00602         ASSERT(TempPte.u.Hard.Valid == 0);
00603         ASSERT(TempPte.u.Soft.Prototype == 1);
00604 
00605         /* Zero the PTE and keep going */
00606         PointerPte->u.Long = 0;
00607         PointerPte++;
00608     }
00609 
00610     /* Release the PFN lock */
00611     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00612 
00613     /* Free the structures */
00614     ExFreePool(ControlArea);
00615     ExFreePool(Segment);
00616 }
00617 
00618 VOID
00619 NTAPI
00620 MiCheckControlArea(IN PCONTROL_AREA ControlArea,
00621                    IN KIRQL OldIrql)
00622 {
00623     BOOLEAN DeleteSegment = FALSE;
00624     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
00625 
00626     /* Check if this is the last reference or view */
00627     if (!(ControlArea->NumberOfMappedViews) &&
00628         !(ControlArea->NumberOfSectionReferences))
00629     {
00630         /* There should be no more user references either */
00631         ASSERT(ControlArea->NumberOfUserReferences == 0);
00632 
00633         /* Not yet supported */
00634         ASSERT(ControlArea->FilePointer == NULL);
00635 
00636         /* The control area is being destroyed */
00637         ControlArea->u.Flags.BeingDeleted = TRUE;
00638         DeleteSegment = TRUE;
00639     }
00640 
00641     /* Release the PFN lock */
00642     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00643 
00644     /* Delete the segment if needed */
00645     if (DeleteSegment)
00646     {
00647         /* No more user write references at all */
00648         ASSERT(ControlArea->WritableUserReferences == 0);
00649         MiSegmentDelete(ControlArea->Segment);
00650     }
00651 }
00652 
00653 VOID
00654 NTAPI
00655 MiRemoveMappedView(IN PEPROCESS CurrentProcess,
00656                    IN PMMVAD Vad)
00657 {
00658     KIRQL OldIrql;
00659     PCONTROL_AREA ControlArea;
00660 
00661     /* Get the control area */
00662     ControlArea = Vad->ControlArea;
00663 
00664     /* We only support non-extendable, non-image, pagefile-backed regular sections */
00665     ASSERT(Vad->u.VadFlags.VadType == VadNone);
00666     ASSERT(Vad->u2.VadFlags2.ExtendableFile == FALSE);
00667     ASSERT(ControlArea);
00668     ASSERT(ControlArea->FilePointer == NULL);
00669 
00670     /* Delete the actual virtual memory pages */
00671     MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT,
00672                              (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1),
00673                              Vad);
00674 
00675     /* Release the working set */
00676     MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
00677 
00678     /* Lock the PFN database */
00679     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00680 
00681     /* Remove references */
00682     ControlArea->NumberOfMappedViews--;
00683     ControlArea->NumberOfUserReferences--;
00684 
00685     /* Check if it should be destroyed */
00686     MiCheckControlArea(ControlArea, OldIrql);
00687 }
00688 
00689 NTSTATUS
00690 NTAPI
00691 MiUnmapViewOfSection(IN PEPROCESS Process,
00692                      IN PVOID BaseAddress,
00693                      IN ULONG Flags)
00694 {
00695     PMEMORY_AREA MemoryArea;
00696     BOOLEAN Attached = FALSE;
00697     KAPC_STATE ApcState;
00698     PMMVAD Vad;
00699     PVOID DbgBase = NULL;
00700     SIZE_T RegionSize;
00701     NTSTATUS Status;
00702     PAGED_CODE();
00703 
00704     /* Check for Mm Region */
00705     MemoryArea = MmLocateMemoryAreaByAddress(&Process->Vm, BaseAddress);
00706     if ((MemoryArea) && (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3))
00707     {
00708         /* Call Mm API */
00709         return MiRosUnmapViewOfSection(Process, BaseAddress, Flags);
00710     }
00711 
00712     /* Check if we should attach to the process */
00713     if (PsGetCurrentProcess() != Process)
00714     {
00715         /* The process is different, do an attach */
00716         KeStackAttachProcess(&Process->Pcb, &ApcState);
00717         Attached = TRUE;
00718     }
00719 
00720     /* Check if we need to lock the address space */
00721     if (!Flags) MmLockAddressSpace(&Process->Vm);
00722 
00723     /* Check if the process is already daed */
00724     if (Process->VmDeleted)
00725     {
00726         /* Fail the call */
00727         DPRINT1("Process died!\n");
00728         if (!Flags) MmUnlockAddressSpace(&Process->Vm);
00729         Status = STATUS_PROCESS_IS_TERMINATING;
00730         goto Quickie;
00731     }
00732 
00733     /* Find the VAD for the address and make sure it's a section VAD */
00734     Vad = MiLocateAddress(BaseAddress);
00735     if (!(Vad) || (Vad->u.VadFlags.PrivateMemory))
00736     {
00737         /* Couldn't find it, or invalid VAD, fail */
00738         DPRINT1("No VAD or invalid VAD\n");
00739         if (!Flags) MmUnlockAddressSpace(&Process->Vm);
00740         Status = STATUS_NOT_MAPPED_VIEW;
00741         goto Quickie;
00742     }
00743 
00744     /* We should be attached */
00745     ASSERT(Process == PsGetCurrentProcess());
00746 
00747     /* We need the base address for the debugger message on image-backed VADs */
00748     if (Vad->u.VadFlags.VadType == VadImageMap)
00749     {
00750         DbgBase = (PVOID)(Vad->StartingVpn >> PAGE_SHIFT);
00751     }
00752 
00753     /* Compute the size of the VAD region */
00754     RegionSize = PAGE_SIZE + ((Vad->EndingVpn - Vad->StartingVpn) << PAGE_SHIFT);
00755 
00756     /* For SEC_NO_CHANGE sections, we need some extra checks */
00757     if (Vad->u.VadFlags.NoChange == 1)
00758     {
00759         DPRINT1("Unmapping SEC_NO_CHANGE. Should validate if allowed!\n");
00760     }
00761 
00762     /* Not currently supported */
00763     ASSERT(Vad->u.VadFlags.VadType != VadRotatePhysical);
00764 
00765     /* FIXME: Remove VAD charges */
00766 
00767     /* Lock the working set */
00768     MiLockWorkingSet(PsGetCurrentThread(), &Process->Vm);
00769 
00770     /* Remove the VAD */
00771     ASSERT(Process->VadRoot.NumberGenericTableElements >= 1);
00772     MiRemoveNode((PMMADDRESS_NODE)Vad, &Process->VadRoot);
00773 
00774     /* Remove the PTEs for this view */
00775     MiRemoveMappedView(Process, Vad);
00776 
00777     /* FIXME: Remove commitment */
00778 
00779     /* Update performance counter and release the lock */
00780     Process->VirtualSize -= RegionSize;
00781     if (!Flags) MmUnlockAddressSpace(&Process->Vm);
00782 
00783     /* Destroy the VAD and return success */
00784     ExFreePool(Vad);
00785     Status = STATUS_SUCCESS;
00786 
00787     /* Failure and success case -- send debugger message, detach, and return */
00788 Quickie:
00789     if (DbgBase) DbgkUnMapViewOfSection(DbgBase);
00790     if (Attached) KeUnstackDetachProcess(&ApcState);
00791     return Status;
00792 }
00793 
00794 NTSTATUS
00795 NTAPI
00796 MiMapViewInSystemSpace(IN PVOID Section,
00797                        IN PMMSESSION Session,
00798                        OUT PVOID *MappedBase,
00799                        IN OUT PSIZE_T ViewSize)
00800 {
00801     PVOID Base;
00802     PCONTROL_AREA ControlArea;
00803     ULONG Buckets, SectionSize;
00804     NTSTATUS Status;
00805     PAGED_CODE();
00806 
00807     /* Only global mappings for now */
00808     ASSERT(Session == &MmSession);
00809 
00810     /* Get the control area, check for any flags ARM3 doesn't yet support */
00811     ControlArea = ((PSECTION)Section)->Segment->ControlArea;
00812     ASSERT(ControlArea->u.Flags.Image == 0);
00813     ASSERT(ControlArea->FilePointer == NULL);
00814     ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
00815     ASSERT(ControlArea->u.Flags.Rom == 0);
00816     ASSERT(ControlArea->u.Flags.WasPurged == 0);
00817 
00818     /* Increase the reference and map count on the control area, no purges yet */
00819     Status = MiCheckPurgeAndUpMapCount(ControlArea, FALSE);
00820     ASSERT(NT_SUCCESS(Status));
00821 
00822     /* Get the section size at creation time */
00823     SectionSize = ((PSECTION)Section)->SizeOfSection.LowPart;
00824 
00825     /* If the caller didn't specify a view size, assume the whole section */
00826     if (!(*ViewSize)) *ViewSize = SectionSize;
00827 
00828     /* Check if the caller wanted a larger section than the view */
00829     if (*ViewSize > SectionSize)
00830     {
00831         /* We should probably fail. FIXME TODO */
00832         ASSERT(FALSE);
00833     }
00834 
00835     /* Get the number of 64K buckets required for this mapping */
00836     Buckets = (ULONG)(*ViewSize / MI_SYSTEM_VIEW_BUCKET_SIZE);
00837     if (*ViewSize & (MI_SYSTEM_VIEW_BUCKET_SIZE - 1)) Buckets++;
00838 
00839     /* Check if the view is more than 4GB large */
00840     if (Buckets >= MI_SYSTEM_VIEW_BUCKET_SIZE)
00841     {
00842         /* We should probably fail */
00843         ASSERT(FALSE);
00844     }
00845 
00846     /* Insert this view into system space and get a base address for it */
00847     Base = MiInsertInSystemSpace(Session, Buckets, ControlArea);
00848     ASSERT(Base);
00849 
00850     /* Create the PDEs needed for this mapping, and double-map them if needed */
00851     MiFillSystemPageDirectory(Base, Buckets * MI_SYSTEM_VIEW_BUCKET_SIZE);
00852 
00853     /* Create the actual prototype PTEs for this mapping */
00854     Status = MiAddMappedPtes(MiAddressToPte(Base),
00855                              BYTES_TO_PAGES(*ViewSize),
00856                              ControlArea);
00857     ASSERT(NT_SUCCESS(Status));
00858 
00859     /* Return the base adress of the mapping and success */
00860     *MappedBase = Base;
00861     return STATUS_SUCCESS;
00862 }
00863 
00864 NTSTATUS
00865 NTAPI
00866 MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
00867                        IN PEPROCESS Process,
00868                        IN PVOID *BaseAddress,
00869                        IN PLARGE_INTEGER SectionOffset,
00870                        IN PSIZE_T ViewSize,
00871                        IN PSECTION Section,
00872                        IN SECTION_INHERIT InheritDisposition,
00873                        IN ULONG ProtectionMask,
00874                        IN SIZE_T CommitSize,
00875                        IN ULONG_PTR ZeroBits,
00876                        IN ULONG AllocationType)
00877 {
00878     PMMVAD_LONG Vad;
00879     PETHREAD Thread = PsGetCurrentThread();
00880     ULONG_PTR StartAddress, EndingAddress;
00881     PSUBSECTION Subsection;
00882     PSEGMENT Segment;
00883     PFN_NUMBER PteOffset;
00884     NTSTATUS Status;
00885     ULONG QuotaCharge = 0, QuotaExcess = 0;
00886     PMMPTE PointerPte, LastPte;
00887     MMPTE TempPte;
00888 
00889     /* Get the segment for this section */
00890     Segment = ControlArea->Segment;
00891 
00892     /* One can only reserve a file-based mapping, not shared memory! */
00893     if ((AllocationType & MEM_RESERVE) && !(ControlArea->FilePointer))
00894     {
00895         return STATUS_INVALID_PARAMETER_9;
00896     }
00897 
00898     /* This flag determines alignment, but ARM3 does not yet support it */
00899     ASSERT((AllocationType & MEM_DOS_LIM) == 0);
00900 
00901     /* First, increase the map count. No purging is supported yet */
00902     Status = MiCheckPurgeAndUpMapCount(ControlArea, FALSE);
00903     if (!NT_SUCCESS(Status)) return Status;
00904 
00905     /* Check if the caller specified the view size */
00906     if (!(*ViewSize))
00907     {
00908         /* The caller did not, so pick a 64K aligned view size based on the offset */
00909         SectionOffset->LowPart &= ~(_64K - 1);
00910         *ViewSize = (SIZE_T)(Section->SizeOfSection.QuadPart - SectionOffset->QuadPart);
00911     }
00912     else
00913     {
00914         /* A size was specified, align it to a 64K boundary */
00915         *ViewSize += SectionOffset->LowPart & (_64K - 1);
00916 
00917         /* Align the offset as well to make this an aligned map */
00918         SectionOffset->LowPart &= ~((ULONG)_64K - 1);
00919     }
00920 
00921     /* We must be dealing with a 64KB aligned offset. This is a Windows ASSERT */
00922     ASSERT((SectionOffset->LowPart & ((ULONG)_64K - 1)) == 0);
00923 
00924     /* It's illegal to try to map more than 2GB */
00925     /* FIXME: Should dereference the control area */
00926     if (*ViewSize >= 0x80000000) return STATUS_INVALID_VIEW_SIZE;
00927 
00928     /* Windows ASSERTs for this flag */
00929     ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
00930 
00931     /* Get the subsection. We don't support LARGE_CONTROL_AREA in ARM3 */
00932     ASSERT(ControlArea->u.Flags.Rom == 0);
00933     Subsection = (PSUBSECTION)(ControlArea + 1);
00934 
00935     /* Sections with extended segments are not supported in ARM3 */
00936     ASSERT(Segment->SegmentFlags.TotalNumberOfPtes4132 == 0);
00937 
00938     /* Within this section, figure out which PTEs will describe the view */
00939     PteOffset = (PFN_NUMBER)(SectionOffset->QuadPart >> PAGE_SHIFT);
00940 
00941     /* The offset must be in this segment's PTE chunk and it must be valid. Windows ASSERTs */
00942     ASSERT(PteOffset < Segment->TotalNumberOfPtes);
00943     ASSERT(((SectionOffset->QuadPart + *ViewSize + PAGE_SIZE - 1) >> PAGE_SHIFT) >= PteOffset);
00944 
00945     /* In ARM3, only one subsection is used for now. It must contain these PTEs */
00946     ASSERT(PteOffset < Subsection->PtesInSubsection);
00947 
00948     /* In ARM3, only page-file backed sections (shared memory) are supported now */
00949     ASSERT(ControlArea->FilePointer == NULL);
00950 
00951     /* Windows ASSERTs for this too -- there must be a subsection base address */
00952     ASSERT(Subsection->SubsectionBase != NULL);
00953 
00954     /* Compute how much commit space the segment will take */
00955     if ((CommitSize) && (Segment->NumberOfCommittedPages < Segment->TotalNumberOfPtes))
00956     {
00957         PointerPte = &Subsection->SubsectionBase[PteOffset];
00958         LastPte = PointerPte + BYTES_TO_PAGES(CommitSize);
00959         QuotaCharge = (ULONG)(LastPte - PointerPte);
00960     }
00961 
00962     /* ARM3 does not currently support large pages */
00963     ASSERT(Segment->SegmentFlags.LargePages == 0);
00964 
00965     /* Did the caller specify an address? */
00966     if (!(*BaseAddress) && !(Section->Address.StartingVpn))
00967     {
00968         /* ARM3 does not support these flags yet */
00969         ASSERT(Process->VmTopDown == 0);
00970         ASSERT(ZeroBits == 0);
00971 
00972         /* Which way should we search? */
00973         if (AllocationType & MEM_TOP_DOWN)
00974         {
00975             /* No, find an address top-down */
00976             Status = MiFindEmptyAddressRangeDownTree(*ViewSize,
00977                                                      (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS,
00978                                                      _64K,
00979                                                      &Process->VadRoot,
00980                                                      &StartAddress,
00981                                                      (PMMADDRESS_NODE*)&Process->VadFreeHint);
00982             ASSERT(NT_SUCCESS(Status));
00983         }
00984         else
00985         {
00986             /* No, find an address bottom-up */
00987             Status = MiFindEmptyAddressRangeInTree(*ViewSize,
00988                                                    _64K,
00989                                                    &Process->VadRoot,
00990                                                    (PMMADDRESS_NODE*)&Process->VadFreeHint,
00991                                                    &StartAddress);
00992             ASSERT(NT_SUCCESS(Status));
00993         }
00994 
00995         /* Get the ending address, which is the last piece we need for the VAD */
00996         EndingAddress = (StartAddress + *ViewSize - 1) | (PAGE_SIZE - 1);
00997     }
00998     else
00999     {
01000         /* Is it SEC_BASED, or did the caller manually specify an address? */
01001         if (!(*BaseAddress))
01002         {
01003             /* It is a SEC_BASED mapping, use the address that was generated */
01004             StartAddress = Section->Address.StartingVpn + SectionOffset->LowPart;
01005             DPRINT("BASED: 0x%p\n", StartAddress);
01006         }
01007         else
01008         {
01009             /* Just align what the caller gave us */
01010             StartAddress = ROUND_UP((ULONG_PTR)*BaseAddress, _64K);
01011         }
01012 
01013         /* Get the ending address, which is the last piece we need for the VAD */
01014         EndingAddress = (StartAddress + *ViewSize - 1) | (PAGE_SIZE - 1);
01015 
01016         /* Make sure it doesn't conflict with an existing allocation */
01017         if (MiCheckForConflictingNode(StartAddress >> PAGE_SHIFT,
01018                                       EndingAddress >> PAGE_SHIFT,
01019                                       &Process->VadRoot))
01020         {
01021             DPRINT1("Conflict with SEC_BASED or manually based section!\n");
01022             return STATUS_CONFLICTING_ADDRESSES; // FIXME: CA Leak
01023         }
01024     }
01025 
01026     /* A VAD can now be allocated. Do so and zero it out */
01027     /* FIXME: we are allocating a LONG VAD for ReactOS compatibility only */
01028     ASSERT((AllocationType & MEM_RESERVE) == 0); /* ARM3 does not support this */
01029     Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV');
01030     if (!Vad) return STATUS_INSUFFICIENT_RESOURCES; /* FIXME: CA Leak */
01031     RtlZeroMemory(Vad, sizeof(MMVAD_LONG));
01032     Vad->u4.Banked = (PVOID)0xDEADBABE;
01033 
01034     /* Write all the data required in the VAD for handling a fault */
01035     Vad->StartingVpn = StartAddress >> PAGE_SHIFT;
01036     Vad->EndingVpn = EndingAddress >> PAGE_SHIFT;
01037     Vad->ControlArea = ControlArea;
01038     Vad->u.VadFlags.Protection = ProtectionMask;
01039     Vad->u2.VadFlags2.FileOffset = (ULONG)(SectionOffset->QuadPart >> 16);
01040     Vad->u2.VadFlags2.Inherit = (InheritDisposition == ViewShare);
01041     if ((AllocationType & SEC_NO_CHANGE) || (Section->u.Flags.NoChange))
01042     {
01043         /* This isn't really implemented yet, but handle setting the flag */
01044         Vad->u.VadFlags.NoChange = 1;
01045         Vad->u2.VadFlags2.SecNoChange = 1;
01046     }
01047 
01048     /* Finally, write down the first and last prototype PTE */
01049     Vad->FirstPrototypePte = &Subsection->SubsectionBase[PteOffset];
01050     PteOffset += (Vad->EndingVpn - Vad->StartingVpn);
01051     ASSERT(PteOffset < Subsection->PtesInSubsection);
01052     Vad->LastContiguousPte = &Subsection->SubsectionBase[PteOffset];
01053 
01054     /* Make sure the prototype PTE ranges make sense, this is a Windows ASSERT */
01055     ASSERT(Vad->FirstPrototypePte <= Vad->LastContiguousPte);
01056 
01057     /* FIXME: Should setup VAD bitmap */
01058     Status = STATUS_SUCCESS;
01059 
01060     /* Pretend as if we own the working set */
01061     MiLockProcessWorkingSet(Process, Thread);
01062 
01063     /* Insert the VAD */
01064     MiInsertVad((PMMVAD)Vad, Process);
01065 
01066     /* Release the working set */
01067     MiUnlockProcessWorkingSet(Process, Thread);
01068 
01069     /* Windows stores this for accounting purposes, do so as well */
01070     if (!Segment->u2.FirstMappedVa) Segment->u2.FirstMappedVa = (PVOID)StartAddress;
01071 
01072     /* Check if anything was committed */
01073     if (QuotaCharge)
01074     {
01075         /* Set the start and end PTE addresses, and pick the template PTE */
01076         PointerPte = Vad->FirstPrototypePte;
01077         LastPte = PointerPte + BYTES_TO_PAGES(CommitSize);
01078         TempPte = Segment->SegmentPteTemplate;
01079 
01080         /* Acquire the commit lock and loop all prototype PTEs to be committed */
01081         KeAcquireGuardedMutexUnsafe(&MmSectionCommitMutex);
01082         while (PointerPte < LastPte)
01083         {
01084             /* Make sure the PTE is already invalid */
01085             if (PointerPte->u.Long == 0)
01086             {
01087                 /* And write the invalid PTE */
01088                 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
01089             }
01090             else
01091             {
01092                 /* The PTE is valid, so skip it */
01093                 QuotaExcess++;
01094             }
01095 
01096             /* Move to the next PTE */
01097             PointerPte++;
01098         }
01099 
01100         /* Now check how many pages exactly we committed, and update accounting */
01101         ASSERT(QuotaCharge >= QuotaExcess);
01102         QuotaCharge -= QuotaExcess;
01103         Segment->NumberOfCommittedPages += QuotaCharge;
01104         ASSERT(Segment->NumberOfCommittedPages <= Segment->TotalNumberOfPtes);
01105 
01106         /* Now that we're done, release the lock */
01107         KeReleaseGuardedMutexUnsafe(&MmSectionCommitMutex);
01108     }
01109 
01110     /* Finally, let the caller know where, and for what size, the view was mapped */
01111     *ViewSize = (ULONG_PTR)EndingAddress - (ULONG_PTR)StartAddress + 1;
01112     *BaseAddress = (PVOID)StartAddress;
01113     DPRINT("Start and region: 0x%p, 0x%p\n", *BaseAddress, *ViewSize);
01114     return STATUS_SUCCESS;
01115 }
01116 
01117 NTSTATUS
01118 NTAPI
01119 MiCreatePagingFileMap(OUT PSEGMENT *Segment,
01120                       IN PSIZE_T MaximumSize,
01121                       IN ULONG ProtectionMask,
01122                       IN ULONG AllocationAttributes)
01123 {
01124     SIZE_T SizeLimit;
01125     PFN_COUNT PteCount;
01126     PMMPTE PointerPte;
01127     MMPTE TempPte;
01128     PCONTROL_AREA ControlArea;
01129     PSEGMENT NewSegment;
01130     PSUBSECTION Subsection;
01131     PAGED_CODE();
01132 
01133     /* No large pages in ARM3 yet */
01134     ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0);
01135 
01136     /* Pagefile-backed sections need a known size */
01137     if (!(*MaximumSize)) return STATUS_INVALID_PARAMETER_4;
01138 
01139     /* Calculate the maximum size possible, given the Prototype PTEs we'll need */
01140     SizeLimit = MAXULONG_PTR - sizeof(SEGMENT);
01141     SizeLimit /= sizeof(MMPTE);
01142     SizeLimit <<= PAGE_SHIFT;
01143 
01144     /* Fail if this size is too big */
01145     if (*MaximumSize > SizeLimit) return STATUS_SECTION_TOO_BIG;
01146 
01147     /* Calculate how many Prototype PTEs will be needed */
01148     PteCount = (PFN_COUNT)((*MaximumSize + PAGE_SIZE - 1) >> PAGE_SHIFT);
01149 
01150     /* For commited memory, we must have a valid protection mask */
01151     if (AllocationAttributes & SEC_COMMIT) ASSERT(ProtectionMask != 0);
01152 
01153     /* The segment contains all the Prototype PTEs, allocate it in paged pool */
01154     NewSegment = ExAllocatePoolWithTag(PagedPool,
01155                                        sizeof(SEGMENT) +
01156                                        sizeof(MMPTE) * (PteCount - 1),
01157                                        'tSmM');
01158     ASSERT(NewSegment);
01159     *Segment = NewSegment;
01160 
01161     /* Now allocate the control area, which has the subsection structure */
01162     ControlArea = ExAllocatePoolWithTag(NonPagedPool,
01163                                         sizeof(CONTROL_AREA) + sizeof(SUBSECTION),
01164                                         'tCmM');
01165     ASSERT(ControlArea);
01166 
01167     /* And zero it out, filling the basic segmnet pointer and reference fields */
01168     RtlZeroMemory(ControlArea, sizeof(CONTROL_AREA) + sizeof(SUBSECTION));
01169     ControlArea->Segment = NewSegment;
01170     ControlArea->NumberOfSectionReferences = 1;
01171     ControlArea->NumberOfUserReferences = 1;
01172 
01173     /* Convert allocation attributes to control area flags */
01174     if (AllocationAttributes & SEC_BASED) ControlArea->u.Flags.Based = 1;
01175     if (AllocationAttributes & SEC_RESERVE) ControlArea->u.Flags.Reserve = 1;
01176     if (AllocationAttributes & SEC_COMMIT) ControlArea->u.Flags.Commit = 1;
01177 
01178     /* The subsection follows, write the mask, PTE count and point back to the CA */
01179     Subsection = (PSUBSECTION)(ControlArea + 1);
01180     Subsection->ControlArea = ControlArea;
01181     Subsection->PtesInSubsection = PteCount;
01182     Subsection->u.SubsectionFlags.Protection = ProtectionMask;
01183 
01184     /* Zero out the segment's prototype PTEs, and link it with the control area */
01185     PointerPte = &NewSegment->ThePtes[0];
01186     RtlZeroMemory(NewSegment, sizeof(SEGMENT));
01187     NewSegment->PrototypePte = PointerPte;
01188     NewSegment->ControlArea = ControlArea;
01189 
01190     /* Save some extra accounting data for the segment as well */
01191     NewSegment->u1.CreatingProcess = PsGetCurrentProcess();
01192     NewSegment->SizeOfSegment = PteCount * PAGE_SIZE;
01193     NewSegment->TotalNumberOfPtes = PteCount;
01194     NewSegment->NonExtendedPtes = PteCount;
01195 
01196     /* The subsection's base address is the first Prototype PTE in the segment */
01197     Subsection->SubsectionBase = PointerPte;
01198 
01199     /* Start with an empty PTE, unless this is a commit operation */
01200     TempPte.u.Long = 0;
01201     if (AllocationAttributes & SEC_COMMIT)
01202     {
01203         /* In which case, write down the protection mask in the Prototype PTEs */
01204         TempPte.u.Soft.Protection = ProtectionMask;
01205 
01206         /* For accounting, also mark these pages as being committed */
01207         NewSegment->NumberOfCommittedPages = PteCount;
01208     }
01209 
01210     /* The template PTE itself for the segment should also have the mask set */
01211     NewSegment->SegmentPteTemplate.u.Soft.Protection = ProtectionMask;
01212 
01213     /* Write out the prototype PTEs, for now they're simply demand zero */
01214 #ifdef _WIN64
01215     RtlFillMemoryUlonglong(PointerPte, PteCount * sizeof(MMPTE), TempPte.u.Long);
01216 #else
01217     RtlFillMemoryUlong(PointerPte, PteCount * sizeof(MMPTE), TempPte.u.Long);
01218 #endif
01219     return STATUS_SUCCESS;
01220 }
01221 
01222 PFILE_OBJECT
01223 NTAPI
01224 MmGetFileObjectForSection(IN PVOID SectionObject)
01225 {
01226     PSECTION_OBJECT Section;
01227     ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
01228     ASSERT(SectionObject != NULL);
01229 
01230     /* Check if it's an ARM3, or ReactOS section */
01231     if (MiIsRosSectionObject(SectionObject) == FALSE)
01232     {
01233         /* Return the file pointer stored in the control area */
01234         Section = SectionObject;
01235         return Section->Segment->ControlArea->FilePointer;
01236     }
01237 
01238     /* Return the file object */
01239     return ((PROS_SECTION_OBJECT)SectionObject)->FileObject;
01240 }
01241 
01242 NTSTATUS
01243 NTAPI
01244 MmGetFileNameForFileObject(IN PFILE_OBJECT FileObject,
01245                            OUT POBJECT_NAME_INFORMATION *ModuleName)
01246 {
01247     POBJECT_NAME_INFORMATION ObjectNameInfo;
01248     NTSTATUS Status;
01249     ULONG ReturnLength;
01250 
01251     /* Allocate memory for our structure */
01252     ObjectNameInfo = ExAllocatePoolWithTag(PagedPool, 1024, TAG_MM);
01253     if (!ObjectNameInfo) return STATUS_NO_MEMORY;
01254 
01255     /* Query the name */
01256     Status = ObQueryNameString(FileObject,
01257                                ObjectNameInfo,
01258                                1024,
01259                                &ReturnLength);
01260     if (!NT_SUCCESS(Status))
01261     {
01262         /* Failed, free memory */
01263         DPRINT1("Name query failed\n");
01264         ExFreePoolWithTag(ObjectNameInfo, TAG_MM);
01265         *ModuleName = NULL;
01266         return Status;
01267     }
01268 
01269     /* Success */
01270     *ModuleName = ObjectNameInfo;
01271     return STATUS_SUCCESS;
01272 }
01273 
01274 NTSTATUS
01275 NTAPI
01276 MmGetFileNameForSection(IN PVOID Section,
01277                         OUT POBJECT_NAME_INFORMATION *ModuleName)
01278 {
01279     PFILE_OBJECT FileObject;
01280 
01281     /* Make sure it's an image section */
01282     if (MiIsRosSectionObject(Section) == FALSE)
01283     {
01284         /* Check ARM3 Section flag */
01285         if (((PSECTION)Section)->u.Flags.Image == 0)
01286         {
01287             /* It's not, fail */
01288             DPRINT1("Not an image section\n");
01289             return STATUS_SECTION_NOT_IMAGE;
01290         }
01291     }
01292     else if (!(((PROS_SECTION_OBJECT)Section)->AllocationAttributes & SEC_IMAGE))
01293     {
01294         /* It's not, fail */
01295         DPRINT1("Not an image section\n");
01296         return STATUS_SECTION_NOT_IMAGE;
01297     }
01298 
01299     /* Get the file object */
01300     FileObject = MmGetFileObjectForSection(Section);
01301     return MmGetFileNameForFileObject(FileObject, ModuleName);
01302 }
01303 
01304 NTSTATUS
01305 NTAPI
01306 MmGetFileNameForAddress(IN PVOID Address,
01307                         OUT PUNICODE_STRING ModuleName)
01308 {
01309    PVOID Section;
01310    PMEMORY_AREA MemoryArea;
01311    POBJECT_NAME_INFORMATION ModuleNameInformation;
01312    PVOID AddressSpace;
01313    NTSTATUS Status;
01314    PFILE_OBJECT FileObject = NULL;
01315    PMMVAD Vad;
01316    PCONTROL_AREA ControlArea;
01317 
01318    /* Lock address space */
01319    AddressSpace = MmGetCurrentAddressSpace();
01320    MmLockAddressSpace(AddressSpace);
01321 
01322    /* Locate the memory area for the process by address */
01323    MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
01324    if (!MemoryArea)
01325    {
01326        /* Fail, the address does not exist */
01327 InvalidAddress:
01328        DPRINT1("Invalid address\n");
01329        MmUnlockAddressSpace(AddressSpace);
01330        return STATUS_INVALID_ADDRESS;
01331    }
01332 
01333    /* Check if it's a section view (RosMm section) or ARM3 section */
01334    if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
01335    {
01336       /* Get the section pointer to the SECTION_OBJECT */
01337       Section = MemoryArea->Data.SectionData.Section;
01338 
01339       /* Unlock address space */
01340       MmUnlockAddressSpace(AddressSpace);
01341 
01342       /* Get the filename of the section */
01343       Status = MmGetFileNameForSection(Section, &ModuleNameInformation);
01344    }
01345    else if (MemoryArea->Type == MEMORY_AREA_OWNED_BY_ARM3)
01346    {
01347        /* Get the VAD */
01348        Vad = MiLocateAddress(Address);
01349        if (!Vad) goto InvalidAddress;
01350 
01351        /* Make sure it's not a VM VAD */
01352        if (Vad->u.VadFlags.PrivateMemory == 1)
01353        {
01354 NotSection:
01355            DPRINT1("Address is not a section\n");
01356            MmUnlockAddressSpace(AddressSpace);
01357            return STATUS_SECTION_NOT_IMAGE;
01358        }
01359 
01360        /* Get the control area */
01361        ControlArea = Vad->ControlArea;
01362        if (!(ControlArea) || !(ControlArea->u.Flags.Image)) goto NotSection;
01363 
01364        /* Get the file object */
01365        FileObject = ControlArea->FilePointer;
01366        ASSERT(FileObject != NULL);
01367        ObReferenceObject(FileObject);
01368 
01369        /* Unlock address space */
01370        MmUnlockAddressSpace(AddressSpace);
01371 
01372        /* Get the filename of the file object */
01373        Status = MmGetFileNameForFileObject(FileObject, &ModuleNameInformation);
01374 
01375        /* Dereference it */
01376        ObDereferenceObject(FileObject);
01377    }
01378    else
01379    {
01380        /* Trying to access virtual memory or something */
01381        goto InvalidAddress;
01382    }
01383 
01384    /* Check if we were able to get the file object name */
01385    if (NT_SUCCESS(Status))
01386    {
01387         /* Init modulename */
01388        RtlCreateUnicodeString(ModuleName,
01389                               ModuleNameInformation->Name.Buffer);
01390 
01391        /* Free temp taged buffer from MmGetFileNameForFileObject() */
01392        ExFreePoolWithTag(ModuleNameInformation, TAG_MM);
01393        DPRINT("Found ModuleName %S by address %p\n", ModuleName->Buffer, Address);
01394    }
01395 
01396    /* Return status */
01397    return Status;
01398 }
01399 
01400 NTSTATUS
01401 NTAPI
01402 MiQueryMemorySectionName(IN HANDLE ProcessHandle,
01403                          IN PVOID BaseAddress,
01404                          OUT PVOID MemoryInformation,
01405                          IN SIZE_T MemoryInformationLength,
01406                          OUT PSIZE_T ReturnLength)
01407 {
01408     PEPROCESS Process;
01409     NTSTATUS Status;
01410     WCHAR ModuleFileNameBuffer[MAX_PATH] = {0};
01411     UNICODE_STRING ModuleFileName;
01412     PMEMORY_SECTION_NAME SectionName = NULL;
01413     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
01414 
01415     Status = ObReferenceObjectByHandle(ProcessHandle,
01416                                        PROCESS_QUERY_INFORMATION,
01417                                        NULL,
01418                                        PreviousMode,
01419                                        (PVOID*)(&Process),
01420                                        NULL);
01421 
01422     if (!NT_SUCCESS(Status))
01423     {
01424         DPRINT("MiQueryMemorySectionName: ObReferenceObjectByHandle returned %x\n",Status);
01425         return Status;
01426     }
01427 
01428     RtlInitEmptyUnicodeString(&ModuleFileName, ModuleFileNameBuffer, sizeof(ModuleFileNameBuffer));
01429     Status = MmGetFileNameForAddress(BaseAddress, &ModuleFileName);
01430 
01431     if (NT_SUCCESS(Status))
01432     {
01433         SectionName = MemoryInformation;
01434         if (PreviousMode != KernelMode)
01435         {
01436             _SEH2_TRY
01437             {
01438                 RtlInitUnicodeString(&SectionName->SectionFileName, SectionName->NameBuffer);
01439                 SectionName->SectionFileName.MaximumLength = (USHORT)MemoryInformationLength;
01440                 RtlCopyUnicodeString(&SectionName->SectionFileName, &ModuleFileName);
01441 
01442                 if (ReturnLength) *ReturnLength = ModuleFileName.Length;
01443 
01444             }
01445             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01446             {
01447                 Status = _SEH2_GetExceptionCode();
01448             }
01449             _SEH2_END;
01450         }
01451         else
01452         {
01453             RtlInitUnicodeString(&SectionName->SectionFileName, SectionName->NameBuffer);
01454             SectionName->SectionFileName.MaximumLength = (USHORT)MemoryInformationLength;
01455             RtlCopyUnicodeString(&SectionName->SectionFileName, &ModuleFileName);
01456 
01457             if (ReturnLength) *ReturnLength = ModuleFileName.Length;
01458 
01459         }
01460     }
01461     ObDereferenceObject(Process);
01462     return Status;
01463 }
01464 
01465 VOID
01466 NTAPI
01467 MiFlushTbAndCapture(IN PMMVAD FoundVad,
01468                     IN PMMPTE PointerPte,
01469                     IN ULONG ProtectionMask,
01470                     IN PMMPFN Pfn1,
01471                     IN BOOLEAN CaptureDirtyBit)
01472 {
01473     MMPTE TempPte, PreviousPte;
01474     KIRQL OldIrql;
01475 
01476     //
01477     // User for sanity checking later on
01478     //
01479     PreviousPte = *PointerPte;
01480 
01481     //
01482     // Build the PTE and acquire the PFN lock
01483     //
01484     MI_MAKE_HARDWARE_PTE_USER(&TempPte,
01485                               PointerPte,
01486                               ProtectionMask,
01487                               PreviousPte.u.Hard.PageFrameNumber);
01488     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
01489 
01490     //
01491     // We don't support I/O mappings in this path yet, and only cached memory
01492     //
01493     ASSERT(Pfn1 != NULL);
01494     ASSERT(Pfn1->u3.e1.CacheAttribute == MiCached);
01495     ASSERT((ProtectionMask & (MM_NOCACHE | MM_NOACCESS)) == 0);
01496 
01497     //
01498     // Write the new PTE, making sure we are only changing the bits
01499     //
01500     ASSERT(PointerPte->u.Hard.Valid == 1);
01501     ASSERT(TempPte.u.Hard.Valid == 1);
01502     ASSERT(PointerPte->u.Hard.PageFrameNumber == TempPte.u.Hard.PageFrameNumber);
01503     *PointerPte = TempPte;
01504 
01505     //
01506     // Flush the TLB
01507     //
01508     ASSERT(PreviousPte.u.Hard.Valid == 1);
01509     KeFlushCurrentTb();
01510     ASSERT(PreviousPte.u.Hard.Valid == 1);
01511 
01512     //
01513     // Windows updates the relevant PFN1 information, we currently don't.
01514     //
01515     if (CaptureDirtyBit) DPRINT1("Warning, not handling dirty bit\n");
01516 
01517     //
01518     // Not supported in ARM3
01519     //
01520     ASSERT(FoundVad->u.VadFlags.VadType != VadWriteWatch);
01521 
01522     //
01523     // Release the PFN lock, we are done
01524     //
01525     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01526 }
01527 
01528 //
01529 // NOTE: This function gets a lot more complicated if we want Copy-on-Write support
01530 //
01531 NTSTATUS
01532 NTAPI
01533 MiSetProtectionOnSection(IN PEPROCESS Process,
01534                          IN PMMVAD FoundVad,
01535                          IN PVOID StartingAddress,
01536                          IN PVOID EndingAddress,
01537                          IN ULONG NewProtect,
01538                          OUT PULONG CapturedOldProtect,
01539                          IN ULONG DontCharge,
01540                          OUT PULONG Locked)
01541 {
01542     PMMPTE PointerPte, LastPte;
01543     MMPTE TempPte, PteContents;
01544     PMMPDE PointerPde;
01545     PMMPFN Pfn1;
01546     ULONG ProtectionMask, QuotaCharge = 0;
01547     PUSHORT UsedPageTableEntries;
01548     //PETHREAD Thread = PsGetCurrentThread();
01549     PAGED_CODE();
01550 
01551     //
01552     // Tell caller nothing is being locked
01553     //
01554     *Locked = FALSE;
01555 
01556     //
01557     // This function should only be used for section VADs. Windows ASSERT */
01558     //
01559     ASSERT(FoundVad->u.VadFlags.PrivateMemory == 0);
01560 
01561     //
01562     // We don't support these features in ARM3
01563     //
01564     ASSERT(FoundVad->u.VadFlags.VadType != VadImageMap);
01565     ASSERT(FoundVad->u2.VadFlags2.CopyOnWrite == 0);
01566 
01567     //
01568     // Convert and validate the protection mask
01569     //
01570     ProtectionMask = MiMakeProtectionMask(NewProtect);
01571     if (ProtectionMask == MM_INVALID_PROTECTION)
01572     {
01573         DPRINT1("Invalid section protect\n");
01574         return STATUS_INVALID_PAGE_PROTECTION;
01575     }
01576 
01577     //
01578     // Get the PTE and PDE for the address, as well as the final PTE
01579     //
01580     //MiLockProcessWorkingSet(Thread, Process);
01581     PointerPde = MiAddressToPde(StartingAddress);
01582     PointerPte = MiAddressToPte(StartingAddress);
01583     LastPte = MiAddressToPte(EndingAddress);
01584 
01585     //
01586     // Make the PDE valid, and check the status of the first PTE
01587     //
01588     MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL);
01589     if (PointerPte->u.Long)
01590     {
01591         //
01592         // Not supported in ARM3
01593         //
01594         ASSERT(FoundVad->u.VadFlags.VadType != VadRotatePhysical);
01595 
01596         //
01597         // Capture the page protection and make the PDE valid
01598         //
01599         *CapturedOldProtect = MiGetPageProtection(PointerPte);
01600         MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL);
01601     }
01602     else
01603     {
01604         //
01605         // Only pagefile-backed section VADs are supported for now
01606         //
01607         ASSERT(FoundVad->u.VadFlags.VadType != VadImageMap);
01608 
01609         //
01610         // Grab the old protection from the VAD itself
01611         //
01612         *CapturedOldProtect = MmProtectToValue[FoundVad->u.VadFlags.Protection];
01613     }
01614 
01615     //
01616     // Loop all the PTEs now
01617     //
01618     MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL);
01619     while (PointerPte <= LastPte)
01620     {
01621         //
01622         // Check if we've crossed a PDE boundary and make the new PDE valid too
01623         //
01624         if ((((ULONG_PTR)PointerPte) & (SYSTEM_PD_SIZE - 1)) == 0)
01625         {
01626             PointerPde = MiAddressToPte(PointerPte);
01627             MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL);
01628         }
01629 
01630         //
01631         // Capture the PTE and see what we're dealing with
01632         //
01633         PteContents = *PointerPte;
01634         if (PteContents.u.Long == 0)
01635         {
01636             //
01637             // This used to be a zero PTE and it no longer is, so we must add a
01638             // reference to the pagetable.
01639             //
01640             UsedPageTableEntries = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(MiPteToAddress(PointerPte))];
01641             (*UsedPageTableEntries)++;
01642             ASSERT((*UsedPageTableEntries) <= PTE_COUNT);
01643 
01644             //
01645             // Create the demand-zero prototype PTE
01646             //
01647             TempPte = PrototypePte;
01648             TempPte.u.Soft.Protection = ProtectionMask;
01649             MI_WRITE_INVALID_PTE(PointerPte, TempPte);
01650         }
01651         else if (PteContents.u.Hard.Valid == 1)
01652         {
01653             //
01654             // Get the PFN entry
01655             //
01656             Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents));
01657 
01658             //
01659             // We don't support these yet
01660             //
01661             ASSERT((NewProtect & (PAGE_NOACCESS | PAGE_GUARD)) == 0);
01662             ASSERT(Pfn1->u3.e1.PrototypePte == 0);
01663 
01664             //
01665             // Write the protection mask and write it with a TLB flush
01666             //
01667             Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
01668             MiFlushTbAndCapture(FoundVad,
01669                                 PointerPte,
01670                                 ProtectionMask,
01671                                 Pfn1,
01672                                 TRUE);
01673         }
01674         else
01675         {
01676             //
01677             // We don't support these cases yet
01678             //
01679             ASSERT(PteContents.u.Soft.Prototype == 0);
01680             ASSERT(PteContents.u.Soft.Transition == 0);
01681 
01682             //
01683             // The PTE is already demand-zero, just update the protection mask
01684             //
01685             PointerPte->u.Soft.Protection = ProtectionMask;
01686         }
01687 
01688         PointerPte++;
01689     }
01690 
01691     //
01692     // Unlock the working set and update quota charges if needed, then return
01693     //
01694     //MiUnlockProcessWorkingSet(Thread, Process);
01695     if ((QuotaCharge > 0) && (!DontCharge))
01696     {
01697         FoundVad->u.VadFlags.CommitCharge -= QuotaCharge;
01698         Process->CommitCharge -= QuotaCharge;
01699     }
01700     return STATUS_SUCCESS;
01701 }
01702 
01703 VOID
01704 NTAPI
01705 MiRemoveMappedPtes(IN PVOID BaseAddress,
01706                    IN ULONG NumberOfPtes,
01707                    IN PCONTROL_AREA ControlArea,
01708                    IN PMMSUPPORT Ws)
01709 {
01710     PMMPTE PointerPte, FirstPte;
01711     PMMPDE PointerPde, SystemMapPde;
01712     PMMPFN Pfn1, Pfn2;
01713     MMPTE PteContents;
01714     KIRQL OldIrql;
01715     DPRINT("Removing mapped view at: 0x%p\n", BaseAddress);
01716 
01717     /* Get the PTE and loop each one */
01718     PointerPte = MiAddressToPte(BaseAddress);
01719     FirstPte = PointerPte;
01720     while (NumberOfPtes)
01721     {
01722         /* Check if the PTE is already valid */
01723         PteContents = *PointerPte;
01724         if (PteContents.u.Hard.Valid == 1)
01725         {
01726             /* Get the PFN entry */
01727             Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents));
01728 
01729             /* Get the PTE */
01730             PointerPde = MiAddressToPte(PointerPte);
01731 
01732             /* Lock the PFN database and make sure this isn't a mapped file */
01733             OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
01734             ASSERT(((Pfn1->u3.e1.PrototypePte) && (Pfn1->OriginalPte.u.Soft.Prototype)) == 0);
01735 
01736             /* FIXME: Dirty bit management */
01737 
01738             /* Was the PDE invalid */
01739             if (PointerPde->u.Long == 0)
01740             {
01741 #if (_MI_PAGING_LEVELS == 2)
01742                 /* Find the system double-mapped PDE that describes this mapping */
01743                 SystemMapPde = &MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)];
01744 
01745                 /* Make it valid */
01746                 ASSERT(SystemMapPde->u.Hard.Valid == 1);
01747                 MI_WRITE_VALID_PDE(PointerPde, *SystemMapPde);
01748 #else
01749                 ASSERT(FALSE);
01750 #endif
01751             }
01752 
01753             /* Dereference the PDE and the PTE */
01754             Pfn2 = MiGetPfnEntry(PFN_FROM_PTE(PointerPde));
01755             //MiDecrementShareCount(Pfn2, PFN_FROM_PTE(PointerPde));
01756             MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&PteContents));
01757 
01758             /* Release the PFN lock */
01759             KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01760         }
01761         else
01762         {
01763             /* Windows ASSERT */
01764             ASSERT((PteContents.u.Long == 0) || (PteContents.u.Soft.Prototype == 1));
01765 
01766             /* But not handled in ARM3 */
01767             ASSERT(PteContents.u.Soft.Prototype == 0);
01768         }
01769 
01770         /* Make the PTE into a zero PTE */
01771         PointerPte->u.Long = 0;
01772 
01773         /* Move to the next PTE */
01774         PointerPte++;
01775         NumberOfPtes--;
01776     }
01777 
01778     /* Flush the TLB */
01779     KeFlushCurrentTb();
01780 
01781     /* Acquire the PFN lock */
01782     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
01783 
01784     /* Decrement the accounting counters */
01785     ControlArea->NumberOfUserReferences--;
01786     ControlArea->NumberOfMappedViews--;
01787 
01788     /* Check if we should destroy the CA and release the lock */
01789     MiCheckControlArea(ControlArea, OldIrql);
01790 }
01791 
01792 ULONG
01793 NTAPI
01794 MiRemoveFromSystemSpace(IN PMMSESSION Session,
01795                         IN PVOID Base,
01796                         OUT PCONTROL_AREA *ControlArea)
01797 {
01798     ULONG Hash, Size, Count = 0;
01799     ULONG_PTR Entry;
01800     PAGED_CODE();
01801 
01802     /* Compute the hash for this entry and loop trying to find it */
01803     Entry = (ULONG_PTR)Base >> 16;
01804     Hash = Entry % Session->SystemSpaceHashKey;
01805     while ((Session->SystemSpaceViewTable[Hash].Entry >> 16) != Entry)
01806     {
01807         /* Check if we overflew past the end of the hash table */
01808         if (++Hash >= Session->SystemSpaceHashSize)
01809         {
01810             /* Reset the hash to zero and keep searching from the bottom */
01811             Hash = 0;
01812             if (++Count == 2)
01813             {
01814                 /* But if we overflew twice, then this is not a real mapping */
01815                 KeBugCheckEx(0xD7, //DRIVER_UNMAPPING_INVALID_VIEW,
01816                              (ULONG_PTR)Base,
01817                              1,
01818                              0,
01819                              0);
01820             }
01821         }
01822     }
01823 
01824     /* One less entry */
01825     Session->SystemSpaceHashEntries--;
01826 
01827     /* Extract the size and clear the entry */
01828     Size = Session->SystemSpaceViewTable[Hash].Entry & 0xFFFF;
01829     Session->SystemSpaceViewTable[Hash].Entry = 0;
01830 
01831     /* Return the control area and the size */
01832     *ControlArea = Session->SystemSpaceViewTable[Hash].ControlArea;
01833     return Size;
01834 }
01835 
01836 NTSTATUS
01837 NTAPI
01838 MiUnmapViewInSystemSpace(IN PMMSESSION Session,
01839                          IN PVOID MappedBase)
01840 {
01841     ULONG Size;
01842     PCONTROL_AREA ControlArea;
01843     PAGED_CODE();
01844 
01845     /* Only global mappings supported for now */
01846     ASSERT(Session == &MmSession);
01847 
01848     /* Remove this mapping */
01849     KeAcquireGuardedMutex(Session->SystemSpaceViewLockPointer);
01850     Size = MiRemoveFromSystemSpace(Session, MappedBase, &ControlArea);
01851 
01852     /* Clear the bits for this mapping */
01853     RtlClearBits(Session->SystemSpaceBitMap,
01854                  (ULONG)(((ULONG_PTR)MappedBase - (ULONG_PTR)Session->SystemSpaceViewStart) >> 16),
01855                  Size);
01856 
01857     /* Convert the size from a bit size into the actual size */
01858     Size = Size * (_64K >> PAGE_SHIFT);
01859 
01860     /* Remove the PTEs now */
01861     MiRemoveMappedPtes(MappedBase, Size, ControlArea, NULL);
01862     KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer);
01863 
01864     /* Return success */
01865     return STATUS_SUCCESS;
01866 }
01867 
01868 /* PUBLIC FUNCTIONS ***********************************************************/
01869 
01870 /*
01871  * @implemented
01872  */
01873 NTSTATUS
01874 NTAPI
01875 MmCreateArm3Section(OUT PVOID *SectionObject,
01876                     IN ACCESS_MASK DesiredAccess,
01877                     IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
01878                     IN PLARGE_INTEGER InputMaximumSize,
01879                     IN ULONG SectionPageProtection,
01880                     IN ULONG AllocationAttributes,
01881                     IN HANDLE FileHandle OPTIONAL,
01882                     IN PFILE_OBJECT FileObject OPTIONAL)
01883 {
01884     SECTION Section;
01885     PSECTION NewSection;
01886     PSUBSECTION Subsection;
01887     PSEGMENT NewSegment;
01888     NTSTATUS Status;
01889     PCONTROL_AREA ControlArea;
01890     ULONG ProtectionMask;
01891 
01892     /* ARM3 does not yet support this */
01893     ASSERT(FileHandle == NULL);
01894     ASSERT(FileObject == NULL);
01895     ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0);
01896 
01897     /* Make the same sanity checks that the Nt interface should've validated */
01898     ASSERT((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED |
01899                                      SEC_LARGE_PAGES | SEC_IMAGE | SEC_NOCACHE |
01900                                      SEC_NO_CHANGE)) == 0);
01901     ASSERT((AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_IMAGE)) != 0);
01902     ASSERT(!((AllocationAttributes & SEC_IMAGE) &&
01903              (AllocationAttributes & (SEC_COMMIT | SEC_RESERVE |
01904                                       SEC_NOCACHE | SEC_NO_CHANGE))));
01905     ASSERT(!((AllocationAttributes & SEC_COMMIT) && (AllocationAttributes & SEC_RESERVE)));
01906     ASSERT(!((SectionPageProtection & PAGE_NOCACHE) ||
01907              (SectionPageProtection & PAGE_WRITECOMBINE) ||
01908              (SectionPageProtection & PAGE_GUARD) ||
01909              (SectionPageProtection & PAGE_NOACCESS)));
01910 
01911     /* Convert section flag to page flag */
01912     if (AllocationAttributes & SEC_NOCACHE) SectionPageProtection |= PAGE_NOCACHE;
01913 
01914     /* Check to make sure the protection is correct. Nt* does this already */
01915     ProtectionMask = MiMakeProtectionMask(SectionPageProtection);
01916     if (ProtectionMask == MM_INVALID_PROTECTION) return STATUS_INVALID_PAGE_PROTECTION;
01917 
01918     /* A handle must be supplied with SEC_IMAGE, and this is the no-handle path */
01919     if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION;
01920 
01921     /* So this must be a pagefile-backed section, create the mappings needed */
01922     Status = MiCreatePagingFileMap(&NewSegment,
01923                                    (PSIZE_T)InputMaximumSize,
01924                                    ProtectionMask,
01925                                    AllocationAttributes);
01926     ASSERT(NT_SUCCESS(Status));
01927     ASSERT(NewSegment != NULL);
01928 
01929     /* Set the initial section object data */
01930     Section.InitialPageProtection = SectionPageProtection;
01931     Section.SizeOfSection.QuadPart = NewSegment->SizeOfSegment;
01932     Section.Segment = NewSegment;
01933 
01934     /* THe mapping created a control area and segment, save the flags */
01935     ControlArea = NewSegment->ControlArea;
01936     Section.u.LongFlags = ControlArea->u.LongFlags;
01937 
01938     /* ARM3 cannot support these right now, make sure they're not being set */
01939     ASSERT(ControlArea->u.Flags.Image == 0);
01940     ASSERT(ControlArea->FilePointer == NULL);
01941     ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
01942     ASSERT(ControlArea->u.Flags.Rom == 0);
01943     ASSERT(ControlArea->u.Flags.WasPurged == 0);
01944 
01945     /* A pagefile-backed mapping only has one subsection, and this is all ARM3 supports */
01946     Subsection = (PSUBSECTION)(ControlArea + 1);
01947     ASSERT(Subsection->NextSubsection == NULL);
01948 
01949     /* Create the actual section object, with enough space for the prototype PTEs */
01950     Status = ObCreateObject(ExGetPreviousMode(),
01951                             MmSectionObjectType,
01952                             ObjectAttributes,
01953                             ExGetPreviousMode(),
01954                             NULL,
01955                             sizeof(SECTION),
01956                             sizeof(SECTION) +
01957                             NewSegment->TotalNumberOfPtes * sizeof(MMPTE),
01958                             sizeof(CONTROL_AREA) + sizeof(SUBSECTION),
01959                             (PVOID*)&NewSection);
01960     ASSERT(NT_SUCCESS(Status));
01961 
01962     /* Now copy the local section object from the stack into this new object */
01963     RtlCopyMemory(NewSection, &Section, sizeof(SECTION));
01964     NewSection->Address.StartingVpn = 0;
01965     NewSection->u.Flags.UserReference = TRUE;
01966 
01967     /* Migrate the attribute into a flag */
01968     if (AllocationAttributes & SEC_NO_CHANGE) NewSection->u.Flags.NoChange = TRUE;
01969 
01970     /* If R/W access is not requested, this might eventually become a CoW mapping */
01971     if (!(SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)))
01972     {
01973         NewSection->u.Flags.CopyOnWrite = TRUE;
01974     }
01975 
01976     /* Is this a "based" allocation, in which all mappings are identical? */
01977     if (AllocationAttributes & SEC_BASED)
01978     {
01979         /* Convert the flag, and make sure the section isn't too big */
01980         NewSection->u.Flags.Based = TRUE;
01981         if ((ULONGLONG)NewSection->SizeOfSection.QuadPart >
01982             (ULONG_PTR)MmHighSectionBase)
01983         {
01984             DPRINT1("BASED section is too large\n");
01985             ObDereferenceObject(NewSection);
01986             return STATUS_NO_MEMORY;
01987         }
01988 
01989         /* Lock the VAD tree during the search */
01990         KeAcquireGuardedMutex(&MmSectionBasedMutex);
01991 
01992         /* Find an address top-down */
01993         Status = MiFindEmptyAddressRangeDownBasedTree(NewSection->SizeOfSection.LowPart,
01994                                                       (ULONG_PTR)MmHighSectionBase,
01995                                                       _64K,
01996                                                       &MmSectionBasedRoot,
01997                                                       &NewSection->Address.StartingVpn);
01998         ASSERT(NT_SUCCESS(Status));
01999 
02000         /* Compute the ending address and insert it into the VAD tree */
02001         NewSection->Address.EndingVpn = NewSection->Address.StartingVpn +
02002                                         NewSection->SizeOfSection.LowPart -
02003                                         1;
02004         MiInsertBasedSection(NewSection);
02005 
02006         /* Finally release the lock */
02007         KeReleaseGuardedMutex(&MmSectionBasedMutex);
02008     }
02009 
02010     /* Return the object and the creation status */
02011     *SectionObject = (PVOID)NewSection;
02012     return Status;
02013 }
02014 
02015 /*
02016  * @implemented
02017  */
02018 NTSTATUS
02019 NTAPI
02020 MmMapViewOfArm3Section(IN PVOID SectionObject,
02021                        IN PEPROCESS Process,
02022                        IN OUT PVOID *BaseAddress,
02023                        IN ULONG_PTR ZeroBits,
02024                        IN SIZE_T CommitSize,
02025                        IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
02026                        IN OUT PSIZE_T ViewSize,
02027                        IN SECTION_INHERIT InheritDisposition,
02028                        IN ULONG AllocationType,
02029                        IN ULONG Protect)
02030 {
02031     KAPC_STATE ApcState;
02032     BOOLEAN Attached = FALSE;
02033     PSECTION Section;
02034     PCONTROL_AREA ControlArea;
02035     ULONG ProtectionMask;
02036     NTSTATUS Status;
02037     PAGED_CODE();
02038 
02039     /* Force PAGE_READWRITE for everything, for now */
02040     Protect = PAGE_READWRITE;
02041 
02042     /* Get the segment and control area */
02043     Section = (PSECTION)SectionObject;
02044     ControlArea = Section->Segment->ControlArea;
02045 
02046     /* These flags/states are not yet supported by ARM3 */
02047     ASSERT(Section->u.Flags.Image == 0);
02048     ASSERT(Section->u.Flags.NoCache == 0);
02049     ASSERT(Section->u.Flags.WriteCombined == 0);
02050     ASSERT((AllocationType & MEM_RESERVE) == 0);
02051     ASSERT(ControlArea->u.Flags.PhysicalMemory == 0);
02052 
02053 #if 0
02054     /* FIXME: Check if the mapping protection is compatible with the create */
02055     if (!MiIsProtectionCompatible(Section->InitialPageProtection, Protect))
02056     {
02057         DPRINT1("Mapping protection is incompatible\n");
02058         return STATUS_SECTION_PROTECTION;
02059     }
02060 #endif
02061 
02062     /* Check if the offset and size would cause an overflow */
02063     if (((ULONG64)SectionOffset->QuadPart + *ViewSize) <
02064          (ULONG64)SectionOffset->QuadPart)
02065     {
02066         DPRINT1("Section offset overflows\n");
02067         return STATUS_INVALID_VIEW_SIZE;
02068     }
02069 
02070     /* Check if the offset and size are bigger than the section itself */
02071     if (((ULONG64)SectionOffset->QuadPart + *ViewSize) >
02072          (ULONG64)Section->SizeOfSection.QuadPart)
02073     {
02074         DPRINT1("Section offset is larger than section\n");
02075         return STATUS_INVALID_VIEW_SIZE;
02076     }
02077 
02078     /* Check if the caller did not specify a view size */
02079     if (!(*ViewSize))
02080     {
02081         /* Compute it for the caller */
02082         *ViewSize = (SIZE_T)(Section->SizeOfSection.QuadPart - SectionOffset->QuadPart);
02083 
02084         /* Check if it's larger than 4GB or overflows into kernel-mode */
02085         if ((*ViewSize > 0xFFFFFFFF) ||
02086             (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)*BaseAddress) < *ViewSize))
02087         {
02088             DPRINT1("Section view won't fit\n");
02089             return STATUS_INVALID_VIEW_SIZE;
02090         }
02091     }
02092 
02093     /* Check if the commit size is larger than the view size */
02094     if (CommitSize > *ViewSize)
02095     {
02096         DPRINT1("Attempting to commit more than the view itself\n");
02097         return STATUS_INVALID_PARAMETER_5;
02098     }
02099 
02100     /* Check if the view size is larger than the section */
02101     if (*ViewSize > (ULONG64)Section->SizeOfSection.QuadPart)
02102     {
02103         DPRINT1("The view is larger than the section\n");
02104         return STATUS_INVALID_VIEW_SIZE;
02105     }
02106 
02107     /* Compute and validate the protection mask */
02108     ProtectionMask = MiMakeProtectionMask(Protect);
02109     if (ProtectionMask == MM_INVALID_PROTECTION)
02110     {
02111         DPRINT1("The protection is invalid\n");
02112         return STATUS_INVALID_PAGE_PROTECTION;
02113     }
02114 
02115     /* We only handle pagefile-backed sections, which cannot be writecombined */
02116     if (Protect & PAGE_WRITECOMBINE)
02117     {
02118         DPRINT1("Cannot write combine a pagefile-backed section\n");
02119         return STATUS_INVALID_PARAMETER_10;
02120     }
02121 
02122     /* Start by attaching to the current process if needed */
02123     if (PsGetCurrentProcess() != Process)
02124     {
02125         KeStackAttachProcess(&Process->Pcb, &ApcState);
02126         Attached = TRUE;
02127     }
02128 
02129     /* Lock the address space and make sure the process is alive */
02130     MmLockAddressSpace(&Process->Vm);
02131     if (!Process->VmDeleted)
02132     {
02133         /* Do the actual mapping */
02134         DPRINT("Mapping ARM3 data section\n");
02135         Status = MiMapViewOfDataSection(ControlArea,
02136                                         Process,
02137                                         BaseAddress,
02138                                         SectionOffset,
02139                                         ViewSize,
02140                                         Section,
02141                                         InheritDisposition,
02142                                         ProtectionMask,
02143                                         CommitSize,
02144                                         ZeroBits,
02145                                         AllocationType);
02146     }
02147     else
02148     {
02149         /* The process is being terminated, fail */
02150         DPRINT1("The process is dying\n");
02151         Status = STATUS_PROCESS_IS_TERMINATING;
02152     }
02153 
02154     /* Unlock the address space and detatch if needed, then return status */
02155     MmUnlockAddressSpace(&Process->Vm);
02156     if (Attached) KeUnstackDetachProcess(&ApcState);
02157     return Status;
02158 }
02159 
02160 /*
02161  * @unimplemented
02162  */
02163 BOOLEAN
02164 NTAPI
02165 MmDisableModifiedWriteOfSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer)
02166 {
02167    UNIMPLEMENTED;
02168    return FALSE;
02169 }
02170 
02171 /*
02172  * @unimplemented
02173  */
02174 BOOLEAN
02175 NTAPI
02176 MmForceSectionClosed(IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
02177                      IN BOOLEAN DelayClose)
02178 {
02179    UNIMPLEMENTED;
02180    return FALSE;
02181 }
02182 
02183 /*
02184  * @unimplemented
02185  */
02186 NTSTATUS
02187 NTAPI
02188 MmMapViewInSessionSpace(IN PVOID Section,
02189                         OUT PVOID *MappedBase,
02190                         IN OUT PSIZE_T ViewSize)
02191 {
02192     UNIMPLEMENTED;
02193     return STATUS_NOT_IMPLEMENTED;
02194 }
02195 
02196 /*
02197  * @unimplemented
02198  */
02199 NTSTATUS
02200 NTAPI
02201 MmUnmapViewInSessionSpace(IN PVOID MappedBase)
02202 {
02203     UNIMPLEMENTED;
02204     return STATUS_NOT_IMPLEMENTED;
02205 }
02206 
02207 /*
02208  * @implemented
02209  */
02210 NTSTATUS
02211 NTAPI
02212 MmUnmapViewOfSection(IN PEPROCESS Process,
02213                      IN PVOID BaseAddress)
02214 {
02215     return MiUnmapViewOfSection(Process, BaseAddress, 0);
02216 }
02217 
02218 /*
02219  * @implemented
02220  */
02221 NTSTATUS
02222 NTAPI
02223 MmUnmapViewInSystemSpace(IN PVOID MappedBase)
02224 {
02225     PMEMORY_AREA MemoryArea;
02226     PAGED_CODE();
02227 
02228     /* Was this mapped by RosMm? */
02229     MemoryArea = MmLocateMemoryAreaByAddress(MmGetKernelAddressSpace(), MappedBase);
02230     if ((MemoryArea) && (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3))
02231     {
02232         return MiRosUnmapViewInSystemSpace(MappedBase);
02233     }
02234 
02235     /* It was not, call the ARM3 routine */
02236     return MiUnmapViewInSystemSpace(&MmSession, MappedBase);
02237 }
02238 
02239 /* SYSTEM CALLS ***************************************************************/
02240 
02241 NTSTATUS
02242 NTAPI
02243 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage,
02244                         IN PVOID File2MappedAsFile)
02245 {
02246     PVOID AddressSpace;
02247     PMEMORY_AREA MemoryArea1, MemoryArea2;
02248     PROS_SECTION_OBJECT Section1, Section2;
02249 
02250     /* Lock address space */
02251     AddressSpace = MmGetCurrentAddressSpace();
02252     MmLockAddressSpace(AddressSpace);
02253 
02254     /* Locate the memory area for the process by address */
02255     MemoryArea1 = MmLocateMemoryAreaByAddress(AddressSpace, File1MappedAsAnImage);
02256     if (!MemoryArea1)
02257     {
02258         /* Fail, the address does not exist */
02259         MmUnlockAddressSpace(AddressSpace);
02260         return STATUS_INVALID_ADDRESS;
02261     }
02262 
02263     /* Check if it's a section view (RosMm section) or ARM3 section */
02264     if (MemoryArea1->Type != MEMORY_AREA_SECTION_VIEW)
02265     {
02266         /* Fail, the address is not a section */
02267         MmUnlockAddressSpace(AddressSpace);
02268         return STATUS_CONFLICTING_ADDRESSES;
02269     }
02270 
02271     /* Get the section pointer to the SECTION_OBJECT */
02272     Section1 = MemoryArea1->Data.SectionData.Section;
02273     if (Section1->FileObject == NULL)
02274     {
02275         MmUnlockAddressSpace(AddressSpace);
02276         return STATUS_CONFLICTING_ADDRESSES;
02277     }
02278 
02279     /* Locate the memory area for the process by address */
02280     MemoryArea2 = MmLocateMemoryAreaByAddress(AddressSpace, File2MappedAsFile);
02281     if (!MemoryArea2)
02282     {
02283         /* Fail, the address does not exist */
02284         MmUnlockAddressSpace(AddressSpace);
02285         return STATUS_INVALID_ADDRESS;
02286     }
02287 
02288     /* Check if it's a section view (RosMm section) or ARM3 section */
02289     if (MemoryArea2->Type != MEMORY_AREA_SECTION_VIEW)
02290     {
02291         /* Fail, the address is not a section */
02292         MmUnlockAddressSpace(AddressSpace);
02293         return STATUS_CONFLICTING_ADDRESSES;
02294     }
02295 
02296     /* Get the section pointer to the SECTION_OBJECT */
02297     Section2 = MemoryArea2->Data.SectionData.Section;
02298     if (Section2->FileObject == NULL)
02299     {
02300         MmUnlockAddressSpace(AddressSpace);
02301         return STATUS_CONFLICTING_ADDRESSES;
02302     }
02303 
02304     /* The shared cache map seems to be the same if both of these are equal */
02305     if (Section1->FileObject->SectionObjectPointer->SharedCacheMap ==
02306         Section2->FileObject->SectionObjectPointer->SharedCacheMap)
02307     {
02308         MmUnlockAddressSpace(AddressSpace);
02309         return STATUS_SUCCESS;
02310     }
02311 
02312     /* Unlock address space */
02313     MmUnlockAddressSpace(AddressSpace);
02314     return STATUS_NOT_SAME_DEVICE;
02315 }
02316 
02317 /*
02318  * @implemented
02319  */
02320 NTSTATUS
02321 NTAPI
02322 NtCreateSection(OUT PHANDLE SectionHandle,
02323                 IN ACCESS_MASK DesiredAccess,
02324                 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
02325                 IN PLARGE_INTEGER MaximumSize OPTIONAL,
02326                 IN ULONG SectionPageProtection OPTIONAL,
02327                 IN ULONG AllocationAttributes,
02328                 IN HANDLE FileHandle OPTIONAL)
02329 {
02330     LARGE_INTEGER SafeMaximumSize;
02331     PVOID SectionObject;
02332     HANDLE Handle;
02333     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
02334     NTSTATUS Status;
02335     PAGED_CODE();
02336 
02337     /* Check for non-existing flags */
02338     if ((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED |
02339                                   SEC_LARGE_PAGES | SEC_IMAGE | SEC_NOCACHE |
02340                                   SEC_NO_CHANGE)))
02341     {
02342         if (!(AllocationAttributes & 1))
02343         {
02344             DPRINT1("Bogus allocation attribute: %lx\n", AllocationAttributes);
02345             return STATUS_INVALID_PARAMETER_6;
02346         }
02347     }
02348 
02349     /* Check for no allocation type */
02350     if (!(AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_IMAGE)))
02351     {
02352         DPRINT1("Missing allocation type in allocation attributes\n");
02353         return STATUS_INVALID_PARAMETER_6;
02354     }
02355 
02356     /* Check for image allocation with invalid attributes */
02357     if ((AllocationAttributes & SEC_IMAGE) &&
02358         (AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_LARGE_PAGES |
02359                                  SEC_NOCACHE | SEC_NO_CHANGE)))
02360     {
02361         DPRINT1("Image allocation with invalid attributes\n");
02362         return STATUS_INVALID_PARAMETER_6;
02363     }
02364 
02365     /* Check for allocation type is both commit and reserve */
02366     if ((AllocationAttributes & SEC_COMMIT) && (AllocationAttributes & SEC_RESERVE))
02367     {
02368         DPRINT1("Commit and reserve in the same time\n");
02369         return STATUS_INVALID_PARAMETER_6;
02370     }
02371 
02372     /* Now check for valid protection */
02373     if ((SectionPageProtection & PAGE_NOCACHE) ||
02374         (SectionPageProtection & PAGE_WRITECOMBINE) ||
02375         (SectionPageProtection & PAGE_GUARD) ||
02376         (SectionPageProtection & PAGE_NOACCESS))
02377     {
02378         DPRINT1("Sections don't support these protections\n");
02379         return STATUS_INVALID_PAGE_PROTECTION;
02380     }
02381 
02382     /* Use a maximum size of zero, if none was specified */
02383     SafeMaximumSize.QuadPart = 0;
02384 
02385     /* Check for user-mode caller */
02386     if (PreviousMode != KernelMode)
02387     {
02388         /* Enter SEH */
02389         _SEH2_TRY
02390         {
02391             /* Safely check user-mode parameters */
02392             if (MaximumSize) SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
02393             MaximumSize = &SafeMaximumSize;
02394             ProbeForWriteHandle(SectionHandle);
02395         }
02396         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02397         {
02398             /* Return the exception code */
02399             _SEH2_YIELD(return _SEH2_GetExceptionCode());
02400         }
02401         _SEH2_END;
02402     }
02403     else if (!MaximumSize) MaximumSize = &SafeMaximumSize;
02404 
02405     /* Check that MaximumSize is valid if backed by paging file */
02406     if ((!FileHandle) && (!MaximumSize->QuadPart))
02407         return STATUS_INVALID_PARAMETER_4;
02408 
02409     /* Create the section */
02410     Status = MmCreateSection(&SectionObject,
02411                              DesiredAccess,
02412                              ObjectAttributes,
02413                              MaximumSize,
02414                              SectionPageProtection,
02415                              AllocationAttributes,
02416                              FileHandle,
02417                              NULL);
02418     if (!NT_SUCCESS(Status)) return Status;
02419 
02420     /* FIXME: Should zero last page for a file mapping */
02421 
02422     /* Now insert the object */
02423     Status = ObInsertObject(SectionObject,
02424                             NULL,
02425                             DesiredAccess,
02426                             0,
02427                             NULL,
02428                             &Handle);
02429     if (NT_SUCCESS(Status))
02430     {
02431         /* Enter SEH */
02432         _SEH2_TRY
02433         {
02434             /* Return the handle safely */
02435             *SectionHandle = Handle;
02436         }
02437         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02438         {
02439             /* Nothing here */
02440         }
02441         _SEH2_END;
02442     }
02443 
02444     /* Return the status */
02445     return Status;
02446 }
02447 
02448 NTSTATUS
02449 NTAPI
02450 NtOpenSection(OUT PHANDLE SectionHandle,
02451               IN ACCESS_MASK DesiredAccess,
02452               IN POBJECT_ATTRIBUTES ObjectAttributes)
02453 {
02454     HANDLE Handle;
02455     NTSTATUS Status;
02456     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
02457     PAGED_CODE();
02458 
02459     /* Check for user-mode caller */
02460     if (PreviousMode != KernelMode)
02461     {
02462         /* Enter SEH */
02463         _SEH2_TRY
02464         {
02465             /* Safely check user-mode parameters */
02466             ProbeForWriteHandle(SectionHandle);
02467         }
02468         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02469         {
02470             /* Return the exception code */
02471             _SEH2_YIELD(return _SEH2_GetExceptionCode());
02472         }
02473         _SEH2_END;
02474     }
02475 
02476     /* Try opening the object */
02477     Status = ObOpenObjectByName(ObjectAttributes,
02478                                 MmSectionObjectType,
02479                                 PreviousMode,
02480                                 NULL,
02481                                 DesiredAccess,
02482                                 NULL,
02483                                 &Handle);
02484 
02485     /* Enter SEH */
02486     _SEH2_TRY
02487     {
02488         /* Return the handle safely */
02489         *SectionHandle = Handle;
02490     }
02491     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02492     {
02493         /* Nothing here */
02494     }
02495     _SEH2_END;
02496 
02497     /* Return the status */
02498     return Status;
02499 }
02500 
02501 NTSTATUS
02502 NTAPI
02503 NtMapViewOfSection(IN HANDLE SectionHandle,
02504                    IN HANDLE ProcessHandle,
02505                    IN OUT PVOID* BaseAddress,
02506                    IN ULONG_PTR ZeroBits,
02507                    IN SIZE_T CommitSize,
02508                    IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
02509                    IN OUT PSIZE_T ViewSize,
02510                    IN SECTION_INHERIT InheritDisposition,
02511                    IN ULONG AllocationType,
02512                    IN ULONG Protect)
02513 {
02514     PVOID SafeBaseAddress;
02515     LARGE_INTEGER SafeSectionOffset;
02516     SIZE_T SafeViewSize;
02517     PROS_SECTION_OBJECT Section;
02518     PEPROCESS Process;
02519     NTSTATUS Status;
02520     ACCESS_MASK DesiredAccess;
02521     ULONG ProtectionMask;
02522     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
02523 
02524     /* Check for invalid zero bits */
02525     if (ZeroBits > 21) // per-arch?
02526     {
02527         DPRINT1("Invalid zero bits\n");
02528         return STATUS_INVALID_PARAMETER_4;
02529     }
02530 
02531     /* Check for invalid inherit disposition */
02532     if ((InheritDisposition > ViewUnmap) || (InheritDisposition < ViewShare))
02533     {
02534         DPRINT1("Invalid inherit disposition\n");
02535         return STATUS_INVALID_PARAMETER_8;
02536     }
02537 
02538     /* Allow only valid allocation types */
02539     if ((AllocationType & ~(MEM_TOP_DOWN | MEM_LARGE_PAGES | MEM_DOS_LIM |
02540                             SEC_NO_CHANGE | MEM_RESERVE)))
02541     {
02542         DPRINT1("Invalid allocation type\n");
02543         return STATUS_INVALID_PARAMETER_9;
02544     }
02545 
02546     /* Convert the protection mask, and validate it */
02547     ProtectionMask = MiMakeProtectionMask(Protect);
02548     if (ProtectionMask == MM_INVALID_PROTECTION)
02549     {
02550         DPRINT1("Invalid page protection\n");
02551         return STATUS_INVALID_PAGE_PROTECTION;
02552     }
02553 
02554     /* Now convert the protection mask into desired section access mask */
02555     DesiredAccess = MmMakeSectionAccess[ProtectionMask & 0x7];
02556 
02557     /* Assume no section offset */
02558     SafeSectionOffset.QuadPart = 0;
02559 
02560     /* Enter SEH */
02561     _SEH2_TRY
02562     {
02563         /* Check for unsafe parameters */
02564         if (PreviousMode != KernelMode)
02565         {
02566             /* Probe the parameters */
02567             ProbeForWritePointer(BaseAddress);
02568             ProbeForWriteSize_t(ViewSize);
02569         }
02570 
02571         /* Check if a section offset was given */
02572         if (SectionOffset)
02573         {
02574             /* Check for unsafe parameters and capture section offset */
02575             if (PreviousMode != KernelMode) ProbeForWriteLargeInteger(SectionOffset);
02576             SafeSectionOffset = *SectionOffset;
02577         }
02578 
02579         /* Capture the other parameters */
02580         SafeBaseAddress = *BaseAddress;
02581         SafeViewSize = *ViewSize;
02582     }
02583     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02584     {
02585         /* Return the exception code */
02586         _SEH2_YIELD(return _SEH2_GetExceptionCode());
02587     }
02588     _SEH2_END;
02589 
02590     /* Check for kernel-mode address */
02591     if (SafeBaseAddress > MM_HIGHEST_VAD_ADDRESS)
02592     {
02593         DPRINT1("Kernel base not allowed\n");
02594         return STATUS_INVALID_PARAMETER_3;
02595     }
02596 
02597     /* Check for range entering kernel-mode */
02598     if (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)SafeBaseAddress) < SafeViewSize)
02599     {
02600         DPRINT1("Overflowing into kernel base not allowed\n");
02601         return STATUS_INVALID_PARAMETER_3;
02602     }
02603 
02604     /* Check for invalid zero bits */
02605     if (((ULONG_PTR)SafeBaseAddress + SafeViewSize) > (0xFFFFFFFF >> ZeroBits)) // arch?
02606     {
02607         DPRINT1("Invalid zero bits\n");
02608         return STATUS_INVALID_PARAMETER_4;
02609     }
02610 
02611     /* Reference the process */
02612     Status = ObReferenceObjectByHandle(ProcessHandle,
02613                                        PROCESS_VM_OPERATION,
02614                                        PsProcessType,
02615                                        PreviousMode,
02616                                        (PVOID*)&Process,
02617                                        NULL);
02618     if (!NT_SUCCESS(Status)) return Status;
02619 
02620     /* Reference the section */
02621     Status = ObReferenceObjectByHandle(SectionHandle,
02622                                        DesiredAccess,
02623                                        MmSectionObjectType,
02624                                        PreviousMode,
02625                                        (PVOID*)&Section,
02626                                        NULL);
02627     if (!NT_SUCCESS(Status))
02628     {
02629         ObDereferenceObject(Process);
02630         return Status;
02631     }
02632 
02633     /* Now do the actual mapping */
02634     Status = MmMapViewOfSection(Section,
02635                                 Process,
02636                                 &SafeBaseAddress,
02637                                 ZeroBits,
02638                                 CommitSize,
02639                                 &SafeSectionOffset,
02640                                 &SafeViewSize,
02641                                 InheritDisposition,
02642                                 AllocationType,
02643                                 Protect);
02644 
02645     /* Return data only on success */
02646     if (NT_SUCCESS(Status))
02647     {
02648         /* Check if this is an image for the current process */
02649         if ((Section->AllocationAttributes & SEC_IMAGE) &&
02650             (Process == PsGetCurrentProcess()) &&
02651             (Status != STATUS_IMAGE_NOT_AT_BASE))
02652         {
02653             /* Notify the debugger */
02654             DbgkMapViewOfSection(Section,
02655                                  SafeBaseAddress,
02656                                  SafeSectionOffset.LowPart,
02657                                  SafeViewSize);
02658         }
02659 
02660         /* Enter SEH */
02661         _SEH2_TRY
02662         {
02663             /* Return parameters to user */
02664             *BaseAddress = SafeBaseAddress;
02665             *ViewSize = SafeViewSize;
02666             if (SectionOffset) *SectionOffset = SafeSectionOffset;
02667         }
02668         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02669         {
02670             /* Nothing to do */
02671         }
02672         _SEH2_END;
02673     }
02674 
02675     /* Dereference all objects and return status */
02676     ObDereferenceObject(Section);
02677     ObDereferenceObject(Process);
02678     return Status;
02679 }
02680 
02681 NTSTATUS
02682 NTAPI
02683 NtUnmapViewOfSection(IN HANDLE ProcessHandle,
02684                      IN PVOID BaseAddress)
02685 {
02686     PEPROCESS Process;
02687     NTSTATUS Status;
02688     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
02689 
02690     /* Don't allowing mapping kernel views */
02691     if ((PreviousMode == UserMode) && (BaseAddress > MM_HIGHEST_USER_ADDRESS))
02692     {
02693         DPRINT1("Trying to unmap a kernel view\n");
02694         return STATUS_NOT_MAPPED_VIEW;
02695     }
02696 
02697     /* Reference the process */
02698     Status = ObReferenceObjectByHandle(ProcessHandle,
02699                                        PROCESS_VM_OPERATION,
02700                                        PsProcessType,
02701                                        PreviousMode,
02702                                        (PVOID*)&Process,
02703                                        NULL);
02704     if (!NT_SUCCESS(Status)) return Status;
02705 
02706     /* Unmap the view */
02707     Status = MiUnmapViewOfSection(Process, BaseAddress, 0);
02708 
02709     /* Dereference the process and return status */
02710     ObDereferenceObject(Process);
02711     return Status;
02712 }
02713 
02714 NTSTATUS
02715 NTAPI
02716 NtExtendSection(IN HANDLE SectionHandle,
02717                 IN OUT PLARGE_INTEGER NewMaximumSize)
02718 {
02719     LARGE_INTEGER SafeNewMaximumSize;
02720     PROS_SECTION_OBJECT Section;
02721     NTSTATUS Status;
02722     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
02723 
02724     /* Check for user-mode parameters */
02725     if (PreviousMode != KernelMode)
02726     {
02727         /* Enter SEH */
02728         _SEH2_TRY
02729         {
02730             /* Probe and capture the maximum size, it's both read and write */
02731             ProbeForWriteLargeInteger(NewMaximumSize);
02732             SafeNewMaximumSize = *NewMaximumSize;
02733         }
02734         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02735         {
02736             /* Return the exception code */
02737             _SEH2_YIELD(return _SEH2_GetExceptionCode());
02738         }
02739         _SEH2_END;
02740     }
02741     else
02742     {
02743         /* Just read the size directly */
02744         SafeNewMaximumSize = *NewMaximumSize;
02745     }
02746 
02747     /* Reference the section */
02748     Status = ObReferenceObjectByHandle(SectionHandle,
02749                                        SECTION_EXTEND_SIZE,
02750                                        MmSectionObjectType,
02751                                        PreviousMode,
02752                                        (PVOID*)&Section,
02753                                        NULL);
02754     if (!NT_SUCCESS(Status)) return Status;
02755 
02756     /* Really this should go in MmExtendSection */
02757     if (!(Section->AllocationAttributes & SEC_FILE))
02758     {
02759         DPRINT1("Not extending a file\n");
02760         ObDereferenceObject(Section);
02761         return STATUS_SECTION_NOT_EXTENDED;
02762     }
02763 
02764     /* FIXME: Do the work */
02765 
02766     /* Dereference the section */
02767     ObDereferenceObject(Section);
02768 
02769     /* Enter SEH */
02770     _SEH2_TRY
02771     {
02772         /* Write back the new size */
02773         *NewMaximumSize = SafeNewMaximumSize;
02774     }
02775     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02776     {
02777         /* Nothing to do */
02778     }
02779     _SEH2_END;
02780 
02781     /* Return the status */
02782     return STATUS_NOT_IMPLEMENTED;
02783 }
02784 
02785 /* EOF */

Generated on Sun May 27 2012 04:37:36 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.