Fixed the check for the MEM_TOP_DOWN flag in MmMapViewOfSection.
[reactos.git] / reactos / ntoskrnl / mm / section.c
index 12f7020..584c9da 100644 (file)
@@ -1,72 +1,81 @@
-/*
- *  ReactOS kernel
- *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
+/* $Id$
  *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
  *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/* $Id: section.c,v 1.131 2003/10/18 09:35:11 hbirr Exp $
  *
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/mm/section.c
  * PURPOSE:         Implements section objects
- * PROGRAMMER:      David Welch (welch@mcmail.com)
- * UPDATE HISTORY:
- *                  Created 22/05/98
+ *
+ * PROGRAMMERS:     Rex Jolliff
+ *                  David Welch
+ *                  Eric Kohl
+ *                  Emanuele Aliberti
+ *                  Eugene Ingerman
+ *                  Hartmut Birr
+ *                  Casper Hornstrup
+ *                  KJK::Hyperion
+ *                  Guido de Jong
+ *                  Ge van Geldorp
+ *                  Royce Mitchell III
+ *                  Filip Navara
+ *                  Aleksey Bragin 
+ *                  Jason Filby
+ *                  Thomas Weidenmueller
+ *                  Gunnar Andre' Dalsnes
+ *                  Mike Nordell
+ *                  Alex Ionescu
+ *                  Gregor Anich
+ *                  Steven Edwards
+ *                  Herve Poussineau
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <limits.h>
-#define NTOS_MODE_KERNEL
-#include <ntos.h>
-#include <internal/mm.h>
-#include <internal/io.h>
-#include <internal/ps.h>
-#include <internal/pool.h>
-#include <internal/cc.h>
-#include <ddk/ntifs.h>
-#include <ntos/minmax.h>
-
+#include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
 
+#include <reactos/exeformat.h>
+
 /* TYPES *********************************************************************/
 
 typedef struct
 {
-  PSECTION_OBJECT Section;
-  PMM_SECTION_SEGMENT Segment;
-  ULONG Offset;
-  BOOLEAN WasDirty;
-  BOOLEAN Private;
-} MM_SECTION_PAGEOUT_CONTEXT;
+   PSECTION_OBJECT Section;
+   PMM_SECTION_SEGMENT Segment;
+   ULONG Offset;
+   BOOLEAN WasDirty;
+   BOOLEAN Private;
+}
+MM_SECTION_PAGEOUT_CONTEXT;
 
 /* GLOBALS *******************************************************************/
 
 POBJECT_TYPE EXPORTED MmSectionObjectType = NULL;
 
 static GENERIC_MAPPING MmpSectionMapping = {
-       STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
-       STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
-       STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
-       SECTION_ALL_ACCESS};
-
-#define TAG_MM_SECTION_SEGMENT   TAG('M', 'M', 'S', 'S')
-#define TAG_SECTION_PAGE_TABLE   TAG('M', 'S', 'P', 'T')
+         STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
+         STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
+         STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
+         SECTION_ALL_ACCESS};
 
 #define PAGE_FROM_SSE(E)         ((E) & 0xFFFFF000)
+#define PFN_FROM_SSE(E)          ((E) >> PAGE_SHIFT)
 #define SHARE_COUNT_FROM_SSE(E)  (((E) & 0x00000FFE) >> 1)
 #define IS_SWAP_FROM_SSE(E)      ((E) & 0x00000001)
 #define MAX_SHARE_COUNT          0x7FF
@@ -74,29 +83,85 @@ static GENERIC_MAPPING MmpSectionMapping = {
 #define SWAPENTRY_FROM_SSE(E)    ((E) >> 1)
 #define MAKE_SWAP_SSE(S)         (((S) << 1) | 0x1)
 
+static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
+{
+  ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */
+  ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionImageInformation */
+};
+
 /* FUNCTIONS *****************************************************************/
 
+/* Note: Mmsp prefix denotes "Memory Manager Section Private". */
+
+/*
+ * FUNCTION:  Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
+ * ARGUMENTS: PMM_PAGEOP which event we should wait for.
+ * RETURNS:   Status of the wait.
+ */
+static NTSTATUS
+MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp)
+{
+   LARGE_INTEGER Timeout;
+#ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
+
+   Timeout.QuadPart = -100000000LL; // 10 sec
+#else
+
+   Timeout.QuadPart = -100000000; // 10 sec
+#endif
+
+   return KeWaitForSingleObject(&PageOp->CompletionEvent, 0, KernelMode, FALSE, &Timeout);
+}
+
+
+/*
+ * FUNCTION:  Sets the page op completion event and releases the page op.
+ * ARGUMENTS: PMM_PAGEOP.
+ * RETURNS:   In shorter time than it takes you to even read this
+ *            description, so don't even think about geting a mug of coffee.
+ */
+static void
+MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp)
+{
+   KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
+   MmReleasePageOp(PageOp);
+}
+
+
+/*
+ * FUNCTION:  Waits in kernel mode indefinitely for a file object lock.
+ * ARGUMENTS: PFILE_OBJECT to wait for.
+ * RETURNS:   Status of the wait.
+ */
+static NTSTATUS
+MmspWaitForFileLock(PFILE_OBJECT File)
+{
+   return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
+}
+
+
 VOID
 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment)
 {
-  ULONG i;
-  if (Segment->Length > NR_SECTION_PAGE_TABLES * PAGE_SIZE)
-    {
+   ULONG i;
+   if (Segment->Length > NR_SECTION_PAGE_TABLES * PAGE_SIZE)
+   {
       for (i = 0; i < NR_SECTION_PAGE_TABLES; i++)
-        {
-          if (Segment->PageDirectory.PageTables[i] != NULL)
-           {
-             ExFreePool(Segment->PageDirectory.PageTables[i]);
-           }
-        }
-    }
+      {
+         if (Segment->PageDirectory.PageTables[i] != NULL)
+         {
+            ExFreePool(Segment->PageDirectory.PageTables[i]);
+         }
+      }
+   }
 }
 
 VOID
+NTAPI
 MmFreeSectionSegments(PFILE_OBJECT FileObject)
 {
-  if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
-    {
+   if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
+   {
       PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
       PMM_SECTION_SEGMENT SectionSegments;
       ULONG NrSegments;
@@ -106,301 +171,338 @@ MmFreeSectionSegments(PFILE_OBJECT FileObject)
       NrSegments = ImageSectionObject->NrSegments;
       SectionSegments = ImageSectionObject->Segments;
       for (i = 0; i < NrSegments; i++)
-       {
-         if (SectionSegments[i].ReferenceCount != 0)
-           {
-             DPRINT1("Image segment %d still referenced (was %d)\n", i,
-                     SectionSegments[i].ReferenceCount);
-             KEBUGCHECK(0);
-           }
-         MmFreePageTablesSectionSegment(&SectionSegments[i]);
-       }
+      {
+         if (SectionSegments[i].ReferenceCount != 0)
+         {
+            DPRINT1("Image segment %d still referenced (was %d)\n", i,
+                    SectionSegments[i].ReferenceCount);
+            KEBUGCHECK(0);
+         }
+         MmFreePageTablesSectionSegment(&SectionSegments[i]);
+      }
+      ExFreePool(ImageSectionObject->Segments);
       ExFreePool(ImageSectionObject);
       FileObject->SectionObjectPointer->ImageSectionObject = NULL;
-    }
-  if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
-    {
+   }
+   if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
+   {
       PMM_SECTION_SEGMENT Segment;
 
       Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
-       DataSectionObject;
+                DataSectionObject;
 
       if (Segment->ReferenceCount != 0)
-       {
-         DPRINT1("Data segment still referenced\n");
-         KEBUGCHECK(0);
-       }
+      {
+         DPRINT1("Data segment still referenced\n");
+         KEBUGCHECK(0);
+      }
       MmFreePageTablesSectionSegment(Segment);
       ExFreePool(Segment);
       FileObject->SectionObjectPointer->DataSectionObject = NULL;
-    }
+   }
 }
 
-VOID 
+VOID
+NTAPI
 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment)
 {
    ExAcquireFastMutex(&Segment->Lock);
 }
 
 VOID
+NTAPI
 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment)
 {
    ExReleaseFastMutex(&Segment->Lock);
 }
 
-VOID 
+VOID
+NTAPI
 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
-                            ULONG Offset,
-                            ULONG Entry)
+                             ULONG Offset,
+                             ULONG Entry)
 {
    PSECTION_PAGE_TABLE Table;
    ULONG DirectoryOffset;
    ULONG TableOffset;
 
    if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
-     {
-       Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
-     }
+   {
+      Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
+   }
    else
-     {
-       DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
-       Table = Segment->PageDirectory.PageTables[DirectoryOffset];
-       if (Table == NULL)
+   {
+      DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
+      Table = Segment->PageDirectory.PageTables[DirectoryOffset];
+      if (Table == NULL)
+      {
+         Table =
+            Segment->PageDirectory.PageTables[DirectoryOffset] =
+               ExAllocatePoolWithTag(PagedPool, sizeof(SECTION_PAGE_TABLE),
+                                     TAG_SECTION_PAGE_TABLE);
+         if (Table == NULL)
          {
-          Table = 
-           Segment->PageDirectory.PageTables[DirectoryOffset] =
-            ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_PAGE_TABLE),
-                                  TAG_SECTION_PAGE_TABLE);
-          if (Table == NULL)
-            {
-               KEBUGCHECK(0);
-            }
-          memset(Table, 0, sizeof(SECTION_PAGE_TABLE));
-          DPRINT("Table %x\n", Table);
-        }
-     }
+            KEBUGCHECK(0);
+         }
+         memset(Table, 0, sizeof(SECTION_PAGE_TABLE));
+         DPRINT("Table %x\n", Table);
+      }
+   }
    TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
    Table->Entry[TableOffset] = Entry;
 }
 
 
-ULONG 
+ULONG
+NTAPI
 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
-                            ULONG Offset)
+                             ULONG Offset)
 {
    PSECTION_PAGE_TABLE Table;
    ULONG Entry;
    ULONG DirectoryOffset;
    ULONG TableOffset;
-   
+
    DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset);
-   
+
    if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
-     {
-       Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
-     }
+   {
+      Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
+   }
    else
-     {
-       DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
-       Table = Segment->PageDirectory.PageTables[DirectoryOffset];
-       DPRINT("Table %x\n", Table);
-       if (Table == NULL)
-         {
-          return(0);
-         }
-     }
+   {
+      DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
+      Table = Segment->PageDirectory.PageTables[DirectoryOffset];
+      DPRINT("Table %x\n", Table);
+      if (Table == NULL)
+      {
+         return(0);
+      }
+   }
    TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
    Entry = Table->Entry[TableOffset];
    return(Entry);
 }
 
 VOID
+NTAPI
 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
-                              ULONG Offset)
+                               ULONG Offset)
 {
-  ULONG Entry;
+   ULONG Entry;
 
-  Entry = MmGetPageEntrySectionSegment(Segment, Offset);
-  if (Entry == 0)
-    {
+   Entry = MmGetPageEntrySectionSegment(Segment, Offset);
+   if (Entry == 0)
+   {
       DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
       KEBUGCHECK(0);
-    }
-  if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
-    {
+   }
+   if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
+   {
       DPRINT1("Maximum share count reached\n");
       KEBUGCHECK(0);
-    }
-  if (IS_SWAP_FROM_SSE(Entry))
-    {
+   }
+   if (IS_SWAP_FROM_SSE(Entry))
+   {
       KEBUGCHECK(0);
-    }
-  Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1);
-  MmSetPageEntrySectionSegment(Segment, Offset, Entry);
+   }
+   Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1);
+   MmSetPageEntrySectionSegment(Segment, Offset, Entry);
 }
 
 BOOLEAN
+NTAPI
 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
-                                PMM_SECTION_SEGMENT Segment,
-                                ULONG Offset,
-                                BOOLEAN Dirty)
+                                 PMM_SECTION_SEGMENT Segment,
+                                 ULONG Offset,
+                                 BOOLEAN Dirty,
+                                 BOOLEAN PageOut)
 {
-  ULONG Entry;
+   ULONG Entry;
+   BOOLEAN IsDirectMapped = FALSE;
 
-  Entry = MmGetPageEntrySectionSegment(Segment, Offset);
-  if (Entry == 0)
-    {
-      DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
+   Entry = MmGetPageEntrySectionSegment(Segment, Offset);
+   if (Entry == 0)
+   {
+      DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
       KEBUGCHECK(0);
-    }
-  if (SHARE_COUNT_FROM_SSE(Entry) == 0)
-    {
+   }
+   if (SHARE_COUNT_FROM_SSE(Entry) == 0)
+   {
       DPRINT1("Zero share count for unshare\n");
       KEBUGCHECK(0);
-    }
-  if (IS_SWAP_FROM_SSE(Entry))
-    {
+   }
+   if (IS_SWAP_FROM_SSE(Entry))
+   {
       KEBUGCHECK(0);
-    }
-  Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1);
-  /*
-   * If we reducing the share count of this entry to zero then set the entry 
-   * to zero and tell the cache the page is no longer mapped.
-   */
-  if (SHARE_COUNT_FROM_SSE(Entry) == 0)
-    {
+   }
+   Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1);
+   /*
+    * If we reducing the share count of this entry to zero then set the entry
+    * to zero and tell the cache the page is no longer mapped.
+    */
+   if (SHARE_COUNT_FROM_SSE(Entry) == 0)
+   {
       PFILE_OBJECT FileObject;
       PBCB Bcb;
       SWAPENTRY SavedSwapEntry;
-      PHYSICAL_ADDRESS Page;
+      PFN_TYPE Page;
       BOOLEAN IsImageSection;
       ULONG FileOffset;
 
       FileOffset = Offset + Segment->FileOffset;
-   
+
       IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
-    
-      Page = (PHYSICAL_ADDRESS)(LONGLONG)PAGE_FROM_SSE(Entry);
+
+      Page = PFN_FROM_SSE(Entry);
       FileObject = Section->FileObject;
-      if (FileObject != NULL)
-       {
-
-         if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
-             (FileOffset % PAGE_SIZE) == 0 &&
-              (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
-           {
-             NTSTATUS Status;
-              Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
-             Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty);
-             if (!NT_SUCCESS(Status))
-               {
-                 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
-                 KEBUGCHECK(0);
-               }
-           }
-       }
+      if (FileObject != NULL &&
+            !(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
+      {
+
+         if ((FileOffset % PAGE_SIZE) == 0 &&
+               (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
+         {
+            NTSTATUS Status;
+            Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
+            IsDirectMapped = TRUE;
+            Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty);
+            if (!NT_SUCCESS(Status))
+            {
+               DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
+               KEBUGCHECK(0);
+            }
+         }
+      }
 
       SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
       if (SavedSwapEntry == 0)
-        {
-         if (Segment->Flags & MM_PAGEFILE_SEGMENT)
+      {
+         if (!PageOut &&
+               ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
+                (Segment->Characteristics & IMAGE_SCN_MEM_SHARED)))
+         {
+            /*
+             * FIXME:
+             *   Try to page out this page and set the swap entry
+             *   within the section segment. There exist no rmap entry
+             *   for this page. The pager thread can't page out a
+             *   page without a rmap entry.
+             */
+            MmSetPageEntrySectionSegment(Segment, Offset, Entry);
+         }
+         else
+         {
+            MmSetPageEntrySectionSegment(Segment, Offset, 0);
+            if (!IsDirectMapped)
             {
-             /* 
-              * FIXME:
-              *   Try to page out this page and set the swap entry 
-              *   within the section segment. There exist no rmap entry
-              *   for this page. The pager thread can't page out a 
-              *   page without a rmap entry.
-              */
-             MmSetPageEntrySectionSegment(Segment, Offset, Entry);
-             MmReferencePage(Page);
-           }
-         else
-           {
-             MmSetPageEntrySectionSegment(Segment, Offset, 0);
-           }
-       }
+               MmReleasePageMemoryConsumer(MC_USER, Page);
+            }
+         }
+      }
       else
-       {
-         MmSetSavedSwapEntryPage(Page, 0);
-         if (Segment->Flags & MM_PAGEFILE_SEGMENT)
-           {
-             MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry));
-           }
-         else
-           {
-             MmSetPageEntrySectionSegment(Segment, Offset, 0);
-             MmFreeSwapPage(SavedSwapEntry);
-           }
-       }
-    }
-  else
-    {
+      {
+         if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
+               (Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
+         {
+            if (!PageOut)
+            {
+               if (Dirty)
+               {
+                  /*
+                   * FIXME:
+                   *   We hold all locks. Nobody can do something with the current
+                   *   process and the current segment (also not within an other process).
+                   */
+                  NTSTATUS Status;
+                  Status = MmWriteToSwapPage(SavedSwapEntry, Page);
+                  if (!NT_SUCCESS(Status))
+                  {
+                     DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status);
+                     KEBUGCHECK(0);
+                  }
+               }
+               MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry));
+               MmSetSavedSwapEntryPage(Page, 0);
+            }
+            MmReleasePageMemoryConsumer(MC_USER, Page);
+         }
+         else
+         {
+            DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
+            KEBUGCHECK(0);
+         }
+      }
+   }
+   else
+   {
       MmSetPageEntrySectionSegment(Segment, Offset, Entry);
-    }
-  return(SHARE_COUNT_FROM_SSE(Entry) > 0);
+   }
+   return(SHARE_COUNT_FROM_SSE(Entry) > 0);
 }
 
 BOOL MiIsPageFromCache(PMEMORY_AREA MemoryArea,
-                      ULONG SegOffset)
+                       ULONG SegOffset)
 {
-  PBCB Bcb;
-  PCACHE_SEGMENT CacheSeg;
-
-  Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap;
-  CacheSeg = CcRosLookupCacheSegment(Bcb, SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset);
-  if (CacheSeg)
-  {
-     CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE);
-     return TRUE;
-  }
-  return FALSE;
+   if (!(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
+   {
+      PBCB Bcb;
+      PCACHE_SEGMENT CacheSeg;
+      Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap;
+      CacheSeg = CcRosLookupCacheSegment(Bcb, SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset);
+      if (CacheSeg)
+      {
+         CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE);
+         return TRUE;
+      }
+   }
+   return FALSE;
 }
 
 NTSTATUS
+NTAPI
 MiReadPage(PMEMORY_AREA MemoryArea,
-          ULONG SegOffset,
-          PHYSICAL_ADDRESS* Page)
-     /*
     * FUNCTION: Read a page for a section backed memory area.
     * PARAMETERS:
     *       MemoryArea - Memory area to read the page for.
     *       Offset - Offset of the page to read.
     *       Page - Variable that receives a page contains the read data.
     */
+           ULONG SegOffset,
+           PPFN_TYPE Page)
+/*
+ * FUNCTION: Read a page for a section backed memory area.
+ * PARAMETERS:
+ *       MemoryArea - Memory area to read the page for.
+ *       Offset - Offset of the page to read.
+ *       Page - Variable that receives a page contains the read data.
+ */
 {
-  ULONG BaseOffset;
-  ULONG FileOffset;
-  PVOID BaseAddress;
-  BOOLEAN UptoDate;
-  PCACHE_SEGMENT CacheSeg;
-  PFILE_OBJECT FileObject;
-  NTSTATUS Status;
-  ULONG RawLength;
-  PBCB Bcb;
-  BOOLEAN IsImageSection;
-  ULONG Length;
-  FileObject = MemoryArea->Data.SectionData.Section->FileObject;
-  Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
-  RawLength = MemoryArea->Data.SectionData.Segment->RawLength;
-  FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset;
-  IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
-  
-  assert(Bcb);
+   ULONG BaseOffset;
+   ULONG FileOffset;
+   PVOID BaseAddress;
+   BOOLEAN UptoDate;
+   PCACHE_SEGMENT CacheSeg;
+   PFILE_OBJECT FileObject;
+   NTSTATUS Status;
+   ULONG RawLength;
+   PBCB Bcb;
+   BOOLEAN IsImageSection;
+   ULONG Length;
 
-  DPRINT("%S %x\n", FileObject->FileName.Buffer, FileOffset);
+   FileObject = MemoryArea->Data.SectionData.Section->FileObject;
+   Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
+   RawLength = MemoryArea->Data.SectionData.Segment->RawLength;
+   FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset;
+   IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
 
-  /*
-   * If the file system is letting us go directly to the cache and the
-   * memory area was mapped at an offset in the file which is page aligned
-   * then get the related cache segment.
-   */
-  if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
-      (FileOffset % PAGE_SIZE) == 0 &&
-      (SegOffset + PAGE_SIZE <= RawLength || !IsImageSection))
-    {
-      PHYSICAL_ADDRESS Addr;
+   ASSERT(Bcb);
+
+   DPRINT("%S %x\n", FileObject->FileName.Buffer, FileOffset);
+
+   /*
+    * If the file system is letting us go directly to the cache and the
+    * memory area was mapped at an offset in the file which is page aligned
+    * then get the related cache segment.
+    */
+   if ((FileOffset % PAGE_SIZE) == 0 &&
+       (SegOffset + PAGE_SIZE <= RawLength || !IsImageSection) &&
+       !(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
+   {
 
       /*
        * Get the related cache segment; we use a lower level interface than
@@ -408,40 +510,38 @@ MiReadPage(PMEMORY_AREA MemoryArea,
        * alignment less than the file system block size.
        */
       Status = CcRosGetCacheSegment(Bcb,
-                                   FileOffset,
-                                   &BaseOffset,
-                                   &BaseAddress,
-                                   &UptoDate,
-                                   &CacheSeg);
+                                    FileOffset,
+                                    &BaseOffset,
+                                    &BaseAddress,
+                                    &UptoDate,
+                                    &CacheSeg);
       if (!NT_SUCCESS(Status))
-       {
-         return(Status);
-       }
+      {
+         return(Status);
+      }
       if (!UptoDate)
-       {
-         /*
-          * If the cache segment isn't up to date then call the file
-          * system to read in the data.
-          */
-          Status = ReadCacheSegment(CacheSeg);
-         if (!NT_SUCCESS(Status))
-         {
-             CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
-             return Status;
-         }
-       }
+      {
+         /*
+          * If the cache segment isn't up to date then call the file
+          * system to read in the data.
+          */
+         Status = ReadCacheSegment(CacheSeg);
+         if (!NT_SUCCESS(Status))
+         {
+            CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
+            return Status;
+         }
+      }
       /*
        * Retrieve the page from the cache segment that we actually want.
        */
-      Addr = MmGetPhysicalAddress(BaseAddress +
-                                 FileOffset - BaseOffset);
-      (*Page) = Addr;
-      MmReferencePage((*Page));
+      (*Page) = MmGetPhysicalAddress((char*)BaseAddress +
+                                     FileOffset - BaseOffset).QuadPart >> PAGE_SHIFT;
 
       CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, TRUE);
-    }
-  else
-    {
+   }
+   else
+   {
       PVOID PageAddr;
       ULONG CacheSegOffset;
       /*
@@ -450,97 +550,98 @@ MiReadPage(PMEMORY_AREA MemoryArea,
        */
       Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
       if (!NT_SUCCESS(Status))
-       {
-         return(Status);
-       }
+      {
+         return(Status);
+      }
       Status = CcRosGetCacheSegment(Bcb,
-                                   FileOffset,
-                                   &BaseOffset,
-                                   &BaseAddress,
-                                   &UptoDate,
-                                   &CacheSeg);
+                                    FileOffset,
+                                    &BaseOffset,
+                                    &BaseAddress,
+                                    &UptoDate,
+                                    &CacheSeg);
       if (!NT_SUCCESS(Status))
-       {
-         return(Status);
-       }
+      {
+         return(Status);
+      }
       if (!UptoDate)
-       {
-         /*
-          * If the cache segment isn't up to date then call the file
-          * system to read in the data.
-          */
-          Status = ReadCacheSegment(CacheSeg);
-         if (!NT_SUCCESS(Status))
-         {
-             CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
-             return Status;
-         }
-       }
-      PageAddr = ExAllocatePageWithPhysPage(*Page);
+      {
+         /*
+          * If the cache segment isn't up to date then call the file
+          * system to read in the data.
+          */
+         Status = ReadCacheSegment(CacheSeg);
+         if (!NT_SUCCESS(Status))
+         {
+            CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
+            return Status;
+         }
+      }
+      PageAddr = MmCreateHyperspaceMapping(*Page);
       CacheSegOffset = BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset;
       Length = RawLength - SegOffset;
       if (Length <= CacheSegOffset && Length <= PAGE_SIZE)
       {
-         memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, Length);
+         memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, Length);
       }
       else if (CacheSegOffset >= PAGE_SIZE)
       {
-         memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, PAGE_SIZE);
+         memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, PAGE_SIZE);
       }
       else
       {
-        memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, CacheSegOffset);
+         memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, CacheSegOffset);
          CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
-        Status = CcRosGetCacheSegment(Bcb,
-                                      FileOffset + CacheSegOffset,
-                                      &BaseOffset,
-                                      &BaseAddress,
-                                      &UptoDate,
-                                      &CacheSeg);
+         Status = CcRosGetCacheSegment(Bcb,
+                                       FileOffset + CacheSegOffset,
+                                       &BaseOffset,
+                                       &BaseAddress,
+                                       &UptoDate,
+                                       &CacheSeg);
          if (!NT_SUCCESS(Status))
-          {
-            ExUnmapPage(PageAddr);
-            return(Status);
-          }
+         {
+            MmDeleteHyperspaceMapping(PageAddr);
+            return(Status);
+         }
          if (!UptoDate)
-          {
-            /*
-             * If the cache segment isn't up to date then call the file
-             * system to read in the data.
-             */
-             Status = ReadCacheSegment(CacheSeg);
-            if (!NT_SUCCESS(Status))
-              {
-                CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
-                ExUnmapPage(PageAddr);
-                return Status;
-              }
-          }
+         {
+            /*
+             * If the cache segment isn't up to date then call the file
+             * system to read in the data.
+             */
+            Status = ReadCacheSegment(CacheSeg);
+            if (!NT_SUCCESS(Status))
+            {
+               CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
+               MmDeleteHyperspaceMapping(PageAddr);
+               return Status;
+            }
+         }
          if (Length < PAGE_SIZE)
-        {
-           memcpy(PageAddr + CacheSegOffset, BaseAddress, Length - CacheSegOffset);
-        }
-        else
-        {
-            memcpy(PageAddr + CacheSegOffset, BaseAddress, PAGE_SIZE - CacheSegOffset);
-        }
+         {
+            memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, Length - CacheSegOffset);
+         }
+         else
+         {
+            memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, PAGE_SIZE - CacheSegOffset);
+         }
       }
       CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
-      ExUnmapPage(PageAddr);
-    }
-  return(STATUS_SUCCESS);
+      MmDeleteHyperspaceMapping(PageAddr);
+   }
+   return(STATUS_SUCCESS);
 }
 
 NTSTATUS
+NTAPI
 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
-                            MEMORY_AREA* MemoryArea,
-                            PVOID Address,
-                            BOOLEAN Locked)
+                             MEMORY_AREA* MemoryArea,
+                             PVOID Address,
+                             BOOLEAN Locked)
 {
    ULONG Offset;
-   LARGE_INTEGER Page;
+   PFN_TYPE Page;
    NTSTATUS Status;
-   ULONG PAddress;
+   PVOID PAddress;
    PSECTION_OBJECT Section;
    PMM_SECTION_SEGMENT Segment;
    ULONG Entry;
@@ -548,7 +649,7 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
    ULONG Attributes;
    PMM_PAGEOP PageOp;
    PMM_REGION Region;
-   LARGE_INTEGER Timeout;
+   BOOL HasSwapEntry;
 
    /*
     * There is a window between taking the page fault and locking the
@@ -556,22 +657,23 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
     * that.
     */
    if (MmIsPagePresent(AddressSpace->Process, Address))
-     {
-       if (Locked)
-         {
-           MmLockPage(MmGetPhysicalAddressForProcess(AddressSpace->Process, Address));
-         }  
-       return(STATUS_SUCCESS);
-     }
-   
-   PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
-   Offset = PAddress - (ULONG)MemoryArea->BaseAddress;
-   
+   {
+      if (Locked)
+      {
+         MmLockPage(MmGetPfnForProcess(AddressSpace->Process, Address));
+      }
+      return(STATUS_SUCCESS);
+   }
+
+   PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
+   Offset = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress 
+            + MemoryArea->Data.SectionData.ViewOffset;
+
    Segment = MemoryArea->Data.SectionData.Segment;
    Section = MemoryArea->Data.SectionData.Section;
-   Region = MmFindRegion(MemoryArea->BaseAddress,
-                        &MemoryArea->Data.SectionData.RegionListHead, 
-                        Address, NULL);
+   Region = MmFindRegion(MemoryArea->StartingAddress,
+                         &MemoryArea->Data.SectionData.RegionListHead,
+                         Address, NULL);
    /*
     * Lock the segment
     */
@@ -582,667 +684,580 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
     */
    if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
        (Region->Protect == PAGE_READWRITE ||
-       Region->Protect == PAGE_EXECUTE_READWRITE))
-     {
-       Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
-     }
+       Region->Protect == PAGE_EXECUTE_READWRITE))
+   {
+      Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
+   }
    else
-     {
-       Attributes = Region->Protect;
-     }
-   
+   {
+      Attributes = Region->Protect;
+   }
+
    /*
     * Get or create a page operation descriptor
     */
-   PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset, MM_PAGEOP_PAGEIN);
+   PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset, MM_PAGEOP_PAGEIN, FALSE);
    if (PageOp == NULL)
-     {
-       DPRINT1("MmGetPageOp failed\n");
-       KEBUGCHECK(0);
-     }
+   {
+      DPRINT1("MmGetPageOp failed\n");
+      KEBUGCHECK(0);
+   }
 
    /*
     * Check if someone else is already handling this fault, if so wait
     * for them
     */
    if (PageOp->Thread != PsGetCurrentThread())
