xref: /reactos/ntoskrnl/mm/section.c (revision cc439606)
1 /*
2  * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  *
18  *
19  * PROJECT:         ReactOS kernel
20  * FILE:            ntoskrnl/mm/section.c
21  * PURPOSE:         Implements section objects
22  *
23  * PROGRAMMERS:     Rex Jolliff
24  *                  David Welch
25  *                  Eric Kohl
26  *                  Emanuele Aliberti
27  *                  Eugene Ingerman
28  *                  Casper Hornstrup
29  *                  KJK::Hyperion
30  *                  Guido de Jong
31  *                  Ge van Geldorp
32  *                  Royce Mitchell III
33  *                  Filip Navara
34  *                  Aleksey Bragin
35  *                  Jason Filby
36  *                  Thomas Weidenmueller
37  *                  Gunnar Andre' Dalsnes
38  *                  Mike Nordell
39  *                  Alex Ionescu
40  *                  Gregor Anich
41  *                  Steven Edwards
42  *                  Herve Poussineau
43  */
44 
45 /* INCLUDES *****************************************************************/
46 
47 #include <ntoskrnl.h>
48 #include <cache/newcc.h>
49 #include <cache/section/newmm.h>
50 #define NDEBUG
51 #include <debug.h>
52 #include <reactos/exeformat.h>
53 
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
57 #endif
58 
59 #include "ARM3/miarm.h"
60 
61 #undef MmSetPageEntrySectionSegment
62 #define MmSetPageEntrySectionSegment(S,O,E) do { \
63         DPRINT("SetPageEntrySectionSegment(old,%p,%x,%x)\n",(S),(O)->LowPart,E); \
64         _MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__);   \
65 	} while (0)
66 
67 extern MMSESSION MmSession;
68 
69 NTSTATUS
70 NTAPI
71 MiMapViewInSystemSpace(IN PVOID Section,
72                        IN PVOID Session,
73                        OUT PVOID *MappedBase,
74                        IN OUT PSIZE_T ViewSize);
75 
76 NTSTATUS
77 NTAPI
78 MmCreateArm3Section(OUT PVOID *SectionObject,
79                     IN ACCESS_MASK DesiredAccess,
80                     IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
81                     IN PLARGE_INTEGER InputMaximumSize,
82                     IN ULONG SectionPageProtection,
83                     IN ULONG AllocationAttributes,
84                     IN HANDLE FileHandle OPTIONAL,
85                     IN PFILE_OBJECT FileObject OPTIONAL);
86 
87 NTSTATUS
88 NTAPI
89 MmMapViewOfArm3Section(IN PVOID SectionObject,
90                        IN PEPROCESS Process,
91                        IN OUT PVOID *BaseAddress,
92                        IN ULONG_PTR ZeroBits,
93                        IN SIZE_T CommitSize,
94                        IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
95                        IN OUT PSIZE_T ViewSize,
96                        IN SECTION_INHERIT InheritDisposition,
97                        IN ULONG AllocationType,
98                        IN ULONG Protect);
99 
100 //
101 // PeFmtCreateSection depends on the following:
102 //
103 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE >= sizeof(IMAGE_DOS_HEADER));
104 C_ASSERT(sizeof(IMAGE_NT_HEADERS32) <= sizeof(IMAGE_NT_HEADERS64));
105 
106 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64));
107 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64, FileHeader));
108 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader) == FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader));
109 
110 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Magic));
111 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SectionAlignment));
112 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, FileAlignment));
113 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Subsystem));
114 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MinorSubsystemVersion));
115 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MajorSubsystemVersion));
116 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint));
117 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode));
118 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfHeaders));
119 
120 /* TYPES *********************************************************************/
121 
122 typedef struct
123 {
124     PROS_SECTION_OBJECT Section;
125     PMM_SECTION_SEGMENT Segment;
126     LARGE_INTEGER Offset;
127     BOOLEAN WasDirty;
128     BOOLEAN Private;
129     PEPROCESS CallingProcess;
130     ULONG_PTR SectionEntry;
131 }
132 MM_SECTION_PAGEOUT_CONTEXT;
133 
134 /* GLOBALS *******************************************************************/
135 
136 POBJECT_TYPE MmSectionObjectType = NULL;
137 
138 ULONG_PTR MmSubsectionBase;
139 
140 static ULONG SectionCharacteristicsToProtect[16] =
141 {
142     PAGE_NOACCESS,          /* 0 = NONE */
143     PAGE_NOACCESS,          /* 1 = SHARED */
144     PAGE_EXECUTE,           /* 2 = EXECUTABLE */
145     PAGE_EXECUTE,           /* 3 = EXECUTABLE, SHARED */
146     PAGE_READONLY,          /* 4 = READABLE */
147     PAGE_READONLY,          /* 5 = READABLE, SHARED */
148     PAGE_EXECUTE_READ,      /* 6 = READABLE, EXECUTABLE */
149     PAGE_EXECUTE_READ,      /* 7 = READABLE, EXECUTABLE, SHARED */
150     /*
151      * FIXME? do we really need the WriteCopy field in segments? can't we use
152      * PAGE_WRITECOPY here?
153      */
154     PAGE_READWRITE,         /* 8 = WRITABLE */
155     PAGE_READWRITE,         /* 9 = WRITABLE, SHARED */
156     PAGE_EXECUTE_READWRITE, /* 10 = WRITABLE, EXECUTABLE */
157     PAGE_EXECUTE_READWRITE, /* 11 = WRITABLE, EXECUTABLE, SHARED */
158     PAGE_READWRITE,         /* 12 = WRITABLE, READABLE */
159     PAGE_READWRITE,         /* 13 = WRITABLE, READABLE, SHARED */
160     PAGE_EXECUTE_READWRITE, /* 14 = WRITABLE, READABLE, EXECUTABLE */
161     PAGE_EXECUTE_READWRITE, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
162 };
163 
164 extern ULONG MmMakeFileAccess [];
165 ACCESS_MASK NTAPI MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection);
166 static GENERIC_MAPPING MmpSectionMapping =
167 {
168     STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
169     STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
170     STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
171     SECTION_ALL_ACCESS
172 };
173 
174 
175 /* FUNCTIONS *****************************************************************/
176 
177 
178 /*
179  References:
180   [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
181       File Format Specification", revision 6.0 (February 1999)
182 */
183 NTSTATUS NTAPI PeFmtCreateSection(IN CONST VOID * FileHeader,
184                                   IN SIZE_T FileHeaderSize,
185                                   IN PVOID File,
186                                   OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
187                                   OUT PULONG Flags,
188                                   IN PEXEFMT_CB_READ_FILE ReadFileCb,
189                                   IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb)
190 {
191     NTSTATUS nStatus;
192     ULONG cbFileHeaderOffsetSize = 0;
193     ULONG cbSectionHeadersOffset = 0;
194     ULONG cbSectionHeadersSize;
195     ULONG cbSectionHeadersOffsetSize = 0;
196     ULONG cbOptHeaderSize;
197     ULONG cbHeadersSize = 0;
198     ULONG nSectionAlignment;
199     ULONG nFileAlignment;
200     ULONG_PTR ImageBase;
201     const IMAGE_DOS_HEADER * pidhDosHeader;
202     const IMAGE_NT_HEADERS32 * pinhNtHeader;
203     const IMAGE_OPTIONAL_HEADER32 * piohOptHeader;
204     const IMAGE_SECTION_HEADER * pishSectionHeaders;
205     PMM_SECTION_SEGMENT pssSegments;
206     LARGE_INTEGER lnOffset;
207     PVOID pBuffer;
208     SIZE_T nPrevVirtualEndOfSegment = 0;
209     ULONG nFileSizeOfHeaders = 0;
210     ULONG i;
211     ULONG AlignedLength;
212 
213     ASSERT(FileHeader);
214     ASSERT(FileHeaderSize > 0);
215     ASSERT(File);
216     ASSERT(ImageSectionObject);
217     ASSERT(ReadFileCb);
218     ASSERT(AllocateSegmentsCb);
219 
220     ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize));
221 
222     ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0);
223 
224 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
225 
226     pBuffer = NULL;
227     pidhDosHeader = FileHeader;
228 
229     /* DOS HEADER */
230     nStatus = STATUS_ROS_EXEFMT_UNKNOWN_FORMAT;
231 
232     /* image too small to be an MZ executable */
233     if(FileHeaderSize < sizeof(IMAGE_DOS_HEADER))
234         DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize));
235 
236     /* no MZ signature */
237     if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
238         DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic));
239 
240     /* NT HEADER */
241     nStatus = STATUS_INVALID_IMAGE_PROTECT;
242 
243     /* not a Windows executable */
244     if(pidhDosHeader->e_lfanew <= 0)
245         DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew));
246 
247     if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize, pidhDosHeader->e_lfanew, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader)))
248         DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
249 
250     if(FileHeaderSize < cbFileHeaderOffsetSize)
251         pinhNtHeader = NULL;
252     else
253     {
254         /*
255          * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
256          * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
257          */
258         ASSERT(Intsafe_CanOffsetPointer(FileHeader, pidhDosHeader->e_lfanew));
259         pinhNtHeader = (PVOID)((UINT_PTR)FileHeader + pidhDosHeader->e_lfanew);
260     }
261 
262     /*
263      * the buffer doesn't contain the NT file header, or the alignment is wrong: we
264      * need to read the header from the file
265      */
266     if(FileHeaderSize < cbFileHeaderOffsetSize ||
267             (UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
268     {
269         ULONG cbNtHeaderSize;
270         ULONG cbReadSize;
271         PVOID pData;
272 
273 l_ReadHeaderFromFile:
274         cbNtHeaderSize = 0;
275         lnOffset.QuadPart = pidhDosHeader->e_lfanew;
276 
277         /* read the header from the file */
278         nStatus = ReadFileCb(File, &lnOffset, sizeof(IMAGE_NT_HEADERS64), &pData, &pBuffer, &cbReadSize);
279 
280         if(!NT_SUCCESS(nStatus))
281         {
282             NTSTATUS ReturnedStatus = nStatus;
283 
284             /* If it attempted to read past the end of the file, it means e_lfanew is invalid */
285             if (ReturnedStatus == STATUS_END_OF_FILE) nStatus = STATUS_INVALID_IMAGE_PROTECT;
286 
287             DIE(("ReadFile failed, status %08X\n", ReturnedStatus));
288         }
289 
290         ASSERT(pData);
291         ASSERT(pBuffer);
292         ASSERT(cbReadSize > 0);
293 
294         nStatus = STATUS_INVALID_IMAGE_FORMAT;
295 
296         /* the buffer doesn't contain the file header */
297         if(cbReadSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader))
298             DIE(("The file doesn't contain the PE file header\n"));
299 
300         pinhNtHeader = pData;
301 
302         /* object still not aligned: copy it to the beginning of the buffer */
303         if((UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
304         {
305             ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == 0);
306             RtlMoveMemory(pBuffer, pData, cbReadSize);
307             pinhNtHeader = pBuffer;
308         }
309 
310         /* invalid NT header */
311         nStatus = STATUS_INVALID_IMAGE_PROTECT;
312 
313         if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
314             DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
315 
316         nStatus = STATUS_INVALID_IMAGE_FORMAT;
317 
318         if(!Intsafe_AddULong32(&cbNtHeaderSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
319             DIE(("The full NT header is too large\n"));
320 
321         /* the buffer doesn't contain the whole NT header */
322         if(cbReadSize < cbNtHeaderSize)
323             DIE(("The file doesn't contain the full NT header\n"));
324     }
325     else
326     {
327         ULONG cbOptHeaderOffsetSize = 0;
328 
329         nStatus = STATUS_INVALID_IMAGE_PROTECT;
330 
331         /* don't trust an invalid NT header */
332         if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
333             DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
334 
335         if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
336             DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
337 
338         nStatus = STATUS_INVALID_IMAGE_FORMAT;
339 
340         if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, cbOptHeaderOffsetSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
341             DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader->FileHeader.SizeOfOptionalHeader));
342 
343         /* the buffer doesn't contain the whole NT header: read it from the file */
344         if(cbOptHeaderOffsetSize > FileHeaderSize)
345             goto l_ReadHeaderFromFile;
346     }
347 
348     /* read information from the NT header */
349     piohOptHeader = &pinhNtHeader->OptionalHeader;
350     cbOptHeaderSize = pinhNtHeader->FileHeader.SizeOfOptionalHeader;
351 
352     nStatus = STATUS_INVALID_IMAGE_FORMAT;
353 
354     if(!RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Magic))
355         DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize));
356 
357     /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
358 
359     switch(piohOptHeader->Magic)
360     {
361     case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
362 #ifdef _WIN64
363     case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
364 #endif // _WIN64
365         break;
366 
367     default:
368         DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader->Magic));
369     }
370 
371     if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SectionAlignment) &&
372             RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, FileAlignment))
373     {
374         /* See [1], section 3.4.2 */
375         if(piohOptHeader->SectionAlignment < PAGE_SIZE)
376         {
377             if(piohOptHeader->FileAlignment != piohOptHeader->SectionAlignment)
378                 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
379         }
380         else if(piohOptHeader->SectionAlignment < piohOptHeader->FileAlignment)
381             DIE(("The section alignment is smaller than the file alignment\n"));
382 
383         nSectionAlignment = piohOptHeader->SectionAlignment;
384         nFileAlignment = piohOptHeader->FileAlignment;
385 
386         if(!IsPowerOf2(nSectionAlignment) || !IsPowerOf2(nFileAlignment))
387             DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment, nFileAlignment));
388     }
389     else
390     {
391         nSectionAlignment = PAGE_SIZE;
392         nFileAlignment = PAGE_SIZE;
393     }
394 
395     ASSERT(IsPowerOf2(nSectionAlignment));
396     ASSERT(IsPowerOf2(nFileAlignment));
397 
398     switch(piohOptHeader->Magic)
399     {
400     /* PE32 */
401     case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
402     {
403         if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, ImageBase))
404             ImageBase = piohOptHeader->ImageBase;
405 
406         if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfImage))
407             ImageSectionObject->ImageInformation.ImageFileSize = piohOptHeader->SizeOfImage;
408 
409         if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackReserve))
410             ImageSectionObject->ImageInformation.MaximumStackSize = piohOptHeader->SizeOfStackReserve;
411 
412         if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackCommit))
413             ImageSectionObject->ImageInformation.CommittedStackSize = piohOptHeader->SizeOfStackCommit;
414 
415         if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Subsystem))
416         {
417             ImageSectionObject->ImageInformation.SubSystemType = piohOptHeader->Subsystem;
418 
419             if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MinorSubsystemVersion) &&
420                     RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MajorSubsystemVersion))
421             {
422                 ImageSectionObject->ImageInformation.SubSystemMinorVersion = piohOptHeader->MinorSubsystemVersion;
423                 ImageSectionObject->ImageInformation.SubSystemMajorVersion = piohOptHeader->MajorSubsystemVersion;
424             }
425         }
426 
427         if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
428         {
429             ImageSectionObject->ImageInformation.TransferAddress = (PVOID) (ImageBase +
430                     piohOptHeader->AddressOfEntryPoint);
431         }
432 
433         if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfCode))
434             ImageSectionObject->ImageInformation.ImageContainsCode = piohOptHeader->SizeOfCode != 0;
435         else
436             ImageSectionObject->ImageInformation.ImageContainsCode = TRUE;
437 
438         if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
439         {
440             if (piohOptHeader->AddressOfEntryPoint == 0)
441             {
442                 ImageSectionObject->ImageInformation.ImageContainsCode = FALSE;
443             }
444         }
445 
446         if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, LoaderFlags))
447             ImageSectionObject->ImageInformation.LoaderFlags = piohOptHeader->LoaderFlags;
448 
449         if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, DllCharacteristics))
450         {
451             ImageSectionObject->ImageInformation.DllCharacteristics = piohOptHeader->DllCharacteristics;
452 
453             /*
454              * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
455              * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
456              * magic to any binary.
457              *
458              * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
459              * but honestly that's not tested. It will also break them when running no ReactOS once we implement
460              * the SxS support -- at which point, duh, this should be removed.
461              *
462              * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
463              */
464             ImageSectionObject->ImageInformation.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION;
465         }
466 
467         break;
468     }
469 #ifdef _WIN64
470     /* PE64 */
471     case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
472     {
473         const IMAGE_OPTIONAL_HEADER64 * pioh64OptHeader;
474 
475         pioh64OptHeader = (const IMAGE_OPTIONAL_HEADER64 *)piohOptHeader;
476 
477         if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, ImageBase))
478         {
479             ImageBase = pioh64OptHeader->ImageBase;
480             if(pioh64OptHeader->ImageBase > MAXULONG_PTR)
481                 DIE(("ImageBase exceeds the address space\n"));
482         }
483 
484         if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfImage))
485         {
486             if(pioh64OptHeader->SizeOfImage > MAXULONG_PTR)
487                 DIE(("SizeOfImage exceeds the address space\n"));
488 
489             ImageSectionObject->ImageInformation.ImageFileSize = pioh64OptHeader->SizeOfImage;
490         }
491 
492         if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackReserve))
493         {
494             if(pioh64OptHeader->SizeOfStackReserve > MAXULONG_PTR)
495                 DIE(("SizeOfStackReserve exceeds the address space\n"));
496 
497             ImageSectionObject->ImageInformation.MaximumStackSize = (ULONG_PTR) pioh64OptHeader->SizeOfStackReserve;
498         }
499 
500         if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackCommit))
501         {
502             if(pioh64OptHeader->SizeOfStackCommit > MAXULONG_PTR)
503                 DIE(("SizeOfStackCommit exceeds the address space\n"));
504 
505             ImageSectionObject->ImageInformation.CommittedStackSize = (ULONG_PTR) pioh64OptHeader->SizeOfStackCommit;
506         }
507 
508         if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, Subsystem))
509         {
510             ImageSectionObject->ImageInformation.SubSystemType = pioh64OptHeader->Subsystem;
511 
512             if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, MinorSubsystemVersion) &&
513                     RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, MajorSubsystemVersion))
514             {
515                 ImageSectionObject->ImageInformation.SubSystemMinorVersion = pioh64OptHeader->MinorSubsystemVersion;
516                 ImageSectionObject->ImageInformation.SubSystemMajorVersion = pioh64OptHeader->MajorSubsystemVersion;
517             }
518         }
519 
520         if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, AddressOfEntryPoint))
521         {
522             ImageSectionObject->ImageInformation.TransferAddress = (PVOID) (ImageBase +
523                     pioh64OptHeader->AddressOfEntryPoint);
524         }
525 
526         if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfCode))
527             ImageSectionObject->ImageInformation.ImageContainsCode = pioh64OptHeader->SizeOfCode != 0;
528         else
529             ImageSectionObject->ImageInformation.ImageContainsCode = TRUE;
530 
531         if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, AddressOfEntryPoint))
532         {
533             if (pioh64OptHeader->AddressOfEntryPoint == 0)
534             {
535                 ImageSectionObject->ImageInformation.ImageContainsCode = FALSE;
536             }
537         }
538 
539         if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, LoaderFlags))
540             ImageSectionObject->ImageInformation.LoaderFlags = pioh64OptHeader->LoaderFlags;
541 
542         if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, DllCharacteristics))
543             ImageSectionObject->ImageInformation.DllCharacteristics = pioh64OptHeader->DllCharacteristics;
544 
545         break;
546     }
547 #endif // _WIN64
548     }
549 
550     /* [1], section 3.4.2 */
551     if((ULONG_PTR)ImageBase % 0x10000)
552         DIE(("ImageBase is not aligned on a 64KB boundary"));
553 
554     ImageSectionObject->ImageInformation.ImageCharacteristics = pinhNtHeader->FileHeader.Characteristics;
555     ImageSectionObject->ImageInformation.Machine = pinhNtHeader->FileHeader.Machine;
556     ImageSectionObject->ImageInformation.GpValue = 0;
557     ImageSectionObject->ImageInformation.ZeroBits = 0;
558     ImageSectionObject->BasedAddress = (PVOID)ImageBase;
559 
560     /* SECTION HEADERS */
561     nStatus = STATUS_INVALID_IMAGE_FORMAT;
562 
563     /* see [1], section 3.3 */
564     if(pinhNtHeader->FileHeader.NumberOfSections > 96)
565         DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader->FileHeader.NumberOfSections));
566 
567     /*
568      * the additional segment is for the file's headers. They need to be present for
569      * the benefit of the dynamic loader (to locate exports, defaults for thread
570      * parameters, resources, etc.)
571      */
572     ImageSectionObject->NrSegments = pinhNtHeader->FileHeader.NumberOfSections + 1;
573 
574     /* file offset for the section headers */
575     if(!Intsafe_AddULong32(&cbSectionHeadersOffset, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
576         DIE(("Offset overflow\n"));
577 
578     if(!Intsafe_AddULong32(&cbSectionHeadersOffset, cbSectionHeadersOffset, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
579         DIE(("Offset overflow\n"));
580 
581     /* size of the section headers */
582     ASSERT(Intsafe_CanMulULong32(pinhNtHeader->FileHeader.NumberOfSections, sizeof(IMAGE_SECTION_HEADER)));
583     cbSectionHeadersSize = pinhNtHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
584 
585     if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize, cbSectionHeadersOffset, cbSectionHeadersSize))
586         DIE(("Section headers too large\n"));
587 
588     /* size of the executable's headers */
589     if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfHeaders))
590     {
591 //        if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
592 //            DIE(("SizeOfHeaders is not aligned\n"));
593 
594         if(cbSectionHeadersSize > piohOptHeader->SizeOfHeaders)
595             DIE(("The section headers overflow SizeOfHeaders\n"));
596 
597         cbHeadersSize = piohOptHeader->SizeOfHeaders;
598     }
599     else if(!AlignUp(&cbHeadersSize, cbSectionHeadersOffsetSize, nFileAlignment))
600         DIE(("Overflow aligning the size of headers\n"));
601 
602     if(pBuffer)
603     {
604         ExFreePool(pBuffer);
605         pBuffer = NULL;
606     }
607     /* WARNING: pinhNtHeader IS NO LONGER USABLE */
608     /* WARNING: piohOptHeader IS NO LONGER USABLE */
609     /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
610 
611     if(FileHeaderSize < cbSectionHeadersOffsetSize)
612         pishSectionHeaders = NULL;
613     else
614     {
615         /*
616          * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
617          * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
618          */
619         ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbSectionHeadersOffset));
620         pishSectionHeaders = (PVOID)((UINT_PTR)FileHeader + cbSectionHeadersOffset);
621     }
622 
623     /*
624      * the buffer doesn't contain the section headers, or the alignment is wrong:
625      * read the headers from the file
626      */
627     if(FileHeaderSize < cbSectionHeadersOffsetSize ||
628             (UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
629     {
630         PVOID pData;
631         ULONG cbReadSize;
632 
633         lnOffset.QuadPart = cbSectionHeadersOffset;
634 
635         /* read the header from the file */
636         nStatus = ReadFileCb(File, &lnOffset, cbSectionHeadersSize, &pData, &pBuffer, &cbReadSize);
637 
638         if(!NT_SUCCESS(nStatus))
639             DIE(("ReadFile failed with status %08X\n", nStatus));
640 
641         ASSERT(pData);
642         ASSERT(pBuffer);
643         ASSERT(cbReadSize > 0);
644 
645         nStatus = STATUS_INVALID_IMAGE_FORMAT;
646 
647         /* the buffer doesn't contain all the section headers */
648         if(cbReadSize < cbSectionHeadersSize)
649             DIE(("The file doesn't contain all of the section headers\n"));
650 
651         pishSectionHeaders = pData;
652 
653         /* object still not aligned: copy it to the beginning of the buffer */
654         if((UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
655         {
656             ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) == 0);
657             RtlMoveMemory(pBuffer, pData, cbReadSize);
658             pishSectionHeaders = pBuffer;
659         }
660     }
661 
662     /* SEGMENTS */
663     /* allocate the segments */
664     nStatus = STATUS_INSUFFICIENT_RESOURCES;
665     ImageSectionObject->Segments = AllocateSegmentsCb(ImageSectionObject->NrSegments);
666 
667     if(ImageSectionObject->Segments == NULL)
668         DIE(("AllocateSegments failed\n"));
669 
670     /* initialize the headers segment */
671     pssSegments = ImageSectionObject->Segments;
672 
673 //  ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
674 
675     if(!AlignUp(&nFileSizeOfHeaders, cbHeadersSize, nFileAlignment))
676         DIE(("Cannot align the size of the section headers\n"));
677 
678     nPrevVirtualEndOfSegment = ALIGN_UP_BY(cbHeadersSize, nSectionAlignment);
679     if (nPrevVirtualEndOfSegment < cbHeadersSize)
680         DIE(("Cannot align the size of the section headers\n"));
681 
682     pssSegments[0].Image.FileOffset = 0;
683     pssSegments[0].Protection = PAGE_READONLY;
684     pssSegments[0].Length.QuadPart = nPrevVirtualEndOfSegment;
685     pssSegments[0].RawLength.QuadPart = nFileSizeOfHeaders;
686     pssSegments[0].Image.VirtualAddress = 0;
687     pssSegments[0].Image.Characteristics = 0;
688     pssSegments[0].WriteCopy = TRUE;
689 
690     /* skip the headers segment */
691     ++ pssSegments;
692 
693     nStatus = STATUS_INVALID_IMAGE_FORMAT;
694 
695     /* convert the executable sections into segments. See also [1], section 4 */
696     for(i = 0; i < ImageSectionObject->NrSegments - 1; ++ i)
697     {
698         ULONG nCharacteristics;
699 
700         /* validate the alignment */
701         if(!IsAligned(pishSectionHeaders[i].VirtualAddress, nSectionAlignment))
702             DIE(("Image.VirtualAddress[%u] is not aligned\n", i));
703 
704         /* sections must be contiguous, ordered by base address and non-overlapping */
705         if(pishSectionHeaders[i].VirtualAddress != nPrevVirtualEndOfSegment)
706             DIE(("Memory gap between section %u and the previous\n", i));
707 
708         /* ignore explicit BSS sections */
709         if(pishSectionHeaders[i].SizeOfRawData != 0)
710         {
711             /* validate the alignment */
712 #if 0
713             /* Yes, this should be a multiple of FileAlignment, but there's
714              * stuff out there that isn't. We can cope with that
715              */
716             if(!IsAligned(pishSectionHeaders[i].SizeOfRawData, nFileAlignment))
717                 DIE(("SizeOfRawData[%u] is not aligned\n", i));
718 #endif
719 
720 //            if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
721 //                DIE(("PointerToRawData[%u] is not aligned\n", i));
722 
723             /* conversion */
724             pssSegments[i].Image.FileOffset = pishSectionHeaders[i].PointerToRawData;
725             pssSegments[i].RawLength.QuadPart = pishSectionHeaders[i].SizeOfRawData;
726         }
727         else
728         {
729             ASSERT(pssSegments[i].Image.FileOffset == 0);
730             ASSERT(pssSegments[i].RawLength.QuadPart == 0);
731         }
732 
733         ASSERT(Intsafe_CanAddLong64(pssSegments[i].Image.FileOffset, pssSegments[i].RawLength.QuadPart));
734 
735         nCharacteristics = pishSectionHeaders[i].Characteristics;
736 
737         /* no explicit protection */
738         if((nCharacteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == 0)
739         {
740             if(nCharacteristics & IMAGE_SCN_CNT_CODE)
741                 nCharacteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
742 
743             if(nCharacteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
744                 nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
745 
746             if(nCharacteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
747                 nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
748         }
749 
750         /* see table above */
751         pssSegments[i].Protection = SectionCharacteristicsToProtect[nCharacteristics >> 28];
752         pssSegments[i].WriteCopy = !(nCharacteristics & IMAGE_SCN_MEM_SHARED);
753 
754         if(pishSectionHeaders[i].Misc.VirtualSize == 0 || pishSectionHeaders[i].Misc.VirtualSize < pishSectionHeaders[i].SizeOfRawData)
755             pssSegments[i].Length.QuadPart = pishSectionHeaders[i].SizeOfRawData;
756         else
757             pssSegments[i].Length.QuadPart = pishSectionHeaders[i].Misc.VirtualSize;
758 
759         AlignedLength = ALIGN_UP_BY(pssSegments[i].Length.LowPart, nSectionAlignment);
760         if(AlignedLength < pssSegments[i].Length.LowPart)
761             DIE(("Cannot align the virtual size of section %u\n", i));
762 
763         pssSegments[i].Length.LowPart = AlignedLength;
764 
765         if(pssSegments[i].Length.QuadPart == 0)
766             DIE(("Virtual size of section %u is null\n", i));
767 
768         pssSegments[i].Image.VirtualAddress = pishSectionHeaders[i].VirtualAddress;
769         pssSegments[i].Image.Characteristics = pishSectionHeaders[i].Characteristics;
770 
771         /* ensure the memory image is no larger than 4GB */
772         nPrevVirtualEndOfSegment = (ULONG_PTR)(pssSegments[i].Image.VirtualAddress + pssSegments[i].Length.QuadPart);
773         if (nPrevVirtualEndOfSegment < pssSegments[i].Image.VirtualAddress)
774             DIE(("The image is too large\n"));
775     }
776 
777     if(nSectionAlignment >= PAGE_SIZE)
778         *Flags |= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED;
779 
780     /* Success */
781     nStatus = STATUS_SUCCESS;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
782 
783 l_Return:
784     if(pBuffer)
785         ExFreePool(pBuffer);
786 
787     return nStatus;
788 }
789 
790 /*
791  * FUNCTION:  Waits in kernel mode indefinitely for a file object lock.
792  * ARGUMENTS: PFILE_OBJECT to wait for.
793  * RETURNS:   Status of the wait.
794  */
795 NTSTATUS
796 MmspWaitForFileLock(PFILE_OBJECT File)
797 {
798     return STATUS_SUCCESS;
799     //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
800 }
801 
802 VOID
803 NTAPI
804 MmFreeSectionSegments(PFILE_OBJECT FileObject)
805 {
806     if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
807     {
808         PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
809         PMM_SECTION_SEGMENT SectionSegments;
810         ULONG NrSegments;
811         ULONG i;
812 
813         ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject;
814         NrSegments = ImageSectionObject->NrSegments;
815         SectionSegments = ImageSectionObject->Segments;
816         for (i = 0; i < NrSegments; i++)
817         {
818             if (SectionSegments[i].ReferenceCount != 0)
819             {
820                 DPRINT1("Image segment %lu still referenced (was %lu)\n", i,
821                         SectionSegments[i].ReferenceCount);
822                 KeBugCheck(MEMORY_MANAGEMENT);
823             }
824             MmFreePageTablesSectionSegment(&SectionSegments[i], NULL);
825         }
826         ExFreePool(ImageSectionObject->Segments);
827         ExFreePool(ImageSectionObject);
828         FileObject->SectionObjectPointer->ImageSectionObject = NULL;
829     }
830     if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
831     {
832         PMM_SECTION_SEGMENT Segment;
833 
834         Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
835                   DataSectionObject;
836 
837         if (Segment->ReferenceCount != 0)
838         {
839             DPRINT1("Data segment still referenced\n");
840             KeBugCheck(MEMORY_MANAGEMENT);
841         }
842         MmFreePageTablesSectionSegment(Segment, NULL);
843         ExFreePool(Segment);
844         FileObject->SectionObjectPointer->DataSectionObject = NULL;
845     }
846 }
847 
848 VOID
849 NTAPI
850 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
851                                PLARGE_INTEGER Offset)
852 {
853     ULONG_PTR Entry;
854 
855     Entry = MmGetPageEntrySectionSegment(Segment, Offset);
856     if (Entry == 0)
857     {
858         DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
859         KeBugCheck(MEMORY_MANAGEMENT);
860     }
861     if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
862     {
863         DPRINT1("Maximum share count reached\n");
864         KeBugCheck(MEMORY_MANAGEMENT);
865     }
866     if (IS_SWAP_FROM_SSE(Entry))
867     {
868         KeBugCheck(MEMORY_MANAGEMENT);
869     }
870     Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1);
871     MmSetPageEntrySectionSegment(Segment, Offset, Entry);
872 }
873 
874 BOOLEAN
875 NTAPI
876 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section,
877                                  PMM_SECTION_SEGMENT Segment,
878                                  PLARGE_INTEGER Offset,
879                                  BOOLEAN Dirty,
880                                  BOOLEAN PageOut,
881                                  ULONG_PTR *InEntry)
882 {
883     ULONG_PTR Entry = InEntry ? *InEntry : MmGetPageEntrySectionSegment(Segment, Offset);
884     BOOLEAN IsDirectMapped = FALSE;
885 
886     if (Entry == 0)
887     {
888         DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
889         KeBugCheck(MEMORY_MANAGEMENT);
890     }
891     if (SHARE_COUNT_FROM_SSE(Entry) == 0)
892     {
893         DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment, Offset->LowPart, PFN_FROM_SSE(Entry));
894         KeBugCheck(MEMORY_MANAGEMENT);
895     }
896     if (IS_SWAP_FROM_SSE(Entry))
897     {
898         KeBugCheck(MEMORY_MANAGEMENT);
899     }
900     Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1);
901     /*
902      * If we reducing the share count of this entry to zero then set the entry
903      * to zero and tell the cache the page is no longer mapped.
904      */
905     if (SHARE_COUNT_FROM_SSE(Entry) == 0)
906     {
907         PFILE_OBJECT FileObject;
908         SWAPENTRY SavedSwapEntry;
909         PFN_NUMBER Page;
910 #ifndef NEWCC
911         PROS_SHARED_CACHE_MAP SharedCacheMap;
912         BOOLEAN IsImageSection;
913         LARGE_INTEGER FileOffset;
914 
915         FileOffset.QuadPart = Offset->QuadPart + Segment->Image.FileOffset;
916         IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
917 #endif
918 
919         Page = PFN_FROM_SSE(Entry);
920         FileObject = Section->FileObject;
921         if (FileObject != NULL &&
922                 !(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
923         {
924 
925 #ifndef NEWCC
926             if ((FileOffset.QuadPart % PAGE_SIZE) == 0 &&
927                     (Offset->QuadPart + PAGE_SIZE <= Segment->RawLength.QuadPart || !IsImageSection))
928             {
929                 NTSTATUS Status;
930                 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
931                 IsDirectMapped = TRUE;
932 #ifndef NEWCC
933                 Status = CcRosUnmapVacb(SharedCacheMap, FileOffset.QuadPart, Dirty);
934 #else
935                 Status = STATUS_SUCCESS;
936 #endif
937                 if (!NT_SUCCESS(Status))
938                 {
939                     DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status);
940                     KeBugCheck(MEMORY_MANAGEMENT);
941                 }
942             }
943 #endif
944         }
945 
946         SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
947         if (SavedSwapEntry == 0)
948         {
949             if (!PageOut &&
950                     ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
951                      (Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)))
952             {
953                 /*
954                  * FIXME:
955                  *   Try to page out this page and set the swap entry
956                  *   within the section segment. There exist no rmap entry
957                  *   for this page. The pager thread can't page out a
958                  *   page without a rmap entry.
959                  */
960                 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
961                 if (InEntry) *InEntry = Entry;
962                 MiSetPageEvent(NULL, NULL);
963             }
964             else
965             {
966                 MmSetPageEntrySectionSegment(Segment, Offset, 0);
967                 if (InEntry) *InEntry = 0;
968                 MiSetPageEvent(NULL, NULL);
969                 if (!IsDirectMapped)
970                 {
971                     MmReleasePageMemoryConsumer(MC_USER, Page);
972                 }
973             }
974         }
975         else
976         {
977             if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
978                     (Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
979             {
980                 if (!PageOut)
981                 {
982                     if (Dirty)
983                     {
984                         /*
985                          * FIXME:
986                          *   We hold all locks. Nobody can do something with the current
987                          *   process and the current segment (also not within an other process).
988                          */
989                         NTSTATUS Status;
990                         Status = MmWriteToSwapPage(SavedSwapEntry, Page);
991                         if (!NT_SUCCESS(Status))
992                         {
993                             DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status);
994                             KeBugCheck(MEMORY_MANAGEMENT);
995                         }
996                     }
997                     MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry));
998                     if (InEntry) *InEntry = MAKE_SWAP_SSE(SavedSwapEntry);
999                     MmSetSavedSwapEntryPage(Page, 0);
1000                     MiSetPageEvent(NULL, NULL);
1001                 }
1002                 MmReleasePageMemoryConsumer(MC_USER, Page);
1003             }
1004             else
1005             {
1006                 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1007                 KeBugCheck(MEMORY_MANAGEMENT);
1008             }
1009         }
1010     }
1011     else
1012     {
1013         if (InEntry)
1014             *InEntry = Entry;
1015         else
1016             MmSetPageEntrySectionSegment(Segment, Offset, Entry);
1017     }
1018     return(SHARE_COUNT_FROM_SSE(Entry) > 0);
1019 }
1020 
1021 BOOLEAN MiIsPageFromCache(PMEMORY_AREA MemoryArea,
1022                           LONGLONG SegOffset)
1023 {
1024 #ifndef NEWCC
1025     if (!(MemoryArea->Data.SectionData.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
1026     {
1027         PROS_SHARED_CACHE_MAP SharedCacheMap;
1028         PROS_VACB Vacb;
1029         SharedCacheMap = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap;
1030         Vacb = CcRosLookupVacb(SharedCacheMap, SegOffset + MemoryArea->Data.SectionData.Segment->Image.FileOffset);
1031         if (Vacb)
1032         {
1033             CcRosReleaseVacb(SharedCacheMap, Vacb, Vacb->Valid, FALSE, TRUE);
1034             return TRUE;
1035         }
1036     }
1037 #endif
1038     return FALSE;
1039 }
1040 
1041 NTSTATUS
1042 NTAPI
1043 MiCopyFromUserPage(PFN_NUMBER DestPage, const VOID *SrcAddress)
1044 {
1045     PEPROCESS Process;
1046     KIRQL Irql;
1047     PVOID DestAddress;
1048 
1049     Process = PsGetCurrentProcess();
1050     DestAddress = MiMapPageInHyperSpace(Process, DestPage, &Irql);
1051     if (DestAddress == NULL)
1052     {
1053         return(STATUS_NO_MEMORY);
1054     }
1055     ASSERT((ULONG_PTR)DestAddress % PAGE_SIZE == 0);
1056     ASSERT((ULONG_PTR)SrcAddress % PAGE_SIZE == 0);
1057     RtlCopyMemory(DestAddress, SrcAddress, PAGE_SIZE);
1058     MiUnmapPageInHyperSpace(Process, DestAddress, Irql);
1059     return(STATUS_SUCCESS);
1060 }
1061 
1062 #ifndef NEWCC
1063 NTSTATUS
1064 NTAPI
1065 MiReadPage(PMEMORY_AREA MemoryArea,
1066            LONGLONG SegOffset,
1067            PPFN_NUMBER Page)
1068 /*
1069  * FUNCTION: Read a page for a section backed memory area.
1070  * PARAMETERS:
1071  *       MemoryArea - Memory area to read the page for.
1072  *       Offset - Offset of the page to read.
1073  *       Page - Variable that receives a page contains the read data.
1074  */
1075 {
1076     LONGLONG BaseOffset;
1077     LONGLONG FileOffset;
1078     PVOID BaseAddress;
1079     BOOLEAN UptoDate;
1080     PROS_VACB Vacb;
1081     PFILE_OBJECT FileObject;
1082     NTSTATUS Status;
1083     LONGLONG RawLength;
1084     PROS_SHARED_CACHE_MAP SharedCacheMap;
1085     BOOLEAN IsImageSection;
1086     LONGLONG Length;
1087 
1088     FileObject = MemoryArea->Data.SectionData.Section->FileObject;
1089     SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
1090     RawLength = MemoryArea->Data.SectionData.Segment->RawLength.QuadPart;
1091     FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->Image.FileOffset;
1092     IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1093 
1094     ASSERT(SharedCacheMap);
1095 
1096     DPRINT("%S %I64x\n", FileObject->FileName.Buffer, FileOffset);
1097 
1098     /*
1099      * If the file system is letting us go directly to the cache and the
1100      * memory area was mapped at an offset in the file which is page aligned
1101      * then get the related VACB.
1102      */
1103     if (((FileOffset % PAGE_SIZE) == 0) &&
1104             ((SegOffset + PAGE_SIZE <= RawLength) || !IsImageSection) &&
1105             !(MemoryArea->Data.SectionData.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
1106     {
1107 
1108         /*
1109          * Get the related VACB; we use a lower level interface than
1110          * filesystems do because it is safe for us to use an offset with an
1111          * alignment less than the file system block size.
1112          */
1113         Status = CcRosGetVacb(SharedCacheMap,
1114                               FileOffset,
1115                               &BaseOffset,
1116                               &BaseAddress,
1117                               &UptoDate,
1118                               &Vacb);
1119         if (!NT_SUCCESS(Status))
1120         {
1121             return(Status);
1122         }
1123         if (!UptoDate)
1124         {
1125             /*
1126              * If the VACB isn't up to date then call the file
1127              * system to read in the data.
1128              */
1129             Status = CcReadVirtualAddress(Vacb);
1130             if (!NT_SUCCESS(Status))
1131             {
1132                 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
1133                 return Status;
1134             }
1135         }
1136 
1137         /* Probe the page, since it's PDE might not be synced */
1138         (void)*((volatile char*)BaseAddress + FileOffset - BaseOffset);
1139 
1140         /*
1141          * Retrieve the page from the view that we actually want.
1142          */
1143         (*Page) = MmGetPhysicalAddress((char*)BaseAddress +
1144                                        FileOffset - BaseOffset).LowPart >> PAGE_SHIFT;
1145 
1146         CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, TRUE);
1147     }
1148     else
1149     {
1150         PEPROCESS Process;
1151         KIRQL Irql;
1152         PVOID PageAddr;
1153         LONGLONG VacbOffset;
1154 
1155         /*
1156          * Allocate a page, this is rather complicated by the possibility
1157          * we might have to move other things out of memory
1158          */
1159         MI_SET_USAGE(MI_USAGE_SECTION);
1160         MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
1161         Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
1162         if (!NT_SUCCESS(Status))
1163         {
1164             return(Status);
1165         }
1166         Status = CcRosGetVacb(SharedCacheMap,
1167                               FileOffset,
1168                               &BaseOffset,
1169                               &BaseAddress,
1170                               &UptoDate,
1171                               &Vacb);
1172         if (!NT_SUCCESS(Status))
1173         {
1174             return(Status);
1175         }
1176         if (!UptoDate)
1177         {
1178             /*
1179              * If the VACB isn't up to date then call the file
1180              * system to read in the data.
1181              */
1182             Status = CcReadVirtualAddress(Vacb);
1183             if (!NT_SUCCESS(Status))
1184             {
1185                 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
1186                 return Status;
1187             }
1188         }
1189 
1190         Process = PsGetCurrentProcess();
1191         PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql);
1192         VacbOffset = BaseOffset + VACB_MAPPING_GRANULARITY - FileOffset;
1193         Length = RawLength - SegOffset;
1194         if (Length <= VacbOffset && Length <= PAGE_SIZE)
1195         {
1196             memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, Length);
1197         }
1198         else if (VacbOffset >= PAGE_SIZE)
1199         {
1200             memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, PAGE_SIZE);
1201         }
1202         else
1203         {
1204             memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, VacbOffset);
1205             MiUnmapPageInHyperSpace(Process, PageAddr, Irql);
1206             CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE);
1207             Status = CcRosGetVacb(SharedCacheMap,
1208                                   FileOffset + VacbOffset,
1209                                   &BaseOffset,
1210                                   &BaseAddress,
1211                                   &UptoDate,
1212                                   &Vacb);
1213             if (!NT_SUCCESS(Status))
1214             {
1215                 return(Status);
1216             }
1217             if (!UptoDate)
1218             {
1219                 /*
1220                  * If the VACB isn't up to date then call the file
1221                  * system to read in the data.
1222                  */
1223                 Status = CcReadVirtualAddress(Vacb);
1224                 if (!NT_SUCCESS(Status))
1225                 {
1226                     CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
1227                     return Status;
1228                 }
1229             }
1230             PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql);
1231             if (Length < PAGE_SIZE)
1232             {
1233                 memcpy((char*)PageAddr + VacbOffset, BaseAddress, Length - VacbOffset);
1234             }
1235             else
1236             {
1237                 memcpy((char*)PageAddr + VacbOffset, BaseAddress, PAGE_SIZE - VacbOffset);
1238             }
1239         }
1240         MiUnmapPageInHyperSpace(Process, PageAddr, Irql);
1241         CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE);
1242     }
1243     return(STATUS_SUCCESS);
1244 }
1245 #else
1246 NTSTATUS
1247 NTAPI
1248 MiReadPage(PMEMORY_AREA MemoryArea,
1249            LONGLONG SegOffset,
1250            PPFN_NUMBER Page)
1251 /*
1252  * FUNCTION: Read a page for a section backed memory area.
1253  * PARAMETERS:
1254  *       MemoryArea - Memory area to read the page for.
1255  *       Offset - Offset of the page to read.
1256  *       Page - Variable that receives a page contains the read data.
1257  */
1258 {
1259     MM_REQUIRED_RESOURCES Resources;
1260     NTSTATUS Status;
1261 
1262     RtlZeroMemory(&Resources, sizeof(MM_REQUIRED_RESOURCES));
1263 
1264     Resources.Context = MemoryArea->Data.SectionData.Section->FileObject;
1265     Resources.FileOffset.QuadPart = SegOffset +
1266                                     MemoryArea->Data.SectionData.Segment->Image.FileOffset;
1267     Resources.Consumer = MC_USER;
1268     Resources.Amount = PAGE_SIZE;
1269 
1270     DPRINT("%S, offset 0x%x, len 0x%x, page 0x%x\n", ((PFILE_OBJECT)Resources.Context)->FileName.Buffer, Resources.FileOffset.LowPart, Resources.Amount, Resources.Page[0]);
1271 
1272     Status = MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea, &Resources);
1273     *Page = Resources.Page[0];
1274     return Status;
1275 }
1276 #endif
1277 
1278 static VOID
1279 MmAlterViewAttributes(PMMSUPPORT AddressSpace,
1280                       PVOID BaseAddress,
1281                       SIZE_T RegionSize,
1282                       ULONG OldType,
1283                       ULONG OldProtect,
1284                       ULONG NewType,
1285                       ULONG NewProtect)
1286 {
1287     PMEMORY_AREA MemoryArea;
1288     PMM_SECTION_SEGMENT Segment;
1289     BOOLEAN DoCOW = FALSE;
1290     ULONG i;
1291     PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1292 
1293     MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
1294     ASSERT(MemoryArea != NULL);
1295     Segment = MemoryArea->Data.SectionData.Segment;
1296     MmLockSectionSegment(Segment);
1297 
1298     if ((Segment->WriteCopy) &&
1299             (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
1300     {
1301         DoCOW = TRUE;
1302     }
1303 
1304     if (OldProtect != NewProtect)
1305     {
1306         for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
1307         {
1308             SWAPENTRY SwapEntry;
1309             PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
1310             ULONG Protect = NewProtect;
1311 
1312             /* Wait for a wait entry to disappear */
1313             do
1314             {
1315                 MmGetPageFileMapping(Process, Address, &SwapEntry);
1316                 if (SwapEntry != MM_WAIT_ENTRY)
1317                     break;
1318                 MiWaitForPageEvent(Process, Address);
1319             }
1320             while (TRUE);
1321 
1322             /*
1323              * If we doing COW for this segment then check if the page is
1324              * already private.
1325              */
1326             if (DoCOW && MmIsPagePresent(Process, Address))
1327             {
1328                 LARGE_INTEGER Offset;
1329                 ULONG_PTR Entry;
1330                 PFN_NUMBER Page;
1331 
1332                 Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)
1333                                   + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
1334                 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
1335                 /*
1336                  * An MM_WAIT_ENTRY is ok in this case...  It'll just count as
1337                  * IS_SWAP_FROM_SSE and we'll do the right thing.
1338                  */
1339                 Page = MmGetPfnForProcess(Process, Address);
1340 
1341                 Protect = PAGE_READONLY;
1342                 if (IS_SWAP_FROM_SSE(Entry) || PFN_FROM_SSE(Entry) != Page)
1343                 {
1344                     Protect = NewProtect;
1345                 }
1346             }
1347 
1348             if (MmIsPagePresent(Process, Address) || MmIsDisabledPage(Process, Address))
1349             {
1350                 MmSetPageProtect(Process, Address,
1351                                  Protect);
1352             }
1353         }
1354     }
1355 
1356     MmUnlockSectionSegment(Segment);
1357 }
1358 
1359 NTSTATUS
1360 NTAPI
1361 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
1362                              MEMORY_AREA* MemoryArea,
1363                              PVOID Address,
1364                              BOOLEAN Locked)
1365 {
1366     LARGE_INTEGER Offset;
1367     PFN_NUMBER Page;
1368     NTSTATUS Status;
1369     PROS_SECTION_OBJECT Section;
1370     PMM_SECTION_SEGMENT Segment;
1371     ULONG_PTR Entry;
1372     ULONG_PTR Entry1;
1373     ULONG Attributes;
1374     PMM_REGION Region;
1375     BOOLEAN HasSwapEntry;
1376     PVOID PAddress;
1377     PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1378     SWAPENTRY SwapEntry;
1379 
1380     /*
1381      * There is a window between taking the page fault and locking the
1382      * address space when another thread could load the page so we check
1383      * that.
1384      */
1385     if (MmIsPagePresent(Process, Address))
1386     {
1387         return(STATUS_SUCCESS);
1388     }
1389 
1390     if (MmIsDisabledPage(Process, Address))
1391     {
1392         return(STATUS_ACCESS_VIOLATION);
1393     }
1394 
1395     /*
1396      * Check for the virtual memory area being deleted.
1397      */
1398     if (MemoryArea->DeleteInProgress)
1399     {
1400         return(STATUS_UNSUCCESSFUL);
1401     }
1402 
1403     PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
1404     Offset.QuadPart = (ULONG_PTR)PAddress - MA_GetStartingAddress(MemoryArea)
1405                       + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
1406 
1407     Segment = MemoryArea->Data.SectionData.Segment;
1408     Section = MemoryArea->Data.SectionData.Section;
1409     Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
1410                           &MemoryArea->Data.SectionData.RegionListHead,
1411                           Address, NULL);
1412     ASSERT(Region != NULL);
1413 
1414     /* Check for a NOACCESS mapping */
1415     if (Region->Protect & PAGE_NOACCESS)
1416     {
1417         return STATUS_ACCESS_VIOLATION;
1418     }
1419 
1420     if (Region->Protect & PAGE_GUARD)
1421     {
1422         /* Remove it */
1423         Status = MmAlterRegion(AddressSpace, (PVOID)MA_GetStartingAddress(MemoryArea),
1424                 &MemoryArea->Data.SectionData.RegionListHead,
1425                 Address, PAGE_SIZE, Region->Type, Region->Protect & ~PAGE_GUARD,
1426                 MmAlterViewAttributes);
1427 
1428         if (!NT_SUCCESS(Status))
1429         {
1430             DPRINT1("Removing PAGE_GUARD protection failed : 0x%08x.\n", Status);
1431         }
1432 
1433         return STATUS_GUARD_PAGE_VIOLATION;
1434     }
1435 
1436     /*
1437      * Lock the segment
1438      */
1439     MmLockSectionSegment(Segment);
1440     Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
1441     /*
1442      * Check if this page needs to be mapped COW
1443      */
1444     if ((Segment->WriteCopy) &&
1445             (Region->Protect == PAGE_READWRITE ||
1446              Region->Protect == PAGE_EXECUTE_READWRITE))
1447     {
1448         Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
1449     }
1450     else
1451     {
1452         Attributes = Region->Protect;
1453     }
1454 
1455     /*
1456      * Check if someone else is already handling this fault, if so wait
1457      * for them
1458      */
1459     if (Entry && MM_IS_WAIT_PTE(Entry))
1460     {
1461         MmUnlockSectionSegment(Segment);
1462         MmUnlockAddressSpace(AddressSpace);
1463         MiWaitForPageEvent(NULL, NULL);
1464         MmLockAddressSpace(AddressSpace);
1465         DPRINT("Address 0x%p\n", Address);
1466         return(STATUS_MM_RESTART_OPERATION);
1467     }
1468 
1469     HasSwapEntry = MmIsPageSwapEntry(Process, Address);
1470 
1471     /* See if we should use a private page */
1472     if (HasSwapEntry)
1473     {
1474         SWAPENTRY DummyEntry;
1475 
1476         /*
1477          * Is it a wait entry?
1478          */
1479         if (HasSwapEntry)
1480         {
1481             MmGetPageFileMapping(Process, Address, &SwapEntry);
1482 
1483             if (SwapEntry == MM_WAIT_ENTRY)
1484             {
1485                 MmUnlockSectionSegment(Segment);
1486                 MmUnlockAddressSpace(AddressSpace);
1487                 MiWaitForPageEvent(NULL, NULL);
1488                 MmLockAddressSpace(AddressSpace);
1489                 return STATUS_MM_RESTART_OPERATION;
1490             }
1491 
1492             /*
1493              * Must be private page we have swapped out.
1494              */
1495 
1496             /*
1497              * Sanity check
1498              */
1499             if (Segment->Flags & MM_PAGEFILE_SEGMENT)
1500             {
1501                 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1502                 KeBugCheck(MEMORY_MANAGEMENT);
1503             }
1504             MmDeletePageFileMapping(Process, Address, &SwapEntry);
1505         }
1506 
1507         MmUnlockSectionSegment(Segment);
1508 
1509         /* Tell everyone else we are serving the fault. */
1510         MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY);
1511 
1512         MmUnlockAddressSpace(AddressSpace);
1513         MI_SET_USAGE(MI_USAGE_SECTION);
1514         if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1515         if (!Process) MI_SET_PROCESS2("Kernel Section");
1516         Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1517         if (!NT_SUCCESS(Status))
1518         {
1519             KeBugCheck(MEMORY_MANAGEMENT);
1520         }
1521 
1522         if (HasSwapEntry)
1523         {
1524             Status = MmReadFromSwapPage(SwapEntry, Page);
1525             if (!NT_SUCCESS(Status))
1526             {
1527                 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
1528                 KeBugCheck(MEMORY_MANAGEMENT);
1529             }
1530         }
1531 
1532         MmLockAddressSpace(AddressSpace);
1533         MmDeletePageFileMapping(Process, PAddress, &DummyEntry);
1534         Status = MmCreateVirtualMapping(Process,
1535                                         PAddress,
1536                                         Region->Protect,
1537                                         &Page,
1538                                         1);
1539         if (!NT_SUCCESS(Status))
1540         {
1541             DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1542             KeBugCheck(MEMORY_MANAGEMENT);
1543             return(Status);
1544         }
1545 
1546         /*
1547          * Store the swap entry for later use.
1548          */
1549         if (HasSwapEntry)
1550             MmSetSavedSwapEntryPage(Page, SwapEntry);
1551 
1552         /*
1553          * Add the page to the process's working set
1554          */
1555         MmInsertRmap(Page, Process, Address);
1556         /*
1557          * Finish the operation
1558          */
1559         MiSetPageEvent(Process, Address);
1560         DPRINT("Address 0x%p\n", Address);
1561         return(STATUS_SUCCESS);
1562     }
1563 
1564     /*
1565      * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1566      */
1567     if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1568     {
1569         MmUnlockSectionSegment(Segment);
1570         /*
1571          * Just map the desired physical page
1572          */
1573         Page = (PFN_NUMBER)(Offset.QuadPart >> PAGE_SHIFT);
1574         Status = MmCreateVirtualMappingUnsafe(Process,
1575                                               PAddress,
1576                                               Region->Protect,
1577                                               &Page,
1578                                               1);
1579         if (!NT_SUCCESS(Status))
1580         {
1581             DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1582             KeBugCheck(MEMORY_MANAGEMENT);
1583             return(Status);
1584         }
1585 
1586         /*
1587          * Cleanup and release locks
1588          */
1589         MiSetPageEvent(Process, Address);
1590         DPRINT("Address 0x%p\n", Address);
1591         return(STATUS_SUCCESS);
1592     }
1593 
1594     /*
1595      * Get the entry corresponding to the offset within the section
1596      */
1597     Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
1598 
1599     if (Entry == 0)
1600     {
1601         SWAPENTRY FakeSwapEntry;
1602 
1603         /*
1604          * If the entry is zero (and it can't change because we have
1605          * locked the segment) then we need to load the page.
1606          */
1607 
1608         /*
1609          * Release all our locks and read in the page from disk
1610          */
1611         MmSetPageEntrySectionSegment(Segment, &Offset, MAKE_SWAP_SSE(MM_WAIT_ENTRY));
1612         MmUnlockSectionSegment(Segment);
1613         MmCreatePageFileMapping(Process, PAddress, MM_WAIT_ENTRY);
1614         MmUnlockAddressSpace(AddressSpace);
1615 
1616         if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
1617                 ((Offset.QuadPart >= (LONGLONG)PAGE_ROUND_UP(Segment->RawLength.QuadPart) &&
1618                   (Section->AllocationAttributes & SEC_IMAGE))))
1619         {
1620             MI_SET_USAGE(MI_USAGE_SECTION);
1621             if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1622             if (!Process) MI_SET_PROCESS2("Kernel Section");
1623             Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1624             if (!NT_SUCCESS(Status))
1625             {
1626                 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
1627             }
1628 
1629         }
1630         else
1631         {
1632             Status = MiReadPage(MemoryArea, Offset.QuadPart, &Page);
1633             if (!NT_SUCCESS(Status))
1634             {
1635                 DPRINT1("MiReadPage failed (Status %x)\n", Status);
1636             }
1637         }
1638         if (!NT_SUCCESS(Status))
1639         {
1640             /*
1641              * FIXME: What do we know in this case?
1642              */
1643             /*
1644              * Cleanup and release locks
1645              */
1646             MmLockAddressSpace(AddressSpace);
1647             MiSetPageEvent(Process, Address);
1648             DPRINT("Address 0x%p\n", Address);
1649             return(Status);
1650         }
1651 
1652         /* Lock both segment and process address space while we proceed. */
1653         MmLockAddressSpace(AddressSpace);
1654         MmLockSectionSegment(Segment);
1655 
1656         MmDeletePageFileMapping(Process, PAddress, &FakeSwapEntry);
1657         DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1658                Page, Process, PAddress, Attributes);
1659         Status = MmCreateVirtualMapping(Process,
1660                                         PAddress,
1661                                         Attributes,
1662                                         &Page,
1663                                         1);
1664         if (!NT_SUCCESS(Status))
1665         {
1666             DPRINT1("Unable to create virtual mapping\n");
1667             KeBugCheck(MEMORY_MANAGEMENT);
1668         }
1669         ASSERT(MmIsPagePresent(Process, PAddress));
1670         MmInsertRmap(Page, Process, Address);
1671 
1672         /* Set this section offset has being backed by our new page. */
1673         Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1674         MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
1675         MmUnlockSectionSegment(Segment);
1676 
1677         MiSetPageEvent(Process, Address);
1678         DPRINT("Address 0x%p\n", Address);
1679         return(STATUS_SUCCESS);
1680     }
1681     else if (IS_SWAP_FROM_SSE(Entry))
1682     {
1683         SWAPENTRY SwapEntry;
1684 
1685         SwapEntry = SWAPENTRY_FROM_SSE(Entry);
1686 
1687         /* See if a page op is running on this segment. */
1688         if (SwapEntry == MM_WAIT_ENTRY)
1689         {
1690             MmUnlockSectionSegment(Segment);
1691             MmUnlockAddressSpace(AddressSpace);
1692             MiWaitForPageEvent(NULL, NULL);
1693             MmLockAddressSpace(AddressSpace);
1694             return STATUS_MM_RESTART_OPERATION;
1695         }
1696 
1697         /*
1698         * Release all our locks and read in the page from disk
1699         */
1700         MmUnlockSectionSegment(Segment);
1701 
1702         MmUnlockAddressSpace(AddressSpace);
1703         MI_SET_USAGE(MI_USAGE_SECTION);
1704         if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1705         if (!Process) MI_SET_PROCESS2("Kernel Section");
1706         Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1707         if (!NT_SUCCESS(Status))
1708         {
1709             KeBugCheck(MEMORY_MANAGEMENT);
1710         }
1711 
1712         Status = MmReadFromSwapPage(SwapEntry, Page);
1713         if (!NT_SUCCESS(Status))
1714         {
1715             KeBugCheck(MEMORY_MANAGEMENT);
1716         }
1717 
1718         /*
1719          * Relock the address space and segment
1720          */
1721         MmLockAddressSpace(AddressSpace);
1722         MmLockSectionSegment(Segment);
1723 
1724         /*
1725          * Check the entry. No one should change the status of a page
1726          * that has a pending page-in.
1727          */
1728         Entry1 = MmGetPageEntrySectionSegment(Segment, &Offset);
1729         if (Entry != Entry1)
1730         {
1731             DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry, Entry1);
1732             KeBugCheck(MEMORY_MANAGEMENT);
1733         }
1734 
1735         /*
1736          * Save the swap entry.
1737          */
1738         MmSetSavedSwapEntryPage(Page, SwapEntry);
1739 
1740         /* Map the page into the process address space */
1741         Status = MmCreateVirtualMapping(Process,
1742                                         PAddress,
1743                                         Region->Protect,
1744                                         &Page,
1745                                         1);
1746         if (!NT_SUCCESS(Status))
1747         {
1748             DPRINT1("Unable to create virtual mapping\n");
1749             KeBugCheck(MEMORY_MANAGEMENT);
1750         }
1751         MmInsertRmap(Page, Process, Address);
1752 
1753         /*
1754          * Mark the offset within the section as having valid, in-memory
1755          * data
1756          */
1757         Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1758         MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
1759         MmUnlockSectionSegment(Segment);
1760 
1761         MiSetPageEvent(Process, Address);
1762         DPRINT("Address 0x%p\n", Address);
1763         return(STATUS_SUCCESS);
1764     }
1765     else
1766     {
1767         /* We already have a page on this section offset. Map it into the process address space. */
1768         Page = PFN_FROM_SSE(Entry);
1769 
1770         Status = MmCreateVirtualMapping(Process,
1771                                         PAddress,
1772                                         Attributes,
1773                                         &Page,
1774                                         1);
1775         if (!NT_SUCCESS(Status))
1776         {
1777             DPRINT1("Unable to create virtual mapping\n");
1778             KeBugCheck(MEMORY_MANAGEMENT);
1779         }
1780         MmInsertRmap(Page, Process, Address);
1781 
1782         /* Take a reference on it */
1783         MmSharePageEntrySectionSegment(Segment, &Offset);
1784         MmUnlockSectionSegment(Segment);
1785 
1786         MiSetPageEvent(Process, Address);
1787         DPRINT("Address 0x%p\n", Address);
1788         return(STATUS_SUCCESS);
1789     }
1790 }
1791 
1792 NTSTATUS
1793 NTAPI
1794 MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
1795                          MEMORY_AREA* MemoryArea,
1796                          PVOID Address)
1797 {
1798     PMM_SECTION_SEGMENT Segment;
1799     PROS_SECTION_OBJECT Section;
1800     PFN_NUMBER OldPage;
1801     PFN_NUMBER NewPage;
1802     NTSTATUS Status;
1803     PVOID PAddress;
1804     LARGE_INTEGER Offset;
1805     PMM_REGION Region;
1806     ULONG_PTR Entry;
1807     PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1808 
1809     DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace, MemoryArea, Address);
1810 
1811     /* Make sure we have a page mapping for this address.  */
1812     Status = MmNotPresentFaultSectionView(AddressSpace, MemoryArea, Address, TRUE);
1813     if (!NT_SUCCESS(Status))
1814     {
1815         /* This is invalid access ! */
1816         return Status;
1817     }
1818 
1819     /*
1820      * Check if the page has already been set readwrite
1821      */
1822     if (MmGetPageProtect(Process, Address) & PAGE_READWRITE)
1823     {
1824         DPRINT("Address 0x%p\n", Address);
1825         return(STATUS_SUCCESS);
1826     }
1827 
1828     /*
1829      * Find the offset of the page
1830      */
1831     PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
1832     Offset.QuadPart = (ULONG_PTR)PAddress - MA_GetStartingAddress(MemoryArea)
1833                       + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
1834 
1835     Segment = MemoryArea->Data.SectionData.Segment;
1836     Section = MemoryArea->Data.SectionData.Section;
1837     Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
1838                           &MemoryArea->Data.SectionData.RegionListHead,
1839                           Address, NULL);
1840     ASSERT(Region != NULL);
1841 
1842     /*
1843      * Check if we are doing COW
1844      */
1845     if (!((Segment->WriteCopy) &&
1846             (Region->Protect == PAGE_READWRITE ||
1847              Region->Protect == PAGE_EXECUTE_READWRITE)))
1848     {
1849         DPRINT("Address 0x%p\n", Address);
1850         return(STATUS_ACCESS_VIOLATION);
1851     }
1852 
1853     /* Get the page mapping this section offset. */
1854     MmLockSectionSegment(Segment);
1855     Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
1856 
1857     /* Get the current page mapping for the process */
1858     ASSERT(MmIsPagePresent(Process, PAddress));
1859     OldPage = MmGetPfnForProcess(Process, PAddress);
1860     ASSERT(OldPage != 0);
1861 
1862     if (IS_SWAP_FROM_SSE(Entry) ||
1863             PFN_FROM_SSE(Entry) != OldPage)
1864     {
1865         MmUnlockSectionSegment(Segment);
1866         /* This is a private page. We must only change the page protection. */
1867         MmSetPageProtect(Process, PAddress, Region->Protect);
1868         return(STATUS_SUCCESS);
1869     }
1870 
1871     /*
1872      * Allocate a page
1873      */
1874     MI_SET_USAGE(MI_USAGE_SECTION);
1875     if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1876     if (!Process) MI_SET_PROCESS2("Kernel Section");
1877     Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1878     if (!NT_SUCCESS(Status))
1879     {
1880         KeBugCheck(MEMORY_MANAGEMENT);
1881     }
1882 
1883     /*
1884      * Copy the old page
1885      */
1886     NT_VERIFY(NT_SUCCESS(MiCopyFromUserPage(NewPage, PAddress)));
1887 
1888     /*
1889      * Unshare the old page.
1890      */
1891     DPRINT("Swapping page (Old %x New %x)\n", OldPage, NewPage);
1892     MmDeleteVirtualMapping(Process, PAddress, NULL, NULL);
1893     MmDeleteRmap(OldPage, Process, PAddress);
1894     MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, FALSE, FALSE, NULL);
1895     MmUnlockSectionSegment(Segment);
1896 
1897     /*
1898      * Set the PTE to point to the new page
1899      */
1900     Status = MmCreateVirtualMapping(Process,
1901                                     PAddress,
1902                                     Region->Protect,
1903                                     &NewPage,
1904                                     1);
1905     if (!NT_SUCCESS(Status))
1906     {
1907         DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1908         KeBugCheck(MEMORY_MANAGEMENT);
1909         return(Status);
1910     }
1911     MmInsertRmap(NewPage, Process, PAddress);
1912 
1913     MiSetPageEvent(Process, Address);
1914     DPRINT("Address 0x%p\n", Address);
1915     return(STATUS_SUCCESS);
1916 }
1917 
1918 VOID
1919 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
1920 {
1921     MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1922     BOOLEAN WasDirty;
1923     PFN_NUMBER Page = 0;
1924 
1925     PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1926     if (Process)
1927     {
1928         MmLockAddressSpace(&Process->Vm);
1929     }
1930 
1931     MmDeleteVirtualMapping(Process,
1932                            Address,
1933                            &WasDirty,
1934                            &Page);
1935     if (WasDirty)
1936     {
1937         PageOutContext->WasDirty = TRUE;
1938     }
1939     if (!PageOutContext->Private)
1940     {
1941         MmLockSectionSegment(PageOutContext->Segment);
1942         MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT)PageOutContext->Section,
1943                                          PageOutContext->Segment,
1944                                          &PageOutContext->Offset,
1945                                          PageOutContext->WasDirty,
1946                                          TRUE,
1947                                          &PageOutContext->SectionEntry);
1948         MmUnlockSectionSegment(PageOutContext->Segment);
1949     }
1950     if (Process)
1951     {
1952         MmUnlockAddressSpace(&Process->Vm);
1953     }
1954 
1955     if (PageOutContext->Private)
1956     {
1957         MmReleasePageMemoryConsumer(MC_USER, Page);
1958     }
1959 }
1960 
1961 NTSTATUS
1962 NTAPI
1963 MmPageOutSectionView(PMMSUPPORT AddressSpace,
1964                      MEMORY_AREA* MemoryArea,
1965                      PVOID Address, ULONG_PTR Entry)
1966 {
1967     PFN_NUMBER Page;
1968     MM_SECTION_PAGEOUT_CONTEXT Context;
1969     SWAPENTRY SwapEntry;
1970     NTSTATUS Status;
1971 #ifndef NEWCC
1972     ULONGLONG FileOffset;
1973     PFILE_OBJECT FileObject;
1974     PROS_SHARED_CACHE_MAP SharedCacheMap = NULL;
1975     BOOLEAN IsImageSection;
1976 #endif
1977     BOOLEAN DirectMapped;
1978     PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1979     KIRQL OldIrql;
1980 
1981     Address = (PVOID)PAGE_ROUND_DOWN(Address);
1982 
1983     /*
1984      * Get the segment and section.
1985      */
1986     Context.Segment = MemoryArea->Data.SectionData.Segment;
1987     Context.Section = MemoryArea->Data.SectionData.Section;
1988     Context.SectionEntry = Entry;
1989     Context.CallingProcess = Process;
1990 
1991     Context.Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)
1992                               + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
1993 
1994     DirectMapped = FALSE;
1995 
1996     MmLockSectionSegment(Context.Segment);
1997 
1998 #ifndef NEWCC
1999     FileOffset = Context.Offset.QuadPart + Context.Segment->Image.FileOffset;
2000     IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
2001     FileObject = Context.Section->FileObject;
2002 
2003     if (FileObject != NULL &&
2004             !(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
2005     {
2006         SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
2007 
2008         /*
2009          * If the file system is letting us go directly to the cache and the
2010          * memory area was mapped at an offset in the file which is page aligned
2011          * then note this is a direct mapped page.
2012          */
2013         if ((FileOffset % PAGE_SIZE) == 0 &&
2014                 (Context.Offset.QuadPart + PAGE_SIZE <= Context.Segment->RawLength.QuadPart || !IsImageSection))
2015         {
2016             DirectMapped = TRUE;
2017         }
2018     }
2019 #endif
2020 
2021 
2022     /*
2023      * This should never happen since mappings of physical memory are never
2024      * placed in the rmap lists.
2025      */
2026     if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
2027     {
2028         DPRINT1("Trying to page out from physical memory section address 0x%p "
2029                 "process %p\n", Address,
2030                 Process ? Process->UniqueProcessId : 0);
2031         KeBugCheck(MEMORY_MANAGEMENT);
2032     }
2033 
2034     /*
2035      * Get the section segment entry and the physical address.
2036      */
2037     if (!MmIsPagePresent(Process, Address))
2038     {
2039         DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2040                 Process ? Process->UniqueProcessId : 0, Address);
2041         KeBugCheck(MEMORY_MANAGEMENT);
2042     }
2043     Page = MmGetPfnForProcess(Process, Address);
2044     SwapEntry = MmGetSavedSwapEntryPage(Page);
2045 
2046     /*
2047      * Check the reference count to ensure this page can be paged out
2048      */
2049     if (MmGetReferenceCountPage(Page) != 1)
2050     {
2051         DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
2052                Page, MmGetReferenceCountPage(Page));
2053         MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2054         MmUnlockSectionSegment(Context.Segment);
2055         return STATUS_UNSUCCESSFUL;
2056     }
2057 
2058     /*
2059      * Prepare the context structure for the rmap delete call.
2060      */
2061     MmUnlockSectionSegment(Context.Segment);
2062     Context.WasDirty = FALSE;
2063     if (IS_SWAP_FROM_SSE(Entry) || PFN_FROM_SSE(Entry) != Page)
2064     {
2065         Context.Private = TRUE;
2066     }
2067     else
2068     {
2069         Context.Private = FALSE;
2070     }
2071 
2072     /*
2073      * Take an additional reference to the page or the VACB.
2074      */
2075     if (DirectMapped && !Context.Private)
2076     {
2077         if(!MiIsPageFromCache(MemoryArea, Context.Offset.QuadPart))
2078         {
2079             DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2080             KeBugCheck(MEMORY_MANAGEMENT);
2081         }
2082     }
2083     else
2084     {
2085         OldIrql = MiAcquirePfnLock();
2086         MmReferencePage(Page);
2087         MiReleasePfnLock(OldIrql);
2088     }
2089 
2090     MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping);
2091 
2092     /* Since we passed in a surrogate, we'll get back the page entry
2093      * state in our context.  This is intended to make intermediate
2094      * decrements of share count not release the wait entry.
2095      */
2096     Entry = Context.SectionEntry;
2097 
2098     /*
2099      * If this wasn't a private page then we should have reduced the entry to
2100      * zero by deleting all the rmaps.
2101      */
2102     if (!Context.Private && Entry != 0)
2103     {
2104         if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
2105                 !(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
2106         {
2107             KeBugCheckEx(MEMORY_MANAGEMENT, Entry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
2108         }
2109     }
2110 
2111     /*
2112      * If the page wasn't dirty then we can just free it as for a readonly page.
2113      * Since we unmapped all the mappings above we know it will not suddenly
2114      * become dirty.
2115      * If the page is from a pagefile section and has no swap entry,
2116      * we can't free the page at this point.
2117      */
2118     SwapEntry = MmGetSavedSwapEntryPage(Page);
2119     if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT)
2120     {
2121         if (Context.Private)
2122         {
2123             DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2124                     Context.WasDirty ? "dirty" : "clean", Address);
2125             KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
2126         }
2127         if (!Context.WasDirty && SwapEntry != 0)
2128         {
2129             MmSetSavedSwapEntryPage(Page, 0);
2130             MmLockSectionSegment(Context.Segment);
2131             MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2132             MmUnlockSectionSegment(Context.Segment);
2133             MmReleasePageMemoryConsumer(MC_USER, Page);
2134             MiSetPageEvent(NULL, NULL);
2135             return(STATUS_SUCCESS);
2136         }
2137     }
2138     else if (Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2139     {
2140         if (Context.Private)
2141         {
2142             DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2143                     Context.WasDirty ? "dirty" : "clean", Address);
2144             KeBugCheckEx(MEMORY_MANAGEMENT, Page, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
2145         }
2146         if (!Context.WasDirty || SwapEntry != 0)
2147         {
2148             MmSetSavedSwapEntryPage(Page, 0);
2149             if (SwapEntry != 0)
2150             {
2151                 MmLockSectionSegment(Context.Segment);
2152                 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2153                 MmUnlockSectionSegment(Context.Segment);
2154             }
2155             MmReleasePageMemoryConsumer(MC_USER, Page);
2156             MiSetPageEvent(NULL, NULL);
2157             return(STATUS_SUCCESS);
2158         }
2159     }
2160     else if (!Context.Private && DirectMapped)
2161     {
2162         if (SwapEntry != 0)
2163         {
2164             DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2165                     Address);
2166             KeBugCheckEx(MEMORY_MANAGEMENT, STATUS_UNSUCCESSFUL, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address);
2167         }
2168 #ifndef NEWCC
2169         Status = CcRosUnmapVacb(SharedCacheMap, FileOffset, FALSE);
2170 #else
2171         Status = STATUS_SUCCESS;
2172 #endif
2173 #ifndef NEWCC
2174         if (!NT_SUCCESS(Status))
2175         {
2176             DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status);
2177             KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)SharedCacheMap, (ULONG_PTR)FileOffset, (ULONG_PTR)Address);
2178         }
2179 #endif
2180         MiSetPageEvent(NULL, NULL);
2181         return(STATUS_SUCCESS);
2182     }
2183     else if (!Context.WasDirty && !DirectMapped && !Context.Private)
2184     {
2185         if (SwapEntry != 0)
2186         {
2187             DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2188                     Address);
2189             KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, Page, (ULONG_PTR)Process, (ULONG_PTR)Address);
2190         }
2191         MmReleasePageMemoryConsumer(MC_USER, Page);
2192         MiSetPageEvent(NULL, NULL);
2193         return(STATUS_SUCCESS);
2194     }
2195     else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
2196     {
2197         DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process, Address);
2198         MmSetSavedSwapEntryPage(Page, 0);
2199         MmLockAddressSpace(AddressSpace);
2200         Status = MmCreatePageFileMapping(Process,
2201                                          Address,
2202                                          SwapEntry);
2203         MmUnlockAddressSpace(AddressSpace);
2204         if (!NT_SUCCESS(Status))
2205         {
2206             DPRINT1("Status %x Swapping out %p:%p\n", Status, Process, Address);
2207             KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry);
2208         }
2209         MmReleasePageMemoryConsumer(MC_USER, Page);
2210         MiSetPageEvent(NULL, NULL);
2211         return(STATUS_SUCCESS);
2212     }
2213 
2214     /*
2215      * If necessary, allocate an entry in the paging file for this page
2216      */
2217     if (SwapEntry == 0)
2218     {
2219         SwapEntry = MmAllocSwapPage();
2220         if (SwapEntry == 0)
2221         {
2222             MmShowOutOfSpaceMessagePagingFile();
2223             MmLockAddressSpace(AddressSpace);
2224             /*
2225              * For private pages restore the old mappings.
2226              */
2227             if (Context.Private)
2228             {
2229                 Status = MmCreateVirtualMapping(Process,
2230                                                 Address,
2231                                                 MemoryArea->Protect,
2232                                                 &Page,
2233                                                 1);
2234                 MmSetDirtyPage(Process, Address);
2235                 MmInsertRmap(Page,
2236                              Process,
2237                              Address);
2238             }
2239             else
2240             {
2241                 ULONG_PTR OldEntry;
2242 
2243                 MmLockSectionSegment(Context.Segment);
2244 
2245                 /*
2246                  * For non-private pages if the page wasn't direct mapped then
2247                  * set it back into the section segment entry so we don't loose
2248                  * our copy. Otherwise it will be handled by the cache manager.
2249                  */
2250                 Status = MmCreateVirtualMapping(Process,
2251                                                 Address,
2252                                                 MemoryArea->Protect,
2253                                                 &Page,
2254                                                 1);
2255                 MmSetDirtyPage(Process, Address);
2256                 MmInsertRmap(Page,
2257                              Process,
2258                              Address);
2259                 // If we got here, the previous entry should have been a wait
2260                 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
2261                 OldEntry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset);
2262                 ASSERT(OldEntry == 0 || OldEntry == MAKE_SWAP_SSE(MM_WAIT_ENTRY));
2263                 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2264                 MmUnlockSectionSegment(Context.Segment);
2265             }
2266             MmUnlockAddressSpace(AddressSpace);
2267             MiSetPageEvent(NULL, NULL);
2268             return(STATUS_PAGEFILE_QUOTA);
2269         }
2270     }
2271 
2272     /*
2273      * Write the page to the pagefile
2274      */
2275     Status = MmWriteToSwapPage(SwapEntry, Page);
2276     if (!NT_SUCCESS(Status))
2277     {
2278         DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2279                 Status);
2280         /*
2281          * As above: undo our actions.
2282          * FIXME: Also free the swap page.
2283          */
2284         MmLockAddressSpace(AddressSpace);
2285         if (Context.Private)
2286         {
2287             Status = MmCreateVirtualMapping(Process,
2288                                             Address,
2289                                             MemoryArea->Protect,
2290                                             &Page,
2291                                             1);
2292             MmSetDirtyPage(Process, Address);
2293             MmInsertRmap(Page,
2294                          Process,
2295                          Address);
2296         }
2297         else
2298         {
2299             MmLockSectionSegment(Context.Segment);
2300             Status = MmCreateVirtualMapping(Process,
2301                                             Address,
2302                                             MemoryArea->Protect,
2303                                             &Page,
2304                                             1);
2305             MmSetDirtyPage(Process, Address);
2306             MmInsertRmap(Page,
2307                          Process,
2308                          Address);
2309             Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
2310             MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2311             MmUnlockSectionSegment(Context.Segment);
2312         }
2313         MmUnlockAddressSpace(AddressSpace);
2314         MiSetPageEvent(NULL, NULL);
2315         return(STATUS_UNSUCCESSFUL);
2316     }
2317 
2318     /*
2319      * Otherwise we have succeeded.
2320      */
2321     DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
2322     MmSetSavedSwapEntryPage(Page, 0);
2323     if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
2324             Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2325     {
2326         MmLockSectionSegment(Context.Segment);
2327         MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2328         MmUnlockSectionSegment(Context.Segment);
2329     }
2330     else
2331     {
2332         MmReleasePageMemoryConsumer(MC_USER, Page);
2333     }
2334 
2335     if (Context.Private)
2336     {
2337         MmLockAddressSpace(AddressSpace);
2338         MmLockSectionSegment(Context.Segment);
2339         Status = MmCreatePageFileMapping(Process,
2340                                          Address,
2341                                          SwapEntry);
2342         /* We had placed a wait entry upon entry ... replace it before leaving */
2343         MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2344         MmUnlockSectionSegment(Context.Segment);
2345         MmUnlockAddressSpace(AddressSpace);
2346         if (!NT_SUCCESS(Status))
2347         {
2348             DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status, Process, Address);
2349             KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry);
2350         }
2351     }
2352     else
2353     {
2354         MmLockAddressSpace(AddressSpace);
2355         MmLockSectionSegment(Context.Segment);
2356         Entry = MAKE_SWAP_SSE(SwapEntry);
2357         /* We had placed a wait entry upon entry ... replace it before leaving */
2358         MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2359         MmUnlockSectionSegment(Context.Segment);
2360         MmUnlockAddressSpace(AddressSpace);
2361     }
2362 
2363     MiSetPageEvent(NULL, NULL);
2364     return(STATUS_SUCCESS);
2365 }
2366 
2367 NTSTATUS
2368 NTAPI
2369 MmWritePageSectionView(PMMSUPPORT AddressSpace,
2370                        PMEMORY_AREA MemoryArea,
2371                        PVOID Address,
2372                        ULONG PageEntry)
2373 {
2374     LARGE_INTEGER Offset;
2375     PROS_SECTION_OBJECT Section;
2376     PMM_SECTION_SEGMENT Segment;
2377     PFN_NUMBER Page;
2378     SWAPENTRY SwapEntry;
2379     ULONG_PTR Entry;
2380     BOOLEAN Private;
2381     NTSTATUS Status;
2382     PFILE_OBJECT FileObject;
2383 #ifndef NEWCC
2384     PROS_SHARED_CACHE_MAP SharedCacheMap = NULL;
2385 #endif
2386     BOOLEAN DirectMapped;
2387     BOOLEAN IsImageSection;
2388     PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
2389 
2390     Address = (PVOID)PAGE_ROUND_DOWN(Address);
2391 
2392     Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)
2393                       + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
2394 
2395     /*
2396      * Get the segment and section.
2397      */
2398     Segment = MemoryArea->Data.SectionData.Segment;
2399     Section = MemoryArea->Data.SectionData.Section;
2400     IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
2401 
2402     FileObject = Section->FileObject;
2403     DirectMapped = FALSE;
2404     if (FileObject != NULL &&
2405             !(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
2406     {
2407 #ifndef NEWCC
2408         SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
2409 #endif
2410 
2411         /*
2412          * If the file system is letting us go directly to the cache and the
2413          * memory area was mapped at an offset in the file which is page aligned
2414          * then note this is a direct mapped page.
2415          */
2416         if (((Offset.QuadPart + Segment->Image.FileOffset) % PAGE_SIZE) == 0 &&
2417                 (Offset.QuadPart + PAGE_SIZE <= Segment->RawLength.QuadPart || !IsImageSection))
2418         {
2419             DirectMapped = TRUE;
2420         }
2421     }
2422 
2423     /*
2424      * This should never happen since mappings of physical memory are never
2425      * placed in the rmap lists.
2426      */
2427     if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
2428     {
2429         DPRINT1("Trying to write back page from physical memory mapped at %p "
2430                 "process %p\n", Address,
2431                 Process ? Process->UniqueProcessId : 0);
2432         KeBugCheck(MEMORY_MANAGEMENT);
2433     }
2434 
2435     /*
2436      * Get the section segment entry and the physical address.
2437      */
2438     Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
2439     if (!MmIsPagePresent(Process, Address))
2440     {
2441         DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2442                 Process ? Process->UniqueProcessId : 0, Address);
2443         KeBugCheck(MEMORY_MANAGEMENT);
2444     }
2445     Page = MmGetPfnForProcess(Process, Address);
2446     SwapEntry = MmGetSavedSwapEntryPage(Page);
2447 
2448     /*
2449      * Check for a private (COWed) page.
2450      */
2451     if (IS_SWAP_FROM_SSE(Entry) || PFN_FROM_SSE(Entry) != Page)
2452     {
2453         Private = TRUE;
2454     }
2455     else
2456     {
2457         Private = FALSE;
2458     }
2459 
2460     /*
2461      * Speculatively set all mappings of the page to clean.
2462      */
2463     MmSetCleanAllRmaps(Page);
2464 
2465     /*
2466      * If this page was direct mapped from the cache then the cache manager
2467      * will take care of writing it back to disk.
2468      */
2469     if (DirectMapped && !Private)
2470     {
2471         //LARGE_INTEGER SOffset;
2472         ASSERT(SwapEntry == 0);
2473         //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2474 #ifndef NEWCC
2475         CcRosMarkDirtyFile(SharedCacheMap, Offset.QuadPart);
2476 #endif
2477         MmLockSectionSegment(Segment);
2478         MmSetPageEntrySectionSegment(Segment, &Offset, PageEntry);
2479         MmUnlockSectionSegment(Segment);
2480         MiSetPageEvent(NULL, NULL);
2481         return(STATUS_SUCCESS);
2482     }
2483 
2484     /*
2485      * If necessary, allocate an entry in the paging file for this page
2486      */
2487     if (SwapEntry == 0)
2488     {
2489         SwapEntry = MmAllocSwapPage();
2490         if (SwapEntry == 0)
2491         {
2492             MmSetDirtyAllRmaps(Page);
2493             MiSetPageEvent(NULL, NULL);
2494             return(STATUS_PAGEFILE_QUOTA);
2495         }
2496         MmSetSavedSwapEntryPage(Page, SwapEntry);
2497     }
2498 
2499     /*
2500      * Write the page to the pagefile
2501      */
2502     Status = MmWriteToSwapPage(SwapEntry, Page);
2503     if (!NT_SUCCESS(Status))
2504     {
2505         DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2506                 Status);
2507         MmSetDirtyAllRmaps(Page);
2508         MiSetPageEvent(NULL, NULL);
2509         return(STATUS_UNSUCCESSFUL);
2510     }
2511 
2512     /*
2513      * Otherwise we have succeeded.
2514      */
2515     DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
2516     MiSetPageEvent(NULL, NULL);
2517     return(STATUS_SUCCESS);
2518 }
2519 
2520 NTSTATUS
2521 NTAPI
2522 MmProtectSectionView(PMMSUPPORT AddressSpace,
2523                      PMEMORY_AREA MemoryArea,
2524                      PVOID BaseAddress,
2525                      SIZE_T Length,
2526                      ULONG Protect,
2527                      PULONG OldProtect)
2528 {
2529     PMM_REGION Region;
2530     NTSTATUS Status;
2531     ULONG_PTR MaxLength;
2532 
2533     MaxLength = MA_GetEndingAddress(MemoryArea) - (ULONG_PTR)BaseAddress;
2534     if (Length > MaxLength)
2535         Length = (ULONG)MaxLength;
2536 
2537     Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
2538                           &MemoryArea->Data.SectionData.RegionListHead,
2539                           BaseAddress, NULL);
2540     ASSERT(Region != NULL);
2541 
2542     if ((MemoryArea->Flags & SEC_NO_CHANGE) &&
2543             Region->Protect != Protect)
2544     {
2545         return STATUS_INVALID_PAGE_PROTECTION;
2546     }
2547 
2548     *OldProtect = Region->Protect;
2549     Status = MmAlterRegion(AddressSpace, (PVOID)MA_GetStartingAddress(MemoryArea),
2550                            &MemoryArea->Data.SectionData.RegionListHead,
2551                            BaseAddress, Length, Region->Type, Protect,
2552                            MmAlterViewAttributes);
2553 
2554     return(Status);
2555 }
2556 
2557 NTSTATUS NTAPI
2558 MmQuerySectionView(PMEMORY_AREA MemoryArea,
2559                    PVOID Address,
2560                    PMEMORY_BASIC_INFORMATION Info,
2561                    PSIZE_T ResultLength)
2562 {
2563     PMM_REGION Region;
2564     PVOID RegionBaseAddress;
2565     PROS_SECTION_OBJECT Section;
2566     PMM_SECTION_SEGMENT Segment;
2567 
2568     Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
2569                           &MemoryArea->Data.SectionData.RegionListHead,
2570                           Address, &RegionBaseAddress);
2571     if (Region == NULL)
2572     {
2573         return STATUS_UNSUCCESSFUL;
2574     }
2575 
2576     Section = MemoryArea->Data.SectionData.Section;
2577     if (Section->AllocationAttributes & SEC_IMAGE)
2578     {
2579         Segment = MemoryArea->Data.SectionData.Segment;
2580         Info->AllocationBase = (PUCHAR)MA_GetStartingAddress(MemoryArea) - Segment->Image.VirtualAddress;
2581         Info->Type = MEM_IMAGE;
2582     }
2583     else
2584     {
2585         Info->AllocationBase = (PVOID)MA_GetStartingAddress(MemoryArea);
2586         Info->Type = MEM_MAPPED;
2587     }
2588     Info->BaseAddress = RegionBaseAddress;
2589     Info->AllocationProtect = MemoryArea->Protect;
2590     Info->RegionSize = Region->Length;
2591     Info->State = MEM_COMMIT;
2592     Info->Protect = Region->Protect;
2593 
2594     *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
2595     return(STATUS_SUCCESS);
2596 }
2597 
2598 VOID
2599 NTAPI
2600 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
2601 {
2602     ULONG Length;
2603     LARGE_INTEGER Offset;
2604     ULONG_PTR Entry;
2605     SWAPENTRY SavedSwapEntry;
2606     PFN_NUMBER Page;
2607 
2608     Page = 0;
2609 
2610     MmLockSectionSegment(Segment);
2611 
2612     Length = PAGE_ROUND_UP(Segment->Length.QuadPart);
2613     for (Offset.QuadPart = 0; Offset.QuadPart < Length; Offset.QuadPart += PAGE_SIZE)
2614     {
2615         Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
2616         if (Entry)
2617         {
2618             MmSetPageEntrySectionSegment(Segment, &Offset, 0);
2619             if (IS_SWAP_FROM_SSE(Entry))
2620             {
2621                 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
2622             }
2623             else
2624             {
2625                 Page = PFN_FROM_SSE(Entry);
2626                 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
2627                 if (SavedSwapEntry != 0)
2628                 {
2629                     MmSetSavedSwapEntryPage(Page, 0);
2630                     MmFreeSwapPage(SavedSwapEntry);
2631                 }
2632                 MmReleasePageMemoryConsumer(MC_USER, Page);
2633             }
2634         }
2635     }
2636 
2637     MmUnlockSectionSegment(Segment);
2638 }
2639 
2640 VOID NTAPI
2641 MmpDeleteSection(PVOID ObjectBody)
2642 {
2643     PROS_SECTION_OBJECT Section = (PROS_SECTION_OBJECT)ObjectBody;
2644 
2645     /* Check if it's an ARM3, or ReactOS section */
2646     if (!MiIsRosSectionObject(Section))
2647     {
2648         MiDeleteARM3Section(ObjectBody);
2649         return;
2650     }
2651 
2652     DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody);
2653     if (Section->AllocationAttributes & SEC_IMAGE)
2654     {
2655         ULONG i;
2656         ULONG NrSegments;
2657         ULONG RefCount;
2658         PMM_SECTION_SEGMENT SectionSegments;
2659 
2660         /*
2661          * NOTE: Section->ImageSection can be NULL for short time
2662          * during the section creating. If we fail for some reason
2663          * until the image section is properly initialized we shouldn't
2664          * process further here.
2665          */
2666         if (Section->ImageSection == NULL)
2667             return;
2668 
2669         SectionSegments = Section->ImageSection->Segments;
2670         NrSegments = Section->ImageSection->NrSegments;
2671 
2672         for (i = 0; i < NrSegments; i++)
2673         {
2674             if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2675             {
2676                 MmLockSectionSegment(&SectionSegments[i]);
2677             }
2678             RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount);
2679             if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2680             {
2681                 MmUnlockSectionSegment(&SectionSegments[i]);
2682                 if (RefCount == 0)
2683                 {
2684                     MmpFreePageFileSegment(&SectionSegments[i]);
2685                 }
2686             }
2687         }
2688     }
2689 #ifdef NEWCC
2690     else if (Section->Segment && Section->Segment->Flags & MM_DATAFILE_SEGMENT)
2691     {
2692         ULONG RefCount = 0;
2693         PMM_SECTION_SEGMENT Segment = Section->Segment;
2694 
2695         if (Segment &&
2696                 (RefCount = InterlockedDecrementUL(&Segment->ReferenceCount)) == 0)
2697         {
2698             DPRINT("Freeing section segment\n");
2699             Section->Segment = NULL;
2700             MmFinalizeSegment(Segment);
2701         }
2702         else
2703         {
2704             DPRINT("RefCount %d\n", RefCount);
2705         }
2706     }
2707 #endif
2708     else
2709     {
2710         /*
2711          * NOTE: Section->Segment can be NULL for short time
2712          * during the section creating.
2713          */
2714         if (Section->Segment == NULL)
2715             return;
2716 
2717         if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
2718         {
2719             MmpFreePageFileSegment(Section->Segment);
2720             MmFreePageTablesSectionSegment(Section->Segment, NULL);
2721             ExFreePool(Section->Segment);
2722             Section->Segment = NULL;
2723         }
2724         else
2725         {
2726             (void)InterlockedDecrementUL(&Section->Segment->ReferenceCount);
2727         }
2728     }
2729     if (Section->FileObject != NULL)
2730     {
2731 #ifndef NEWCC
2732         CcRosDereferenceCache(Section->FileObject);
2733 #endif
2734         ObDereferenceObject(Section->FileObject);
2735         Section->FileObject = NULL;
2736     }
2737 }
2738 
2739 VOID NTAPI
2740 MmpCloseSection(IN PEPROCESS Process OPTIONAL,
2741                 IN PVOID Object,
2742                 IN ACCESS_MASK GrantedAccess,
2743                 IN ULONG ProcessHandleCount,
2744                 IN ULONG SystemHandleCount)
2745 {
2746     DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object, ProcessHandleCount);
2747 }
2748 
2749 NTSTATUS
2750 INIT_FUNCTION
2751 NTAPI
2752 MmCreatePhysicalMemorySection(VOID)
2753 {
2754     PROS_SECTION_OBJECT PhysSection;
2755     NTSTATUS Status;
2756     OBJECT_ATTRIBUTES Obj;
2757     UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
2758     LARGE_INTEGER SectionSize;
2759     HANDLE Handle;
2760 
2761     /*
2762      * Create the section mapping physical memory
2763      */
2764     SectionSize.QuadPart = 0xFFFFFFFF;
2765     InitializeObjectAttributes(&Obj,
2766                                &Name,
2767                                OBJ_PERMANENT | OBJ_KERNEL_EXCLUSIVE,
2768                                NULL,
2769                                NULL);
2770     Status = MmCreateSection((PVOID)&PhysSection,
2771                              SECTION_ALL_ACCESS,
2772                              &Obj,
2773                              &SectionSize,
2774                              PAGE_EXECUTE_READWRITE,
2775                              SEC_PHYSICALMEMORY,
2776                              NULL,
2777                              NULL);
2778     if (!NT_SUCCESS(Status))
2779     {
2780         DPRINT1("Failed to create PhysicalMemory section\n");
2781         KeBugCheck(MEMORY_MANAGEMENT);
2782     }
2783     Status = ObInsertObject(PhysSection,
2784                             NULL,
2785                             SECTION_ALL_ACCESS,
2786                             0,
2787                             NULL,
2788                             &Handle);
2789     if (!NT_SUCCESS(Status))
2790     {
2791         ObDereferenceObject(PhysSection);
2792     }
2793     ObCloseHandle(Handle, KernelMode);
2794     PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
2795     PhysSection->Segment->Flags &= ~MM_PAGEFILE_SEGMENT;
2796 
2797     return(STATUS_SUCCESS);
2798 }
2799 
2800 NTSTATUS
2801 INIT_FUNCTION
2802 NTAPI
2803 MmInitSectionImplementation(VOID)
2804 {
2805     OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
2806     UNICODE_STRING Name;
2807 
2808     DPRINT("Creating Section Object Type\n");
2809 
2810     /* Initialize the section based root */
2811     ASSERT(MmSectionBasedRoot.NumberGenericTableElements == 0);
2812     MmSectionBasedRoot.BalancedRoot.u1.Parent = &MmSectionBasedRoot.BalancedRoot;
2813 
2814     /* Initialize the Section object type  */
2815     RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
2816     RtlInitUnicodeString(&Name, L"Section");
2817     ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
2818     ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(ROS_SECTION_OBJECT);
2819     ObjectTypeInitializer.PoolType = PagedPool;
2820     ObjectTypeInitializer.UseDefaultObject = TRUE;
2821     ObjectTypeInitializer.GenericMapping = MmpSectionMapping;
2822     ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection;
2823     ObjectTypeInitializer.CloseProcedure = MmpCloseSection;
2824     ObjectTypeInitializer.ValidAccessMask = SECTION_ALL_ACCESS;
2825     ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
2826     ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &MmSectionObjectType);
2827 
2828     MmCreatePhysicalMemorySection();
2829 
2830     return(STATUS_SUCCESS);
2831 }
2832 
2833 NTSTATUS
2834 NTAPI
2835 MmCreatePageFileSection(PROS_SECTION_OBJECT *SectionObject,
2836                         ACCESS_MASK DesiredAccess,
2837                         POBJECT_ATTRIBUTES ObjectAttributes,
2838                         PLARGE_INTEGER UMaximumSize,
2839                         ULONG SectionPageProtection,
2840                         ULONG AllocationAttributes)
2841 /*
2842  * Create a section which is backed by the pagefile
2843  */
2844 {
2845     LARGE_INTEGER MaximumSize;
2846     PROS_SECTION_OBJECT Section;
2847     PMM_SECTION_SEGMENT Segment;
2848     NTSTATUS Status;
2849 
2850     if (UMaximumSize == NULL)
2851     {
2852         DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2853         return(STATUS_INVALID_PARAMETER);
2854     }
2855     MaximumSize = *UMaximumSize;
2856 
2857     /*
2858      * Create the section
2859      */
2860     Status = ObCreateObject(ExGetPreviousMode(),
2861                             MmSectionObjectType,
2862                             ObjectAttributes,
2863                             ExGetPreviousMode(),
2864                             NULL,
2865                             sizeof(ROS_SECTION_OBJECT),
2866                             0,
2867                             0,
2868                             (PVOID*)(PVOID)&Section);
2869     if (!NT_SUCCESS(Status))
2870     {
2871         DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status);
2872         return(Status);
2873     }
2874 
2875     /*
2876      * Initialize it
2877      */
2878     RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
2879     Section->Type = 'SC';
2880     Section->Size = 'TN';
2881     Section->SectionPageProtection = SectionPageProtection;
2882     Section->AllocationAttributes = AllocationAttributes;
2883     Section->MaximumSize = MaximumSize;
2884     Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2885                                     TAG_MM_SECTION_SEGMENT);
2886     if (Segment == NULL)
2887     {
2888         ObDereferenceObject(Section);
2889         return(STATUS_NO_MEMORY);
2890     }
2891     RtlZeroMemory(Segment, sizeof(MM_SECTION_SEGMENT));
2892     Section->Segment = Segment;
2893     Segment->ReferenceCount = 1;
2894     ExInitializeFastMutex(&Segment->Lock);
2895     Segment->Image.FileOffset = 0;
2896     Segment->Protection = SectionPageProtection;
2897     Segment->RawLength.QuadPart = MaximumSize.u.LowPart;
2898     Segment->Length.QuadPart = PAGE_ROUND_UP(MaximumSize.u.LowPart);
2899     Segment->Flags = MM_PAGEFILE_SEGMENT;
2900     Segment->WriteCopy = FALSE;
2901     Segment->Image.VirtualAddress = 0;
2902     Segment->Image.Characteristics = 0;
2903     *SectionObject = Section;
2904     MiInitializeSectionPageTable(Segment);
2905     return(STATUS_SUCCESS);
2906 }
2907 
2908 NTSTATUS
2909 NTAPI
2910 MmCreateDataFileSection(PROS_SECTION_OBJECT *SectionObject,
2911                         ACCESS_MASK DesiredAccess,
2912                         POBJECT_ATTRIBUTES ObjectAttributes,
2913                         PLARGE_INTEGER UMaximumSize,
2914                         ULONG SectionPageProtection,
2915                         ULONG AllocationAttributes,
2916                         PFILE_OBJECT FileObject)
2917 /*
2918  * Create a section backed by a data file
2919  */
2920 {
2921     PROS_SECTION_OBJECT Section;
2922     NTSTATUS Status;
2923     LARGE_INTEGER MaximumSize;
2924     PMM_SECTION_SEGMENT Segment;
2925     FILE_STANDARD_INFORMATION FileInfo;
2926     ULONG Length;
2927 
2928     /*
2929      * Create the section
2930      */
2931     Status = ObCreateObject(ExGetPreviousMode(),
2932                             MmSectionObjectType,
2933                             ObjectAttributes,
2934                             ExGetPreviousMode(),
2935                             NULL,
2936                             sizeof(ROS_SECTION_OBJECT),
2937                             0,
2938                             0,
2939                             (PVOID*)&Section);
2940     if (!NT_SUCCESS(Status))
2941     {
2942         ObDereferenceObject(FileObject);
2943         return(Status);
2944     }
2945     /*
2946      * Initialize it
2947      */
2948     RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
2949     Section->Type = 'SC';
2950     Section->Size = 'TN';
2951     Section->SectionPageProtection = SectionPageProtection;
2952     Section->AllocationAttributes = AllocationAttributes;
2953 
2954     /*
2955      * FIXME: This is propably not entirely correct. We can't look into
2956      * the standard FCB header because it might not be initialized yet
2957      * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2958      * standard file information is filled on first request).
2959      */
2960     Status = IoQueryFileInformation(FileObject,
2961                                     FileStandardInformation,
2962                                     sizeof(FILE_STANDARD_INFORMATION),
2963                                     &FileInfo,
2964                                     &Length);
2965     if (!NT_SUCCESS(Status))
2966     {
2967         ObDereferenceObject(Section);
2968         ObDereferenceObject(FileObject);
2969         return Status;
2970     }
2971 
2972     /*
2973      * FIXME: Revise this once a locking order for file size changes is
2974      * decided
2975      */
2976     if ((UMaximumSize != NULL) && (UMaximumSize->QuadPart != 0))
2977     {
2978         MaximumSize = *UMaximumSize;
2979     }
2980     else
2981     {
2982         MaximumSize = FileInfo.EndOfFile;
2983         /* Mapping zero-sized files isn't allowed. */
2984         if (MaximumSize.QuadPart == 0)
2985         {
2986             ObDereferenceObject(Section);
2987             ObDereferenceObject(FileObject);
2988             return STATUS_MAPPED_FILE_SIZE_ZERO;
2989         }
2990     }
2991 
2992     if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart)
2993     {
2994         Status = IoSetInformation(FileObject,
2995                                   FileEndOfFileInformation,
2996                                   sizeof(LARGE_INTEGER),
2997                                   &MaximumSize);
2998         if (!NT_SUCCESS(Status))
2999         {
3000             ObDereferenceObject(Section);
3001             ObDereferenceObject(FileObject);
3002             return(STATUS_SECTION_NOT_EXTENDED);
3003         }
3004     }
3005 
3006     if (FileObject->SectionObjectPointer == NULL ||
3007             FileObject->SectionObjectPointer->SharedCacheMap == NULL)
3008     {
3009         ObDereferenceObject(Section);
3010         ObDereferenceObject(FileObject);
3011         return STATUS_INVALID_FILE_FOR_SECTION;
3012     }
3013 
3014     /*
3015      * Lock the file
3016      */
3017     Status = MmspWaitForFileLock(FileObject);
3018     if (Status != STATUS_SUCCESS)
3019     {
3020         ObDereferenceObject(Section);
3021         ObDereferenceObject(FileObject);
3022         return(Status);
3023     }
3024 
3025     /*
3026      * If this file hasn't been mapped as a data file before then allocate a
3027      * section segment to describe the data file mapping
3028      */
3029     if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
3030     {
3031         Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
3032                                         TAG_MM_SECTION_SEGMENT);
3033         if (Segment == NULL)
3034         {
3035             //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3036             ObDereferenceObject(Section);
3037             ObDereferenceObject(FileObject);
3038             return(STATUS_NO_MEMORY);
3039         }
3040         Section->Segment = Segment;
3041         Segment->ReferenceCount = 1;
3042         ExInitializeFastMutex(&Segment->Lock);
3043         /*
3044          * Set the lock before assigning the segment to the file object
3045          */
3046         ExAcquireFastMutex(&Segment->Lock);
3047         FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
3048 
3049         Segment->Image.FileOffset = 0;
3050         Segment->Protection = SectionPageProtection;
3051         Segment->Flags = MM_DATAFILE_SEGMENT;
3052         Segment->Image.Characteristics = 0;
3053         Segment->WriteCopy = (SectionPageProtection & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY));
3054         if (AllocationAttributes & SEC_RESERVE)
3055         {
3056             Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0;
3057         }
3058         else
3059         {
3060             Segment->RawLength.QuadPart = MaximumSize.QuadPart;
3061             Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
3062         }
3063         Segment->Image.VirtualAddress = 0;
3064         Segment->Locked = TRUE;
3065         MiInitializeSectionPageTable(Segment);
3066     }
3067     else
3068     {
3069         /*
3070          * If the file is already mapped as a data file then we may need
3071          * to extend it
3072          */
3073         Segment =
3074             (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
3075             DataSectionObject;
3076         Section->Segment = Segment;
3077         (void)InterlockedIncrementUL(&Segment->ReferenceCount);
3078         MmLockSectionSegment(Segment);
3079 
3080         if (MaximumSize.QuadPart > Segment->RawLength.QuadPart &&
3081                 !(AllocationAttributes & SEC_RESERVE))
3082         {
3083             Segment->RawLength.QuadPart = MaximumSize.QuadPart;
3084             Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
3085         }
3086     }
3087     MmUnlockSectionSegment(Segment);
3088     Section->FileObject = FileObject;
3089     Section->MaximumSize = MaximumSize;
3090 #ifndef NEWCC
3091     CcRosReferenceCache(FileObject);
3092 #endif
3093     //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3094     *SectionObject = Section;
3095     return(STATUS_SUCCESS);
3096 }
3097 
3098 /*
3099  TODO: not that great (declaring loaders statically, having to declare all of
3100  them, having to keep them extern, etc.), will fix in the future
3101 */
3102 extern NTSTATUS NTAPI PeFmtCreateSection
3103 (
3104     IN CONST VOID * FileHeader,
3105     IN SIZE_T FileHeaderSize,
3106     IN PVOID File,
3107     OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3108     OUT PULONG Flags,
3109     IN PEXEFMT_CB_READ_FILE ReadFileCb,
3110     IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3111 );
3112 
3113 extern NTSTATUS NTAPI ElfFmtCreateSection
3114 (
3115     IN CONST VOID * FileHeader,
3116     IN SIZE_T FileHeaderSize,
3117     IN PVOID File,
3118     OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3119     OUT PULONG Flags,
3120     IN PEXEFMT_CB_READ_FILE ReadFileCb,
3121     IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3122 );
3123 
3124 static PEXEFMT_LOADER ExeFmtpLoaders[] =
3125 {
3126     PeFmtCreateSection,
3127 #ifdef __ELF
3128     ElfFmtCreateSection
3129 #endif
3130 };
3131 
3132 static
3133 PMM_SECTION_SEGMENT
3134 NTAPI
3135 ExeFmtpAllocateSegments(IN ULONG NrSegments)
3136 {
3137     SIZE_T SizeOfSegments;
3138     PMM_SECTION_SEGMENT Segments;
3139 
3140     /* TODO: check for integer overflow */
3141     SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments;
3142 
3143     Segments = ExAllocatePoolWithTag(NonPagedPool,
3144                                      SizeOfSegments,
3145                                      TAG_MM_SECTION_SEGMENT);
3146 
3147     if(Segments)
3148         RtlZeroMemory(Segments, SizeOfSegments);
3149 
3150     return Segments;
3151 }
3152 
3153 static
3154 NTSTATUS
3155 NTAPI
3156 ExeFmtpReadFile(IN PVOID File,
3157                 IN PLARGE_INTEGER Offset,
3158                 IN ULONG Length,
3159                 OUT PVOID * Data,
3160                 OUT PVOID * AllocBase,
3161                 OUT PULONG ReadSize)
3162 {
3163     NTSTATUS Status;
3164     LARGE_INTEGER FileOffset;
3165     ULONG AdjustOffset;
3166     ULONG OffsetAdjustment;
3167     ULONG BufferSize;
3168     ULONG UsedSize;
3169     PVOID Buffer;
3170     PFILE_OBJECT FileObject = File;
3171     IO_STATUS_BLOCK Iosb;
3172 
3173     ASSERT_IRQL_LESS(DISPATCH_LEVEL);
3174 
3175     if(Length == 0)
3176     {
3177         KeBugCheck(MEMORY_MANAGEMENT);
3178     }
3179 
3180     FileOffset = *Offset;
3181 
3182     /* Negative/special offset: it cannot be used in this context */
3183     if(FileOffset.u.HighPart < 0)
3184     {
3185         KeBugCheck(MEMORY_MANAGEMENT);
3186     }
3187 
3188     AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart);
3189     OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset;
3190     FileOffset.u.LowPart = AdjustOffset;
3191 
3192     BufferSize = Length + OffsetAdjustment;
3193     BufferSize = PAGE_ROUND_UP(BufferSize);
3194 
3195     /* Flush data since we're about to perform a non-cached read */
3196     CcFlushCache(FileObject->SectionObjectPointer,
3197                  &FileOffset,
3198                  BufferSize,
3199                  &Iosb);
3200 
3201     /*
3202      * It's ok to use paged pool, because this is a temporary buffer only used in
3203      * the loading of executables. The assumption is that MmCreateSection is
3204      * always called at low IRQLs and that these buffers don't survive a brief
3205      * initialization phase
3206      */
3207     Buffer = ExAllocatePoolWithTag(PagedPool,
3208                                    BufferSize,
3209                                    'rXmM');
3210     if (!Buffer)
3211     {
3212         return STATUS_INSUFFICIENT_RESOURCES;
3213     }
3214 
3215     UsedSize = 0;
3216 
3217     Status = MiSimpleRead(FileObject, &FileOffset, Buffer, BufferSize, TRUE, &Iosb);
3218 
3219     UsedSize = (ULONG)Iosb.Information;
3220 
3221     if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
3222     {
3223         Status = STATUS_IN_PAGE_ERROR;
3224         ASSERT(!NT_SUCCESS(Status));
3225     }
3226 
3227     if(NT_SUCCESS(Status))
3228     {
3229         *Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment);
3230         *AllocBase = Buffer;
3231         *ReadSize = UsedSize - OffsetAdjustment;
3232     }
3233     else
3234     {
3235         ExFreePoolWithTag(Buffer, 'rXmM');
3236     }
3237 
3238     return Status;
3239 }
3240 
3241 #ifdef NASSERT
3242 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3243 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3244 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3245 #else
3246 static
3247 VOID
3248 NTAPI
3249 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3250 {
3251     ULONG i;
3252 
3253     for( i = 1; i < ImageSectionObject->NrSegments; ++ i )
3254     {
3255         ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >=
3256                ImageSectionObject->Segments[i - 1].Image.VirtualAddress);
3257     }
3258 }
3259 
3260 static
3261 VOID
3262 NTAPI
3263 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3264 {
3265     ULONG i;
3266 
3267     MmspAssertSegmentsSorted(ImageSectionObject);
3268 
3269     for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3270     {
3271         ASSERT(ImageSectionObject->Segments[i].Length.QuadPart > 0);
3272 
3273         if(i > 0)
3274         {
3275             ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >=
3276                    (ImageSectionObject->Segments[i - 1].Image.VirtualAddress +
3277                     ImageSectionObject->Segments[i - 1].Length.QuadPart));
3278         }
3279     }
3280 }
3281 
3282 static
3283 VOID
3284 NTAPI
3285 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3286 {
3287     ULONG i;
3288 
3289     for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3290     {
3291         ASSERT((ImageSectionObject->Segments[i].Image.VirtualAddress % PAGE_SIZE) == 0);
3292         ASSERT((ImageSectionObject->Segments[i].Length.QuadPart % PAGE_SIZE) == 0);
3293     }
3294 }
3295 #endif
3296 
3297 static
3298 int
3299 __cdecl
3300 MmspCompareSegments(const void * x,
3301                     const void * y)
3302 {
3303     const MM_SECTION_SEGMENT *Segment1 = (const MM_SECTION_SEGMENT *)x;
3304     const MM_SECTION_SEGMENT *Segment2 = (const MM_SECTION_SEGMENT *)y;
3305 
3306     return
3307         (Segment1->Image.VirtualAddress - Segment2->Image.VirtualAddress) >>
3308         ((sizeof(ULONG_PTR) - sizeof(int)) * 8);
3309 }
3310 
3311 /*
3312  * Ensures an image section's segments are sorted in memory
3313  */
3314 static
3315 VOID
3316 NTAPI
3317 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3318                  IN ULONG Flags)
3319 {
3320     if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED)
3321     {
3322         MmspAssertSegmentsSorted(ImageSectionObject);
3323     }
3324     else
3325     {
3326         qsort(ImageSectionObject->Segments,
3327               ImageSectionObject->NrSegments,
3328               sizeof(ImageSectionObject->Segments[0]),
3329               MmspCompareSegments);
3330     }
3331 }
3332 
3333 
3334 /*
3335  * Ensures an image section's segments don't overlap in memory and don't have
3336  * gaps and don't have a null size. We let them map to overlapping file regions,
3337  * though - that's not necessarily an error
3338  */
3339 static
3340 BOOLEAN
3341 NTAPI
3342 MmspCheckSegmentBounds
3343 (
3344     IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3345     IN ULONG Flags
3346 )
3347 {
3348     ULONG i;
3349 
3350     if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP)
3351     {
3352         MmspAssertSegmentsNoOverlap(ImageSectionObject);
3353         return TRUE;
3354     }
3355 
3356     ASSERT(ImageSectionObject->NrSegments >= 1);
3357 
3358     for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3359     {
3360         if(ImageSectionObject->Segments[i].Length.QuadPart == 0)
3361         {
3362             return FALSE;
3363         }
3364 
3365         if(i > 0)
3366         {
3367             /*
3368              * TODO: relax the limitation on gaps. For example, gaps smaller than a
3369              * page could be OK (Windows seems to be OK with them), and larger gaps
3370              * could lead to image sections spanning several discontiguous regions
3371              * (NtMapViewOfSection could then refuse to map them, and they could
3372              * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3373              */
3374             if ((ImageSectionObject->Segments[i - 1].Image.VirtualAddress +
3375                     ImageSectionObject->Segments[i - 1].Length.QuadPart) !=
3376                     ImageSectionObject->Segments[i].Image.VirtualAddress)
3377             {
3378                 return FALSE;
3379             }
3380         }
3381     }
3382 
3383     return TRUE;
3384 }
3385 
3386 /*
3387  * Merges and pads an image section's segments until they all are page-aligned
3388  * and have a size that is a multiple of the page size
3389  */
3390 static
3391 BOOLEAN
3392 NTAPI
3393 MmspPageAlignSegments
3394 (
3395     IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3396     IN ULONG Flags
3397 )
3398 {
3399     ULONG i;
3400     ULONG LastSegment;
3401     PMM_SECTION_SEGMENT EffectiveSegment;
3402 
3403     if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED)
3404     {
3405         MmspAssertSegmentsPageAligned(ImageSectionObject);
3406         return TRUE;
3407     }
3408 
3409     LastSegment = 0;
3410     EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
3411 
3412     for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3413     {
3414         /*
3415          * The first segment requires special handling
3416          */
3417         if (i == 0)
3418         {
3419             ULONG_PTR VirtualAddress;
3420             ULONG_PTR VirtualOffset;
3421 
3422             VirtualAddress = EffectiveSegment->Image.VirtualAddress;
3423 
3424             /* Round down the virtual address to the nearest page */
3425             EffectiveSegment->Image.VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
3426 
3427             /* Round up the virtual size to the nearest page */
3428             EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length.QuadPart) -
3429                                                 EffectiveSegment->Image.VirtualAddress;
3430 
3431             /* Adjust the raw address and size */
3432             VirtualOffset = VirtualAddress - EffectiveSegment->Image.VirtualAddress;
3433 
3434             if (EffectiveSegment->Image.FileOffset < VirtualOffset)
3435             {
3436                 return FALSE;
3437             }
3438 
3439             /*
3440              * Garbage in, garbage out: unaligned base addresses make the file
3441              * offset point in curious and odd places, but that's what we were
3442              * asked for
3443              */
3444             EffectiveSegment->Image.FileOffset -= VirtualOffset;
3445             EffectiveSegment->RawLength.QuadPart += VirtualOffset;
3446         }
3447         else
3448         {
3449             PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
3450             ULONG_PTR EndOfEffectiveSegment;
3451 
3452             EndOfEffectiveSegment = (ULONG_PTR)(EffectiveSegment->Image.VirtualAddress + EffectiveSegment->Length.QuadPart);
3453             ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
3454 
3455             /*
3456              * The current segment begins exactly where the current effective
3457              * segment ended, therefore beginning a new effective segment
3458              */
3459             if (EndOfEffectiveSegment == Segment->Image.VirtualAddress)
3460             {
3461                 LastSegment ++;
3462                 ASSERT(LastSegment <= i);
3463                 ASSERT(LastSegment < ImageSectionObject->NrSegments);
3464 
3465                 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
3466 
3467                 if (LastSegment != i)
3468                 {
3469                     /*
3470                      * Copy the current segment. If necessary, the effective segment
3471                      * will be expanded later
3472                      */
3473                     *EffectiveSegment = *Segment;
3474                 }
3475 
3476                 /*
3477                  * Page-align the virtual size. We know for sure the virtual address
3478                  * already is
3479                  */
3480                 ASSERT((EffectiveSegment->Image.VirtualAddress % PAGE_SIZE) == 0);
3481                 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(EffectiveSegment->Length.QuadPart);
3482             }
3483             /*
3484              * The current segment is still part of the current effective segment:
3485              * extend the effective segment to reflect this
3486              */
3487             else if (EndOfEffectiveSegment > Segment->Image.VirtualAddress)
3488             {
3489                 static const ULONG FlagsToProtection[16] =
3490                 {
3491                     PAGE_NOACCESS,
3492                     PAGE_READONLY,
3493                     PAGE_READWRITE,
3494                     PAGE_READWRITE,
3495                     PAGE_EXECUTE_READ,
3496                     PAGE_EXECUTE_READ,
3497                     PAGE_EXECUTE_READWRITE,
3498                     PAGE_EXECUTE_READWRITE,
3499                     PAGE_WRITECOPY,
3500                     PAGE_WRITECOPY,
3501                     PAGE_WRITECOPY,
3502                     PAGE_WRITECOPY,
3503                     PAGE_EXECUTE_WRITECOPY,
3504                     PAGE_EXECUTE_WRITECOPY,
3505                     PAGE_EXECUTE_WRITECOPY,
3506                     PAGE_EXECUTE_WRITECOPY
3507                 };
3508 
3509                 unsigned ProtectionFlags;
3510 
3511                 /*
3512                  * Extend the file size
3513                  */
3514 
3515                 /* Unaligned segments must be contiguous within the file */
3516                 if (Segment->Image.FileOffset != (EffectiveSegment->Image.FileOffset +
3517                                                   EffectiveSegment->RawLength.QuadPart))
3518                 {
3519                     return FALSE;
3520                 }
3521 
3522                 EffectiveSegment->RawLength.QuadPart += Segment->RawLength.QuadPart;
3523 
3524                 /*
3525                  * Extend the virtual size
3526                  */
3527                 ASSERT(PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) >= EndOfEffectiveSegment);
3528 
3529                 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) -
3530                                                     EffectiveSegment->Image.VirtualAddress;
3531 
3532                 /*
3533                  * Merge the protection
3534                  */
3535                 EffectiveSegment->Protection |= Segment->Protection;
3536 
3537                 /* Clean up redundance */
3538                 ProtectionFlags = 0;
3539 
3540                 if(EffectiveSegment->Protection & PAGE_IS_READABLE)
3541                     ProtectionFlags |= 1 << 0;
3542 
3543                 if(EffectiveSegment->Protection & PAGE_IS_WRITABLE)
3544                     ProtectionFlags |= 1 << 1;
3545 
3546                 if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE)
3547                     ProtectionFlags |= 1 << 2;
3548 
3549                 if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3550                     ProtectionFlags |= 1 << 3;
3551 
3552                 ASSERT(ProtectionFlags < 16);
3553                 EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags];
3554 
3555                 /* If a segment was required to be shared and cannot, fail */
3556                 if(!(Segment->Protection & PAGE_IS_WRITECOPY) &&
3557                         EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3558                 {
3559                     return FALSE;
3560                 }
3561             }
3562             /*
3563              * We assume no holes between segments at this point
3564              */
3565             else
3566             {
3567                 KeBugCheck(MEMORY_MANAGEMENT);
3568             }
3569         }
3570     }
3571     ImageSectionObject->NrSegments = LastSegment + 1;
3572 
3573     return TRUE;
3574 }
3575 
3576 NTSTATUS
3577 ExeFmtpCreateImageSection(PFILE_OBJECT FileObject,
3578                           PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3579 {
3580     LARGE_INTEGER Offset;
3581     PVOID FileHeader;
3582     PVOID FileHeaderBuffer;
3583     ULONG FileHeaderSize;
3584     ULONG Flags;
3585     ULONG OldNrSegments;
3586     NTSTATUS Status;
3587     ULONG i;
3588 
3589     /*
3590      * Read the beginning of the file (2 pages). Should be enough to contain
3591      * all (or most) of the headers
3592      */
3593     Offset.QuadPart = 0;
3594 
3595     Status = ExeFmtpReadFile (FileObject,
3596                               &Offset,
3597                               PAGE_SIZE * 2,
3598                               &FileHeader,
3599                               &FileHeaderBuffer,
3600                               &FileHeaderSize);
3601 
3602     if (!NT_SUCCESS(Status))
3603         return Status;
3604 
3605     if (FileHeaderSize == 0)
3606     {
3607         ExFreePool(FileHeaderBuffer);
3608         return STATUS_UNSUCCESSFUL;
3609     }
3610 
3611     /*
3612      * Look for a loader that can handle this executable
3613      */
3614     for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i)
3615     {
3616         RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject));
3617         Flags = 0;
3618 
3619         Status = ExeFmtpLoaders[i](FileHeader,
3620                                    FileHeaderSize,
3621                                    FileObject,
3622                                    ImageSectionObject,
3623                                    &Flags,
3624                                    ExeFmtpReadFile,
3625                                    ExeFmtpAllocateSegments);
3626 
3627         if (!NT_SUCCESS(Status))
3628         {
3629             if (ImageSectionObject->Segments)
3630             {
3631                 ExFreePool(ImageSectionObject->Segments);
3632                 ImageSectionObject->Segments = NULL;
3633             }
3634         }
3635 
3636         if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3637             break;
3638     }
3639 
3640     ExFreePoolWithTag(FileHeaderBuffer, 'rXmM');
3641 
3642     /*
3643      * No loader handled the format
3644      */
3645     if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3646     {
3647         Status = STATUS_INVALID_IMAGE_NOT_MZ;
3648         ASSERT(!NT_SUCCESS(Status));
3649     }
3650 
3651     if (!NT_SUCCESS(Status))
3652         return Status;
3653 
3654     ASSERT(ImageSectionObject->Segments != NULL);
3655 
3656     /*
3657      * Some defaults
3658      */
3659     /* FIXME? are these values platform-dependent? */
3660     if (ImageSectionObject->ImageInformation.MaximumStackSize == 0)
3661         ImageSectionObject->ImageInformation.MaximumStackSize = 0x40000;
3662 
3663     if(ImageSectionObject->ImageInformation.CommittedStackSize == 0)
3664         ImageSectionObject->ImageInformation.CommittedStackSize = 0x1000;
3665 
3666     if(ImageSectionObject->BasedAddress == NULL)
3667     {
3668         if(ImageSectionObject->ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL)
3669             ImageSectionObject->BasedAddress = (PVOID)0x10000000;
3670         else
3671             ImageSectionObject->BasedAddress = (PVOID)0x00400000;
3672     }
3673 
3674     /*
3675      * And now the fun part: fixing the segments
3676      */
3677 
3678     /* Sort them by virtual address */
3679     MmspSortSegments(ImageSectionObject, Flags);
3680 
3681     /* Ensure they don't overlap in memory */
3682     if (!MmspCheckSegmentBounds(ImageSectionObject, Flags))
3683         return STATUS_INVALID_IMAGE_FORMAT;
3684 
3685     /* Ensure they are aligned */
3686     OldNrSegments = ImageSectionObject->NrSegments;
3687 
3688     if (!MmspPageAlignSegments(ImageSectionObject, Flags))
3689         return STATUS_INVALID_IMAGE_FORMAT;
3690 
3691     /* Trim them if the alignment phase merged some of them */
3692     if (ImageSectionObject->NrSegments < OldNrSegments)
3693     {
3694         PMM_SECTION_SEGMENT Segments;
3695         SIZE_T SizeOfSegments;
3696 
3697         SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments;
3698 
3699         Segments = ExAllocatePoolWithTag(PagedPool,
3700                                          SizeOfSegments,
3701                                          TAG_MM_SECTION_SEGMENT);
3702 
3703         if (Segments == NULL)
3704             return STATUS_INSUFFICIENT_RESOURCES;
3705 
3706         RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments);
3707         ExFreePool(ImageSectionObject->Segments);
3708         ImageSectionObject->Segments = Segments;
3709     }
3710 
3711     /* And finish their initialization */
3712     for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3713     {
3714         ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock);
3715         ImageSectionObject->Segments[i].ReferenceCount = 1;
3716         MiInitializeSectionPageTable(&ImageSectionObject->Segments[i]);
3717     }
3718 
3719     ASSERT(NT_SUCCESS(Status));
3720     return Status;
3721 }
3722 
3723 NTSTATUS
3724 MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
3725                      ACCESS_MASK DesiredAccess,
3726                      POBJECT_ATTRIBUTES ObjectAttributes,
3727                      PLARGE_INTEGER UMaximumSize,
3728                      ULONG SectionPageProtection,
3729                      ULONG AllocationAttributes,
3730                      PFILE_OBJECT FileObject)
3731 {
3732     PROS_SECTION_OBJECT Section;
3733     NTSTATUS Status;
3734     PMM_SECTION_SEGMENT SectionSegments;
3735     PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3736     ULONG i;
3737 
3738     if (FileObject == NULL)
3739         return STATUS_INVALID_FILE_FOR_SECTION;
3740 
3741 #ifndef NEWCC
3742     if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
3743     {
3744         DPRINT1("Denying section creation due to missing cache initialization\n");
3745         return STATUS_INVALID_FILE_FOR_SECTION;
3746     }
3747 #endif
3748 
3749     /*
3750      * Create the section
3751      */
3752     Status = ObCreateObject (ExGetPreviousMode(),
3753                              MmSectionObjectType,
3754                              ObjectAttributes,
3755                              ExGetPreviousMode(),
3756                              NULL,
3757                              sizeof(ROS_SECTION_OBJECT),
3758                              0,
3759                              0,
3760                              (PVOID*)(PVOID)&Section);
3761     if (!NT_SUCCESS(Status))
3762     {
3763         ObDereferenceObject(FileObject);
3764         return(Status);
3765     }
3766 
3767     /*
3768      * Initialize it
3769      */
3770     RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
3771     Section->Type = 'SC';
3772     Section->Size = 'TN';
3773     Section->SectionPageProtection = SectionPageProtection;
3774     Section->AllocationAttributes = AllocationAttributes;
3775 
3776     if (FileObject->SectionObjectPointer->ImageSectionObject == NULL)
3777     {
3778         NTSTATUS StatusExeFmt;
3779 
3780         ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
3781         if (ImageSectionObject == NULL)
3782         {
3783             ObDereferenceObject(FileObject);
3784             ObDereferenceObject(Section);
3785             return(STATUS_NO_MEMORY);
3786         }
3787 
3788         RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
3789 
3790         StatusExeFmt = ExeFmtpCreateImageSection(FileObject, ImageSectionObject);
3791 
3792         if (!NT_SUCCESS(StatusExeFmt))
3793         {
3794             if(ImageSectionObject->Segments != NULL)
3795                 ExFreePool(ImageSectionObject->Segments);
3796 
3797             /*
3798              * If image file is empty, then return that the file is invalid for section
3799              */
3800             Status = StatusExeFmt;
3801             if (StatusExeFmt == STATUS_END_OF_FILE)
3802             {
3803                 Status = STATUS_INVALID_FILE_FOR_SECTION;
3804             }
3805 
3806             ExFreePoolWithTag(ImageSectionObject, TAG_MM_SECTION_SEGMENT);
3807             ObDereferenceObject(Section);
3808             ObDereferenceObject(FileObject);
3809             return(Status);
3810         }
3811 
3812         Section->ImageSection = ImageSectionObject;
3813         ASSERT(ImageSectionObject->Segments);
3814 
3815         /*
3816          * Lock the file
3817          */
3818         Status = MmspWaitForFileLock(FileObject);
3819         if (!NT_SUCCESS(Status))
3820         {
3821             ExFreePool(ImageSectionObject->Segments);
3822             ExFreePool(ImageSectionObject);
3823             ObDereferenceObject(Section);
3824             ObDereferenceObject(FileObject);
3825             return(Status);
3826         }
3827 
3828         if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject,
3829                 ImageSectionObject, NULL))
3830         {
3831             /*
3832              * An other thread has initialized the same image in the background
3833              */
3834             ExFreePool(ImageSectionObject->Segments);
3835             ExFreePool(ImageSectionObject);
3836             ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3837             Section->ImageSection = ImageSectionObject;
3838             SectionSegments = ImageSectionObject->Segments;
3839 
3840             for (i = 0; i < ImageSectionObject->NrSegments; i++)
3841             {
3842                 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3843             }
3844         }
3845 
3846         Status = StatusExeFmt;
3847     }
3848     else
3849     {
3850         /*
3851          * Lock the file
3852          */
3853         Status = MmspWaitForFileLock(FileObject);
3854         if (Status != STATUS_SUCCESS)
3855         {
3856             ObDereferenceObject(Section);
3857             ObDereferenceObject(FileObject);
3858             return(Status);
3859         }
3860 
3861         ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3862         Section->ImageSection = ImageSectionObject;
3863         SectionSegments = ImageSectionObject->Segments;
3864 
3865         /*
3866          * Otherwise just reference all the section segments
3867          */
3868         for (i = 0; i < ImageSectionObject->NrSegments; i++)
3869         {
3870             (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3871         }
3872 
3873         Status = STATUS_SUCCESS;
3874     }
3875     Section->FileObject = FileObject;
3876 #ifndef NEWCC
3877     CcRosReferenceCache(FileObject);
3878 #endif
3879     //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3880     *SectionObject = Section;
3881     return(Status);
3882 }
3883 
3884 
3885 
3886 static NTSTATUS
3887 MmMapViewOfSegment(PMMSUPPORT AddressSpace,
3888                    PROS_SECTION_OBJECT Section,
3889                    PMM_SECTION_SEGMENT Segment,
3890                    PVOID* BaseAddress,
3891                    SIZE_T ViewSize,
3892                    ULONG Protect,
3893                    ULONG ViewOffset,
3894                    ULONG AllocationType)
3895 {
3896     PMEMORY_AREA MArea;
3897     NTSTATUS Status;
3898     ULONG Granularity;
3899 
3900     if (Segment->WriteCopy)
3901     {
3902         /* We have to do this because the not present fault
3903          * and access fault handlers depend on the protection
3904          * that should be granted AFTER the COW fault takes
3905          * place to be in Region->Protect. The not present fault
3906          * handler changes this to the correct protection for COW when
3907          * mapping the pages into the process's address space. If a COW
3908          * fault takes place, the access fault handler sets the page protection
3909          * to these values for the newly copied pages
3910          */
3911         if (Protect == PAGE_WRITECOPY)
3912             Protect = PAGE_READWRITE;
3913         else if (Protect == PAGE_EXECUTE_WRITECOPY)
3914             Protect = PAGE_EXECUTE_READWRITE;
3915     }
3916 
3917     if (*BaseAddress == NULL)
3918         Granularity = MM_ALLOCATION_GRANULARITY;
3919     else
3920         Granularity = PAGE_SIZE;
3921 
3922 #ifdef NEWCC
3923     if (Segment->Flags & MM_DATAFILE_SEGMENT)
3924     {
3925         LARGE_INTEGER FileOffset;
3926         FileOffset.QuadPart = ViewOffset;
3927         ObReferenceObject(Section);
3928         return _MiMapViewOfSegment(AddressSpace, Segment, BaseAddress, ViewSize, Protect, &FileOffset, AllocationType, __FILE__, __LINE__);
3929     }
3930 #endif
3931     Status = MmCreateMemoryArea(AddressSpace,
3932                                 MEMORY_AREA_SECTION_VIEW,
3933                                 BaseAddress,
3934                                 ViewSize,
3935                                 Protect,
3936                                 &MArea,
3937                                 AllocationType,
3938                                 Granularity);
3939     if (!NT_SUCCESS(Status))
3940     {
3941         DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3942                 (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
3943         return(Status);
3944     }
3945 
3946     ObReferenceObject((PVOID)Section);
3947 
3948     MArea->Data.SectionData.Segment = Segment;
3949     MArea->Data.SectionData.Section = Section;
3950     MArea->Data.SectionData.ViewOffset.QuadPart = ViewOffset;
3951     if (Section->AllocationAttributes & SEC_IMAGE)
3952     {
3953         MArea->VadNode.u.VadFlags.VadType = VadImageMap;
3954     }
3955 
3956     MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
3957                        ViewSize, 0, Protect);
3958 
3959     return(STATUS_SUCCESS);
3960 }
3961 
3962 
3963 static VOID
3964 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
3965                   PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
3966 {
3967     ULONG_PTR Entry;
3968 #ifndef NEWCC
3969     PFILE_OBJECT FileObject;
3970     PROS_SHARED_CACHE_MAP SharedCacheMap;
3971 #endif
3972     LARGE_INTEGER Offset;
3973     SWAPENTRY SavedSwapEntry;
3974     PROS_SECTION_OBJECT Section;
3975     PMM_SECTION_SEGMENT Segment;
3976     PMMSUPPORT AddressSpace;
3977     PEPROCESS Process;
3978 
3979     AddressSpace = (PMMSUPPORT)Context;
3980     Process = MmGetAddressSpaceOwner(AddressSpace);
3981 
3982     Address = (PVOID)PAGE_ROUND_DOWN(Address);
3983 
3984     Offset.QuadPart = ((ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)) +
3985                       MemoryArea->Data.SectionData.ViewOffset.QuadPart;
3986 
3987     Section = MemoryArea->Data.SectionData.Section;
3988     Segment = MemoryArea->Data.SectionData.Segment;
3989 
3990     Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
3991     while (Entry && MM_IS_WAIT_PTE(Entry))
3992     {
3993         MmUnlockSectionSegment(Segment);
3994         MmUnlockAddressSpace(AddressSpace);
3995 
3996         MiWaitForPageEvent(NULL, NULL);
3997 
3998         MmLockAddressSpace(AddressSpace);
3999         MmLockSectionSegment(Segment);
4000         Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
4001     }
4002 
4003     /*
4004      * For a dirty, datafile, non-private page mark it as dirty in the
4005      * cache manager.
4006      */
4007     if (Segment->Flags & MM_DATAFILE_SEGMENT)
4008     {
4009         if (Page == PFN_FROM_SSE(Entry) && Dirty)
4010         {
4011 #ifndef NEWCC
4012             FileObject = MemoryArea->Data.SectionData.Section->FileObject;
4013             SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
4014             CcRosMarkDirtyFile(SharedCacheMap, Offset.QuadPart + Segment->Image.FileOffset);
4015 #endif
4016             ASSERT(SwapEntry == 0);
4017         }
4018     }
4019 
4020     if (SwapEntry != 0)
4021     {
4022         /*
4023          * Sanity check
4024          */
4025         if (Segment->Flags & MM_PAGEFILE_SEGMENT)
4026         {
4027             DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4028             KeBugCheck(MEMORY_MANAGEMENT);
4029         }
4030         MmFreeSwapPage(SwapEntry);
4031     }
4032     else if (Page != 0)
4033     {
4034         if (IS_SWAP_FROM_SSE(Entry) ||
4035                 Page != PFN_FROM_SSE(Entry))
4036         {
4037             /*
4038              * Sanity check
4039              */
4040             if (Segment->Flags & MM_PAGEFILE_SEGMENT)
4041             {
4042                 DPRINT1("Found a private page in a pagefile section.\n");
4043                 KeBugCheck(MEMORY_MANAGEMENT);
4044             }
4045             /*
4046              * Just dereference private pages
4047              */
4048             SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
4049             if (SavedSwapEntry != 0)
4050             {
4051                 MmFreeSwapPage(SavedSwapEntry);
4052                 MmSetSavedSwapEntryPage(Page, 0);
4053             }
4054             MmDeleteRmap(Page, Process, Address);
4055             MmReleasePageMemoryConsumer(MC_USER, Page);
4056         }
4057         else
4058         {
4059             MmDeleteRmap(Page, Process, Address);
4060             MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, Dirty, FALSE, NULL);
4061         }
4062     }
4063 }
4064 
4065 static NTSTATUS
4066 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace,
4067                      PVOID BaseAddress)
4068 {
4069     NTSTATUS Status;
4070     PMEMORY_AREA MemoryArea;
4071     PROS_SECTION_OBJECT Section;
4072     PMM_SECTION_SEGMENT Segment;
4073     PLIST_ENTRY CurrentEntry;
4074     PMM_REGION CurrentRegion;
4075     PLIST_ENTRY RegionListHead;
4076 
4077     MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4078                  BaseAddress);
4079     if (MemoryArea == NULL)
4080     {
4081         return(STATUS_UNSUCCESSFUL);
4082     }
4083 
4084     Section = MemoryArea->Data.SectionData.Section;
4085     Segment = MemoryArea->Data.SectionData.Segment;
4086 
4087 #ifdef NEWCC
4088     if (Segment->Flags & MM_DATAFILE_SEGMENT)
4089     {
4090         MmUnlockAddressSpace(AddressSpace);
4091         Status = MmUnmapViewOfCacheSegment(AddressSpace, BaseAddress);
4092         MmLockAddressSpace(AddressSpace);
4093 
4094         return Status;
4095     }
4096 #endif
4097 
4098     MemoryArea->DeleteInProgress = TRUE;
4099 
4100     MmLockSectionSegment(Segment);
4101 
4102     RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
4103     while (!IsListEmpty(RegionListHead))
4104     {
4105         CurrentEntry = RemoveHeadList(RegionListHead);
4106         CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
4107         ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION);
4108     }
4109 
4110     if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
4111     {
4112         Status = MmFreeMemoryArea(AddressSpace,
4113                                   MemoryArea,
4114                                   NULL,
4115                                   NULL);
4116     }
4117     else
4118     {
4119         Status = MmFreeMemoryArea(AddressSpace,
4120                                   MemoryArea,
4121                                   MmFreeSectionPage,
4122                                   AddressSpace);
4123     }
4124     MmUnlockSectionSegment(Segment);
4125     ObDereferenceObject(Section);
4126     return(Status);
4127 }
4128 
4129 NTSTATUS
4130 NTAPI
4131 MiRosUnmapViewOfSection(IN PEPROCESS Process,
4132                         IN PVOID BaseAddress,
4133                         IN BOOLEAN SkipDebuggerNotify)
4134 {
4135     NTSTATUS Status;
4136     PMEMORY_AREA MemoryArea;
4137     PMMSUPPORT AddressSpace;
4138     PROS_SECTION_OBJECT Section;
4139     PVOID ImageBaseAddress = 0;
4140 
4141     DPRINT("Opening memory area Process %p BaseAddress %p\n",
4142            Process, BaseAddress);
4143 
4144     ASSERT(Process);
4145 
4146     AddressSpace = Process ? &Process->Vm : MmGetKernelAddressSpace();
4147 
4148     MmLockAddressSpace(AddressSpace);
4149     MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4150                  BaseAddress);
4151     if (MemoryArea == NULL ||
4152             ((MemoryArea->Type != MEMORY_AREA_SECTION_VIEW) &&
4153              (MemoryArea->Type != MEMORY_AREA_CACHE)) ||
4154             MemoryArea->DeleteInProgress)
4155     {
4156         if (MemoryArea) ASSERT(MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3);
4157         MmUnlockAddressSpace(AddressSpace);
4158         return STATUS_NOT_MAPPED_VIEW;
4159     }
4160 
4161     Section = MemoryArea->Data.SectionData.Section;
4162 
4163     if ((Section != NULL) && (Section->AllocationAttributes & SEC_IMAGE))
4164     {
4165         ULONG i;
4166         ULONG NrSegments;
4167         PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4168         PMM_SECTION_SEGMENT SectionSegments;
4169         PMM_SECTION_SEGMENT Segment;
4170 
4171         Segment = MemoryArea->Data.SectionData.Segment;
4172         ImageSectionObject = Section->ImageSection;
4173         SectionSegments = ImageSectionObject->Segments;
4174         NrSegments = ImageSectionObject->NrSegments;
4175 
4176         MemoryArea->DeleteInProgress = TRUE;
4177 
4178         /* Search for the current segment within the section segments
4179          * and calculate the image base address */
4180         for (i = 0; i < NrSegments; i++)
4181         {
4182             if (Segment == &SectionSegments[i])
4183             {
4184                 ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].Image.VirtualAddress;
4185                 break;
4186             }
4187         }
4188         if (i >= NrSegments)
4189         {
4190             KeBugCheck(MEMORY_MANAGEMENT);
4191         }
4192 
4193         for (i = 0; i < NrSegments; i++)
4194         {
4195             PVOID SBaseAddress = (PVOID)
4196                                  ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress);
4197 
4198             Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
4199             if (!NT_SUCCESS(Status))
4200             {
4201                 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4202                         SBaseAddress, Process, Status);
4203                 ASSERT(NT_SUCCESS(Status));
4204             }
4205         }
4206     }
4207     else
4208     {
4209         Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
4210         if (!NT_SUCCESS(Status))
4211         {
4212             DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4213                     BaseAddress, Process, Status);
4214             ASSERT(NT_SUCCESS(Status));
4215         }
4216     }
4217 
4218     MmUnlockAddressSpace(AddressSpace);
4219 
4220     /* Notify debugger */
4221     if (ImageBaseAddress && !SkipDebuggerNotify) DbgkUnMapViewOfSection(ImageBaseAddress);
4222 
4223     return(STATUS_SUCCESS);
4224 }
4225 
4226 
4227 
4228 
4229 /**
4230  * Queries the information of a section object.
4231  *
4232  * @param SectionHandle
4233  *        Handle to the section object. It must be opened with SECTION_QUERY
4234  *        access.
4235  * @param SectionInformationClass
4236  *        Index to a certain information structure. Can be either
4237  *        SectionBasicInformation or SectionImageInformation. The latter
4238  *        is valid only for sections that were created with the SEC_IMAGE
4239  *        flag.
4240  * @param SectionInformation
4241  *        Caller supplies storage for resulting information.
4242  * @param Length
4243  *        Size of the supplied storage.
4244  * @param ResultLength
4245  *        Data written.
4246  *
4247  * @return Status.
4248  *
4249  * @implemented
4250  */
4251 NTSTATUS
4252 NTAPI
4253 NtQuerySection(
4254     _In_ HANDLE SectionHandle,
4255     _In_ SECTION_INFORMATION_CLASS SectionInformationClass,
4256     _Out_ PVOID SectionInformation,
4257     _In_ SIZE_T SectionInformationLength,
4258     _Out_opt_ PSIZE_T ResultLength)
4259 {
4260     PSECTION Section;
4261     KPROCESSOR_MODE PreviousMode;
4262     NTSTATUS Status;
4263     PAGED_CODE();
4264 
4265     PreviousMode = ExGetPreviousMode();
4266     if (PreviousMode != KernelMode)
4267     {
4268         _SEH2_TRY
4269         {
4270             ProbeForWrite(SectionInformation,
4271                           SectionInformationLength,
4272                           __alignof(ULONG));
4273             if (ResultLength != NULL)
4274             {
4275                 ProbeForWrite(ResultLength,
4276                               sizeof(*ResultLength),
4277                               __alignof(SIZE_T));
4278             }
4279         }
4280         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4281         {
4282             _SEH2_YIELD(return _SEH2_GetExceptionCode());
4283         }
4284         _SEH2_END;
4285     }
4286 
4287     if (SectionInformationClass == SectionBasicInformation)
4288     {
4289         if (SectionInformationLength < sizeof(SECTION_BASIC_INFORMATION))
4290         {
4291             return STATUS_INFO_LENGTH_MISMATCH;
4292         }
4293     }
4294     else if (SectionInformationClass == SectionImageInformation)
4295     {
4296         if (SectionInformationLength < sizeof(SECTION_IMAGE_INFORMATION))
4297         {
4298             return STATUS_INFO_LENGTH_MISMATCH;
4299         }
4300     }
4301     else
4302     {
4303         return STATUS_INVALID_INFO_CLASS;
4304     }
4305 
4306     Status = ObReferenceObjectByHandle(SectionHandle,
4307                                        SECTION_QUERY,
4308                                        MmSectionObjectType,
4309                                        PreviousMode,
4310                                        (PVOID*)(PVOID)&Section,
4311                                        NULL);
4312     if (!NT_SUCCESS(Status))
4313     {
4314         DPRINT1("Failed to reference section: 0x%lx\n", Status);
4315         return Status;
4316     }
4317 
4318     if (MiIsRosSectionObject(Section))
4319     {
4320         PROS_SECTION_OBJECT RosSection = (PROS_SECTION_OBJECT)Section;
4321 
4322         switch (SectionInformationClass)
4323         {
4324             case SectionBasicInformation:
4325             {
4326                 PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
4327 
4328                 _SEH2_TRY
4329                 {
4330                     Sbi->Attributes = RosSection->AllocationAttributes;
4331                     if (RosSection->AllocationAttributes & SEC_IMAGE)
4332                     {
4333                         Sbi->BaseAddress = 0;
4334                         Sbi->Size.QuadPart = 0;
4335                     }
4336                     else
4337                     {
4338                         Sbi->BaseAddress = (PVOID)RosSection->Segment->Image.VirtualAddress;
4339                         Sbi->Size.QuadPart = RosSection->Segment->Length.QuadPart;
4340                     }
4341 
4342                     if (ResultLength != NULL)
4343                     {
4344                         *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
4345                     }
4346                     Status = STATUS_SUCCESS;
4347                 }
4348                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4349                 {
4350                     Status = _SEH2_GetExceptionCode();
4351                 }
4352                 _SEH2_END;
4353 
4354                 break;
4355             }
4356 
4357             case SectionImageInformation:
4358             {
4359                 PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
4360 
4361                 _SEH2_TRY
4362                 {
4363                     if (RosSection->AllocationAttributes & SEC_IMAGE)
4364                     {
4365                         PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4366                         ImageSectionObject = RosSection->ImageSection;
4367 
4368                         *Sii = ImageSectionObject->ImageInformation;
4369                     }
4370 
4371                     if (ResultLength != NULL)
4372                     {
4373                         *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
4374                     }
4375                     Status = STATUS_SUCCESS;
4376                 }
4377                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4378                 {
4379                     Status = _SEH2_GetExceptionCode();
4380                 }
4381                 _SEH2_END;
4382 
4383                 break;
4384             }
4385         }
4386     }
4387     else
4388     {
4389         switch(SectionInformationClass)
4390         {
4391             case SectionBasicInformation:
4392             {
4393                 SECTION_BASIC_INFORMATION Sbi;
4394 
4395                 Sbi.Size = Section->SizeOfSection;
4396                 Sbi.BaseAddress = (PVOID)Section->Address.StartingVpn;
4397 
4398                 Sbi.Attributes = 0;
4399                 if (Section->u.Flags.Image)
4400                     Sbi.Attributes |= SEC_IMAGE;
4401                 if (Section->u.Flags.Commit)
4402                     Sbi.Attributes |= SEC_COMMIT;
4403                 if (Section->u.Flags.Reserve)
4404                     Sbi.Attributes |= SEC_RESERVE;
4405                 if (Section->u.Flags.File)
4406                     Sbi.Attributes |= SEC_FILE;
4407                 if (Section->u.Flags.Image)
4408                     Sbi.Attributes |= SEC_IMAGE;
4409 
4410                 /* FIXME : Complete/test the list of flags passed back from NtCreateSection */
4411 
4412                 _SEH2_TRY
4413                 {
4414                     *((SECTION_BASIC_INFORMATION*)SectionInformation) = Sbi;
4415                     if (ResultLength)
4416                         *ResultLength = sizeof(Sbi);
4417                 }
4418                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4419                 {
4420                     Status = _SEH2_GetExceptionCode();
4421                 }
4422                 _SEH2_END;
4423                 break;
4424             }
4425             case SectionImageInformation:
4426             {
4427                 if (!Section->u.Flags.Image)
4428                 {
4429                     Status = STATUS_SECTION_NOT_IMAGE;
4430                 }
4431                 else
4432                 {
4433                     /* Currently not supported */
4434                     ASSERT(FALSE);
4435                 }
4436                 break;
4437             }
4438         }
4439     }
4440 
4441     ObDereferenceObject(Section);
4442 
4443     return(Status);
4444 }
4445 
4446 /**********************************************************************
4447  * NAME       EXPORTED
4448  * MmMapViewOfSection
4449  *
4450  * DESCRIPTION
4451  * Maps a view of a section into the virtual address space of a
4452  * process.
4453  *
4454  * ARGUMENTS
4455  * Section
4456  *  Pointer to the section object.
4457  *
4458  * ProcessHandle
4459  *  Pointer to the process.
4460  *
4461  * BaseAddress
4462  *  Desired base address (or NULL) on entry;
4463  *  Actual base address of the view on exit.
4464  *
4465  * ZeroBits
4466  *  Number of high order address bits that must be zero.
4467  *
4468  * CommitSize
4469  *  Size in bytes of the initially committed section of
4470  *  the view.
4471  *
4472  * SectionOffset
4473  *  Offset in bytes from the beginning of the section
4474  *  to the beginning of the view.
4475  *
4476  * ViewSize
4477  *  Desired length of map (or zero to map all) on entry
4478  *  Actual length mapped on exit.
4479  *
4480  * InheritDisposition
4481  *  Specified how the view is to be shared with
4482  *  child processes.
4483  *
4484  * AllocationType
4485  *  Type of allocation for the pages.
4486  *
4487  * Protect
4488  *  Protection for the committed region of the view.
4489  *
4490  * RETURN VALUE
4491  * Status.
4492  *
4493  * @implemented
4494  */
4495 NTSTATUS NTAPI
4496 MmMapViewOfSection(IN PVOID SectionObject,
4497                    IN PEPROCESS Process,
4498                    IN OUT PVOID *BaseAddress,
4499                    IN ULONG_PTR ZeroBits,
4500                    IN SIZE_T CommitSize,
4501                    IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
4502                    IN OUT PSIZE_T ViewSize,
4503                    IN SECTION_INHERIT InheritDisposition,
4504                    IN ULONG AllocationType,
4505                    IN ULONG Protect)
4506 {
4507     PROS_SECTION_OBJECT Section;
4508     PMMSUPPORT AddressSpace;
4509     ULONG ViewOffset;
4510     NTSTATUS Status = STATUS_SUCCESS;
4511     BOOLEAN NotAtBase = FALSE;
4512 
4513     if (MiIsRosSectionObject(SectionObject) == FALSE)
4514     {
4515         DPRINT("Mapping ARM3 section into %s\n", Process->ImageFileName);
4516         return MmMapViewOfArm3Section(SectionObject,
4517                                       Process,
4518                                       BaseAddress,
4519                                       ZeroBits,
4520                                       CommitSize,
4521                                       SectionOffset,
4522                                       ViewSize,
4523                                       InheritDisposition,
4524                                       AllocationType,
4525                                       Protect);
4526     }
4527 
4528     ASSERT(Process);
4529 
4530     if (!Protect || Protect & ~PAGE_FLAGS_VALID_FOR_SECTION)
4531     {
4532         return STATUS_INVALID_PAGE_PROTECTION;
4533     }
4534 
4535     /* FIXME: We should keep this, but it would break code checking equality */
4536     Protect &= ~PAGE_NOCACHE;
4537 
4538     Section = (PROS_SECTION_OBJECT)SectionObject;
4539     AddressSpace = &Process->Vm;
4540 
4541     AllocationType |= (Section->AllocationAttributes & SEC_NO_CHANGE);
4542 
4543     MmLockAddressSpace(AddressSpace);
4544 
4545     if (Section->AllocationAttributes & SEC_IMAGE)
4546     {
4547         ULONG i;
4548         ULONG NrSegments;
4549         ULONG_PTR ImageBase;
4550         SIZE_T ImageSize;
4551         PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4552         PMM_SECTION_SEGMENT SectionSegments;
4553 
4554         ImageSectionObject = Section->ImageSection;
4555         SectionSegments = ImageSectionObject->Segments;
4556         NrSegments = ImageSectionObject->NrSegments;
4557 
4558         ImageBase = (ULONG_PTR)*BaseAddress;
4559         if (ImageBase == 0)
4560         {
4561             ImageBase = (ULONG_PTR)ImageSectionObject->BasedAddress;
4562         }
4563 
4564         ImageSize = 0;
4565         for (i = 0; i < NrSegments; i++)
4566         {
4567             ULONG_PTR MaxExtent;
4568             MaxExtent = (ULONG_PTR)(SectionSegments[i].Image.VirtualAddress +
4569                                     SectionSegments[i].Length.QuadPart);
4570             ImageSize = max(ImageSize, MaxExtent);
4571         }
4572 
4573         ImageSectionObject->ImageInformation.ImageFileSize = (ULONG)ImageSize;
4574 
4575         /* Check for an illegal base address */
4576         if (((ImageBase + ImageSize) > (ULONG_PTR)MmHighestUserAddress) ||
4577                 ((ImageBase + ImageSize) < ImageSize))
4578         {
4579             ASSERT(*BaseAddress == NULL);
4580             ImageBase = ALIGN_DOWN_BY((ULONG_PTR)MmHighestUserAddress - ImageSize,
4581                                       MM_VIRTMEM_GRANULARITY);
4582             NotAtBase = TRUE;
4583         }
4584         else if (ImageBase != ALIGN_DOWN_BY(ImageBase, MM_VIRTMEM_GRANULARITY))
4585         {
4586             ASSERT(*BaseAddress == NULL);
4587             ImageBase = ALIGN_DOWN_BY(ImageBase, MM_VIRTMEM_GRANULARITY);
4588             NotAtBase = TRUE;
4589         }
4590 
4591         /* Check there is enough space to map the section at that point. */
4592         if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
4593                                        PAGE_ROUND_UP(ImageSize)) != NULL)
4594         {
4595             /* Fail if the user requested a fixed base address. */
4596             if ((*BaseAddress) != NULL)
4597             {
4598                 MmUnlockAddressSpace(AddressSpace);
4599                 return(STATUS_CONFLICTING_ADDRESSES);
4600             }
4601             /* Otherwise find a gap to map the image. */
4602             ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), MM_VIRTMEM_GRANULARITY, FALSE);
4603             if (ImageBase == 0)
4604             {
4605                 MmUnlockAddressSpace(AddressSpace);
4606                 return(STATUS_CONFLICTING_ADDRESSES);
4607             }
4608             /* Remember that we loaded image at a different base address */
4609             NotAtBase = TRUE;
4610         }
4611 
4612         for (i = 0; i < NrSegments; i++)
4613         {
4614             PVOID SBaseAddress = (PVOID)
4615                                  ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress);
4616             MmLockSectionSegment(&SectionSegments[i]);
4617             Status = MmMapViewOfSegment(AddressSpace,
4618                                         Section,
4619                                         &SectionSegments[i],
4620                                         &SBaseAddress,
4621                                         SectionSegments[i].Length.LowPart,
4622                                         SectionSegments[i].Protection,
4623                                         0,
4624                                         0);
4625             MmUnlockSectionSegment(&SectionSegments[i]);
4626             if (!NT_SUCCESS(Status))
4627             {
4628                 MmUnlockAddressSpace(AddressSpace);
4629                 return(Status);
4630             }
4631         }
4632 
4633         *BaseAddress = (PVOID)ImageBase;
4634         *ViewSize = ImageSize;
4635     }
4636     else
4637     {
4638         /* check for write access */
4639         if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) &&
4640                 !(Section->SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)))
4641         {
4642             MmUnlockAddressSpace(AddressSpace);
4643             return STATUS_SECTION_PROTECTION;
4644         }
4645         /* check for read access */
4646         if ((Protect & (PAGE_READONLY|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_WRITECOPY)) &&
4647                 !(Section->SectionPageProtection & (PAGE_READONLY|PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4648         {
4649             MmUnlockAddressSpace(AddressSpace);
4650             return STATUS_SECTION_PROTECTION;
4651         }
4652         /* check for execute access */
4653         if ((Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)) &&
4654                 !(Section->SectionPageProtection & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4655         {
4656             MmUnlockAddressSpace(AddressSpace);
4657             return STATUS_SECTION_PROTECTION;
4658         }
4659 
4660         if (SectionOffset == NULL)
4661         {
4662             ViewOffset = 0;
4663         }
4664         else
4665         {
4666             ViewOffset = SectionOffset->u.LowPart;
4667         }
4668 
4669         if ((ViewOffset % PAGE_SIZE) != 0)
4670         {
4671             MmUnlockAddressSpace(AddressSpace);
4672             return(STATUS_MAPPED_ALIGNMENT);
4673         }
4674 
4675         if ((*ViewSize) == 0)
4676         {
4677             (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4678         }
4679         else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
4680         {
4681             (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4682         }
4683 
4684         *ViewSize = PAGE_ROUND_UP(*ViewSize);
4685 
4686         MmLockSectionSegment(Section->Segment);
4687         Status = MmMapViewOfSegment(AddressSpace,
4688                                     Section,
4689                                     Section->Segment,
4690                                     BaseAddress,
4691                                     *ViewSize,
4692                                     Protect,
4693                                     ViewOffset,
4694                                     AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE));
4695         MmUnlockSectionSegment(Section->Segment);
4696         if (!NT_SUCCESS(Status))
4697         {
4698             MmUnlockAddressSpace(AddressSpace);
4699             return(Status);
4700         }
4701     }
4702 
4703     MmUnlockAddressSpace(AddressSpace);
4704     ASSERT(*BaseAddress == ALIGN_DOWN_POINTER_BY(*BaseAddress, MM_VIRTMEM_GRANULARITY));
4705 
4706     if (NotAtBase)
4707         Status = STATUS_IMAGE_NOT_AT_BASE;
4708     else
4709         Status = STATUS_SUCCESS;
4710 
4711     return Status;
4712 }
4713 
4714 /*
4715  * @unimplemented
4716  */
4717 BOOLEAN NTAPI
4718 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4719                       IN PLARGE_INTEGER   NewFileSize)
4720 {
4721     /* Check whether an ImageSectionObject exists */
4722     if (SectionObjectPointer->ImageSectionObject != NULL)
4723     {
4724         DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4725         return FALSE;
4726     }
4727 
4728     if (SectionObjectPointer->DataSectionObject != NULL)
4729     {
4730         PMM_SECTION_SEGMENT Segment;
4731 
4732         Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->
4733                   DataSectionObject;
4734 
4735         if (Segment->ReferenceCount != 0)
4736         {
4737 #ifdef NEWCC
4738             CC_FILE_SIZES FileSizes;
4739             CcpLock();
4740             if (SectionObjectPointer->SharedCacheMap && (Segment->ReferenceCount > CcpCountCacheSections((PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap)))
4741             {
4742                 CcpUnlock();
4743                 /* Check size of file */
4744                 if (SectionObjectPointer->SharedCacheMap)
4745                 {
4746                     if (!CcGetFileSizes(Segment->FileObject, &FileSizes))
4747                     {
4748                         return FALSE;
4749                     }
4750 
4751                     if (NewFileSize->QuadPart <= FileSizes.FileSize.QuadPart)
4752                     {
4753                         return FALSE;
4754                     }
4755                 }
4756             }
4757             else
4758                 CcpUnlock();
4759 #else
4760             /* Check size of file */
4761             if (SectionObjectPointer->SharedCacheMap)
4762             {
4763                 PROS_SHARED_CACHE_MAP SharedCacheMap = SectionObjectPointer->SharedCacheMap;
4764                 if (NewFileSize->QuadPart <= SharedCacheMap->FileSize.QuadPart)
4765                 {
4766                     return FALSE;
4767                 }
4768             }
4769 #endif
4770         }
4771         else
4772         {
4773             /* Something must gone wrong
4774              * how can we have a Section but no
4775              * reference? */
4776             DPRINT("ERROR: DataSectionObject without reference!\n");
4777         }
4778     }
4779 
4780     DPRINT("FIXME: didn't check for outstanding write probes\n");
4781 
4782     return TRUE;
4783 }
4784 
4785 
4786 
4787 
4788 /*
4789  * @implemented
4790  */
4791 BOOLEAN NTAPI
4792 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4793                      IN MMFLUSH_TYPE   FlushType)
4794 {
4795     BOOLEAN Result = TRUE;
4796 #ifdef NEWCC
4797     PMM_SECTION_SEGMENT Segment;
4798 #endif
4799 
4800     switch(FlushType)
4801     {
4802     case MmFlushForDelete:
4803         if (SectionObjectPointer->ImageSectionObject ||
4804                 SectionObjectPointer->DataSectionObject)
4805         {
4806             return FALSE;
4807         }
4808 #ifndef NEWCC
4809         CcRosRemoveIfClosed(SectionObjectPointer);
4810 #endif
4811         return TRUE;
4812     case MmFlushForWrite:
4813     {
4814         DPRINT("MmFlushImageSection(%d)\n", FlushType);
4815 #ifdef NEWCC
4816         Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->DataSectionObject;
4817 #endif
4818 
4819         if (SectionObjectPointer->ImageSectionObject)
4820         {
4821             DPRINT1("SectionObject has ImageSection\n");
4822             return FALSE;
4823         }
4824 
4825 #ifdef NEWCC
4826         CcpLock();
4827         Result = !SectionObjectPointer->SharedCacheMap || (Segment->ReferenceCount == CcpCountCacheSections((PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap));
4828         CcpUnlock();
4829         DPRINT("Result %d\n", Result);
4830 #endif
4831         return Result;
4832     }
4833     }
4834     return FALSE;
4835 }
4836 
4837 /*
4838  * @implemented
4839  */
4840 NTSTATUS NTAPI
4841 MmMapViewInSystemSpace (IN PVOID SectionObject,
4842                         OUT PVOID * MappedBase,
4843                         IN OUT PSIZE_T ViewSize)
4844 {
4845     PROS_SECTION_OBJECT Section;
4846     PMMSUPPORT AddressSpace;
4847     NTSTATUS Status;
4848     PAGED_CODE();
4849 
4850     if (MiIsRosSectionObject(SectionObject) == FALSE)
4851     {
4852         return MiMapViewInSystemSpace(SectionObject,
4853                                       &MmSession,
4854                                       MappedBase,
4855                                       ViewSize);
4856     }
4857 
4858     DPRINT("MmMapViewInSystemSpace() called\n");
4859 
4860     Section = (PROS_SECTION_OBJECT)SectionObject;
4861     AddressSpace = MmGetKernelAddressSpace();
4862 
4863     MmLockAddressSpace(AddressSpace);
4864 
4865 
4866     if ((*ViewSize) == 0)
4867     {
4868         (*ViewSize) = Section->MaximumSize.u.LowPart;
4869     }
4870     else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
4871     {
4872         (*ViewSize) = Section->MaximumSize.u.LowPart;
4873     }
4874 
4875     MmLockSectionSegment(Section->Segment);
4876 
4877 
4878     Status = MmMapViewOfSegment(AddressSpace,
4879                                 Section,
4880                                 Section->Segment,
4881                                 MappedBase,
4882                                 *ViewSize,
4883                                 PAGE_READWRITE,
4884                                 0,
4885                                 0);
4886 
4887     MmUnlockSectionSegment(Section->Segment);
4888     MmUnlockAddressSpace(AddressSpace);
4889 
4890     return Status;
4891 }
4892 
4893 NTSTATUS
4894 NTAPI
4895 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase)
4896 {
4897     PMMSUPPORT AddressSpace;
4898     NTSTATUS Status;
4899 
4900     DPRINT("MmUnmapViewInSystemSpace() called\n");
4901 
4902     AddressSpace = MmGetKernelAddressSpace();
4903 
4904     MmLockAddressSpace(AddressSpace);
4905 
4906     Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
4907 
4908     MmUnlockAddressSpace(AddressSpace);
4909 
4910     return Status;
4911 }
4912 
4913 /**********************************************************************
4914  * NAME       EXPORTED
4915  *  MmCreateSection@
4916  *
4917  * DESCRIPTION
4918  *  Creates a section object.
4919  *
4920  * ARGUMENTS
4921  * SectionObject (OUT)
4922  *  Caller supplied storage for the resulting pointer
4923  *  to a SECTION_OBJECT instance;
4924  *
4925  * DesiredAccess
4926  *  Specifies the desired access to the section can be a
4927  *  combination of:
4928  *   STANDARD_RIGHTS_REQUIRED |
4929  *   SECTION_QUERY   |
4930  *   SECTION_MAP_WRITE  |
4931  *   SECTION_MAP_READ  |
4932  *   SECTION_MAP_EXECUTE
4933  *
4934  * ObjectAttributes [OPTIONAL]
4935  *  Initialized attributes for the object can be used
4936  *  to create a named section;
4937  *
4938  * MaximumSize
4939  *  Maximizes the size of the memory section. Must be
4940  *  non-NULL for a page-file backed section.
4941  *  If value specified for a mapped file and the file is
4942  *  not large enough, file will be extended.
4943  *
4944  * SectionPageProtection
4945  *  Can be a combination of:
4946  *   PAGE_READONLY |
4947  *   PAGE_READWRITE |
4948  *   PAGE_WRITEONLY |
4949  *   PAGE_WRITECOPY
4950  *
4951  * AllocationAttributes
4952  *  Can be a combination of:
4953  *   SEC_IMAGE |
4954  *   SEC_RESERVE
4955  *
4956  * FileHandle
4957  *  Handle to a file to create a section mapped to a file
4958  *  instead of a memory backed section;
4959  *
4960  * File
4961  *  Unknown.
4962  *
4963  * RETURN VALUE
4964  *  Status.
4965  *
4966  * @implemented
4967  */
4968 NTSTATUS NTAPI
4969 MmCreateSection (OUT PVOID  * Section,
4970                  IN ACCESS_MASK  DesiredAccess,
4971                  IN POBJECT_ATTRIBUTES ObjectAttributes     OPTIONAL,
4972                  IN PLARGE_INTEGER  MaximumSize,
4973                  IN ULONG   SectionPageProtection,
4974                  IN ULONG   AllocationAttributes,
4975                  IN HANDLE   FileHandle   OPTIONAL,
4976                  IN PFILE_OBJECT  FileObject  OPTIONAL)
4977 {
4978     NTSTATUS Status;
4979     ULONG Protection;
4980     PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section;
4981 
4982     /* Check if an ARM3 section is being created instead */
4983     if (!(AllocationAttributes & (SEC_IMAGE | SEC_PHYSICALMEMORY)))
4984     {
4985         if (!(FileObject) && !(FileHandle))
4986         {
4987             return MmCreateArm3Section(Section,
4988                                        DesiredAccess,
4989                                        ObjectAttributes,
4990                                        MaximumSize,
4991                                        SectionPageProtection,
4992                                        AllocationAttributes &~ 1,
4993                                        FileHandle,
4994                                        FileObject);
4995         }
4996     }
4997 
4998     /* Convert section flag to page flag */
4999     if (AllocationAttributes & SEC_NOCACHE) SectionPageProtection |= PAGE_NOCACHE;
5000 
5001     /* Check to make sure the protection is correct. Nt* does this already */
5002     Protection = MiMakeProtectionMask(SectionPageProtection);
5003     if (Protection == MM_INVALID_PROTECTION)
5004     {
5005         DPRINT1("Page protection is invalid\n");
5006         return STATUS_INVALID_PAGE_PROTECTION;
5007     }
5008 
5009     /* Check if this is going to be a data or image backed file section */
5010     if ((FileHandle) || (FileObject))
5011     {
5012         /* These cannot be mapped with large pages */
5013         if (AllocationAttributes & SEC_LARGE_PAGES)
5014         {
5015             DPRINT1("Large pages cannot be used with an image mapping\n");
5016             return STATUS_INVALID_PARAMETER_6;
5017         }
5018 
5019         /* Did the caller pass an object? */
5020         if (FileObject)
5021         {
5022             /* Reference the object directly */
5023             ObReferenceObject(FileObject);
5024         }
5025         else
5026         {
5027             /* Reference the file handle to get the object */
5028             Status = ObReferenceObjectByHandle(FileHandle,
5029                                                MmMakeFileAccess[Protection],
5030                                                IoFileObjectType,
5031                                                ExGetPreviousMode(),
5032                                                (PVOID*)&FileObject,
5033                                                NULL);
5034             if (!NT_SUCCESS(Status))
5035             {
5036                 DPRINT1("Failed to get a handle to the FO: %lx\n", Status);
5037                 return Status;
5038             }
5039         }
5040     }
5041     else
5042     {
5043         /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
5044         if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION;
5045     }
5046 
5047 #ifndef NEWCC // A hack for initializing caching.
5048     // This is needed only in the old case.
5049     if (FileHandle)
5050     {
5051         IO_STATUS_BLOCK Iosb;
5052         NTSTATUS Status;
5053         CHAR Buffer;
5054         LARGE_INTEGER ByteOffset;
5055         ByteOffset.QuadPart = 0;
5056         Status = ZwReadFile(FileHandle,
5057                             NULL,
5058                             NULL,
5059                             NULL,
5060                             &Iosb,
5061                             &Buffer,
5062                             sizeof(Buffer),
5063                             &ByteOffset,
5064                             NULL);
5065         if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
5066         {
5067             DPRINT1("CC failure: %lx\n", Status);
5068             if (FileObject)
5069                 ObDereferenceObject(FileObject);
5070             return Status;
5071         }
5072         // Caching is initialized...
5073 
5074         // Hack of the hack: actually, it might not be initialized if FSD init on effective right and if file is null-size
5075         // In such case, force cache by initiating a write IRP
5076         if (Status == STATUS_END_OF_FILE && !(AllocationAttributes & SEC_IMAGE) && FileObject != NULL &&
5077             (FileObject->SectionObjectPointer == NULL || FileObject->SectionObjectPointer->SharedCacheMap == NULL))
5078         {
5079             Buffer = 0xdb;
5080             Status = ZwWriteFile(FileHandle,
5081                                  NULL,
5082                                  NULL,
5083                                  NULL,
5084                                  &Iosb,
5085                                  &Buffer,
5086                                  sizeof(Buffer),
5087                                  &ByteOffset,
5088                                  NULL);
5089             if (NT_SUCCESS(Status))
5090             {
5091                 LARGE_INTEGER Zero;
5092                 Zero.QuadPart = 0LL;
5093 
5094                 Status = IoSetInformation(FileObject,
5095                                           FileEndOfFileInformation,
5096                                           sizeof(LARGE_INTEGER),
5097                                           &Zero);
5098                 ASSERT(NT_SUCCESS(Status));
5099             }
5100         }
5101     }
5102 #endif
5103 
5104     if (AllocationAttributes & SEC_IMAGE)
5105     {
5106         Status = MmCreateImageSection(SectionObject,
5107                                       DesiredAccess,
5108                                       ObjectAttributes,
5109                                       MaximumSize,
5110                                       SectionPageProtection,
5111                                       AllocationAttributes,
5112                                       FileObject);
5113     }
5114 #ifndef NEWCC
5115     else if (FileHandle != NULL)
5116     {
5117         Status =  MmCreateDataFileSection(SectionObject,
5118                                           DesiredAccess,
5119                                           ObjectAttributes,
5120                                           MaximumSize,
5121                                           SectionPageProtection,
5122                                           AllocationAttributes,
5123                                           FileObject);
5124     }
5125 #else
5126     else if (FileHandle != NULL || FileObject != NULL)
5127     {
5128         Status = MmCreateCacheSection(SectionObject,
5129                                       DesiredAccess,
5130                                       ObjectAttributes,
5131                                       MaximumSize,
5132                                       SectionPageProtection,
5133                                       AllocationAttributes,
5134                                       FileObject);
5135     }
5136 #endif
5137     else
5138     {
5139         if ((AllocationAttributes & SEC_PHYSICALMEMORY) == 0)
5140         {
5141             DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes, FileObject, FileHandle);
5142         }
5143 //        ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5144         Status = MmCreatePageFileSection(SectionObject,
5145                                          DesiredAccess,
5146                                          ObjectAttributes,
5147                                          MaximumSize,
5148                                          SectionPageProtection,
5149                                          AllocationAttributes);
5150         if (FileObject)
5151             ObDereferenceObject(FileObject);
5152     }
5153 
5154     return Status;
5155 }
5156 
5157 /* EOF */
5158