update for HEAD-2003091401
[reactos.git] / ntoskrnl / mm / section.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$
20  *
21  * PROJECT:         ReactOS kernel
22  * FILE:            ntoskrnl/mm/section.c
23  * PURPOSE:         Implements section objects
24  * PROGRAMMER:      David Welch (welch@mcmail.com)
25  * UPDATE HISTORY:
26  *                  Created 22/05/98
27  */
28
29 /* INCLUDES *****************************************************************/
30
31 #include <limits.h>
32 #define NTOS_MODE_KERNEL
33 #include <ntos.h>
34 #include <internal/mm.h>
35 #include <internal/io.h>
36 #include <internal/ps.h>
37 #include <internal/pool.h>
38 #include <internal/cc.h>
39 #include <ddk/ntifs.h>
40 #include <ntos/minmax.h>
41
42 #define NDEBUG
43 #include <internal/debug.h>
44
45 /* TYPES *********************************************************************/
46
47 typedef struct
48 {
49   PSECTION_OBJECT Section;
50   PMM_SECTION_SEGMENT Segment;
51   ULONG Offset;
52   BOOLEAN WasDirty;
53   BOOLEAN Private;
54 } MM_SECTION_PAGEOUT_CONTEXT;
55
56 /* GLOBALS *******************************************************************/
57
58 POBJECT_TYPE EXPORTED MmSectionObjectType = NULL;
59
60 static GENERIC_MAPPING MmpSectionMapping = {
61         STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
62         STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
63         STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
64         SECTION_ALL_ACCESS};
65
66 #define TAG_MM_SECTION_SEGMENT   TAG('M', 'M', 'S', 'S')
67 #define TAG_SECTION_PAGE_TABLE   TAG('M', 'S', 'P', 'T')
68
69 #define PAGE_FROM_SSE(E)         ((E) & 0xFFFFF000)
70 #define SHARE_COUNT_FROM_SSE(E)  (((E) & 0x00000FFE) >> 1)
71 #define IS_SWAP_FROM_SSE(E)      ((E) & 0x00000001)
72 #define MAX_SHARE_COUNT          0x7FF
73 #define MAKE_SSE(P, C)           ((P) | ((C) << 1))
74 #define SWAPENTRY_FROM_SSE(E)    ((E) >> 1)
75 #define MAKE_SWAP_SSE(S)         (((S) << 1) | 0x1)
76
77 /* FUNCTIONS *****************************************************************/
78
79 VOID
80 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment)
81 {
82   ULONG i;
83   if (Segment->Length > NR_SECTION_PAGE_TABLES * PAGE_SIZE)
84     {
85       for (i = 0; i < NR_SECTION_PAGE_TABLES; i++)
86         {
87           if (Segment->PageDirectory.PageTables[i] != NULL)
88             {
89               ExFreePool(Segment->PageDirectory.PageTables[i]);
90             }
91         }
92     }
93 }
94
95 VOID
96 MmFreeSectionSegments(PFILE_OBJECT FileObject)
97 {
98   if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
99     {
100       PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
101       PMM_SECTION_SEGMENT SectionSegments;
102       ULONG NrSegments;
103       ULONG i;
104
105       ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject;
106       NrSegments = ImageSectionObject->NrSegments;
107       SectionSegments = ImageSectionObject->Segments;
108       for (i = 0; i < NrSegments; i++)
109         {
110           if (SectionSegments[i].ReferenceCount != 0)
111             {
112               DPRINT1("Image segment %d still referenced (was %d)\n", i,
113                       SectionSegments[i].ReferenceCount);
114               KEBUGCHECK(0);
115             }
116           MmFreePageTablesSectionSegment(&SectionSegments[i]);
117         }
118       ExFreePool(ImageSectionObject);
119       FileObject->SectionObjectPointer->ImageSectionObject = NULL;
120     }
121   if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
122     {
123       PMM_SECTION_SEGMENT Segment;
124
125       Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
126         DataSectionObject;
127
128       if (Segment->ReferenceCount != 0)
129         {
130           DPRINT1("Data segment still referenced\n");
131           KEBUGCHECK(0);
132         }
133       MmFreePageTablesSectionSegment(Segment);
134       ExFreePool(Segment);
135       FileObject->SectionObjectPointer->DataSectionObject = NULL;
136     }
137 }
138
139 VOID 
140 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment)
141 {
142    ExAcquireFastMutex(&Segment->Lock);
143 }
144
145 VOID
146 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment)
147 {
148    ExReleaseFastMutex(&Segment->Lock);
149 }
150
151 VOID 
152 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
153                              ULONG Offset,
154                              ULONG Entry)
155 {
156    PSECTION_PAGE_TABLE Table;
157    ULONG DirectoryOffset;
158    ULONG TableOffset;
159
160    if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
161      {
162        Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
163      }
164    else
165      {
166        DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
167        Table = Segment->PageDirectory.PageTables[DirectoryOffset];
168        if (Table == NULL)
169          {
170            Table = 
171             Segment->PageDirectory.PageTables[DirectoryOffset] =
172              ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_PAGE_TABLE),
173                                    TAG_SECTION_PAGE_TABLE);
174            if (Table == NULL)
175              {
176                KEBUGCHECK(0);
177              }
178            memset(Table, 0, sizeof(SECTION_PAGE_TABLE));
179            DPRINT("Table %x\n", Table);
180          }
181      }
182    TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
183    Table->Entry[TableOffset] = Entry;
184 }
185
186
187 ULONG 
188 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
189                              ULONG Offset)
190 {
191    PSECTION_PAGE_TABLE Table;
192    ULONG Entry;
193    ULONG DirectoryOffset;
194    ULONG TableOffset;
195    
196    DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset);
197    
198    if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
199      {
200        Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
201      }
202    else
203      {
204        DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
205        Table = Segment->PageDirectory.PageTables[DirectoryOffset];
206        DPRINT("Table %x\n", Table);
207        if (Table == NULL)
208          {
209            return(0);
210          }
211      }
212    TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
213    Entry = Table->Entry[TableOffset];
214    return(Entry);
215 }
216
217 VOID
218 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
219                                ULONG Offset)
220 {
221   ULONG Entry;
222
223   Entry = MmGetPageEntrySectionSegment(Segment, Offset);
224   if (Entry == 0)
225     {
226       DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
227       KEBUGCHECK(0);
228     }
229   if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
230     {
231       DPRINT1("Maximum share count reached\n");
232       KEBUGCHECK(0);
233     }
234   if (IS_SWAP_FROM_SSE(Entry))
235     {
236       KEBUGCHECK(0);
237     }
238   Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1);
239   MmSetPageEntrySectionSegment(Segment, Offset, Entry);
240 }
241
242 BOOLEAN
243 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
244                                  PMM_SECTION_SEGMENT Segment,
245                                  ULONG Offset,
246                                  BOOLEAN Dirty)
247 {
248   ULONG Entry;
249
250   Entry = MmGetPageEntrySectionSegment(Segment, Offset);
251   if (Entry == 0)
252     {
253       DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
254       KEBUGCHECK(0);
255     }
256   if (SHARE_COUNT_FROM_SSE(Entry) == 0)
257     {
258       DPRINT1("Zero share count for unshare\n");
259       KEBUGCHECK(0);
260     }
261   if (IS_SWAP_FROM_SSE(Entry))
262     {
263       KEBUGCHECK(0);
264     }
265   Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1);
266   /*
267    * If we reducing the share count of this entry to zero then set the entry 
268    * to zero and tell the cache the page is no longer mapped.
269    */
270   if (SHARE_COUNT_FROM_SSE(Entry) == 0)
271     {
272       PFILE_OBJECT FileObject;
273       PBCB Bcb;
274       SWAPENTRY SavedSwapEntry;
275       PHYSICAL_ADDRESS Page;
276       BOOLEAN IsImageSection;
277       ULONG FileOffset;
278
279       FileOffset = Offset + Segment->FileOffset;
280    
281       IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
282     
283       Page = (PHYSICAL_ADDRESS)(LONGLONG)PAGE_FROM_SSE(Entry);
284       FileObject = Section->FileObject;
285       if (FileObject != NULL)
286         {
287
288           if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
289               (FileOffset % PAGE_SIZE) == 0 &&
290               (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
291             {
292               NTSTATUS Status;
293               Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
294               Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty);
295               if (!NT_SUCCESS(Status))
296                 {
297                   DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
298                   KEBUGCHECK(0);
299                 }
300             }
301         }
302
303       SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
304       if (SavedSwapEntry == 0)
305         {
306           if (Segment->Flags & MM_PAGEFILE_SEGMENT)
307             {
308               /* 
309                * FIXME:
310                *   Try to page out this page and set the swap entry 
311                *   within the section segment. There exist no rmap entry
312                *   for this page. The pager thread can't page out a 
313                *   page without a rmap entry.
314                */
315               MmSetPageEntrySectionSegment(Segment, Offset, Entry);
316               MmReferencePage(Page);
317             }
318           else
319             {
320               MmSetPageEntrySectionSegment(Segment, Offset, 0);
321             }
322         }
323       else
324         {
325           MmSetSavedSwapEntryPage(Page, 0);
326           if (Segment->Flags & MM_PAGEFILE_SEGMENT)
327             {
328               MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry));
329             }
330           else
331             {
332               MmSetPageEntrySectionSegment(Segment, Offset, 0);
333               MmFreeSwapPage(SavedSwapEntry);
334             }
335         }
336     }
337   else
338     {
339       MmSetPageEntrySectionSegment(Segment, Offset, Entry);
340     }
341   return(SHARE_COUNT_FROM_SSE(Entry) > 0);
342 }
343
344 BOOL MiIsPageFromCache(PMEMORY_AREA MemoryArea,
345                        ULONG SegOffset)
346 {
347   PBCB Bcb;
348   PCACHE_SEGMENT CacheSeg;
349
350   Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap;
351   CacheSeg = CcRosLookupCacheSegment(Bcb, SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset);
352   if (CacheSeg)
353   {
354      CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE);
355      return TRUE;
356   }
357   return FALSE;
358 }
359
360 NTSTATUS
361 MiReadPage(PMEMORY_AREA MemoryArea,
362            ULONG SegOffset,
363            PHYSICAL_ADDRESS* Page)
364      /*
365       * FUNCTION: Read a page for a section backed memory area.
366       * PARAMETERS:
367       *       MemoryArea - Memory area to read the page for.
368       *       Offset - Offset of the page to read.
369       *       Page - Variable that receives a page contains the read data.
370       */
371 {
372   ULONG BaseOffset;
373   ULONG FileOffset;
374   PVOID BaseAddress;
375   BOOLEAN UptoDate;
376   PCACHE_SEGMENT CacheSeg;
377   PFILE_OBJECT FileObject;
378   NTSTATUS Status;
379   ULONG RawLength;
380   PBCB Bcb;
381   BOOLEAN IsImageSection;
382   ULONG Length;
383  
384   FileObject = MemoryArea->Data.SectionData.Section->FileObject;
385   Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
386   RawLength = MemoryArea->Data.SectionData.Segment->RawLength;
387   FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset;
388   IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
389   
390   assert(Bcb);
391
392   DPRINT("%S %x\n", FileObject->FileName.Buffer, FileOffset);
393
394   /*
395    * If the file system is letting us go directly to the cache and the
396    * memory area was mapped at an offset in the file which is page aligned
397    * then get the related cache segment.
398    */
399   if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
400       (FileOffset % PAGE_SIZE) == 0 &&
401       (SegOffset + PAGE_SIZE <= RawLength || !IsImageSection))
402     {
403       PHYSICAL_ADDRESS Addr;
404
405       /*
406        * Get the related cache segment; we use a lower level interface than
407        * filesystems do because it is safe for us to use an offset with a
408        * alignment less than the file system block size.
409        */
410       Status = CcRosGetCacheSegment(Bcb,
411                                     FileOffset,
412                                     &BaseOffset,
413                                     &BaseAddress,
414                                     &UptoDate,
415                                     &CacheSeg);
416       if (!NT_SUCCESS(Status))
417         {
418           return(Status);
419         }
420       if (!UptoDate)
421         {
422           /*
423            * If the cache segment isn't up to date then call the file
424            * system to read in the data.
425            */
426           Status = ReadCacheSegment(CacheSeg);
427           if (!NT_SUCCESS(Status))
428           {
429               CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
430               return Status;
431           }
432         }
433       /*
434        * Retrieve the page from the cache segment that we actually want.
435        */
436       Addr = MmGetPhysicalAddress(BaseAddress +
437                                   FileOffset - BaseOffset);
438       (*Page) = Addr;
439       MmReferencePage((*Page));
440
441       CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, TRUE);
442     }
443   else
444     {
445       PVOID PageAddr;
446       ULONG CacheSegOffset;
447       /*
448        * Allocate a page, this is rather complicated by the possibility
449        * we might have to move other things out of memory
450        */
451       Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
452       if (!NT_SUCCESS(Status))
453         {
454           return(Status);
455         }
456       Status = CcRosGetCacheSegment(Bcb,
457                                     FileOffset,
458                                     &BaseOffset,
459                                     &BaseAddress,
460                                     &UptoDate,
461                                     &CacheSeg);
462       if (!NT_SUCCESS(Status))
463         {
464           return(Status);
465         }
466       if (!UptoDate)
467         {
468           /*
469            * If the cache segment isn't up to date then call the file
470            * system to read in the data.
471            */
472           Status = ReadCacheSegment(CacheSeg);
473           if (!NT_SUCCESS(Status))
474           {
475               CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
476               return Status;
477           }
478         }
479       PageAddr = ExAllocatePageWithPhysPage(*Page);
480       CacheSegOffset = BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset;
481       Length = RawLength - SegOffset;
482       if (Length <= CacheSegOffset && Length <= PAGE_SIZE)
483       {
484          memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, Length);
485       }
486       else if (CacheSegOffset >= PAGE_SIZE)
487       {
488          memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, PAGE_SIZE);
489       }
490       else
491       {
492          memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, CacheSegOffset);
493          CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
494          Status = CcRosGetCacheSegment(Bcb,
495                                        FileOffset + CacheSegOffset,
496                                        &BaseOffset,
497                                        &BaseAddress,
498                                        &UptoDate,
499                                        &CacheSeg);
500          if (!NT_SUCCESS(Status))
501            {
502              ExUnmapPage(PageAddr);
503              return(Status);
504            }
505          if (!UptoDate)
506            {
507              /*
508               * If the cache segment isn't up to date then call the file
509               * system to read in the data.
510               */
511              Status = ReadCacheSegment(CacheSeg);
512              if (!NT_SUCCESS(Status))
513                {
514                  CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
515                  ExUnmapPage(PageAddr);
516                  return Status;
517                }
518            }
519          if (Length < PAGE_SIZE)
520          {
521             memcpy(PageAddr + CacheSegOffset, BaseAddress, Length - CacheSegOffset);
522          }
523          else
524          {
525             memcpy(PageAddr + CacheSegOffset, BaseAddress, PAGE_SIZE - CacheSegOffset);
526          }
527       }
528       CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
529       ExUnmapPage(PageAddr);
530     }
531   return(STATUS_SUCCESS);
532 }
533
534 NTSTATUS
535 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
536                              MEMORY_AREA* MemoryArea,
537                              PVOID Address,
538                              BOOLEAN Locked)
539 {
540    ULONG Offset;
541    LARGE_INTEGER Page;
542    NTSTATUS Status;
543    ULONG PAddress;
544    PSECTION_OBJECT Section;
545    PMM_SECTION_SEGMENT Segment;
546    ULONG Entry;
547    ULONG Entry1;
548    ULONG Attributes;
549    PMM_PAGEOP PageOp;
550    PMM_REGION Region;
551    LARGE_INTEGER Timeout;
552
553    /*
554     * There is a window between taking the page fault and locking the
555     * address space when another thread could load the page so we check
556     * that.
557     */
558    if (MmIsPagePresent(AddressSpace->Process, Address))
559      {
560         if (Locked)
561           {
562             MmLockPage(MmGetPhysicalAddressForProcess(AddressSpace->Process, Address));
563           }  
564         return(STATUS_SUCCESS);
565      }
566    
567    PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
568    Offset = PAddress - (ULONG)MemoryArea->BaseAddress;
569    
570    Segment = MemoryArea->Data.SectionData.Segment;
571    Section = MemoryArea->Data.SectionData.Section;
572    Region = MmFindRegion(MemoryArea->BaseAddress,
573                          &MemoryArea->Data.SectionData.RegionListHead, 
574                          Address, NULL);
575    /*
576     * Lock the segment
577     */
578    MmLockSectionSegment(Segment);
579
580    /*
581     * Check if this page needs to be mapped COW
582     */
583    if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
584        (Region->Protect == PAGE_READWRITE ||
585         Region->Protect == PAGE_EXECUTE_READWRITE))
586      {
587        Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
588      }
589    else
590      {
591        Attributes = Region->Protect;
592      }
593    
594    /*
595     * Get or create a page operation descriptor
596     */
597    PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset, MM_PAGEOP_PAGEIN);
598    if (PageOp == NULL)
599      {
600        DPRINT1("MmGetPageOp failed\n");
601        KEBUGCHECK(0);
602      }
603
604    /*
605     * Check if someone else is already handling this fault, if so wait
606     * for them
607     */
608    if (PageOp->Thread != PsGetCurrentThread())
609      {
610        MmUnlockSectionSegment(Segment);
611        MmUnlockAddressSpace(AddressSpace);
612        Timeout.QuadPart = -100000000LL; // 10 sec
613        Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
614                                       0,
615                                       KernelMode,
616                                       FALSE,
617                                       &Timeout);
618
619        /*
620         * Check for various strange conditions
621         */
622        if (Status != STATUS_SUCCESS)
623          {
624            DPRINT1("Failed to wait for page op, status = %x\n", Status);
625            KEBUGCHECK(0);
626          }
627        if (PageOp->Status == STATUS_PENDING)
628          {
629            DPRINT1("Woke for page op before completion\n");
630            KEBUGCHECK(0);
631          }
632        MmLockAddressSpace(AddressSpace);
633        /*
634         * If this wasn't a pagein then restart the operation
635         */
636        if (PageOp->OpType != MM_PAGEOP_PAGEIN)
637          {
638            KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
639            MmReleasePageOp(PageOp);
640            DPRINT("Address 0x%.8X\n", Address);
641            return(STATUS_MM_RESTART_OPERATION);
642          }
643        
644        /*
645         * If the thread handling this fault has failed then we don't retry
646         */
647        if (!NT_SUCCESS(PageOp->Status))
648          {
649            Status = PageOp->Status;
650            KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
651            MmReleasePageOp(PageOp);
652            DPRINT("Address 0x%.8X\n", Address);
653            return(Status);
654          }
655        MmLockSectionSegment(Segment);
656        /*
657         * If the completed fault was for another address space then set the 
658         * page in this one.
659         */
660        if (!MmIsPagePresent(AddressSpace->Process, Address))
661          {
662            Entry = MmGetPageEntrySectionSegment(Segment, Offset);
663            if (Entry == 0)
664            {
665                 MmUnlockSectionSegment(Segment);
666                 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
667                 MmReleasePageOp(PageOp);
668                 return(STATUS_MM_RESTART_OPERATION);
669            } 
670
671            Page = (LARGE_INTEGER)(LONGLONG)(PAGE_FROM_SSE(Entry));
672            MmReferencePage(Page);       
673            MmSharePageEntrySectionSegment(Segment, Offset);
674
675            Status = MmCreateVirtualMapping(MemoryArea->Process,
676                                            Address,
677                                            Attributes,
678                                            Page,
679                                            FALSE);
680            if (Status == STATUS_NO_MEMORY)
681              {
682                MmUnlockAddressSpace(AddressSpace);
683                Status = MmCreateVirtualMapping(MemoryArea->Process,
684                                                Address,
685                                                Attributes,
686                                                Page,
687                                                TRUE);
688                MmLockAddressSpace(AddressSpace);
689              }
690
691            if (!NT_SUCCESS(Status))
692              {
693                DbgPrint("Unable to create virtual mapping\n");
694                KEBUGCHECK(0);
695              }
696            MmInsertRmap(Page, MemoryArea->Process, (PVOID)PAddress);
697          }
698        if (Locked)
699          {
700            MmLockPage(Page);
701          }
702        MmUnlockSectionSegment(Segment);
703        PageOp->Status = STATUS_SUCCESS;
704        KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
705        MmReleasePageOp(PageOp);
706        DPRINT("Address 0x%.8X\n", Address);
707        return(STATUS_SUCCESS);
708      }
709
710    /*
711     * Must be private page we have swapped out.
712     */
713    if (MmIsPageSwapEntry(AddressSpace->Process, (PVOID)PAddress))
714      {
715        SWAPENTRY SwapEntry;
716        PMDL Mdl;
717
718        /*
719         * Sanity check
720         */
721        if (Segment->Flags & MM_PAGEFILE_SEGMENT)
722          {
723            DPRINT1("Found a swaped out private page in a pagefile section.\n");
724            KEBUGCHECK(0);
725          }
726
727        MmUnlockSectionSegment(Segment);
728        MmDeletePageFileMapping(AddressSpace->Process, (PVOID)PAddress, &SwapEntry);
729
730        MmUnlockAddressSpace(AddressSpace);
731        Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
732        if (!NT_SUCCESS(Status))
733          {
734            KEBUGCHECK(0);
735          }
736
737        Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
738        MmBuildMdlFromPages(Mdl, (PULONG)&Page);
739        Status = MmReadFromSwapPage(SwapEntry, Mdl);
740        if (!NT_SUCCESS(Status))
741          {
742            DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
743            KEBUGCHECK(0);
744          }
745        MmLockAddressSpace(AddressSpace);
746        Status = MmCreateVirtualMapping(AddressSpace->Process,                 
747                                        Address,
748                                        Region->Protect,
749                                        Page,
750                                        FALSE);
751        if (Status == STATUS_NO_MEMORY)
752          {
753            MmUnlockAddressSpace(AddressSpace);     
754            Status = MmCreateVirtualMapping(AddressSpace->Process,
755                                            Address,
756                                            Region->Protect,
757                                            Page,
758                                            TRUE);
759            MmLockAddressSpace(AddressSpace);
760          }  
761        if (!NT_SUCCESS(Status))
762          {
763            DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
764            KEBUGCHECK(0);
765            return(Status);
766          }
767
768        /*
769         * Store the swap entry for later use.
770         */
771        MmSetSavedSwapEntryPage(Page, SwapEntry);
772        
773        /*
774         * Add the page to the process's working set
775         */
776        MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
777        
778        /*
779         * Finish the operation
780         */
781        if (Locked)
782          {
783            MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
784          }  
785        PageOp->Status = STATUS_SUCCESS;
786        KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
787        MmReleasePageOp(PageOp);
788        DPRINT("Address 0x%.8X\n", Address);
789        return(STATUS_SUCCESS);
790      }
791
792    /*
793     * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
794     */
795    if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
796      {
797        MmUnlockSectionSegment(Segment);
798        /*
799         * Just map the desired physical page 
800         */
801        Page.QuadPart = Offset + MemoryArea->Data.SectionData.ViewOffset;
802        Status = MmCreateVirtualMapping(AddressSpace->Process,
803                                        Address,
804                                        Region->Protect,
805                                        Page,
806                                        FALSE);
807        if (Status == STATUS_NO_MEMORY)
808          {
809            MmUnlockAddressSpace(AddressSpace);     
810            Status = MmCreateVirtualMapping(AddressSpace->Process,
811                                            Address,
812                                            Region->Protect,
813                                            Page,
814                                            TRUE);
815            MmLockAddressSpace(AddressSpace);
816          }  
817        if (!NT_SUCCESS(Status))
818          {
819            DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
820            KEBUGCHECK(0);
821            return(Status);
822          }
823        /* 
824         * Don't add an rmap entry since the page mapped could be for 
825         * anything. 
826         */
827        if (Locked)
828          {
829            MmLockPage(Page);
830          }  
831
832        /*
833         * Cleanup and release locks
834         */
835        PageOp->Status = STATUS_SUCCESS;
836        KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
837        MmReleasePageOp(PageOp);
838        DPRINT("Address 0x%.8X\n", Address);
839        return(STATUS_SUCCESS);
840      }
841    
842    /*
843     * Map anonymous memory for BSS sections
844     */
845    if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS)
846      {
847        MmUnlockSectionSegment(Segment);
848        Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
849        if (!NT_SUCCESS(Status))
850          {
851            MmUnlockAddressSpace(AddressSpace);     
852            Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
853            MmLockAddressSpace(AddressSpace);
854          }
855        if (!NT_SUCCESS(Status))
856          {
857            KEBUGCHECK(0);
858          }
859        Status = MmCreateVirtualMapping(AddressSpace->Process,
860                                        Address,
861                                        Region->Protect,
862                                        Page,
863                                        FALSE);
864        if (Status == STATUS_NO_MEMORY)
865          {
866            MmUnlockAddressSpace(AddressSpace);     
867            Status = MmCreateVirtualMapping(AddressSpace->Process,
868                                            Address,
869                                            Region->Protect,
870                                            Page,
871                                            TRUE);
872            MmLockAddressSpace(AddressSpace);
873          }  
874
875        if (!NT_SUCCESS(Status))
876          {
877            DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
878            KEBUGCHECK(0);
879            return(Status);
880          }
881        MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
882        if (Locked)
883          {
884            MmLockPage(Page);
885          }  
886
887        /*
888         * Cleanup and release locks
889         */
890        PageOp->Status = STATUS_SUCCESS;
891        KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
892        MmReleasePageOp(PageOp);
893        DPRINT("Address 0x%.8X\n", Address);
894        return(STATUS_SUCCESS);
895      }
896
897    /*
898     * Get the entry corresponding to the offset within the section
899     */
900    Entry = MmGetPageEntrySectionSegment(Segment, Offset);
901    
902    if (Entry == 0)
903      {   
904        /*
905         * If the entry is zero (and it can't change because we have
906         * locked the segment) then we need to load the page.
907         */
908
909        /*
910         * Release all our locks and read in the page from disk
911         */
912        MmUnlockSectionSegment(Segment);
913        MmUnlockAddressSpace(AddressSpace);
914
915        if ((Segment->Flags & MM_PAGEFILE_SEGMENT) || 
916            (Offset >= PAGE_ROUND_UP(Segment->RawLength) && Section->AllocationAttributes & SEC_IMAGE))
917          {
918            Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
919            if (!NT_SUCCESS(Status))
920              {
921                DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
922              }
923          }
924        else
925          {
926            Status = MiReadPage(MemoryArea, Offset, &Page);
927            if (!NT_SUCCESS(Status))
928              {
929                DPRINT1("MiReadPage failed (Status %x)\n", Status);
930              }
931          }
932        if (!NT_SUCCESS(Status))
933          {
934            /*
935             * FIXME: What do we know in this case?
936             */
937            /*
938             * Cleanup and release locks
939             */
940            MmLockAddressSpace(AddressSpace);
941            PageOp->Status = Status;
942            KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
943            MmReleasePageOp(PageOp);
944            DPRINT("Address 0x%.8X\n", Address);
945            return(Status);
946          }
947        /*
948         * Relock the address space and segment
949         */
950        MmLockAddressSpace(AddressSpace);
951        MmLockSectionSegment(Segment);
952        
953        /*
954         * Check the entry. No one should change the status of a page
955         * that has a pending page-in.
956         */
957        Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
958        if (Entry != Entry1)
959          {
960            DbgPrint("Someone changed ppte entry while we slept\n");
961            KEBUGCHECK(0);
962          }
963        
964        /*
965         * Mark the offset within the section as having valid, in-memory
966         * data
967         */
968        Entry = MAKE_SSE(Page.u.LowPart, 1);
969        MmSetPageEntrySectionSegment(Segment, Offset, Entry);
970        MmUnlockSectionSegment(Segment);
971
972        Status = MmCreateVirtualMapping(AddressSpace->Process,
973                                        Address,
974                                        Attributes,
975                                        Page,
976                                        FALSE);
977        if (Status == STATUS_NO_MEMORY)
978          {
979            MmUnlockAddressSpace(AddressSpace);
980            Status = MmCreateVirtualMapping(AddressSpace->Process,
981                                            Address,
982                                            Attributes,
983                                            Page,
984                                            TRUE);
985            MmLockAddressSpace(AddressSpace);
986          }
987        if (!NT_SUCCESS(Status))
988          {
989            DbgPrint("Unable to create virtual mapping\n");
990            KEBUGCHECK(0);
991          }
992        MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
993
994        if (Locked)
995          {
996            MmLockPage(Page);
997          }  
998        PageOp->Status = STATUS_SUCCESS;
999        KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1000        MmReleasePageOp(PageOp);
1001        DPRINT("Address 0x%.8X\n", Address);
1002        return(STATUS_SUCCESS);
1003      }
1004    else if (IS_SWAP_FROM_SSE(Entry))
1005      {
1006        SWAPENTRY SwapEntry;
1007        PMDL Mdl;
1008
1009        SwapEntry = SWAPENTRY_FROM_SSE(Entry);
1010
1011        /*
1012         * Release all our locks and read in the page from disk
1013         */
1014        MmUnlockSectionSegment(Segment);
1015
1016        MmUnlockAddressSpace(AddressSpace);
1017         
1018        Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1019        if (!NT_SUCCESS(Status))
1020          {
1021            KEBUGCHECK(0);
1022          }
1023
1024        Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
1025        MmBuildMdlFromPages(Mdl, (PULONG)&Page);
1026        Status = MmReadFromSwapPage(SwapEntry, Mdl);
1027        if (!NT_SUCCESS(Status))
1028          {
1029            KEBUGCHECK(0);
1030          }
1031
1032        /*
1033         * Relock the address space and segment
1034         */
1035        MmLockAddressSpace(AddressSpace);
1036        MmLockSectionSegment(Segment);
1037        
1038        /*
1039         * Check the entry. No one should change the status of a page
1040         * that has a pending page-in.
1041         */
1042        Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
1043        if (Entry != Entry1)
1044          {
1045            DbgPrint("Someone changed ppte entry while we slept\n");
1046            KEBUGCHECK(0);
1047          }
1048        
1049        /*
1050         * Mark the offset within the section as having valid, in-memory
1051         * data
1052         */
1053        Entry = MAKE_SSE(Page.u.LowPart, 1);
1054        MmSetPageEntrySectionSegment(Segment, Offset, Entry);
1055        MmUnlockSectionSegment(Segment);
1056
1057        /*
1058         * Save the swap entry.
1059         */
1060        MmSetSavedSwapEntryPage(Page, SwapEntry);
1061        Status = MmCreateVirtualMapping(AddressSpace->Process,
1062                                        Address,
1063                                        Region->Protect,
1064                                        Page,
1065                                        FALSE);
1066        if (Status == STATUS_NO_MEMORY)
1067          {
1068            MmUnlockAddressSpace(AddressSpace);
1069            Status = MmCreateVirtualMapping(AddressSpace->Process,
1070                                            Address,
1071                                            Region->Protect,
1072                                            Page,
1073                                            TRUE);
1074            MmLockAddressSpace(AddressSpace);
1075          }
1076        if (!NT_SUCCESS(Status))
1077          {
1078            DbgPrint("Unable to create virtual mapping\n");
1079            KEBUGCHECK(0);
1080          }
1081        MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
1082        if (Locked)
1083          {
1084            MmLockPage(Page);
1085          }  
1086        PageOp->Status = STATUS_SUCCESS;
1087        KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1088        MmReleasePageOp(PageOp);
1089        DPRINT("Address 0x%.8X\n", Address);
1090        return(STATUS_SUCCESS);
1091      }
1092    else
1093      {
1094        /*
1095         * If the section offset is already in-memory and valid then just
1096         * take another reference to the page 
1097         */
1098         
1099        Page = (LARGE_INTEGER)(LONGLONG)PAGE_FROM_SSE(Entry);
1100        MmReferencePage(Page);   
1101        MmSharePageEntrySectionSegment(Segment, Offset);
1102        MmUnlockSectionSegment(Segment);
1103
1104        Status = MmCreateVirtualMapping(AddressSpace->Process,
1105                                        Address,
1106                                        Attributes,
1107                                        Page,
1108                                        FALSE);
1109        if (Status == STATUS_NO_MEMORY)
1110          {
1111            MmUnlockAddressSpace(AddressSpace);
1112            Status = MmCreateVirtualMapping(AddressSpace->Process,
1113                                            Address,
1114                                            Attributes,
1115                                            Page,
1116                                            TRUE);
1117            MmLockAddressSpace(AddressSpace);
1118          }
1119        if (!NT_SUCCESS(Status))
1120          {
1121            DbgPrint("Unable to create virtual mapping\n");
1122            KEBUGCHECK(0);
1123          }
1124        MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
1125        if (Locked)
1126          {
1127            MmLockPage(Page);
1128          }  
1129        PageOp->Status = STATUS_SUCCESS;
1130        KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1131        MmReleasePageOp(PageOp);
1132        DPRINT("Address 0x%.8X\n", Address);
1133        return(STATUS_SUCCESS);
1134      }
1135 }
1136
1137 NTSTATUS 
1138 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
1139                          MEMORY_AREA* MemoryArea, 
1140                          PVOID Address,
1141                          BOOLEAN Locked)
1142 {
1143   PMM_SECTION_SEGMENT Segment;
1144   PSECTION_OBJECT Section;
1145   PHYSICAL_ADDRESS OldPage;
1146   PHYSICAL_ADDRESS NewPage;
1147   PVOID NewAddress;
1148   NTSTATUS Status;
1149   ULONG PAddress;
1150   ULONG Offset;
1151   PMM_PAGEOP PageOp;
1152   PMM_REGION Region;
1153   LARGE_INTEGER Timeout;
1154
1155   /*
1156    * Check if the page has been paged out or has already been set readwrite
1157    */
1158    if (!MmIsPagePresent(AddressSpace->Process, Address) ||
1159        MmGetPageProtect(AddressSpace->Process, Address) & PAGE_READWRITE)
1160      {
1161        DPRINT("Address 0x%.8X\n", Address);
1162        return(STATUS_SUCCESS);
1163      }  
1164
1165    /*
1166     * Find the offset of the page
1167     */
1168    PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
1169    Offset = PAddress - (ULONG)MemoryArea->BaseAddress;
1170
1171    Segment = MemoryArea->Data.SectionData.Segment;
1172    Section = MemoryArea->Data.SectionData.Section;
1173    Region = MmFindRegion(MemoryArea->BaseAddress,
1174                          &MemoryArea->Data.SectionData.RegionListHead,
1175                          Address, NULL);
1176    /*
1177     * Lock the segment
1178     */
1179    MmLockSectionSegment(Segment);
1180
1181    /*
1182     * Sanity check.
1183     */
1184    if (MmGetPageEntrySectionSegment(Segment, Offset) == 0)
1185      {
1186        DPRINT1("COW fault for page with PESS 0. Address was 0x%.8X\n",
1187                Address);
1188      }
1189    MmUnlockSectionSegment(Segment);
1190    /*
1191     * Check if we are doing COW
1192     */
1193    if (!((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1194          (Region->Protect == PAGE_READWRITE ||
1195           Region->Protect == PAGE_EXECUTE_READWRITE)))
1196      {
1197        DPRINT("Address 0x%.8X\n", Address);
1198        return(STATUS_UNSUCCESSFUL);
1199      }
1200
1201    /*
1202     * Get or create a pageop
1203     */
1204    PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset,
1205                         MM_PAGEOP_ACCESSFAULT);
1206    if (PageOp == NULL)
1207      {
1208        DPRINT1("MmGetPageOp failed\n");
1209        KEBUGCHECK(0);
1210      }
1211
1212    /*
1213     * Wait for any other operations to complete
1214     */
1215    if (PageOp->Thread != PsGetCurrentThread())
1216      {
1217        MmUnlockAddressSpace(AddressSpace);
1218        Timeout.QuadPart = -100000000LL; // 10 sec
1219        Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
1220                                       0,
1221                                       KernelMode,
1222                                       FALSE,
1223                                       &Timeout);
1224        /*
1225         * Check for various strange conditions
1226         */
1227        if (Status == STATUS_TIMEOUT)
1228          {
1229            DPRINT1("Failed to wait for page op, status = %x\n", Status);
1230            KEBUGCHECK(0);
1231          }
1232        if (PageOp->Status == STATUS_PENDING)
1233          {
1234            DPRINT1("Woke for page op before completion\n");
1235            KEBUGCHECK(0);
1236          }
1237        /*
1238         * Restart the operation
1239         */
1240        MmLockAddressSpace(AddressSpace);
1241        KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1242        MmReleasePageOp(PageOp);
1243        DPRINT("Address 0x%.8X\n", Address);
1244        return(STATUS_MM_RESTART_OPERATION);
1245      }
1246
1247    /*
1248     * Release locks now we have the pageop
1249     */
1250    MmUnlockAddressSpace(AddressSpace);
1251
1252    /*
1253     * Allocate a page
1254     */
1255    Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1256    if (!NT_SUCCESS(Status))
1257    {
1258      KEBUGCHECK(0);
1259    }
1260
1261    /*
1262     * Copy the old page
1263     */
1264    OldPage = MmGetPhysicalAddressForProcess(NULL, Address);
1265  
1266    NewAddress = ExAllocatePageWithPhysPage(NewPage);
1267    memcpy(NewAddress, (PVOID)PAddress, PAGE_SIZE);
1268    ExUnmapPage(NewAddress);
1269
1270    /*
1271     * Delete the old entry.
1272     */
1273    MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
1274
1275    /*
1276     * Set the PTE to point to the new page
1277     */
1278    MmLockAddressSpace(AddressSpace);
1279    Status = MmCreateVirtualMapping(AddressSpace->Process,
1280                                    Address,
1281                                    Region->Protect,
1282                                    NewPage,
1283                                    FALSE);   
1284    if (Status == STATUS_NO_MEMORY)
1285      {
1286        MmUnlockAddressSpace(AddressSpace);         
1287        Status = MmCreateVirtualMapping(AddressSpace->Process,
1288                                        Address,
1289                                        Region->Protect,
1290                                        NewPage,
1291                                        TRUE);
1292        MmLockAddressSpace(AddressSpace);
1293      }  
1294    if (!NT_SUCCESS(Status))
1295      {
1296        DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1297        KEBUGCHECK(0);
1298        return(Status);
1299      }
1300    MmInsertRmap(NewPage, AddressSpace->Process, (PVOID)PAddress);
1301    if (!NT_SUCCESS(Status))
1302      {
1303        DbgPrint("Unable to create virtual mapping\n");
1304        KEBUGCHECK(0);
1305      }
1306    if (Locked)
1307      {
1308        MmLockPage(NewPage);
1309      }  
1310
1311    /*
1312     * Unshare the old page.
1313     */
1314    MmDeleteRmap(OldPage, AddressSpace->Process, (PVOID)PAddress);
1315    MmLockSectionSegment(Segment);
1316    MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE);
1317    MmUnlockSectionSegment(Segment);
1318    MmReleasePageMemoryConsumer(MC_USER, OldPage);
1319
1320    PageOp->Status = STATUS_SUCCESS;
1321    KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1322    MmReleasePageOp(PageOp);
1323    DPRINT("Address 0x%.8X\n", Address);
1324    return(STATUS_SUCCESS);
1325 }
1326
1327 VOID
1328 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
1329 {
1330   MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1331   BOOL WasDirty;
1332   PHYSICAL_ADDRESS Page;
1333
1334   PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1335   MmDeleteVirtualMapping(Process,
1336                          Address,
1337                          FALSE,
1338                          &WasDirty,
1339                          &Page);
1340   if (WasDirty)
1341     {
1342       PageOutContext->WasDirty = TRUE;
1343     }
1344   if (!PageOutContext->Private)
1345     {
1346       MmUnsharePageEntrySectionSegment(PageOutContext->Section,
1347                                        PageOutContext->Segment,
1348                                        PageOutContext->Offset,
1349                                        PageOutContext->WasDirty);
1350     }
1351   MmReleasePageMemoryConsumer(MC_USER, Page);
1352   DPRINT("PhysicalAddress %I64x, Address %x\n", Page, Address);
1353 }
1354
1355 NTSTATUS
1356 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
1357                      MEMORY_AREA* MemoryArea, 
1358                      PVOID Address,
1359                      PMM_PAGEOP PageOp)
1360 {
1361   PHYSICAL_ADDRESS PhysicalAddress;
1362   MM_SECTION_PAGEOUT_CONTEXT Context;
1363   SWAPENTRY SwapEntry;
1364   PMDL Mdl;
1365   ULONG Entry;
1366   ULONG FileOffset;
1367   NTSTATUS Status;
1368   PFILE_OBJECT FileObject;
1369   PBCB Bcb = NULL;
1370   BOOLEAN DirectMapped;
1371   BOOLEAN IsImageSection;
1372
1373   Address = (PVOID)PAGE_ROUND_DOWN(Address);
1374
1375   /*
1376    * Get the segment and section.
1377    */
1378   Context.Segment = MemoryArea->Data.SectionData.Segment;
1379   Context.Section = MemoryArea->Data.SectionData.Section;
1380
1381   Context.Offset = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress);
1382   FileOffset = Context.Offset + Context.Segment->FileOffset;
1383
1384   IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1385
1386   FileObject = Context.Section->FileObject;
1387   DirectMapped = FALSE;
1388   if (FileObject != NULL)
1389     {
1390       Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1391   
1392       /*
1393        * If the file system is letting us go directly to the cache and the
1394        * memory area was mapped at an offset in the file which is page aligned
1395        * then note this is a direct mapped page.
1396        */
1397       if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
1398           (FileOffset % PAGE_SIZE) == 0 &&
1399           (Context.Offset + PAGE_SIZE <= Context.Segment->RawLength || !IsImageSection))
1400         {
1401           DirectMapped = TRUE;
1402         }
1403     }
1404    
1405
1406   /*
1407    * This should never happen since mappings of physical memory are never
1408    * placed in the rmap lists.
1409    */
1410   if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1411     {
1412       DPRINT1("Trying to page out from physical memory section address 0x%X "
1413               "process %d\n", Address, 
1414               AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
1415       KEBUGCHECK(0);
1416     }
1417
1418   /*
1419    * Get the section segment entry and the physical address.
1420    */
1421   Entry = MmGetPageEntrySectionSegment(Context.Segment, Context.Offset);
1422   if (!MmIsPagePresent(AddressSpace->Process, Address))
1423     {
1424       DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1425           AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
1426       KEBUGCHECK(0);
1427     }
1428   PhysicalAddress = 
1429     MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1430   SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1431
1432   /*
1433    * Prepare the context structure for the rmap delete call.
1434    */
1435   Context.WasDirty = FALSE;
1436   if (Context.Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1437       IS_SWAP_FROM_SSE(Entry) || 
1438       (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart)
1439     {
1440       Context.Private = TRUE;
1441     }
1442   else
1443     {
1444       Context.Private = FALSE;
1445     }
1446
1447   /*
1448    * Paging out data mapped read-only is easy.
1449    */
1450   if (Context.Segment->Protection & (PAGE_READONLY|PAGE_EXECUTE_READ))
1451     {
1452       /*
1453        * Read-only data should never be in the swapfile.
1454        */
1455       if (SwapEntry != 0)
1456         {
1457           DPRINT1("SwapEntry != 0 was 0x%.8X at address 0x%.8X, "
1458                   "paddress 0x%.8X\n", SwapEntry, Address, 
1459                   PhysicalAddress);
1460           KEBUGCHECK(0);
1461         }
1462
1463       /*
1464        * Read-only data should never be COWed
1465        */
1466       if (Context.Private)
1467         {
1468           DPRINT1("Had private copy of read-only page.\n");
1469           KEBUGCHECK(0);
1470         }
1471       
1472       /*
1473        * Delete all mappings of this page.
1474        */
1475       MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context, 
1476                        MmPageOutDeleteMapping);
1477       if (Context.WasDirty)
1478         {
1479           DPRINT1("Had a dirty page of a read-only page.\n");
1480           KEBUGCHECK(0);
1481         }
1482
1483       PageOp->Status = STATUS_SUCCESS;
1484       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1485       MmReleasePageOp(PageOp);
1486       return(STATUS_SUCCESS);
1487     }
1488
1489   /*
1490    * Otherwise we have read-write data.
1491    */
1492
1493   /*
1494    * Take an additional reference to the page or the cache segment.
1495    */
1496   if (DirectMapped && !Context.Private)
1497     {
1498       if(!MiIsPageFromCache(MemoryArea, Context.Offset))
1499         {
1500           DPRINT1("Direct mapped non private page is not associated with the cache.\n")
1501           KEBUGCHECK(0);
1502         }
1503     }
1504   else
1505     {
1506       MmReferencePage(PhysicalAddress);
1507     }
1508
1509   MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context, MmPageOutDeleteMapping);
1510   
1511   /*
1512    * If this wasn't a private page then we should have reduced the entry to
1513    * zero by deleting all the rmaps.
1514    */
1515   if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0)
1516     {
1517       if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT))
1518         {
1519           CHECKPOINT1;
1520           KEBUGCHECK(0);
1521         }
1522     }
1523
1524   /*
1525    * If the page wasn't dirty then we can just free it as for a readonly page.
1526    * Since we unmapped all the mappings above we know it will not suddenly
1527    * become dirty. 
1528    * If the page is from a pagefile section and has no swap entry, 
1529    * we can't free the page at this point.
1530    */
1531   SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1532   if (!Context.WasDirty && 
1533       !(SwapEntry == 0 && Context.Segment->Flags & MM_PAGEFILE_SEGMENT))
1534       
1535     {
1536       if (Context.Private)
1537         {
1538           MmSetSavedSwapEntryPage(PhysicalAddress, 0);
1539           if (!(Context.Segment->Characteristics & IMAGE_SECTION_CHAR_BSS) &&
1540               SwapEntry == 0)
1541             {
1542               DPRINT1("Private page, non-dirty but not swapped out "
1543                       "process %d address 0x%.8X\n",
1544                       AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0,
1545                       Address);       
1546               KEBUGCHECK(0);
1547             }
1548           else
1549             {
1550               Status = MmCreatePageFileMapping(AddressSpace->Process,
1551                                                Address,
1552                                                SwapEntry);
1553               if (!NT_SUCCESS(Status))
1554                 {
1555                   KEBUGCHECK(0);
1556                 }
1557             }
1558         }
1559       if (DirectMapped && !Context.Private)
1560         {
1561           Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
1562           if (!NT_SUCCESS(Status))
1563             {
1564               DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
1565               KEBUGCHECK(0);
1566             }
1567         }
1568       else
1569         {
1570           MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1571         }
1572       
1573       PageOp->Status = STATUS_SUCCESS;
1574       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1575       MmReleasePageOp(PageOp);
1576       return(STATUS_SUCCESS);
1577     }
1578
1579   /*
1580    * If this page was direct mapped from the cache then the cache manager
1581    * will already have taken care of writing it back.
1582    */
1583   if (DirectMapped && !Context.Private)
1584     {
1585       assert(SwapEntry == 0);
1586       Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
1587       if (!NT_SUCCESS(Status))
1588         {
1589           DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
1590           KEBUGCHECK(0);
1591         }
1592       PageOp->Status = STATUS_SUCCESS;
1593       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1594       MmReleasePageOp(PageOp);
1595       return(STATUS_SUCCESS);
1596     }
1597
1598   /*
1599    * If necessary, allocate an entry in the paging file for this page
1600    */
1601   if (SwapEntry == 0)
1602     {
1603       SwapEntry = MmAllocSwapPage();
1604       if (SwapEntry == 0)
1605         {
1606           MmShowOutOfSpaceMessagePagingFile();
1607
1608           /*
1609            * For private pages restore the old mappings.
1610            */
1611           if (Context.Private)
1612             {
1613               Status = MmCreateVirtualMapping(MemoryArea->Process,   
1614                                               Address,
1615                                               MemoryArea->Attributes,
1616                                               PhysicalAddress,
1617                                               FALSE);
1618               MmSetDirtyPage(MemoryArea->Process, Address);
1619               MmInsertRmap(PhysicalAddress, 
1620                            MemoryArea->Process,
1621                            Address);
1622             }
1623           else
1624             {
1625               /*
1626                * For non-private pages if the page wasn't direct mapped then
1627                * set it back into the section segment entry so we don't loose 
1628                * our copy. Otherwise it will be handled by the cache manager.
1629                */
1630               Status = MmCreateVirtualMapping(MemoryArea->Process,   
1631                                               Address,
1632                                               MemoryArea->Attributes,
1633                                               PhysicalAddress,
1634                                               FALSE);
1635               MmSetDirtyPage(MemoryArea->Process, Address);
1636               MmInsertRmap(PhysicalAddress, 
1637                            MemoryArea->Process,
1638                            Address);
1639               Entry = MAKE_SSE(PhysicalAddress.u.LowPart, 1);
1640               MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1641             }
1642           PageOp->Status = STATUS_UNSUCCESSFUL;
1643           KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1644           MmReleasePageOp(PageOp);
1645           return(STATUS_PAGEFILE_QUOTA);
1646         }
1647     }
1648
1649   /*
1650    * Write the page to the pagefile
1651    */
1652   Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
1653   MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
1654   Status = MmWriteToSwapPage(SwapEntry, Mdl);
1655   if (!NT_SUCCESS(Status))
1656     {
1657       DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", 
1658               Status);
1659       /*
1660        * As above: undo our actions.
1661        * FIXME: Also free the swap page.
1662        */
1663       if (Context.Private)
1664         {
1665           Status = MmCreateVirtualMapping(MemoryArea->Process,   
1666                                           Address,
1667                                           MemoryArea->Attributes,
1668                                           PhysicalAddress,
1669                                           FALSE);
1670           MmSetDirtyPage(MemoryArea->Process, Address);
1671           MmInsertRmap(PhysicalAddress, 
1672                        MemoryArea->Process,
1673                        Address);
1674         }
1675       else
1676         {
1677           Status = MmCreateVirtualMapping(MemoryArea->Process,   
1678                                           Address,
1679                                           MemoryArea->Attributes,
1680                                           PhysicalAddress,
1681                                           FALSE);
1682           MmSetDirtyPage(MemoryArea->Process, Address);
1683           MmInsertRmap(PhysicalAddress, 
1684                            MemoryArea->Process,
1685                            Address);
1686           Entry = MAKE_SSE(PhysicalAddress.u.LowPart, 1);
1687           MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1688         }
1689       PageOp->Status = STATUS_UNSUCCESSFUL;
1690       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1691       MmReleasePageOp(PageOp);
1692       return(STATUS_UNSUCCESSFUL);
1693     }
1694
1695   /*
1696    * Otherwise we have succeeded.
1697    */
1698   DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress);
1699   MmSetSavedSwapEntryPage(PhysicalAddress, 0);
1700   MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1701
1702   if (Context.Private)
1703     {
1704       Status = MmCreatePageFileMapping(MemoryArea->Process,   
1705                                        Address,
1706                                        SwapEntry);
1707       if (!NT_SUCCESS(Status))
1708         {
1709           KEBUGCHECK(0);
1710         }
1711     }
1712   else
1713     {
1714       Entry = MAKE_SWAP_SSE(SwapEntry);
1715       MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1716     }
1717
1718   PageOp->Status = STATUS_SUCCESS;
1719   KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1720   MmReleasePageOp(PageOp);
1721   return(STATUS_SUCCESS);
1722 }
1723
1724 NTSTATUS 
1725 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
1726                        PMEMORY_AREA MemoryArea,
1727                        PVOID Address,
1728                        PMM_PAGEOP PageOp)
1729 {
1730   ULONG Offset;
1731   PSECTION_OBJECT Section;
1732   PMM_SECTION_SEGMENT Segment;
1733   PHYSICAL_ADDRESS PhysicalAddress;
1734   SWAPENTRY SwapEntry;
1735   PMDL Mdl;
1736   ULONG Entry;
1737   BOOLEAN Private;
1738   NTSTATUS Status;
1739   PFILE_OBJECT FileObject;
1740   PBCB Bcb = NULL;
1741   BOOLEAN DirectMapped;
1742   BOOLEAN IsImageSection;
1743
1744   Address = (PVOID)PAGE_ROUND_DOWN(Address);
1745
1746   Offset = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress);
1747
1748   /*
1749    * Get the segment and section.
1750    */
1751   Segment = MemoryArea->Data.SectionData.Segment;
1752   Section = MemoryArea->Data.SectionData.Section;
1753   IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1754
1755   FileObject = Section->FileObject;
1756   DirectMapped = FALSE;
1757   if (FileObject != NULL)
1758     {
1759       Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1760   
1761       /*
1762        * If the file system is letting us go directly to the cache and the
1763        * memory area was mapped at an offset in the file which is page aligned
1764        * then note this is a direct mapped page.
1765        */
1766       if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
1767           (Offset + MemoryArea->Data.SectionData.ViewOffset % PAGE_SIZE) == 0 &&
1768           (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
1769         {
1770           DirectMapped = TRUE;
1771         }
1772     }
1773    
1774   /*
1775    * This should never happen since mappings of physical memory are never
1776    * placed in the rmap lists.
1777    */
1778   if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1779     {
1780       DPRINT1("Trying to write back page from physical memory mapped at %X "
1781               "process %d\n", Address, 
1782               AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
1783       KEBUGCHECK(0);
1784     }
1785
1786   /*
1787    * Get the section segment entry and the physical address.
1788    */
1789   Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1790   if (!MmIsPagePresent(AddressSpace->Process, Address))
1791     {
1792       DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1793           AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
1794       KEBUGCHECK(0);
1795     }
1796   PhysicalAddress = 
1797     MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1798   SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1799
1800   /*
1801    * Check for a private (COWed) page.
1802    */
1803   if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1804       IS_SWAP_FROM_SSE(Entry) || 
1805       (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart)
1806     {
1807       Private = TRUE;
1808     }
1809   else
1810     {
1811       Private = FALSE;
1812     }
1813
1814   /*
1815    * Speculatively set all mappings of the page to clean.
1816    */
1817   MmSetCleanAllRmaps(PhysicalAddress);
1818   
1819   /*
1820    * If this page was direct mapped from the cache then the cache manager
1821    * will take care of writing it back to disk.
1822    */
1823   if (DirectMapped && !Private)
1824     {
1825       assert(SwapEntry == 0);
1826       CcRosMarkDirtyCacheSegment(Bcb, Offset + MemoryArea->Data.SectionData.ViewOffset);
1827       PageOp->Status = STATUS_SUCCESS;
1828       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1829       MmReleasePageOp(PageOp);
1830       return(STATUS_SUCCESS);
1831     }
1832
1833   /*
1834    * If necessary, allocate an entry in the paging file for this page
1835    */
1836   if (SwapEntry == 0)
1837     {
1838       SwapEntry = MmAllocSwapPage();
1839       if (SwapEntry == 0)
1840         {
1841           MmSetDirtyAllRmaps(PhysicalAddress);
1842           PageOp->Status = STATUS_UNSUCCESSFUL;
1843           KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1844           MmReleasePageOp(PageOp);
1845           return(STATUS_PAGEFILE_QUOTA);
1846         }
1847     }
1848
1849   /*
1850    * Write the page to the pagefile
1851    */
1852   Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
1853   MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
1854   Status = MmWriteToSwapPage(SwapEntry, Mdl);
1855   if (!NT_SUCCESS(Status))
1856     {
1857       DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", 
1858               Status);
1859       MmSetDirtyAllRmaps(PhysicalAddress);
1860       PageOp->Status = STATUS_UNSUCCESSFUL;
1861       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1862       MmReleasePageOp(PageOp);
1863       return(STATUS_UNSUCCESSFUL);
1864     }
1865
1866   /*
1867    * Otherwise we have succeeded.
1868    */
1869   DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress);
1870   MmSetSavedSwapEntryPage(PhysicalAddress, SwapEntry);
1871   PageOp->Status = STATUS_SUCCESS;
1872   KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1873   MmReleasePageOp(PageOp);
1874   return(STATUS_SUCCESS);
1875 }
1876
1877 VOID STATIC
1878 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace,
1879                       PVOID BaseAddress,
1880                       ULONG RegionSize,
1881                       ULONG OldType,
1882                       ULONG OldProtect,
1883                       ULONG NewType,
1884                       ULONG NewProtect)
1885 {
1886   PMEMORY_AREA MemoryArea;
1887   PMM_SECTION_SEGMENT Segment;
1888   BOOL DoCOW = FALSE;
1889   ULONG i;
1890
1891   MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, BaseAddress);
1892   Segment = MemoryArea->Data.SectionData.Segment;
1893
1894   if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1895        (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
1896      {
1897        DoCOW = TRUE;
1898      }
1899
1900   if (OldProtect != NewProtect)
1901     {
1902       for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
1903         {
1904           PVOID Address = BaseAddress + (i * PAGE_SIZE);
1905           ULONG Protect = NewProtect;
1906
1907           /* 
1908            * If we doing COW for this segment then check if the page is
1909            * already private.
1910            */
1911           if (DoCOW && MmIsPagePresent(AddressSpace->Process, Address))
1912             {
1913               ULONG Offset;
1914               ULONG Entry;
1915               LARGE_INTEGER PhysicalAddress;
1916
1917               Offset =  (ULONG)Address - (ULONG)MemoryArea->BaseAddress;
1918               Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1919               PhysicalAddress = 
1920                 MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1921
1922               Protect = PAGE_READONLY;
1923               if ((Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1924                    IS_SWAP_FROM_SSE(Entry) || 
1925                    (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart))
1926                 {
1927                   Protect = NewProtect;
1928                 }
1929             }
1930
1931           if (MmIsPagePresent(AddressSpace->Process, Address))
1932             {
1933               MmSetPageProtect(AddressSpace->Process, BaseAddress, 
1934                                Protect);
1935             }
1936         }
1937     }
1938 }
1939
1940 NTSTATUS
1941 MmProtectSectionView(PMADDRESS_SPACE AddressSpace,
1942                      PMEMORY_AREA MemoryArea,
1943                      PVOID BaseAddress,
1944                      ULONG Length,
1945                      ULONG Protect,
1946                      PULONG OldProtect)
1947 {
1948   PMM_REGION Region;
1949   NTSTATUS Status;
1950
1951   Length = 
1952     min(Length, (ULONG) (MemoryArea->BaseAddress + MemoryArea->Length - BaseAddress));
1953   Region = MmFindRegion(MemoryArea->BaseAddress,
1954                         &MemoryArea->Data.SectionData.RegionListHead,
1955                         BaseAddress, NULL);
1956   *OldProtect = Region->Protect;
1957   Status = MmAlterRegion(AddressSpace, MemoryArea->BaseAddress,
1958                          &MemoryArea->Data.SectionData.RegionListHead,
1959                          BaseAddress, Length, Region->Type, Protect,
1960                          MmAlterViewAttributes);
1961
1962   return(Status);
1963 }
1964
1965 NTSTATUS STDCALL
1966 MmQuerySectionView(PMEMORY_AREA MemoryArea,
1967                    PVOID Address,
1968                    PMEMORY_BASIC_INFORMATION Info,
1969                    PULONG ResultLength)
1970 {
1971   PMM_REGION Region;
1972   PVOID RegionBaseAddress;
1973   
1974   Region = MmFindRegion(MemoryArea->BaseAddress,
1975                         &MemoryArea->Data.SectionData.RegionListHead,
1976                         Address, &RegionBaseAddress);
1977   if (Region == NULL)
1978     {
1979       return STATUS_UNSUCCESSFUL;
1980     }
1981   Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
1982   Info->AllocationBase = MemoryArea->BaseAddress;
1983   Info->AllocationProtect = MemoryArea->Attributes;
1984   Info->RegionSize = MemoryArea->Length;
1985   Info->State = MEM_COMMIT;
1986   Info->Protect = Region->Protect;
1987   if (MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE)
1988     {
1989       Info->Type = MEM_IMAGE;
1990     }
1991   else
1992     {
1993       Info->Type = MEM_MAPPED;
1994     }
1995
1996   return(STATUS_SUCCESS);
1997 }
1998
1999 VOID STDCALL
2000 MmpDeleteSection(PVOID ObjectBody)
2001 {
2002   PSECTION_OBJECT Section = (PSECTION_OBJECT)ObjectBody;
2003
2004   DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
2005   if (Section->AllocationAttributes & SEC_IMAGE)
2006     {
2007       ULONG i;
2008       ULONG NrSegments;
2009       PMM_SECTION_SEGMENT SectionSegments;
2010
2011       SectionSegments = Section->ImageSection->Segments;
2012       NrSegments = Section->ImageSection->NrSegments;
2013
2014       for (i = 0; i < NrSegments; i++)
2015         {
2016           InterlockedDecrement((LONG *)&SectionSegments[i].ReferenceCount);
2017         }
2018     }
2019   else
2020     {
2021       if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
2022         {
2023           ULONG Offset;
2024           ULONG Length;
2025           ULONG Entry;
2026           PMM_SECTION_SEGMENT Segment;
2027           
2028           Segment = Section->Segment;
2029           Length = PAGE_ROUND_UP(Segment->Length);
2030           
2031           for (Offset = 0; Offset < Length; Offset += PAGE_SIZE)
2032             {
2033               Entry = MmGetPageEntrySectionSegment(Segment, Offset);
2034               if (Entry)
2035                 {
2036                   if (IS_SWAP_FROM_SSE(Entry))
2037                     {
2038                       MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
2039                     }
2040                   else
2041                     {
2042                       PHYSICAL_ADDRESS Page = (PHYSICAL_ADDRESS)(LONGLONG)PAGE_FROM_SSE(Entry);
2043                       MmReleasePageMemoryConsumer(MC_USER, Page);
2044                     }
2045                 }
2046             }
2047           MmFreePageTablesSectionSegment(Section->Segment);
2048           ExFreePool(Section->Segment);
2049           Section->Segment = NULL;
2050         }
2051       else
2052         {
2053           InterlockedDecrement((LONG *)&Section->Segment->ReferenceCount);
2054         }
2055     }
2056   if (Section->FileObject != NULL)
2057     {
2058       CcRosDereferenceCache(Section->FileObject);
2059       ObDereferenceObject(Section->FileObject);
2060       Section->FileObject = NULL;
2061     }  
2062 }
2063
2064 VOID STDCALL
2065 MmpCloseSection(PVOID ObjectBody,
2066                 ULONG HandleCount)
2067 {
2068    DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2069            ObjectBody, HandleCount, ObGetObjectPointerCount(ObjectBody));
2070 }
2071
2072 NTSTATUS STDCALL
2073 MmpCreateSection(PVOID ObjectBody,
2074                  PVOID Parent,
2075                  PWSTR RemainingPath,
2076                  POBJECT_ATTRIBUTES ObjectAttributes)
2077 {
2078    DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2079            ObjectBody, Parent, RemainingPath);
2080    
2081    if (RemainingPath == NULL)
2082      {
2083          return(STATUS_SUCCESS);
2084      }
2085    
2086    if (wcschr(RemainingPath+1, L'\\') != NULL)
2087      {
2088         return(STATUS_UNSUCCESSFUL);
2089      }
2090    return(STATUS_SUCCESS);
2091 }
2092
2093 NTSTATUS 
2094 MmCreatePhysicalMemorySection(VOID)
2095 {
2096   HANDLE PhysSectionH;
2097   PSECTION_OBJECT PhysSection;
2098   NTSTATUS Status;
2099   OBJECT_ATTRIBUTES Obj;
2100   UNICODE_STRING Name = UNICODE_STRING_INITIALIZER(L"\\Device\\PhysicalMemory");
2101   LARGE_INTEGER SectionSize;
2102    
2103   /*
2104    * Create the section mapping physical memory 
2105    */
2106   SectionSize.QuadPart = 0xFFFFFFFF;
2107   InitializeObjectAttributes(&Obj,
2108                              &Name,
2109                              0,
2110                              NULL,
2111                              NULL);
2112   Status = NtCreateSection(&PhysSectionH,
2113                            SECTION_ALL_ACCESS,
2114                            &Obj,
2115                            &SectionSize,
2116                            PAGE_EXECUTE_READWRITE,
2117                            0,
2118                            NULL);
2119   if (!NT_SUCCESS(Status))
2120     {
2121       DbgPrint("Failed to create PhysicalMemory section\n");
2122       KEBUGCHECK(0);
2123     }
2124   Status = ObReferenceObjectByHandle(PhysSectionH,
2125                                      SECTION_ALL_ACCESS,
2126                                      NULL,
2127                                      KernelMode,
2128                                      (PVOID*)&PhysSection,
2129                                      NULL);
2130   if (!NT_SUCCESS(Status))
2131     {
2132       DbgPrint("Failed to reference PhysicalMemory section\n");
2133       KEBUGCHECK(0);
2134     }
2135   PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
2136   ObDereferenceObject((PVOID)PhysSection);
2137    
2138   return(STATUS_SUCCESS);
2139 }
2140
2141 NTSTATUS 
2142 MmInitSectionImplementation(VOID)
2143 {
2144    MmSectionObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
2145    
2146    RtlInitUnicodeStringFromLiteral(&MmSectionObjectType->TypeName, L"Section");
2147    
2148    MmSectionObjectType->Tag = TAG('S', 'E', 'C', 'T');
2149    MmSectionObjectType->TotalObjects = 0;
2150    MmSectionObjectType->TotalHandles = 0;
2151    MmSectionObjectType->MaxObjects = ULONG_MAX;
2152    MmSectionObjectType->MaxHandles = ULONG_MAX;
2153    MmSectionObjectType->PagedPoolCharge = 0;
2154    MmSectionObjectType->NonpagedPoolCharge = sizeof(SECTION_OBJECT);
2155    MmSectionObjectType->Mapping = &MmpSectionMapping;
2156    MmSectionObjectType->Dump = NULL;
2157    MmSectionObjectType->Open = NULL;
2158    MmSectionObjectType->Close = MmpCloseSection;
2159    MmSectionObjectType->Delete = MmpDeleteSection;
2160    MmSectionObjectType->Parse = NULL;
2161    MmSectionObjectType->Security = NULL;
2162    MmSectionObjectType->QueryName = NULL;
2163    MmSectionObjectType->OkayToClose = NULL;
2164    MmSectionObjectType->Create = MmpCreateSection;
2165    MmSectionObjectType->DuplicationNotify = NULL;
2166    
2167    return(STATUS_SUCCESS);
2168 }
2169
2170 NTSTATUS
2171 MmCreatePageFileSection(PHANDLE SectionHandle,
2172                         ACCESS_MASK DesiredAccess,
2173                         POBJECT_ATTRIBUTES ObjectAttributes,
2174                         PLARGE_INTEGER UMaximumSize,
2175                         ULONG SectionPageProtection,
2176                         ULONG AllocationAttributes)
2177      /*
2178       * Create a section which is backed by the pagefile
2179       */
2180 {
2181   LARGE_INTEGER MaximumSize;
2182   PSECTION_OBJECT Section;
2183   PMM_SECTION_SEGMENT Segment;
2184   NTSTATUS Status;
2185
2186   if (UMaximumSize == NULL)
2187     {
2188       return(STATUS_UNSUCCESSFUL);
2189     }
2190   MaximumSize = *UMaximumSize;
2191   
2192   /*
2193    * Check the protection
2194    */
2195   if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) != 
2196       SectionPageProtection)
2197     {
2198       return(STATUS_INVALID_PAGE_PROTECTION);
2199     }
2200   
2201   /*
2202    * Create the section
2203    */
2204   Status = ObRosCreateObject(SectionHandle,
2205                           DesiredAccess,
2206                           ObjectAttributes,
2207                           MmSectionObjectType,
2208                           (PVOID*)&Section);
2209   if (!NT_SUCCESS(Status))
2210     {
2211       return(Status);
2212     }
2213   
2214   /*
2215    * Initialize it
2216    */
2217   Section->SectionPageProtection = SectionPageProtection;
2218   Section->AllocationAttributes = AllocationAttributes;
2219   InitializeListHead(&Section->ViewListHead);
2220   KeInitializeSpinLock(&Section->ViewListLock);
2221   Section->FileObject = NULL;
2222   Section->MaximumSize = MaximumSize;
2223   Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2224                                   TAG_MM_SECTION_SEGMENT);
2225   if (Segment == NULL)
2226     {
2227       ZwClose(*SectionHandle);
2228       ObDereferenceObject(Section);
2229       return(STATUS_NO_MEMORY);
2230     }
2231   Section->Segment = Segment;
2232   Segment->ReferenceCount = 1;
2233   ExInitializeFastMutex(&Segment->Lock);
2234   Segment->FileOffset = 0;
2235   Segment->Protection = SectionPageProtection;
2236   Segment->Attributes = AllocationAttributes;
2237   Segment->Length = MaximumSize.u.LowPart;
2238   Segment->Flags = MM_PAGEFILE_SEGMENT;
2239   Segment->WriteCopy = FALSE;
2240   ObDereferenceObject(Section);
2241   return(STATUS_SUCCESS);
2242 }
2243
2244
2245 NTSTATUS
2246 MmCreateDataFileSection(PHANDLE SectionHandle,
2247                         ACCESS_MASK DesiredAccess,
2248                         POBJECT_ATTRIBUTES ObjectAttributes,
2249                         PLARGE_INTEGER UMaximumSize,
2250                         ULONG SectionPageProtection,
2251                         ULONG AllocationAttributes,
2252                         HANDLE FileHandle)
2253      /*
2254       * Create a section backed by a data file
2255       */
2256 {
2257   PSECTION_OBJECT Section;
2258   NTSTATUS Status;
2259   LARGE_INTEGER MaximumSize;
2260   PFILE_OBJECT FileObject;
2261   PMM_SECTION_SEGMENT Segment;
2262   ULONG FileAccess;
2263   IO_STATUS_BLOCK Iosb;
2264   LARGE_INTEGER Offset;
2265   CHAR Buffer;
2266   
2267   /*
2268    * Check the protection
2269    */
2270   if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) != 
2271       SectionPageProtection)
2272     {
2273       return(STATUS_INVALID_PAGE_PROTECTION);
2274     }
2275
2276   /*
2277    * Read a bit so caching is initiated for the file object.
2278    * This is only needed because MiReadPage currently cannot
2279    * handle non-cached streams.
2280    */
2281   Offset.QuadPart = 0;
2282   Status = ZwReadFile(FileHandle,
2283                       NULL,
2284                       NULL,
2285                       NULL,
2286                       &Iosb,
2287                       &Buffer,
2288                       sizeof (Buffer),
2289                       &Offset,
2290                       0);
2291   if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
2292     {
2293       return(Status);
2294     }
2295
2296   /*
2297    * Create the section
2298    */
2299   Status = ObRosCreateObject(SectionHandle,
2300                           DesiredAccess,
2301                           ObjectAttributes,
2302                           MmSectionObjectType,
2303                           (PVOID*)&Section);
2304   if (!NT_SUCCESS(Status))
2305     {
2306       return(Status);
2307     }
2308   
2309   /*
2310    * Initialize it
2311    */
2312   Section->SectionPageProtection = SectionPageProtection;
2313   Section->AllocationAttributes = AllocationAttributes;
2314   InitializeListHead(&Section->ViewListHead);
2315   KeInitializeSpinLock(&Section->ViewListLock);
2316
2317   /*
2318    * Check file access required
2319    */
2320   if (SectionPageProtection & PAGE_READWRITE ||
2321       SectionPageProtection & PAGE_EXECUTE_READWRITE)
2322     {
2323       FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2324     }
2325   else
2326     {
2327       FileAccess = FILE_READ_DATA;
2328     }
2329   
2330   /*
2331    * Reference the file handle
2332    */
2333   Status = ObReferenceObjectByHandle(FileHandle,
2334                                      FileAccess,
2335                                      IoFileObjectType,
2336                                      UserMode,
2337                                      (PVOID*)&FileObject,
2338                                      NULL);
2339   if (!NT_SUCCESS(Status))
2340     {
2341       ZwClose(*SectionHandle);
2342       ObDereferenceObject(Section);
2343       return(Status);
2344     }
2345
2346   /*
2347    * We can't do memory mappings if the file system doesn't support the
2348    * standard FCB
2349    */
2350   if (!(FileObject->Flags & FO_FCB_IS_VALID))
2351     {
2352       ZwClose(*SectionHandle);
2353       ObDereferenceObject(Section);
2354       ObDereferenceObject(FileObject);
2355       return(STATUS_INVALID_FILE_FOR_SECTION);
2356     }
2357   
2358   /*
2359    * FIXME: Revise this once a locking order for file size changes is
2360    * decided
2361    */
2362   if (UMaximumSize != NULL)
2363     {
2364       MaximumSize = *UMaximumSize;
2365     }
2366   else
2367     {
2368       MaximumSize = 
2369         ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize;
2370     }
2371
2372   if (MaximumSize.QuadPart > 
2373       ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize.QuadPart)
2374     {
2375       IO_STATUS_BLOCK Iosb;
2376       Status = NtSetInformationFile(FileHandle,
2377                                     &Iosb,
2378                                     &MaximumSize,
2379                                     sizeof(LARGE_INTEGER),
2380                                     FileAllocationInformation);
2381       if (!NT_SUCCESS(Status))
2382         {
2383           ZwClose(*SectionHandle);
2384           ObDereferenceObject(Section);
2385           ObDereferenceObject(FileObject);
2386           return(STATUS_SECTION_NOT_EXTENDED);
2387         }
2388     }
2389
2390   /*
2391    * Lock the file
2392    */
2393   Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
2394                                  0,
2395                                  KernelMode,
2396                                  FALSE,
2397                                  NULL);
2398   if (Status != STATUS_SUCCESS)
2399     {
2400       ZwClose(*SectionHandle);
2401       ObDereferenceObject(Section);
2402       ObDereferenceObject(FileObject);
2403       return(Status);
2404     }
2405
2406   /*
2407    * If this file hasn't been mapped as a data file before then allocate a
2408    * section segment to describe the data file mapping
2409    */
2410   if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
2411     {
2412       Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2413                                       TAG_MM_SECTION_SEGMENT);
2414       if (Segment == NULL)
2415         {
2416           KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2417           ZwClose(*SectionHandle);
2418           ObDereferenceObject(Section);
2419           ObDereferenceObject(FileObject);
2420           return(STATUS_NO_MEMORY);
2421         }
2422       Section->Segment = Segment;
2423       Segment->ReferenceCount = 1;
2424       ExInitializeFastMutex(&Segment->Lock);
2425       /*
2426        * Set the lock before assigning the segment to the file object
2427        */
2428       ExAcquireFastMutex(&Segment->Lock);
2429       FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
2430
2431       Segment->FileOffset = 0;
2432       Segment->Protection = 0;
2433       Segment->Attributes = 0;
2434       Segment->Flags = MM_DATAFILE_SEGMENT;
2435       Segment->Characteristics = 0;
2436       Segment->WriteCopy = FALSE;
2437       if (AllocationAttributes & SEC_RESERVE)
2438         {
2439           Segment->Length = Segment->RawLength = 0;
2440         }
2441       else
2442         {
2443           Segment->RawLength = MaximumSize.u.LowPart;
2444           Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
2445         }
2446       Segment->VirtualAddress = NULL;
2447     }
2448   else
2449     {
2450       /*
2451        * If the file is already mapped as a data file then we may need
2452        * to extend it
2453        */      
2454       Segment = 
2455         (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
2456         DataSectionObject;
2457       Section->Segment = Segment;
2458       InterlockedIncrement((PLONG)&Segment->ReferenceCount);
2459       MmLockSectionSegment(Segment);
2460
2461       if (MaximumSize.u.LowPart > Segment->RawLength && 
2462           !(AllocationAttributes & SEC_RESERVE))
2463         {
2464           Segment->RawLength = MaximumSize.u.LowPart;
2465           Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
2466         }
2467     }
2468   MmUnlockSectionSegment(Segment);
2469   Section->FileObject = FileObject; 
2470   Section->MaximumSize = MaximumSize;
2471   CcRosReferenceCache(FileObject);
2472   KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2473   ObDereferenceObject(Section);
2474   return(STATUS_SUCCESS);
2475 }
2476
2477 static ULONG SectionCharacteristicsToProtect[16] = 
2478 {
2479   PAGE_NOACCESS,               // 0 = NONE
2480   PAGE_NOACCESS,               // 1 = SHARED
2481   PAGE_EXECUTE,                // 2 = EXECUTABLE
2482   PAGE_EXECUTE,                // 3 = EXECUTABLE, SHARED
2483   PAGE_READONLY,               // 4 = READABLE
2484   PAGE_READONLY,               // 5 = READABLE, SHARED
2485   PAGE_EXECUTE_READ,           // 6 = READABLE, EXECUTABLE
2486   PAGE_EXECUTE_READ,           // 7 = READABLE, EXECUTABLE, SHARED
2487   PAGE_READWRITE,              // 8 = WRITABLE
2488   PAGE_READWRITE,              // 9 = WRITABLE, SHARED
2489   PAGE_EXECUTE_READWRITE,      // 10 = WRITABLE, EXECUTABLE
2490   PAGE_EXECUTE_READWRITE,      // 11 = WRITABLE, EXECUTABLE, SHARED
2491   PAGE_READWRITE,              // 12 = WRITABLE, READABLE
2492   PAGE_READWRITE,              // 13 = WRITABLE, READABLE, SHARED
2493   PAGE_EXECUTE_READWRITE,      // 14 = WRITABLE, READABLE, EXECUTABLE,
2494   PAGE_EXECUTE_READWRITE,      // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2495 };
2496
2497 NTSTATUS
2498 MmCreateImageSection(PHANDLE SectionHandle,
2499                      ACCESS_MASK DesiredAccess,
2500                      POBJECT_ATTRIBUTES ObjectAttributes,
2501                      PLARGE_INTEGER UMaximumSize,
2502                      ULONG SectionPageProtection,
2503                      ULONG AllocationAttributes,
2504                      HANDLE FileHandle)
2505 {
2506   PSECTION_OBJECT Section;
2507   NTSTATUS Status;
2508   PFILE_OBJECT FileObject;
2509   IMAGE_DOS_HEADER DosHeader;
2510   IO_STATUS_BLOCK Iosb;
2511   LARGE_INTEGER Offset;
2512   IMAGE_NT_HEADERS PEHeader;
2513   PIMAGE_SECTION_HEADER ImageSections;
2514   PMM_SECTION_SEGMENT SectionSegments;
2515   ULONG NrSegments;
2516   PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
2517   ULONG i;
2518   ULONG Size;
2519   ULONG Characteristics;
2520   ULONG FileAccess = 0;
2521   /*
2522    * Check the protection
2523    */
2524   if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) != 
2525       SectionPageProtection)
2526     {
2527       return(STATUS_INVALID_PAGE_PROTECTION);
2528     }
2529   
2530   /*
2531    * Specifying a maximum size is meaningless for an image section
2532    */
2533   if (UMaximumSize != NULL)
2534     {
2535       return(STATUS_INVALID_PARAMETER_4);
2536     } 
2537
2538   /*
2539    * Reference the file handle
2540    */
2541   Status = ObReferenceObjectByHandle(FileHandle,
2542                                      FileAccess,
2543                                      IoFileObjectType,
2544                                      UserMode,
2545                                      (PVOID*)&FileObject,
2546                                      NULL);
2547   if (!NT_SUCCESS(Status))
2548     {
2549       return Status;
2550     }
2551
2552   /*
2553    * Initialized caching for this file object if previously caching 
2554    * was initialized for the same on disk file
2555    */
2556   Status = CcTryToInitializeFileCache(FileObject);
2557   
2558   if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
2559     {
2560       /*
2561        * Read the dos header and check the DOS signature
2562        */
2563       Offset.QuadPart = 0;
2564       Status = ZwReadFile(FileHandle,
2565                           NULL,
2566                           NULL,
2567                           NULL,
2568                           &Iosb,
2569                           &DosHeader,
2570                           sizeof(DosHeader),
2571                           &Offset,
2572                           0);
2573       if (!NT_SUCCESS(Status))
2574         {
2575           ObDereferenceObject(FileObject);
2576           return(Status);
2577         }
2578     
2579       /*
2580        * Check the DOS signature
2581        */
2582       if (Iosb.Information != sizeof(DosHeader) ||
2583           DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
2584         {
2585           ObDereferenceObject(FileObject);
2586           return(STATUS_INVALID_IMAGE_FORMAT);
2587         }
2588
2589       /*
2590        * Read the PE header
2591        */
2592       Offset.QuadPart = DosHeader.e_lfanew;
2593       Status = ZwReadFile(FileHandle,
2594                           NULL,
2595                           NULL,
2596                           NULL,
2597                           &Iosb,
2598                           &PEHeader,
2599                           sizeof(PEHeader),
2600                           &Offset,
2601                           0);
2602       if (!NT_SUCCESS(Status))
2603         {
2604           ObDereferenceObject(FileObject);
2605           return(Status);
2606         }
2607
2608       /*
2609        * Check the signature
2610        */
2611       if (Iosb.Information != sizeof(PEHeader) || 
2612           PEHeader.Signature != IMAGE_NT_SIGNATURE)
2613         {
2614           ObDereferenceObject(FileObject);
2615           return(STATUS_INVALID_IMAGE_FORMAT);
2616         }
2617
2618       /*
2619        * Read in the section headers
2620        */
2621       Offset.QuadPart = DosHeader.e_lfanew + sizeof(PEHeader);  
2622       ImageSections = ExAllocatePool(NonPagedPool,
2623                                      PEHeader.FileHeader.NumberOfSections * 
2624                                      sizeof(IMAGE_SECTION_HEADER));
2625       if (ImageSections == NULL)
2626         {
2627           ObDereferenceObject(FileObject);
2628           return(STATUS_NO_MEMORY);
2629         }
2630
2631       Status = ZwReadFile(FileHandle,
2632                           NULL,
2633                           NULL,
2634                           NULL,
2635                           &Iosb,
2636                           ImageSections,
2637                           PEHeader.FileHeader.NumberOfSections * 
2638                           sizeof(IMAGE_SECTION_HEADER),
2639                           &Offset,
2640                           0);
2641       if (!NT_SUCCESS(Status))
2642         {
2643           ObDereferenceObject(FileObject);
2644           ExFreePool(ImageSections);
2645           return(Status);
2646         }
2647       if (Iosb.Information != (PEHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
2648         {
2649           ObDereferenceObject(FileObject);
2650           ExFreePool(ImageSections);
2651           return(STATUS_INVALID_IMAGE_FORMAT);
2652         }
2653
2654       /*
2655        * Create the section
2656        */
2657         Status = ObRosCreateObject(SectionHandle,
2658                                    DesiredAccess,
2659                                    ObjectAttributes,
2660                                    MmSectionObjectType,
2661                                    (PVOID*)&Section);
2662         if (!NT_SUCCESS(Status))
2663           {
2664             ObDereferenceObject(FileObject);
2665             ExFreePool(ImageSections);
2666             return(Status);
2667           }
2668
2669         /*
2670          * Initialize it
2671          */
2672         Section->SectionPageProtection = SectionPageProtection;
2673         Section->AllocationAttributes = AllocationAttributes;
2674         InitializeListHead(&Section->ViewListHead);
2675         KeInitializeSpinLock(&Section->ViewListLock);
2676
2677         /*
2678          * Check file access required
2679          */
2680         if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
2681           {
2682             FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2683           }
2684         else
2685           {
2686             FileAccess = FILE_READ_DATA;
2687           }
2688   
2689         /*
2690          * We can't do memory mappings if the file system doesn't support the
2691          * standard FCB
2692          */
2693         if (!(FileObject->Flags & FO_FCB_IS_VALID))
2694           {
2695             ZwClose(*SectionHandle);
2696             ObDereferenceObject(Section);
2697             ObDereferenceObject(FileObject);
2698             ExFreePool(ImageSections);
2699             return(STATUS_INVALID_FILE_FOR_SECTION);
2700           }
2701   
2702         /*
2703          * Lock the file
2704          */
2705         Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
2706                                        0,
2707                                        KernelMode,
2708                                        FALSE,
2709                                        NULL);
2710         if (Status != STATUS_SUCCESS)
2711           {
2712             ZwClose(*SectionHandle);
2713             ObDereferenceObject(Section);
2714             ObDereferenceObject(FileObject);
2715             ExFreePool(ImageSections);
2716             return(Status);
2717           }
2718
2719         /*
2720          * allocate the section segments to describe the mapping
2721          */
2722         NrSegments = PEHeader.FileHeader.NumberOfSections + 1;
2723         Size = sizeof(MM_IMAGE_SECTION_OBJECT) + sizeof(MM_SECTION_SEGMENT) * NrSegments;
2724         ImageSectionObject = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MM_SECTION_SEGMENT);
2725         if (ImageSectionObject == NULL)
2726           {
2727             KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2728             ZwClose(*SectionHandle);
2729             ObDereferenceObject(Section);
2730             ObDereferenceObject(FileObject);
2731             ExFreePool(ImageSections);
2732             return(STATUS_NO_MEMORY);
2733           }
2734         Section->ImageSection = ImageSectionObject;
2735         ImageSectionObject->NrSegments = NrSegments;
2736         ImageSectionObject->ImageBase = (PVOID)PEHeader.OptionalHeader.ImageBase;
2737         ImageSectionObject->EntryPoint = (PVOID)PEHeader.OptionalHeader.AddressOfEntryPoint;
2738         ImageSectionObject->StackReserve = PEHeader.OptionalHeader.SizeOfStackReserve;
2739         ImageSectionObject->StackCommit = PEHeader.OptionalHeader.SizeOfStackCommit;
2740         ImageSectionObject->Subsystem = PEHeader.OptionalHeader.Subsystem;
2741         ImageSectionObject->MinorSubsystemVersion = PEHeader.OptionalHeader.MinorSubsystemVersion;
2742         ImageSectionObject->MajorSubsystemVersion = PEHeader.OptionalHeader.MajorSubsystemVersion;
2743         ImageSectionObject->ImageCharacteristics = PEHeader.FileHeader.Characteristics;
2744         ImageSectionObject->Machine = PEHeader.FileHeader.Machine;
2745         ImageSectionObject->Executable = (PEHeader.OptionalHeader.SizeOfCode != 0);
2746
2747         SectionSegments = ImageSectionObject->Segments;
2748         SectionSegments[0].FileOffset = 0;
2749         SectionSegments[0].Characteristics = IMAGE_SECTION_CHAR_DATA;
2750         SectionSegments[0].Protection = PAGE_READONLY;
2751         SectionSegments[0].RawLength = PAGE_SIZE;
2752         SectionSegments[0].Length = PAGE_SIZE;
2753         SectionSegments[0].Flags = 0;
2754         SectionSegments[0].ReferenceCount = 1;
2755         SectionSegments[0].VirtualAddress = 0;
2756         SectionSegments[0].WriteCopy = FALSE;
2757         ExInitializeFastMutex(&SectionSegments[0].Lock);
2758         for (i = 1; i < NrSegments; i++)
2759           {
2760             SectionSegments[i].FileOffset = ImageSections[i-1].PointerToRawData;
2761             SectionSegments[i].Characteristics = ImageSections[i-1].Characteristics;
2762
2763             /*
2764              * Set up the protection and write copy variables.
2765              */
2766             Characteristics = ImageSections[i - 1].Characteristics;
2767             if (Characteristics & (IMAGE_SECTION_CHAR_READABLE|IMAGE_SECTION_CHAR_WRITABLE|IMAGE_SECTION_CHAR_EXECUTABLE))
2768               {
2769                 SectionSegments[i].Protection = SectionCharacteristicsToProtect[Characteristics >> 28];
2770                 SectionSegments[i].WriteCopy = !(Characteristics & IMAGE_SECTION_CHAR_SHARED);
2771               }
2772             else if (Characteristics & IMAGE_SECTION_CHAR_CODE)
2773               {
2774                 SectionSegments[i].Protection = PAGE_EXECUTE_READ;
2775                 SectionSegments[i].WriteCopy = TRUE;
2776               }
2777             else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
2778               {
2779                 SectionSegments[i].Protection = PAGE_READWRITE;
2780                 SectionSegments[i].WriteCopy = TRUE;
2781               }
2782             else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
2783               {
2784                 SectionSegments[i].Protection = PAGE_READWRITE;
2785                 SectionSegments[i].WriteCopy = TRUE;
2786               }
2787             else
2788               {
2789                 SectionSegments[i].Protection = PAGE_NOACCESS;
2790                 SectionSegments[i].WriteCopy = TRUE;
2791               }
2792           
2793             /*
2794              * Set up the attributes.
2795              */
2796             if (Characteristics & IMAGE_SECTION_CHAR_CODE)
2797               {
2798                 SectionSegments[i].Attributes = 0;
2799               }
2800             else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
2801               {
2802                 SectionSegments[i].Attributes = 0;
2803               }
2804             else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
2805               {
2806                 SectionSegments[i].Attributes = MM_SECTION_SEGMENT_BSS;
2807               }
2808             else
2809               {
2810                 SectionSegments[i].Attributes = 0;
2811               }
2812
2813             SectionSegments[i].RawLength = ImageSections[i-1].SizeOfRawData;
2814             SectionSegments[i].Length = ImageSections[i-1].Misc.VirtualSize;
2815             SectionSegments[i].Flags = 0;
2816             SectionSegments[i].ReferenceCount = 1;
2817             SectionSegments[i].VirtualAddress = (PVOID)ImageSections[i-1].VirtualAddress;
2818             ExInitializeFastMutex(&SectionSegments[i].Lock);
2819           }
2820         if (0 != InterlockedCompareExchange((PLONG)&FileObject->SectionObjectPointer->ImageSectionObject, 
2821                                             (LONG)ImageSectionObject, 0))
2822           {
2823             /*
2824              * An other thread has initialized the some image in the background
2825              */
2826             ExFreePool(ImageSectionObject);
2827             ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
2828             Section->ImageSection = ImageSectionObject;
2829             SectionSegments = ImageSectionObject->Segments;
2830
2831             for (i = 0; i < NrSegments; i++)
2832              {
2833                InterlockedIncrement((LONG *)&SectionSegments[i].ReferenceCount);
2834              }
2835           }
2836         ExFreePool(ImageSections);
2837     }
2838   else
2839     {
2840       /*
2841        * Create the section
2842        */
2843       Status = ObRosCreateObject(SectionHandle,
2844                                  DesiredAccess,
2845                                  ObjectAttributes,
2846                                  MmSectionObjectType,
2847                                  (PVOID*)&Section);
2848       if (!NT_SUCCESS(Status))
2849         {
2850           ObDereferenceObject(FileObject);
2851           return(Status);
2852         }
2853
2854       /*
2855        * Initialize it
2856        */
2857       Section->SectionPageProtection = SectionPageProtection;
2858       Section->AllocationAttributes = AllocationAttributes;
2859       InitializeListHead(&Section->ViewListHead);
2860       KeInitializeSpinLock(&Section->ViewListLock);
2861
2862       /*
2863        * Check file access required
2864        */
2865       if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
2866         {
2867           FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2868         }
2869       else
2870         {
2871           FileAccess = FILE_READ_DATA;
2872         }
2873   
2874       /*
2875        * Lock the file
2876        */
2877       Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
2878                                      0,
2879                                      KernelMode,
2880                                      FALSE,
2881                                      NULL);
2882       if (Status != STATUS_SUCCESS)
2883         {
2884           ZwClose(*SectionHandle);
2885           ObDereferenceObject(Section);
2886           ObDereferenceObject(FileObject);
2887           return(Status);
2888         }
2889
2890       ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
2891       Section->ImageSection = ImageSectionObject;
2892       SectionSegments = ImageSectionObject->Segments;
2893       NrSegments = ImageSectionObject->NrSegments;
2894
2895       /*
2896        * Otherwise just reference all the section segments
2897        */
2898       for (i = 0; i < NrSegments; i++)
2899         {
2900           InterlockedIncrement((LONG *)&SectionSegments[i].ReferenceCount);
2901         }
2902
2903     }
2904   Section->FileObject = FileObject;
2905   CcRosReferenceCache(FileObject);
2906   KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2907   ObDereferenceObject(Section);
2908   return(STATUS_SUCCESS);
2909 }
2910
2911 /*
2912  * @implemented
2913  */
2914 NTSTATUS STDCALL
2915 NtCreateSection (OUT PHANDLE SectionHandle,
2916                  IN ACCESS_MASK DesiredAccess,
2917                  IN POBJECT_ATTRIBUTES  ObjectAttributes OPTIONAL,
2918                  IN PLARGE_INTEGER MaximumSize  OPTIONAL,
2919                  IN ULONG SectionPageProtection OPTIONAL,
2920                  IN ULONG AllocationAttributes,
2921                  IN HANDLE FileHandle OPTIONAL)
2922 {
2923   if (AllocationAttributes & SEC_IMAGE)
2924     {
2925       return(MmCreateImageSection(SectionHandle,
2926                                   DesiredAccess,
2927                                   ObjectAttributes,
2928                                   MaximumSize,
2929                                   SectionPageProtection,
2930                                   AllocationAttributes,
2931                                   FileHandle));
2932     }
2933   else if (FileHandle != NULL)
2934     {
2935       return(MmCreateDataFileSection(SectionHandle,
2936                                      DesiredAccess,
2937                                      ObjectAttributes,
2938                                      MaximumSize,
2939                                      SectionPageProtection,
2940                                      AllocationAttributes,
2941                                      FileHandle));
2942     }
2943   else
2944     {
2945       return(MmCreatePageFileSection(SectionHandle,
2946                                      DesiredAccess,
2947                                      ObjectAttributes,
2948                                      MaximumSize,
2949                                      SectionPageProtection,
2950                                      AllocationAttributes));
2951     }
2952 }
2953
2954
2955 /**********************************************************************
2956  * NAME
2957  *      NtOpenSection
2958  *
2959  * DESCRIPTION
2960  *
2961  * ARGUMENTS
2962  *      SectionHandle
2963  *
2964  *      DesiredAccess
2965  *
2966  *      ObjectAttributes
2967  *
2968  * RETURN VALUE
2969  *
2970  * REVISIONS
2971  */
2972 NTSTATUS STDCALL
2973 NtOpenSection(PHANDLE                   SectionHandle,
2974               ACCESS_MASK               DesiredAccess,
2975               POBJECT_ATTRIBUTES        ObjectAttributes)
2976 {
2977   NTSTATUS Status;
2978
2979   *SectionHandle = 0;
2980
2981   Status = ObOpenObjectByName(ObjectAttributes,
2982                               MmSectionObjectType,
2983                               NULL,
2984                               UserMode,
2985                               DesiredAccess,
2986                               NULL,
2987                               SectionHandle);
2988
2989   return(Status);
2990 }
2991
2992 NTSTATUS STATIC
2993 MmMapViewOfSegment(PEPROCESS Process,
2994                    PMADDRESS_SPACE AddressSpace,
2995                    PSECTION_OBJECT Section,
2996                    PMM_SECTION_SEGMENT Segment,
2997                    PVOID* BaseAddress,
2998                    ULONG ViewSize,
2999                    ULONG Protect,
3000                    ULONG ViewOffset,
3001                    BOOL TopDown)
3002 {
3003   PMEMORY_AREA MArea;
3004   NTSTATUS Status;
3005   KIRQL oldIrql;
3006
3007   Status = MmCreateMemoryArea(Process,
3008                               AddressSpace,
3009                               MEMORY_AREA_SECTION_VIEW,
3010                               BaseAddress,
3011                               ViewSize,
3012                               Protect,
3013                               &MArea,
3014                               FALSE,
3015                               TopDown);
3016   if (!NT_SUCCESS(Status))
3017     {
3018       DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
3019               (*BaseAddress), (*BaseAddress) + ViewSize);
3020       return(Status);
3021     }
3022
3023   KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
3024   InsertTailList(&Section->ViewListHead,
3025                  &MArea->Data.SectionData.ViewListEntry);
3026   KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
3027
3028   ObReferenceObjectByPointer((PVOID)Section,
3029                              SECTION_MAP_READ,
3030                              NULL,
3031                              ExGetPreviousMode());
3032   MArea->Data.SectionData.Segment = Segment;
3033   MArea->Data.SectionData.Section = Section;
3034   MArea->Data.SectionData.ViewOffset = ViewOffset;
3035   MArea->Data.SectionData.WriteCopyView = FALSE;
3036   MmInitialiseRegion(&MArea->Data.SectionData.RegionListHead,
3037                      ViewSize, 0, Protect);
3038
3039   return(STATUS_SUCCESS);
3040 }
3041
3042
3043 /**********************************************************************
3044  * NAME                                                 EXPORTED
3045  *      NtMapViewOfSection
3046  *
3047  * DESCRIPTION
3048  *      Maps a view of a section into the virtual address space of a 
3049  *      process.
3050  *      
3051  * ARGUMENTS
3052  *      SectionHandle
3053  *              Handle of the section.
3054  *              
3055  *      ProcessHandle
3056  *              Handle of the process.
3057  *              
3058  *      BaseAddress
3059  *              Desired base address (or NULL) on entry;
3060  *              Actual base address of the view on exit.
3061  *              
3062  *      ZeroBits
3063  *              Number of high order address bits that must be zero.
3064  *              
3065  *      CommitSize
3066  *              Size in bytes of the initially committed section of 
3067  *              the view.
3068  *              
3069  *      SectionOffset
3070  *              Offset in bytes from the beginning of the section
3071  *              to the beginning of the view.
3072  *              
3073  *      ViewSize
3074  *              Desired length of map (or zero to map all) on entry
3075  *              Actual length mapped on exit.
3076  *              
3077  *      InheritDisposition
3078  *              Specified how the view is to be shared with
3079  *              child processes.
3080  *              
3081  *      AllocateType
3082  *              Type of allocation for the pages.
3083  *              
3084  *      Protect
3085  *              Protection for the committed region of the view.
3086  *
3087  * RETURN VALUE
3088  *      Status.
3089  *
3090  * @implemented
3091  */
3092 NTSTATUS STDCALL
3093 NtMapViewOfSection(HANDLE SectionHandle,
3094                    HANDLE ProcessHandle,
3095                    PVOID* BaseAddress,
3096                    ULONG ZeroBits,
3097                    ULONG CommitSize,
3098                    PLARGE_INTEGER SectionOffset,
3099                    PULONG ViewSize,
3100                    SECTION_INHERIT InheritDisposition,
3101                    ULONG AllocationType,
3102                    ULONG Protect)
3103 {
3104    PSECTION_OBJECT Section;
3105    PEPROCESS Process;
3106    NTSTATUS Status;
3107    PMADDRESS_SPACE AddressSpace;
3108
3109    Status = ObReferenceObjectByHandle(ProcessHandle,
3110                                       PROCESS_VM_OPERATION,
3111                                       PsProcessType,
3112                                       UserMode,
3113                                       (PVOID*)&Process,
3114                                       NULL);
3115    if (!NT_SUCCESS(Status))
3116      {
3117         return(Status);
3118      }
3119    
3120    AddressSpace = &Process->AddressSpace;
3121    
3122    Status = ObReferenceObjectByHandle(SectionHandle,
3123                                       SECTION_MAP_READ,
3124                                       MmSectionObjectType,
3125                                       UserMode,
3126                                       (PVOID*)&Section,
3127                                       NULL);
3128    if (!(NT_SUCCESS(Status)))
3129      {
3130         DPRINT("ObReference failed rc=%x\n",Status);
3131         ObDereferenceObject(Process);
3132         return(Status);
3133      }
3134    
3135    Status = MmMapViewOfSection(Section,
3136                                Process,
3137                                BaseAddress,
3138                                ZeroBits,
3139                                CommitSize,
3140                                SectionOffset,
3141                                ViewSize,
3142                                InheritDisposition,
3143                                AllocationType,
3144                                Protect);
3145    
3146    ObDereferenceObject(Section);
3147    ObDereferenceObject(Process);
3148    
3149    return(Status);
3150 }
3151
3152 VOID STATIC
3153 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
3154                   PHYSICAL_ADDRESS PhysAddr, SWAPENTRY SwapEntry, 
3155                   BOOLEAN Dirty)
3156 {
3157   PMEMORY_AREA MArea;
3158   ULONG Entry;
3159   PFILE_OBJECT FileObject;
3160   PBCB Bcb;
3161   ULONG Offset;
3162   SWAPENTRY SavedSwapEntry;
3163   PMM_PAGEOP PageOp;
3164   LARGE_INTEGER Timeout;
3165   NTSTATUS Status;
3166   PSECTION_OBJECT Section;
3167   PMM_SECTION_SEGMENT Segment;
3168
3169   MArea = (PMEMORY_AREA)Context;
3170
3171   Address = (PVOID)PAGE_ROUND_DOWN(Address);
3172
3173   Offset = ((ULONG)Address - (ULONG)MArea->BaseAddress);
3174
3175   Section = MArea->Data.SectionData.Section;
3176   Segment = MArea->Data.SectionData.Segment;
3177
3178
3179   PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset);
3180   
3181   while (PageOp)
3182   {
3183      MmUnlockSectionSegment(Segment);
3184      MmUnlockAddressSpace(&MArea->Process->AddressSpace);
3185
3186      Timeout.QuadPart = -100000000LL;   // 10 sec
3187      Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
3188                                     0,
3189                                     KernelMode,
3190                                     FALSE,
3191                                     &Timeout);
3192      if (Status != STATUS_SUCCESS)
3193        {
3194          DPRINT1("Failed to wait for page op, status = %x\n", Status);
3195          KEBUGCHECK(0);
3196        }
3197
3198      MmLockAddressSpace(&MArea->Process->AddressSpace);
3199      MmLockSectionSegment(Segment);
3200      KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
3201      MmReleasePageOp(PageOp);
3202      PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset);
3203   }
3204
3205   Entry = MmGetPageEntrySectionSegment(Segment, Offset);
3206   
3207   /*
3208    * For a dirty, datafile, non-private page mark it as dirty in the
3209    * cache manager.
3210    */
3211   if (Segment->Flags & MM_DATAFILE_SEGMENT)
3212     {
3213       if (PhysAddr.QuadPart == PAGE_FROM_SSE(Entry) && Dirty)
3214         {
3215           FileObject = MemoryArea->Data.SectionData.Section->FileObject;
3216           Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
3217           CcRosMarkDirtyCacheSegment(Bcb, Offset);
3218           assert(SwapEntry == 0);
3219         }
3220     }
3221
3222   if (SwapEntry != 0)
3223     {
3224       /*
3225        * Sanity check
3226        */
3227       if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3228         {
3229           DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3230           KEBUGCHECK(0);
3231         }
3232       MmFreeSwapPage(SwapEntry);
3233     }
3234   else if (PhysAddr.QuadPart != 0)
3235     {      
3236       if (IS_SWAP_FROM_SSE(Entry) || 
3237           PhysAddr.QuadPart != (PAGE_FROM_SSE(Entry)))
3238         {
3239           /*
3240            * Sanity check
3241            */
3242           if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3243             {
3244               DPRINT1("Found a private page in a pagefile section.\n");
3245               KEBUGCHECK(0);
3246             }
3247           /*
3248            * Just dereference private pages
3249            */
3250           SavedSwapEntry = MmGetSavedSwapEntryPage(PhysAddr);
3251           if (SavedSwapEntry != 0)
3252             {
3253               MmFreeSwapPage(SavedSwapEntry);
3254               MmSetSavedSwapEntryPage(PhysAddr, 0);
3255             }
3256           MmDeleteRmap(PhysAddr, MArea->Process, Address);
3257           MmReleasePageMemoryConsumer(MC_USER, PhysAddr);
3258         }
3259       else
3260         {
3261           MmDeleteRmap(PhysAddr, MArea->Process, Address);
3262           MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty);
3263           MmReleasePageMemoryConsumer(MC_USER, PhysAddr);
3264         }
3265     }
3266 }
3267
3268 NTSTATUS
3269 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace,
3270                      PVOID BaseAddress)
3271 {
3272    NTSTATUS Status;
3273    PMEMORY_AREA MemoryArea;
3274    PSECTION_OBJECT Section;
3275    PMM_SECTION_SEGMENT Segment;
3276    KIRQL oldIrql;
3277    PLIST_ENTRY CurrentEntry;
3278    PMM_REGION CurrentRegion;
3279    PLIST_ENTRY RegionListHead;
3280
3281    MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
3282                                           BaseAddress);
3283    if (MemoryArea == NULL)
3284      {
3285         return(STATUS_UNSUCCESSFUL);
3286      }
3287
3288    MemoryArea->DeleteInProgress = TRUE;
3289    Section = MemoryArea->Data.SectionData.Section;
3290    Segment = MemoryArea->Data.SectionData.Segment;
3291    
3292    MmLockSectionSegment(Segment);
3293    KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
3294    RemoveEntryList(&MemoryArea->Data.SectionData.ViewListEntry);
3295    KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
3296
3297    RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
3298    while (!IsListEmpty(RegionListHead))
3299      {
3300        CurrentEntry = RemoveHeadList(RegionListHead);
3301        CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
3302        ExFreePool(CurrentRegion);
3303      }
3304
3305    if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
3306      {
3307        Status = MmFreeMemoryArea(AddressSpace,
3308                                  BaseAddress,
3309                                  0,
3310                                  NULL,
3311                                  NULL);
3312      }
3313    else
3314      {
3315        Status = MmFreeMemoryArea(AddressSpace,
3316                                  BaseAddress,
3317                                  0,
3318                                  MmFreeSectionPage,
3319                                  MemoryArea);
3320      }
3321    MmUnlockSectionSegment(Segment);
3322    ObDereferenceObject(Section);
3323    return(STATUS_SUCCESS);
3324 }
3325
3326 /*
3327  * @implemented
3328  */
3329 NTSTATUS STDCALL
3330 MmUnmapViewOfSection(PEPROCESS Process,
3331                      PVOID BaseAddress)
3332 {
3333    NTSTATUS     Status;
3334    PMEMORY_AREA MemoryArea;
3335    PMADDRESS_SPACE AddressSpace;
3336    PSECTION_OBJECT Section;
3337    
3338    DPRINT("Opening memory area Process %x BaseAddress %x\n",
3339           Process, BaseAddress);
3340
3341    assert(Process);
3342    
3343    AddressSpace = &Process->AddressSpace;
3344    MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
3345                                           BaseAddress);
3346    if (MemoryArea == NULL)
3347      {
3348         return(STATUS_UNSUCCESSFUL);
3349      }
3350
3351    Section = MemoryArea->Data.SectionData.Section;
3352
3353    if (Section->AllocationAttributes & SEC_IMAGE)
3354      {
3355        ULONG i;
3356        ULONG NrSegments;
3357        PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3358        PMM_SECTION_SEGMENT SectionSegments;
3359        PVOID ImageBaseAddress;
3360        PMM_SECTION_SEGMENT Segment;
3361    
3362        Segment = MemoryArea->Data.SectionData.Segment;
3363        ImageSectionObject = Section->ImageSection;
3364        SectionSegments = ImageSectionObject->Segments;
3365        NrSegments = ImageSectionObject->NrSegments;
3366
3367        /* Search for the current segment within the section segments 
3368         * and calculate the image base address */
3369        for (i = 0; i < NrSegments; i++)
3370          {
3371            if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3372              {
3373                if (Segment == &SectionSegments[i])
3374                  {
3375                    ImageBaseAddress = BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress;
3376                    break;
3377                  }
3378              }
3379          }
3380        if (i >= NrSegments)
3381          {
3382            KEBUGCHECK(0);
3383          }
3384
3385        for (i = 0; i < NrSegments; i++)
3386          {
3387            if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3388              {
3389                PVOID SBaseAddress = (PVOID)
3390                  (ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
3391
3392                Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
3393              }
3394          }
3395      }
3396    else
3397      {
3398        Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
3399      }
3400    return(STATUS_SUCCESS);
3401 }
3402
3403 /**********************************************************************
3404  * NAME                                                 EXPORTED
3405  *      NtUnmapViewOfSection
3406  *
3407  * DESCRIPTION
3408  *
3409  * ARGUMENTS
3410  *      ProcessHandle
3411  *
3412  *      BaseAddress
3413  *
3414  * RETURN VALUE
3415  *      Status.
3416  *
3417  * REVISIONS
3418  */
3419 NTSTATUS STDCALL
3420 NtUnmapViewOfSection (HANDLE    ProcessHandle,
3421                       PVOID     BaseAddress)
3422 {
3423    PEPROCESS    Process;
3424    NTSTATUS Status;
3425    
3426    DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3427            ProcessHandle, BaseAddress);
3428    
3429    DPRINT("Referencing process\n");
3430    Status = ObReferenceObjectByHandle(ProcessHandle,
3431                                       PROCESS_VM_OPERATION,
3432                                       PsProcessType,
3433                                       UserMode,
3434                                       (PVOID*)&Process,
3435                                       NULL);
3436    if (!NT_SUCCESS(Status))
3437      {
3438         DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
3439         return(Status);
3440      }
3441
3442    MmLockAddressSpace(&Process->AddressSpace);
3443    Status = MmUnmapViewOfSection(Process, BaseAddress);
3444    MmUnlockAddressSpace(&Process->AddressSpace);
3445
3446    ObDereferenceObject(Process);
3447
3448    return Status;
3449 }
3450
3451
3452 NTSTATUS STDCALL
3453 NtQuerySection (IN      HANDLE  SectionHandle,
3454                 IN      CINT    SectionInformationClass,
3455                 OUT     PVOID   SectionInformation,
3456                 IN      ULONG   Length, 
3457                 OUT     PULONG  ResultLength)
3458 /*
3459  * FUNCTION: Queries the information of a section object.
3460  * ARGUMENTS: 
3461  *        SectionHandle = Handle to the section link object
3462  *        SectionInformationClass = Index to a certain information structure
3463  *        SectionInformation (OUT)= Caller supplies storage for resulting 
3464  *                                  information
3465  *        Length =  Size of the supplied storage 
3466  *        ResultLength = Data written
3467  * RETURNS: Status
3468  *
3469  */
3470 {
3471   PSECTION_OBJECT Section;
3472   NTSTATUS Status;
3473
3474   Status = ObReferenceObjectByHandle(SectionHandle,
3475                                      SECTION_MAP_READ,
3476                                      MmSectionObjectType,
3477                                      UserMode,
3478                                      (PVOID*)&Section,
3479                                      NULL);
3480   if (!(NT_SUCCESS(Status)))
3481     {
3482       return(Status);
3483     }
3484
3485   switch (SectionInformationClass)
3486     {
3487     case SectionBasicInformation:
3488       {
3489         PSECTION_BASIC_INFORMATION Sbi;
3490
3491         if (Length != sizeof(SECTION_BASIC_INFORMATION))
3492           {
3493             ObDereferenceObject(Section);
3494             return(STATUS_INFO_LENGTH_MISMATCH);
3495           }
3496
3497         Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
3498         
3499         Sbi->BaseAddress = 0;
3500         Sbi->Attributes = 0;
3501         Sbi->Size.QuadPart = 0;
3502
3503         *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
3504         Status = STATUS_SUCCESS;
3505         break;
3506       }
3507
3508       case SectionImageInformation:
3509         {
3510           PSECTION_IMAGE_INFORMATION Sii;
3511
3512           if (Length != sizeof(SECTION_IMAGE_INFORMATION))
3513             {
3514               ObDereferenceObject(Section);
3515               return(STATUS_INFO_LENGTH_MISMATCH);
3516             }
3517           
3518           Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation; 
3519           memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
3520           if (Section->AllocationAttributes & SEC_IMAGE)
3521             {
3522               PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3523               ImageSectionObject = Section->ImageSection;
3524               
3525               Sii->EntryPoint = ImageSectionObject->EntryPoint;
3526               Sii->StackReserve = ImageSectionObject->StackReserve;
3527               Sii->StackCommit = ImageSectionObject->StackCommit;
3528               Sii->Subsystem = ImageSectionObject->Subsystem;
3529               Sii->MinorSubsystemVersion = ImageSectionObject->MinorSubsystemVersion;
3530               Sii->MajorSubsystemVersion = ImageSectionObject->MajorSubsystemVersion;
3531               Sii->Characteristics = ImageSectionObject->ImageCharacteristics;
3532               Sii->ImageNumber = ImageSectionObject->Machine;
3533               Sii->Executable = ImageSectionObject->Executable;
3534             }
3535           *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
3536           Status = STATUS_SUCCESS;
3537           break;
3538         }
3539
3540     default:
3541       *ResultLength = 0;
3542       Status = STATUS_INVALID_INFO_CLASS;
3543     }
3544   ObDereferenceObject(Section);
3545   return(Status);
3546 }
3547
3548
3549 NTSTATUS STDCALL 
3550 NtExtendSection(IN      HANDLE  SectionHandle,
3551                 IN      ULONG   NewMaximumSize)
3552 {
3553    UNIMPLEMENTED;
3554    return(STATUS_NOT_IMPLEMENTED);
3555 }
3556
3557
3558 /**********************************************************************
3559  * NAME                                                 INTERNAL
3560  *      MmAllocateSection@4
3561  *
3562  * DESCRIPTION
3563  *
3564  * ARGUMENTS
3565  *      Length
3566  *
3567  * RETURN VALUE
3568  *
3569  * NOTE
3570  *      Code taken from ntoskrnl/mm/special.c.
3571  *
3572  * REVISIONS
3573  */
3574 PVOID STDCALL 
3575 MmAllocateSection (IN ULONG Length)
3576 {
3577    PVOID Result;
3578    MEMORY_AREA* marea;
3579    NTSTATUS Status;
3580    ULONG i;
3581    PMADDRESS_SPACE AddressSpace;
3582    
3583    DPRINT("MmAllocateSection(Length %x)\n",Length);
3584    
3585    AddressSpace = MmGetKernelAddressSpace();
3586    Result = NULL;
3587    MmLockAddressSpace(AddressSpace);
3588    Status = MmCreateMemoryArea (NULL,
3589                                 AddressSpace,
3590                                 MEMORY_AREA_SYSTEM,
3591                                 &Result,
3592                                 Length,
3593                                 0,
3594                                 &marea,
3595                                 FALSE,
3596                                 FALSE);
3597    if (!NT_SUCCESS(Status))
3598      {
3599         MmUnlockAddressSpace(AddressSpace);
3600         return (NULL);
3601      }
3602    MmUnlockAddressSpace(AddressSpace);
3603    DPRINT("Result %p\n",Result);
3604    for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
3605      {
3606        PHYSICAL_ADDRESS Page;
3607
3608        Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page);
3609        if (!NT_SUCCESS(Status))
3610          {
3611            DbgPrint("Unable to allocate page\n");
3612            KEBUGCHECK(0);
3613          }
3614        Status = MmCreateVirtualMapping (NULL,
3615                                         (Result + (i * PAGE_SIZE)),
3616                                         PAGE_READWRITE,
3617                                         Page,
3618                                         TRUE);
3619        if (!NT_SUCCESS(Status))
3620          {
3621            DbgPrint("Unable to create virtual mapping\n");
3622            KEBUGCHECK(0);
3623          }
3624      }
3625    return ((PVOID)Result);
3626 }
3627
3628
3629 /**********************************************************************
3630  * NAME                                                 EXPORTED
3631  *      MmMapViewOfSection
3632  *
3633  * DESCRIPTION
3634  *      Maps a view of a section into the virtual address space of a 
3635  *      process.
3636  *      
3637  * ARGUMENTS
3638  *      Section
3639  *              Pointer to the section object.
3640  *              
3641  *      ProcessHandle
3642  *              Pointer to the process.
3643  *              
3644  *      BaseAddress
3645  *              Desired base address (or NULL) on entry;
3646  *              Actual base address of the view on exit.
3647  *              
3648  *      ZeroBits
3649  *              Number of high order address bits that must be zero.
3650  *              
3651  *      CommitSize
3652  *              Size in bytes of the initially committed section of 
3653  *              the view.
3654  *              
3655  *      SectionOffset
3656  *              Offset in bytes from the beginning of the section
3657  *              to the beginning of the view.
3658  *              
3659  *      ViewSize
3660  *              Desired length of map (or zero to map all) on entry
3661  *              Actual length mapped on exit.
3662  *              
3663  *      InheritDisposition
3664  *              Specified how the view is to be shared with
3665  *              child processes.
3666  *              
3667  *      AllocationType
3668  *              Type of allocation for the pages.
3669  *              
3670  *      Protect
3671  *              Protection for the committed region of the view.
3672  *
3673  * RETURN VALUE
3674  *      Status.
3675  *
3676  * @implemented
3677  */
3678 NTSTATUS STDCALL
3679 MmMapViewOfSection(IN PVOID SectionObject,
3680                    IN PEPROCESS Process,
3681                    IN OUT PVOID *BaseAddress,
3682                    IN ULONG ZeroBits,
3683                    IN ULONG CommitSize,
3684                    IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
3685                    IN OUT PULONG ViewSize,
3686                    IN SECTION_INHERIT InheritDisposition,
3687                    IN ULONG AllocationType,
3688                    IN ULONG Protect)
3689 {
3690    PSECTION_OBJECT Section;
3691    PMADDRESS_SPACE AddressSpace;
3692    ULONG ViewOffset;
3693    NTSTATUS Status = STATUS_SUCCESS;
3694
3695    assert(Process);
3696
3697    Section = (PSECTION_OBJECT)SectionObject;
3698    AddressSpace = &Process->AddressSpace;
3699
3700    MmLockAddressSpace(AddressSpace);
3701
3702    if (Section->AllocationAttributes & SEC_IMAGE)
3703      {
3704        ULONG i;
3705        ULONG NrSegments;
3706        PVOID ImageBase;
3707        ULONG ImageSize;
3708        PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3709        PMM_SECTION_SEGMENT SectionSegments;
3710
3711        ImageSectionObject = Section->ImageSection;
3712        SectionSegments = ImageSectionObject->Segments;
3713        NrSegments = ImageSectionObject->NrSegments;
3714
3715
3716        ImageBase = *BaseAddress;
3717        if (ImageBase == NULL)
3718          {
3719            ImageBase = ImageSectionObject->ImageBase;
3720          }
3721
3722        ImageSize = 0;
3723        for (i = 0; i < NrSegments; i++)
3724          {
3725            if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3726              {
3727                ULONG MaxExtent;
3728                MaxExtent = (ULONG)(SectionSegments[i].VirtualAddress +
3729                                    SectionSegments[i].Length);
3730                ImageSize = max(ImageSize, MaxExtent);
3731              }
3732          }
3733
3734        /* Check there is enough space to map the section at that point. */
3735        if (MmOpenMemoryAreaByRegion(AddressSpace, ImageBase, 
3736                                     PAGE_ROUND_UP(ImageSize)) != NULL)
3737          {
3738            /* Fail if the user requested a fixed base address. */
3739            if ((*BaseAddress) != NULL)
3740              {
3741                MmUnlockAddressSpace(AddressSpace);
3742                return(STATUS_UNSUCCESSFUL);
3743              }
3744            /* Otherwise find a gap to map the image. */
3745            ImageBase = MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), FALSE);
3746            if (ImageBase == NULL)
3747              {
3748                MmUnlockAddressSpace(AddressSpace);
3749                return(STATUS_UNSUCCESSFUL);
3750              }
3751          }
3752
3753        for (i = 0; i < NrSegments; i++)
3754          {
3755            PVOID SBaseAddress;
3756
3757            if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3758              {
3759                SBaseAddress = (PVOID)
3760                  (ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
3761                MmLockSectionSegment(&SectionSegments[i]);
3762                Status = MmMapViewOfSegment(Process,
3763                                            AddressSpace,
3764                                            Section,
3765                                            &SectionSegments[i],
3766                                            &SBaseAddress,
3767                                            SectionSegments[i].Length,
3768                                            SectionSegments[i].Protection,
3769                                            (ULONG_PTR)SectionSegments[i].VirtualAddress,
3770                                            FALSE);
3771                MmUnlockSectionSegment(&SectionSegments[i]);
3772                if (!NT_SUCCESS(Status))
3773                  {
3774                    MmUnlockAddressSpace(AddressSpace);
3775                    return(Status);
3776                  }
3777              }
3778          }
3779
3780        *BaseAddress = ImageBase;
3781      }
3782    else
3783      {
3784        if (SectionOffset == NULL)
3785          {
3786            ViewOffset = 0;
3787          }
3788        else
3789          {
3790            ViewOffset = SectionOffset->u.LowPart;
3791          }
3792
3793        if ((ViewOffset % PAGE_SIZE) != 0)
3794          {
3795            MmUnlockAddressSpace(AddressSpace);
3796            return(STATUS_MAPPED_ALIGNMENT);
3797          }
3798
3799        if ((*ViewSize) == 0)
3800          {
3801            (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3802          }
3803        else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
3804          {
3805            (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3806          }
3807
3808        MmLockSectionSegment(Section->Segment);
3809        Status = MmMapViewOfSegment(Process,
3810                                    AddressSpace,
3811                                    Section,
3812                                    Section->Segment,
3813                                    BaseAddress,
3814                                    *ViewSize,
3815                                    Protect,
3816                                    ViewOffset,
3817                                    (AllocationType & MEM_TOP_DOWN));
3818        MmUnlockSectionSegment(Section->Segment);
3819        if (!NT_SUCCESS(Status))
3820          {
3821            MmUnlockAddressSpace(AddressSpace);
3822            return(Status);
3823          }
3824      }
3825
3826    MmUnlockAddressSpace(AddressSpace);
3827
3828    return(STATUS_SUCCESS);
3829 }
3830
3831 /*
3832  * @unimplemented
3833  */
3834 BOOLEAN STDCALL
3835 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS       SectionObjectPointer,
3836                       IN PLARGE_INTEGER                 NewFileSize)
3837 {
3838   UNIMPLEMENTED;
3839   return (FALSE);
3840 }
3841
3842
3843 /*
3844  * @unimplemented
3845  */
3846 BOOLEAN STDCALL
3847 MmDisableModifiedWriteOfSection (DWORD  Unknown0)
3848 {
3849   UNIMPLEMENTED;
3850   return (FALSE);
3851 }
3852
3853 /*
3854  * @implemented
3855  */
3856 BOOLEAN STDCALL
3857 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS        SectionObjectPointer,
3858                      IN MMFLUSH_TYPE                    FlushType)
3859 {
3860    switch(FlushType)
3861    {
3862       case MmFlushForDelete: 
3863          if (SectionObjectPointer->ImageSectionObject || 
3864              SectionObjectPointer->DataSectionObject)
3865          {
3866             return FALSE;
3867          }
3868          CcRosSetRemoveOnClose(SectionObjectPointer);
3869          return TRUE;
3870       case MmFlushForWrite:
3871          break;
3872    }
3873    return FALSE;
3874 }
3875
3876 /*
3877  * @unimplemented
3878  */
3879 BOOLEAN STDCALL
3880 MmForceSectionClosed (DWORD     Unknown0,
3881                       DWORD     Unknown1)
3882 {
3883   UNIMPLEMENTED;
3884   return (FALSE);
3885 }
3886
3887
3888 /*
3889  * @implemented
3890  */
3891 NTSTATUS STDCALL
3892 MmMapViewInSystemSpace (IN      PVOID   SectionObject,
3893                         OUT     PVOID   * MappedBase,
3894                         IN OUT  PULONG  ViewSize)
3895 {
3896   PSECTION_OBJECT Section;
3897   PMADDRESS_SPACE AddressSpace;
3898   NTSTATUS Status;
3899
3900   DPRINT("MmMapViewInSystemSpace() called\n");
3901
3902   Section = (PSECTION_OBJECT)SectionObject;
3903   AddressSpace = MmGetKernelAddressSpace();
3904
3905   MmLockAddressSpace(AddressSpace);
3906
3907   
3908   if ((*ViewSize) == 0)
3909     {
3910       (*ViewSize) = Section->MaximumSize.u.LowPart;
3911     }
3912   else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
3913     {
3914       (*ViewSize) = Section->MaximumSize.u.LowPart;
3915     }
3916
3917   MmLockSectionSegment(Section->Segment);
3918
3919
3920   Status = MmMapViewOfSegment(NULL,
3921                               AddressSpace,
3922                               Section,
3923                               Section->Segment,
3924                               MappedBase,
3925                               *ViewSize,
3926                               PAGE_READWRITE,
3927                               0,
3928                               FALSE);
3929
3930   MmUnlockSectionSegment(Section->Segment);
3931   MmUnlockAddressSpace(AddressSpace);
3932
3933   return Status;
3934 }
3935
3936
3937 /*
3938  * @implemented
3939  */
3940 NTSTATUS STDCALL
3941 MmUnmapViewInSystemSpace (IN    PVOID   MappedBase)
3942 {
3943   PMADDRESS_SPACE AddressSpace;
3944   NTSTATUS Status;
3945
3946   DPRINT("MmUnmapViewInSystemSpace() called\n");
3947
3948   AddressSpace = MmGetKernelAddressSpace();
3949
3950   Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
3951
3952   return Status;
3953 }
3954
3955
3956 /*
3957  * @unimplemented
3958  */
3959 NTSTATUS STDCALL
3960 MmSetBankedSection (DWORD       Unknown0,
3961                     DWORD       Unknown1,
3962                     DWORD       Unknown2,
3963                     DWORD       Unknown3,
3964                     DWORD       Unknown4,
3965                     DWORD       Unknown5)
3966 {
3967   UNIMPLEMENTED;
3968   return (STATUS_NOT_IMPLEMENTED);
3969 }
3970
3971
3972 /**********************************************************************
3973  * NAME                                                 EXPORTED
3974  *      MmCreateSection@
3975  *      
3976  * DESCRIPTION
3977  *      Creates a section object.
3978  *      
3979  * ARGUMENTS
3980  *      SectionObjiect (OUT)
3981  *              Caller supplied storage for the resulting pointer
3982  *              to a SECTION_OBJECT instance;
3983  *              
3984  *      DesiredAccess
3985  *              Specifies the desired access to the section can be a
3986  *              combination of:
3987  *                      STANDARD_RIGHTS_REQUIRED        |
3988  *                      SECTION_QUERY                   |
3989  *                      SECTION_MAP_WRITE               |
3990  *                      SECTION_MAP_READ                |
3991  *                      SECTION_MAP_EXECUTE
3992  *                      
3993  *      ObjectAttributes [OPTIONAL]
3994  *              Initialized attributes for the object can be used 
3995  *              to create a named section;
3996  *
3997  *      MaximumSize
3998  *              Maximizes the size of the memory section. Must be 
3999  *              non-NULL for a page-file backed section. 
4000  *              If value specified for a mapped file and the file is 
4001  *              not large enough, file will be extended.
4002  *              
4003  *      SectionPageProtection
4004  *              Can be a combination of:
4005  *                      PAGE_READONLY   | 
4006  *                      PAGE_READWRITE  |
4007  *                      PAGE_WRITEONLY  | 
4008  *                      PAGE_WRITECOPY
4009  *                      
4010  *      AllocationAttributes
4011  *              Can be a combination of:
4012  *                      SEC_IMAGE       | 
4013  *                      SEC_RESERVE
4014  *                      
4015  *      FileHandle
4016  *              Handle to a file to create a section mapped to a file
4017  *              instead of a memory backed section;
4018  *
4019  *      File
4020  *              Unknown.
4021  *      
4022  * RETURN VALUE
4023  *      Status.
4024  *
4025  * @unimplemented
4026  */
4027 NTSTATUS STDCALL
4028 MmCreateSection (OUT    PSECTION_OBJECT         * SectionObject,
4029                  IN     ACCESS_MASK             DesiredAccess,
4030                  IN     POBJECT_ATTRIBUTES      ObjectAttributes     OPTIONAL,
4031                  IN     PLARGE_INTEGER          MaximumSize,
4032                  IN     ULONG                   SectionPageProtection,
4033                  IN     ULONG                   AllocationAttributes,
4034                  IN     HANDLE                  FileHandle        OPTIONAL,
4035                  IN     PFILE_OBJECT            File                OPTIONAL)
4036 {
4037   return (STATUS_NOT_IMPLEMENTED);
4038 }
4039
4040 /* EOF */