-     {
-       MmUnlockSectionSegment(Segment);
-       MmUnlockAddressSpace(AddressSpace);
-       Timeout.QuadPart = -100000000LL;        // 10 sec
-       Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
-                                     0,
-                                     KernelMode,
-                                     FALSE,
-                                     &Timeout);
-
-       /*
-       * Check for various strange conditions
-       */
-       if (Status != STATUS_SUCCESS)
-        {
-          DPRINT1("Failed to wait for page op, status = %x\n", Status);
-          KEBUGCHECK(0);
-        }
-       if (PageOp->Status == STATUS_PENDING)
-        {
-          DPRINT1("Woke for page op before completion\n");
-          KEBUGCHECK(0);
-        }
-       MmLockAddressSpace(AddressSpace);
-       /*
-       * If this wasn't a pagein then restart the operation
-       */
-       if (PageOp->OpType != MM_PAGEOP_PAGEIN)
-        {
-           KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-          MmReleasePageOp(PageOp);
-          DPRINT("Address 0x%.8X\n", Address);
-          return(STATUS_MM_RESTART_OPERATION);
-        }
-       
-       /*
-       * If the thread handling this fault has failed then we don't retry
-       */
-       if (!NT_SUCCESS(PageOp->Status))
-        {
-          Status = PageOp->Status;
-          KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-          MmReleasePageOp(PageOp);
-          DPRINT("Address 0x%.8X\n", Address);
-          return(Status);
-        }
-       MmLockSectionSegment(Segment);
-       /*
-       * If the completed fault was for another address space then set the 
-       * page in this one.
-       */
-       if (!MmIsPagePresent(AddressSpace->Process, Address))
-        {
-          Entry = MmGetPageEntrySectionSegment(Segment, Offset);
-          if (Entry == 0)
-          {
-               MmUnlockSectionSegment(Segment);
-                KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-               MmReleasePageOp(PageOp);
-               return(STATUS_MM_RESTART_OPERATION);
-          } 
-
-          Page = (LARGE_INTEGER)(LONGLONG)(PAGE_FROM_SSE(Entry));
-          MmReferencePage(Page);       
-          MmSharePageEntrySectionSegment(Segment, Offset);
-
-          Status = MmCreateVirtualMapping(MemoryArea->Process,
-                                          Address,
-                                          Attributes,
-                                          Page,
-                                          FALSE);
-          if (Status == STATUS_NO_MEMORY)
-            {
-              MmUnlockAddressSpace(AddressSpace);
-              Status = MmCreateVirtualMapping(MemoryArea->Process,
-                                              Address,
-                                              Attributes,
-                                              Page,
-                                              TRUE);
-              MmLockAddressSpace(AddressSpace);
-            }
-
-          if (!NT_SUCCESS(Status))
-            {
-              DbgPrint("Unable to create virtual mapping\n");
-              KEBUGCHECK(0);
-            }
-          MmInsertRmap(Page, MemoryArea->Process, (PVOID)PAddress);
-        }
-       if (Locked)
-        {
-          MmLockPage(Page);
-        }
-       MmUnlockSectionSegment(Segment);
-       PageOp->Status = STATUS_SUCCESS;
-       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-       MmReleasePageOp(PageOp);
-       DPRINT("Address 0x%.8X\n", Address);
-       return(STATUS_SUCCESS);
-     }
+   {
+      MmUnlockSectionSegment(Segment);
+      MmUnlockAddressSpace(AddressSpace);
+      Status = MmspWaitForPageOpCompletionEvent(PageOp);
+      /*
+      * Check for various strange conditions
+      */
+      if (Status != STATUS_SUCCESS)
+      {
+         DPRINT1("Failed to wait for page op, status = %x\n", Status);
+         KEBUGCHECK(0);
+      }
+      if (PageOp->Status == STATUS_PENDING)
+      {
+         DPRINT1("Woke for page op before completion\n");
+         KEBUGCHECK(0);
+      }
+      MmLockAddressSpace(AddressSpace);
+      /*
+      * If this wasn't a pagein then restart the operation
+      */
+      if (PageOp->OpType != MM_PAGEOP_PAGEIN)
+      {
+         MmspCompleteAndReleasePageOp(PageOp);
+         DPRINT("Address 0x%.8X\n", Address);
+         return(STATUS_MM_RESTART_OPERATION);
+      }
 
-   /*
-    * Must be private page we have swapped out.
-    */
-   if (MmIsPageSwapEntry(AddressSpace->Process, (PVOID)PAddress))
-     {
-       SWAPENTRY SwapEntry;
-       PMDL Mdl;
+      /*
+      * If the thread handling this fault has failed then we don't retry
+      */
+      if (!NT_SUCCESS(PageOp->Status))
+      {
+         Status = PageOp->Status;
+         MmspCompleteAndReleasePageOp(PageOp);
+         DPRINT("Address 0x%.8X\n", Address);
+         return(Status);
+      }
+      MmLockSectionSegment(Segment);
+      /*
+      * If the completed fault was for another address space then set the
+      * page in this one.
+      */
+      if (!MmIsPagePresent(AddressSpace->Process, Address))
+      {
+         Entry = MmGetPageEntrySectionSegment(Segment, Offset);
+         HasSwapEntry = MmIsPageSwapEntry(AddressSpace->Process, (PVOID)PAddress);
 
-       /*
-        * Sanity check
-       */
-       if (Segment->Flags & MM_PAGEFILE_SEGMENT)
+         if (PAGE_FROM_SSE(Entry) == 0 || HasSwapEntry)
          {
-          DPRINT1("Found a swaped out private page in a pagefile section.\n");
-          KEBUGCHECK(0);
-        }
-
-       MmUnlockSectionSegment(Segment);
-       MmDeletePageFileMapping(AddressSpace->Process, (PVOID)PAddress, &SwapEntry);
-
-       MmUnlockAddressSpace(AddressSpace);
-       Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
-       if (!NT_SUCCESS(Status))
-        {
-          KEBUGCHECK(0);
-        }
-
-       Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
-       MmBuildMdlFromPages(Mdl, (PULONG)&Page);
-       Status = MmReadFromSwapPage(SwapEntry, Mdl);
-       if (!NT_SUCCESS(Status))
-        {
-          DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
-          KEBUGCHECK(0);
-        }
-       MmLockAddressSpace(AddressSpace);
-       Status = MmCreateVirtualMapping(AddressSpace->Process,                
-                                      Address,
-                                      Region->Protect,
-                                      Page,
-                                      FALSE);
-       if (Status == STATUS_NO_MEMORY)
-        {
-          MmUnlockAddressSpace(AddressSpace);     
-          Status = MmCreateVirtualMapping(AddressSpace->Process,
-                                          Address,
-                                          Region->Protect,
-                                          Page,
-                                          TRUE);
-          MmLockAddressSpace(AddressSpace);
-        }  
-       if (!NT_SUCCESS(Status))
-        {
-          DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
-          KEBUGCHECK(0);
-          return(Status);
-        }
-
-       /*
-       * Store the swap entry for later use.
-       */
-       MmSetSavedSwapEntryPage(Page, SwapEntry);
-       
-       /*
-       * Add the page to the process's working set
-       */
-       MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
-       
-       /*
-       * Finish the operation
-       */
-       if (Locked)
-        {
-          MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
-        }  
-       PageOp->Status = STATUS_SUCCESS;
-       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-       MmReleasePageOp(PageOp);
-       DPRINT("Address 0x%.8X\n", Address);
-       return(STATUS_SUCCESS);
-     }
+            /*
+             * The page was a private page in another or in our address space
+            */
+            MmUnlockSectionSegment(Segment);
+            MmspCompleteAndReleasePageOp(PageOp);
+            return(STATUS_MM_RESTART_OPERATION);
+         }
 
-   /*
-    * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
-    */
-   if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
-     {
-       MmUnlockSectionSegment(Segment);
-       /*
-       * Just map the desired physical page 
-       */
-       Page.QuadPart = Offset + MemoryArea->Data.SectionData.ViewOffset;
-       Status = MmCreateVirtualMapping(AddressSpace->Process,
-                                      Address,
-                                      Region->Protect,
-                                      Page,
-                                      FALSE);
-       if (Status == STATUS_NO_MEMORY)
-        {
-          MmUnlockAddressSpace(AddressSpace);     
-          Status = MmCreateVirtualMapping(AddressSpace->Process,
-                                          Address,
-                                          Region->Protect,
-                                          Page,
-                                          TRUE);
-          MmLockAddressSpace(AddressSpace);
-        }  
-       if (!NT_SUCCESS(Status))
-        {
-          DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
-          KEBUGCHECK(0);
-          return(Status);
-        }
-       /* 
-        * Don't add an rmap entry since the page mapped could be for 
-       * anything. 
-       */
-       if (Locked)
-        {
-          MmLockPage(Page);
-        }  
-
-       /*
-       * Cleanup and release locks
-       */
-       PageOp->Status = STATUS_SUCCESS;
-       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-       MmReleasePageOp(PageOp);
-       DPRINT("Address 0x%.8X\n", Address);
-       return(STATUS_SUCCESS);
-     }
-   
-   /*
-    * Map anonymous memory for BSS sections
-    */
-   if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS)
-     {
-       MmUnlockSectionSegment(Segment);
-       Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
-       if (!NT_SUCCESS(Status))
-        {
-          MmUnlockAddressSpace(AddressSpace);     
-          Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
-          MmLockAddressSpace(AddressSpace);
-        }
-       if (!NT_SUCCESS(Status))
+         Page = PFN_FROM_SSE(Entry);
+
+         MmSharePageEntrySectionSegment(Segment, Offset);
+
+         /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
+          * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
+          */
+         Status = MmCreateVirtualMapping(AddressSpace->Process,
+                                         Address,
+                                         Attributes,
+                                         &Page,
+                                         1);
+         if (!NT_SUCCESS(Status))
          {
-           KEBUGCHECK(0);
+            DbgPrint("Unable to create virtual mapping\n");
+            KEBUGCHECK(0);
          }
-       Status = MmCreateVirtualMapping(AddressSpace->Process,
-                                      Address,
-                                      Region->Protect,
-                                      Page,
-                                      FALSE);
-       if (Status == STATUS_NO_MEMORY)
-        {
-          MmUnlockAddressSpace(AddressSpace);     
-          Status = MmCreateVirtualMapping(AddressSpace->Process,
-                                          Address,
-                                          Region->Protect,
-                                          Page,
-                                          TRUE);
-          MmLockAddressSpace(AddressSpace);
-        }  
-
-       if (!NT_SUCCESS(Status))
-        {
-          DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
-          KEBUGCHECK(0);
-          return(Status);
-        }
-       MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
-       if (Locked)
-        {
-          MmLockPage(Page);
-        }  
-
-       /*
-       * Cleanup and release locks
-       */
-       PageOp->Status = STATUS_SUCCESS;
-       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-       MmReleasePageOp(PageOp);
-       DPRINT("Address 0x%.8X\n", Address);
-       return(STATUS_SUCCESS);
-     }
-
-   /*
+         MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
+      }
+      if (Locked)
+      {
+         MmLockPage(Page);
+      }
+      MmUnlockSectionSegment(Segment);
+      PageOp->Status = STATUS_SUCCESS;
+      MmspCompleteAndReleasePageOp(PageOp);
+      DPRINT("Address 0x%.8X\n", Address);
+      return(STATUS_SUCCESS);
+   }
+
+   HasSwapEntry = MmIsPageSwapEntry(AddressSpace->Process, (PVOID)PAddress);
+   if (HasSwapEntry)
+   {
+      /*
+       * Must be private page we have swapped out.
+       */
+      SWAPENTRY SwapEntry;
+
+      /*
+       * Sanity check
+      */
+      if (Segment->Flags & MM_PAGEFILE_SEGMENT)
+      {
+         DPRINT1("Found a swaped out private page in a pagefile section.\n");
+         KEBUGCHECK(0);
+      }
+
+      MmUnlockSectionSegment(Segment);
+      MmDeletePageFileMapping(AddressSpace->Process, (PVOID)PAddress, &SwapEntry);
+
+      MmUnlockAddressSpace(AddressSpace);
+      Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
+      if (!NT_SUCCESS(Status))
+      {
+         KEBUGCHECK(0);
+      }
+
+      Status = MmReadFromSwapPage(SwapEntry, Page);
+      if (!NT_SUCCESS(Status))
+      {
+         DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
+         KEBUGCHECK(0);
+      }
+      MmLockAddressSpace(AddressSpace);
+      Status = MmCreateVirtualMapping(AddressSpace->Process,
+                                      Address,
+                                      Region->Protect,
+                                      &Page,
+                                      1);
+      if (!NT_SUCCESS(Status))
+      {
+         DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
+         KEBUGCHECK(0);
+         return(Status);
+      }
+
+      /*
+       * Store the swap entry for later use.
+       */
+      MmSetSavedSwapEntryPage(Page, SwapEntry);
+
+      /*
+      * Add the page to the process's working set
+      */
+      MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
+
+      /*
+      * Finish the operation
+      */
+      if (Locked)
+      {
+         MmLockPage(Page);
+      }
+      PageOp->Status = STATUS_SUCCESS;
+      MmspCompleteAndReleasePageOp(PageOp);
+      DPRINT("Address 0x%.8X\n", Address);
+      return(STATUS_SUCCESS);
+   }
+
+   /*
+    * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
+    */
+   if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
+   {
+      MmUnlockSectionSegment(Segment);
+      /*
+      * Just map the desired physical page
+      */
+      Page = Offset >> PAGE_SHIFT;
+      Status = MmCreateVirtualMappingUnsafe(AddressSpace->Process,
+                                            Address,
+                                            Region->Protect,
+                                            &Page,
+                                            1);
+      if (!NT_SUCCESS(Status))
+      {
+         DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
+         KEBUGCHECK(0);
+         return(Status);
+      }
+      /*
+       * Don't add an rmap entry since the page mapped could be for
+      * anything.
+      */
+      if (Locked)
+      {
+         MmLockPageUnsafe(Page);
+      }
+
+      /*
+      * Cleanup and release locks
+      */
+      PageOp->Status = STATUS_SUCCESS;
+      MmspCompleteAndReleasePageOp(PageOp);
+      DPRINT("Address 0x%.8X\n", Address);
+      return(STATUS_SUCCESS);
+   }
+
+   /*
+    * Map anonymous memory for BSS sections
+    */
+   if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+   {
+      MmUnlockSectionSegment(Segment);
+      Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
+      if (!NT_SUCCESS(Status))
+      {
+         MmUnlockAddressSpace(AddressSpace);
+         Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
+         MmLockAddressSpace(AddressSpace);
+      }
+      if (!NT_SUCCESS(Status))
+      {
+         KEBUGCHECK(0);
+      }
+      Status = MmCreateVirtualMapping(AddressSpace->Process,
+                                      Address,
+                                      Region->Protect,
+                                      &Page,
+                                      1);
+      if (!NT_SUCCESS(Status))
+      {
+         DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
+         KEBUGCHECK(0);
+         return(Status);
+      }
+      MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
+      if (Locked)
+      {
+         MmLockPage(Page);
+      }
+
+      /*
+      * Cleanup and release locks
+      */
+      PageOp->Status = STATUS_SUCCESS;
+      MmspCompleteAndReleasePageOp(PageOp);
+      DPRINT("Address 0x%.8X\n", Address);
+      return(STATUS_SUCCESS);
+   }
+
+   /*
     * Get the entry corresponding to the offset within the section
     */
    Entry = MmGetPageEntrySectionSegment(Segment, Offset);
-   
+
    if (Entry == 0)
-     {   
-       /*
-       * If the entry is zero (and it can't change because we have
-       * locked the segment) then we need to load the page.
-       */
-
-       /*
-       * Release all our locks and read in the page from disk
-       */
-       MmUnlockSectionSegment(Segment);
-       MmUnlockAddressSpace(AddressSpace);
-
-       if ((Segment->Flags & MM_PAGEFILE_SEGMENT) || 
-          (Offset >= PAGE_ROUND_UP(Segment->RawLength) && Section->AllocationAttributes & SEC_IMAGE))
-        {
-          Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
-          if (!NT_SUCCESS(Status))
-            {
-              DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
-            }
-        }
-       else
-         {
-           Status = MiReadPage(MemoryArea, Offset, &Page);
-          if (!NT_SUCCESS(Status))
-            {
-              DPRINT1("MiReadPage failed (Status %x)\n", Status);
-            }
-        }
-       if (!NT_SUCCESS(Status))
-        {
-          /*
-           * FIXME: What do we know in this case?
-           */
-          /*
-           * Cleanup and release locks
-           */
-          MmLockAddressSpace(AddressSpace);
-          PageOp->Status = Status;
-          KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-          MmReleasePageOp(PageOp);
-           DPRINT("Address 0x%.8X\n", Address);
-          return(Status);
-        }
-       /*
-       * Relock the address space and segment
-       */
-       MmLockAddressSpace(AddressSpace);
-       MmLockSectionSegment(Segment);
-       
-       /*
-       * Check the entry. No one should change the status of a page
-       * that has a pending page-in.
-       */
-       Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
-       if (Entry != Entry1)
-        {
-          DbgPrint("Someone changed ppte entry while we slept\n");
-          KEBUGCHECK(0);
-        }
-       
-       /*
-       * Mark the offset within the section as having valid, in-memory
-       * data
-       */
-       Entry = MAKE_SSE(Page.u.LowPart, 1);
-       MmSetPageEntrySectionSegment(Segment, Offset, Entry);
-       MmUnlockSectionSegment(Segment);
-
-       Status = MmCreateVirtualMapping(AddressSpace->Process,
-                                      Address,
-                                      Attributes,
-                                      Page,
-                                      FALSE);
-       if (Status == STATUS_NO_MEMORY)
+   {
+      /*
+      * If the entry is zero (and it can't change because we have
+      * locked the segment) then we need to load the page.
+      */
+
+      /*
+      * Release all our locks and read in the page from disk
+      */
+      MmUnlockSectionSegment(Segment);
+      MmUnlockAddressSpace(AddressSpace);
+
+      if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
+          (Offset >= PAGE_ROUND_UP(Segment->RawLength) && Section->AllocationAttributes & SEC_IMAGE))
+      {
+         Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
+         if (!NT_SUCCESS(Status))
          {
-           MmUnlockAddressSpace(AddressSpace);
-           Status = MmCreateVirtualMapping(AddressSpace->Process,
-                                          Address,
-                                          Attributes,
-                                          Page,
-                                          TRUE);
-           MmLockAddressSpace(AddressSpace);
+            DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
          }
-       if (!NT_SUCCESS(Status))
+      }
+      else
+      {
+         Status = MiReadPage(MemoryArea, Offset, &Page);
+         if (!NT_SUCCESS(Status))
          {
-           DbgPrint("Unable to create virtual mapping\n");
-           KEBUGCHECK(0);
+            DPRINT1("MiReadPage failed (Status %x)\n", Status);
          }
-       MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
-
-       if (Locked)
-        {
-          MmLockPage(Page);
-        }  
-       PageOp->Status = STATUS_SUCCESS;
-       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-       MmReleasePageOp(PageOp);
-       DPRINT("Address 0x%.8X\n", Address);
-       return(STATUS_SUCCESS);
-     }
+      }
+      if (!NT_SUCCESS(Status))
+      {
+         /*
+          * FIXME: What do we know in this case?
+          */
+         /*
+          * Cleanup and release locks
+          */
+         MmLockAddressSpace(AddressSpace);
+         PageOp->Status = Status;
+         MmspCompleteAndReleasePageOp(PageOp);
+         DPRINT("Address 0x%.8X\n", Address);
+         return(Status);
+      }
+      /*
+      * Relock the address space and segment
+      */
+      MmLockAddressSpace(AddressSpace);
+      MmLockSectionSegment(Segment);
+
+      /*
+      * Check the entry. No one should change the status of a page
+      * that has a pending page-in.
+      */
+      Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
+      if (Entry != Entry1)
+      {
+         DbgPrint("Someone changed ppte entry while we slept\n");
+         KEBUGCHECK(0);
+      }
+
+      /*
+      * Mark the offset within the section as having valid, in-memory
+      * data
+      */
+      Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
+      MmSetPageEntrySectionSegment(Segment, Offset, Entry);
+      MmUnlockSectionSegment(Segment);
+
+      Status = MmCreateVirtualMapping(AddressSpace->Process,
+                                      Address,
+                                      Attributes,
+                                      &Page,
+                                      1);
+      if (!NT_SUCCESS(Status))
+      {
+         DbgPrint("Unable to create virtual mapping\n");
+         KEBUGCHECK(0);
+      }
+      MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
+
+      if (Locked)
+      {
+         MmLockPage(Page);
+      }
+      PageOp->Status = STATUS_SUCCESS;
+      MmspCompleteAndReleasePageOp(PageOp);
+      DPRINT("Address 0x%.8X\n", Address);
+      return(STATUS_SUCCESS);
+   }
    else if (IS_SWAP_FROM_SSE(Entry))
-     {
-       SWAPENTRY SwapEntry;
-       PMDL Mdl;
-
-       SwapEntry = SWAPENTRY_FROM_SSE(Entry);
-
-       /*
-       * Release all our locks and read in the page from disk
-       */
-       MmUnlockSectionSegment(Segment);
-
-       MmUnlockAddressSpace(AddressSpace);
-       
-       Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
-       if (!NT_SUCCESS(Status))
-        {
-          KEBUGCHECK(0);
-        }
-
-       Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
-       MmBuildMdlFromPages(Mdl, (PULONG)&Page);
-       Status = MmReadFromSwapPage(SwapEntry, Mdl);
-       if (!NT_SUCCESS(Status))
-        {
-          KEBUGCHECK(0);
-        }
-
-       /*
-       * Relock the address space and segment
-       */
-       MmLockAddressSpace(AddressSpace);
-       MmLockSectionSegment(Segment);
-       
-       /*
-       * Check the entry. No one should change the status of a page
-       * that has a pending page-in.
-       */
-       Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
-       if (Entry != Entry1)
-        {
-          DbgPrint("Someone changed ppte entry while we slept\n");
-          KEBUGCHECK(0);
-        }
-       
-       /*
-       * Mark the offset within the section as having valid, in-memory
-       * data
-       */
-       Entry = MAKE_SSE(Page.u.LowPart, 1);
-       MmSetPageEntrySectionSegment(Segment, Offset, Entry);
-       MmUnlockSectionSegment(Segment);
-
-       /*
-       * Save the swap entry.
-       */
-       MmSetSavedSwapEntryPage(Page, SwapEntry);
-       Status = MmCreateVirtualMapping(AddressSpace->Process,
-                                      Address,
-                                      Region->Protect,
-                                      Page,
-                                      FALSE);
-       if (Status == STATUS_NO_MEMORY)
-         {
-           MmUnlockAddressSpace(AddressSpace);
-           Status = MmCreateVirtualMapping(AddressSpace->Process,
-                                          Address,
-                                          Region->Protect,
-                                          Page,
-                                          TRUE);
-           MmLockAddressSpace(AddressSpace);
-         }
-       if (!NT_SUCCESS(Status))
-         {
-           DbgPrint("Unable to create virtual mapping\n");
-           KEBUGCHECK(0);
-         }
-       MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
-       if (Locked)
-        {
-          MmLockPage(Page);
-        }  
-       PageOp->Status = STATUS_SUCCESS;
-       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-       MmReleasePageOp(PageOp);
-       DPRINT("Address 0x%.8X\n", Address);
-       return(STATUS_SUCCESS);
-     }
+   {
+      SWAPENTRY SwapEntry;
+
+      SwapEntry = SWAPENTRY_FROM_SSE(Entry);
+
+      /*
+      * Release all our locks and read in the page from disk
+      */
+      MmUnlockSectionSegment(Segment);
+
+      MmUnlockAddressSpace(AddressSpace);
+
+      Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
+      if (!NT_SUCCESS(Status))
+      {
+         KEBUGCHECK(0);
+      }
+
+      Status = MmReadFromSwapPage(SwapEntry, Page);
+      if (!NT_SUCCESS(Status))
+      {
+         KEBUGCHECK(0);
+      }
+
+      /*
+      * Relock the address space and segment
+      */
+      MmLockAddressSpace(AddressSpace);
+      MmLockSectionSegment(Segment);
+
+      /*
+      * Check the entry. No one should change the status of a page
+      * that has a pending page-in.
+      */
+      Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
+      if (Entry != Entry1)
+      {
+         DbgPrint("Someone changed ppte entry while we slept\n");
+         KEBUGCHECK(0);
+      }
+
+      /*
+      * Mark the offset within the section as having valid, in-memory
+      * data
+      */
+      Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
+      MmSetPageEntrySectionSegment(Segment, Offset, Entry);
+      MmUnlockSectionSegment(Segment);
+
+      /*
+      * Save the swap entry.
+      */
+      MmSetSavedSwapEntryPage(Page, SwapEntry);
+      Status = MmCreateVirtualMapping(AddressSpace->Process,
+                                      Address,
+                                      Region->Protect,
+                                      &Page,
+                                      1);
+      if (!NT_SUCCESS(Status))
+      {
+         DbgPrint("Unable to create virtual mapping\n");
+         KEBUGCHECK(0);
+      }
+      MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
+      if (Locked)
+      {
+         MmLockPage(Page);
+      }
+      PageOp->Status = STATUS_SUCCESS;
+      MmspCompleteAndReleasePageOp(PageOp);
+      DPRINT("Address 0x%.8X\n", Address);
+      return(STATUS_SUCCESS);
+   }
    else
-     {
-       /*
-        * If the section offset is already in-memory and valid then just
-       * take another reference to the page 
-       */
-       
-       Page = (LARGE_INTEGER)(LONGLONG)PAGE_FROM_SSE(Entry);
-       MmReferencePage(Page);  
-       MmSharePageEntrySectionSegment(Segment, Offset);
-       MmUnlockSectionSegment(Segment);
-
-       Status = MmCreateVirtualMapping(AddressSpace->Process,
-                                      Address,
-                                      Attributes,
-                                      Page,
-                                      FALSE);
-       if (Status == STATUS_NO_MEMORY)
-         {
-           MmUnlockAddressSpace(AddressSpace);
-           Status = MmCreateVirtualMapping(AddressSpace->Process,
-                                          Address,
-                                          Attributes,
-                                          Page,
-                                          TRUE);
-           MmLockAddressSpace(AddressSpace);
-         }
-       if (!NT_SUCCESS(Status))
-         {
-           DbgPrint("Unable to create virtual mapping\n");
-           KEBUGCHECK(0);
-         }
-       MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
-       if (Locked)
-         {
-           MmLockPage(Page);
-         }  
-       PageOp->Status = STATUS_SUCCESS;
-       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-       MmReleasePageOp(PageOp);
-       DPRINT("Address 0x%.8X\n", Address);
-       return(STATUS_SUCCESS);
-     }
+   {
+      /*
+       * If the section offset is already in-memory and valid then just
+      * take another reference to the page
+      */
+
+      Page = PFN_FROM_SSE(Entry);
+
+      MmSharePageEntrySectionSegment(Segment, Offset);
+      MmUnlockSectionSegment(Segment);
+
+      Status = MmCreateVirtualMapping(AddressSpace->Process,
+                                      Address,
+                                      Attributes,
+                                      &Page,
+                                      1);
+      if (!NT_SUCCESS(Status))
+      {
+         DbgPrint("Unable to create virtual mapping\n");
+         KEBUGCHECK(0);
+      }
+      MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
+      if (Locked)
+      {
+         MmLockPage(Page);
+      }
+      PageOp->Status = STATUS_SUCCESS;
+      MmspCompleteAndReleasePageOp(PageOp);
+      DPRINT("Address 0x%.8X\n", Address);
+      return(STATUS_SUCCESS);
+   }
 }
 
-NTSTATUS 
+NTSTATUS
+NTAPI
 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
-                        MEMORY_AREA* MemoryArea, 
-                        PVOID Address,
-                        BOOLEAN Locked)
+                         MEMORY_AREA* MemoryArea,
+                         PVOID Address,
+                         BOOLEAN Locked)
 {
-  PMM_SECTION_SEGMENT Segment;
-  PSECTION_OBJECT Section;
-  PHYSICAL_ADDRESS OldPage;
-  PHYSICAL_ADDRESS NewPage;
-  PVOID NewAddress;
-  NTSTATUS Status;
-  ULONG PAddress;
-  ULONG Offset;
-  PMM_PAGEOP PageOp;
-  PMM_REGION Region;
-  LARGE_INTEGER Timeout;
-
-  /*
-   * Check if the page has been paged out or has already been set readwrite
-   */
+   PMM_SECTION_SEGMENT Segment;
+   PSECTION_OBJECT Section;
+   PFN_TYPE OldPage;
+   PFN_TYPE NewPage;
+   NTSTATUS Status;
+   PVOID PAddress;
+   ULONG Offset;
+   PMM_PAGEOP PageOp;
+   PMM_REGION Region;
+   ULONG Entry;
+
+   /*
+    * Check if the page has been paged out or has already been set readwrite
+    */
    if (!MmIsPagePresent(AddressSpace->Process, Address) ||
-       MmGetPageProtect(AddressSpace->Process, Address) & PAGE_READWRITE)
-     {
-       DPRINT("Address 0x%.8X\n", Address);
-       return(STATUS_SUCCESS);
-     }  
+         MmGetPageProtect(AddressSpace->Process, Address) & PAGE_READWRITE)
+   {
+      DPRINT("Address 0x%.8X\n", Address);
+      return(STATUS_SUCCESS);
+   }
 
    /*
     * Find the offset of the page
     */
-   PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
-   Offset = PAddress - (ULONG)MemoryArea->BaseAddress;
+   PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
+   Offset = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress 
+            + MemoryArea->Data.SectionData.ViewOffset;
 
    Segment = MemoryArea->Data.SectionData.Segment;
    Section = MemoryArea->Data.SectionData.Section;
