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