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