-   Region = MmFindRegion(MemoryArea->BaseAddress,
-                        &MemoryArea->Data.SectionData.RegionListHead,
-                        Address, NULL);
+   Region = MmFindRegion(MemoryArea->StartingAddress,
+                         &MemoryArea->Data.SectionData.RegionListHead,
+                         Address, NULL);
    /*
     * Lock the segment
     */
    MmLockSectionSegment(Segment);
 
-   /*
-    * Sanity check.
-    */
-   if (MmGetPageEntrySectionSegment(Segment, Offset) == 0)
-     {
-       DPRINT1("COW fault for page with PESS 0. Address was 0x%.8X\n",
-              Address);
-     }
+   OldPage = MmGetPfnForProcess(NULL, Address);
+   Entry = MmGetPageEntrySectionSegment(Segment, Offset);
+
    MmUnlockSectionSegment(Segment);
+
    /*
     * Check if we are doing COW
     */
    if (!((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
-        (Region->Protect == PAGE_READWRITE ||
-         Region->Protect == PAGE_EXECUTE_READWRITE)))
-     {
-       DPRINT("Address 0x%.8X\n", Address);
-       return(STATUS_UNSUCCESSFUL);
-     }
+         (Region->Protect == PAGE_READWRITE ||
+          Region->Protect == PAGE_EXECUTE_READWRITE)))
+   {
+      DPRINT("Address 0x%.8X\n", Address);
+      return(STATUS_UNSUCCESSFUL);
+   }
+
+   if (IS_SWAP_FROM_SSE(Entry) ||
+       PFN_FROM_SSE(Entry) != OldPage)
+   {
+      /* This is a private page. We must only change the page protection. */
+      MmSetPageProtect(AddressSpace->Process, PAddress, Region->Protect);
+      return(STATUS_SUCCESS);
+   }
 
    /*
     * Get or create a pageop
     */
-   PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset,
-                       MM_PAGEOP_ACCESSFAULT);
+   PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset,
+                        MM_PAGEOP_ACCESSFAULT, FALSE);
    if (PageOp == NULL)
-     {
-       DPRINT1("MmGetPageOp failed\n");
-       KEBUGCHECK(0);
-     }
+   {
+      DPRINT1("MmGetPageOp failed\n");
+      KEBUGCHECK(0);
+   }
 
    /*
     * Wait for any other operations to complete
     */
    if (PageOp->Thread != PsGetCurrentThread())
-     {
-       MmUnlockAddressSpace(AddressSpace);
-       Timeout.QuadPart = -100000000LL;        // 10 sec
-       Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
-                                     0,
-                                     KernelMode,
-                                     FALSE,
-                                     &Timeout);
-       /*
-       * Check for various strange conditions
-       */
-       if (Status == STATUS_TIMEOUT)
-        {
-          DPRINT1("Failed to wait for page op, status = %x\n", Status);
-          KEBUGCHECK(0);
-        }
-       if (PageOp->Status == STATUS_PENDING)
-        {
-          DPRINT1("Woke for page op before completion\n");
-          KEBUGCHECK(0);
-        }
-       /*
-       * Restart the operation
-       */
-       MmLockAddressSpace(AddressSpace);
-       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-       MmReleasePageOp(PageOp);
-       DPRINT("Address 0x%.8X\n", Address);
-       return(STATUS_MM_RESTART_OPERATION);
-     }
+   {
+      MmUnlockAddressSpace(AddressSpace);
+      Status = MmspWaitForPageOpCompletionEvent(PageOp);
+      /*
+      * Check for various strange conditions
+      */
+      if (Status == STATUS_TIMEOUT)
+      {
+         DPRINT1("Failed to wait for page op, status = %x\n", Status);
+         KEBUGCHECK(0);
+      }
+      if (PageOp->Status == STATUS_PENDING)
+      {
+         DPRINT1("Woke for page op before completion\n");
+         KEBUGCHECK(0);
+      }
+      /*
+      * Restart the operation
+      */
+      MmLockAddressSpace(AddressSpace);
+      MmspCompleteAndReleasePageOp(PageOp);
+      DPRINT("Address 0x%.8X\n", Address);
+      return(STATUS_MM_RESTART_OPERATION);
+   }
 
    /*
     * Release locks now we have the pageop
@@ -1255,18 +1270,15 @@ MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
    Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
    if (!NT_SUCCESS(Status))
    {
-     KEBUGCHECK(0);
+      KEBUGCHECK(0);
    }
 
    /*
     * Copy the old page
     */
-   OldPage = MmGetPhysicalAddressForProcess(NULL, Address);
-   NewAddress = ExAllocatePageWithPhysPage(NewPage);
-   memcpy(NewAddress, (PVOID)PAddress, PAGE_SIZE);
-   ExUnmapPage(NewAddress);
+   MiCopyFromUserPage(NewPage, PAddress);
 
+   MmLockAddressSpace(AddressSpace);
    /*
     * Delete the old entry.
     */
@@ -1275,51 +1287,39 @@ MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
    /*
     * Set the PTE to point to the new page
     */
-   MmLockAddressSpace(AddressSpace);
    Status = MmCreateVirtualMapping(AddressSpace->Process,
-                                  Address,
-                                  Region->Protect,
-                                  NewPage,
-                                  FALSE);   
-   if (Status == STATUS_NO_MEMORY)
-     {
-       MmUnlockAddressSpace(AddressSpace);        
-       Status = MmCreateVirtualMapping(AddressSpace->Process,
-                                      Address,
-                                      Region->Protect,
-                                      NewPage,
-                                      TRUE);
-       MmLockAddressSpace(AddressSpace);
-     }  
+                                   Address,
+                                   Region->Protect,
+                                   &NewPage,
+                                   1);
    if (!NT_SUCCESS(Status))
-     {
-       DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
-       KEBUGCHECK(0);
-       return(Status);
-     }
-   MmInsertRmap(NewPage, AddressSpace->Process, (PVOID)PAddress);
+   {
+      DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
+      KEBUGCHECK(0);
+      return(Status);
+   }
    if (!NT_SUCCESS(Status))
-     {
-       DbgPrint("Unable to create virtual mapping\n");
-       KEBUGCHECK(0);
-     }
+   {
+      DbgPrint("Unable to create virtual mapping\n");
+      KEBUGCHECK(0);
+   }
    if (Locked)
-     {
-       MmLockPage(NewPage);
-     }  
+   {
+      MmLockPage(NewPage);
+      MmUnlockPage(OldPage);
+   }
 
    /*
     * Unshare the old page.
     */
-   MmDeleteRmap(OldPage, AddressSpace->Process, (PVOID)PAddress);
+   MmDeleteRmap(OldPage, AddressSpace->Process, PAddress);
+   MmInsertRmap(NewPage, AddressSpace->Process, PAddress);
    MmLockSectionSegment(Segment);
-   MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE);
+   MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE, FALSE);
    MmUnlockSectionSegment(Segment);
-   MmReleasePageMemoryConsumer(MC_USER, OldPage);
 
    PageOp->Status = STATUS_SUCCESS;
-   KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-   MmReleasePageOp(PageOp);
+   MmspCompleteAndReleasePageOp(PageOp);
    DPRINT("Address 0x%.8X\n", Address);
    return(STATUS_SUCCESS);
 }
@@ -1327,1085 +1327,1074 @@ MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
 VOID
 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
 {
-  MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
-  BOOL WasDirty;
-  PHYSICAL_ADDRESS Page;
-
-  PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
-  MmDeleteVirtualMapping(Process,
-                        Address,
-                        FALSE,
-                        &WasDirty,
-                        &Page);
-  if (WasDirty)
-    {
+   MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
+   BOOL WasDirty;
+   PFN_TYPE Page;
+
+   PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
+   if (Process)
+   {
+      MmLockAddressSpace(&Process->AddressSpace);
+   }
+
+   MmDeleteVirtualMapping(Process,
+                          Address,
+                          FALSE,
+                          &WasDirty,
+                          &Page);
+   if (WasDirty)
+   {
       PageOutContext->WasDirty = TRUE;
-    }
-  if (!PageOutContext->Private)
-    {
+   }
+   if (!PageOutContext->Private)
+   {
+      MmLockSectionSegment(PageOutContext->Segment);
       MmUnsharePageEntrySectionSegment(PageOutContext->Section,
-                                      PageOutContext->Segment,
-                                      PageOutContext->Offset,
-                                      PageOutContext->WasDirty);
-    }
-  MmReleasePageMemoryConsumer(MC_USER, Page);
-  DPRINT("PhysicalAddress %I64x, Address %x\n", Page, Address);
+                                       PageOutContext->Segment,
+                                       PageOutContext->Offset,
+                                       PageOutContext->WasDirty,
+                                       TRUE);
+      MmUnlockSectionSegment(PageOutContext->Segment);
+   }
+   if (Process)
+   {
+      MmUnlockAddressSpace(&Process->AddressSpace);
+   }
+   
+   if (PageOutContext->Private)
+   {
+      MmReleasePageMemoryConsumer(MC_USER, Page);
+   }
+
+   DPRINT("PhysicalAddress %x, Address %x\n", Page << PAGE_SHIFT, Address);
 }
 
 NTSTATUS
+NTAPI
 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
-                    MEMORY_AREA* MemoryArea, 
-                    PVOID Address,
-                    PMM_PAGEOP PageOp)
+                     MEMORY_AREA* MemoryArea,
+                     PVOID Address,
+                     PMM_PAGEOP PageOp)
 {
-  PHYSICAL_ADDRESS PhysicalAddress;
-  MM_SECTION_PAGEOUT_CONTEXT Context;
-  SWAPENTRY SwapEntry;
-  PMDL Mdl;
-  ULONG Entry;
-  ULONG FileOffset;
-  NTSTATUS Status;
-  PFILE_OBJECT FileObject;
-  PBCB Bcb = NULL;
-  BOOLEAN DirectMapped;
-  BOOLEAN IsImageSection;
-
-  Address = (PVOID)PAGE_ROUND_DOWN(Address);
-
-  /*
-   * Get the segment and section.
-   */
-  Context.Segment = MemoryArea->Data.SectionData.Segment;
-  Context.Section = MemoryArea->Data.SectionData.Section;
-
-  Context.Offset = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress);
-  FileOffset = Context.Offset + Context.Segment->FileOffset;
-
-  IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
-
-  FileObject = Context.Section->FileObject;
-  DirectMapped = FALSE;
-  if (FileObject != NULL)
-    {
+   PFN_TYPE Page;
+   MM_SECTION_PAGEOUT_CONTEXT Context;
+   SWAPENTRY SwapEntry;
+   ULONG Entry;
+   ULONG FileOffset;
+   NTSTATUS Status;
+   PFILE_OBJECT FileObject;
+   PBCB Bcb = NULL;
+   BOOLEAN DirectMapped;
+   BOOLEAN IsImageSection;
+
+   Address = (PVOID)PAGE_ROUND_DOWN(Address);
+
+   /*
+    * Get the segment and section.
+    */
+   Context.Segment = MemoryArea->Data.SectionData.Segment;
+   Context.Section = MemoryArea->Data.SectionData.Section;
+
+   Context.Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress 
+                    + MemoryArea->Data.SectionData.ViewOffset;
+   FileOffset = Context.Offset + Context.Segment->FileOffset;
+
+   IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
+
+   FileObject = Context.Section->FileObject;
+   DirectMapped = FALSE;
+   if (FileObject != NULL &&
+       !(Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
+   {
       Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
-  
+
       /*
        * If the file system is letting us go directly to the cache and the
        * memory area was mapped at an offset in the file which is page aligned
        * then note this is a direct mapped page.
        */
-      if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
-         (FileOffset % PAGE_SIZE) == 0 &&
-         (Context.Offset + PAGE_SIZE <= Context.Segment->RawLength || !IsImageSection))
-       {
-         DirectMapped = TRUE;
-       }
-    }
-   
+      if ((FileOffset % PAGE_SIZE) == 0 &&
+            (Context.Offset + PAGE_SIZE <= Context.Segment->RawLength || !IsImageSection))
+      {
+         DirectMapped = TRUE;
+      }
+   }
+
 
-  /*
-   * This should never happen since mappings of physical memory are never
-   * placed in the rmap lists.
-   */
-  if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
-    {
+   /*
+    * This should never happen since mappings of physical memory are never
+    * placed in the rmap lists.
+    */
+   if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
+   {
       DPRINT1("Trying to page out from physical memory section address 0x%X "
-             "process %d\n", Address, 
-             AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
+              "process %d\n", Address,
+              AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
       KEBUGCHECK(0);
-    }
-
-  /*
-   * Get the section segment entry and the physical address.
-   */
-  Entry = MmGetPageEntrySectionSegment(Context.Segment, Context.Offset);
-  if (!MmIsPagePresent(AddressSpace->Process, Address))
-    {
+   }
+
+   /*
+    * Get the section segment entry and the physical address.
+    */
+   Entry = MmGetPageEntrySectionSegment(Context.Segment, Context.Offset);
+   if (!MmIsPagePresent(AddressSpace->Process, Address))
+   {
       DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
-         AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
+              AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
       KEBUGCHECK(0);
-    }
-  PhysicalAddress = 
-    MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
-  SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
-
-  /*
-   * Prepare the context structure for the rmap delete call.
-   */
-  Context.WasDirty = FALSE;
-  if (Context.Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
-      IS_SWAP_FROM_SSE(Entry) || 
-      (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart)
-    {
+   }
+   Page = MmGetPfnForProcess(AddressSpace->Process, Address);
+   SwapEntry = MmGetSavedSwapEntryPage(Page);
+
+   /*
+    * Prepare the context structure for the rmap delete call.
+    */
+   Context.WasDirty = FALSE;
+   if (Context.Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
+         IS_SWAP_FROM_SSE(Entry) ||
+         PFN_FROM_SSE(Entry) != Page)
+   {
       Context.Private = TRUE;
-    }
-  else
-    {
+   }
+   else
+   {
       Context.Private = FALSE;
-    }
-
-  /*
-   * Paging out data mapped read-only is easy.
-   */
-  if (Context.Segment->Protection & (PAGE_READONLY|PAGE_EXECUTE_READ))
-    {
-      /*
-       * Read-only data should never be in the swapfile.
-       */
-      if (SwapEntry != 0)
-       {
-         DPRINT1("SwapEntry != 0 was 0x%.8X at address 0x%.8X, "
-                 "paddress 0x%.8X\n", SwapEntry, Address, 
-                 PhysicalAddress);
-         KEBUGCHECK(0);
-       }
+   }
 
-      /*
-       * Read-only data should never be COWed
-       */
-      if (Context.Private)
-       {
-         DPRINT1("Had private copy of read-only page.\n");
-         KEBUGCHECK(0);
-       }
-      
-      /*
-       * Delete all mappings of this page.
-       */
-      MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context, 
-                      MmPageOutDeleteMapping);
-      if (Context.WasDirty)
-       {
-         DPRINT1("Had a dirty page of a read-only page.\n");
-         KEBUGCHECK(0);
-       }
+   /*
+    * Take an additional reference to the page or the cache segment.
+    */
+   if (DirectMapped && !Context.Private)
+   {
+      if(!MiIsPageFromCache(MemoryArea, Context.Offset))
+      {
+         DPRINT1("Direct mapped non private page is not associated with the cache.\n");
+         KEBUGCHECK(0);
+      }
+   }
+   else
+   {
+      MmReferencePage(Page);
+   }
 
-      PageOp->Status = STATUS_SUCCESS;
-      KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-      MmReleasePageOp(PageOp);
-      return(STATUS_SUCCESS);
-    }
+   MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping);
 
-  /*
-   * Otherwise we have read-write data.
-   */
+   /*
+    * If this wasn't a private page then we should have reduced the entry to
+    * zero by deleting all the rmaps.
+    */
+   if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0)
+   {
+      if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
+            !(Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
+      {
+         KEBUGCHECK(0);
+      }
+   }
 
-  /*
-   * Take an additional reference to the page or the cache segment.
-   */
-  if (DirectMapped && !Context.Private)
-    {
-      if(!MiIsPageFromCache(MemoryArea, Context.Offset))
-        {
-         DPRINT1("Direct mapped non private page is not associated with the cache.\n")
-          KEBUGCHECK(0);
-        }
-    }
-  else
-    {
-      MmReferencePage(PhysicalAddress);
-    }
-
-  MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context, MmPageOutDeleteMapping);
-  
-  /*
-   * If this wasn't a private page then we should have reduced the entry to
-   * zero by deleting all the rmaps.
-   */
-  if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0)
-    {
-      if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT))
-        {
-         CHECKPOINT1;
-          KEBUGCHECK(0);
-       }
-    }
-
-  /*
-   * If the page wasn't dirty then we can just free it as for a readonly page.
-   * Since we unmapped all the mappings above we know it will not suddenly
-   * become dirty. 
-   * If the page is from a pagefile section and has no swap entry, 
-   * we can't free the page at this point.
-   */
-  SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
-  if (!Context.WasDirty && 
-      !(SwapEntry == 0 && Context.Segment->Flags & MM_PAGEFILE_SEGMENT))
-      
-    {
+   /*
+    * If the page wasn't dirty then we can just free it as for a readonly page.
+    * Since we unmapped all the mappings above we know it will not suddenly
+    * become dirty.
+    * If the page is from a pagefile section and has no swap entry,
+    * we can't free the page at this point.
+    */
+   SwapEntry = MmGetSavedSwapEntryPage(Page);
+   if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT)
+   {
       if (Context.Private)
-       {
-         MmSetSavedSwapEntryPage(PhysicalAddress, 0);
-         if (!(Context.Segment->Characteristics & IMAGE_SECTION_CHAR_BSS) &&
-             SwapEntry == 0)
-           {
-             DPRINT1("Private page, non-dirty but not swapped out "
-                     "process %d address 0x%.8X\n",
-                     AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0,
-                     Address);       
-             KEBUGCHECK(0);
-           }
-         else
-           {
-             Status = MmCreatePageFileMapping(AddressSpace->Process,
-                                              Address,
-                                              SwapEntry);
-             if (!NT_SUCCESS(Status))
-               {
-                 KEBUGCHECK(0);
-               }
-           }
-       }
-      if (DirectMapped && !Context.Private)
-        {
-          Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
-          if (!NT_SUCCESS(Status))
-            {
-              DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
-              KEBUGCHECK(0);
-           }
-       }
-      else
-        {
-          MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
-       }
-      
+      {
+         DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
+                 Context.WasDirty ? "dirty" : "clean", Address);
+         KEBUGCHECK(0);
+      }
+      if (!Context.WasDirty && SwapEntry != 0)
+      {
+         MmSetSavedSwapEntryPage(Page, 0);
+         MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
+         MmReleasePageMemoryConsumer(MC_USER, Page);
+         PageOp->Status = STATUS_SUCCESS;
+         MmspCompleteAndReleasePageOp(PageOp);
+         return(STATUS_SUCCESS);
+      }
+   }
+   else if (Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED)
+   {
+      if (Context.Private)
+      {
+         DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
+                 Context.WasDirty ? "dirty" : "clean", Address);
+         KEBUGCHECK(0);
+      }
+      if (!Context.WasDirty || SwapEntry != 0)
+      {
+         MmSetSavedSwapEntryPage(Page, 0);
+         if (SwapEntry != 0)
+         {
+            MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
+         }
+         MmReleasePageMemoryConsumer(MC_USER, Page);
+         PageOp->Status = STATUS_SUCCESS;
+         MmspCompleteAndReleasePageOp(PageOp);
+         return(STATUS_SUCCESS);
+      }
+   }
+   else if (!Context.Private && DirectMapped)
+   {
+      if (SwapEntry != 0)
+      {
+         DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
+                 Address);
+         KEBUGCHECK(0);
+      }
+      Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
+      if (!NT_SUCCESS(Status))
+      {
+         DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
+         KEBUGCHECK(0);
+      }
       PageOp->Status = STATUS_SUCCESS;
-      KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-      MmReleasePageOp(PageOp);
+      MmspCompleteAndReleasePageOp(PageOp);
       return(STATUS_SUCCESS);
-    }
-
-  /*
-   * If this page was direct mapped from the cache then the cache manager
-   * will already have taken care of writing it back.
-   */
-  if (DirectMapped && !Context.Private)
-    {
-      assert(SwapEntry == 0);
-      Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
+   }
+   else if (!Context.WasDirty && !DirectMapped && !Context.Private)
+   {
+      if (SwapEntry != 0)
+      {
+         DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
+                 Address);
+         KEBUGCHECK(0);
+      }
+      MmReleasePageMemoryConsumer(MC_USER, Page);
+      PageOp->Status = STATUS_SUCCESS;
+      MmspCompleteAndReleasePageOp(PageOp);
+      return(STATUS_SUCCESS);
+   }
+   else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
+   {
+      MmSetSavedSwapEntryPage(Page, 0);
+      MmLockAddressSpace(AddressSpace);
+      Status = MmCreatePageFileMapping(AddressSpace->Process,
+                                       Address,
+                                       SwapEntry);
+      MmUnlockAddressSpace(AddressSpace);
       if (!NT_SUCCESS(Status))
-        {
-          DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
-          KEBUGCHECK(0);
-       }
+      {
+         KEBUGCHECK(0);
+      }
+      MmReleasePageMemoryConsumer(MC_USER, Page);
       PageOp->Status = STATUS_SUCCESS;
-      KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-      MmReleasePageOp(PageOp);
+      MmspCompleteAndReleasePageOp(PageOp);
       return(STATUS_SUCCESS);
-    }
+   }
 
-  /*
-   * If necessary, allocate an entry in the paging file for this page
-   */
-  if (SwapEntry == 0)
-    {
+   /*
+    * If necessary, allocate an entry in the paging file for this page
+    */
+   if (SwapEntry == 0)
+   {
       SwapEntry = MmAllocSwapPage();
       if (SwapEntry == 0)
-       {
-         MmShowOutOfSpaceMessagePagingFile();
-
-         /*
-          * For private pages restore the old mappings.
-          */
-         if (Context.Private)
-           {
-             Status = MmCreateVirtualMapping(MemoryArea->Process,   
-                                             Address,
-                                             MemoryArea->Attributes,
-                                             PhysicalAddress,
-                                             FALSE);
-             MmSetDirtyPage(MemoryArea->Process, Address);
-             MmInsertRmap(PhysicalAddress, 
-                          MemoryArea->Process,
-                          Address);
-           }
-         else
-           {
-             /*
-              * For non-private pages if the page wasn't direct mapped then
-              * set it back into the section segment entry so we don't loose 
-              * our copy. Otherwise it will be handled by the cache manager.
-              */
-             Status = MmCreateVirtualMapping(MemoryArea->Process,   
-                                             Address,
-                                             MemoryArea->Attributes,
-                                             PhysicalAddress,
-                                             FALSE);
-             MmSetDirtyPage(MemoryArea->Process, Address);
-             MmInsertRmap(PhysicalAddress, 
-                          MemoryArea->Process,
-                          Address);
-              Entry = MAKE_SSE(PhysicalAddress.u.LowPart, 1);
-             MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
-           }
-         PageOp->Status = STATUS_UNSUCCESSFUL;
-         KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-         MmReleasePageOp(PageOp);
-         return(STATUS_PAGEFILE_QUOTA);
-       }
-    }
-
-  /*
-   * Write the page to the pagefile
-   */
-  Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
-  MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
-  Status = MmWriteToSwapPage(SwapEntry, Mdl);
-  if (!NT_SUCCESS(Status))
-    {
-      DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", 
-             Status);
+      {
+         MmShowOutOfSpaceMessagePagingFile();
+         MmLockAddressSpace(AddressSpace);
+         /*
+          * For private pages restore the old mappings.
+          */
+         if (Context.Private)
+         {
+            Status = MmCreateVirtualMapping(AddressSpace->Process,
+                                            Address,
+                                            MemoryArea->Attributes,
+                                            &Page,
+                                            1);
+            MmSetDirtyPage(AddressSpace->Process, Address);
+            MmInsertRmap(Page,
+                         AddressSpace->Process,
+                         Address);
+         }
+         else
+         {
+            /*
+             * For non-private pages if the page wasn't direct mapped then
+             * set it back into the section segment entry so we don't loose
+             * our copy. Otherwise it will be handled by the cache manager.
+             */
+            Status = MmCreateVirtualMapping(AddressSpace->Process,
+                                            Address,
+                                            MemoryArea->Attributes,
+                                            &Page,
+                                            1);
+            MmSetDirtyPage(AddressSpace->Process, Address);
+            MmInsertRmap(Page,
+                         AddressSpace->Process,
+                         Address);
+            Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
+            MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
+         }
+         MmUnlockAddressSpace(AddressSpace);
+         PageOp->Status = STATUS_UNSUCCESSFUL;
+         MmspCompleteAndReleasePageOp(PageOp);
+         return(STATUS_PAGEFILE_QUOTA);
+      }
+   }
+
+   /*
+    * Write the page to the pagefile
+    */
+   Status = MmWriteToSwapPage(SwapEntry, Page);
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
+              Status);
       /*
        * As above: undo our actions.
        * FIXME: Also free the swap page.
        */
+      MmLockAddressSpace(AddressSpace);
       if (Context.Private)
-       {
-         Status = MmCreateVirtualMapping(MemoryArea->Process,   
-                                         Address,
-                                         MemoryArea->Attributes,
-                                         PhysicalAddress,
-                                         FALSE);
-         MmSetDirtyPage(MemoryArea->Process, Address);
-         MmInsertRmap(PhysicalAddress, 
-                      MemoryArea->Process,
-                      Address);
-       }
+      {
+         Status = MmCreateVirtualMapping(AddressSpace->Process,
+                                         Address,
+                                         MemoryArea->Attributes,
+                                         &Page,
+                                         1);
+         MmSetDirtyPage(AddressSpace->Process, Address);
+         MmInsertRmap(Page,
+                      AddressSpace->Process,
+                      Address);
+      }
       else
-       {
-         Status = MmCreateVirtualMapping(MemoryArea->Process,   
-                                         Address,
-                                         MemoryArea->Attributes,
-                                         PhysicalAddress,
-                                         FALSE);
-         MmSetDirtyPage(MemoryArea->Process, Address);
-         MmInsertRmap(PhysicalAddress, 
-                          MemoryArea->Process,
-                          Address);
-          Entry = MAKE_SSE(PhysicalAddress.u.LowPart, 1);
-         MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
-       }
+      {
+         Status = MmCreateVirtualMapping(AddressSpace->Process,
+                                         Address,
+                                         MemoryArea->Attributes,
+                                         &Page,
+                                         1);
+         MmSetDirtyPage(AddressSpace->Process, Address);
+         MmInsertRmap(Page,
+                      AddressSpace->Process,
+                      Address);
+         Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
+         MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
+      }
+      MmUnlockAddressSpace(AddressSpace);
       PageOp->Status = STATUS_UNSUCCESSFUL;
-      KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-      MmReleasePageOp(PageOp);
+      MmspCompleteAndReleasePageOp(PageOp);
       return(STATUS_UNSUCCESSFUL);
-    }
-
-  /*
-   * Otherwise we have succeeded.
-   */
-  DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress);
-  MmSetSavedSwapEntryPage(PhysicalAddress, 0);
-  MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
-
-  if (Context.Private)
-    {
-      Status = MmCreatePageFileMapping(MemoryArea->Process,   
-                                      Address,
-                                      SwapEntry);
+   }
+
+   /*
+    * Otherwise we have succeeded.
+    */
+   DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
+   MmSetSavedSwapEntryPage(Page, 0);
+   if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
+         Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED)
+   {
+      MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
+   }
+   else
+   {
+      MmReleasePageMemoryConsumer(MC_USER, Page);
+   }
+
+   if (Context.Private)
+   {
+      MmLockAddressSpace(AddressSpace);
+      Status = MmCreatePageFileMapping(AddressSpace->Process,
+                                       Address,
+                                       SwapEntry);
+      MmUnlockAddressSpace(AddressSpace);
       if (!NT_SUCCESS(Status))
-       {
-         KEBUGCHECK(0);
-       }
-    }
-  else
-    {
+      {
+         KEBUGCHECK(0);
+      }
+   }
+   else
+   {
       Entry = MAKE_SWAP_SSE(SwapEntry);
       MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
-    }
+   }
 
-  PageOp->Status = STATUS_SUCCESS;
-  KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-  MmReleasePageOp(PageOp);
-  return(STATUS_SUCCESS);
+   PageOp->Status = STATUS_SUCCESS;
+   MmspCompleteAndReleasePageOp(PageOp);
+   return(STATUS_SUCCESS);
 }
 
-NTSTATUS 
+NTSTATUS
+NTAPI
 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
