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