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