-                      PMEMORY_AREA MemoryArea,
-                      PVOID Address,
-                      PMM_PAGEOP PageOp)
+                       PMEMORY_AREA MemoryArea,
+                       PVOID Address,
+                       PMM_PAGEOP PageOp)
 {
-  ULONG Offset;
-  PSECTION_OBJECT Section;
-  PMM_SECTION_SEGMENT Segment;
-  PHYSICAL_ADDRESS PhysicalAddress;
-  SWAPENTRY SwapEntry;
-  PMDL Mdl;
-  ULONG Entry;
-  BOOLEAN Private;
-  NTSTATUS Status;
-  PFILE_OBJECT FileObject;
-  PBCB Bcb = NULL;
-  BOOLEAN DirectMapped;
-  BOOLEAN IsImageSection;
-
-  Address = (PVOID)PAGE_ROUND_DOWN(Address);
-
-  Offset = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress);
-
-  /*
-   * Get the segment and section.
-   */
-  Segment = MemoryArea->Data.SectionData.Segment;
-  Section = MemoryArea->Data.SectionData.Section;
-  IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
-
-  FileObject = Section->FileObject;
-  DirectMapped = FALSE;
-  if (FileObject != NULL)
-    {
+   ULONG Offset;
+   PSECTION_OBJECT Section;
+   PMM_SECTION_SEGMENT Segment;
+   PFN_TYPE Page;
+   SWAPENTRY SwapEntry;
+   ULONG Entry;
+   BOOLEAN Private;
+   NTSTATUS Status;
+   PFILE_OBJECT FileObject;
+   PBCB Bcb = NULL;
+   BOOLEAN DirectMapped;
+   BOOLEAN IsImageSection;
+
+   Address = (PVOID)PAGE_ROUND_DOWN(Address);
+
+   Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress 
+            + MemoryArea->Data.SectionData.ViewOffset;
+
+   /*
+    * Get the segment and section.
+    */
+   Segment = MemoryArea->Data.SectionData.Segment;
+   Section = MemoryArea->Data.SectionData.Section;
+   IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
+
+   FileObject = Section->FileObject;
+   DirectMapped = FALSE;
+   if (FileObject != NULL &&
+         !(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
+   {
       Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
-  
+
       /*
        * If the file system is letting us go directly to the cache and the
        * memory area was mapped at an offset in the file which is page aligned
        * then note this is a direct mapped page.
        */
-      if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
-         (Offset + MemoryArea->Data.SectionData.ViewOffset % PAGE_SIZE) == 0 &&
-         (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
-       {
-         DirectMapped = TRUE;
-       }
-    }
-   
-  /*
-   * This should never happen since mappings of physical memory are never
-   * placed in the rmap lists.
-   */
-  if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
-    {
+      if (((Offset + Segment->FileOffset) % PAGE_SIZE) == 0 &&
+            (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
+      {
+         DirectMapped = TRUE;
+      }
+   }
+
+   /*
+    * This should never happen since mappings of physical memory are never
+    * placed in the rmap lists.
+    */
+   if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
+   {
       DPRINT1("Trying to write back page from physical memory mapped at %X "
-             "process %d\n", Address, 
-             AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
+              "process %d\n", Address,
+              AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
       KEBUGCHECK(0);
-    }
-
-  /*
-   * Get the section segment entry and the physical address.
-   */
-  Entry = MmGetPageEntrySectionSegment(Segment, Offset);
-  if (!MmIsPagePresent(AddressSpace->Process, Address))
-    {
+   }
+
+   /*
+    * Get the section segment entry and the physical address.
+    */
+   Entry = MmGetPageEntrySectionSegment(Segment, Offset);
+   if (!MmIsPagePresent(AddressSpace->Process, Address))
+   {
       DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
-         AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
+              AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
       KEBUGCHECK(0);
-    }
-  PhysicalAddress = 
-    MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
-  SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
-
-  /*
-   * Check for a private (COWed) page.
-   */
-  if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
-      IS_SWAP_FROM_SSE(Entry) || 
-      (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart)
-    {
+   }
+   Page = MmGetPfnForProcess(AddressSpace->Process, Address);
+   SwapEntry = MmGetSavedSwapEntryPage(Page);
+
+   /*
+    * Check for a private (COWed) page.
+    */
+   if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
+         IS_SWAP_FROM_SSE(Entry) ||
+         PFN_FROM_SSE(Entry) != Page)
+   {
       Private = TRUE;
-    }
-  else
-    {
+   }
+   else
+   {
       Private = FALSE;
-    }
+   }
 
-  /*
-   * Speculatively set all mappings of the page to clean.
-   */
-  MmSetCleanAllRmaps(PhysicalAddress);
-  
-  /*
-   * If this page was direct mapped from the cache then the cache manager
-   * will take care of writing it back to disk.
-   */
-  if (DirectMapped && !Private)
-    {
-      assert(SwapEntry == 0);
-      CcRosMarkDirtyCacheSegment(Bcb, Offset + MemoryArea->Data.SectionData.ViewOffset);
+   /*
+    * Speculatively set all mappings of the page to clean.
+    */
+   MmSetCleanAllRmaps(Page);
+
+   /*
+    * If this page was direct mapped from the cache then the cache manager
+    * will take care of writing it back to disk.
+    */
+   if (DirectMapped && !Private)
+   {
+      ASSERT(SwapEntry == 0);
+      CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
       PageOp->Status = STATUS_SUCCESS;
-      KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-      MmReleasePageOp(PageOp);
+      MmspCompleteAndReleasePageOp(PageOp);
       return(STATUS_SUCCESS);
-    }
+   }
 
-  /*
-   * If necessary, allocate an entry in the paging file for this page
-   */
-  if (SwapEntry == 0)
-    {
+   /*
+    * If necessary, allocate an entry in the paging file for this page
+    */
+   if (SwapEntry == 0)
+   {
       SwapEntry = MmAllocSwapPage();
       if (SwapEntry == 0)
-       {
-         MmSetDirtyAllRmaps(PhysicalAddress);
-         PageOp->Status = STATUS_UNSUCCESSFUL;
-         KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-         MmReleasePageOp(PageOp);
-         return(STATUS_PAGEFILE_QUOTA);
-       }
-    }
-
-  /*
-   * Write the page to the pagefile
-   */
-  Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
-  MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
-  Status = MmWriteToSwapPage(SwapEntry, Mdl);
-  if (!NT_SUCCESS(Status))
-    {
-      DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", 
-             Status);
-      MmSetDirtyAllRmaps(PhysicalAddress);
+      {
+         MmSetDirtyAllRmaps(Page);
+         PageOp->Status = STATUS_UNSUCCESSFUL;
+         MmspCompleteAndReleasePageOp(PageOp);
+         return(STATUS_PAGEFILE_QUOTA);
+      }
+      MmSetSavedSwapEntryPage(Page, SwapEntry);
+   }
+
+   /*
+    * Write the page to the pagefile
+    */
+   Status = MmWriteToSwapPage(SwapEntry, Page);
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
+              Status);
+      MmSetDirtyAllRmaps(Page);
       PageOp->Status = STATUS_UNSUCCESSFUL;
-      KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-      MmReleasePageOp(PageOp);
+      MmspCompleteAndReleasePageOp(PageOp);
       return(STATUS_UNSUCCESSFUL);
-    }
-
-  /*
-   * Otherwise we have succeeded.
-   */
-  DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress);
-  MmSetSavedSwapEntryPage(PhysicalAddress, SwapEntry);
-  PageOp->Status = STATUS_SUCCESS;
-  KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-  MmReleasePageOp(PageOp);
-  return(STATUS_SUCCESS);
+   }
+
+   /*
+    * Otherwise we have succeeded.
+    */
+   DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
+   PageOp->Status = STATUS_SUCCESS;
+   MmspCompleteAndReleasePageOp(PageOp);
+   return(STATUS_SUCCESS);
 }
 
 VOID STATIC
 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace,
-                     PVOID BaseAddress,
-                     ULONG RegionSize,
-                     ULONG OldType,
-                     ULONG OldProtect,
-                     ULONG NewType,
-                     ULONG NewProtect)
+                      PVOID BaseAddress,
+                      ULONG RegionSize,
+                      ULONG OldType,
+                      ULONG OldProtect,
+                      ULONG NewType,
+                      ULONG NewProtect)
 {
-  PMEMORY_AREA MemoryArea;
-  PMM_SECTION_SEGMENT Segment;
-  BOOL DoCOW = FALSE;
-  ULONG i;
+   PMEMORY_AREA MemoryArea;
+   PMM_SECTION_SEGMENT Segment;
+   BOOL DoCOW = FALSE;
+   ULONG i;
 
-  MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, BaseAddress);
-  Segment = MemoryArea->Data.SectionData.Segment;
+   MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
+   Segment = MemoryArea->Data.SectionData.Segment;
 
-  if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
-       (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
-     {
-       DoCOW = TRUE;
-     }
+   if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
+         (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
+   {
+      DoCOW = TRUE;
+   }
 
-  if (OldProtect != NewProtect)
-    {
+   if (OldProtect != NewProtect)
+   {
       for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
-       {
-         PVOID Address = BaseAddress + (i * PAGE_SIZE);
-         ULONG Protect = NewProtect;
-
-         /* 
-          * If we doing COW for this segment then check if the page is
-          * already private.
-          */
-         if (DoCOW && MmIsPagePresent(AddressSpace->Process, Address))
-           {
-             ULONG Offset;
-             ULONG Entry;
-             LARGE_INTEGER PhysicalAddress;
-
-             Offset =  (ULONG)Address - (ULONG)MemoryArea->BaseAddress;
-             Entry = MmGetPageEntrySectionSegment(Segment, Offset);
-             PhysicalAddress = 
-               MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
-
-             Protect = PAGE_READONLY;
-             if ((Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
-                  IS_SWAP_FROM_SSE(Entry) || 
-                  (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart))
-               {
-                 Protect = NewProtect;
-               }
-           }
-
-         if (MmIsPagePresent(AddressSpace->Process, Address))
-           {
-             MmSetPageProtect(AddressSpace->Process, BaseAddress, 
-                              Protect);
-           }
-       }
-    }
+      {
+         PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
+         ULONG Protect = NewProtect;
+
+         /*
+          * If we doing COW for this segment then check if the page is
+          * already private.
+          */
+         if (DoCOW && MmIsPagePresent(AddressSpace->Process, Address))
+         {
+            ULONG Offset;
+            ULONG Entry;
+            PFN_TYPE Page;
+
+            Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress 
+                     + MemoryArea->Data.SectionData.ViewOffset;
+            Entry = MmGetPageEntrySectionSegment(Segment, Offset);
+            Page = MmGetPfnForProcess(AddressSpace->Process, Address);
+
+            Protect = PAGE_READONLY;
+            if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
+                  IS_SWAP_FROM_SSE(Entry) ||
+                  PFN_FROM_SSE(Entry) != Page)
+            {
+               Protect = NewProtect;
+            }
+         }
+
+         if (MmIsPagePresent(AddressSpace->Process, Address))
+         {
+            MmSetPageProtect(AddressSpace->Process, Address,
+                             Protect);
+         }
+      }
+   }
 }
 
 NTSTATUS
+NTAPI
 MmProtectSectionView(PMADDRESS_SPACE AddressSpace,
-                    PMEMORY_AREA MemoryArea,
-                    PVOID BaseAddress,
-                    ULONG Length,
-                    ULONG Protect,
-                    PULONG OldProtect)
+                     PMEMORY_AREA MemoryArea,
+                     PVOID BaseAddress,
+                     ULONG Length,
+                     ULONG Protect,
+                     PULONG OldProtect)
 {
-  PMM_REGION Region;
-  NTSTATUS Status;
-
-  Length = 
-    min(Length, (ULONG) (MemoryArea->BaseAddress + MemoryArea->Length - BaseAddress));
-  Region = MmFindRegion(MemoryArea->BaseAddress,
-                       &MemoryArea->Data.SectionData.RegionListHead,
-                       BaseAddress, NULL);
-  *OldProtect = Region->Protect;
-  Status = MmAlterRegion(AddressSpace, MemoryArea->BaseAddress,
-                        &MemoryArea->Data.SectionData.RegionListHead,
-                        BaseAddress, Length, Region->Type, Protect,
-                        MmAlterViewAttributes);
-
-  return(Status);
-}
+   PMM_REGION Region;
+   NTSTATUS Status;
+   ULONG_PTR MaxLength;
 
-NTSTATUS STDCALL
+   MaxLength = (ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)BaseAddress;
+   if (Length > MaxLength)
+      Length = MaxLength;
+
+   Region = MmFindRegion(MemoryArea->StartingAddress,
+                         &MemoryArea->Data.SectionData.RegionListHead,
+                         BaseAddress, NULL);
+   *OldProtect = Region->Protect;
+   Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress,
+                          &MemoryArea->Data.SectionData.RegionListHead,
+                          BaseAddress, Length, Region->Type, Protect,
+                          MmAlterViewAttributes);
+
+   return(Status);
+}
+
+NTSTATUS STDCALL
 MmQuerySectionView(PMEMORY_AREA MemoryArea,
-                  PVOID Address,
-                  PMEMORY_BASIC_INFORMATION Info,
-                  PULONG ResultLength)
+                   PVOID Address,
+                   PMEMORY_BASIC_INFORMATION Info,
+                   PULONG ResultLength)
 {
-  PMM_REGION Region;
-  PVOID RegionBaseAddress;
-  
-  Region = MmFindRegion(MemoryArea->BaseAddress,
-                       &MemoryArea->Data.SectionData.RegionListHead,
-                       Address, &RegionBaseAddress);
-  if (Region == NULL)
-    {
+   PMM_REGION Region;
+   PVOID RegionBaseAddress;
+   PSECTION_OBJECT Section;
+   PMM_SECTION_SEGMENT Segment;
+
+   Region = MmFindRegion((PVOID)MemoryArea->StartingAddress,
+                         &MemoryArea->Data.SectionData.RegionListHead,
+                         Address, &RegionBaseAddress);
+   if (Region == NULL)
+   {
       return STATUS_UNSUCCESSFUL;
-    }
-  Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
-  Info->AllocationBase = MemoryArea->BaseAddress;
-  Info->AllocationProtect = MemoryArea->Attributes;
-  Info->RegionSize = MemoryArea->Length;
-  Info->State = MEM_COMMIT;
-  Info->Protect = Region->Protect;
-  if (MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE)
-    {
+   }
+
+   Section = MemoryArea->Data.SectionData.Section;
+   if (Section->AllocationAttributes & SEC_IMAGE)
+   {
+      Segment = MemoryArea->Data.SectionData.Segment;
+      Info->AllocationBase = (PBYTE)MemoryArea->StartingAddress - Segment->VirtualAddress;
       Info->Type = MEM_IMAGE;
-    }
-  else
-    {
+   }
+   else
+   {
+      Info->AllocationBase = MemoryArea->StartingAddress;
       Info->Type = MEM_MAPPED;
-    }
+   }
+   Info->BaseAddress = RegionBaseAddress;
+   Info->AllocationProtect = MemoryArea->Attributes;
+   Info->RegionSize = Region->Length;
+   Info->State = MEM_COMMIT;
+   Info->Protect = Region->Protect;
+
+   *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+   return(STATUS_SUCCESS);
+}
 
-  return(STATUS_SUCCESS);
+VOID
+NTAPI
+MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
+{
+   ULONG Length;
+   ULONG Offset;
+   ULONG Entry;
+   ULONG SavedSwapEntry;
+   PFN_TYPE Page;
+
+   Page = 0;
+
+   Length = PAGE_ROUND_UP(Segment->Length);
+   for (Offset = 0; Offset < Length; Offset += PAGE_SIZE)
+   {
+      Entry = MmGetPageEntrySectionSegment(Segment, Offset);
+      if (Entry)
+      {
+         if (IS_SWAP_FROM_SSE(Entry))
+         {
+            MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
+         }
+         else
+         {
+            Page = PFN_FROM_SSE(Entry);
+            SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
+            if (SavedSwapEntry != 0)
+            {
+               MmSetSavedSwapEntryPage(Page, 0);
+               MmFreeSwapPage(SavedSwapEntry);
+            }
+            MmReleasePageMemoryConsumer(MC_USER, Page);
+         }
+         MmSetPageEntrySectionSegment(Segment, Offset, 0);
+      }
+   }
 }
 
 VOID STDCALL
 MmpDeleteSection(PVOID ObjectBody)
 {
-  PSECTION_OBJECT Section = (PSECTION_OBJECT)ObjectBody;
+   PSECTION_OBJECT Section = (PSECTION_OBJECT)ObjectBody;
 
-  DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
-  if (Section->AllocationAttributes & SEC_IMAGE)
-    {
+   DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
+   if (Section->AllocationAttributes & SEC_IMAGE)
+   {
       ULONG i;
       ULONG NrSegments;
+      ULONG RefCount;
       PMM_SECTION_SEGMENT SectionSegments;
 
+      /*
+       * NOTE: Section->ImageSection can be NULL for short time
+       * during the section creating. If we fail for some reason
+       * until the image section is properly initialized we shouldn't
+       * process further here.
+       */
+      if (Section->ImageSection == NULL)
+         return;
+
       SectionSegments = Section->ImageSection->Segments;
       NrSegments = Section->ImageSection->NrSegments;
 
       for (i = 0; i < NrSegments; i++)
-       {
-         InterlockedDecrement((LONG *)&SectionSegments[i].ReferenceCount);
-       }
-    }
-  else
-    {
+      {
+         if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
+         {
+            MmLockSectionSegment(&SectionSegments[i]);
+         }
+         RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount);
+         if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
+         {
+            if (RefCount == 0)
+            {
+               MmpFreePageFileSegment(&SectionSegments[i]);
+            }
+            MmUnlockSectionSegment(&SectionSegments[i]);
+         }
+      }
+   }
+   else
+   {
+      /*
+       * NOTE: Section->Segment can be NULL for short time
+       * during the section creating.
+       */
+      if (Section->Segment == NULL)
+         return;
+
       if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
-       {
-         ULONG Offset;
-         ULONG Length;
-         ULONG Entry;
-         PMM_SECTION_SEGMENT Segment;
-         
-         Segment = Section->Segment;
-         Length = PAGE_ROUND_UP(Segment->Length);
-         
-         for (Offset = 0; Offset < Length; Offset += PAGE_SIZE)
-           {
-             Entry = MmGetPageEntrySectionSegment(Segment, Offset);
-             if (Entry)
-               {
-                 if (IS_SWAP_FROM_SSE(Entry))
-                   {
-                     MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
-                   }
-                 else
-                   {
-                     PHYSICAL_ADDRESS Page = (PHYSICAL_ADDRESS)(LONGLONG)PAGE_FROM_SSE(Entry);
-                     MmReleasePageMemoryConsumer(MC_USER, Page);
-                   }
-               }
-           }
-         MmFreePageTablesSectionSegment(Section->Segment);
-         ExFreePool(Section->Segment);
-         Section->Segment = NULL;
-       }
+      {
+         MmpFreePageFileSegment(Section->Segment);
+         MmFreePageTablesSectionSegment(Section->Segment);
+         ExFreePool(Section->Segment);
+         Section->Segment = NULL;
+      }
       else
-       {
-         InterlockedDecrement((LONG *)&Section->Segment->ReferenceCount);
-       }
-    }
-  if (Section->FileObject != NULL)
-    {
+      {
+         InterlockedDecrementUL(&Section->Segment->ReferenceCount);
+      }
+   }
+   if (Section->FileObject != NULL)
+   {
       CcRosDereferenceCache(Section->FileObject);
       ObDereferenceObject(Section->FileObject);
       Section->FileObject = NULL;
-    }  
+   }
 }
 
 VOID STDCALL
 MmpCloseSection(PVOID ObjectBody,
-               ULONG HandleCount)
+                ULONG HandleCount)
 {
    DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
-          ObjectBody, HandleCount, ObGetObjectPointerCount(ObjectBody));
-}
-
-NTSTATUS STDCALL
-MmpCreateSection(PVOID ObjectBody,
-                PVOID Parent,
-                PWSTR RemainingPath,
-                POBJECT_ATTRIBUTES ObjectAttributes)
-{
-   DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
-          ObjectBody, Parent, RemainingPath);
-   
-   if (RemainingPath == NULL)
-     {
-        return(STATUS_SUCCESS);
-     }
-   
-   if (wcschr(RemainingPath+1, L'\\') != NULL)
-     {
-       return(STATUS_UNSUCCESSFUL);
-     }
-   return(STATUS_SUCCESS);
+          ObjectBody, HandleCount, ObGetObjectPointerCount(ObjectBody));
 }
 
-NTSTATUS INIT_FUNCTION
+NTSTATUS
+INIT_FUNCTION
+NTAPI
 MmCreatePhysicalMemorySection(VOID)
 {
-  HANDLE PhysSectionH;
-  PSECTION_OBJECT PhysSection;
-  NTSTATUS Status;
-  OBJECT_ATTRIBUTES Obj;
-  UNICODE_STRING Name = UNICODE_STRING_INITIALIZER(L"\\Device\\PhysicalMemory");
-  LARGE_INTEGER SectionSize;
-   
-  /*
-   * Create the section mapping physical memory 
-   */
-  SectionSize.QuadPart = 0xFFFFFFFF;
-  InitializeObjectAttributes(&Obj,
-                            &Name,
-                            0,
-                            NULL,
-                            NULL);
-  Status = NtCreateSection(&PhysSectionH,
-                          SECTION_ALL_ACCESS,
-                          &Obj,
-                          &SectionSize,
-                          PAGE_EXECUTE_READWRITE,
-                          0,
-                          NULL);
-  if (!NT_SUCCESS(Status))
-    {
+   PSECTION_OBJECT PhysSection;
+   NTSTATUS Status;
+   OBJECT_ATTRIBUTES Obj;
+   UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
+   LARGE_INTEGER SectionSize;
+
+   /*
+    * Create the section mapping physical memory
+    */
+   SectionSize.QuadPart = 0xFFFFFFFF;
+   InitializeObjectAttributes(&Obj,
+                              &Name,
+                              OBJ_PERMANENT,
+                              NULL,
+                              NULL);
+   Status = MmCreateSection(&PhysSection,
+                            SECTION_ALL_ACCESS,
+                            &Obj,
+                            &SectionSize,
+                            PAGE_EXECUTE_READWRITE,
+                            0,
+                            NULL,
+                            NULL);
+   if (!NT_SUCCESS(Status))
+   {
       DbgPrint("Failed to create PhysicalMemory section\n");
       KEBUGCHECK(0);
-    }
-  Status = ObReferenceObjectByHandle(PhysSectionH,
-                                    SECTION_ALL_ACCESS,
-                                    NULL,
-                                    KernelMode,
-                                    (PVOID*)&PhysSection,
-                                    NULL);
-  if (!NT_SUCCESS(Status))
-    {
-      DbgPrint("Failed to reference PhysicalMemory section\n");
-      KEBUGCHECK(0);
-    }
-  PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
-  ObDereferenceObject((PVOID)PhysSection);
-   
-  return(STATUS_SUCCESS);
+   }
+   Status = ObInsertObject(PhysSection,
+                           NULL,
+                           SECTION_ALL_ACCESS,
+                           0,
+                           NULL,
+                           NULL);
+   if (!NT_SUCCESS(Status))
+   {
+      ObDereferenceObject(PhysSection);
+   }
+   PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
+   PhysSection->Segment->Flags &= ~MM_PAGEFILE_SEGMENT;
+
+   return(STATUS_SUCCESS);
 }
 
-NTSTATUS INIT_FUNCTION
+NTSTATUS
+INIT_FUNCTION
+NTAPI
 MmInitSectionImplementation(VOID)
 {
-   MmSectionObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
-   
-   RtlInitUnicodeStringFromLiteral(&MmSectionObjectType->TypeName, L"Section");
-   
-   MmSectionObjectType->Tag = TAG('S', 'E', 'C', 'T');
-   MmSectionObjectType->TotalObjects = 0;
-   MmSectionObjectType->TotalHandles = 0;
-   MmSectionObjectType->MaxObjects = ULONG_MAX;
-   MmSectionObjectType->MaxHandles = ULONG_MAX;
-   MmSectionObjectType->PagedPoolCharge = 0;
-   MmSectionObjectType->NonpagedPoolCharge = sizeof(SECTION_OBJECT);
-   MmSectionObjectType->Mapping = &MmpSectionMapping;
-   MmSectionObjectType->Dump = NULL;
-   MmSectionObjectType->Open = NULL;
-   MmSectionObjectType->Close = MmpCloseSection;
-   MmSectionObjectType->Delete = MmpDeleteSection;
-   MmSectionObjectType->Parse = NULL;
-   MmSectionObjectType->Security = NULL;
-   MmSectionObjectType->QueryName = NULL;
-   MmSectionObjectType->OkayToClose = NULL;
-   MmSectionObjectType->Create = MmpCreateSection;
-   MmSectionObjectType->DuplicationNotify = NULL;
-   
-   /*
-    * NOTE: Do not register the section object type here because
-    * the object manager it not initialized yet!
-    * The section object type will be created in ObInit().
-    */
+   OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
+   UNICODE_STRING Name;
+
+   DPRINT("Creating Section Object Type\n");
+  
+   /* Initialize the Section object type  */
+   RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
+   RtlInitUnicodeString(&Name, L"Section");
+   ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
+   ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(SECTION_OBJECT);
+   ObjectTypeInitializer.PoolType = PagedPool;
+   ObjectTypeInitializer.UseDefaultObject = TRUE;
+   ObjectTypeInitializer.GenericMapping = MmpSectionMapping;
+   ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection;
+   ObjectTypeInitializer.CloseProcedure = MmpCloseSection;
+   ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &MmSectionObjectType);
 
    return(STATUS_SUCCESS);
 }
 
 NTSTATUS
-MmCreatePageFileSection(PHANDLE SectionHandle,
-                       ACCESS_MASK DesiredAccess,
-                       POBJECT_ATTRIBUTES ObjectAttributes,
-                       PLARGE_INTEGER UMaximumSize,
-                       ULONG SectionPageProtection,
-                       ULONG AllocationAttributes)
-     /*
-      * Create a section which is backed by the pagefile
-      */
+NTAPI
+MmCreatePageFileSection(PSECTION_OBJECT *SectionObject,
+                        ACCESS_MASK DesiredAccess,
+                        POBJECT_ATTRIBUTES ObjectAttributes,
+                        PLARGE_INTEGER UMaximumSize,
+                        ULONG SectionPageProtection,
+                        ULONG AllocationAttributes)
+/*
+ * Create a section which is backed by the pagefile
+ */
 {
-  LARGE_INTEGER MaximumSize;
-  PSECTION_OBJECT Section;
-  PMM_SECTION_SEGMENT Segment;
-  NTSTATUS Status;
+   LARGE_INTEGER MaximumSize;
+   PSECTION_OBJECT Section;
+   PMM_SECTION_SEGMENT Segment;
+   NTSTATUS Status;
 
-  if (UMaximumSize == NULL)
-    {
+   if (UMaximumSize == NULL)
+   {
       return(STATUS_UNSUCCESSFUL);
-    }
-  MaximumSize = *UMaximumSize;
-  
-  /*
-   * Check the protection
-   */
-  if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) != 
-      SectionPageProtection)
-    {
-      return(STATUS_INVALID_PAGE_PROTECTION);
-    }
-  
-  /*
-   * Create the section
-   */
-  Status = ObCreateObject(ExGetPreviousMode(),
-                         MmSectionObjectType,
-                         ObjectAttributes,
-                         ExGetPreviousMode(),
-                         NULL,
-                         sizeof(SECTION_OBJECT),
-                         0,
-                         0,
-                         (PVOID*)&Section);
-  if (!NT_SUCCESS(Status))
-    {
-      return(Status);
-    }
-
-  Status = ObInsertObject ((PVOID)Section,
-                          NULL,
-                          DesiredAccess,
-                          0,
-                          NULL,
-                          SectionHandle);
-  if (!NT_SUCCESS(Status))
-    {
-      ObDereferenceObject(Section);
+   }
+   MaximumSize = *UMaximumSize;
+
+   /*
+    * Create the section
+    */
+   Status = ObCreateObject(ExGetPreviousMode(),
+                           MmSectionObjectType,
+                           ObjectAttributes,
+                           ExGetPreviousMode(),
+                           NULL,
+                           sizeof(SECTION_OBJECT),
+                           0,
+                           0,
+                           (PVOID*)(PVOID)&Section);
+   if (!NT_SUCCESS(Status))
+   {
       return(Status);
-    }
-
-  /*
-   * Initialize it
-   */
-  Section->SectionPageProtection = SectionPageProtection;
-  Section->AllocationAttributes = AllocationAttributes;
-  InitializeListHead(&Section->ViewListHead);
-  KeInitializeSpinLock(&Section->ViewListLock);
-  Section->FileObject = NULL;
-  Section->MaximumSize = MaximumSize;
-  Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
-                                 TAG_MM_SECTION_SEGMENT);
-  if (Segment == NULL)
-    {
-      ZwClose(*SectionHandle);
+   }
+
+   /*
+    * Initialize it
+    */
+   Section->SectionPageProtection = SectionPageProtection;
+   Section->AllocationAttributes = AllocationAttributes;
+   Section->Segment = NULL;
+   Section->FileObject = NULL;
+   Section->MaximumSize = MaximumSize;
+   Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
+                                   TAG_MM_SECTION_SEGMENT);
+   if (Segment == NULL)
+   {
       ObDereferenceObject(Section);
       return(STATUS_NO_MEMORY);
-    }
-  Section->Segment = Segment;
-  Segment->ReferenceCount = 1;
-  ExInitializeFastMutex(&Segment->Lock);
-  Segment->FileOffset = 0;
-  Segment->Protection = SectionPageProtection;
-  Segment->Attributes = AllocationAttributes;
-  Segment->Length = MaximumSize.u.LowPart;
-  Segment->Flags = MM_PAGEFILE_SEGMENT;
-  Segment->WriteCopy = FALSE;
-  ObDereferenceObject(Section);
-  return(STATUS_SUCCESS);
+   }
+   Section->Segment = Segment;
+   Segment->ReferenceCount = 1;
+   ExInitializeFastMutex(&Segment->Lock);
+   Segment->FileOffset = 0;
+   Segment->Protection = SectionPageProtection;
+   Segment->RawLength = MaximumSize.u.LowPart;
+   Segment->Length = PAGE_ROUND_UP(MaximumSize.u.LowPart);
+   Segment->Flags = MM_PAGEFILE_SEGMENT;
+   Segment->WriteCopy = FALSE;
+   RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
+   Segment->VirtualAddress = 0;
+   Segment->Characteristics = 0;
+   *SectionObject = Section;
+   return(STATUS_SUCCESS);
 }
 
 
 NTSTATUS
