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