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