-MmCreateDataFileSection(PHANDLE SectionHandle,
-                       ACCESS_MASK DesiredAccess,
-                       POBJECT_ATTRIBUTES ObjectAttributes,
-                       PLARGE_INTEGER UMaximumSize,
-                       ULONG SectionPageProtection,
-                       ULONG AllocationAttributes,
-                       HANDLE FileHandle)
-     /*
-      * Create a section backed by a data file
-      */
+NTAPI
+MmCreateDataFileSection(PSECTION_OBJECT *SectionObject,
+                        ACCESS_MASK DesiredAccess,
+                        POBJECT_ATTRIBUTES ObjectAttributes,
+                        PLARGE_INTEGER UMaximumSize,
+                        ULONG SectionPageProtection,
+                        ULONG AllocationAttributes,
+                        HANDLE FileHandle)
+/*
+ * Create a section backed by a data file
+ */
 {
-  PSECTION_OBJECT Section;
-  NTSTATUS Status;
-  LARGE_INTEGER MaximumSize;
-  PFILE_OBJECT FileObject;
-  PMM_SECTION_SEGMENT Segment;
-  ULONG FileAccess;
-  IO_STATUS_BLOCK Iosb;
-  LARGE_INTEGER Offset;
-  CHAR Buffer;
-  
-  /*
-   * Check the protection
-   */
-  if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) != 
-      SectionPageProtection)
-    {
-      return(STATUS_INVALID_PAGE_PROTECTION);
-    }
-  /*
-   * Create the section
-   */
-  Status = ObCreateObject(ExGetPreviousMode(),
-                         MmSectionObjectType,
-                         ObjectAttributes,
-                         ExGetPreviousMode(),
-                         NULL,
-                         sizeof(SECTION_OBJECT),
-                         0,
-                         0,
-                         (PVOID*)&Section);
-  if (!NT_SUCCESS(Status))
-    {
-      return(Status);
-    }
-
-  Status = ObInsertObject ((PVOID)Section,
-                          NULL,
-                          DesiredAccess,
-                          0,
-                          NULL,
-                          SectionHandle);
-  if (!NT_SUCCESS(Status))
-    {
-      ObDereferenceObject(Section);
+   PSECTION_OBJECT Section;
+   NTSTATUS Status;
+   LARGE_INTEGER MaximumSize;
+   PFILE_OBJECT FileObject;
+   PMM_SECTION_SEGMENT Segment;
+   ULONG FileAccess;
+   IO_STATUS_BLOCK Iosb;
+   LARGE_INTEGER Offset;
+   CHAR Buffer;
+   FILE_STANDARD_INFORMATION FileInfo;
+
+   /*
+    * Create the section
+    */
+   Status = ObCreateObject(ExGetPreviousMode(),
+                           MmSectionObjectType,
+                           ObjectAttributes,
+                           ExGetPreviousMode(),
+                           NULL,
+                           sizeof(SECTION_OBJECT),
+                           0,
+                           0,
+                           (PVOID*)(PVOID)&Section);
+   if (!NT_SUCCESS(Status))
+   {
       return(Status);
-    }
-
-  /*
-   * Initialize it
-   */
-  Section->SectionPageProtection = SectionPageProtection;
-  Section->AllocationAttributes = AllocationAttributes;
-  InitializeListHead(&Section->ViewListHead);
-  KeInitializeSpinLock(&Section->ViewListLock);
-
-  /*
-   * Check file access required
-   */
-  if (SectionPageProtection & PAGE_READWRITE ||
-      SectionPageProtection & PAGE_EXECUTE_READWRITE)
-    {
+   }
+   /*
+    * Initialize it
+    */
+   Section->SectionPageProtection = SectionPageProtection;
+   Section->AllocationAttributes = AllocationAttributes;
+   Section->Segment = NULL;
+
+   /*
+    * Check file access required
+    */
+   if (SectionPageProtection & PAGE_READWRITE ||
+         SectionPageProtection & PAGE_EXECUTE_READWRITE)
+   {
       FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
-    }
-  else
-    {
+   }
+   else
+   {
       FileAccess = FILE_READ_DATA;
-    }
-  
-  /*
-   * Reference the file handle
-   */
-  Status = ObReferenceObjectByHandle(FileHandle,
-                                    FileAccess,
-                                    IoFileObjectType,
-                                    UserMode,
-                                    (PVOID*)&FileObject,
-                                    NULL);
-  if (!NT_SUCCESS(Status))
-    {
-      ZwClose(*SectionHandle);
+   }
+
+   /*
+    * Reference the file handle
+    */
+   Status = ObReferenceObjectByHandle(FileHandle,
+                                      FileAccess,
+                                      IoFileObjectType,
+                                      UserMode,
+                                      (PVOID*)(PVOID)&FileObject,
+                                      NULL);
+   if (!NT_SUCCESS(Status))
+   {
       ObDereferenceObject(Section);
       return(Status);
-    }
-
-  /*
-   * We can't do memory mappings if the file system doesn't support the
-   * standard FCB
-   */
-  if (!(FileObject->Flags & FO_FCB_IS_VALID))
-    {
-      ZwClose(*SectionHandle);
+   }
+
+   /*
+    * FIXME: This is propably not entirely correct. We can't look into
+    * the standard FCB header because it might not be initialized yet
+    * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
+    * standard file information is filled on first request).
+    */
+   Status = IoQueryFileInformation(FileObject,
+                                   FileStandardInformation,
+                                   sizeof(FILE_STANDARD_INFORMATION),
+                                   &FileInfo,
+                                   &Iosb.Information);
+   if (!NT_SUCCESS(Status))
+   {
       ObDereferenceObject(Section);
       ObDereferenceObject(FileObject);
-      return(STATUS_INVALID_FILE_FOR_SECTION);
-    }
-  
-  /*
-   * FIXME: Revise this once a locking order for file size changes is
-   * decided
-   */
-  if (UMaximumSize != NULL)
-    {
+      return Status;
+   }
+
+   /*
+    * FIXME: Revise this once a locking order for file size changes is
+    * decided
+    */
+   if (UMaximumSize != NULL)
+   {
       MaximumSize = *UMaximumSize;
-    }
-  else
-    {
-      MaximumSize = 
-       ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize;
-    }
-
-  if (MaximumSize.QuadPart > 
-      ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize.QuadPart)
-    {
-      Status = NtSetInformationFile(FileHandle,
-                                   &Iosb,
-                                   &MaximumSize,
-                                   sizeof(LARGE_INTEGER),
-                                   FileAllocationInformation);
+   }
+   else
+   {
+      MaximumSize = FileInfo.EndOfFile;
+      /* Mapping zero-sized files isn't allowed. */
+      if (MaximumSize.QuadPart == 0)
+      {
+         ObDereferenceObject(Section);
+         ObDereferenceObject(FileObject);
+         return STATUS_FILE_INVALID;
+      }
+   }
+
+   if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart)
+   {
+      Status = IoSetInformation(FileObject,
+                                FileAllocationInformation,
+                                sizeof(LARGE_INTEGER),
+                                &MaximumSize);
       if (!NT_SUCCESS(Status))
-       {
-         ZwClose(*SectionHandle);
-         ObDereferenceObject(Section);
-         ObDereferenceObject(FileObject);
-         return(STATUS_SECTION_NOT_EXTENDED);
-       }
-    }
-
-  if (FileObject->SectionObjectPointer == NULL ||
-      FileObject->SectionObjectPointer->SharedCacheMap == NULL)
-    {
+      {
+         ObDereferenceObject(Section);
+         ObDereferenceObject(FileObject);
+         return(STATUS_SECTION_NOT_EXTENDED);
+      }
+   }
+
+   if (FileObject->SectionObjectPointer == NULL ||
+         FileObject->SectionObjectPointer->SharedCacheMap == NULL)
+   {
       /*
        * Read a bit so caching is initiated for the file object.
        * This is only needed because MiReadPage currently cannot
@@ -2413,64 +2402,56 @@ MmCreateDataFileSection(PHANDLE SectionHandle,
        */
       Offset.QuadPart = 0;
       Status = ZwReadFile(FileHandle,
-                         NULL,
-                         NULL,
-                         NULL,
-                         &Iosb,
-                         &Buffer,
-                         sizeof (Buffer),
-                         &Offset,
-                         0);
+                          NULL,
+                          NULL,
+                          NULL,
+                          &Iosb,
+                          &Buffer,
+                          sizeof (Buffer),
+                          &Offset,
+                          0);
       if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
-        {
-          ZwClose(*SectionHandle);
-          ObDereferenceObject(Section);
-          ObDereferenceObject(FileObject);
-          return(Status);
-        }
+      {
+         ObDereferenceObject(Section);
+         ObDereferenceObject(FileObject);
+         return(Status);
+      }
       if (FileObject->SectionObjectPointer == NULL ||
-          FileObject->SectionObjectPointer->SharedCacheMap == NULL)
-        {
-         /* FIXME: handle this situation */
-          ZwClose(*SectionHandle);
-          ObDereferenceObject(Section);
-          ObDereferenceObject(FileObject);
-         return STATUS_INVALID_PARAMETER; 
-       }
-    }
-
-  /*
-   * Lock the file
-   */
-  Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
-                                0,
-                                KernelMode,
-                                FALSE,
-                                NULL);
-  if (Status != STATUS_SUCCESS)
-    {
-      ZwClose(*SectionHandle);
+            FileObject->SectionObjectPointer->SharedCacheMap == NULL)
+      {
+         /* FIXME: handle this situation */
+         ObDereferenceObject(Section);
+         ObDereferenceObject(FileObject);
+         return STATUS_INVALID_PARAMETER;
+      }
+   }
+
+   /*
+    * Lock the file
+    */
+   Status = MmspWaitForFileLock(FileObject);
+   if (Status != STATUS_SUCCESS)
+   {
       ObDereferenceObject(Section);
       ObDereferenceObject(FileObject);
       return(Status);
-    }
-
-  /*
-   * If this file hasn't been mapped as a data file before then allocate a
-   * section segment to describe the data file mapping
-   */
-  if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
-    {
+   }
+
+   /*
+    * If this file hasn't been mapped as a data file before then allocate a
+    * section segment to describe the data file mapping
+    */
+   if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
+   {
       Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
-                                     TAG_MM_SECTION_SEGMENT);
+                                      TAG_MM_SECTION_SEGMENT);
       if (Segment == NULL)
-       {
-         KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
-         ZwClose(*SectionHandle);
-         ObDereferenceObject(Section);
-         ObDereferenceObject(FileObject);
-         return(STATUS_NO_MEMORY);
-       }
+      {
+         KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
+         ObDereferenceObject(Section);
+         ObDereferenceObject(FileObject);
+         return(STATUS_NO_MEMORY);
+      }
       Section->Segment = Segment;
       Segment->ReferenceCount = 1;
       ExInitializeFastMutex(&Segment->Lock);
@@ -2481,518 +2462,880 @@ MmCreateDataFileSection(PHANDLE SectionHandle,
       FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
 
       Segment->FileOffset = 0;
-      Segment->Protection = 0;
-      Segment->Attributes = 0;
+      Segment->Protection = SectionPageProtection;
       Segment->Flags = MM_DATAFILE_SEGMENT;
       Segment->Characteristics = 0;
       Segment->WriteCopy = FALSE;
       if (AllocationAttributes & SEC_RESERVE)
-       {
-         Segment->Length = Segment->RawLength = 0;
-       }
+      {
+         Segment->Length = Segment->RawLength = 0;
+      }
       else
-       {
-         Segment->RawLength = MaximumSize.u.LowPart;
-         Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
-       }
-      Segment->VirtualAddress = NULL;
-    }
-  else
-    {
+      {
+         Segment->RawLength = MaximumSize.u.LowPart;
+         Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
+      }
+      Segment->VirtualAddress = 0;
+      RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
+   }
+   else
+   {
       /*
        * If the file is already mapped as a data file then we may need
        * to extend it
-       */      
-      Segment = 
-       (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
-       DataSectionObject;
+       */
+      Segment =
+         (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
+         DataSectionObject;
       Section->Segment = Segment;
-      InterlockedIncrement((PLONG)&Segment->ReferenceCount);
+      InterlockedIncrementUL(&Segment->ReferenceCount);
       MmLockSectionSegment(Segment);
 
-      if (MaximumSize.u.LowPart > Segment->RawLength && 
-         !(AllocationAttributes & SEC_RESERVE))
-       {
-         Segment->RawLength = MaximumSize.u.LowPart;
-         Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
-       }
-    }
-  MmUnlockSectionSegment(Segment);
-  Section->FileObject = FileObject; 
-  Section->MaximumSize = MaximumSize;
-  CcRosReferenceCache(FileObject);
-  KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
-  ObDereferenceObject(Section);
-  return(STATUS_SUCCESS);
+      if (MaximumSize.u.LowPart > Segment->RawLength &&
+            !(AllocationAttributes & SEC_RESERVE))
+      {
+         Segment->RawLength = MaximumSize.u.LowPart;
+         Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
+      }
+   }
+   MmUnlockSectionSegment(Segment);
+   Section->FileObject = FileObject;
+   Section->MaximumSize = MaximumSize;
+   CcRosReferenceCache(FileObject);
+   KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
+   *SectionObject = Section;
+   return(STATUS_SUCCESS);
 }
 
-static ULONG SectionCharacteristicsToProtect[16] = 
+/*
+ TODO: not that great (declaring loaders statically, having to declare all of
+ them, having to keep them extern, etc.), will fix in the future
+*/
+extern NTSTATUS NTAPI PeFmtCreateSection
+(
+ IN CONST VOID * FileHeader,
+ IN SIZE_T FileHeaderSize,
+ IN PVOID File,
+ OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
+ OUT PULONG Flags,
+ IN PEXEFMT_CB_READ_FILE ReadFileCb,
+ IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
+);
+
+extern NTSTATUS NTAPI ElfFmtCreateSection
+(
+ IN CONST VOID * FileHeader,
+ IN SIZE_T FileHeaderSize,
+ IN PVOID File,
+ OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
+ OUT PULONG Flags,
+ IN PEXEFMT_CB_READ_FILE ReadFileCb,
+ IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
+);
+
+/* TODO: this is a standard DDK/PSDK macro */
+#ifndef RTL_NUMBER_OF
+#define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
+#endif
+
+static PEXEFMT_LOADER ExeFmtpLoaders[] =
 {
-  PAGE_NOACCESS,               // 0 = NONE
-  PAGE_NOACCESS,               // 1 = SHARED
-  PAGE_EXECUTE,                // 2 = EXECUTABLE
-  PAGE_EXECUTE,                // 3 = EXECUTABLE, SHARED
-  PAGE_READONLY,               // 4 = READABLE
-  PAGE_READONLY,               // 5 = READABLE, SHARED
-  PAGE_EXECUTE_READ,           // 6 = READABLE, EXECUTABLE
-  PAGE_EXECUTE_READ,           // 7 = READABLE, EXECUTABLE, SHARED
-  PAGE_READWRITE,              // 8 = WRITABLE
-  PAGE_READWRITE,              // 9 = WRITABLE, SHARED
-  PAGE_EXECUTE_READWRITE,      // 10 = WRITABLE, EXECUTABLE
-  PAGE_EXECUTE_READWRITE,      // 11 = WRITABLE, EXECUTABLE, SHARED
-  PAGE_READWRITE,              // 12 = WRITABLE, READABLE
-  PAGE_READWRITE,              // 13 = WRITABLE, READABLE, SHARED
-  PAGE_EXECUTE_READWRITE,      // 14 = WRITABLE, READABLE, EXECUTABLE,
-  PAGE_EXECUTE_READWRITE,      // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
+ PeFmtCreateSection,
+ ElfFmtCreateSection
 };
 
+static
+PMM_SECTION_SEGMENT
+NTAPI
+ExeFmtpAllocateSegments(IN ULONG NrSegments)
+{
+ SIZE_T SizeOfSegments;
+ PMM_SECTION_SEGMENT Segments;
+
+ /* TODO: check for integer overflow */
+ SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments;
+
+ Segments = ExAllocatePoolWithTag(NonPagedPool,
+                                  SizeOfSegments,
+                                  TAG_MM_SECTION_SEGMENT);
+
+ if(Segments)
+  RtlZeroMemory(Segments, SizeOfSegments);
+
+ return Segments;
+}
+
+static
 NTSTATUS
-MmCreateImageSection(PHANDLE SectionHandle,
-                    ACCESS_MASK DesiredAccess,
-                    POBJECT_ATTRIBUTES ObjectAttributes,
-                    PLARGE_INTEGER UMaximumSize,
-                    ULONG SectionPageProtection,
-                    ULONG AllocationAttributes,
-                    HANDLE FileHandle)
+NTAPI
+ExeFmtpReadFile(IN PVOID File,
+                IN PLARGE_INTEGER Offset,
+                IN ULONG Length,
+                OUT PVOID * Data,
+                OUT PVOID * AllocBase,
+                OUT PULONG ReadSize)
 {
-  PSECTION_OBJECT Section;
-  NTSTATUS Status;
-  PFILE_OBJECT FileObject;
-  IMAGE_DOS_HEADER DosHeader;
-  IO_STATUS_BLOCK Iosb;
-  LARGE_INTEGER Offset;
-  IMAGE_NT_HEADERS PEHeader;
-  PIMAGE_SECTION_HEADER ImageSections;
-  PMM_SECTION_SEGMENT SectionSegments;
-  ULONG NrSegments;
-  PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
-  ULONG i;
-  ULONG Size;
-  ULONG Characteristics;
-  ULONG FileAccess = 0;
-  /*
-   * Check the protection
-   */
-  if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) != 
-      SectionPageProtection)
-    {
-      return(STATUS_INVALID_PAGE_PROTECTION);
-    }
-  
-  /*
-   * Specifying a maximum size is meaningless for an image section
-   */
-  if (UMaximumSize != NULL)
-    {
-      return(STATUS_INVALID_PARAMETER_4);
-    } 
-
-  /*
-   * Reference the file handle
-   */
-  Status = ObReferenceObjectByHandle(FileHandle,
-                                    FileAccess,
-                                    IoFileObjectType,
-                                    UserMode,
-                                    (PVOID*)&FileObject,
-                                    NULL);
-  if (!NT_SUCCESS(Status))
-    {
-      return Status;
-    }
+   NTSTATUS Status;
+   LARGE_INTEGER FileOffset;
+   ULONG AdjustOffset;
+   ULONG OffsetAdjustment;
+   ULONG BufferSize;
+   ULONG UsedSize;
+   PVOID Buffer;
 
-  /*
-   * Initialized caching for this file object if previously caching 
-   * was initialized for the same on disk file
-   */
-  Status = CcTryToInitializeFileCache(FileObject);
-  
-  if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
-    {
+   ASSERT_IRQL_LESS(DISPATCH_LEVEL);
+
+   if(Length == 0)
+   {
+      KEBUGCHECK(STATUS_INVALID_PARAMETER_4);
+   }
+
+   FileOffset = *Offset;
+
+   /* Negative/special offset: it cannot be used in this context */
+   if(FileOffset.u.HighPart < 0)
+   {
+      KEBUGCHECK(STATUS_INVALID_PARAMETER_5);
+   }
+
+   AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart);
+   OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset;
+   FileOffset.u.LowPart = AdjustOffset;
+
+   BufferSize = Length + OffsetAdjustment;
+   BufferSize = PAGE_ROUND_UP(BufferSize);
+
+   /*
+    * It's ok to use paged pool, because this is a temporary buffer only used in
+    * the loading of executables. The assumption is that MmCreateSection is
+    * always called at low IRQLs and that these buffers don't survive a brief
+    * initialization phase
+    */
+   Buffer = ExAllocatePoolWithTag(PagedPool,
+                                  BufferSize,
+                                  TAG('M', 'm', 'X', 'r'));
+
+   UsedSize = 0;
+
+#if 0
+   Status = MmspPageRead(File,
+                         Buffer,
+                         BufferSize,
+                         &FileOffset,
+                         &UsedSize);
+#else
+/*
+ * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
+ * nothing will work. But using ZwReadFile is wrong, and using its side effects
+ * to initialize internal state is even worse. Our cache manager is in need of
+ * professional help
+ */
+   {
+      IO_STATUS_BLOCK Iosb;
+
+      Status = ZwReadFile(File,
+                          NULL,
+                          NULL,
+                          NULL,
+                          &Iosb,
+                          Buffer,
+                          BufferSize,
+                          &FileOffset,
+                          NULL);
+
+      if(NT_SUCCESS(Status))
+      {
+         UsedSize = Iosb.Information;
+      }
+   }
+#endif
+
+   if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
+   {
+      Status = STATUS_IN_PAGE_ERROR;
+      ASSERT(!NT_SUCCESS(Status));
+   }
+
+   if(NT_SUCCESS(Status))
+   {
+      *Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment);
+      *AllocBase = Buffer;
+      *ReadSize = UsedSize - OffsetAdjustment;
+   }
+   else
+   {
+      ExFreePool(Buffer);
+   }
+
+   return Status;
+}
+
+#ifdef NASSERT
+# define MmspAssertSegmentsSorted(OBJ_) ((void)0)
+# define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
+# define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
+#else
+static
+VOID
+NTAPI
+MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
+{
+   ULONG i;
+
+   for( i = 1; i < ImageSectionObject->NrSegments; ++ i )
+   {
+      ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
+             ImageSectionObject->Segments[i - 1].VirtualAddress);
+   }
+}
+
+static
+VOID
+NTAPI
+MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
+{
+   ULONG i;
+
+   MmspAssertSegmentsSorted(ImageSectionObject);
+
+   for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
+   {
+      ASSERT(ImageSectionObject->Segments[i].Length > 0);
+
+      if(i > 0)
+      {
+         ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
+                (ImageSectionObject->Segments[i - 1].VirtualAddress +
+                 ImageSectionObject->Segments[i - 1].Length));
+      }
+   }
+}
+
+static
+VOID
+NTAPI
+MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
+{
+   ULONG i;
+
+   for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
+   {
+      ASSERT((ImageSectionObject->Segments[i].VirtualAddress % PAGE_SIZE) == 0);
+      ASSERT((ImageSectionObject->Segments[i].Length % PAGE_SIZE) == 0);
+   }
+}
+#endif
+
+static
+int
+__cdecl
+MmspCompareSegments(const void * x,
+                    const void * y)
+{
+   PMM_SECTION_SEGMENT Segment1 = (PMM_SECTION_SEGMENT)x;
+   PMM_SECTION_SEGMENT Segment2 = (PMM_SECTION_SEGMENT)y;
+
+   return
+      (Segment1->VirtualAddress - Segment2->VirtualAddress) >>
+      ((sizeof(ULONG_PTR) - sizeof(int)) * 8);
+}
+
+/*
+ * Ensures an image section's segments are sorted in memory
+ */
+static
+VOID
+NTAPI
+MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
+                 IN ULONG Flags)
+{
+   if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED)
+   {
+      MmspAssertSegmentsSorted(ImageSectionObject);
+   }
+   else
+   {
+      qsort(ImageSectionObject->Segments,
+            ImageSectionObject->NrSegments,
+            sizeof(ImageSectionObject->Segments[0]),
+            MmspCompareSegments);
+   }
+}
+
+
+/*
+ * Ensures an image section's segments don't overlap in memory and don't have
+ * gaps and don't have a null size. We let them map to overlapping file regions,
+ * though - that's not necessarily an error
+ */
+static
+BOOLEAN
+NTAPI
+MmspCheckSegmentBounds
+(
+ IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
+ IN ULONG Flags
+)
+{
+   ULONG i;
+
+   if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP)
+   {
+      MmspAssertSegmentsNoOverlap(ImageSectionObject);
+      return TRUE;
+   }
+
+   ASSERT(ImageSectionObject->NrSegments >= 1);
+
+   for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
+   {
+      if(ImageSectionObject->Segments[i].Length == 0)
+      {
+         return FALSE;
+      }
+
+      if(i > 0)
+      {
+         /*
+          * TODO: relax the limitation on gaps. For example, gaps smaller than a
+          * page could be OK (Windows seems to be OK with them), and larger gaps
+          * could lead to image sections spanning several discontiguous regions
+          * (NtMapViewOfSection could then refuse to map them, and they could
+          * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
+          */
+         if ((ImageSectionObject->Segments[i - 1].VirtualAddress +
+              ImageSectionObject->Segments[i - 1].Length) !=
+              ImageSectionObject->Segments[i].VirtualAddress)
+         {
+            return FALSE;
+         }
+      }
+   }
+
+   return TRUE;
+}
+
+/*
+ * Merges and pads an image section's segments until they all are page-aligned
+ * and have a size that is a multiple of the page size
+ */
+static
+BOOLEAN
+NTAPI
+MmspPageAlignSegments
+(
+ IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
+ IN ULONG Flags
+)
+{
+   ULONG i;
+   ULONG LastSegment;
+   BOOLEAN Initialized;
+   PMM_SECTION_SEGMENT EffectiveSegment;
+
+   if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED)
+   {
+      MmspAssertSegmentsPageAligned(ImageSectionObject);
+      return TRUE;
+   }
+
+   Initialized = FALSE;
+   LastSegment = 0;
+   EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
+
+   for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
+   {
       /*
-       * Read the dos header and check the DOS signature
+       * The first segment requires special handling
        */
-      Offset.QuadPart = 0;
-      Status = ZwReadFile(FileHandle,
-                         NULL,
-                         NULL,
-                         NULL,
-                         &Iosb,
-                         &DosHeader,
-                         sizeof(DosHeader),
-                         &Offset,
-                         0);
+      if (i == 0)
+      {
+         ULONG_PTR VirtualAddress;
+         ULONG_PTR VirtualOffset;
+
+         VirtualAddress = EffectiveSegment->VirtualAddress;
+
+         /* Round down the virtual address to the nearest page */
+         EffectiveSegment->VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
+
+         /* Round up the virtual size to the nearest page */
+         EffectiveSegment->Length = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length) -
+                                    EffectiveSegment->VirtualAddress;
+
+         /* Adjust the raw address and size */
+         VirtualOffset = VirtualAddress - EffectiveSegment->VirtualAddress;
+
+         if (EffectiveSegment->FileOffset < VirtualOffset)
+         {
+            return FALSE;
+         }
+
+         /*
+          * Garbage in, garbage out: unaligned base addresses make the file
+          * offset point in curious and odd places, but that's what we were
+          * asked for
+          */
+         EffectiveSegment->FileOffset -= VirtualOffset;
+         EffectiveSegment->RawLength += VirtualOffset;
+      }
+      else
+      {
+         PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
+         ULONG_PTR EndOfEffectiveSegment;
+
+         EndOfEffectiveSegment = EffectiveSegment->VirtualAddress + EffectiveSegment->Length;
+         ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
+
+         /*
+          * The current segment begins exactly where the current effective
+          * segment ended, therefore beginning a new effective segment
+          */
+         if (EndOfEffectiveSegment == Segment->VirtualAddress)
+         {
+            LastSegment ++;
+            ASSERT(LastSegment <= i);
+            ASSERT(LastSegment < ImageSectionObject->NrSegments);
+
+            EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
+
+            if (LastSegment != i)
+            {
+               /*
+                * Copy the current segment. If necessary, the effective segment
+                * will be expanded later
+                */
+               *EffectiveSegment = *Segment;
+            }
+
+            /*
+             * Page-align the virtual size. We know for sure the virtual address
+             * already is
+             */
+            ASSERT((EffectiveSegment->VirtualAddress % PAGE_SIZE) == 0);
+            EffectiveSegment->Length = PAGE_ROUND_UP(EffectiveSegment->Length);
+         }
+         /*
+          * The current segment is still part of the current effective segment:
+          * extend the effective segment to reflect this
+          */
+         else if (EndOfEffectiveSegment > Segment->VirtualAddress)
+         {
+            static const ULONG FlagsToProtection[16] =
+            {
+               PAGE_NOACCESS,
+               PAGE_READONLY,
+               PAGE_READWRITE,
+               PAGE_READWRITE,
+               PAGE_EXECUTE_READ,
+               PAGE_EXECUTE_READ,
+               PAGE_EXECUTE_READWRITE,
+               PAGE_EXECUTE_READWRITE,
+               PAGE_WRITECOPY,
+               PAGE_WRITECOPY,
+               PAGE_WRITECOPY,
+               PAGE_WRITECOPY,
+               PAGE_EXECUTE_WRITECOPY,
+               PAGE_EXECUTE_WRITECOPY,
+               PAGE_EXECUTE_WRITECOPY,
+               PAGE_EXECUTE_WRITECOPY
+            };
+
+            unsigned ProtectionFlags;
+
+            /*
+             * Extend the file size
+             */
+
+            /* Unaligned segments must be contiguous within the file */
+            if (Segment->FileOffset != (EffectiveSegment->FileOffset +
+                                        EffectiveSegment->RawLength))
+            {
+               return FALSE;
+            }
+
+            EffectiveSegment->RawLength += Segment->RawLength;
+
+            /*
+             * Extend the virtual size
+             */
+            ASSERT(PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) >= EndOfEffectiveSegment);
+
+            EffectiveSegment->Length = PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) -
+                                       EffectiveSegment->VirtualAddress;
+
+            /*
+             * Merge the protection
+             */
+            EffectiveSegment->Protection |= Segment->Protection;
+
+            /* Clean up redundance */
+            ProtectionFlags = 0;
+
+            if(EffectiveSegment->Protection & PAGE_IS_READABLE)
+               ProtectionFlags |= 1 << 0;
+
+            if(EffectiveSegment->Protection & PAGE_IS_WRITABLE)
+               ProtectionFlags |= 1 << 1;
+
+            if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE)
+               ProtectionFlags |= 1 << 2;
+
+            if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
+               ProtectionFlags |= 1 << 3;
+
+            ASSERT(ProtectionFlags < 16);
+            EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags];
+
+            /* If a segment was required to be shared and cannot, fail */
+            if(!(Segment->Protection & PAGE_IS_WRITECOPY) &&
+               EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
+            {
+               return FALSE;
+            }
+         }
+         /*
+          * We assume no holes between segments at this point
+          */
+         else
+         {
+            ASSERT(FALSE);
+         }
+      }
+   }
+   ImageSectionObject->NrSegments = LastSegment + 1;
+
+   return TRUE;
+}
+
+NTSTATUS
+ExeFmtpCreateImageSection(HANDLE FileHandle,
+                          PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
+{
+   LARGE_INTEGER Offset;
+   PVOID FileHeader;
+   PVOID FileHeaderBuffer;
+   ULONG FileHeaderSize;
+   ULONG Flags;
+   ULONG OldNrSegments;
+   NTSTATUS Status;
+   ULONG i;
+
+   /*
+    * Read the beginning of the file (2 pages). Should be enough to contain
+    * all (or most) of the headers
+    */
+   Offset.QuadPart = 0;
+
+   /* FIXME: use FileObject instead of FileHandle */
+   Status = ExeFmtpReadFile (FileHandle,
+                             &Offset,
+                             PAGE_SIZE * 2,
+                             &FileHeader,
+                             &FileHeaderBuffer,
+                             &FileHeaderSize);
+
+   if (!NT_SUCCESS(Status))
+      return Status;
+
+   if (FileHeaderSize == 0)
+   {
+      ExFreePool(FileHeaderBuffer);
+      return STATUS_UNSUCCESSFUL;
+   }
+
+   /*
+    * Look for a loader that can handle this executable
+    */
+   for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i)
+   {
+      RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject));
+      Flags = 0;
+
+      /* FIXME: use FileObject instead of FileHandle */
+      Status = ExeFmtpLoaders[i](FileHeader,
+                                 FileHeaderSize,
+                                 FileHandle,
+                                 ImageSectionObject,
+                                 &Flags,
+                                 ExeFmtpReadFile,
+                                 ExeFmtpAllocateSegments);
+
       if (!NT_SUCCESS(Status))
