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