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