-        {
-          ObDereferenceObject(FileObject);
-          return(Status);
-       }
-    
-      /*
-       * Check the DOS signature
-       */
-      if (Iosb.Information != sizeof(DosHeader) ||
-         DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
-        {
-          ObDereferenceObject(FileObject);
-          return(STATUS_INVALID_IMAGE_FORMAT);
-        }
+      {
+         if (ImageSectionObject->Segments)
+         {
+            ExFreePool(ImageSectionObject->Segments);
+            ImageSectionObject->Segments = NULL;
+         }
+      }
+
+      if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
+         break;
+   }
+
+   ExFreePool(FileHeaderBuffer);
+
+   /*
+    * No loader handled the format
+    */
+   if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
+   {
+      Status = STATUS_INVALID_IMAGE_NOT_MZ;
+      ASSERT(!NT_SUCCESS(Status));
+   }
+
+   if (!NT_SUCCESS(Status))
+      return Status;
+
+   ASSERT(ImageSectionObject->Segments != NULL);
+
+   /*
+    * Some defaults
+    */
+   /* FIXME? are these values platform-dependent? */
+   if(ImageSectionObject->StackReserve == 0)
+      ImageSectionObject->StackReserve = 0x40000;
+
+   if(ImageSectionObject->StackCommit == 0)
+      ImageSectionObject->StackCommit = 0x1000;
+
+   if(ImageSectionObject->ImageBase == 0)
+   {
+      if(ImageSectionObject->ImageCharacteristics & IMAGE_FILE_DLL)
+         ImageSectionObject->ImageBase = 0x10000000;
+      else
+         ImageSectionObject->ImageBase = 0x00400000;
+   }
+
+   /*
+    * And now the fun part: fixing the segments
+    */
+
+   /* Sort them by virtual address */
+   MmspSortSegments(ImageSectionObject, Flags);
+
+   /* Ensure they don't overlap in memory */
+   if (!MmspCheckSegmentBounds(ImageSectionObject, Flags))
+      return STATUS_INVALID_IMAGE_FORMAT;
+
+   /* Ensure they are aligned */
+   OldNrSegments = ImageSectionObject->NrSegments;
+
+   if (!MmspPageAlignSegments(ImageSectionObject, Flags))
+      return STATUS_INVALID_IMAGE_FORMAT;
+
+   /* Trim them if the alignment phase merged some of them */
+   if (ImageSectionObject->NrSegments < OldNrSegments)
+   {
+      PMM_SECTION_SEGMENT Segments;
+      SIZE_T SizeOfSegments;
+
+      SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments;
+
+      Segments = ExAllocatePoolWithTag(PagedPool,
+                                       SizeOfSegments,
+                                       TAG_MM_SECTION_SEGMENT);
+
+      if (Segments == NULL)
+         return STATUS_INSUFFICIENT_RESOURCES;
+
+      RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments);
+      ExFreePool(ImageSectionObject->Segments);
+      ImageSectionObject->Segments = Segments;
+   }
+
+   /* And finish their initialization */
+   for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
+   {
+      ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock);
+      ImageSectionObject->Segments[i].ReferenceCount = 1;
+
+      RtlZeroMemory(&ImageSectionObject->Segments[i].PageDirectory,
+                    sizeof(ImageSectionObject->Segments[i].PageDirectory));
+   }
+
+   ASSERT(NT_SUCCESS(Status));
+   return Status;
+}
+
+NTSTATUS
+MmCreateImageSection(PSECTION_OBJECT *SectionObject,
+                     ACCESS_MASK DesiredAccess,
+                     POBJECT_ATTRIBUTES ObjectAttributes,
+                     PLARGE_INTEGER UMaximumSize,
+                     ULONG SectionPageProtection,
+                     ULONG AllocationAttributes,
+                     HANDLE FileHandle)
+{
+   PSECTION_OBJECT Section;
+   NTSTATUS Status;
+   PFILE_OBJECT FileObject;
+   PMM_SECTION_SEGMENT SectionSegments;
+   PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
+   ULONG i;
+   ULONG FileAccess = 0;
+
+   /*
+    * Specifying a maximum size is meaningless for an image section
+    */
+   if (UMaximumSize != NULL)
+   {
+      return(STATUS_INVALID_PARAMETER_4);
+   }
+
+   /*
+    * Check file access required
+    */
+   if (SectionPageProtection & PAGE_READWRITE ||
+         SectionPageProtection & PAGE_EXECUTE_READWRITE)
+   {
+      FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
+   }
+   else
+   {
+      FileAccess = FILE_READ_DATA;
+   }
+
+   /*
+    * Reference the file handle
+    */
+   Status = ObReferenceObjectByHandle(FileHandle,
+                                      FileAccess,
+                                      IoFileObjectType,
+                                      UserMode,
+                                      (PVOID*)(PVOID)&FileObject,
+                                      NULL);
+
+   if (!NT_SUCCESS(Status))
+   {
+      return Status;
+   }
+
+   /*
+    * Create the section
+    */
+   Status = ObCreateObject (ExGetPreviousMode(),
+                            MmSectionObjectType,
+                            ObjectAttributes,
+                            ExGetPreviousMode(),
+                            NULL,
+                            sizeof(SECTION_OBJECT),
+                            0,
+                            0,
+                            (PVOID*)(PVOID)&Section);
+   if (!NT_SUCCESS(Status))
+   {
+      ObDereferenceObject(FileObject);
+      return(Status);
+   }
+
+   /*
+    * Initialize it
+    */
+   Section->SectionPageProtection = SectionPageProtection;
+   Section->AllocationAttributes = AllocationAttributes;
+
+   /*
+    * Initialized caching for this file object if previously caching
+    * was initialized for the same on disk file
+    */
+   Status = CcTryToInitializeFileCache(FileObject);
+
+   if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
+   {
+      NTSTATUS StatusExeFmt;
+
+      ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
+      if (ImageSectionObject == NULL)
+      {
+         ObDereferenceObject(FileObject);
+         ObDereferenceObject(Section);
+         return(STATUS_NO_MEMORY);
+      }
+      
+      RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
 
-      /*
-       * Read the PE header
-       */
-      Offset.QuadPart = DosHeader.e_lfanew;
-      Status = ZwReadFile(FileHandle,
-                         NULL,
-                         NULL,
-                         NULL,
-                         &Iosb,
-                         &PEHeader,
-                         sizeof(PEHeader),
-                         &Offset,
-                         0);
-      if (!NT_SUCCESS(Status))
-        {
-          ObDereferenceObject(FileObject);
-          return(Status);
-        }
+      StatusExeFmt = ExeFmtpCreateImageSection(FileHandle, ImageSectionObject);
 
-      /*
-       * Check the signature
-       */
-      if (Iosb.Information != sizeof(PEHeader) || 
-         PEHeader.Signature != IMAGE_NT_SIGNATURE)
-        {
-          ObDereferenceObject(FileObject);
-          return(STATUS_INVALID_IMAGE_FORMAT);
-        }
+      if (!NT_SUCCESS(StatusExeFmt))
+      {
+         if(ImageSectionObject->Segments != NULL)
+            ExFreePool(ImageSectionObject->Segments);
 
-      /*
-       * Read in the section headers
-       */
-      Offset.QuadPart = DosHeader.e_lfanew + sizeof(PEHeader);  
-      ImageSections = ExAllocatePool(NonPagedPool,
-                                    PEHeader.FileHeader.NumberOfSections * 
-                                    sizeof(IMAGE_SECTION_HEADER));
-      if (ImageSections == NULL)
-        {
-         ObDereferenceObject(FileObject);
-         return(STATUS_NO_MEMORY);
-       }
+         ExFreePool(ImageSectionObject);
+         ObDereferenceObject(Section);
+         ObDereferenceObject(FileObject);
+         return(StatusExeFmt);
+      }
 
-      Status = ZwReadFile(FileHandle,
-                         NULL,
-                         NULL,
-                         NULL,
-                         &Iosb,
-                         ImageSections,
-                         PEHeader.FileHeader.NumberOfSections * 
-                         sizeof(IMAGE_SECTION_HEADER),
-                         &Offset,
-                         0);
-      if (!NT_SUCCESS(Status))
-        {
-          ObDereferenceObject(FileObject);
-          ExFreePool(ImageSections);
-          return(Status);
-        }
-      if (Iosb.Information != (PEHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
-        {
-          ObDereferenceObject(FileObject);
-          ExFreePool(ImageSections);
-          return(STATUS_INVALID_IMAGE_FORMAT);
-        }
+      Section->ImageSection = ImageSectionObject;
+      ASSERT(ImageSectionObject->Segments);
 
       /*
-       * Create the section
-       */
-        Status = ObCreateObject (ExGetPreviousMode(),
-                                MmSectionObjectType,
-                                ObjectAttributes,
-                                ExGetPreviousMode(),
-                                NULL,
-                                sizeof(SECTION_OBJECT),
-                                0,
-                                0,
-                                (PVOID*)&Section);
-        if (!NT_SUCCESS(Status))
-          {
-            ObDereferenceObject(FileObject);
-            ExFreePool(ImageSections);
-            return(Status);
-          }
-
-        Status = ObInsertObject ((PVOID)Section,
-                                NULL,
-                                DesiredAccess,
-                                0,
-                                NULL,
-                                SectionHandle);
-        if (!NT_SUCCESS(Status))
-          {
-            ObDereferenceObject(Section);
-            ObDereferenceObject(FileObject);
-            ExFreePool(ImageSections);
-            return(Status);
-          }
-
-        /*
-         * Initialize it
-         */
-        Section->SectionPageProtection = SectionPageProtection;
-        Section->AllocationAttributes = AllocationAttributes;
-        InitializeListHead(&Section->ViewListHead);
-        KeInitializeSpinLock(&Section->ViewListLock);
-
-       /*
-         * Check file access required
-         */
-        if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
-          {
-            FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
-          }
-        else
-          {
-            FileAccess = FILE_READ_DATA;
-          }
-  
-        /*
-         * We can't do memory mappings if the file system doesn't support the
-         * standard FCB
-         */
-        if (!(FileObject->Flags & FO_FCB_IS_VALID))
-          {
-            ZwClose(*SectionHandle);
-            ObDereferenceObject(Section);
-            ObDereferenceObject(FileObject);
-            ExFreePool(ImageSections);
-            return(STATUS_INVALID_FILE_FOR_SECTION);
-          }
-  
-        /*
-         * Lock the file
-         */
-        Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
-                                      0,
-                                      KernelMode,
-                                      FALSE,
-                                      NULL);
-        if (Status != STATUS_SUCCESS)
-          {
-            ZwClose(*SectionHandle);
-            ObDereferenceObject(Section);
-            ObDereferenceObject(FileObject);
-            ExFreePool(ImageSections);
-            return(Status);
-          }
-
-        /*
-         * allocate the section segments to describe the mapping
-         */
-        NrSegments = PEHeader.FileHeader.NumberOfSections + 1;
-       Size = sizeof(MM_IMAGE_SECTION_OBJECT) + sizeof(MM_SECTION_SEGMENT) * NrSegments;
-        ImageSectionObject = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MM_SECTION_SEGMENT);
-        if (ImageSectionObject == NULL)
-         {
-           KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
-           ZwClose(*SectionHandle);
-           ObDereferenceObject(Section);
-           ObDereferenceObject(FileObject);
-           ExFreePool(ImageSections);
-           return(STATUS_NO_MEMORY);
-         }
-        Section->ImageSection = ImageSectionObject;
-        ImageSectionObject->NrSegments = NrSegments;
-       ImageSectionObject->ImageBase = (PVOID)PEHeader.OptionalHeader.ImageBase;
-       ImageSectionObject->EntryPoint = (PVOID)PEHeader.OptionalHeader.AddressOfEntryPoint;
-       ImageSectionObject->StackReserve = PEHeader.OptionalHeader.SizeOfStackReserve;
-       ImageSectionObject->StackCommit = PEHeader.OptionalHeader.SizeOfStackCommit;
-       ImageSectionObject->Subsystem = PEHeader.OptionalHeader.Subsystem;
-       ImageSectionObject->MinorSubsystemVersion = PEHeader.OptionalHeader.MinorSubsystemVersion;
-       ImageSectionObject->MajorSubsystemVersion = PEHeader.OptionalHeader.MajorSubsystemVersion;
-        ImageSectionObject->ImageCharacteristics = PEHeader.FileHeader.Characteristics;
-       ImageSectionObject->Machine = PEHeader.FileHeader.Machine;
-       ImageSectionObject->Executable = (PEHeader.OptionalHeader.SizeOfCode != 0);
-
-       SectionSegments = ImageSectionObject->Segments;
-        SectionSegments[0].FileOffset = 0;
-        SectionSegments[0].Characteristics = IMAGE_SECTION_CHAR_DATA;
-        SectionSegments[0].Protection = PAGE_READONLY;
-        SectionSegments[0].RawLength = PAGE_SIZE;
-        SectionSegments[0].Length = PAGE_SIZE;
-        SectionSegments[0].Flags = 0;
-        SectionSegments[0].ReferenceCount = 1;
-        SectionSegments[0].VirtualAddress = 0;
-        SectionSegments[0].WriteCopy = FALSE;
-       ExInitializeFastMutex(&SectionSegments[0].Lock);
-        for (i = 1; i < NrSegments; i++)
-         {
-           SectionSegments[i].FileOffset = ImageSections[i-1].PointerToRawData;
-           SectionSegments[i].Characteristics = ImageSections[i-1].Characteristics;
-
-           /*
-            * Set up the protection and write copy variables.
-            */
-           Characteristics = ImageSections[i - 1].Characteristics;
-           if (Characteristics & (IMAGE_SECTION_CHAR_READABLE|IMAGE_SECTION_CHAR_WRITABLE|IMAGE_SECTION_CHAR_EXECUTABLE))
-             {
-               SectionSegments[i].Protection = SectionCharacteristicsToProtect[Characteristics >> 28];
-               SectionSegments[i].WriteCopy = !(Characteristics & IMAGE_SECTION_CHAR_SHARED);
-             }
-           else if (Characteristics & IMAGE_SECTION_CHAR_CODE)
-             {
-               SectionSegments[i].Protection = PAGE_EXECUTE_READ;
-               SectionSegments[i].WriteCopy = TRUE;
-             }
-           else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
-             {
-               SectionSegments[i].Protection = PAGE_READWRITE;
-               SectionSegments[i].WriteCopy = TRUE;
-             }
-           else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
-             {
-               SectionSegments[i].Protection = PAGE_READWRITE;
-               SectionSegments[i].WriteCopy = TRUE;
-             }
-           else
-             {
-               SectionSegments[i].Protection = PAGE_NOACCESS;
-               SectionSegments[i].WriteCopy = TRUE;
-             }
-         
-           /*
-            * Set up the attributes.
-            */
-           if (Characteristics & IMAGE_SECTION_CHAR_CODE)
-             {
-               SectionSegments[i].Attributes = 0;
-             }
-           else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
-             {
-               SectionSegments[i].Attributes = 0;
-             }
-           else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
-             {
-               SectionSegments[i].Attributes = MM_SECTION_SEGMENT_BSS;
-             }
-           else
-             {
-               SectionSegments[i].Attributes = 0;
-             }
-
-           SectionSegments[i].RawLength = ImageSections[i-1].SizeOfRawData;
-           SectionSegments[i].Length = ImageSections[i-1].Misc.VirtualSize;
-           SectionSegments[i].Flags = 0;
-           SectionSegments[i].ReferenceCount = 1;
-           SectionSegments[i].VirtualAddress = (PVOID)ImageSections[i-1].VirtualAddress;
-           ExInitializeFastMutex(&SectionSegments[i].Lock);
-         }
-        if (0 != InterlockedCompareExchange((PLONG)&FileObject->SectionObjectPointer->ImageSectionObject, 
-                                           (LONG)ImageSectionObject, 0))
-         {
-           /*
-            * An other thread has initialized the some image in the background
-            */
-           ExFreePool(ImageSectionObject);
-           ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
-            Section->ImageSection = ImageSectionObject;
-            SectionSegments = ImageSectionObject->Segments;
-
-            for (i = 0; i < NrSegments; i++)
-            {
-               InterlockedIncrement((LONG *)&SectionSegments[i].ReferenceCount);
-            }
-         }
-        ExFreePool(ImageSections);
-    }
-  else
-    {
-      /*
-       * Create the section
+       * Lock the file
        */
-      Status = ObCreateObject (ExGetPreviousMode(),
-                              MmSectionObjectType,
-                              ObjectAttributes,
-                              ExGetPreviousMode(),
-                              NULL,
-                              sizeof(SECTION_OBJECT),
-                              0,
-                              0,
-                              (PVOID*)&Section);
-      if (!NT_SUCCESS(Status))
-        {
-          ObDereferenceObject(FileObject);
-          return(Status);
-        }
-
-      Status = ObInsertObject ((PVOID)Section,
-                              NULL,
-                              DesiredAccess,
-                              0,
-                              NULL,
-                               SectionHandle);
+      Status = MmspWaitForFileLock(FileObject);
       if (!NT_SUCCESS(Status))
-        {
-          ObDereferenceObject(Section);
-          ObDereferenceObject(FileObject);
-          return(Status);
-        }
+      {
+         ExFreePool(ImageSectionObject->Segments);
+         ExFreePool(ImageSectionObject);
+         ObDereferenceObject(Section);
+         ObDereferenceObject(FileObject);
+         return(Status);
+      }
 
-      /*
-       * Initialize it
-       */
-      Section->SectionPageProtection = SectionPageProtection;
-      Section->AllocationAttributes = AllocationAttributes;
-      InitializeListHead(&Section->ViewListHead);
-      KeInitializeSpinLock(&Section->ViewListLock);
+      if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject,
+                                                    ImageSectionObject, NULL))
+      {
+         /*
+          * An other thread has initialized the some image in the background
+          */
+         ExFreePool(ImageSectionObject->Segments);
+         ExFreePool(ImageSectionObject);
+         ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
+         Section->ImageSection = ImageSectionObject;
+         SectionSegments = ImageSectionObject->Segments;
+
+         for (i = 0; i < ImageSectionObject->NrSegments; i++)
+         {
+            InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
+         }
+      }
 
-      /*
-       * Check file access required
-       */
-      if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
-        {
-          FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
-        }
-      else
-        {
-          FileAccess = FILE_READ_DATA;
-        }
-  
+      Status = StatusExeFmt;
+   }
+   else
+   {
       /*
        * Lock the file
        */
-      Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
-                                    0,
-                                    KernelMode,
-                                    FALSE,
-                                    NULL);
+      Status = MmspWaitForFileLock(FileObject);
       if (Status != STATUS_SUCCESS)
-        {
-          ZwClose(*SectionHandle);
-          ObDereferenceObject(Section);
-          ObDereferenceObject(FileObject);
-          return(Status);
-        }
+      {
+         ObDereferenceObject(Section);
+         ObDereferenceObject(FileObject);
+         return(Status);
+      }
 
       ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
       Section->ImageSection = ImageSectionObject;
       SectionSegments = ImageSectionObject->Segments;
-      NrSegments = ImageSectionObject->NrSegments;
 
       /*
        * Otherwise just reference all the section segments
        */
-      for (i = 0; i < NrSegments; i++)
-       {
-         InterlockedIncrement((LONG *)&SectionSegments[i].ReferenceCount);
-       }
-
-    }
-  Section->FileObject = FileObject;
-  CcRosReferenceCache(FileObject);
-  KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
-  ObDereferenceObject(Section);
-  return(STATUS_SUCCESS);
+      for (i = 0; i < ImageSectionObject->NrSegments; i++)
+      {
+         InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
+      }
+
+      Status = STATUS_SUCCESS;
+   }
+   Section->FileObject = FileObject;
+   CcRosReferenceCache(FileObject);
+   KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
+   *SectionObject = Section;
+   return(Status);
 }
 
 /*
@@ -3000,411 +3343,526 @@ MmCreateImageSection(PHANDLE SectionHandle,
  */
 NTSTATUS STDCALL
 NtCreateSection (OUT PHANDLE SectionHandle,
-                IN ACCESS_MASK DesiredAccess,
-                IN POBJECT_ATTRIBUTES  ObjectAttributes OPTIONAL,
-                IN PLARGE_INTEGER MaximumSize  OPTIONAL,
-                IN ULONG SectionPageProtection OPTIONAL,
-                IN ULONG AllocationAttributes,
-                IN HANDLE FileHandle OPTIONAL)
+                 IN ACCESS_MASK DesiredAccess,
+                 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
+                 IN PLARGE_INTEGER MaximumSize OPTIONAL,
+                 IN ULONG SectionPageProtection OPTIONAL,
+                 IN ULONG AllocationAttributes,
+                 IN HANDLE FileHandle OPTIONAL)
 {
-  if (AllocationAttributes & SEC_IMAGE)
-    {
-      return(MmCreateImageSection(SectionHandle,
-                                 DesiredAccess,
-                                 ObjectAttributes,
-                                 MaximumSize,
-                                 SectionPageProtection,
-                                 AllocationAttributes,
-                                 FileHandle));
-    }
-  else if (FileHandle != NULL)
-    {
-      return(MmCreateDataFileSection(SectionHandle,
-                                    DesiredAccess,
-                                    ObjectAttributes,
-                                    MaximumSize,
-                                    SectionPageProtection,
-                                    AllocationAttributes,
-                                    FileHandle));
-    }
-  else
-    {
-      return(MmCreatePageFileSection(SectionHandle,
-                                    DesiredAccess,
-                                    ObjectAttributes,
-                                    MaximumSize,
-                                    SectionPageProtection,
-                                    AllocationAttributes));
-    }
+   LARGE_INTEGER SafeMaximumSize;
+   PSECTION_OBJECT SectionObject;
+   KPROCESSOR_MODE PreviousMode;
+   NTSTATUS Status = STATUS_SUCCESS;
+
+   PreviousMode = ExGetPreviousMode();
+
+   if(MaximumSize != NULL && PreviousMode != KernelMode)
+   {
+     _SEH_TRY
+     {
+       /* make a copy on the stack */
+       SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
+       MaximumSize = &SafeMaximumSize;
+     }
+     _SEH_HANDLE
+     {
+       Status = _SEH_GetExceptionCode();
+     }
+     _SEH_END;
+
+     if(!NT_SUCCESS(Status))
+     {
+       return Status;
+     }
+   }
+
+   /*
+    * Check the protection
+    */
+   if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
+         SectionPageProtection)
+   {
+      return(STATUS_INVALID_PAGE_PROTECTION);
+   }
+
+   Status = MmCreateSection(&SectionObject,
+                            DesiredAccess,
+                            ObjectAttributes,
+                            MaximumSize,
+                            SectionPageProtection,
+                            AllocationAttributes,
+                            FileHandle,
+                            NULL);
+
+   if (NT_SUCCESS(Status))
+   {
+      Status = ObInsertObject ((PVOID)SectionObject,
+                               NULL,
+                               DesiredAccess,
+                               0,
+                               NULL,
+                               SectionHandle);
+      ObDereferenceObject(SectionObject);
+   }
+
+   return Status;
 }
 
 
 /**********************************************************************
  * NAME
- *     NtOpenSection
+ *  NtOpenSection
  *
  * DESCRIPTION
  *
  * ARGUMENTS
- *     SectionHandle
+ *  SectionHandle
  *
- *     DesiredAccess
+ *  DesiredAccess
  *
- *     ObjectAttributes
+ *  ObjectAttributes
  *
  * RETURN VALUE
  *
  * REVISIONS
  */
 NTSTATUS STDCALL
-NtOpenSection(PHANDLE                  SectionHandle,
-             ACCESS_MASK               DesiredAccess,
-             POBJECT_ATTRIBUTES        ObjectAttributes)
+NtOpenSection(PHANDLE   SectionHandle,
+              ACCESS_MASK  DesiredAccess,
+              POBJECT_ATTRIBUTES ObjectAttributes)
 {
-  NTSTATUS Status;
+   HANDLE hSection;
+   KPROCESSOR_MODE PreviousMode;
+   NTSTATUS Status = STATUS_SUCCESS;
+
+   PreviousMode = ExGetPreviousMode();
+
+   if(PreviousMode != KernelMode)
+   {
+     _SEH_TRY
+     {
+       ProbeForWriteHandle(SectionHandle);
+     }
+     _SEH_HANDLE
+     {
+       Status = _SEH_GetExceptionCode();
+     }
+     _SEH_END;
+
+     if(!NT_SUCCESS(Status))
+     {
+       return Status;
+     }
+   }
 
-  *SectionHandle = 0;
+   Status = ObOpenObjectByName(ObjectAttributes,
+                               MmSectionObjectType,
+                               NULL,
+                               PreviousMode,
+                               DesiredAccess,
+                               NULL,
+                               &hSection);
 
-  Status = ObOpenObjectByName(ObjectAttributes,
-                             MmSectionObjectType,
-                             NULL,
-                             UserMode,
-                             DesiredAccess,
-                             NULL,
-                             SectionHandle);
+   if(NT_SUCCESS(Status))
+   {
+     _SEH_TRY
+     {
+       *SectionHandle = hSection;
+     }
+     _SEH_HANDLE
+     {
+       Status = _SEH_GetExceptionCode();
+     }
+     _SEH_END;
+   }
 
-  return(Status);
+   return(Status);
 }
 
 NTSTATUS STATIC
 MmMapViewOfSegment(PEPROCESS Process,
-                  PMADDRESS_SPACE AddressSpace,
-                  PSECTION_OBJECT Section,
-                  PMM_SECTION_SEGMENT Segment,
-                  PVOID* BaseAddress,
-                  ULONG ViewSize,
-                  ULONG Protect,
-                  ULONG ViewOffset,
-                  BOOL TopDown)
+                   PMADDRESS_SPACE AddressSpace,
+                   PSECTION_OBJECT Section,
+                   PMM_SECTION_SEGMENT Segment,
+                   PVOID* BaseAddress,
+                   ULONG ViewSize,
+                   ULONG Protect,
+                   ULONG ViewOffset,
+                   BOOL TopDown)
 {
-  PMEMORY_AREA MArea;
-  NTSTATUS Status;
-  KIRQL oldIrql;
-
-  Status = MmCreateMemoryArea(Process,
-                             AddressSpace,
-                             MEMORY_AREA_SECTION_VIEW,
-                             BaseAddress,
-                             ViewSize,
-                             Protect,
-                             &MArea,
-                             FALSE,
-                             TopDown);
-  if (!NT_SUCCESS(Status))
-    {
-      DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
-             (*BaseAddress), (*BaseAddress) + ViewSize);
+   PMEMORY_AREA MArea;
+   NTSTATUS Status;
+   PHYSICAL_ADDRESS BoundaryAddressMultiple;
+
+   BoundaryAddressMultiple.QuadPart = 0;
+
+   Status = MmCreateMemoryArea(Process,
+                               AddressSpace,
+                               MEMORY_AREA_SECTION_VIEW,
+                               BaseAddress,
+                               ViewSize,
+                               Protect,
+                               &MArea,
+                               FALSE,
+                               TopDown,
+                               BoundaryAddressMultiple);
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
+              (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
       return(Status);
-    }
-
-  KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
-  InsertTailList(&Section->ViewListHead,
-                &MArea->Data.SectionData.ViewListEntry);
-  KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
-
-  ObReferenceObjectByPointer((PVOID)Section,
-                            SECTION_MAP_READ,
-                            NULL,
-                            ExGetPreviousMode());
-  MArea->Data.SectionData.Segment = Segment;
-  MArea->Data.SectionData.Section = Section;
-  MArea->Data.SectionData.ViewOffset = ViewOffset;
-  MArea->Data.SectionData.WriteCopyView = FALSE;
-  MmInitialiseRegion(&MArea->Data.SectionData.RegionListHead,
-                    ViewSize, 0, Protect);
-
-  return(STATUS_SUCCESS);
+   }
+
+
+   ObReferenceObjectByPointer((PVOID)Section,
+                              SECTION_MAP_READ,
+                              NULL,
+                              ExGetPreviousMode());
+   MArea->Data.SectionData.Segment = Segment;
+   MArea->Data.SectionData.Section = Section;
+   MArea->Data.SectionData.ViewOffset = ViewOffset;
+   MArea->Data.SectionData.WriteCopyView = FALSE;
+   MmInitialiseRegion(&MArea->Data.SectionData.RegionListHead,
+                      ViewSize, 0, Protect);
+
+   return(STATUS_SUCCESS);
 }
 
 
 /**********************************************************************
- * NAME                                                        EXPORTED
- *     NtMapViewOfSection
+ * NAME       EXPORTED
+ * NtMapViewOfSection
  *
  * DESCRIPTION
- *     Maps a view of a section into the virtual address space of a 
- *     process.
- *     
+ * Maps a view of a section into the virtual address space of a
+ * process.
+ *
  * ARGUMENTS
- *     SectionHandle
- *             Handle of the section.
- *             
- *     ProcessHandle
- *             Handle of the process.
- *             
- *     BaseAddress
- *             Desired base address (or NULL) on entry;
- *             Actual base address of the view on exit.
- *             
- *     ZeroBits
- *             Number of high order address bits that must be zero.
- *             
- *     CommitSize
- *             Size in bytes of the initially committed section of 
- *             the view.
- *             
- *     SectionOffset
- *             Offset in bytes from the beginning of the section
- *             to the beginning of the view.
- *             
- *     ViewSize
- *             Desired length of map (or zero to map all) on entry
- *             Actual length mapped on exit.
- *             
- *     InheritDisposition
- *             Specified how the view is to be shared with
- *             child processes.
- *             
- *     AllocateType
- *             Type of allocation for the pages.
- *             
- *     Protect
- *             Protection for the committed region of the view.
+ * SectionHandle
+ *  Handle of the section.
+ *
+ * ProcessHandle
+ *  Handle of the process.
+ *
+ * BaseAddress
+ *  Desired base address (or NULL) on entry;
+ *  Actual base address of the view on exit.
+ *
+ * ZeroBits
+ *  Number of high order address bits that must be zero.
+ *
+ * CommitSize
+ *  Size in bytes of the initially committed section of
+ *  the view.
+ *
+ * SectionOffset
+ *  Offset in bytes from the beginning of the section
+ *  to the beginning of the view.
+ *
+ * ViewSize
+ *  Desired length of map (or zero to map all) on entry
+ *  Actual length mapped on exit.
+ *
+ * InheritDisposition
+ *  Specified how the view is to be shared with
+ *  child processes.
+ *
+ * AllocateType
+ *  Type of allocation for the pages.
+ *
+ * Protect
+ *  Protection for the committed region of the view.
  *
  * RETURN VALUE
- *     Status.
+ *  Status.
  *
  * @implemented
  */
 NTSTATUS STDCALL
