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