ReactOS  0.4.12-dev-90-g2e2e63e
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 */
184  IN SIZE_T FileHeaderSize,
185  IN PVOID File,
186  OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
187  OUT PULONG Flags,
188  IN PEXEFMT_CB_READ_FILE ReadFileCb,
189  IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb)
190 {
191  NTSTATUS nStatus;
192  ULONG cbFileHeaderOffsetSize = 0;
193  ULONG cbSectionHeadersOffset = 0;
194  ULONG cbSectionHeadersSize;
195  ULONG cbSectionHeadersOffsetSize = 0;
196  ULONG cbOptHeaderSize;
197  ULONG cbHeadersSize = 0;
198  ULONG nSectionAlignment;
199  ULONG nFileAlignment;
200  ULONG_PTR ImageBase;
201  const IMAGE_DOS_HEADER * pidhDosHeader;
202  const IMAGE_NT_HEADERS32 * pinhNtHeader;
203  const IMAGE_OPTIONAL_HEADER32 * piohOptHeader;
204  const IMAGE_SECTION_HEADER * pishSectionHeaders;
205  PMM_SECTION_SEGMENT pssSegments;
206  LARGE_INTEGER lnOffset;
207  PVOID pBuffer;
208  SIZE_T nPrevVirtualEndOfSegment = 0;
209  ULONG nFileSizeOfHeaders = 0;
210  ULONG i;
211  ULONG AlignedLength;
212 
213  ASSERT(FileHeader);
214  ASSERT(FileHeaderSize > 0);
215  ASSERT(File);
216  ASSERT(ImageSectionObject);
217  ASSERT(ReadFileCb);
218  ASSERT(AllocateSegmentsCb);
219 
220  ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize));
221 
222  ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0);
223 
224 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
225 
226  pBuffer = NULL;
227  pidhDosHeader = FileHeader;
228 
229  /* DOS HEADER */
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  {
808  PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
809  PMM_SECTION_SEGMENT SectionSegments;
810  ULONG NrSegments;
811  ULONG i;
812 
813  ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject;
814  NrSegments = ImageSectionObject->NrSegments;
815  SectionSegments = ImageSectionObject->Segments;
816  for (i = 0; i < NrSegments; i++)
817  {
818  if (SectionSegments[i].ReferenceCount != 0)
819  {
820  DPRINT1("Image segment %lu still referenced (was %lu)\n", i,
821  SectionSegments[i].ReferenceCount);
822  KeBugCheck(MEMORY_MANAGEMENT);
823  }
824  MmFreePageTablesSectionSegment(&SectionSegments[i], NULL);
825  }
826  ExFreePool(ImageSectionObject->Segments);
827  ExFreePool(ImageSectionObject);
828  FileObject->SectionObjectPointer->ImageSectionObject = NULL;
829  }
830  if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
831  {
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 static VOID
1282  ULONG OldType,
1283  ULONG OldProtect,
1284  ULONG NewType,
1285  ULONG NewProtect)
1286 {
1289  BOOLEAN DoCOW = FALSE;
1290  ULONG i;
1291  PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1292 
1293  MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
1294  ASSERT(MemoryArea != NULL);
1295  Segment = MemoryArea->Data.SectionData.Segment;
1296  MmLockSectionSegment(Segment);
1297 
1298  if ((Segment->WriteCopy) &&
1299  (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
1300  {
1301  DoCOW = TRUE;
1302  }
1303 
1304  if (OldProtect != NewProtect)
1305  {
1306  for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
1307  {
1308  SWAPENTRY SwapEntry;
1309  PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
1311 
1312  /* Wait for a wait entry to disappear */
1313  do
1314  {
1315  MmGetPageFileMapping(Process, Address, &SwapEntry);
1316  if (SwapEntry != MM_WAIT_ENTRY)
1317  break;
1318  MiWaitForPageEvent(Process, Address);
1319  }
1320  while (TRUE);
1321 
1322  /*
1323  * If we doing COW for this segment then check if the page is
1324  * already private.
1325  */
1326  if (DoCOW && MmIsPagePresent(Process, Address))
1327  {
1329  ULONG_PTR Entry;
1330  PFN_NUMBER Page;
1331 
1332  Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)
1333  + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
1334  Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
1335  /*
1336  * An MM_WAIT_ENTRY is ok in this case... It'll just count as
1337  * IS_SWAP_FROM_SSE and we'll do the right thing.
1338  */
1339  Page = MmGetPfnForProcess(Process, Address);
1340 
1341  Protect = PAGE_READONLY;
1342  if (IS_SWAP_FROM_SSE(Entry) || PFN_FROM_SSE(Entry) != Page)
1343  {
1344  Protect = NewProtect;
1345  }
1346  }
1347 
1348  if (MmIsPagePresent(Process, Address) || MmIsDisabledPage(Process, Address))
1349  {
1350  MmSetPageProtect(Process, Address,
1351  Protect);
1352  }
1353  }
1354  }
1355 
1356  MmUnlockSectionSegment(Segment);
1357 }
1358 
1359 NTSTATUS
1360 NTAPI
1362  MEMORY_AREA* MemoryArea,
1363  PVOID Address,
1364  BOOLEAN Locked)
1365 {
1367  PFN_NUMBER Page;
1368  NTSTATUS Status;
1369  PROS_SECTION_OBJECT Section;
1371  ULONG_PTR Entry;
1372  ULONG_PTR Entry1;
1373  ULONG Attributes;
1375  BOOLEAN HasSwapEntry;
1376  PVOID PAddress;
1377  PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1378  SWAPENTRY SwapEntry;
1379 
1380  /*
1381  * There is a window between taking the page fault and locking the
1382  * address space when another thread could load the page so we check
1383  * that.
1384  */
1385  if (MmIsPagePresent(Process, Address))
1386  {
1387  return(STATUS_SUCCESS);
1388  }
1389 
1390  if (MmIsDisabledPage(Process, Address))
1391  {
1392  return(STATUS_ACCESS_VIOLATION);
1393  }
1394 
1395  /*
1396  * Check for the virtual memory area being deleted.
1397  */
1398  if (MemoryArea->DeleteInProgress)
1399  {
1400  return(STATUS_UNSUCCESSFUL);
1401  }
1402 
1403  PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
1404  Offset.QuadPart = (ULONG_PTR)PAddress - MA_GetStartingAddress(MemoryArea)
1405  + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
1406 
1407  Segment = MemoryArea->Data.SectionData.Segment;
1408  Section = MemoryArea->Data.SectionData.Section;
1409  Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
1410  &MemoryArea->Data.SectionData.RegionListHead,
1411  Address, NULL);
1412  ASSERT(Region != NULL);
1413 
1414  /* Check for a NOACCESS mapping */
1415  if (Region->Protect & PAGE_NOACCESS)
1416  {
1417  return STATUS_ACCESS_VIOLATION;
1418  }
1419 
1420  if (Region->Protect & PAGE_GUARD)
1421  {
1422  /* Remove it */
1423  Status = MmAlterRegion(AddressSpace, (PVOID)MA_GetStartingAddress(MemoryArea),
1424  &MemoryArea->Data.SectionData.RegionListHead,
1425  Address, PAGE_SIZE, Region->Type, Region->Protect & ~PAGE_GUARD,
1427 
1428  if (!NT_SUCCESS(Status))
1429  {
1430  DPRINT1("Removing PAGE_GUARD protection failed : 0x%08x.\n", Status);
1431  }
1432 
1434  }
1435 
1436  /*
1437  * Lock the segment
1438  */
1439  MmLockSectionSegment(Segment);
1440  Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
1441  /*
1442  * Check if this page needs to be mapped COW
1443  */
1444  if ((Segment->WriteCopy) &&
1445  (Region->Protect == PAGE_READWRITE ||
1446  Region->Protect == PAGE_EXECUTE_READWRITE))
1447  {
1448  Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
1449  }
1450  else
1451  {
1452  Attributes = Region->Protect;
1453  }
1454 
1455  /*
1456  * Check if someone else is already handling this fault, if so wait
1457  * for them
1458  */
1459  if (Entry && MM_IS_WAIT_PTE(Entry))
1460  {
1461  MmUnlockSectionSegment(Segment);
1462  MmUnlockAddressSpace(AddressSpace);
1464  MmLockAddressSpace(AddressSpace);
1465  DPRINT("Address 0x%p\n", Address);
1467  }
1468 
1469  HasSwapEntry = MmIsPageSwapEntry(Process, Address);
1470 
1471  /* See if we should use a private page */
1472  if (HasSwapEntry)
1473  {
1474  SWAPENTRY DummyEntry;
1475 
1476  /*
1477  * Is it a wait entry?
1478  */
1479  if (HasSwapEntry)
1480  {
1481  MmGetPageFileMapping(Process, Address, &SwapEntry);
1482 
1483  if (SwapEntry == MM_WAIT_ENTRY)
1484  {
1485  MmUnlockSectionSegment(Segment);
1486  MmUnlockAddressSpace(AddressSpace);
1488  MmLockAddressSpace(AddressSpace);
1490  }
1491 
1492  /*
1493  * Must be private page we have swapped out.
1494  */
1495 
1496  /*
1497  * Sanity check
1498  */
1499  if (Segment->Flags & MM_PAGEFILE_SEGMENT)
1500  {
1501  DPRINT1("Found a swaped out private page in a pagefile section.\n");
1502  KeBugCheck(MEMORY_MANAGEMENT);
1503  }
1504  MmDeletePageFileMapping(Process, Address, &SwapEntry);
1505  }
1506 
1507  MmUnlockSectionSegment(Segment);
1508 
1509  /* Tell everyone else we are serving the fault. */
1510  MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY);
1511 
1512  MmUnlockAddressSpace(AddressSpace);
1514  if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1515  if (!Process) MI_SET_PROCESS2("Kernel Section");
1516  Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1517  if (!NT_SUCCESS(Status))
1518  {
1519  KeBugCheck(MEMORY_MANAGEMENT);
1520  }
1521 
1522  if (HasSwapEntry)
1523  {
1524  Status = MmReadFromSwapPage(SwapEntry, Page);
1525  if (!NT_SUCCESS(Status))
1526  {
1527  DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
1528  KeBugCheck(MEMORY_MANAGEMENT);
1529  }
1530  }
1531 
1532  MmLockAddressSpace(AddressSpace);
1533  MmDeletePageFileMapping(Process, PAddress, &DummyEntry);
1534  Status = MmCreateVirtualMapping(Process,
1535  PAddress,
1536  Region->Protect,
1537  &Page,
1538  1);
1539  if (!NT_SUCCESS(Status))
1540  {
1541  DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1542  KeBugCheck(MEMORY_MANAGEMENT);
1543  return(Status);
1544  }
1545 
1546  /*
1547  * Store the swap entry for later use.
1548  */
1549  if (HasSwapEntry)
1550  MmSetSavedSwapEntryPage(Page, SwapEntry);
1551 
1552  /*
1553  * Add the page to the process's working set
1554  */
1555  MmInsertRmap(Page, Process, Address);
1556  /*
1557  * Finish the operation
1558  */
1559  MiSetPageEvent(Process, Address);
1560  DPRINT("Address 0x%p\n", Address);
1561  return(STATUS_SUCCESS);
1562  }
1563 
1564  /*
1565  * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1566  */
1568  {
1569  MmUnlockSectionSegment(Segment);
1570  /*
1571  * Just map the desired physical page
1572  */
1573  Page = (PFN_NUMBER)(Offset.QuadPart >> PAGE_SHIFT);
1574  Status = MmCreateVirtualMappingUnsafe(Process,
1575  PAddress,
1576  Region->Protect,
1577  &Page,
1578  1);
1579  if (!NT_SUCCESS(Status))
1580  {
1581  DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1582  KeBugCheck(MEMORY_MANAGEMENT);
1583  return(Status);
1584  }
1585 
1586  /*
1587  * Cleanup and release locks
1588  */
1589  MiSetPageEvent(Process, Address);
1590  DPRINT("Address 0x%p\n", Address);
1591  return(STATUS_SUCCESS);
1592  }
1593 
1594  /*
1595  * Get the entry corresponding to the offset within the section
1596  */
1597  Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
1598 
1599  if (Entry == 0)
1600  {
1601  SWAPENTRY FakeSwapEntry;
1602 
1603  /*
1604  * If the entry is zero (and it can't change because we have
1605  * locked the segment) then we need to load the page.
1606  */
1607 
1608  /*
1609  * Release all our locks and read in the page from disk
1610  */
1612  MmUnlockSectionSegment(Segment);
1613  MmCreatePageFileMapping(Process, PAddress, MM_WAIT_ENTRY);
1614  MmUnlockAddressSpace(AddressSpace);
1615 
1616  if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
1617  ((Offset.QuadPart >= (LONGLONG)PAGE_ROUND_UP(Segment->RawLength.QuadPart) &&
1618  (Section->AllocationAttributes & SEC_IMAGE))))
1619  {
1621  if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1622  if (!Process) MI_SET_PROCESS2("Kernel Section");
1623  Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1624  if (!NT_SUCCESS(Status))
1625  {
1626  DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
1627  }
1628 
1629  }
1630  else
1631  {
1632  Status = MiReadPage(MemoryArea, Offset.QuadPart, &Page);
1633  if (!NT_SUCCESS(Status))
1634  {
1635  DPRINT1("MiReadPage failed (Status %x)\n", Status);
1636  }
1637  }
1638  if (!NT_SUCCESS(Status))
1639  {
1640  /*
1641  * FIXME: What do we know in this case?
1642  */
1643  /*
1644  * Cleanup and release locks
1645  */
1646  MmLockAddressSpace(AddressSpace);
1647  MiSetPageEvent(Process, Address);
1648  DPRINT("Address 0x%p\n", Address);
1649  return(Status);
1650  }
1651 
1652  /* Lock both segment and process address space while we proceed. */
1653  MmLockAddressSpace(AddressSpace);
1654  MmLockSectionSegment(Segment);
1655 
1656  MmDeletePageFileMapping(Process, PAddress, &FakeSwapEntry);
1657  DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1658  Page, Process, PAddress, Attributes);
1659  Status = MmCreateVirtualMapping(Process,
1660  PAddress,
1661  Attributes,
1662  &Page,
1663  1);
1664  if (!NT_SUCCESS(Status))
1665  {
1666  DPRINT1("Unable to create virtual mapping\n");
1667  KeBugCheck(MEMORY_MANAGEMENT);
1668  }
1669  ASSERT(MmIsPagePresent(Process, PAddress));
1670  MmInsertRmap(Page, Process, Address);
1671 
1672  /* Set this section offset has being backed by our new page. */
1673  Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1674  MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
1675  MmUnlockSectionSegment(Segment);
1676 
1677  MiSetPageEvent(Process, Address);
1678  DPRINT("Address 0x%p\n", Address);
1679  return(STATUS_SUCCESS);
1680  }
1681  else if (IS_SWAP_FROM_SSE(Entry))
1682  {
1683  SWAPENTRY SwapEntry;
1684 
1685  SwapEntry = SWAPENTRY_FROM_SSE(Entry);
1686 
1687  /* See if a page op is running on this segment. */
1688  if (SwapEntry == MM_WAIT_ENTRY)
1689  {
1690  MmUnlockSectionSegment(Segment);
1691  MmUnlockAddressSpace(AddressSpace);
1693  MmLockAddressSpace(AddressSpace);
1695  }
1696 
1697  /*
1698  * Release all our locks and read in the page from disk
1699  */
1700  MmUnlockSectionSegment(Segment);
1701 
1702  MmUnlockAddressSpace(AddressSpace);
1704  if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1705  if (!Process) MI_SET_PROCESS2("Kernel Section");
1706  Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1707  if (!NT_SUCCESS(Status))
1708  {
1709  KeBugCheck(MEMORY_MANAGEMENT);
1710  }
1711 
1712  Status = MmReadFromSwapPage(SwapEntry, Page);
1713  if (!NT_SUCCESS(Status))
1714  {
1715  KeBugCheck(MEMORY_MANAGEMENT);
1716  }
1717 
1718  /*
1719  * Relock the address space and segment
1720  */
1721  MmLockAddressSpace(AddressSpace);
1722  MmLockSectionSegment(Segment);
1723 
1724  /*
1725  * Check the entry. No one should change the status of a page
1726  * that has a pending page-in.
1727  */
1728  Entry1 = MmGetPageEntrySectionSegment(Segment, &Offset);
1729  if (Entry != Entry1)
1730  {
1731  DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry, Entry1);
1732  KeBugCheck(MEMORY_MANAGEMENT);
1733  }
1734 
1735  /*
1736  * Save the swap entry.
1737  */
1738  MmSetSavedSwapEntryPage(Page, SwapEntry);
1739 
1740  /* Map the page into the process address space */
1741  Status = MmCreateVirtualMapping(Process,
1742  PAddress,
1743  Region->Protect,
1744  &Page,
1745  1);
1746  if (!NT_SUCCESS(Status))
1747  {
1748  DPRINT1("Unable to create virtual mapping\n");
1749  KeBugCheck(MEMORY_MANAGEMENT);
1750  }
1751  MmInsertRmap(Page, Process, Address);
1752 
1753  /*
1754  * Mark the offset within the section as having valid, in-memory
1755  * data
1756  */
1757  Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1758  MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
1759  MmUnlockSectionSegment(Segment);
1760 
1761  MiSetPageEvent(Process, Address);
1762  DPRINT("Address 0x%p\n", Address);
1763  return(STATUS_SUCCESS);
1764  }
1765  else
1766  {
1767  /* We already have a page on this section offset. Map it into the process address space. */
1768  Page = PFN_FROM_SSE(Entry);
1769 
1770  Status = MmCreateVirtualMapping(Process,
1771  PAddress,
1772  Attributes,
1773  &Page,
1774  1);
1775  if (!NT_SUCCESS(Status))
1776  {
1777  DPRINT1("Unable to create virtual mapping\n");
1778  KeBugCheck(MEMORY_MANAGEMENT);
1779  }
1780  MmInsertRmap(Page, Process, Address);
1781 
1782  /* Take a reference on it */
1783  MmSharePageEntrySectionSegment(Segment, &Offset);
1784  MmUnlockSectionSegment(Segment);
1785 
1786  MiSetPageEvent(Process, Address);
1787  DPRINT("Address 0x%p\n", Address);
1788  return(STATUS_SUCCESS);
1789  }
1790 }
1791 
1792 NTSTATUS
1793 NTAPI
1795  MEMORY_AREA* MemoryArea,
1796  PVOID Address)
1797 {
1799  PROS_SECTION_OBJECT Section;
1800  PFN_NUMBER OldPage;
1801  PFN_NUMBER NewPage;
1802  NTSTATUS Status;
1803  PVOID PAddress;
1806  ULONG_PTR Entry;
1807  PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1808 
1809  DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace, MemoryArea, Address);
1810 
1811  /* Make sure we have a page mapping for this address. */
1812  Status = MmNotPresentFaultSectionView(AddressSpace, MemoryArea, Address, TRUE);
1813  if (!NT_SUCCESS(Status))
1814  {
1815  /* This is invalid access ! */
1816  return Status;
1817  }
1818 
1819  /*
1820  * Check if the page has already been set readwrite
1821  */
1822  if (MmGetPageProtect(Process, Address) & PAGE_READWRITE)
1823  {
1824  DPRINT("Address 0x%p\n", Address);
1825  return(STATUS_SUCCESS);
1826  }
1827 
1828  /*
1829  * Find the offset of the page
1830  */
1831  PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
1832  Offset.QuadPart = (ULONG_PTR)PAddress - MA_GetStartingAddress(MemoryArea)
1833  + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
1834 
1835  Segment = MemoryArea->Data.SectionData.Segment;
1836  Section = MemoryArea->Data.SectionData.Section;
1837  Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
1838  &MemoryArea->Data.SectionData.RegionListHead,
1839  Address, NULL);
1840  ASSERT(Region != NULL);
1841 
1842  /*
1843  * Check if we are doing COW
1844  */
1845  if (!((Segment->WriteCopy) &&
1846  (Region->Protect == PAGE_READWRITE ||
1847  Region->Protect == PAGE_EXECUTE_READWRITE)))
1848  {
1849  DPRINT("Address 0x%p\n", Address);
1850  return(STATUS_ACCESS_VIOLATION);
1851  }
1852 
1853  /* Get the page mapping this section offset. */
1854  MmLockSectionSegment(Segment);
1855  Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
1856 
1857  /* Get the current page mapping for the process */
1858  ASSERT(MmIsPagePresent(Process, PAddress));
1859  OldPage = MmGetPfnForProcess(Process, PAddress);
1860  ASSERT(OldPage != 0);
1861 
1862  if (IS_SWAP_FROM_SSE(Entry) ||
1863  PFN_FROM_SSE(Entry) != OldPage)
1864  {
1865  MmUnlockSectionSegment(Segment);
1866  /* This is a private page. We must only change the page protection. */
1867  MmSetPageProtect(Process, PAddress, Region->Protect);
1868  return(STATUS_SUCCESS);
1869  }
1870 
1871  /*
1872  * Allocate a page
1873  */
1875  if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1876  if (!Process) MI_SET_PROCESS2("Kernel Section");
1877  Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1878  if (!NT_SUCCESS(Status))
1879  {
1880  KeBugCheck(MEMORY_MANAGEMENT);
1881  }
1882 
1883  /*
1884  * Copy the old page
1885  */
1886  NT_VERIFY(NT_SUCCESS(MiCopyFromUserPage(NewPage, PAddress)));
1887 
1888  /*
1889  * Unshare the old page.
1890  */
1891  DPRINT("Swapping page (Old %x New %x)\n", OldPage, NewPage);
1892  MmDeleteVirtualMapping(Process, PAddress, NULL, NULL);
1893  MmDeleteRmap(OldPage, Process, PAddress);
1894  MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, FALSE, FALSE, NULL);
1895  MmUnlockSectionSegment(Segment);
1896 
1897  /*
1898  * Set the PTE to point to the new page
1899  */
1900  Status = MmCreateVirtualMapping(Process,
1901  PAddress,
1902  Region->Protect,
1903  &NewPage,
1904  1);
1905  if (!NT_SUCCESS(Status))
1906  {
1907  DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1908  KeBugCheck(MEMORY_MANAGEMENT);
1909  return(Status);
1910  }
1911  MmInsertRmap(NewPage, Process, PAddress);
1912 
1913  MiSetPageEvent(Process, Address);
1914  DPRINT("Address 0x%p\n", Address);
1915  return(STATUS_SUCCESS);
1916 }
1917 
1918 VOID
1920 {
1921  MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1922  BOOLEAN WasDirty;
1923  PFN_NUMBER Page = 0;
1924 
1925  PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1926  if (Process)
1927  {
1928  MmLockAddressSpace(&Process->Vm);
1929  }
1930 
1931  MmDeleteVirtualMapping(Process,
1932  Address,
1933  &WasDirty,
1934  &Page);
1935  if (WasDirty)
1936  {
1937  PageOutContext->WasDirty = TRUE;
1938  }
1939  if (!PageOutContext->Private)
1940  {
1941  MmLockSectionSegment(PageOutContext->Segment);
1943  PageOutContext->Segment,
1944  &PageOutContext->Offset,
1945  PageOutContext->WasDirty,
1946  TRUE,
1947  &PageOutContext->SectionEntry);
1948  MmUnlockSectionSegment(PageOutContext->Segment);
1949  }
1950  if (Process)
1951  {
1952  MmUnlockAddressSpace(&Process->Vm);
1953  }
1954 
1955  if (PageOutContext->Private)
1956  {
1958  }
1959 }
1960 
1961 NTSTATUS
1962 NTAPI
1964  MEMORY_AREA* MemoryArea,
1966 {
1967  PFN_NUMBER Page;
1969  SWAPENTRY SwapEntry;
1970  NTSTATUS Status;
1971 #ifndef NEWCC
1974  PROS_SHARED_CACHE_MAP SharedCacheMap = NULL;
1975  BOOLEAN IsImageSection;
1976 #endif
1977  BOOLEAN DirectMapped;
1978  PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1979  KIRQL OldIrql;
1980 
1981  Address = (PVOID)PAGE_ROUND_DOWN(Address);
1982 
1983  /*
1984  * Get the segment and section.
1985  */
1986  Context.Segment = MemoryArea->Data.SectionData.Segment;
1987  Context.Section = MemoryArea->Data.SectionData.Section;
1988  Context.SectionEntry = Entry;
1989  Context.CallingProcess = Process;
1990 
1991  Context.Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)
1992  + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
1993 
1994  DirectMapped = FALSE;
1995 
1996  MmLockSectionSegment(Context.Segment);
1997 
1998 #ifndef NEWCC
1999  FileOffset = Context.Offset.QuadPart + Context.Segment->Image.FileOffset;
2000  IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
2001  FileObject = Context.Section->FileObject;
2002 
2003  if (FileObject != NULL &&
2004  !(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
2005  {
2006  SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
2007 
2008  /*
2009  * If the file system is letting us go directly to the cache and the
2010  * memory area was mapped at an offset in the file which is page aligned
2011  * then note this is a direct mapped page.
2012  */
2013  if ((FileOffset % PAGE_SIZE) == 0 &&
2014  (Context.Offset.QuadPart + PAGE_SIZE <= Context.Segment->RawLength.QuadPart || !IsImageSection))
2015  {
2016  DirectMapped = TRUE;
2017  }
2018  }
2019 #endif
2020 
2021 
2022  /*
2023  * This should never happen since mappings of physical memory are never
2024  * placed in the rmap lists.
2025  */
2027  {
2028  DPRINT1("Trying to page out from physical memory section address 0x%p "
2029  "process %p\n", Address,
2030  Process ? Process->UniqueProcessId : 0);
2031  KeBugCheck(MEMORY_MANAGEMENT);
2032  }
2033 
2034  /*
2035  * Get the section segment entry and the physical address.
2036  */
2037  if (!MmIsPagePresent(Process, Address))
2038  {
2039  DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2040  Process ? Process->UniqueProcessId : 0, Address);
2041  KeBugCheck(MEMORY_MANAGEMENT);
2042  }
2043  Page = MmGetPfnForProcess(Process, Address);
2044  SwapEntry = MmGetSavedSwapEntryPage(Page);
2045 
2046  /*
2047  * Check the reference count to ensure this page can be paged out
2048  */
2049  if (MmGetReferenceCountPage(Page) != 1)
2050  {
2051  DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
2052  Page, MmGetReferenceCountPage(Page));
2053  MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2055  return STATUS_UNSUCCESSFUL;
2056  }
2057 
2058  /*
2059  * Prepare the context structure for the rmap delete call.
2060  */
2062  Context.WasDirty = FALSE;
2063  if (IS_SWAP_FROM_SSE(Entry) || PFN_FROM_SSE(Entry) != Page)
2064  {
2065  Context.Private = TRUE;
2066  }
2067  else
2068  {
2069  Context.Private = FALSE;
2070  }
2071 
2072  /*
2073  * Take an additional reference to the page or the VACB.
2074  */
2075  if (DirectMapped && !Context.Private)
2076  {
2077  if(!MiIsPageFromCache(MemoryArea, Context.Offset.QuadPart))
2078  {
2079  DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2080  KeBugCheck(MEMORY_MANAGEMENT);
2081  }
2082  }
2083  else
2084  {
2085  OldIrql = MiAcquirePfnLock();
2086  MmReferencePage(Page);
2087  MiReleasePfnLock(OldIrql);
2088  }
2089 
2090  MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping);
2091 
2092  /* Since we passed in a surrogate, we'll get back the page entry
2093  * state in our context. This is intended to make intermediate
2094  * decrements of share count not release the wait entry.
2095  */
2096  Entry = Context.SectionEntry;
2097 
2098  /*
2099  * If this wasn't a private page then we should have reduced the entry to
2100  * zero by deleting all the rmaps.
2101  */
2102  if (!Context.Private && Entry != 0)
2103  {
2104  if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
2105  !(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
2106  {
2107  KeBugCheckEx(MEMORY_MANAGEMENT, Entry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
2108  }
2109  }
2110 
2111  /*
2112  * If the page wasn't dirty then we can just free it as for a readonly page.
2113  * Since we unmapped all the mappings above we know it will not suddenly
2114  * become dirty.
2115  * If the page is from a pagefile section and has no swap entry,
2116  * we can't free the page at this point.
2117  */
2118  SwapEntry = MmGetSavedSwapEntryPage(Page);
2119  if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT)
2120  {
2121  if (Context.Private)
2122  {
2123  DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2124  Context.WasDirty ? "dirty" : "clean", Address);
2125  KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
2126  }
2127  if (!Context.WasDirty && SwapEntry != 0)
2128  {
2129  MmSetSavedSwapEntryPage(Page, 0);
2130  MmLockSectionSegment(Context.Segment);
2131  MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2132  MmUnlockSectionSegment(Context.Segment);
2135  return(STATUS_SUCCESS);
2136  }
2137  }
2138  else if (Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2139  {
2140  if (Context.Private)
2141  {
2142  DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2143  Context.WasDirty ? "dirty" : "clean", Address);
2144  KeBugCheckEx(MEMORY_MANAGEMENT, Page, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
2145  }
2146  if (!Context.WasDirty || SwapEntry != 0)
2147  {
2148  MmSetSavedSwapEntryPage(Page, 0);
2149  if (SwapEntry != 0)
2150  {
2151  MmLockSectionSegment(Context.Segment);
2152  MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2153  MmUnlockSectionSegment(Context.Segment);
2154  }
2157  return(STATUS_SUCCESS);
2158  }
2159  }
2160  else if (!Context.Private && DirectMapped)
2161  {
2162  if (SwapEntry != 0)
2163  {
2164  DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2165  Address);
2166  KeBugCheckEx(MEMORY_MANAGEMENT, STATUS_UNSUCCESSFUL, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address);
2167  }
2168 #ifndef NEWCC
2169  Status = CcRosUnmapVacb(SharedCacheMap, FileOffset, FALSE);
2170 #else
2171  Status = STATUS_SUCCESS;
2172 #endif
2173 #ifndef NEWCC
2174  if (!NT_SUCCESS(Status))
2175  {
2176  DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status);
2177  KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)SharedCacheMap, (ULONG_PTR)FileOffset, (ULONG_PTR)Address);
2178  }
2179 #endif
2181  return(STATUS_SUCCESS);
2182  }
2183  else if (!Context.WasDirty && !DirectMapped && !Context.Private)
2184  {
2185  if (SwapEntry != 0)
2186  {
2187  DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2188  Address);
2189  KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, Page, (ULONG_PTR)Process, (ULONG_PTR)Address);
2190  }
2193  return(STATUS_SUCCESS);
2194  }
2195  else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
2196  {
2197  DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process, Address);
2198  MmSetSavedSwapEntryPage(Page, 0);
2199  MmLockAddressSpace(AddressSpace);
2200  Status = MmCreatePageFileMapping(Process,
2201  Address,
2202  SwapEntry);
2203  MmUnlockAddressSpace(AddressSpace);
2204  if (!NT_SUCCESS(Status))
2205  {
2206  DPRINT1("Status %x Swapping out %p:%p\n", Status, Process, Address);
2207  KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry);
2208  }
2211  return(STATUS_SUCCESS);
2212  }
2213 
2214  /*
2215  * If necessary, allocate an entry in the paging file for this page
2216  */
2217  if (SwapEntry == 0)
2218  {
2219  SwapEntry = MmAllocSwapPage();
2220  if (SwapEntry == 0)
2221  {
2223  MmLockAddressSpace(AddressSpace);
2224  /*
2225  * For private pages restore the old mappings.
2226  */
2227  if (Context.Private)
2228  {
2229  Status = MmCreateVirtualMapping(Process,
2230  Address,
2231  MemoryArea->Protect,
2232  &Page,
2233  1);
2234  MmSetDirtyPage(Process, Address);
2235  MmInsertRmap(Page,
2236  Process,
2237  Address);
2238  }
2239  else
2240  {
2241  ULONG_PTR OldEntry;
2242 
2243  MmLockSectionSegment(Context.Segment);
2244 
2245  /*
2246  * For non-private pages if the page wasn't direct mapped then
2247  * set it back into the section segment entry so we don't loose
2248  * our copy. Otherwise it will be handled by the cache manager.
2249  */
2250  Status = MmCreateVirtualMapping(Process,
2251  Address,
2252  MemoryArea->Protect,
2253  &Page,
2254  1);
2255  MmSetDirtyPage(Process, Address);
2256  MmInsertRmap(Page,
2257  Process,
2258  Address);
2259  // If we got here, the previous entry should have been a wait
2260  Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
2261  OldEntry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset);
2262  ASSERT(OldEntry == 0 || OldEntry == MAKE_SWAP_SSE(MM_WAIT_ENTRY));
2263  MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2264  MmUnlockSectionSegment(Context.Segment);
2265  }
2266  MmUnlockAddressSpace(AddressSpace);
2268  return(STATUS_PAGEFILE_QUOTA);
2269  }
2270  }
2271 
2272  /*
2273  * Write the page to the pagefile
2274  */
2275  Status = MmWriteToSwapPage(SwapEntry, Page);
2276  if (!NT_SUCCESS(Status))
2277  {
2278  DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2279  Status);
2280  /*
2281  * As above: undo our actions.
2282  * FIXME: Also free the swap page.
2283  */
2284  MmLockAddressSpace(AddressSpace);
2285  if (Context.Private)
2286  {
2287  Status = MmCreateVirtualMapping(Process,
2288  Address,
2289  MemoryArea->Protect,
2290  &Page,
2291  1);
2292  MmSetDirtyPage(Process, Address);
2293  MmInsertRmap(Page,
2294  Process,
2295  Address);
2296  }
2297  else
2298  {
2299  MmLockSectionSegment(Context.Segment);
2300  Status = MmCreateVirtualMapping(Process,
2301  Address,
2302  MemoryArea->Protect,
2303  &Page,
2304  1);
2305  MmSetDirtyPage(Process, Address);
2306  MmInsertRmap(Page,
2307  Process,
2308  Address);
2309  Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
2310  MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2311  MmUnlockSectionSegment(Context.Segment);
2312  }
2313  MmUnlockAddressSpace(AddressSpace);
2315  return(STATUS_UNSUCCESSFUL);
2316  }
2317 
2318  /*
2319  * Otherwise we have succeeded.
2320  */
2321  DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
2322  MmSetSavedSwapEntryPage(Page, 0);
2323  if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
2324  Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2325  {
2326  MmLockSectionSegment(Context.Segment);
2327  MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2328  MmUnlockSectionSegment(Context.Segment);
2329  }
2330  else
2331  {
2333  }
2334 
2335  if (Context.Private)
2336  {
2337  MmLockAddressSpace(AddressSpace);
2338  MmLockSectionSegment(Context.Segment);
2339  Status = MmCreatePageFileMapping(Process,
2340  Address,
2341  SwapEntry);
2342  /* We had placed a wait entry upon entry ... replace it before leaving */
2343  MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2344  MmUnlockSectionSegment(Context.Segment);
2345  MmUnlockAddressSpace(AddressSpace);
2346  if (!NT_SUCCESS(Status))
2347  {
2348  DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status, Process, Address);
2349  KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry);
2350  }
2351  }
2352  else
2353  {
2354  MmLockAddressSpace(AddressSpace);
2355  MmLockSectionSegment(Context.Segment);
2356  Entry = MAKE_SWAP_SSE(SwapEntry);
2357  /* We had placed a wait entry upon entry ... replace it before leaving */
2358  MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2359  MmUnlockSectionSegment(Context.Segment);
2360  MmUnlockAddressSpace(AddressSpace);
2361  }
2362 
2364  return(STATUS_SUCCESS);
2365 }
2366 
2367 NTSTATUS
2368 NTAPI
2370  PMEMORY_AREA MemoryArea,
2371  PVOID Address,
2372  ULONG PageEntry)
2373 {
2375  PROS_SECTION_OBJECT Section;
2377  PFN_NUMBER Page;
2378  SWAPENTRY SwapEntry;
2379  ULONG_PTR Entry;
2380  BOOLEAN Private;
2381  NTSTATUS Status;
2383 #ifndef NEWCC
2384  PROS_SHARED_CACHE_MAP SharedCacheMap = NULL;
2385 #endif
2386  BOOLEAN DirectMapped;
2387  BOOLEAN IsImageSection;
2388  PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
2389 
2390  Address = (PVOID)PAGE_ROUND_DOWN(Address);
2391 
2392  Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)
2393  + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
2394 
2395  /*
2396  * Get the segment and section.
2397  */
2398  Segment = MemoryArea->Data.SectionData.Segment;
2399  Section = MemoryArea->Data.SectionData.Section;
2400  IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
2401 
2402  FileObject = Section->FileObject;
2403  DirectMapped = FALSE;
2404  if (FileObject != NULL &&
2405  !(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
2406  {
2407 #ifndef NEWCC
2408  SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
2409 #endif
2410 
2411  /*
2412  * If the file system is letting us go directly to the cache and the
2413  * memory area was mapped at an offset in the file which is page aligned
2414  * then note this is a direct mapped page.
2415  */
2416  if (((Offset.QuadPart + Segment->Image.FileOffset) % PAGE_SIZE) == 0 &&
2417  (Offset.QuadPart + PAGE_SIZE <= Segment->RawLength.QuadPart || !IsImageSection))
2418  {
2419  DirectMapped = TRUE;
2420  }
2421  }
2422 
2423  /*
2424  * This should never happen since mappings of physical memory are never
2425  * placed in the rmap lists.
2426  */
2428  {
2429  DPRINT1("Trying to write back page from physical memory mapped at %p "
2430  "process %p\n", Address,
2431  Process ? Process->UniqueProcessId : 0);
2432  KeBugCheck(MEMORY_MANAGEMENT);
2433  }
2434 
2435  /*
2436  * Get the section segment entry and the physical address.
2437  */
2438  Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
2439  if (!MmIsPagePresent(Process, Address))
2440  {
2441  DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2442  Process ? Process->UniqueProcessId : 0, Address);
2443  KeBugCheck(MEMORY_MANAGEMENT);
2444  }
2445  Page = MmGetPfnForProcess(Process, Address);
2446  SwapEntry = MmGetSavedSwapEntryPage(Page);
2447 
2448  /*
2449  * Check for a private (COWed) page.
2450  */
2451  if (IS_SWAP_FROM_SSE(Entry) || PFN_FROM_SSE(Entry) != Page)
2452  {
2453  Private = TRUE;
2454  }
2455  else
2456  {
2457  Private = FALSE;
2458  }
2459 
2460  /*
2461  * Speculatively set all mappings of the page to clean.
2462  */
2463  MmSetCleanAllRmaps(Page);
2464 
2465  /*
2466  * If this page was direct mapped from the cache then the cache manager
2467  * will take care of writing it back to disk.
2468  */
2469  if (DirectMapped && !Private)
2470  {
2471  //LARGE_INTEGER SOffset;
2472  ASSERT(SwapEntry == 0);
2473  //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2474 #ifndef NEWCC
2475  CcRosMarkDirtyFile(SharedCacheMap, Offset.QuadPart);
2476 #endif
2477  MmLockSectionSegment(Segment);
2478  MmSetPageEntrySectionSegment(Segment, &Offset, PageEntry);
2479  MmUnlockSectionSegment(Segment);
2481  return(STATUS_SUCCESS);
2482  }
2483 
2484  /*
2485  * If necessary, allocate an entry in the paging file for this page
2486  */
2487  if (SwapEntry == 0)
2488  {
2489  SwapEntry = MmAllocSwapPage();
2490  if (SwapEntry == 0)
2491  {
2492  MmSetDirtyAllRmaps(Page);
2494  return(STATUS_PAGEFILE_QUOTA);
2495  }
2496  MmSetSavedSwapEntryPage(Page, SwapEntry);
2497  }
2498 
2499  /*
2500  * Write the page to the pagefile
2501  */
2502  Status = MmWriteToSwapPage(SwapEntry, Page);
2503  if (!NT_SUCCESS(Status))
2504  {
2505  DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2506  Status);
2507  MmSetDirtyAllRmaps(Page);
2509  return(STATUS_UNSUCCESSFUL);
2510  }
2511 
2512  /*
2513  * Otherwise we have succeeded.
2514  */
2515  DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
2517  return(STATUS_SUCCESS);
2518 }
2519 
2520 NTSTATUS
2521 NTAPI
2523  PMEMORY_AREA MemoryArea,
2525  SIZE_T Length,
2526  ULONG Protect,
2527  PULONG OldProtect)
2528 {
2530  NTSTATUS Status;
2531  ULONG_PTR MaxLength;
2532 
2533  MaxLength = MA_GetEndingAddress(MemoryArea) - (ULONG_PTR)BaseAddress;
2534  if (Length > MaxLength)
2535  Length = (ULONG)MaxLength;
2536 
2537  Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
2538  &MemoryArea->Data.SectionData.RegionListHead,
2539  BaseAddress, NULL);
2540  ASSERT(Region != NULL);
2541 
2542  if ((MemoryArea->Flags & SEC_NO_CHANGE) &&
2543  Region->Protect != Protect)
2544  {
2546  }
2547 
2548  *OldProtect = Region->Protect;
2549  Status = MmAlterRegion(AddressSpace, (PVOID)MA_GetStartingAddress(MemoryArea),
2550  &MemoryArea->Data.SectionData.RegionListHead,
2551  BaseAddress, Length, Region->Type, Protect,
2553 
2554  return(Status);
2555 }
2556 
2559  PVOID Address,
2562 {
2564  PVOID RegionBaseAddress;
2565  PROS_SECTION_OBJECT Section;
2567 
2568  Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
2569  &MemoryArea->Data.SectionData.RegionListHead,
2570  Address, &RegionBaseAddress);
2571  if (Region == NULL)
2572  {
2573  return STATUS_UNSUCCESSFUL;
2574  }
2575 
2576  Section = MemoryArea->Data.SectionData.Section;
2577  if (Section->AllocationAttributes & SEC_IMAGE)
2578  {
2579  Segment = MemoryArea->Data.SectionData.Segment;
2580  Info->AllocationBase = (PUCHAR)MA_GetStartingAddress(MemoryArea) - Segment->Image.VirtualAddress;
2581  Info->Type = MEM_IMAGE;
2582  }
2583  else
2584  {
2585  Info->AllocationBase = (PVOID)MA_GetStartingAddress(MemoryArea);
2586  Info->Type = MEM_MAPPED;
2587  }
2588  Info->BaseAddress = RegionBaseAddress;
2589  Info->AllocationProtect = MemoryArea->Protect;
2590  Info->RegionSize = Region->Length;
2591  Info->State = MEM_COMMIT;
2592  Info->Protect = Region->Protect;
2593 
2594  *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
2595  return(STATUS_SUCCESS);
2596 }
2597 
2598 VOID
2599 NTAPI
2601 {
2602  ULONG Length;
2604  ULONG_PTR Entry;
2605  SWAPENTRY SavedSwapEntry;
2606  PFN_NUMBER Page;
2607 
2608  Page = 0;
2609 
2610  MmLockSectionSegment(Segment);
2611 
2612  Length = PAGE_ROUND_UP(Segment->Length.QuadPart);
2613  for (Offset.QuadPart = 0; Offset.QuadPart < Length; Offset.QuadPart += PAGE_SIZE)
2614  {
2615  Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
2616  if (Entry)
2617  {
2618  MmSetPageEntrySectionSegment(Segment, &Offset, 0);
2619  if (IS_SWAP_FROM_SSE(Entry))
2620  {
2622  }
2623  else
2624  {
2625  Page = PFN_FROM_SSE(Entry);
2626  SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
2627  if (SavedSwapEntry != 0)
2628  {
2629  MmSetSavedSwapEntryPage(Page, 0);
2630  MmFreeSwapPage(SavedSwapEntry);
2631  }
2633  }
2634  }
2635  }
2636 
2637  MmUnlockSectionSegment(Segment);
2638 }
2639 
2640 VOID NTAPI
2642 {
2643  PROS_SECTION_OBJECT Section = (PROS_SECTION_OBJECT)ObjectBody;
2644 
2645  /* Check if it's an ARM3, or ReactOS section */
2646  if (!MiIsRosSectionObject(Section))
2647  {
2648  MiDeleteARM3Section(ObjectBody);
2649  return;
2650  }
2651 
2652  DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody);
2653  if (Section->AllocationAttributes & SEC_IMAGE)
2654  {
2655  ULONG i;
2656  ULONG NrSegments;
2657  ULONG RefCount;
2658  PMM_SECTION_SEGMENT SectionSegments;
2659 
2660  /*
2661  * NOTE: Section->ImageSection can be NULL for short time
2662  * during the section creating. If we fail for some reason
2663  * until the image section is properly initialized we shouldn't
2664  * process further here.
2665  */
2666  if (Section->ImageSection == NULL)
2667  return;
2668 
2669  SectionSegments = Section->ImageSection->Segments;
2670  NrSegments = Section->ImageSection->NrSegments;
2671 
2672  for (i = 0; i < NrSegments; i++)
2673  {
2674  if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2675  {
2676  MmLockSectionSegment(&SectionSegments[i]);
2677  }
2678  RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount);
2679  if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2680  {
2681  MmUnlockSectionSegment(&SectionSegments[i]);
2682  if (RefCount == 0)
2683  {
2684  MmpFreePageFileSegment(&SectionSegments[i]);
2685  }
2686  }
2687  }
2688  }
2689 #ifdef NEWCC
2690  else if (Section->Segment && Section->Segment->Flags & MM_DATAFILE_SEGMENT)
2691  {
2692  ULONG RefCount = 0;
2693  PMM_SECTION_SEGMENT Segment = Section->Segment;
2694 
2695  if (Segment &&
2696  (RefCount = InterlockedDecrementUL(&Segment->ReferenceCount)) == 0)
2697  {
2698  DPRINT("Freeing section segment\n");
2699  Section->Segment = NULL;
2700  MmFinalizeSegment(Segment);
2701  }
2702  else
2703  {
2704  DPRINT("RefCount %d\n", RefCount);
2705  }
2706  }
2707 #endif
2708  else
2709  {
2710  /*
2711  * NOTE: Section->Segment can be NULL for short time
2712  * during the section creating.
2713  */
2714  if (Section->Segment == NULL)
2715  return;
2716 
2717  if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
2718  {
2719  MmpFreePageFileSegment(Section->Segment);
2721  ExFreePool(Section->Segment);
2722  Section->Segment = NULL;
2723  }
2724  else
2725  {
2727  }
2728  }
2729  if (Section->FileObject != NULL)
2730  {
2731 #ifndef NEWCC
2733 #endif
2734  ObDereferenceObject(Section->FileObject);
2735  Section->FileObject = NULL;
2736  }
2737 }
2738 
2739 VOID NTAPI
2741  IN PVOID Object,
2744  IN ULONG SystemHandleCount)
2745 {
2746  DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object, ProcessHandleCount);
2747 }
2748 
2749 NTSTATUS
2751 NTAPI
2753 {
2754  PROS_SECTION_OBJECT PhysSection;
2755  NTSTATUS Status;
2757  UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
2758  LARGE_INTEGER SectionSize;
2759  HANDLE Handle;
2760 
2761  /*
2762  * Create the section mapping physical memory
2763  */
2764  SectionSize.QuadPart = 0xFFFFFFFF;
2766  &Name,
2768  NULL,
2769  NULL);
2770  Status = MmCreateSection((PVOID)&PhysSection,
2771  SECTION_ALL_ACCESS,
2772  &Obj,
2773  &SectionSize,
2776  NULL,
2777  NULL);
2778  if (!NT_SUCCESS(Status))
2779  {
2780  DPRINT1("Failed to create PhysicalMemory section\n");
2781  KeBugCheck(MEMORY_MANAGEMENT);
2782  }
2783  Status = ObInsertObject(PhysSection,
2784  NULL,
2785  SECTION_ALL_ACCESS,
2786  0,
2787  NULL,
2788  &Handle);
2789  if (!NT_SUCCESS(Status))
2790  {
2791  ObDereferenceObject(PhysSection);
2792  }
2793  ObCloseHandle(Handle, KernelMode);
2794  PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
2795  PhysSection->Segment->Flags &= ~MM_PAGEFILE_SEGMENT;
2796 
2797  return(STATUS_SUCCESS);
2798 }
2799 
2800 NTSTATUS
2802 NTAPI
2804 {
2805  OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
2807 
2808  DPRINT("Creating Section Object Type\n");
2809 
2810  /* Initialize the section based root */
2813 
2814  /* Initialize the Section object type */
2815  RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
2816  RtlInitUnicodeString(&Name, L"Section");
2817  ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
2818  ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(ROS_SECTION_OBJECT);
2819  ObjectTypeInitializer.PoolType = PagedPool;
2820  ObjectTypeInitializer.UseDefaultObject = TRUE;
2821  ObjectTypeInitializer.GenericMapping = MmpSectionMapping;
2822  ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection;
2823  ObjectTypeInitializer.CloseProcedure = MmpCloseSection;
2824  ObjectTypeInitializer.ValidAccessMask = SECTION_ALL_ACCESS;
2825  ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
2826  ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &MmSectionObjectType);
2827 
2829 
2830  return(STATUS_SUCCESS);
2831 }
2832 
2833 NTSTATUS
2834 NTAPI
2838  PLARGE_INTEGER UMaximumSize,
2839  ULONG SectionPageProtection,
2841 /*
2842  * Create a section which is backed by the pagefile
2843  */
2844 {
2846  PROS_SECTION_OBJECT Section;
2848  NTSTATUS Status;
2849 
2850  if (UMaximumSize == NULL)
2851  {
2852  DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2853  return(STATUS_INVALID_PARAMETER);
2854  }
2855  MaximumSize = *UMaximumSize;
2856 
2857  /*
2858  * Create the section
2859  */
2860  Status = ObCreateObject(ExGetPreviousMode(),
2861  MmSectionObjectType,
2862  ObjectAttributes,
2864  NULL,
2865  sizeof(ROS_SECTION_OBJECT),
2866  0,
2867  0,
2868  (PVOID*)(PVOID)&Section);
2869  if (!NT_SUCCESS(Status))
2870  {
2871  DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status);
2872  return(Status);
2873  }
2874 
2875  /*
2876  * Initialize it
2877  */
2878  RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
2879  Section->Type = 'SC';
2880  Section->Size = 'TN';
2881  Section->SectionPageProtection = SectionPageProtection;
2882  Section->AllocationAttributes = AllocationAttributes;
2883  Section->MaximumSize = MaximumSize;
2886  if (Segment == NULL)
2887  {
2888  ObDereferenceObject(Section);
2889  return(STATUS_NO_MEMORY);
2890  }
2891  RtlZeroMemory(Segment, sizeof(MM_SECTION_SEGMENT));
2892  Section->Segment = Segment;
2893  Segment->ReferenceCount = 1;
2894  ExInitializeFastMutex(&Segment->Lock);
2895  Segment->Image.FileOffset = 0;
2896  Segment->Protection = SectionPageProtection;
2897  Segment->RawLength.QuadPart = MaximumSize.u.LowPart;
2898  Segment->Length.QuadPart = PAGE_ROUND_UP(MaximumSize.u.LowPart);
2899  Segment->Flags = MM_PAGEFILE_SEGMENT;
2900  Segment->WriteCopy = FALSE;
2901  Segment->Image.VirtualAddress = 0;
2902  Segment->Image.Characteristics = 0;
2903  *SectionObject = Section;
2905  return(STATUS_SUCCESS);
2906 }
2907 
2908 NTSTATUS
2909 NTAPI
2913  PLARGE_INTEGER UMaximumSize,
2914  ULONG SectionPageProtection,
2917 /*
2918  * Create a section backed by a data file
2919  */
2920 {
2921  PROS_SECTION_OBJECT Section;
2922  NTSTATUS Status;
2926  ULONG Length;
2927 
2928  /*
2929  * Create the section
2930  */
2931  Status = ObCreateObject(ExGetPreviousMode(),
2932  MmSectionObjectType,
2933  ObjectAttributes,
2935  NULL,
2936  sizeof(ROS_SECTION_OBJECT),
2937  0,
2938  0,
2939  (PVOID*)&Section);
2940  if (!NT_SUCCESS(Status))
2941  {
2942  ObDereferenceObject(FileObject);
2943  return(Status);
2944  }
2945  /*
2946  * Initialize it
2947  */
2948  RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
2949  Section->Type = 'SC';
2950  Section->Size = 'TN';
2951  Section->SectionPageProtection = SectionPageProtection;
2952  Section->AllocationAttributes = AllocationAttributes;
2953 
2954  /*
2955  * FIXME: This is propably not entirely correct. We can't look into
2956  * the standard FCB header because it might not be initialized yet
2957  * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2958  * standard file information is filled on first request).
2959  */
2960  Status = IoQueryFileInformation(FileObject,
2962  sizeof(FILE_STANDARD_INFORMATION),
2963  &FileInfo,
2964  &Length);
2965  if (!NT_SUCCESS(Status))
2966  {
2967  ObDereferenceObject(Section);
2968  ObDereferenceObject(FileObject);
2969  return Status;
2970  }
2971 
2972  /*
2973  * FIXME: Revise this once a locking order for file size changes is
2974  * decided
2975  */
2976  if ((UMaximumSize != NULL) && (UMaximumSize->QuadPart != 0))
2977  {
2978  MaximumSize = *UMaximumSize;
2979  }
2980  else
2981  {
2982  MaximumSize = FileInfo.EndOfFile;
2983  /* Mapping zero-sized files isn't allowed. */
2984  if (MaximumSize.QuadPart == 0)
2985  {
2986  ObDereferenceObject(Section);
2987  ObDereferenceObject(FileObject);
2989  }
2990  }
2991 
2992  if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart)
2993  {
2994  Status = IoSetInformation(FileObject,
2996  sizeof(LARGE_INTEGER),
2997  &MaximumSize);
2998  if (!NT_SUCCESS(Status))
2999  {
3000  ObDereferenceObject(Section);
3001  ObDereferenceObject(FileObject);
3003  }
3004  }
3005 
3006  if (FileObject->SectionObjectPointer == NULL ||
3007  FileObject->SectionObjectPointer->SharedCacheMap == NULL)
3008  {
3009  ObDereferenceObject(Section);
3010  ObDereferenceObject(FileObject);
3012  }
3013 
3014  /*
3015  * Lock the file
3016  */
3017  Status = MmspWaitForFileLock(FileObject);
3018  if (Status != STATUS_SUCCESS)
3019  {
3020  ObDereferenceObject(Section);
3021  ObDereferenceObject(FileObject);
3022  return(Status);
3023  }
3024 
3025  /*
3026  * If this file hasn't been mapped as a data file before then allocate a
3027  * section segment to describe the data file mapping
3028  */
3029  if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
3030  {
3033  if (Segment == NULL)
3034  {
3035  //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3036  ObDereferenceObject(Section);
3037  ObDereferenceObject(FileObject);
3038  return(STATUS_NO_MEMORY);
3039  }
3040  Section->Segment = Segment;
3041  Segment->ReferenceCount = 1;
3042  ExInitializeFastMutex(&Segment->Lock);
3043  /*
3044  * Set the lock before assigning the segment to the file object
3045  */
3046  ExAcquireFastMutex(&Segment->Lock);
3047  FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
3048 
3049  Segment->Image.FileOffset = 0;
3050  Segment->Protection = SectionPageProtection;
3051  Segment->Flags = MM_DATAFILE_SEGMENT;
3052  Segment->Image.Characteristics = 0;
3053  Segment->WriteCopy = (SectionPageProtection & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY));
3054  if (AllocationAttributes & SEC_RESERVE)
3055  {
3056  Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0;
3057  }
3058  else
3059  {
3060  Segment->RawLength.QuadPart = MaximumSize.QuadPart;
3061  Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
3062  }
3063  Segment->Image.VirtualAddress = 0;
3064  Segment->Locked = TRUE;
3066  }
3067  else
3068  {
3069  /*
3070  * If the file is already mapped as a data file then we may need
3071  * to extend it
3072  */
3073  Segment =
3074  (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
3075  DataSectionObject;
3076  Section->Segment = Segment;
3077  (void)InterlockedIncrementUL(&Segment->ReferenceCount);
3078  MmLockSectionSegment(Segment);
3079 
3080  if (MaximumSize.QuadPart > Segment->RawLength.QuadPart &&
3081  !(AllocationAttributes & SEC_RESERVE))
3082  {
3083  Segment->RawLength.QuadPart = MaximumSize.QuadPart;
3084  Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
3085  }
3086  }
3087  MmUnlockSectionSegment(Segment);
3088  Section->FileObject = FileObject;
3089  Section->MaximumSize = MaximumSize;
3090 #ifndef NEWCC
3091  CcRosReferenceCache(FileObject);
3092 #endif
3093  //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3094  *SectionObject = Section;
3095  return(STATUS_SUCCESS);
3096 }
3097 
3098 /*
3099  TODO: not that great (declaring loaders statically, having to declare all of
3100  them, having to keep them extern, etc.), will fix in the future
3101 */
3103 (
3104  IN CONST VOID * FileHeader,
3105  IN SIZE_T FileHeaderSize,
3106  IN PVOID File,
3107  OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3108  OUT PULONG Flags,
3109  IN PEXEFMT_CB_READ_FILE ReadFileCb,
3110  IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3111 );
3112 
3114 (
3115  IN CONST VOID * FileHeader,
3116  IN SIZE_T FileHeaderSize,
3117  IN PVOID File,
3118  OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3119  OUT PULONG Flags,
3120  IN PEXEFMT_CB_READ_FILE ReadFileCb,
3121  IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3122 );
3123 
3125 {
3127 #ifdef __ELF
3128  ElfFmtCreateSection
3129 #endif
3130 };
3131 
3132 static
3134 NTAPI
3136 {
3137  SIZE_T SizeOfSegments;
3138  PMM_SECTION_SEGMENT Segments;
3139 
3140  /* TODO: check for integer overflow */
3141  SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments;
3142 
3144  SizeOfSegments,
3146 
3147  if(Segments)
3148  RtlZeroMemory(Segments, SizeOfSegments);
3149 
3150  return Segments;
3151 }
3152 
3153 static
3154 NTSTATUS
3155 NTAPI
3158  IN ULONG Length,
3159  OUT PVOID * Data,
3160  OUT PVOID * AllocBase,
3161  OUT PULONG ReadSize)
3162 {
3163  NTSTATUS Status;
3165  ULONG AdjustOffset;
3166  ULONG OffsetAdjustment;
3167  ULONG BufferSize;
3168  ULONG UsedSize;
3169  PVOID Buffer;
3172 
3174 
3175  if(Length == 0)
3176  {
3177  KeBugCheck(MEMORY_MANAGEMENT);
3178  }
3179 
3180  FileOffset = *Offset;
3181 
3182  /* Negative/special offset: it cannot be used in this context */
3183  if(FileOffset.u.HighPart < 0)
3184  {
3185  KeBugCheck(MEMORY_MANAGEMENT);
3186  }
3187 
3188  AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart);
3189  OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset;
3190  FileOffset.u.LowPart = AdjustOffset;
3191 
3192  BufferSize = Length + OffsetAdjustment;
3193  BufferSize = PAGE_ROUND_UP(BufferSize);
3194 
3195  /* Flush data since we're about to perform a non-cached read */
3196  CcFlushCache(FileObject->SectionObjectPointer,
3197  &FileOffset,
3198  BufferSize,
3199  &Iosb);
3200 
3201  /*
3202  * It's ok to use paged pool, because this is a temporary buffer only used in
3203  * the loading of executables. The assumption is that MmCreateSection is
3204  * always called at low IRQLs and that these buffers don't survive a brief
3205  * initialization phase
3206  */
3208  BufferSize,
3209  'rXmM');
3210  if (!Buffer)
3211  {
3213  }
3214 
3215  UsedSize = 0;
3216 
3217  Status = MiSimpleRead(FileObject, &FileOffset, Buffer, BufferSize, TRUE, &Iosb);
3218 
3219  UsedSize = (ULONG)Iosb.Information;
3220 
3221  if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
3222  {
3223  Status = STATUS_IN_PAGE_ERROR;
3224  ASSERT(!NT_SUCCESS(Status));
3225  }
3226 
3227  if(NT_SUCCESS(Status))
3228  {
3229  *Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment);
3230  *AllocBase = Buffer;
3231  *ReadSize = UsedSize - OffsetAdjustment;
3232  }
3233  else
3234  {
3235  ExFreePoolWithTag(Buffer, 'rXmM');
3236  }
3237 
3238  return Status;
3239 }
3240 
3241 #ifdef NASSERT
3242 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3243 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3244 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3245 #else
3246 static
3247 VOID
3248 NTAPI
3250 {
3251  ULONG i;
3252 
3253  for( i = 1; i < ImageSectionObject->NrSegments; ++ i )
3254  {
3255  ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >=
3256  ImageSectionObject->Segments[i - 1].Image.VirtualAddress);
3257  }
3258 }
3259 
3260 static
3261 VOID
3262 NTAPI
3264 {
3265  ULONG i;
3266 
3267  MmspAssertSegmentsSorted(ImageSectionObject);
3268 
3269  for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3270  {
3271  ASSERT(ImageSectionObject->Segments[i].Length.QuadPart > 0);
3272 
3273  if(i > 0)
3274  {
3275  ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >=
3276  (ImageSectionObject->Segments[i - 1].Image.VirtualAddress +
3277  ImageSectionObject->Segments[i - 1].Length.QuadPart));
3278  }
3279  }
3280 }
3281 
3282 static
3283 VOID
3284 NTAPI
3286 {
3287  ULONG i;
3288 
3289  for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3290  {
3291  ASSERT((ImageSectionObject->Segments[i].Image.VirtualAddress % PAGE_SIZE) == 0);
3292  ASSERT((ImageSectionObject->Segments[i].Length.QuadPart % PAGE_SIZE) == 0);
3293  }
3294 }
3295 #endif
3296 
3297 static
3298 int
3299 __cdecl
3300 MmspCompareSegments(const void * x,
3301  const void * y)
3302 {
3303  const MM_SECTION_SEGMENT *Segment1 = (const MM_SECTION_SEGMENT *)x;
3304  const MM_SECTION_SEGMENT *Segment2 = (const MM_SECTION_SEGMENT *)y;
3305 
3306  return
3307  (Segment1->Image.VirtualAddress - Segment2->Image.VirtualAddress) >>
3308  ((sizeof(ULONG_PTR) - sizeof(int)) * 8);
3309 }
3310 
3311 /*
3312  * Ensures an image section's segments are sorted in memory
3313  */
3314 static
3315 VOID
3316 NTAPI
3318  IN ULONG Flags)
3319 {
3321  {
3322  MmspAssertSegmentsSorted(ImageSectionObject);
3323  }
3324  else
3325  {
3326  qsort(ImageSectionObject->Segments,
3327  ImageSectionObject->NrSegments,
3328  sizeof(ImageSectionObject->Segments[0]),
3330  }
3331 }
3332 
3333 
3334 /*
3335  * Ensures an image section's segments don't overlap in memory and don't have
3336  * gaps and don't have a null size. We let them map to overlapping file regions,
3337  * though - that's not necessarily an error
3338  */
3339 static
3340 BOOLEAN
3341 NTAPI
3344  IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3345  IN ULONG Flags
3346 )
3347 {
3348  ULONG i;
3349 
3351  {
3352  MmspAssertSegmentsNoOverlap(ImageSectionObject);
3353  return TRUE;
3354  }
3355 
3356  ASSERT(ImageSectionObject->NrSegments >= 1);
3357 
3358  for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3359  {
3360  if(ImageSectionObject->Segments[i].Length.QuadPart == 0)
3361  {
3362  return FALSE;
3363  }
3364 
3365  if(i > 0)
3366  {
3367  /*
3368  * TODO: relax the limitation on gaps. For example, gaps smaller than a
3369  * page could be OK (Windows seems to be OK with them), and larger gaps
3370  * could lead to image sections spanning several discontiguous regions
3371  * (NtMapViewOfSection could then refuse to map them, and they could
3372  * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3373  */
3374  if ((ImageSectionObject->Segments[i - 1].Image.VirtualAddress +
3375  ImageSectionObject->Segments[i - 1].Length.QuadPart) !=
3376  ImageSectionObject->Segments[i].Image.VirtualAddress)
3377  {
3378  return FALSE;
3379  }
3380  }
3381  }
3382 
3383  return TRUE;
3384 }
3385 
3386 /*
3387  * Merges and pads an image section's segments until they all are page-aligned
3388  * and have a size that is a multiple of the page size
3389  */
3390 static
3391 BOOLEAN
3392 NTAPI
3395  IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3396  IN ULONG Flags
3397 )
3398 {
3399  ULONG i;
3400  ULONG LastSegment;
3401  PMM_SECTION_SEGMENT EffectiveSegment;
3402 
3404  {
3405  MmspAssertSegmentsPageAligned(ImageSectionObject);
3406  return TRUE;
3407  }
3408 
3409  LastSegment = 0;
3410  EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
3411 
3412  for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3413  {
3414  /*
3415  * The first segment requires special handling
3416  */
3417  if (i == 0)
3418  {
3420  ULONG_PTR VirtualOffset;
3421 
3422  VirtualAddress = EffectiveSegment->Image.VirtualAddress;
3423 
3424  /* Round down the virtual address to the nearest page */
3425  EffectiveSegment->Image.VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
3426 
3427  /* Round up the virtual size to the nearest page */
3428  EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length.QuadPart) -
3429  EffectiveSegment->Image.VirtualAddress;
3430 
3431  /* Adjust the raw address and size */
3432  VirtualOffset = VirtualAddress - EffectiveSegment->Image.VirtualAddress;
3433 
3434  if (EffectiveSegment->Image.FileOffset < VirtualOffset)
3435  {
3436  return FALSE;
3437  }
3438 
3439  /*
3440  * Garbage in, garbage out: unaligned base addresses make the file
3441  * offset point in curious and odd places, but that's what we were
3442  * asked for
3443  */
3444  EffectiveSegment->Image.FileOffset -= VirtualOffset;
3445  EffectiveSegment->RawLength.QuadPart += VirtualOffset;
3446  }
3447  else
3448  {
3449  PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
3450  ULONG_PTR EndOfEffectiveSegment;
3451 
3452  EndOfEffectiveSegment = (ULONG_PTR)(EffectiveSegment->Image.VirtualAddress + EffectiveSegment->Length.QuadPart);
3453  ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
3454 
3455  /*
3456  * The current segment begins exactly where the current effective
3457  * segment ended, therefore beginning a new effective segment
3458  */
3459  if (EndOfEffectiveSegment == Segment->Image.VirtualAddress)
3460  {
3461  LastSegment ++;
3462  ASSERT(LastSegment <= i);
3463  ASSERT(LastSegment < ImageSectionObject->NrSegments);
3464 
3465  EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
3466 
3467  if (LastSegment != i)
3468  {
3469  /*
3470  * Copy the current segment. If necessary, the effective segment
3471  * will be expanded later
3472  */
3473  *EffectiveSegment = *Segment;
3474  }
3475 
3476  /*
3477  * Page-align the virtual size. We know for sure the virtual address
3478  * already is
3479  */
3480  ASSERT((EffectiveSegment->Image.VirtualAddress % PAGE_SIZE) == 0);
3481  EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(EffectiveSegment->Length.QuadPart);
3482  }
3483  /*
3484  * The current segment is still part of the current effective segment:
3485  * extend the effective segment to reflect this
3486  */
3487  else if (EndOfEffectiveSegment > Segment->Image.VirtualAddress)
3488  {
3489  static const ULONG FlagsToProtection[16] =
3490  {
3491  PAGE_NOACCESS,
3492  PAGE_READONLY,
3506  PAGE_EXECUTE_WRITECOPY
3507  };
3508 
3509  unsigned ProtectionFlags;
3510 
3511  /*
3512  * Extend the file size
3513  */
3514 
3515  /* Unaligned segments must be contiguous within the file */
3516  if (Segment->Image.FileOffset != (EffectiveSegment->Image.FileOffset +
3517  EffectiveSegment->RawLength.QuadPart))
3518  {
3519  return FALSE;
3520  }
3521 
3522  EffectiveSegment->RawLength.QuadPart += Segment->RawLength.QuadPart;
3523 
3524  /*
3525  * Extend the virtual size
3526  */
3527  ASSERT(PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) >= EndOfEffectiveSegment);
3528 
3529  EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) -
3530  EffectiveSegment->Image.VirtualAddress;
3531 
3532  /*
3533  * Merge the protection
3534  */
3535  EffectiveSegment->Protection |= Segment->Protection;
3536 
3537  /* Clean up redundance */
3538  ProtectionFlags = 0;
3539 
3540  if(EffectiveSegment->Protection & PAGE_IS_READABLE)
3541  ProtectionFlags |= 1 << 0;
3542 
3543  if(EffectiveSegment->Protection & PAGE_IS_WRITABLE)
3544  ProtectionFlags |= 1 << 1;
3545 
3546  if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE)
3547  ProtectionFlags |= 1 << 2;
3548 
3549  if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3550  ProtectionFlags |= 1 << 3;
3551 
3552  ASSERT(ProtectionFlags < 16);
3553  EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags];
3554 
3555  /* If a segment was required to be shared and cannot, fail */
3556  if(!(Segment->Protection & PAGE_IS_WRITECOPY) &&
3557  EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3558  {
3559  return FALSE;
3560  }
3561  }
3562  /*
3563  * We assume no holes between segments at this point
3564  */
3565  else
3566  {
3567  KeBugCheck(MEMORY_MANAGEMENT);
3568  }
3569  }
3570  }
3571  ImageSectionObject->NrSegments = LastSegment + 1;
3572 
3573  return TRUE;
3574 }
3575 
3576 NTSTATUS
3578  PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3579 {
3581  PVOID FileHeader;
3582  PVOID FileHeaderBuffer;
3583  ULONG FileHeaderSize;
3584  ULONG Flags;
3585  ULONG OldNrSegments;
3586  NTSTATUS Status;
3587  ULONG i;
3588 
3589  /*
3590  * Read the beginning of the file (2 pages). Should be enough to contain
3591  * all (or most) of the headers
3592  */
3593  Offset.QuadPart = 0;
3594 
3595  Status = ExeFmtpReadFile (FileObject,
3596  &Offset,
3597  PAGE_SIZE * 2,
3598  &FileHeader,
3599  &FileHeaderBuffer,
3600  &FileHeaderSize);
3601 
3602  if (!NT_SUCCESS(Status))
3603  return Status;
3604 
3605  if (FileHeaderSize == 0)
3606  {
3607  ExFreePool(FileHeaderBuffer);
3608  return STATUS_UNSUCCESSFUL;
3609  }
3610 
3611  /*
3612  * Look for a loader that can handle this executable
3613  */
3614  for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i)
3615  {
3616  RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject));
3617  Flags = 0;
3618 
3619  Status = ExeFmtpLoaders[i](FileHeader,
3620  FileHeaderSize,
3621  FileObject,
3622  ImageSectionObject,
3623  &Flags,
3626 
3627  if (!NT_SUCCESS(Status))
3628  {
3629  if (ImageSectionObject->Segments)
3630  {
3631  ExFreePool(ImageSectionObject->Segments);
3632  ImageSectionObject->Segments = NULL;
3633  }
3634  }
3635 
3636  if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3637  break;
3638  }
3639 
3640  ExFreePoolWithTag(FileHeaderBuffer, 'rXmM');
3641 
3642  /*
3643  * No loader handled the format
3644  */
3645  if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3646  {
3647  Status = STATUS_INVALID_IMAGE_NOT_MZ;
3648  ASSERT(!NT_SUCCESS(Status));
3649  }
3650 
3651  if (!NT_SUCCESS(Status))
3652  return Status;
3653 
3654  ASSERT(ImageSectionObject->Segments != NULL);
3655 
3656  /*
3657  * Some defaults
3658  */
3659  /* FIXME? are these values platform-dependent? */
3660  if (ImageSectionObject->ImageInformation.MaximumStackSize == 0)
3661  ImageSectionObject->ImageInformation.MaximumStackSize = 0x40000;
3662 
3663  if(ImageSectionObject->ImageInformation.CommittedStackSize == 0)
3664  ImageSectionObject->ImageInformation.CommittedStackSize = 0x1000;
3665 
3666  if(ImageSectionObject->BasedAddress == NULL)
3667  {
3668  if(ImageSectionObject->ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL)
3669  ImageSectionObject->BasedAddress = (PVOID)0x10000000;
3670  else
3671  ImageSectionObject->BasedAddress = (PVOID)0x00400000;
3672  }
3673 
3674  /*
3675  * And now the fun part: fixing the segments
3676  */
3677 
3678  /* Sort them by virtual address */
3679  MmspSortSegments(ImageSectionObject, Flags);
3680 
3681  /* Ensure they don't overlap in memory */
3682  if (!MmspCheckSegmentBounds(ImageSectionObject, Flags))
3684 
3685  /* Ensure they are aligned */
3686  OldNrSegments = ImageSectionObject->NrSegments;
3687 
3688  if (!MmspPageAlignSegments(ImageSectionObject, Flags))
3690 
3691  /* Trim them if the alignment phase merged some of them */
3692  if (ImageSectionObject->NrSegments < OldNrSegments)
3693  {
3694  PMM_SECTION_SEGMENT Segments;
3695  SIZE_T SizeOfSegments;
3696 
3697  SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments;
3698 
3699  Segments = ExAllocatePoolWithTag(PagedPool,
3700  SizeOfSegments,
3702 
3703  if (Segments == NULL)
3705 
3706  RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments);
3707  ExFreePool(ImageSectionObject->Segments);
3708  ImageSectionObject->Segments = Segments;
3709  }
3710 
3711  /* And finish their initialization */
3712  for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3713  {
3714  ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock);
3715  ImageSectionObject->Segments[i].ReferenceCount = 1;
3716  MiInitializeSectionPageTable(&ImageSectionObject->Segments[i]);
3717  }
3718 
3719  ASSERT(NT_SUCCESS(Status));
3720  return Status;
3721 }
3722 
3723 NTSTATUS
3727  PLARGE_INTEGER UMaximumSize,
3728  ULONG SectionPageProtection,
3731 {
3732  PROS_SECTION_OBJECT Section;
3733  NTSTATUS Status;
3734  PMM_SECTION_SEGMENT SectionSegments;
3735  PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3736  ULONG i;
3737 
3738  if (FileObject == NULL)
3740 
3741 #ifndef NEWCC
3742  if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
3743  {
3744  DPRINT1("Denying section creation due to missing cache initialization\n");
3746  }
3747 #endif
3748 
3749  /*
3750  * Create the section
3751  */
3752  Status = ObCreateObject (ExGetPreviousMode(),
3753  MmSectionObjectType,
3754  ObjectAttributes,
3756  NULL,
3757  sizeof(ROS_SECTION_OBJECT),
3758  0,
3759  0,
3760  (PVOID*)(PVOID)&Section);
3761  if (!NT_SUCCESS(Status))
3762  {
3763  ObDereferenceObject(FileObject);
3764  return(Status);
3765  }
3766 
3767  /*
3768  * Initialize it
3769  */
3770  RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
3771  Section->Type = 'SC';
3772  Section->Size = 'TN';
3773  Section->SectionPageProtection = SectionPageProtection;
3774  Section->AllocationAttributes = AllocationAttributes;
3775 
3776  if (FileObject->SectionObjectPointer->ImageSectionObject == NULL)
3777  {
3778  NTSTATUS StatusExeFmt;
3779 
3781  if (ImageSectionObject == NULL)
3782  {
3783  ObDereferenceObject(FileObject);
3784  ObDereferenceObject(Section);
3785  return(STATUS_NO_MEMORY);
3786  }
3787 
3788  RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
3789 
3790  StatusExeFmt = ExeFmtpCreateImageSection(FileObject, ImageSectionObject);
3791 
3792  if (!NT_SUCCESS(StatusExeFmt))
3793  {
3794  if(ImageSectionObject->Segments != NULL)
3795  ExFreePool(ImageSectionObject->Segments);
3796 
3797  /*
3798  * If image file is empty, then return that the file is invalid for section
3799  */
3800  Status = StatusExeFmt;
3801  if (StatusExeFmt == STATUS_END_OF_FILE)
3802  {
3804  }
3805 
3806  ExFreePoolWithTag(ImageSectionObject, TAG_MM_SECTION_SEGMENT);
3807  ObDereferenceObject(Section);
3808  ObDereferenceObject(FileObject);
3809  return(Status);
3810  }
3811 
3812  Section->ImageSection = ImageSectionObject;
3813  ASSERT(ImageSectionObject->Segments);
3814 
3815  /*
3816  * Lock the file
3817  */
3818  Status = MmspWaitForFileLock(FileObject);
3819  if (!NT_SUCCESS(Status))
3820  {
3821  ExFreePool(ImageSectionObject->Segments);
3822  ExFreePool(ImageSectionObject);
3823  ObDereferenceObject(Section);
3824  ObDereferenceObject(FileObject);
3825  return(Status);
3826  }
3827 
3828  if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject,
3829  ImageSectionObject, NULL))
3830  {
3831  /*
3832  * An other thread has initialized the same image in the background
3833  */
3834  ExFreePool(ImageSectionObject->Segments);
3835  ExFreePool(ImageSectionObject);
3836  ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3837  Section->ImageSection = ImageSectionObject;
3838  SectionSegments = ImageSectionObject->Segments;
3839 
3840  for (i = 0; i < ImageSectionObject->NrSegments; i++)
3841  {
3842  (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3843  }
3844  }
3845 
3846  Status = StatusExeFmt;
3847  }
3848  else
3849  {
3850  /*
3851  * Lock the file
3852  */
3853  Status = MmspWaitForFileLock(FileObject);
3854  if (Status != STATUS_SUCCESS)
3855  {
3856  ObDereferenceObject(Section);
3857  ObDereferenceObject(FileObject);
3858  return(Status);
3859  }
3860 
3861  ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3862  Section->ImageSection = ImageSectionObject;
3863  SectionSegments = ImageSectionObject->Segments;
3864 
3865  /*
3866  * Otherwise just reference all the section segments
3867  */
3868  for (i = 0; i < ImageSectionObject->NrSegments; i++)
3869  {
3870  (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3871  }
3872 
3873  Status = STATUS_SUCCESS;
3874  }
3875  Section->FileObject = FileObject;
3876 #ifndef NEWCC
3877  CcRosReferenceCache(FileObject);
3878 #endif
3879  //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3880  *SectionObject = Section;
3881  return(Status);
3882 }
3883 
3884 
3885 
3886 static NTSTATUS
3888  PROS_SECTION_OBJECT Section,
3890  PVOID* BaseAddress,
3891  SIZE_T ViewSize,
3892  ULONG Protect,
3893  ULONG ViewOffset,
3895 {
3896  PMEMORY_AREA MArea;
3897  NTSTATUS Status;
3898  ULONG Granularity;
3899 
3900  if (Segment->WriteCopy)
3901  {
3902  /* We have to do this because the not present fault
3903  * and access fault handlers depend on the protection
3904  * that should be granted AFTER the COW fault takes
3905  * place to be in Region->Protect. The not present fault
3906  * handler changes this to the correct protection for COW when
3907  * mapping the pages into the process's address space. If a COW
3908  * fault takes place, the access fault handler sets the page protection
3909  * to these values for the newly copied pages
3910  */
3911  if (Protect == PAGE_WRITECOPY)
3912  Protect = PAGE_READWRITE;
3913  else if (Protect == PAGE_EXECUTE_WRITECOPY)
3914  Protect = PAGE_EXECUTE_READWRITE;
3915  }
3916 
3917  if (*BaseAddress == NULL)
3918  Granularity = MM_ALLOCATION_GRANULARITY;
3919  else
3920  Granularity = PAGE_SIZE;
3921 
3922 #ifdef NEWCC
3923  if (Segment->Flags & MM_DATAFILE_SEGMENT)
3924  {
3926  FileOffset.QuadPart = ViewOffset;
3927  ObReferenceObject(Section);
3928  return _MiMapViewOfSegment(AddressSpace, Segment, BaseAddress, ViewSize, Protect, &FileOffset, AllocationType, __FILE__, __LINE__);
3929  }
3930 #endif
3931  Status = MmCreateMemoryArea(AddressSpace,
3933  BaseAddress,
3934  ViewSize,
3935  Protect,
3936  &MArea,
3937  AllocationType,
3938  Granularity);
3939  if (!NT_SUCCESS(Status))
3940  {
3941  DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3942  (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
3943  return(Status);
3944  }
3945 
3946  ObReferenceObject((PVOID)Section);
3947 
3948  MArea->Data.SectionData.Segment = Segment;
3949  MArea->Data.SectionData.Section = Section;
3950  MArea->Data.SectionData.ViewOffset.QuadPart = ViewOffset;
3951  if (Section->AllocationAttributes & SEC_IMAGE)
3952  {
3954  }
3955 
3956  MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
3957  ViewSize, 0, Protect);
3958 
3959  return(STATUS_SUCCESS);
3960 }
3961 
3962 
3963 static VOID
3965  PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
3966 {
3967  ULONG_PTR Entry;
3968 #ifndef NEWCC
3970  PROS_SHARED_CACHE_MAP SharedCacheMap;
3971 #endif
3973  SWAPENTRY SavedSwapEntry;
3974  PROS_SECTION_OBJECT Section;
3978 
3979  AddressSpace = (PMMSUPPORT)Context;
3980  Process = MmGetAddressSpaceOwner(AddressSpace);
3981 
3982  Address = (PVOID)PAGE_ROUND_DOWN(Address);
3983 
3984  Offset.QuadPart = ((ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)) +
3985  MemoryArea->Data.SectionData.ViewOffset.QuadPart;
3986 
3987  Section = MemoryArea->Data.SectionData.Section;
3988  Segment = MemoryArea->Data.SectionData.Segment;
3989 
3990  Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
3991  while (Entry && MM_IS_WAIT_PTE(Entry))
3992  {
3993  MmUnlockSectionSegment(Segment);
3994  MmUnlockAddressSpace(AddressSpace);
3995 
3997 
3998  MmLockAddressSpace(AddressSpace);
3999  MmLockSectionSegment(Segment);
4000  Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
4001  }
4002 
4003  /*
4004  * For a dirty, datafile, non-private page mark it as dirty in the
4005  * cache manager.
4006  */
4007  if (Segment->Flags & MM_DATAFILE_SEGMENT)
4008  {
4009  if (Page == PFN_FROM_SSE(Entry) && Dirty)
4010  {
4011 #ifndef NEWCC
4012  FileObject = MemoryArea->Data.SectionData.Section->FileObject;
4013  SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
4014  CcRosMarkDirtyFile(SharedCacheMap, Offset.QuadPart + Segment->Image.FileOffset);
4015 #endif
4016  ASSERT(SwapEntry == 0);
4017  }
4018  }
4019 
4020  if (SwapEntry != 0)
4021  {
4022  /*
4023  * Sanity check
4024  */
4025  if (Segment->Flags & MM_PAGEFILE_SEGMENT)
4026  {
4027  DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4028  KeBugCheck(MEMORY_MANAGEMENT);
4029  }
4030  MmFreeSwapPage(SwapEntry);
4031  }
4032  else if (Page != 0)
4033  {
4034  if (IS_SWAP_FROM_SSE(Entry) ||
4035  Page != PFN_FROM_SSE(Entry))
4036  {
4037  /*
4038  * Sanity check
4039  */
4040  if (Segment->Flags & MM_PAGEFILE_SEGMENT)
4041  {
4042  DPRINT1("Found a private page in a pagefile section.\n");
4043  KeBugCheck(MEMORY_MANAGEMENT);
4044  }
4045  /*
4046  * Just dereference private pages
4047  */
4048  SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
4049  if (SavedSwapEntry != 0)
4050  {
4051  MmFreeSwapPage(SavedSwapEntry);
4052  MmSetSavedSwapEntryPage(Page, 0);
4053  }
4054  MmDeleteRmap(Page, Process, Address);
4056  }
4057  else
4058  {
4059  MmDeleteRmap(Page, Process, Address);
4060  MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, Dirty, FALSE, NULL);
4061  }
4062  }
4063 }
4064 
4065 static NTSTATUS
4068 {
4069  NTSTATUS Status;
4071  PROS_SECTION_OBJECT Section;
4073  PLIST_ENTRY CurrentEntry;
4074  PMM_REGION CurrentRegion;
4075  PLIST_ENTRY RegionListHead;
4076 
4077  MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4078  BaseAddress);
4079  if (MemoryArea == NULL)
4080  {
4081  return(STATUS_UNSUCCESSFUL);
4082  }
4083 
4084  Section = MemoryArea->Data.SectionData.Section;
4085  Segment = MemoryArea->Data.SectionData.Segment;
4086 
4087 #ifdef NEWCC
4088  if (Segment->Flags & MM_DATAFILE_SEGMENT)
4089  {
4090  MmUnlockAddressSpace(AddressSpace);
4091  Status = MmUnmapViewOfCacheSegment(AddressSpace, BaseAddress);
4092  MmLockAddressSpace(AddressSpace);
4093 
4094  return Status;
4095  }
4096 #endif
4097 
4098  MemoryArea->DeleteInProgress = TRUE;
4099 
4100  MmLockSectionSegment(Segment);
4101 
4102  RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
4103  while (!IsListEmpty(RegionListHead))
4104  {
4105  CurrentEntry = RemoveHeadList(RegionListHead);
4106  CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
4107  ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION);
4108  }
4109 
4111  {
4112  Status = MmFreeMemoryArea(AddressSpace,
4113  MemoryArea,
4114  NULL,
4115  NULL);
4116  }
4117  else
4118  {
4119  Status = MmFreeMemoryArea(AddressSpace,
4120  MemoryArea,
4122  AddressSpace);
4123  }
4124  MmUnlockSectionSegment(Segment);
4125  ObDereferenceObject(Section);
4126  return(Status);
4127 }
4128 
4129 NTSTATUS
4130 NTAPI
4133  IN BOOLEAN SkipDebuggerNotify)
4134 {
4135  NTSTATUS Status;
4138  PROS_SECTION_OBJECT Section;
4139  PVOID ImageBaseAddress = 0;
4140 
4141  DPRINT("Opening memory area Process %p BaseAddress %p\n",
4142  Process, BaseAddress);
4143 
4144  ASSERT(Process);
4145 
4146  AddressSpace = Process ? &Process->Vm : MmGetKernelAddressSpace();
4147 
4148  MmLockAddressSpace(AddressSpace);
4149  MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4150  BaseAddress);
4151  if (MemoryArea == NULL ||
4152  ((MemoryArea->Type != MEMORY_AREA_SECTION_VIEW) &&
4153  (MemoryArea->Type != MEMORY_AREA_CACHE)) ||
4154  MemoryArea->DeleteInProgress)
4155  {
4156  if (MemoryArea) ASSERT(MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3);
4157  MmUnlockAddressSpace(AddressSpace);
4158  return STATUS_NOT_MAPPED_VIEW;
4159  }
4160 
4161  Section = MemoryArea->Data.SectionData.Section;
4162 
4163  if ((Section != NULL) && (Section->AllocationAttributes & SEC_IMAGE))
4164  {
4165  ULONG i;
4166  ULONG NrSegments;
4167  PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4168  PMM_SECTION_SEGMENT SectionSegments;
4170 
4171  Segment = MemoryArea->Data.SectionData.Segment;
4172  ImageSectionObject = Section->ImageSection;
4173  SectionSegments = ImageSectionObject->Segments;
4174  NrSegments = ImageSectionObject->NrSegments;
4175 
4176  MemoryArea->DeleteInProgress = TRUE;
4177 
4178  /* Search for the current segment within the section segments
4179  * and calculate the image base address */
4180  for (i = 0; i < NrSegments; i++)
4181  {
4182  if (Segment == &SectionSegments[i])
4183  {
4184  ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].Image.VirtualAddress;
4185  break;
4186  }
4187  }
4188  if (i >= NrSegments)
4189  {
4190  KeBugCheck(MEMORY_MANAGEMENT);
4191  }
4192 
4193  for (i = 0; i < NrSegments; i++)
4194  {
4195  PVOID SBaseAddress = (PVOID)
4196  ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress);
4197 
4198  Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
4199  if (!NT_SUCCESS(Status))
4200  {
4201  DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4202  SBaseAddress, Process, Status);
4203  ASSERT(NT_SUCCESS(Status));
4204  }
4205  }
4206  }
4207  else
4208  {
4209  Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
4210  if (!NT_SUCCESS(Status))
4211  {
4212  DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4213  BaseAddress, Process, Status);
4214  ASSERT(NT_SUCCESS(Status));
4215  }
4216  }
4217 
4218  MmUnlockAddressSpace(AddressSpace);
4219 
4220  /* Notify debugger */
4221  if (ImageBaseAddress && !SkipDebuggerNotify) DbgkUnMapViewOfSection(ImageBaseAddress);
4222 
4223  return(STATUS_SUCCESS);
4224 }
4225 
4226 
4227 
4228 
4251 NTSTATUS
4252 NTAPI
4254  _In_ HANDLE SectionHandle,
4255  _In_ SECTION_INFORMATION_CLASS SectionInformationClass,
4256  _Out_ PVOID SectionInformation,
4257  _In_ SIZE_T SectionInformationLength,
4259 {
4260  PSECTION Section;
4262  NTSTATUS Status;
4263  PAGED_CODE();
4264 
4265  PreviousMode = ExGetPreviousMode();
4266  if (PreviousMode != KernelMode)
4267  {
4268  _SEH2_TRY
4269  {
4270  ProbeForWrite(SectionInformation,
4271  SectionInformationLength,
4272  __alignof(ULONG));
4273  if (ResultLength != NULL)
4274  {
4275  ProbeForWrite(ResultLength,
4276  sizeof(*ResultLength),
4277  __alignof(SIZE_T));
4278  }
4279  }
4281  {
4283  }
4284  _SEH2_END;
4285  }
4286 
4287  if (SectionInformationClass == SectionBasicInformation)
4288  {
4289  if (SectionInformationLength < sizeof(SECTION_BASIC_INFORMATION))
4290  {
4292  }
4293  }
4294  else if (SectionInformationClass == SectionImageInformation)
4295  {
4296  if (SectionInformationLength < sizeof(SECTION_IMAGE_INFORMATION))
4297  {
4299  }
4300  }
4301  else
4302  {
4304  }
4305 
4306  Status = ObReferenceObjectByHandle(SectionHandle,
4307  SECTION_QUERY,
4308  MmSectionObjectType,
4309  PreviousMode,
4310  (PVOID*)(PVOID)&Section,
4311  NULL);
4312  if (!NT_SUCCESS(Status))
4313  {
4314  DPRINT1("Failed to reference section: 0x%lx\n", Status);
4315  return Status;
4316  }
4317 
4318  if (MiIsRosSectionObject(Section))
4319  {
4320  PROS_SECTION_OBJECT RosSection = (PROS_SECTION_OBJECT)Section;
4321 
4322  switch (SectionInformationClass)
4323  {
4325  {
4326  PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
4327 
4328  _SEH2_TRY
4329  {
4330  Sbi->Attributes = RosSection->AllocationAttributes;
4331  if (RosSection->AllocationAttributes & SEC_IMAGE)
4332  {
4333  Sbi->BaseAddress = 0;
4334  Sbi->Size.QuadPart = 0;
4335  }
4336  else
4337  {
4338  Sbi->BaseAddress = (PVOID)RosSection->Segment->Image.VirtualAddress;
4339  Sbi->Size.QuadPart = RosSection->Segment->Length.QuadPart;
4340  }
4341 
4342  if (ResultLength != NULL)
4343  {
4344  *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
4345  }
4346  Status = STATUS_SUCCESS;
4347  }
4349  {
4350  Status = _SEH2_GetExceptionCode();
4351  }
4352  _SEH2_END;
4353 
4354  break;
4355  }
4356 
4358  {
4359  PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
4360 
4361  _SEH2_TRY
4362  {
4363  if (RosSection->AllocationAttributes & SEC_IMAGE)
4364  {
4365  PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4366  ImageSectionObject = RosSection->ImageSection;
4367 
4368  *Sii = ImageSectionObject->ImageInformation;
4369  }
4370 
4371  if (ResultLength != NULL)
4372  {
4373  *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
4374  }
4375  Status = STATUS_SUCCESS;
4376  }
4378  {
4379  Status = _SEH2_GetExceptionCode();
4380  }
4381  _SEH2_END;
4382 
4383  break;
4384  }
4385  }
4386  }
4387  else
4388  {
4389  switch(SectionInformationClass)
4390  {
4392  {
4394 
4395  Sbi.Size = Section->SizeOfSection;
4396  Sbi.BaseAddress = (PVOID)Section->Address.StartingVpn;
4397 
4398  Sbi.Attributes = 0;
4399  if (Section->u.Flags.Image)
4400  Sbi.Attributes |= SEC_IMAGE;
4401  if (Section->u.Flags.Commit)
4402  Sbi.Attributes |= SEC_COMMIT;
4403  if (Section->u.Flags.Reserve)
4404  Sbi.Attributes |= SEC_RESERVE;
4405  if (Section->u.Flags.File)
4406  Sbi.Attributes |= SEC_FILE;
4407  if (Section->u.Flags.Image)
4408  Sbi.Attributes |= SEC_IMAGE;
4409 
4410  /* FIXME : Complete/test the list of flags passed back from NtCreateSection */
4411 
4412  _SEH2_TRY
4413  {
4414  *((SECTION_BASIC_INFORMATION*)SectionInformation) = Sbi;
4415  if (ResultLength)
4416  *ResultLength = sizeof(Sbi);
4417  }
4419  {
4420  Status = _SEH2_GetExceptionCode();
4421  }
4422  _SEH2_END;
4423  break;
4424  }
4426  {
4427  if (!Section->u.Flags.Image)
4428  {
4429  Status = STATUS_SECTION_NOT_IMAGE;
4430  }
4431  else
4432  {
4433  /* Currently not supported */
4434  ASSERT(FALSE);
4435  }
4436  break;
4437  }
4438  }
4439  }
4440 
4441  ObDereferenceObject(Section);
4442 
4443  return(Status);
4444 }
4445 
4446 /**********************************************************************
4447  * NAME EXPORTED
4448  * MmMapViewOfSection
4449  *
4450  * DESCRIPTION
4451  * Maps a view of a section into the virtual address space of a
4452  * process.
4453  *
4454  * ARGUMENTS
4455  * Section
4456  * Pointer to the section object.
4457  *
4458  * ProcessHandle
4459  * Pointer to the process.
4460  *
4461  * BaseAddress
4462  * Desired base address (or NULL) on entry;
4463  * Actual base address of the view on exit.
4464  *
4465  * ZeroBits
4466  * Number of high order address bits that must be zero.
4467  *
4468  * CommitSize
4469  * Size in bytes of the initially committed section of
4470  * the view.
4471  *
4472  * SectionOffset
4473  * Offset in bytes from the beginning of the section
4474  * to the beginning of the view.
4475  *
4476  * ViewSize
4477  * Desired length of map (or zero to map all) on entry
4478  * Actual length mapped on exit.
4479  *
4480  * InheritDisposition
4481  * Specified how the view is to be shared with
4482  * child processes.
4483  *
4484  * AllocationType
4485  * Type of allocation for the pages.
4486  *
4487  * Protect
4488  * Protection for the committed region of the view.
4489  *
4490  * RETURN VALUE
4491  * Status.
4492  *
4493  * @implemented
4494  */
4505  IN ULONG Protect)
4506 {
4507  PROS_SECTION_OBJECT Section;
4509  ULONG ViewOffset;
4511  BOOLEAN NotAtBase = FALSE;
4512 
4513  if (MiIsRosSectionObject(SectionObject) == FALSE)
4514  {
4515  DPRINT("Mapping ARM3 section into %s\n", Process->ImageFileName);
4516  return MmMapViewOfArm3Section(SectionObject,
4517  Process,
4518  BaseAddress,
4519  ZeroBits,
4520  CommitSize,
4521  SectionOffset,
4522  ViewSize,
4523  InheritDisposition,
4524  AllocationType,
4525  Protect);
4526  }
4527 
4528  ASSERT(Process);
4529 
4530  if (!Protect || Protect & ~PAGE_FLAGS_VALID_FOR_SECTION)
4531  {
4533  }
4534 
4535  /* FIXME: We should keep this, but it would break code checking equality */
4536  Protect &= ~PAGE_NOCACHE;
4537 
4538  Section = (PROS_SECTION_OBJECT)SectionObject;
4539  AddressSpace = &Process->Vm;
4540 
4541  AllocationType |= (Section->AllocationAttributes & SEC_NO_CHANGE);
4542 
4543  MmLockAddressSpace(AddressSpace);
4544 
4545  if (Section->AllocationAttributes & SEC_IMAGE)
4546  {
4547  ULONG i;
4548  ULONG NrSegments;
4549  ULONG_PTR ImageBase;
4550  SIZE_T ImageSize;
4551  PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4552  PMM_SECTION_SEGMENT SectionSegments;
4553 
4554  ImageSectionObject = Section->ImageSection;
4555  SectionSegments = ImageSectionObject->Segments;
4556  NrSegments = ImageSectionObject->NrSegments;
4557 
4558  ImageBase = (ULONG_PTR)*BaseAddress;
4559  if (ImageBase == 0)
4560  {
4561  ImageBase = (ULONG_PTR)ImageSectionObject->BasedAddress;
4562  }
4563 
4564  ImageSize = 0;
4565  for (i = 0; i < NrSegments; i++)
4566  {
4567  ULONG_PTR MaxExtent;
4568  MaxExtent = (ULONG_PTR)(SectionSegments[i].Image.VirtualAddress +
4569  SectionSegments[i].Length.QuadPart);
4570  ImageSize = max(ImageSize, MaxExtent);
4571  }
4572 
4573  ImageSectionObject->ImageInformation.ImageFileSize = (ULONG)ImageSize;
4574 
4575  /* Check for an illegal base address */
4576  if (((ImageBase + ImageSize) > (ULONG_PTR)MmHighestUserAddress) ||
4577  ((ImageBase + ImageSize) < ImageSize))
4578  {
4579  ASSERT(*BaseAddress == NULL);
4580  ImageBase = ALIGN_DOWN_BY((ULONG_PTR)MmHighestUserAddress - ImageSize,
4582  NotAtBase = TRUE;
4583  }
4584  else if (ImageBase != ALIGN_DOWN_BY(ImageBase, MM_VIRTMEM_GRANULARITY))
4585  {
4586  ASSERT(*BaseAddress == NULL);
4587  ImageBase = ALIGN_DOWN_BY(ImageBase, MM_VIRTMEM_GRANULARITY);
4588  NotAtBase = TRUE;
4589  }
4590 
4591  /* Check there is enough space to map the section at that point. */
4592  if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
4593  PAGE_ROUND_UP(ImageSize)) != NULL)
4594  {
4595  /* Fail if the user requested a fixed base address. */
4596  if ((*BaseAddress) != NULL)
4597  {
4598  MmUnlockAddressSpace(AddressSpace);
4600  }
4601  /* Otherwise find a gap to map the image. */
4602  ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), MM_VIRTMEM_GRANULARITY, FALSE);
4603  if (ImageBase == 0)
4604  {
4605  MmUnlockAddressSpace(AddressSpace);
4607  }
4608  /* Remember that we loaded image at a different base address */
4609  NotAtBase = TRUE;
4610  }
4611 
4612  for (i = 0; i < NrSegments; i++)
4613  {
4614  PVOID SBaseAddress = (PVOID)
4615  ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress);
4616  MmLockSectionSegment(&SectionSegments[i]);
4617  Status = MmMapViewOfSegment(AddressSpace,
4618  Section,
4619  &SectionSegments[i],
4620  &SBaseAddress,
4621  SectionSegments[i].Length.LowPart,
4622  SectionSegments[i].Protection,
4623  0,
4624  0);
4625  MmUnlockSectionSegment(&SectionSegments[i]);
4626  if (!NT_SUCCESS(Status))
4627  {
4628  MmUnlockAddressSpace(AddressSpace);
4629  return(Status);
4630  }
4631  }
4632 
4633  *BaseAddress = (PVOID)ImageBase;
4634  *ViewSize = ImageSize;
4635  }
4636  else
4637  {
4638  /* check for write access */
4639  if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) &&
4641  {
4642  MmUnlockAddressSpace(AddressSpace);
4644  }
4645  /* check for read access */
4648  {
4649  MmUnlockAddressSpace(AddressSpace);
4651  }
4652  /* check for execute access */
4655  {
4656  MmUnlockAddressSpace(AddressSpace);
4658  }
4659 
4660  if (SectionOffset == NULL)
4661  {
4662  ViewOffset = 0;
4663  }
4664  else
4665  {
4666  ViewOffset = SectionOffset->u.LowPart;
4667  }
4668 
4669  if ((ViewOffset % PAGE_SIZE) != 0)
4670  {
4671  MmUnlockAddressSpace(AddressSpace);
4672  return(STATUS_MAPPED_ALIGNMENT);
4673  }
4674 
4675  if ((*ViewSize) == 0)
4676  {
4677  (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4678  }
4679  else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
4680  {
4681  (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4682  }
4683 
4684  *ViewSize = PAGE_ROUND_UP(*ViewSize);
4685 
4686  MmLockSectionSegment(Section->Segment);
4687  Status = MmMapViewOfSegment(AddressSpace,
4688  Section,
4689  Section->Segment,
4690  BaseAddress,
4691  *ViewSize,
4692  Protect,
4693  ViewOffset,
4694  AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE));
4695  MmUnlockSectionSegment(Section->Segment);
4696  if (!NT_SUCCESS(Status))
4697  {
4698  MmUnlockAddressSpace(AddressSpace);
4699  return(Status);
4700  }
4701  }
4702 
4703  MmUnlockAddressSpace(AddressSpace);
4704  ASSERT(*BaseAddress == ALIGN_DOWN_POINTER_BY(*BaseAddress, MM_VIRTMEM_GRANULARITY));
4705 
4706  if (NotAtBase)
4707  Status = STATUS_IMAGE_NOT_AT_BASE;
4708  else
4709  Status = STATUS_SUCCESS;
4710 
4711  return Status;
4712 }
4713 
4714 /*
4715  * @unimplemented
4716  */
4717 BOOLEAN NTAPI
4720 {
4721  /* Check whether an ImageSectionObject exists */
4722  if (SectionObjectPointer->ImageSectionObject != NULL)
4723  {
4724  DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4725  return FALSE;
4726  }
4727 
4728  if (SectionObjectPointer->DataSectionObject != NULL)
4729  {
4731 
4732  Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->
4733  DataSectionObject;
4734 
4735  if (Segment->ReferenceCount != 0)
4736  {
4737 #ifdef NEWCC
4739  CcpLock();
4740  if (SectionObjectPointer->SharedCacheMap && (Segment->ReferenceCount > CcpCountCacheSections((PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap)))
4741  {
4742  CcpUnlock();
4743  /* Check size of file */
4744  if (SectionObjectPointer->SharedCacheMap)
4745  {
4746  if (!CcGetFileSizes(Segment->FileObject, &FileSizes))
4747  {
4748  return FALSE;
4749  }
4750 
4751  if (NewFileSize->QuadPart <= FileSizes.FileSize.QuadPart)
4752  {
4753  return FALSE;
4754  }
4755  }
4756  }
4757  else
4758  CcpUnlock();
4759 #else
4760  /* Check size of file */
4761  if (SectionObjectPointer->SharedCacheMap)
4762  {
4763  PROS_SHARED_CACHE_MAP SharedCacheMap = SectionObjectPointer->SharedCacheMap;
4764  if (NewFileSize->QuadPart <= SharedCacheMap->FileSize.QuadPart)
4765  {
4766  return FALSE;
4767  }
4768  }
4769 #endif
4770  }
4771  else
4772  {
4773  /* Something must gone wrong
4774  * how can we have a Section but no
4775  * reference? */
4776  DPRINT("ERROR: DataSectionObject without reference!\n");
4777  }
4778  }
4779 
4780  DPRINT("FIXME: didn't check for outstanding write probes\n");
4781 
4782  return TRUE;
4783 }
4784 
4785 
4786 
4787 
4788 /*
4789  * @implemented
4790  */
4791 BOOLEAN NTAPI
4794 {
4795  BOOLEAN Result = TRUE;
4796 #ifdef NEWCC
4798 #endif
4799 
4800  switch(FlushType)
4801  {
4802  case MmFlushForDelete:
4803  if (SectionObjectPointer->ImageSectionObject ||
4804  SectionObjectPointer->DataSectionObject)
4805  {
4806  return FALSE;
4807  }
4808 #ifndef NEWCC
4809  CcRosRemoveIfClosed(SectionObjectPointer);
4810 #endif
4811  return TRUE;
4812  case MmFlushForWrite:
4813  {
4814  DPRINT("MmFlushImageSection(%d)\n", FlushType);
4815 #ifdef NEWCC
4816  Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->DataSectionObject;
4817 #endif
4818 
4819  if (SectionObjectPointer->ImageSectionObject)
4820  {
4821  DPRINT1("SectionObject has ImageSection\n");
4822  return FALSE;
4823  }
4824 
4825 #ifdef NEWCC
4826  CcpLock();
4827  Result = !SectionObjectPointer->SharedCacheMap || (Segment->ReferenceCount == CcpCountCacheSections((PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap));
4828  CcpUnlock();
4829  DPRINT("Result %d\n", Result);
4830 #endif
4831  return Result;
4832  }
4833  }
4834  return FALSE;
4835 }
4836 
4837 /*
4838  * @implemented
4839  */
4842  OUT PVOID * MappedBase,
4844 {
4845  PROS_SECTION_OBJECT Section;
4847  NTSTATUS Status;
4848  PAGED_CODE();
4849 
4850  if (MiIsRosSectionObject(SectionObject) == FALSE)
4851  {
4852  return MiMapViewInSystemSpace(SectionObject,
4853  &MmSession,
4854  MappedBase,
4855  ViewSize);
4856  }
4857 
4858  DPRINT("MmMapViewInSystemSpace() called\n");
4859 
4860  Section = (PROS_SECTION_OBJECT)SectionObject;
4861  AddressSpace = MmGetKernelAddressSpace();
4862 
4863  MmLockAddressSpace(AddressSpace);
4864 
4865 
4866  if ((*ViewSize) == 0)
4867  {
4868  (*ViewSize) = Section->MaximumSize.u.LowPart;
4869  }
4870  else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
4871  {
4872  (*ViewSize) = Section->MaximumSize.u.LowPart;
4873  }
4874 
4875  MmLockSectionSegment(Section->Segment);
4876 
4877 
4878  Status = MmMapViewOfSegment(AddressSpace,
4879  Section,
4880  Section->Segment,
4881  MappedBase,
4882  *ViewSize,
4884  0,
4885  0);
4886 
4887  MmUnlockSectionSegment(Section->Segment);
4888  MmUnlockAddressSpace(AddressSpace);
4889 
4890  return Status;
4891 }
4892 
4893 NTSTATUS
4894 NTAPI
4896 {
4898  NTSTATUS Status;
4899 
4900  DPRINT("MmUnmapViewInSystemSpace() called\n");
4901 
4902  AddressSpace = MmGetKernelAddressSpace();
4903 
4904  MmLockAddressSpace(AddressSpace);
4905 
4906  Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
4907 
4908  MmUnlockAddressSpace(AddressSpace);
4909 
4910  return Status;
4911 }
4912 
4913 /**********************************************************************
4914  * NAME EXPORTED
4915  * MmCreateSection@
4916  *
4917  * DESCRIPTION
4918  * Creates a section object.
4919  *
4920  * ARGUMENTS
4921  * SectionObject (OUT)
4922  * Caller supplied storage for the resulting pointer
4923  * to a SECTION_OBJECT instance;
4924  *
4925  * DesiredAccess
4926  * Specifies the desired access to the section can be a
4927  * combination of:
4928  * STANDARD_RIGHTS_REQUIRED |
4929  * SECTION_QUERY |
4930  * SECTION_MAP_WRITE |
4931  * SECTION_MAP_READ |
4932  * SECTION_MAP_EXECUTE
4933  *
4934  * ObjectAttributes [OPTIONAL]
4935  * Initialized attributes for the object can be used
4936  * to create a named section;
4937  *
4938  * MaximumSize
4939  * Maximizes the size of the memory section. Must be
4940  * non-NULL for a page-file backed section.
4941  * If value specified for a mapped file and the file is
4942  * not large enough, file will be extended.
4943  *
4944  * SectionPageProtection
4945  * Can be a combination of:
4946  * PAGE_READONLY |
4947  * PAGE_READWRITE |
4948  * PAGE_WRITEONLY |
4949  * PAGE_WRITECOPY
4950  *
4951  * AllocationAttributes
4952  * Can be a combination of:
4953  * SEC_IMAGE |
4954  * SEC_RESERVE
4955  *
4956  * FileHandle
4957  * Handle to a file to create a section mapped to a file
4958  * instead of a memory backed section;
4959  *
4960  * File
4961  * Unknown.
4962  *
4963  * RETURN VALUE
4964  * Status.
4965  *
4966  * @implemented
4967  */
4973  IN ULONG SectionPageProtection,
4975  IN HANDLE FileHandle OPTIONAL,
4976  IN PFILE_OBJECT FileObject OPTIONAL)
4977 {
4978  NTSTATUS Status;
4979  ULONG Protection;
4981 
4982  /* Check if an ARM3 section is being created instead */
4983  if (!(AllocationAttributes & (SEC_IMAGE | SEC_PHYSICALMEMORY)))
4984  {
4985  if (!(FileObject) && !(FileHandle))
4986  {
4987  return MmCreateArm3Section(Section,
4988  DesiredAccess,
4990  MaximumSize,
4991  SectionPageProtection,
4992  AllocationAttributes &~ 1,
4993  FileHandle,
4994  FileObject);
4995  }
4996  }
4997 
4998  /* Convert section flag to page flag */
4999  if (AllocationAttributes & SEC_NOCACHE) SectionPageProtection |= PAGE_NOCACHE;
5000 
5001  /* Check to make sure the protection is correct. Nt* does this already */
5002  Protection = MiMakeProtectionMask(SectionPageProtection);
5003  if (Protection == MM_INVALID_PROTECTION)
5004  {
5005  DPRINT1("Page protection is invalid\n");
5007  }
5008 
5009  /* Check if this is going to be a data or image backed file section */
5010  if ((FileHandle) || (FileObject))
5011  {
5012  /* These cannot be mapped with large pages */
5013  if (AllocationAttributes & SEC_LARGE_PAGES)
5014  {
5015  DPRINT1("Large pages cannot be used with an image mapping\n");
5017  }
5018 
5019  /* Did the caller pass an object? */
5020  if (FileObject)
5021  {
5022  /* Reference the object directly */
5024  }
5025  else
5026  {
5027  /* Reference the file handle to get the object */
5029  MmMakeFileAccess[Protection],
5032  (PVOID*)&FileObject,
5033  NULL);
5034  if (!NT_SUCCESS(Status))
5035  {
5036  DPRINT1("Failed to get a handle to the FO: %lx\n", Status);
5037  return Status;
5038  }
5039  }
5040  }
5041  else
5042  {
5043  /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
5044  if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION;
5045  }
5046 
5047 #ifndef NEWCC // A hack for initializing caching.
5048  // This is needed only in the old case.
5049  if (FileHandle)
5050  {
5052  NTSTATUS Status;
5053  CHAR Buffer;
5055  ByteOffset.QuadPart = 0;
5056  Status = ZwReadFile(FileHandle,
5057  NULL,
5058  NULL,
5059  NULL,
5060  &Iosb,
5061  &Buffer,
5062  sizeof(Buffer),
5063  &ByteOffset,
5064  NULL);
5065  if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
5066  {
5067  DPRINT1("CC failure: %lx\n", Status);
5068  if (FileObject)
5070  return Status;
5071  }
5072  // Caching is initialized...
5073 
5074  // Hack of the hack: actually, it might not be initialized if FSD init on effective right and if file is null-size
5075  // In such case, force cache by initiating a write IRP
5076  if (Status == STATUS_END_OF_FILE && !(AllocationAttributes & SEC_IMAGE) && FileObject != NULL &&
5077  (FileObject->SectionObjectPointer == NULL || FileObject->SectionObjectPointer->SharedCacheMap == NULL))
5078  {
5079  Buffer = 0xdb;
5080  Status = ZwWriteFile(FileHandle,
5081  NULL,
5082  NULL,
5083  NULL,
5084  &Iosb,
5085  &Buffer,
5086  sizeof(Buffer),
5087  &ByteOffset,
5088  NULL);
5089  if (NT_SUCCESS(Status))
5090  {
5092  Zero.QuadPart = 0LL;
5093 
5094  Status = IoSetInformation(FileObject,
5096  sizeof(LARGE_INTEGER),
5097  &Zero);
5098  ASSERT(NT_SUCCESS(Status));
5099  }
5100  }
5101  }
5102 #endif
5103 
5104  if (AllocationAttributes & SEC_IMAGE)
5105  {
5106  Status = MmCreateImageSection(SectionObject,
5107  DesiredAccess,
5109  MaximumSize,
5110  SectionPageProtection,
5111  AllocationAttributes,
5112  FileObject);
5113  }
5114 #ifndef NEWCC
5115  else if (FileHandle != NULL)
5116  {
5117  Status = MmCreateDataFileSection(SectionObject,
5118  DesiredAccess,
5120  MaximumSize,
5121  SectionPageProtection,
5122  AllocationAttributes,
5123  FileObject);
5124  }
5125 #else
5126  else if (FileHandle != NULL || FileObject != NULL)
5127  {
5128  Status = MmCreateCacheSection(SectionObject,
5129  DesiredAccess,
5131  MaximumSize,
5132  SectionPageProtection,
5133  AllocationAttributes,
5134  FileObject);
5135  }
5136 #endif
5137  else
5138  {
5139  if ((AllocationAttributes & SEC_PHYSICALMEMORY) == 0)
5140  {
5141  DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes, FileObject, FileHandle);
5142  }
5143 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5144  Status = MmCreatePageFileSection(SectionObject,
5145  DesiredAccess,
5147  MaximumSize,
5148  SectionPageProtection,
5149  AllocationAttributes);
5150  if (FileObject)
5152  }
5153 
5154  return Status;
5155 }
5156 
5157 /* 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
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:4718
PMM_REGION NTAPI MmFindRegion(PVOID BaseAddress, PLIST_ENTRY RegionListHead, PVOID Address, PVOID *RegionBaseAddress)
Definition: region.c:257
BOOLEAN WriteCopy
Definition: mm.h:170
_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
struct _MM_SECTION_SEGMENT::@1714 Image
#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:1048
struct _LARGE_INTEGER::@2193 u
#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
#define LL
Definition: tui.h:72
#define TYPE_ALIGNMENT(t)
Definition: ntbasedef.h:117
Definition: cc.h:202
NTSTATUS NTAPI MmWritePageSectionView(PMMSUPPORT AddressSpace, PMEMORY_AREA MemoryArea, PVOID Address, ULONG PageEntry)
Definition: section.c:2369
static VOID MmAlterViewAttributes(PMMSUPPORT AddressSpace, PVOID BaseAddress, SIZE_T RegionSize, ULONG OldType, ULONG OldProtect, ULONG NewType, ULONG NewProtect)
Definition: section.c:1279
VOID NTAPI MmInsertRmap(PFN_NUMBER Page, struct _EPROCESS *Process, PVOID Address)
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:47
LARGE_INTEGER MaximumSize
Definition: mm.h:196
NTSTATUS ExeFmtpCreateImageSection(PFILE_OBJECT FileObject, PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
Definition: section.c:3577
LONG ReferenceCount
Definition: miarm.h:450
#define PAGE_IS_EXECUTABLE
Definition: mm.h:139
#define PAGE_FROM_SSE(E)
Definition: newmm.h:17
#define SEC_LARGE_PAGES
Definition: mmtypes.h:102
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133
ULONG Type
Definition: mm.h:214
#define MiSetPageEvent(Process, Address)
Definition: newmm.h:43
_In_ ACCESS_MASK _In_opt_ POBJECT_ATTRIBUTES _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ ULONG AllocationAttributes
Definition: mmfuncs.h:360
#define STANDARD_RIGHTS_WRITE
Definition: nt_native.h:66
#define CcpLock()
Definition: newcc.h:140
struct _Entry Entry
Definition: kefuncs.h:640
#define __cdecl
Definition: accygwin.h:79
#define PFN_FROM_SSE(E)
Definition: newmm.h:7
ULONGLONG SizeOfStackCommit
Definition: