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