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