-NtMapViewOfSection(HANDLE SectionHandle,
-                  HANDLE ProcessHandle,
-                  PVOID* BaseAddress,
-                  ULONG ZeroBits,
-                  ULONG CommitSize,
-                  PLARGE_INTEGER SectionOffset,
-                  PULONG ViewSize,
-                  SECTION_INHERIT InheritDisposition,
-                  ULONG AllocationType,
-                  ULONG Protect)
+NtMapViewOfSection(IN HANDLE SectionHandle,
+                   IN HANDLE ProcessHandle,
+                   IN OUT PVOID* BaseAddress  OPTIONAL,
+                   IN ULONG ZeroBits  OPTIONAL,
+                   IN ULONG CommitSize,
+                   IN OUT PLARGE_INTEGER SectionOffset  OPTIONAL,
+                   IN OUT PULONG ViewSize,
+                   IN SECTION_INHERIT InheritDisposition,
+                   IN ULONG AllocationType  OPTIONAL,
+                   IN ULONG Protect)
 {
+   PVOID SafeBaseAddress;
+   LARGE_INTEGER SafeSectionOffset;
+   ULONG SafeViewSize;
    PSECTION_OBJECT Section;
    PEPROCESS Process;
-   NTSTATUS Status;
+   KPROCESSOR_MODE PreviousMode;
    PMADDRESS_SPACE AddressSpace;
+   NTSTATUS Status = STATUS_SUCCESS;
 
-   Status = ObReferenceObjectByHandle(ProcessHandle,
-                                     PROCESS_VM_OPERATION,
-                                     PsProcessType,
-                                     UserMode,
-                                     (PVOID*)&Process,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
+   PreviousMode = ExGetPreviousMode();
+
+   if(PreviousMode != KernelMode)
+   {
+     SafeBaseAddress = NULL;
+     SafeSectionOffset.QuadPart = 0;
+     SafeViewSize = 0;
+
+     _SEH_TRY
      {
-       return(Status);
+       if(BaseAddress != NULL)
+       {
+         ProbeForWritePointer(BaseAddress);
+         SafeBaseAddress = *BaseAddress;
+       }
+       if(SectionOffset != NULL)
+       {
+         ProbeForWriteLargeInteger(SectionOffset);
+         SafeSectionOffset = *SectionOffset;
+       }
+       ProbeForWriteUlong(ViewSize);
+       SafeViewSize = *ViewSize;
      }
-   
+     _SEH_HANDLE
+     {
+       Status = _SEH_GetExceptionCode();
+     }
+     _SEH_END;
+
+     if(!NT_SUCCESS(Status))
+     {
+       return Status;
+     }
+   }
+   else
+   {
+     SafeBaseAddress = (BaseAddress != NULL ? *BaseAddress : NULL);
+     SafeSectionOffset.QuadPart = (SectionOffset != NULL ? SectionOffset->QuadPart : 0);
+     SafeViewSize = (ViewSize != NULL ? *ViewSize : 0);
+   }
+
+   Status = ObReferenceObjectByHandle(ProcessHandle,
+                                      PROCESS_VM_OPERATION,
+                                      PsProcessType,
+                                      PreviousMode,
+                                      (PVOID*)(PVOID)&Process,
+                                      NULL);
+   if (!NT_SUCCESS(Status))
+   {
+      return(Status);
+   }
+
    AddressSpace = &Process->AddressSpace;
-   
+
    Status = ObReferenceObjectByHandle(SectionHandle,
-                                     SECTION_MAP_READ,
-                                     MmSectionObjectType,
-                                     UserMode,
-                                     (PVOID*)&Section,
-                                     NULL);
+                                      SECTION_MAP_READ,
+                                      MmSectionObjectType,
+                                      PreviousMode,
+                                      (PVOID*)(PVOID)&Section,
+                                      NULL);
    if (!(NT_SUCCESS(Status)))
-     {
-       DPRINT("ObReference failed rc=%x\n",Status);
-       ObDereferenceObject(Process);
-       return(Status);
-     }
-   
+   {
+      DPRINT("ObReference failed rc=%x\n",Status);
+      ObDereferenceObject(Process);
+      return(Status);
+   }
+
    Status = MmMapViewOfSection(Section,
-                              Process,
-                              BaseAddress,
-                              ZeroBits,
-                              CommitSize,
-                              SectionOffset,
-                              ViewSize,
-                              InheritDisposition,
-                              AllocationType,
-                              Protect);
-   
+                               Process,
+                               (BaseAddress != NULL ? &SafeBaseAddress : NULL),
+                               ZeroBits,
+                               CommitSize,
+                               (SectionOffset != NULL ? &SafeSectionOffset : NULL),
+                               (ViewSize != NULL ? &SafeViewSize : NULL),
+                               InheritDisposition,
+                               AllocationType,
+                               Protect);
+
    ObDereferenceObject(Section);
    ObDereferenceObject(Process);
-   
+
+   if(NT_SUCCESS(Status))
+   {
+     /* copy parameters back to the caller */
+     _SEH_TRY
+     {
+       if(BaseAddress != NULL)
+       {
+         *BaseAddress = SafeBaseAddress;
+       }
+       if(SectionOffset != NULL)
+       {
+         *SectionOffset = SafeSectionOffset;
+       }
+       if(ViewSize != NULL)
+       {
+         *ViewSize = SafeViewSize;
+       }
+     }
+     _SEH_HANDLE
+     {
+       Status = _SEH_GetExceptionCode();
+     }
+     _SEH_END;
+   }
+
    return(Status);
 }
 
 VOID STATIC
 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
-                 PHYSICAL_ADDRESS PhysAddr, SWAPENTRY SwapEntry, 
-                 BOOLEAN Dirty)
+                  PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
 {
-  PMEMORY_AREA MArea;
-  ULONG Entry;
-  PFILE_OBJECT FileObject;
-  PBCB Bcb;
-  ULONG Offset;
-  SWAPENTRY SavedSwapEntry;
-  PMM_PAGEOP PageOp;
-  LARGE_INTEGER Timeout;
-  NTSTATUS Status;
-  PSECTION_OBJECT Section;
-  PMM_SECTION_SEGMENT Segment;
+   ULONG Entry;
+   PFILE_OBJECT FileObject;
+   PBCB Bcb;
+   ULONG Offset;
+   SWAPENTRY SavedSwapEntry;
+   PMM_PAGEOP PageOp;
+   NTSTATUS Status;
+   PSECTION_OBJECT Section;
+   PMM_SECTION_SEGMENT Segment;
+   PMADDRESS_SPACE AddressSpace;
 
-  MArea = (PMEMORY_AREA)Context;
+   AddressSpace = (PMADDRESS_SPACE)Context;
 
-  Address = (PVOID)PAGE_ROUND_DOWN(Address);
+   Address = (PVOID)PAGE_ROUND_DOWN(Address);
 
-  Offset = ((ULONG)Address - (ULONG)MArea->BaseAddress);
+   Offset = ((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress) +
+            MemoryArea->Data.SectionData.ViewOffset;
 
-  Section = MArea->Data.SectionData.Section;
-  Segment = MArea->Data.SectionData.Segment;
+   Section = MemoryArea->Data.SectionData.Section;
+   Segment = MemoryArea->Data.SectionData.Segment;
 
+   PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
 
-  PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset);
-  
-  while (PageOp)
-  {
-     MmUnlockSectionSegment(Segment);
-     MmUnlockAddressSpace(&MArea->Process->AddressSpace);
-
-     Timeout.QuadPart = -100000000LL;  // 10 sec
-     Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
-                                   0,
-                                   KernelMode,
-                                   FALSE,
-                                   &Timeout);
-     if (Status != STATUS_SUCCESS)
-       {
+   while (PageOp)
+   {
+      MmUnlockSectionSegment(Segment);
+      MmUnlockAddressSpace(AddressSpace);
+
+      Status = MmspWaitForPageOpCompletionEvent(PageOp);
+      if (Status != STATUS_SUCCESS)
+      {
          DPRINT1("Failed to wait for page op, status = %x\n", Status);
-        KEBUGCHECK(0);
-       }
+         KEBUGCHECK(0);
+      }
+
+      MmLockAddressSpace(AddressSpace);
+      MmLockSectionSegment(Segment);
+      MmspCompleteAndReleasePageOp(PageOp);
+      PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
+   }
 
-     MmLockAddressSpace(&MArea->Process->AddressSpace);
-     MmLockSectionSegment(Segment);
-     KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-     MmReleasePageOp(PageOp);
-     PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset);
-  }
+   Entry = MmGetPageEntrySectionSegment(Segment, Offset);
 
-  Entry = MmGetPageEntrySectionSegment(Segment, Offset);
-  
-  /*
-   * For a dirty, datafile, non-private page mark it as dirty in the
-   * cache manager.
-   */
-  if (Segment->Flags & MM_DATAFILE_SEGMENT)
-    {
-      if (PhysAddr.QuadPart == PAGE_FROM_SSE(Entry) && Dirty)
-       {
-         FileObject = MemoryArea->Data.SectionData.Section->FileObject;
-         Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
-         CcRosMarkDirtyCacheSegment(Bcb, Offset);
-         assert(SwapEntry == 0);
-       }
-    }
-
-  if (SwapEntry != 0)
-    {
+   /*
+    * For a dirty, datafile, non-private page mark it as dirty in the
+    * cache manager.
+    */
+   if (Segment->Flags & MM_DATAFILE_SEGMENT)
+   {
+      if (Page == PFN_FROM_SSE(Entry) && Dirty)
+      {
+         FileObject = MemoryArea->Data.SectionData.Section->FileObject;
+         Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
+         CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
+         ASSERT(SwapEntry == 0);
+      }
+   }
+
+   if (SwapEntry != 0)
+   {
       /*
        * Sanity check
        */
       if (Segment->Flags & MM_PAGEFILE_SEGMENT)
-        {
-         DPRINT1("Found a swap entry for a page in a pagefile section.\n");
-         KEBUGCHECK(0);
-       }
+      {
+         DPRINT1("Found a swap entry for a page in a pagefile section.\n");
+         KEBUGCHECK(0);
+      }
       MmFreeSwapPage(SwapEntry);
-    }
-  else if (PhysAddr.QuadPart != 0)
-    {      
-      if (IS_SWAP_FROM_SSE(Entry) || 
-         PhysAddr.QuadPart != (PAGE_FROM_SSE(Entry)))
-       {
-          /*
-           * Sanity check
-           */
-          if (Segment->Flags & MM_PAGEFILE_SEGMENT)
-            {
-             DPRINT1("Found a private page in a pagefile section.\n");
-             KEBUGCHECK(0);
-           }
-         /*
-          * Just dereference private pages
-          */
-         SavedSwapEntry = MmGetSavedSwapEntryPage(PhysAddr);
-         if (SavedSwapEntry != 0)
-           {
-             MmFreeSwapPage(SavedSwapEntry);
-             MmSetSavedSwapEntryPage(PhysAddr, 0);
-           }
-          MmDeleteRmap(PhysAddr, MArea->Process, Address);
-          MmReleasePageMemoryConsumer(MC_USER, PhysAddr);
-       }
+   }
+   else if (Page != 0)
+   {
+      if (IS_SWAP_FROM_SSE(Entry) ||
+          Page != PFN_FROM_SSE(Entry))
+      {
+         /*
+          * Sanity check
+          */
+         if (Segment->Flags & MM_PAGEFILE_SEGMENT)
+         {
+            DPRINT1("Found a private page in a pagefile section.\n");
+            KEBUGCHECK(0);
+         }
+         /*
+          * Just dereference private pages
+          */
+         SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
+         if (SavedSwapEntry != 0)
+         {
+            MmFreeSwapPage(SavedSwapEntry);
+            MmSetSavedSwapEntryPage(Page, 0);
+         }
+         MmDeleteRmap(Page, AddressSpace->Process, Address);
+         MmReleasePageMemoryConsumer(MC_USER, Page);
+      }
       else
-       {
-          MmDeleteRmap(PhysAddr, MArea->Process, Address);
-         MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty);
-          MmReleasePageMemoryConsumer(MC_USER, PhysAddr);
-       }
-    }
+      {
+         MmDeleteRmap(Page, AddressSpace->Process, Address);
+         MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty, FALSE);
+      }
+   }
 }
 
-NTSTATUS
+STATIC NTSTATUS
 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace,
-                    PVOID BaseAddress)
+                     PVOID BaseAddress)
 {
    NTSTATUS Status;
    PMEMORY_AREA MemoryArea;
    PSECTION_OBJECT Section;
    PMM_SECTION_SEGMENT Segment;
-   KIRQL oldIrql;
    PLIST_ENTRY CurrentEntry;
    PMM_REGION CurrentRegion;
    PLIST_ENTRY RegionListHead;
 
-   MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
-                                         BaseAddress);
+   MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
+                                            BaseAddress);
    if (MemoryArea == NULL)
-     {
-       return(STATUS_UNSUCCESSFUL);
-     }
+   {
+      return(STATUS_UNSUCCESSFUL);
+   }
 
    MemoryArea->DeleteInProgress = TRUE;
    Section = MemoryArea->Data.SectionData.Section;
    Segment = MemoryArea->Data.SectionData.Segment;
-   
+
    MmLockSectionSegment(Segment);
-   KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
-   RemoveEntryList(&MemoryArea->Data.SectionData.ViewListEntry);
-   KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
 
    RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
    while (!IsListEmpty(RegionListHead))
-     {
-       CurrentEntry = RemoveHeadList(RegionListHead);
-       CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
-       ExFreePool(CurrentRegion);
-     }
+   {
+      CurrentEntry = RemoveHeadList(RegionListHead);
+      CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
+      ExFreePool(CurrentRegion);
+   }
 
    if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
-     {
-       Status = MmFreeMemoryArea(AddressSpace,
-                                BaseAddress,
-                                0,
-                                NULL,
-                                NULL);
-     }
+   {
+      Status = MmFreeMemoryArea(AddressSpace,
+                                MemoryArea,
+                                NULL,
+                                NULL);
+   }
    else
-     {
-       Status = MmFreeMemoryArea(AddressSpace,
-                                BaseAddress,
-                                0,
-                                MmFreeSectionPage,
-                                MemoryArea);
-     }
+   {
+      Status = MmFreeMemoryArea(AddressSpace,
+                                MemoryArea,
+                                MmFreeSectionPage,
+                                AddressSpace);
+   }
    MmUnlockSectionSegment(Segment);
    ObDereferenceObject(Section);
    return(STATUS_SUCCESS);
@@ -3415,120 +3873,164 @@ MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace,
  */
 NTSTATUS STDCALL
 MmUnmapViewOfSection(PEPROCESS Process,
-                    PVOID BaseAddress)
+                     PVOID BaseAddress)
 {
-   NTSTATUS    Status;
+   NTSTATUS Status;
    PMEMORY_AREA MemoryArea;
    PMADDRESS_SPACE AddressSpace;
    PSECTION_OBJECT Section;
-   
+   PMM_PAGEOP PageOp;
+   ULONG_PTR Offset;
+
    DPRINT("Opening memory area Process %x BaseAddress %x\n",
-         Process, BaseAddress);
+          Process, BaseAddress);
+
+   ASSERT(Process);
 
-   assert(Process);
-   
    AddressSpace = &Process->AddressSpace;
-   MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
-                                         BaseAddress);
-   if (MemoryArea == NULL)
-     {
-       return(STATUS_UNSUCCESSFUL);
-     }
+   
+   MmLockAddressSpace(AddressSpace);
+   MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
+                                            BaseAddress);
+   if (MemoryArea == NULL ||
+       MemoryArea->Type != MEMORY_AREA_SECTION_VIEW ||
+       MemoryArea->DeleteInProgress)
+   {
+      MmUnlockAddressSpace(AddressSpace);
+      return STATUS_NOT_MAPPED_VIEW;
+   }
+
+   MemoryArea->DeleteInProgress = TRUE;
+
+   while (MemoryArea->PageOpCount)
+   {
+      Offset = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress);
+
+      while (Offset)
+      {
+         Offset -= PAGE_SIZE;
+         PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL,
+                                   MemoryArea->Data.SectionData.Segment,
+                                   Offset + MemoryArea->Data.SectionData.ViewOffset);
+         if (PageOp)
+         {
+            MmUnlockAddressSpace(AddressSpace);
+            Status = MmspWaitForPageOpCompletionEvent(PageOp);
+            if (Status != STATUS_SUCCESS)
+            {
+               DPRINT1("Failed to wait for page op, status = %x\n", Status);
+               KEBUGCHECK(0);
+            }
+            MmLockAddressSpace(AddressSpace);
+            MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
+                                                     BaseAddress);
+            if (MemoryArea == NULL ||
+                MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
+            {
+               MmUnlockAddressSpace(AddressSpace);
+               return STATUS_NOT_MAPPED_VIEW;
+            }
+            break;
+         }
+      }
+   }
+
+   Section = MemoryArea->Data.SectionData.Section;
+
+   if (Section->AllocationAttributes & SEC_IMAGE)
+   {
+      ULONG i;
+      ULONG NrSegments;
+      PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
+      PMM_SECTION_SEGMENT SectionSegments;
+      PVOID ImageBaseAddress = 0;
+      PMM_SECTION_SEGMENT Segment;
 
-   Section = MemoryArea->Data.SectionData.Section;
+      Segment = MemoryArea->Data.SectionData.Segment;
+      ImageSectionObject = Section->ImageSection;
+      SectionSegments = ImageSectionObject->Segments;
+      NrSegments = ImageSectionObject->NrSegments;
 
-   if (Section->AllocationAttributes & SEC_IMAGE)
-     {
-       ULONG i;
-       ULONG NrSegments;
-       PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
-       PMM_SECTION_SEGMENT SectionSegments;
-       PVOID ImageBaseAddress;
-       PMM_SECTION_SEGMENT Segment;
-   
-       Segment = MemoryArea->Data.SectionData.Segment;
-       ImageSectionObject = Section->ImageSection;
-       SectionSegments = ImageSectionObject->Segments;
-       NrSegments = ImageSectionObject->NrSegments;
-
-       /* Search for the current segment within the section segments 
-        * and calculate the image base address */
-       for (i = 0; i < NrSegments; i++)
+      /* Search for the current segment within the section segments
+       * and calculate the image base address */
+      for (i = 0; i < NrSegments; i++)
+      {
+         if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
          {
-          if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
-            {
-              if (Segment == &SectionSegments[i])
-                {
-                  ImageBaseAddress = BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress;
-                  break;
-                }
-            }
-        }
-       if (i >= NrSegments)
+            if (Segment == &SectionSegments[i])
+            {
+               ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress;
+               break;
+            }
+         }
+      }
+      if (i >= NrSegments)
+      {
+         KEBUGCHECK(0);
+      }
+
+      for (i = 0; i < NrSegments; i++)
+      {
+         if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
          {
-           KEBUGCHECK(0);
-        }
-
-       for (i = 0; i < NrSegments; i++)
-        {
-          if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
-            {
-              PVOID SBaseAddress = (PVOID)
-                (ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
-
-              Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
-            }
-        }
-     }
+            PVOID SBaseAddress = (PVOID)
+                                 ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
+
+            Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
+         }
+      }
+   }
    else
-     {
-       Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
-     }
+   {
+      Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
+   }
+   MmUnlockAddressSpace(AddressSpace);
    return(STATUS_SUCCESS);
 }
 
 /**********************************************************************
- * NAME                                                        EXPORTED
- *     NtUnmapViewOfSection
+ * NAME       EXPORTED
+ * NtUnmapViewOfSection
  *
  * DESCRIPTION
  *
  * ARGUMENTS
- *     ProcessHandle
+ * ProcessHandle
  *
- *     BaseAddress
+ * BaseAddress
  *
  * RETURN VALUE
- *     Status.
+ * Status.
  *
  * REVISIONS
  */
 NTSTATUS STDCALL
-NtUnmapViewOfSection (HANDLE   ProcessHandle,
-                     PVOID     BaseAddress)
+NtUnmapViewOfSection (HANDLE ProcessHandle,
+                      PVOID BaseAddress)
 {
-   PEPROCESS   Process;
+   PEPROCESS Process;
+   KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;
-   
+
    DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
-          ProcessHandle, BaseAddress);
-   
+          ProcessHandle, BaseAddress);
+
+   PreviousMode = ExGetPreviousMode();
+
    DPRINT("Referencing process\n");
    Status = ObReferenceObjectByHandle(ProcessHandle,
-                                     PROCESS_VM_OPERATION,
-                                     PsProcessType,
-                                     UserMode,
-                                     (PVOID*)&Process,
-                                     NULL);
+                                      PROCESS_VM_OPERATION,
+                                      PsProcessType,
+                                      PreviousMode,
+                                      (PVOID*)(PVOID)&Process,
+                                      NULL);
    if (!NT_SUCCESS(Status))
-     {
-       DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
-       return(Status);
-     }
+   {
+      DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
+      return(Status);
+   }
 
-   MmLockAddressSpace(&Process->AddressSpace);
    Status = MmUnmapViewOfSection(Process, BaseAddress);
-   MmUnlockAddressSpace(&Process->AddressSpace);
 
    ObDereferenceObject(Process);
 
@@ -3536,250 +4038,362 @@ NtUnmapViewOfSection (HANDLE  ProcessHandle,
 }
 
 
-NTSTATUS STDCALL
-NtQuerySection (IN     HANDLE  SectionHandle,
-               IN      CINT    SectionInformationClass,
-               OUT     PVOID   SectionInformation,
-               IN      ULONG   Length, 
-               OUT     PULONG  ResultLength)
-/*
- * FUNCTION: Queries the information of a section object.
- * ARGUMENTS: 
- *        SectionHandle = Handle to the section link object
- *       SectionInformationClass = Index to a certain information structure
- *        SectionInformation (OUT)= Caller supplies storage for resulting 
- *                                  information
- *        Length =  Size of the supplied storage 
- *        ResultLength = Data written
- * RETURNS: Status
+/**
+ * Queries the information of a section object.
  *
+ * @param SectionHandle
+ *        Handle to the section object. It must be opened with SECTION_QUERY
+ *        access.
+ * @param SectionInformationClass
+ *        Index to a certain information structure. Can be either
+ *        SectionBasicInformation or SectionImageInformation. The latter
+ *        is valid only for sections that were created with the SEC_IMAGE
+ *        flag.
+ * @param SectionInformation
+ *        Caller supplies storage for resulting information.
+ * @param Length
+ *        Size of the supplied storage.
+ * @param ResultLength
+ *        Data written.
+ *
+ * @return Status.
+ *
+ * @implemented
  */
+NTSTATUS STDCALL
+NtQuerySection(IN HANDLE SectionHandle,
+               IN SECTION_INFORMATION_CLASS SectionInformationClass,
+               OUT PVOID SectionInformation,
+               IN ULONG SectionInformationLength,
+               OUT PULONG ResultLength  OPTIONAL)
 {
-  PSECTION_OBJECT Section;
-  NTSTATUS Status;
-
-  Status = ObReferenceObjectByHandle(SectionHandle,
-                                    SECTION_MAP_READ,
-                                    MmSectionObjectType,
-                                    UserMode,
-                                    (PVOID*)&Section,
-                                    NULL);
-  if (!(NT_SUCCESS(Status)))
-    {
-      return(Status);
-    }
+   PSECTION_OBJECT Section;
+   KPROCESSOR_MODE PreviousMode;
+   NTSTATUS Status = STATUS_SUCCESS;
+
+   PreviousMode = ExGetPreviousMode();
+
+   Status = DefaultQueryInfoBufferCheck(SectionInformationClass,
+                                        ExSectionInfoClass,
+                                        sizeof(ExSectionInfoClass) / sizeof(ExSectionInfoClass[0]),
+                                        SectionInformation,
+                                        SectionInformationLength,
+                                        ResultLength,
+                                        PreviousMode);
+
+   if(!NT_SUCCESS(Status))
+   {
+     DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status);
+     return Status;
+   }
 
-  switch (SectionInformationClass)
-    {
-    case SectionBasicInformation:
+   Status = ObReferenceObjectByHandle(SectionHandle,
+                                      SECTION_QUERY,
+                                      MmSectionObjectType,
+                                      PreviousMode,
+                                      (PVOID*)(PVOID)&Section,
+                                      NULL);
+   if (NT_SUCCESS(Status))
+   {
+      switch (SectionInformationClass)
       {
-       PSECTION_BASIC_INFORMATION Sbi;
-
-       if (Length != sizeof(SECTION_BASIC_INFORMATION))
-         {
-           ObDereferenceObject(Section);
-           return(STATUS_INFO_LENGTH_MISMATCH);
-         }
-
-       Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
-       
-       Sbi->BaseAddress = 0;
-       Sbi->Attributes = 0;
-       Sbi->Size.QuadPart = 0;
-
-       *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
-       Status = STATUS_SUCCESS;
-       break;
+         case SectionBasicInformation:
+         {
+            PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
+
+            _SEH_TRY
+            {
+               Sbi->Attributes = Section->AllocationAttributes;
+               if (Section->AllocationAttributes & SEC_IMAGE)
+               {
+                  Sbi->BaseAddress = 0;
+                  Sbi->Size.QuadPart = 0;
+               }
+               else
+               {
+                  Sbi->BaseAddress = (PVOID)Section->Segment->VirtualAddress;
+                  Sbi->Size.QuadPart = Section->Segment->Length;
+               }
+
+               if (ResultLength != NULL)
+               {
+                  *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
+               }
+               Status = STATUS_SUCCESS;
+            }
+            _SEH_HANDLE
+            {
+               Status = _SEH_GetExceptionCode();
+            }
+            _SEH_END;
+
+            break;
+         }
+
+         case SectionImageInformation:
+         {
+            PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
+
+            _SEH_TRY
+            {
+               memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
+               if (Section->AllocationAttributes & SEC_IMAGE)
+               {
+                  PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
+                  ImageSectionObject = Section->ImageSection;
+
+                  Sii->TransferAddress = (PVOID)ImageSectionObject->EntryPoint;
+                  Sii->MaximumStackSize = ImageSectionObject->StackReserve;
+                  Sii->CommittedStackSize = ImageSectionObject->StackCommit;
+                  Sii->SubsystemType = ImageSectionObject->Subsystem;
+                  Sii->SubSystemMinorVersion = ImageSectionObject->MinorSubsystemVersion;
+                  Sii->SubSystemMajorVersion = ImageSectionObject->MajorSubsystemVersion;
+                  Sii->ImageCharacteristics = ImageSectionObject->ImageCharacteristics;
+                  Sii->Machine = ImageSectionObject->Machine;
+                  Sii->ImageContainsCode = ImageSectionObject->Executable;
+               }
+
+               if (ResultLength != NULL)
+               {
+                  *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
+               }
+               Status = STATUS_SUCCESS;
+            }
+            _SEH_HANDLE
+            {
+               Status = _SEH_GetExceptionCode();
+            }
+            _SEH_END;
+
+            break;
+         }
       }
 
-      case SectionImageInformation:
-       {
-         PSECTION_IMAGE_INFORMATION Sii;
-
-         if (Length != sizeof(SECTION_IMAGE_INFORMATION))
-           {
-             ObDereferenceObject(Section);
-             return(STATUS_INFO_LENGTH_MISMATCH);
-           }
-         
-         Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation; 
-         memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
-         if (Section->AllocationAttributes & SEC_IMAGE)
-           {
-             PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
-             ImageSectionObject = Section->ImageSection;
-             
-             Sii->EntryPoint = ImageSectionObject->EntryPoint;
-             Sii->StackReserve = ImageSectionObject->StackReserve;
-             Sii->StackCommit = ImageSectionObject->StackCommit;
-             Sii->Subsystem = ImageSectionObject->Subsystem;
-             Sii->MinorSubsystemVersion = ImageSectionObject->MinorSubsystemVersion;
-             Sii->MajorSubsystemVersion = ImageSectionObject->MajorSubsystemVersion;
-             Sii->Characteristics = ImageSectionObject->ImageCharacteristics;
-             Sii->ImageNumber = ImageSectionObject->Machine;
-             Sii->Executable = ImageSectionObject->Executable;
-           }
-         *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
-         Status = STATUS_SUCCESS;
-         break;
-       }
-
-    default:
-      *ResultLength = 0;
-      Status = STATUS_INVALID_INFO_CLASS;
-    }
-  ObDereferenceObject(Section);
-  return(Status);
+      ObDereferenceObject(Section);
+   }
+
+   return(Status);
 }
 
 
-NTSTATUS STDCALL 
-NtExtendSection(IN     HANDLE  SectionHandle,
-               IN      ULONG   NewMaximumSize)
+/**
+ * Extends size of file backed section.
+ *
+ * @param SectionHandle
+ *        Handle to the section object. It must be opened with
+ *        SECTION_EXTEND_SIZE access.
+ * @param NewMaximumSize
+ *        New maximum size of the section in bytes.
+ *
+ * @return Status.
+ *
+ * @todo Move the actual code to internal function MmExtendSection.
+ * @unimplemented
+ */
+NTSTATUS STDCALL
+NtExtendSection(IN HANDLE SectionHandle,
+                IN PLARGE_INTEGER NewMaximumSize)
 {
-   UNIMPLEMENTED;
-   return(STATUS_NOT_IMPLEMENTED);
+   LARGE_INTEGER SafeNewMaximumSize;
+   PSECTION_OBJECT Section;
+   KPROCESSOR_MODE PreviousMode;
+   NTSTATUS Status = STATUS_SUCCESS;
+
+   PreviousMode = ExGetPreviousMode();
+
+   if(PreviousMode != KernelMode)
+   {
+     _SEH_TRY
+     {
+       /* make a copy on the stack */
+       SafeNewMaximumSize = ProbeForReadLargeInteger(NewMaximumSize);
+       NewMaximumSize = &SafeNewMaximumSize;
+     }
+     _SEH_HANDLE
+     {
+       Status = _SEH_GetExceptionCode();
+     }
+     _SEH_END;
+
+     if(!NT_SUCCESS(Status))
+     {
+       return Status;
+     }
+   }
+
+   Status = ObReferenceObjectByHandle(SectionHandle,
+                                      SECTION_EXTEND_SIZE,
+                                      MmSectionObjectType,
+                                      PreviousMode,
+                                      (PVOID*)&Section,
+                                      NULL);
+   if (!NT_SUCCESS(Status))
+   {
+      return Status;
+   }
+
+   if (!(Section->AllocationAttributes & SEC_FILE))
+   {
+      ObfDereferenceObject(Section);
+      return STATUS_INVALID_PARAMETER;
+   }
+
+   /*
+    * - Acquire file extneding resource.
+    * - Check if we're not resizing the section below it's actual size!
+    * - Extend segments if needed.
+    * - Set file information (FileAllocationInformation) to the new size.
+    * - Release file extending resource.
+    */
+
+   ObDereferenceObject(Section);
+
+   return STATUS_NOT_IMPLEMENTED;
 }
 
 
 /**********************************************************************
- * NAME                                                        INTERNAL
- *     MmAllocateSection@4
+ * NAME       INTERNAL
+ *  MmAllocateSection@4
  *
  * DESCRIPTION
  *
  * ARGUMENTS
- *     Length
+ *  Length
  *
  * RETURN VALUE
  *
  * NOTE
- *     Code taken from ntoskrnl/mm/special.c.
+ *  Code taken from ntoskrnl/mm/special.c.
  *
  * REVISIONS
  */
-PVOID STDCALL 
-MmAllocateSection (IN ULONG Length)
+PVOID STDCALL
+MmAllocateSection (IN ULONG Length, PVOID BaseAddress)
 {
    PVOID Result;
    MEMORY_AREA* marea;
    NTSTATUS Status;
    ULONG i;
    PMADDRESS_SPACE AddressSpace;
-   
+   PHYSICAL_ADDRESS BoundaryAddressMultiple;
+
    DPRINT("MmAllocateSection(Length %x)\n",Length);
-   
+
+   BoundaryAddressMultiple.QuadPart = 0;
+
    AddressSpace = MmGetKernelAddressSpace();
-   Result = NULL;
+   Result = BaseAddress;
    MmLockAddressSpace(AddressSpace);
    Status = MmCreateMemoryArea (NULL,
-                               AddressSpace,
-                               MEMORY_AREA_SYSTEM,
-                               &Result,
-                               Length,
-                               0,
-                               &marea,
-                               FALSE,
-                               FALSE);
-   if (!NT_SUCCESS(Status))
-     {
-       MmUnlockAddressSpace(AddressSpace);
-       return (NULL);
-     }
+                                AddressSpace,
+                                MEMORY_AREA_SYSTEM,
+                                &Result,
+                                Length,
+                                0,
+                                &marea,
+                                FALSE,
+                                FALSE,
+                                BoundaryAddressMultiple);
    MmUnlockAddressSpace(AddressSpace);
+
+   if (!NT_SUCCESS(Status))
+   {
+      return (NULL);
+   }
    DPRINT("Result %p\n",Result);
    for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
-     {
-       PHYSICAL_ADDRESS Page;
-
-       Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page);
-       if (!NT_SUCCESS(Status))
-        {
-          DbgPrint("Unable to allocate page\n");
-          KEBUGCHECK(0);
-        }
-       Status = MmCreateVirtualMapping (NULL,
-                                       (Result + (i * PAGE_SIZE)),
-                                       PAGE_READWRITE,
-                                       Page,
-                                       TRUE);
-       if (!NT_SUCCESS(Status))
-        {
-          DbgPrint("Unable to create virtual mapping\n");
-          KEBUGCHECK(0);
-        }
-     }
+   {
+      PFN_TYPE Page;
+
+      Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page);
+      if (!NT_SUCCESS(Status))
+      {
+         DbgPrint("Unable to allocate page\n");
+         KEBUGCHECK(0);
+      }
+      Status = MmCreateVirtualMapping (NULL,
+                                       (PVOID)((ULONG_PTR)Result + (i * PAGE_SIZE)),
+                                       PAGE_READWRITE,
+                                       &Page,
+                                       1);
+      if (!NT_SUCCESS(Status))
+      {
+         DbgPrint("Unable to create virtual mapping\n");
+         KEBUGCHECK(0);
+      }
+   }
    return ((PVOID)Result);
 }
 
 
 /**********************************************************************
- * NAME                                                        EXPORTED
- *     MmMapViewOfSection
+ * NAME       EXPORTED
+ * MmMapViewOfSection
  *
  * DESCRIPTION
- *     Maps a view of a section into the virtual address space of a 
- *     process.
- *     
+ * Maps a view of a section into the virtual address space of a
+ * process.
+ *
  * ARGUMENTS
- *     Section
- *             Pointer to the section object.
- *             
- *     ProcessHandle
- *             Pointer to the process.
- *             
- *     BaseAddress
- *             Desired base address (or NULL) on entry;
- *             Actual base address of the view on exit.
- *             
- *     ZeroBits
- *             Number of high order address bits that must be zero.
- *             
- *     CommitSize
- *             Size in bytes of the initially committed section of 
- *             the view.
- *             
- *     SectionOffset
- *             Offset in bytes from the beginning of the section
- *             to the beginning of the view.
- *             
- *     ViewSize
- *             Desired length of map (or zero to map all) on entry
- *             Actual length mapped on exit.
- *             
- *     InheritDisposition
- *             Specified how the view is to be shared with
- *             child processes.
- *             
- *     AllocationType
- *             Type of allocation for the pages.
- *             
- *     Protect
- *             Protection for the committed region of the view.
+ * Section
+ *  Pointer to the section object.
+ *
+ * ProcessHandle
+ *  Pointer to the process.
+ *
+ * BaseAddress
+ *  Desired base address (or NULL) on entry;
+ *  Actual base address of the view on exit.
+ *
+ * ZeroBits
+ *  Number of high order address bits that must be zero.
+ *
+ * CommitSize
+ *  Size in bytes of the initially committed section of
+ *  the view.
+ *
+ * SectionOffset
+ *  Offset in bytes from the beginning of the section
+ *  to the beginning of the view.
+ *
+ * ViewSize
+ *  Desired length of map (or zero to map all) on entry
+ *  Actual length mapped on exit.
+ *
+ * InheritDisposition
+ *  Specified how the view is to be shared with
+ *  child processes.
+ *
+ * AllocationType
+ *  Type of allocation for the pages.
+ *
+ * Protect
+ *  Protection for the committed region of the view.
  *
  * RETURN VALUE
- *     Status.
+ * Status.
  *
  * @implemented
  */
 NTSTATUS STDCALL
 MmMapViewOfSection(IN PVOID SectionObject,
-                  IN PEPROCESS Process,
-                  IN OUT PVOID *BaseAddress,
-                  IN ULONG ZeroBits,
-                  IN ULONG CommitSize,
-                  IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
-                  IN OUT PULONG ViewSize,
-                  IN SECTION_INHERIT InheritDisposition,
-                  IN ULONG AllocationType,
-                  IN ULONG Protect)
+                   IN PEPROCESS Process,
+                   IN OUT PVOID *BaseAddress,
+                   IN ULONG ZeroBits,
+                   IN ULONG CommitSize,
+                   IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
+                   IN OUT PULONG ViewSize,
+                   IN SECTION_INHERIT InheritDisposition,
+                   IN ULONG AllocationType,
+                   IN ULONG Protect)
 {
    PSECTION_OBJECT Section;
    PMADDRESS_SPACE AddressSpace;
    ULONG ViewOffset;
    NTSTATUS Status = STATUS_SUCCESS;
 
-   assert(Process);
+   ASSERT(Process);
 
    Section = (PSECTION_OBJECT)SectionObject;
    AddressSpace = &Process->AddressSpace;
@@ -3787,128 +4401,133 @@ MmMapViewOfSection(IN PVOID SectionObject,
    MmLockAddressSpace(AddressSpace);
 
    if (Section->AllocationAttributes & SEC_IMAGE)
-     {
-       ULONG i;
-       ULONG NrSegments;
-       PVOID ImageBase;
-       ULONG ImageSize;
-       PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
-       PMM_SECTION_SEGMENT SectionSegments;
-
-       ImageSectionObject = Section->ImageSection;
-       SectionSegments = ImageSectionObject->Segments;
-       NrSegments = ImageSectionObject->NrSegments;
-
-
-       ImageBase = *BaseAddress;
-       if (ImageBase == NULL)
-        {
-          ImageBase = ImageSectionObject->ImageBase;
-        }
-
-       ImageSize = 0;
-       for (i = 0; i < NrSegments; i++)
-        {
-          if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
-            {
-              ULONG MaxExtent;
-              MaxExtent = (ULONG)(SectionSegments[i].VirtualAddress +
-                                  SectionSegments[i].Length);
-              ImageSize = max(ImageSize, MaxExtent);
-            }
-        }
-
-       /* Check there is enough space to map the section at that point. */
-       if (MmOpenMemoryAreaByRegion(AddressSpace, ImageBase, 
-                                   PAGE_ROUND_UP(ImageSize)) != NULL)
-        {
-          /* Fail if the user requested a fixed base address. */
-          if ((*BaseAddress) != NULL)
-            {
-              MmUnlockAddressSpace(AddressSpace);
-              return(STATUS_UNSUCCESSFUL);
-            }
-          /* Otherwise find a gap to map the image. */
-          ImageBase = MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), FALSE);
-          if (ImageBase == NULL)
-            {
-              MmUnlockAddressSpace(AddressSpace);
-              return(STATUS_UNSUCCESSFUL);
-            }
-        }
-
-       for (i = 0; i < NrSegments; i++)
-        {
-          PVOID SBaseAddress;
-
-          if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
-            {
-              SBaseAddress = (PVOID)
-                (ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
-              MmLockSectionSegment(&SectionSegments[i]);
-              Status = MmMapViewOfSegment(Process,
-                                          AddressSpace,
-                                          Section,
-                                          &SectionSegments[i],
-                                          &SBaseAddress,
-                                          SectionSegments[i].Length,
-                                          SectionSegments[i].Protection,
-                                          (ULONG_PTR)SectionSegments[i].VirtualAddress,
-                                          FALSE);
-              MmUnlockSectionSegment(&SectionSegments[i]);
-              if (!NT_SUCCESS(Status))
-                {
-                  MmUnlockAddressSpace(AddressSpace);
-                  return(Status);
-                }
-            }
-        }
-
-       *BaseAddress = ImageBase;
-     }
+   {
+      ULONG i;
+      ULONG NrSegments;
+      ULONG_PTR ImageBase;
+      ULONG ImageSize;
+      PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
+      PMM_SECTION_SEGMENT SectionSegments;
+
+      ImageSectionObject = Section->ImageSection;
+      SectionSegments = ImageSectionObject->Segments;
+      NrSegments = ImageSectionObject->NrSegments;
+
+
+      ImageBase = (ULONG_PTR)*BaseAddress;
+      if (ImageBase == 0)
+      {
+         ImageBase = ImageSectionObject->ImageBase;
+      }
+
+      ImageSize = 0;
+      for (i = 0; i < NrSegments; i++)
+      {
+         if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
+         {
+            ULONG_PTR MaxExtent;
+            MaxExtent = (ULONG_PTR)SectionSegments[i].VirtualAddress +
+                        SectionSegments[i].Length;
+            ImageSize = max(ImageSize, MaxExtent);
+         }
+      }
+
+      /* Check there is enough space to map the section at that point. */
+      if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
+                                     PAGE_ROUND_UP(ImageSize)) != NULL)
+      {
+         /* Fail if the user requested a fixed base address. */
+         if ((*BaseAddress) != NULL)
+         {
+            MmUnlockAddressSpace(AddressSpace);
+            return(STATUS_UNSUCCESSFUL);
+         }
+         /* Otherwise find a gap to map the image. */
+         ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE);
+         if (ImageBase == 0)
+         {
+            MmUnlockAddressSpace(AddressSpace);
+            return(STATUS_UNSUCCESSFUL);
+         }
+      }
+
+      for (i = 0; i < NrSegments; i++)
+      {
+         if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
+         {
+            PVOID SBaseAddress = (PVOID)
+                                 ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
+            MmLockSectionSegment(&SectionSegments[i]);
+            Status = MmMapViewOfSegment(Process,
+                                        AddressSpace,
+                                        Section,
+                                        &SectionSegments[i],
+                                        &SBaseAddress,
+                                        SectionSegments[i].Length,
+                                        SectionSegments[i].Protection,
+                                        0,
+                                        FALSE);
+            MmUnlockSectionSegment(&SectionSegments[i]);
+            if (!NT_SUCCESS(Status))
+            {
+               MmUnlockAddressSpace(AddressSpace);
+               return(Status);
+            }
+         }
+      }
+
+      *BaseAddress = (PVOID)ImageBase;
+   }
    else
-     {
-       if (SectionOffset == NULL)
-        {
-          ViewOffset = 0;
-        }
-       else
-        {
-          ViewOffset = SectionOffset->u.LowPart;
-        }
-
-       if ((ViewOffset % PAGE_SIZE) != 0)
-        {
-          MmUnlockAddressSpace(AddressSpace);
-          return(STATUS_MAPPED_ALIGNMENT);
-        }
-
-       if ((*ViewSize) == 0)
-        {
-          (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
-        }
-       else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
-        {
-          (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
-        }
-
-       MmLockSectionSegment(Section->Segment);
-       Status = MmMapViewOfSegment(Process,
-                                  AddressSpace,
-                                  Section,
-                                  Section->Segment,
-                                  BaseAddress,
-                                  *ViewSize,
-                                  Protect,
-                                  ViewOffset,
-                                  (AllocationType & MEM_TOP_DOWN));
-       MmUnlockSectionSegment(Section->Segment);
-       if (!NT_SUCCESS(Status))
-        {
-           MmUnlockAddressSpace(AddressSpace);
-          return(Status);
-        }
-     }
+   {
+      if (ViewSize == NULL)
+      {
+         /* Following this pointer would lead to us to the dark side */
+         /* What to do? Bugcheck? Return status? Do the mambo? */
+         KEBUGCHECK(MEMORY_MANAGEMENT);
+      }
+
+      if (SectionOffset == NULL)
+      {
+         ViewOffset = 0;
+      }
+      else
+      {
+         ViewOffset = SectionOffset->u.LowPart;
+      }
+
+      if ((ViewOffset % PAGE_SIZE) != 0)
+      {
+         MmUnlockAddressSpace(AddressSpace);
+         return(STATUS_MAPPED_ALIGNMENT);
+      }
+
+      if ((*ViewSize) == 0)
+      {
+         (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
+      }
+      else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
+      {
+         (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
+      }
+
+      MmLockSectionSegment(Section->Segment);
+      Status = MmMapViewOfSegment(Process,
+                                  AddressSpace,
+                                  Section,
+                                  Section->Segment,
+                                  BaseAddress,
+                                  *ViewSize,
+                                  Protect,
+                                  ViewOffset,
+                                  (AllocationType & MEM_TOP_DOWN) == MEM_TOP_DOWN);
+      MmUnlockSectionSegment(Section->Segment);
+      if (!NT_SUCCESS(Status))
+      {
+         MmUnlockAddressSpace(AddressSpace);
+         return(Status);
+      }
+   }
 
    MmUnlockAddressSpace(AddressSpace);
 
@@ -3919,11 +4538,11 @@ MmMapViewOfSection(IN PVOID SectionObject,
  * @unimplemented
  */
 BOOLEAN STDCALL
-MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS      SectionObjectPointer,
-                     IN PLARGE_INTEGER                 NewFileSize)
+MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
+                      IN PLARGE_INTEGER   NewFileSize)
 {
-  UNIMPLEMENTED;
-  return (FALSE);
+   UNIMPLEMENTED;
+   return (FALSE);
 }
 
 
@@ -3931,31 +4550,31 @@ MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS       SectionObjectPointer,
  * @unimplemented
  */
 BOOLEAN STDCALL
-MmDisableModifiedWriteOfSection (DWORD Unknown0)
+MmDisableModifiedWriteOfSection (DWORD Unknown0)
 {
-  UNIMPLEMENTED;
-  return (FALSE);
+   UNIMPLEMENTED;
+   return (FALSE);
 }
 
 /*
  * @implemented
  */
 BOOLEAN STDCALL
-MmFlushImageSection (IN        PSECTION_OBJECT_POINTERS        SectionObjectPointer,
-                    IN MMFLUSH_TYPE                    FlushType)
+MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
+                     IN MMFLUSH_TYPE   FlushType)
 {
    switch(FlushType)
    {
-      case MmFlushForDelete: 
-         if (SectionObjectPointer->ImageSectionObject || 
-            SectionObjectPointer->DataSectionObject)
-        {
+      case MmFlushForDelete:
+         if (SectionObjectPointer->ImageSectionObject ||
+               SectionObjectPointer->DataSectionObject)
+         {
             return FALSE;
-        }
-        CcRosSetRemoveOnClose(SectionObjectPointer);
+         }
+         CcRosSetRemoveOnClose(SectionObjectPointer);
          return TRUE;
       case MmFlushForWrite:
-        break;
+         break;
    }
    return FALSE;
 }
@@ -3964,11 +4583,12 @@ MmFlushImageSection (IN PSECTION_OBJECT_POINTERS        SectionObjectPointer,
  * @unimplemented
  */
 BOOLEAN STDCALL
-MmForceSectionClosed (DWORD    Unknown0,
-                     DWORD     Unknown1)
+MmForceSectionClosed (
+    IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
+    IN BOOLEAN                  DelayClose)
 {
-  UNIMPLEMENTED;
-  return (FALSE);
+   UNIMPLEMENTED;
+   return (FALSE);
 }
 
 
@@ -3976,48 +4596,63 @@ MmForceSectionClosed (DWORD     Unknown0,
  * @implemented
  */
 NTSTATUS STDCALL
-MmMapViewInSystemSpace (IN     PVOID   SectionObject,
-                       OUT     PVOID   * MappedBase,
-                       IN OUT  PULONG  ViewSize)
+MmMapViewInSystemSpace (IN PVOID SectionObject,
+                        OUT PVOID * MappedBase,
+                        IN OUT PULONG ViewSize)
 {
-  PSECTION_OBJECT Section;
-  PMADDRESS_SPACE AddressSpace;
-  NTSTATUS Status;
+   PSECTION_OBJECT Section;
+   PMADDRESS_SPACE AddressSpace;
+   NTSTATUS Status;
+
+   DPRINT("MmMapViewInSystemSpace() called\n");
 
-  DPRINT("MmMapViewInSystemSpace() called\n");
+   Section = (PSECTION_OBJECT)SectionObject;
+   AddressSpace = MmGetKernelAddressSpace();
 
-  Section = (PSECTION_OBJECT)SectionObject;
-  AddressSpace = MmGetKernelAddressSpace();
+   MmLockAddressSpace(AddressSpace);
 
-  MmLockAddressSpace(AddressSpace);
 
-  
-  if ((*ViewSize) == 0)
-    {
+   if ((*ViewSize) == 0)
+   {
       (*ViewSize) = Section->MaximumSize.u.LowPart;
-    }
-  else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
-    {
+   }
+   else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
+   {
       (*ViewSize) = Section->MaximumSize.u.LowPart;
-    }
+   }
 
-  MmLockSectionSegment(Section->Segment);
+   MmLockSectionSegment(Section->Segment);
 
 
-  Status = MmMapViewOfSegment(NULL,
-                             AddressSpace,
-                             Section,
-                             Section->Segment,
-                             MappedBase,
-                             *ViewSize,
-                             PAGE_READWRITE,
-                             0,
-                             FALSE);
+   Status = MmMapViewOfSegment(NULL,
+                               AddressSpace,
+                               Section,
+                               Section->Segment,
+                               MappedBase,
+                               *ViewSize,
+                               PAGE_READWRITE,
+                               0,
+                               FALSE);
 
-  MmUnlockSectionSegment(Section->Segment);
-  MmUnlockAddressSpace(AddressSpace);
+   MmUnlockSectionSegment(Section->Segment);
+   MmUnlockAddressSpace(AddressSpace);
+
+   return Status;
+}
 
-  return Status;
+/*
+ * @unimplemented
+ */
+NTSTATUS
+STDCALL
+MmMapViewInSessionSpace (
+    IN PVOID Section,
+    OUT PVOID *MappedBase,
+    IN OUT PSIZE_T ViewSize
+    )
+{
+       UNIMPLEMENTED;
+       return STATUS_NOT_IMPLEMENTED;
 }
 
 
@@ -4025,103 +4660,142 @@ MmMapViewInSystemSpace (IN    PVOID   SectionObject,
  * @implemented
  */
 NTSTATUS STDCALL
-MmUnmapViewInSystemSpace (IN   PVOID   MappedBase)
+MmUnmapViewInSystemSpace (IN PVOID MappedBase)
 {
-  PMADDRESS_SPACE AddressSpace;
-  NTSTATUS Status;
+   PMADDRESS_SPACE AddressSpace;
+   NTSTATUS Status;
 
-  DPRINT("MmUnmapViewInSystemSpace() called\n");
+   DPRINT("MmUnmapViewInSystemSpace() called\n");
 
-  AddressSpace = MmGetKernelAddressSpace();
+   AddressSpace = MmGetKernelAddressSpace();
 
-  Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
+   Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
 
-  return Status;
+   return Status;
 }
 
+/*
+ * @unimplemented
+ */
+NTSTATUS
+STDCALL
+MmUnmapViewInSessionSpace (
+    IN PVOID MappedBase
+    )
+{
+       UNIMPLEMENTED;
+       return STATUS_NOT_IMPLEMENTED;
+}
 
 /*
  * @unimplemented
  */
 NTSTATUS STDCALL
-MmSetBankedSection (DWORD      Unknown0,
-                   DWORD       Unknown1,
-                   DWORD       Unknown2,
-                   DWORD       Unknown3,
-                   DWORD       Unknown4,
-                   DWORD       Unknown5)
+MmSetBankedSection (DWORD Unknown0,
+                    DWORD Unknown1,
+                    DWORD Unknown2,
+                    DWORD Unknown3,
+                    DWORD Unknown4,
+                    DWORD Unknown5)
 {
-  UNIMPLEMENTED;
-  return (STATUS_NOT_IMPLEMENTED);
+   UNIMPLEMENTED;
+   return (STATUS_NOT_IMPLEMENTED);
 }
 
 
 /**********************************************************************
- * NAME                                                        EXPORTED
- *     MmCreateSection@
- *     
+ * NAME       EXPORTED
+ *  MmCreateSection@
+ *
  * DESCRIPTION
- *     Creates a section object.
- *     
+ *  Creates a section object.
+ *
  * ARGUMENTS
- *     SectionObjiect (OUT)
- *             Caller supplied storage for the resulting pointer
- *             to a SECTION_OBJECT instance;
- *             
- *     DesiredAccess
- *             Specifies the desired access to the section can be a
- *             combination of:
- *                     STANDARD_RIGHTS_REQUIRED        |
- *                     SECTION_QUERY                   |
- *                     SECTION_MAP_WRITE               |
- *                     SECTION_MAP_READ                |
- *                     SECTION_MAP_EXECUTE
- *                     
- *     ObjectAttributes [OPTIONAL]
- *             Initialized attributes for the object can be used 
- *             to create a named section;
+ * SectionObject (OUT)
+ *  Caller supplied storage for the resulting pointer
+ *  to a SECTION_OBJECT instance;
+ *
+ * DesiredAccess
+ *  Specifies the desired access to the section can be a
+ *  combination of:
+ *   STANDARD_RIGHTS_REQUIRED |
+ *   SECTION_QUERY   |
+ *   SECTION_MAP_WRITE  |
+ *   SECTION_MAP_READ  |
+ *   SECTION_MAP_EXECUTE
+ *
+ * ObjectAttributes [OPTIONAL]
+ *  Initialized attributes for the object can be used
+ *  to create a named section;
+ *
+ * MaximumSize
+ *  Maximizes the size of the memory section. Must be
+ *  non-NULL for a page-file backed section.
+ *  If value specified for a mapped file and the file is
+ *  not large enough, file will be extended.
+ *
+ * SectionPageProtection
+ *  Can be a combination of:
+ *   PAGE_READONLY |
+ *   PAGE_READWRITE |
+ *   PAGE_WRITEONLY |
+ *   PAGE_WRITECOPY
+ *
+ * AllocationAttributes
+ *  Can be a combination of:
+ *   SEC_IMAGE |
+ *   SEC_RESERVE
+ *
+ * FileHandle
+ *  Handle to a file to create a section mapped to a file
+ *  instead of a memory backed section;
  *
- *     MaximumSize
- *             Maximizes the size of the memory section. Must be 
- *             non-NULL for a page-file backed section. 
- *             If value specified for a mapped file and the file is 
- *             not large enough, file will be extended.
- *             
- *     SectionPageProtection
- *             Can be a combination of:
- *                     PAGE_READONLY   | 
- *                     PAGE_READWRITE  |
- *                     PAGE_WRITEONLY  | 
- *                     PAGE_WRITECOPY
- *                     
- *     AllocationAttributes
- *             Can be a combination of:
- *                     SEC_IMAGE       | 
- *                     SEC_RESERVE
- *                     
- *     FileHandle
- *             Handle to a file to create a section mapped to a file
- *             instead of a memory backed section;
+ * File
+ *  Unknown.
  *
- *     File
- *             Unknown.
- *     
  * RETURN VALUE
- *     Status.
+ *  Status.
  *
- * @unimplemented
+ * @implemented
  */
 NTSTATUS STDCALL
-MmCreateSection (OUT   PSECTION_OBJECT         * SectionObject,
-                IN     ACCESS_MASK             DesiredAccess,
-                IN     POBJECT_ATTRIBUTES      ObjectAttributes     OPTIONAL,
-                IN     PLARGE_INTEGER          MaximumSize,
-                IN     ULONG                   SectionPageProtection,
-                IN     ULONG                   AllocationAttributes,
-                IN     HANDLE                  FileHandle        OPTIONAL,
-                IN     PFILE_OBJECT            File                OPTIONAL)
+MmCreateSection (OUT PSECTION_OBJECT  * SectionObject,
+                 IN ACCESS_MASK  DesiredAccess,
+                 IN POBJECT_ATTRIBUTES ObjectAttributes     OPTIONAL,
+                 IN PLARGE_INTEGER  MaximumSize,
+                 IN ULONG   SectionPageProtection,
+                 IN ULONG   AllocationAttributes,
+                 IN HANDLE   FileHandle   OPTIONAL,
+                 IN PFILE_OBJECT  File      OPTIONAL)
 {
-  return (STATUS_NOT_IMPLEMENTED);
+   if (AllocationAttributes & SEC_IMAGE)
+   {
+      return(MmCreateImageSection(SectionObject,
+                                  DesiredAccess,
+                                  ObjectAttributes,
+                                  MaximumSize,
+                                  SectionPageProtection,
+                                  AllocationAttributes,
+                                  FileHandle));
+   }
+
+   if (FileHandle != NULL)
+   {
+      return(MmCreateDataFileSection(SectionObject,
+                                     DesiredAccess,
+                                     ObjectAttributes,
+                                     MaximumSize,
+                                     SectionPageProtection,
+                                     AllocationAttributes,
+                                     FileHandle));
+   }
+
+   return(MmCreatePageFileSection(SectionObject,
+                                  DesiredAccess,
+                                  ObjectAttributes,
+                                  MaximumSize,
+                                  SectionPageProtection,
+                                  AllocationAttributes));
 }
 
 /* EOF */