2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
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.
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.
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.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
48 #include <cache/newcc.h>
49 #include <cache/section/newmm.h>
52 #include <reactos/exeformat.h>
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 #include "ARM3/miarm.h"
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__); \
67 extern MMSESSION MmSession
;
71 MiMapViewInSystemSpace(IN PVOID Section
,
73 OUT PVOID
*MappedBase
,
74 IN OUT PSIZE_T ViewSize
);
78 MmCreateArm3Section(OUT PVOID
*SectionObject
,
79 IN ACCESS_MASK DesiredAccess
,
80 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
81 IN PLARGE_INTEGER InputMaximumSize
,
82 IN ULONG SectionPageProtection
,
83 IN ULONG AllocationAttributes
,
84 IN HANDLE FileHandle OPTIONAL
,
85 IN PFILE_OBJECT FileObject OPTIONAL
);
89 MmMapViewOfArm3Section(IN PVOID SectionObject
,
91 IN OUT PVOID
*BaseAddress
,
92 IN ULONG_PTR ZeroBits
,
94 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
95 IN OUT PSIZE_T ViewSize
,
96 IN SECTION_INHERIT InheritDisposition
,
97 IN ULONG AllocationType
,
101 // PeFmtCreateSection depends on the following:
103 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
104 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
106 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
107 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
108 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
110 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
111 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
112 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
113 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
114 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
115 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
116 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
117 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
118 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
120 /* TYPES *********************************************************************/
124 PROS_SECTION_OBJECT Section
;
125 PMM_SECTION_SEGMENT Segment
;
126 LARGE_INTEGER Offset
;
129 PEPROCESS CallingProcess
;
130 ULONG_PTR SectionEntry
;
132 MM_SECTION_PAGEOUT_CONTEXT
;
134 /* GLOBALS *******************************************************************/
136 POBJECT_TYPE MmSectionObjectType
= NULL
;
138 ULONG_PTR MmSubsectionBase
;
140 static ULONG SectionCharacteristicsToProtect
[16] =
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 */
151 * FIXME? do we really need the WriteCopy field in segments? can't we use
152 * PAGE_WRITECOPY here?
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 */
164 extern ULONG MmMakeFileAccess
[];
165 ACCESS_MASK NTAPI
MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection
);
166 static GENERIC_MAPPING MmpSectionMapping
=
168 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
169 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
170 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
174 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
176 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
177 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
180 /* FUNCTIONS *****************************************************************/
185 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
186 File Format Specification", revision 6.0 (February 1999)
188 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
189 IN SIZE_T FileHeaderSize
,
191 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
193 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
194 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
197 ULONG cbFileHeaderOffsetSize
= 0;
198 ULONG cbSectionHeadersOffset
= 0;
199 ULONG cbSectionHeadersSize
;
200 ULONG cbSectionHeadersOffsetSize
= 0;
201 ULONG cbOptHeaderSize
;
202 ULONG cbHeadersSize
= 0;
203 ULONG nSectionAlignment
;
204 ULONG nFileAlignment
;
206 const IMAGE_DOS_HEADER
* pidhDosHeader
;
207 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
208 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
209 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
210 PMM_SECTION_SEGMENT pssSegments
;
211 LARGE_INTEGER lnOffset
;
213 SIZE_T nPrevVirtualEndOfSegment
= 0;
214 ULONG nFileSizeOfHeaders
= 0;
218 ASSERT(FileHeaderSize
> 0);
220 ASSERT(ImageSectionObject
);
222 ASSERT(AllocateSegmentsCb
);
224 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
226 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
228 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
231 pidhDosHeader
= FileHeader
;
234 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
236 /* image too small to be an MZ executable */
237 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
238 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
240 /* no MZ signature */
241 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
242 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
245 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
247 /* not a Windows executable */
248 if(pidhDosHeader
->e_lfanew
<= 0)
249 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
251 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
252 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
254 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
259 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
260 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
262 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
263 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
267 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
268 * need to read the header from the file
270 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
271 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
273 ULONG cbNtHeaderSize
;
277 l_ReadHeaderFromFile
:
279 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
281 /* read the header from the file */
282 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
284 if(!NT_SUCCESS(nStatus
))
286 NTSTATUS ReturnedStatus
= nStatus
;
288 /* If it attempted to read past the end of the file, it means e_lfanew is invalid */
289 if (ReturnedStatus
== STATUS_END_OF_FILE
) nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
291 DIE(("ReadFile failed, status %08X\n", ReturnedStatus
));
296 ASSERT(cbReadSize
> 0);
298 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
300 /* the buffer doesn't contain the file header */
301 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
302 DIE(("The file doesn't contain the PE file header\n"));
304 pinhNtHeader
= pData
;
306 /* object still not aligned: copy it to the beginning of the buffer */
307 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
309 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
310 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
311 pinhNtHeader
= pBuffer
;
314 /* invalid NT header */
315 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
317 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
318 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
320 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
322 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
323 DIE(("The full NT header is too large\n"));
325 /* the buffer doesn't contain the whole NT header */
326 if(cbReadSize
< cbNtHeaderSize
)
327 DIE(("The file doesn't contain the full NT header\n"));
331 ULONG cbOptHeaderOffsetSize
= 0;
333 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
335 /* don't trust an invalid NT header */
336 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
337 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
339 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
340 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
342 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
344 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
345 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
347 /* the buffer doesn't contain the whole NT header: read it from the file */
348 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
349 goto l_ReadHeaderFromFile
;
352 /* read information from the NT header */
353 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
354 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
356 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
358 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
359 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
361 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
363 switch(piohOptHeader
->Magic
)
365 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
367 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
372 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
375 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
376 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
378 /* See [1], section 3.4.2 */
379 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
381 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
382 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
384 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
385 DIE(("The section alignment is smaller than the file alignment\n"));
387 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
388 nFileAlignment
= piohOptHeader
->FileAlignment
;
390 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
391 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
395 nSectionAlignment
= PAGE_SIZE
;
396 nFileAlignment
= PAGE_SIZE
;
399 ASSERT(IsPowerOf2(nSectionAlignment
));
400 ASSERT(IsPowerOf2(nFileAlignment
));
402 switch(piohOptHeader
->Magic
)
405 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
407 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
408 ImageBase
= piohOptHeader
->ImageBase
;
410 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
411 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
413 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
414 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
416 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
417 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
419 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
421 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
423 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
424 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
426 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
427 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
431 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
433 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
434 piohOptHeader
->AddressOfEntryPoint
);
437 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
438 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
440 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
442 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
444 if (piohOptHeader
->AddressOfEntryPoint
== 0)
446 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
450 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
451 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
453 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
455 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
458 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
459 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
460 * magic to any binary.
462 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
463 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
464 * the SxS support -- at which point, duh, this should be removed.
466 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
468 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
475 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
477 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
479 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
481 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
483 ImageBase
= pioh64OptHeader
->ImageBase
;
484 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
485 DIE(("ImageBase exceeds the address space\n"));
488 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
490 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
491 DIE(("SizeOfImage exceeds the address space\n"));
493 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
496 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
498 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
499 DIE(("SizeOfStackReserve exceeds the address space\n"));
501 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
504 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
506 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
507 DIE(("SizeOfStackCommit exceeds the address space\n"));
509 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
512 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
514 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
516 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
517 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
519 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
520 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
524 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
526 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
527 pioh64OptHeader
->AddressOfEntryPoint
);
530 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
531 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
533 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
535 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
537 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
539 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
543 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
544 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
546 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
547 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
554 /* [1], section 3.4.2 */
555 if((ULONG_PTR
)ImageBase
% 0x10000)
556 DIE(("ImageBase is not aligned on a 64KB boundary"));
558 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
559 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
560 ImageSectionObject
->ImageInformation
.GpValue
= 0;
561 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
562 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
564 /* SECTION HEADERS */
565 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
567 /* see [1], section 3.3 */
568 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
569 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
572 * the additional segment is for the file's headers. They need to be present for
573 * the benefit of the dynamic loader (to locate exports, defaults for thread
574 * parameters, resources, etc.)
576 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
578 /* file offset for the section headers */
579 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
580 DIE(("Offset overflow\n"));
582 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
583 DIE(("Offset overflow\n"));
585 /* size of the section headers */
586 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
587 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
589 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
590 DIE(("Section headers too large\n"));
592 /* size of the executable's headers */
593 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
595 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
596 // DIE(("SizeOfHeaders is not aligned\n"));
598 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
599 DIE(("The section headers overflow SizeOfHeaders\n"));
601 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
603 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
604 DIE(("Overflow aligning the size of headers\n"));
611 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
612 /* WARNING: piohOptHeader IS NO LONGER USABLE */
613 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
615 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
616 pishSectionHeaders
= NULL
;
620 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
621 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
623 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
624 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
628 * the buffer doesn't contain the section headers, or the alignment is wrong:
629 * read the headers from the file
631 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
632 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
637 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
639 /* read the header from the file */
640 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
642 if(!NT_SUCCESS(nStatus
))
643 DIE(("ReadFile failed with status %08X\n", nStatus
));
647 ASSERT(cbReadSize
> 0);
649 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
651 /* the buffer doesn't contain all the section headers */
652 if(cbReadSize
< cbSectionHeadersSize
)
653 DIE(("The file doesn't contain all of the section headers\n"));
655 pishSectionHeaders
= pData
;
657 /* object still not aligned: copy it to the beginning of the buffer */
658 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
660 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
661 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
662 pishSectionHeaders
= pBuffer
;
667 /* allocate the segments */
668 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
669 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
671 if(ImageSectionObject
->Segments
== NULL
)
672 DIE(("AllocateSegments failed\n"));
674 /* initialize the headers segment */
675 pssSegments
= ImageSectionObject
->Segments
;
677 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
679 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
680 DIE(("Cannot align the size of the section headers\n"));
682 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
683 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
684 DIE(("Cannot align the size of the section headers\n"));
686 pssSegments
[0].Image
.FileOffset
= 0;
687 pssSegments
[0].Protection
= PAGE_READONLY
;
688 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
689 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
690 pssSegments
[0].Image
.VirtualAddress
= 0;
691 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
692 pssSegments
[0].WriteCopy
= TRUE
;
694 /* skip the headers segment */
697 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
699 /* convert the executable sections into segments. See also [1], section 4 */
700 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
702 ULONG nCharacteristics
;
704 /* validate the alignment */
705 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
706 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
708 /* sections must be contiguous, ordered by base address and non-overlapping */
709 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
710 DIE(("Memory gap between section %u and the previous\n", i
));
712 /* ignore explicit BSS sections */
713 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
715 /* validate the alignment */
717 /* Yes, this should be a multiple of FileAlignment, but there's
718 * stuff out there that isn't. We can cope with that
720 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
721 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
724 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
725 // DIE(("PointerToRawData[%u] is not aligned\n", i));
728 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
729 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
733 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
734 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
737 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
739 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
741 /* no explicit protection */
742 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
744 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
745 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
747 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
748 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
750 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
751 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
754 /* see table above */
755 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
756 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
758 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
759 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
761 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
763 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
764 /* FIXME: always false */
765 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
766 DIE(("Cannot align the virtual size of section %u\n", i
));
768 if(pssSegments
[i
].Length
.QuadPart
== 0)
769 DIE(("Virtual size of section %u is null\n", i
));
771 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
772 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
774 /* ensure the memory image is no larger than 4GB */
775 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
776 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
777 DIE(("The image is too large\n"));
780 if(nSectionAlignment
>= PAGE_SIZE
)
781 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
784 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
794 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
795 * ARGUMENTS: PFILE_OBJECT to wait for.
796 * RETURNS: Status of the wait.
799 MmspWaitForFileLock(PFILE_OBJECT File
)
801 return STATUS_SUCCESS
;
802 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
807 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
809 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
811 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
812 PMM_SECTION_SEGMENT SectionSegments
;
816 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
817 NrSegments
= ImageSectionObject
->NrSegments
;
818 SectionSegments
= ImageSectionObject
->Segments
;
819 for (i
= 0; i
< NrSegments
; i
++)
821 if (SectionSegments
[i
].ReferenceCount
!= 0)
823 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
824 SectionSegments
[i
].ReferenceCount
);
825 KeBugCheck(MEMORY_MANAGEMENT
);
827 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
829 ExFreePool(ImageSectionObject
->Segments
);
830 ExFreePool(ImageSectionObject
);
831 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
833 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
835 PMM_SECTION_SEGMENT Segment
;
837 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
840 if (Segment
->ReferenceCount
!= 0)
842 DPRINT1("Data segment still referenced\n");
843 KeBugCheck(MEMORY_MANAGEMENT
);
845 MmFreePageTablesSectionSegment(Segment
, NULL
);
847 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
853 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
854 PLARGE_INTEGER Offset
)
858 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
861 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
862 KeBugCheck(MEMORY_MANAGEMENT
);
864 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
866 DPRINT1("Maximum share count reached\n");
867 KeBugCheck(MEMORY_MANAGEMENT
);
869 if (IS_SWAP_FROM_SSE(Entry
))
871 KeBugCheck(MEMORY_MANAGEMENT
);
873 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
874 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
879 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
880 PMM_SECTION_SEGMENT Segment
,
881 PLARGE_INTEGER Offset
,
886 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
887 BOOLEAN IsDirectMapped
= FALSE
;
891 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
892 KeBugCheck(MEMORY_MANAGEMENT
);
894 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
896 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
897 KeBugCheck(MEMORY_MANAGEMENT
);
899 if (IS_SWAP_FROM_SSE(Entry
))
901 KeBugCheck(MEMORY_MANAGEMENT
);
903 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
905 * If we reducing the share count of this entry to zero then set the entry
906 * to zero and tell the cache the page is no longer mapped.
908 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
910 PFILE_OBJECT FileObject
;
911 SWAPENTRY SavedSwapEntry
;
914 PROS_SHARED_CACHE_MAP SharedCacheMap
;
915 BOOLEAN IsImageSection
;
916 LARGE_INTEGER FileOffset
;
918 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
919 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
922 Page
= PFN_FROM_SSE(Entry
);
923 FileObject
= Section
->FileObject
;
924 if (FileObject
!= NULL
&&
925 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
929 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
930 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
933 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
934 IsDirectMapped
= TRUE
;
936 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
.QuadPart
, Dirty
);
938 Status
= STATUS_SUCCESS
;
940 if (!NT_SUCCESS(Status
))
942 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
943 KeBugCheck(MEMORY_MANAGEMENT
);
949 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
950 if (SavedSwapEntry
== 0)
953 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
954 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
958 * Try to page out this page and set the swap entry
959 * within the section segment. There exist no rmap entry
960 * for this page. The pager thread can't page out a
961 * page without a rmap entry.
963 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
964 if (InEntry
) *InEntry
= Entry
;
965 MiSetPageEvent(NULL
, NULL
);
969 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
970 if (InEntry
) *InEntry
= 0;
971 MiSetPageEvent(NULL
, NULL
);
974 MmReleasePageMemoryConsumer(MC_USER
, Page
);
980 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
981 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
989 * We hold all locks. Nobody can do something with the current
990 * process and the current segment (also not within an other process).
993 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
994 if (!NT_SUCCESS(Status
))
996 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
997 KeBugCheck(MEMORY_MANAGEMENT
);
1000 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
1001 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
1002 MmSetSavedSwapEntryPage(Page
, 0);
1003 MiSetPageEvent(NULL
, NULL
);
1005 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1009 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1010 KeBugCheck(MEMORY_MANAGEMENT
);
1019 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1021 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1024 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1028 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1030 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1032 SharedCacheMap
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1033 Vacb
= CcRosLookupVacb(SharedCacheMap
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
);
1036 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, FALSE
, TRUE
);
1046 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1050 PVOID DestAddress
, SrcAddress
;
1052 Process
= PsGetCurrentProcess();
1053 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1054 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1055 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1057 return(STATUS_NO_MEMORY
);
1059 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1060 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1061 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1062 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1063 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1064 return(STATUS_SUCCESS
);
1070 MiReadPage(PMEMORY_AREA MemoryArea
,
1074 * FUNCTION: Read a page for a section backed memory area.
1076 * MemoryArea - Memory area to read the page for.
1077 * Offset - Offset of the page to read.
1078 * Page - Variable that receives a page contains the read data.
1081 LONGLONG BaseOffset
;
1082 LONGLONG FileOffset
;
1086 PFILE_OBJECT FileObject
;
1089 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1090 BOOLEAN IsImageSection
;
1093 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1094 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1095 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
;
1096 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1097 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1099 ASSERT(SharedCacheMap
);
1101 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1104 * If the file system is letting us go directly to the cache and the
1105 * memory area was mapped at an offset in the file which is page aligned
1106 * then get the related VACB.
1108 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1109 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1110 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1114 * Get the related VACB; we use a lower level interface than
1115 * filesystems do because it is safe for us to use an offset with an
1116 * alignment less than the file system block size.
1118 Status
= CcRosGetVacb(SharedCacheMap
,
1124 if (!NT_SUCCESS(Status
))
1131 * If the VACB isn't up to date then call the file
1132 * system to read in the data.
1134 Status
= CcReadVirtualAddress(Vacb
);
1135 if (!NT_SUCCESS(Status
))
1137 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1142 /* Probe the page, since it's PDE might not be synced */
1143 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1146 * Retrieve the page from the view that we actually want.
1148 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1149 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1151 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, TRUE
);
1158 LONGLONG VacbOffset
;
1161 * Allocate a page, this is rather complicated by the possibility
1162 * we might have to move other things out of memory
1164 MI_SET_USAGE(MI_USAGE_SECTION
);
1165 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1166 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1167 if (!NT_SUCCESS(Status
))
1171 Status
= CcRosGetVacb(SharedCacheMap
,
1177 if (!NT_SUCCESS(Status
))
1184 * If the VACB isn't up to date then call the file
1185 * system to read in the data.
1187 Status
= CcReadVirtualAddress(Vacb
);
1188 if (!NT_SUCCESS(Status
))
1190 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1195 Process
= PsGetCurrentProcess();
1196 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1197 VacbOffset
= BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
;
1198 Length
= RawLength
- SegOffset
;
1199 if (Length
<= VacbOffset
&& Length
<= PAGE_SIZE
)
1201 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1203 else if (VacbOffset
>= PAGE_SIZE
)
1205 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1209 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, VacbOffset
);
1210 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1211 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1212 Status
= CcRosGetVacb(SharedCacheMap
,
1213 FileOffset
+ VacbOffset
,
1218 if (!NT_SUCCESS(Status
))
1225 * If the VACB isn't up to date then call the file
1226 * system to read in the data.
1228 Status
= CcReadVirtualAddress(Vacb
);
1229 if (!NT_SUCCESS(Status
))
1231 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1235 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1236 if (Length
< PAGE_SIZE
)
1238 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, Length
- VacbOffset
);
1242 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, PAGE_SIZE
- VacbOffset
);
1245 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1246 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1248 return(STATUS_SUCCESS
);
1253 MiReadPage(PMEMORY_AREA MemoryArea
,
1257 * FUNCTION: Read a page for a section backed memory area.
1259 * MemoryArea - Memory area to read the page for.
1260 * Offset - Offset of the page to read.
1261 * Page - Variable that receives a page contains the read data.
1264 MM_REQUIRED_RESOURCES Resources
;
1267 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1269 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1270 Resources
.FileOffset
.QuadPart
= SegOffset
+
1271 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1272 Resources
.Consumer
= MC_USER
;
1273 Resources
.Amount
= PAGE_SIZE
;
1275 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]);
1277 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1278 *Page
= Resources
.Page
[0];
1285 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1286 MEMORY_AREA
* MemoryArea
,
1290 LARGE_INTEGER Offset
;
1293 PROS_SECTION_OBJECT Section
;
1294 PMM_SECTION_SEGMENT Segment
;
1299 BOOLEAN HasSwapEntry
;
1301 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1302 SWAPENTRY SwapEntry
;
1305 * There is a window between taking the page fault and locking the
1306 * address space when another thread could load the page so we check
1309 if (MmIsPagePresent(Process
, Address
))
1311 return(STATUS_SUCCESS
);
1314 if (MmIsDisabledPage(Process
, Address
))
1316 return(STATUS_ACCESS_VIOLATION
);
1320 * Check for the virtual memory area being deleted.
1322 if (MemoryArea
->DeleteInProgress
)
1324 return(STATUS_UNSUCCESSFUL
);
1327 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1328 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1329 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1331 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1332 Section
= MemoryArea
->Data
.SectionData
.Section
;
1333 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1334 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1336 ASSERT(Region
!= NULL
);
1340 MmLockSectionSegment(Segment
);
1341 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1343 * Check if this page needs to be mapped COW
1345 if ((Segment
->WriteCopy
) &&
1346 (Region
->Protect
== PAGE_READWRITE
||
1347 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1349 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1353 Attributes
= Region
->Protect
;
1357 * Check if someone else is already handling this fault, if so wait
1360 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1362 MmUnlockSectionSegment(Segment
);
1363 MmUnlockAddressSpace(AddressSpace
);
1364 MiWaitForPageEvent(NULL
, NULL
);
1365 MmLockAddressSpace(AddressSpace
);
1366 DPRINT("Address 0x%p\n", Address
);
1367 return(STATUS_MM_RESTART_OPERATION
);
1370 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1374 SWAPENTRY DummyEntry
;
1377 * Is it a wait entry?
1379 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1381 if (SwapEntry
== MM_WAIT_ENTRY
)
1383 MmUnlockSectionSegment(Segment
);
1384 MmUnlockAddressSpace(AddressSpace
);
1385 MiWaitForPageEvent(NULL
, NULL
);
1386 MmLockAddressSpace(AddressSpace
);
1387 return STATUS_MM_RESTART_OPERATION
;
1391 * Must be private page we have swapped out.
1397 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1399 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1400 KeBugCheck(MEMORY_MANAGEMENT
);
1403 MmUnlockSectionSegment(Segment
);
1404 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1405 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1407 MmUnlockAddressSpace(AddressSpace
);
1408 MI_SET_USAGE(MI_USAGE_SECTION
);
1409 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1410 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1411 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1412 if (!NT_SUCCESS(Status
))
1414 KeBugCheck(MEMORY_MANAGEMENT
);
1417 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1418 if (!NT_SUCCESS(Status
))
1420 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1421 KeBugCheck(MEMORY_MANAGEMENT
);
1423 MmLockAddressSpace(AddressSpace
);
1424 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1425 Status
= MmCreateVirtualMapping(Process
,
1430 if (!NT_SUCCESS(Status
))
1432 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1433 KeBugCheck(MEMORY_MANAGEMENT
);
1438 * Store the swap entry for later use.
1440 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1443 * Add the page to the process's working set
1445 MmInsertRmap(Page
, Process
, Address
);
1447 * Finish the operation
1449 MiSetPageEvent(Process
, Address
);
1450 DPRINT("Address 0x%p\n", Address
);
1451 return(STATUS_SUCCESS
);
1455 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1457 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1459 MmUnlockSectionSegment(Segment
);
1461 * Just map the desired physical page
1463 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1464 Status
= MmCreateVirtualMappingUnsafe(Process
,
1469 if (!NT_SUCCESS(Status
))
1471 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1472 KeBugCheck(MEMORY_MANAGEMENT
);
1477 * Cleanup and release locks
1479 MiSetPageEvent(Process
, Address
);
1480 DPRINT("Address 0x%p\n", Address
);
1481 return(STATUS_SUCCESS
);
1485 * Get the entry corresponding to the offset within the section
1487 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1491 SWAPENTRY FakeSwapEntry
;
1494 * If the entry is zero (and it can't change because we have
1495 * locked the segment) then we need to load the page.
1499 * Release all our locks and read in the page from disk
1501 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1502 MmUnlockSectionSegment(Segment
);
1503 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1504 MmUnlockAddressSpace(AddressSpace
);
1506 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1507 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1508 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1510 MI_SET_USAGE(MI_USAGE_SECTION
);
1511 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1512 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1513 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1514 if (!NT_SUCCESS(Status
))
1516 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1522 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1523 if (!NT_SUCCESS(Status
))
1525 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1528 if (!NT_SUCCESS(Status
))
1531 * FIXME: What do we know in this case?
1534 * Cleanup and release locks
1536 MmLockAddressSpace(AddressSpace
);
1537 MiSetPageEvent(Process
, Address
);
1538 DPRINT("Address 0x%p\n", Address
);
1543 * Mark the offset within the section as having valid, in-memory
1546 MmLockAddressSpace(AddressSpace
);
1547 MmLockSectionSegment(Segment
);
1548 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1549 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1550 MmUnlockSectionSegment(Segment
);
1552 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1553 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1554 Page
, Process
, PAddress
, Attributes
);
1555 Status
= MmCreateVirtualMapping(Process
,
1560 if (!NT_SUCCESS(Status
))
1562 DPRINT1("Unable to create virtual mapping\n");
1563 KeBugCheck(MEMORY_MANAGEMENT
);
1565 ASSERT(MmIsPagePresent(Process
, PAddress
));
1566 MmInsertRmap(Page
, Process
, Address
);
1568 MiSetPageEvent(Process
, Address
);
1569 DPRINT("Address 0x%p\n", Address
);
1570 return(STATUS_SUCCESS
);
1572 else if (IS_SWAP_FROM_SSE(Entry
))
1574 SWAPENTRY SwapEntry
;
1576 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1579 * Release all our locks and read in the page from disk
1581 MmUnlockSectionSegment(Segment
);
1583 MmUnlockAddressSpace(AddressSpace
);
1584 MI_SET_USAGE(MI_USAGE_SECTION
);
1585 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1586 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1587 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1588 if (!NT_SUCCESS(Status
))
1590 KeBugCheck(MEMORY_MANAGEMENT
);
1593 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1594 if (!NT_SUCCESS(Status
))
1596 KeBugCheck(MEMORY_MANAGEMENT
);
1600 * Relock the address space and segment
1602 MmLockAddressSpace(AddressSpace
);
1603 MmLockSectionSegment(Segment
);
1606 * Check the entry. No one should change the status of a page
1607 * that has a pending page-in.
1609 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1610 if (Entry
!= Entry1
)
1612 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1613 KeBugCheck(MEMORY_MANAGEMENT
);
1617 * Mark the offset within the section as having valid, in-memory
1620 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1621 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1622 MmUnlockSectionSegment(Segment
);
1625 * Save the swap entry.
1627 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1628 Status
= MmCreateVirtualMapping(Process
,
1633 if (!NT_SUCCESS(Status
))
1635 DPRINT1("Unable to create virtual mapping\n");
1636 KeBugCheck(MEMORY_MANAGEMENT
);
1638 MmInsertRmap(Page
, Process
, Address
);
1639 MiSetPageEvent(Process
, Address
);
1640 DPRINT("Address 0x%p\n", Address
);
1641 return(STATUS_SUCCESS
);
1646 * If the section offset is already in-memory and valid then just
1647 * take another reference to the page
1650 Page
= PFN_FROM_SSE(Entry
);
1652 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1653 MmUnlockSectionSegment(Segment
);
1655 Status
= MmCreateVirtualMapping(Process
,
1660 if (!NT_SUCCESS(Status
))
1662 DPRINT1("Unable to create virtual mapping\n");
1663 KeBugCheck(MEMORY_MANAGEMENT
);
1665 MmInsertRmap(Page
, Process
, Address
);
1666 MiSetPageEvent(Process
, Address
);
1667 DPRINT("Address 0x%p\n", Address
);
1668 return(STATUS_SUCCESS
);
1674 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1675 MEMORY_AREA
* MemoryArea
,
1678 PMM_SECTION_SEGMENT Segment
;
1679 PROS_SECTION_OBJECT Section
;
1684 LARGE_INTEGER Offset
;
1687 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1688 SWAPENTRY SwapEntry
;
1690 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1693 * Check if the page has already been set readwrite
1695 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1697 DPRINT("Address 0x%p\n", Address
);
1698 return(STATUS_SUCCESS
);
1702 * Find the offset of the page
1704 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1705 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1706 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1708 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1709 Section
= MemoryArea
->Data
.SectionData
.Section
;
1710 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1711 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1713 ASSERT(Region
!= NULL
);
1717 MmLockSectionSegment(Segment
);
1719 OldPage
= MmGetPfnForProcess(Process
, Address
);
1720 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1722 MmUnlockSectionSegment(Segment
);
1725 * Check if we are doing COW
1727 if (!((Segment
->WriteCopy
) &&
1728 (Region
->Protect
== PAGE_READWRITE
||
1729 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1731 DPRINT("Address 0x%p\n", Address
);
1732 return(STATUS_ACCESS_VIOLATION
);
1735 if (IS_SWAP_FROM_SSE(Entry
) ||
1736 PFN_FROM_SSE(Entry
) != OldPage
)
1738 /* This is a private page. We must only change the page protection. */
1739 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1740 return(STATUS_SUCCESS
);
1744 DPRINT("OldPage == 0!\n");
1747 * Get or create a pageop
1749 MmLockSectionSegment(Segment
);
1750 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1753 * Wait for any other operations to complete
1755 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1757 MmUnlockSectionSegment(Segment
);
1758 MmUnlockAddressSpace(AddressSpace
);
1759 MiWaitForPageEvent(NULL
, NULL
);
1761 * Restart the operation
1763 MmLockAddressSpace(AddressSpace
);
1764 DPRINT("Address 0x%p\n", Address
);
1765 return(STATUS_MM_RESTART_OPERATION
);
1768 MmDeleteRmap(OldPage
, Process
, PAddress
);
1769 MmDeleteVirtualMapping(Process
, PAddress
, NULL
, NULL
);
1770 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1773 * Release locks now we have the pageop
1775 MmUnlockSectionSegment(Segment
);
1776 MmUnlockAddressSpace(AddressSpace
);
1781 MI_SET_USAGE(MI_USAGE_SECTION
);
1782 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1783 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1784 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1785 if (!NT_SUCCESS(Status
))
1787 KeBugCheck(MEMORY_MANAGEMENT
);
1793 MiCopyFromUserPage(NewPage
, OldPage
);
1795 MmLockAddressSpace(AddressSpace
);
1798 * Set the PTE to point to the new page
1800 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1801 Status
= MmCreateVirtualMapping(Process
,
1806 if (!NT_SUCCESS(Status
))
1808 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1809 KeBugCheck(MEMORY_MANAGEMENT
);
1814 * Unshare the old page.
1816 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1817 MmInsertRmap(NewPage
, Process
, PAddress
);
1818 MmLockSectionSegment(Segment
);
1819 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1820 MmUnlockSectionSegment(Segment
);
1822 MiSetPageEvent(Process
, Address
);
1823 DPRINT("Address 0x%p\n", Address
);
1824 return(STATUS_SUCCESS
);
1828 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1830 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1832 PFN_NUMBER Page
= 0;
1834 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1837 MmLockAddressSpace(&Process
->Vm
);
1840 MmDeleteVirtualMapping(Process
,
1846 PageOutContext
->WasDirty
= TRUE
;
1848 if (!PageOutContext
->Private
)
1850 MmLockSectionSegment(PageOutContext
->Segment
);
1851 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1852 PageOutContext
->Segment
,
1853 &PageOutContext
->Offset
,
1854 PageOutContext
->WasDirty
,
1856 &PageOutContext
->SectionEntry
);
1857 MmUnlockSectionSegment(PageOutContext
->Segment
);
1861 MmUnlockAddressSpace(&Process
->Vm
);
1864 if (PageOutContext
->Private
)
1866 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1872 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1873 MEMORY_AREA
* MemoryArea
,
1874 PVOID Address
, ULONG_PTR Entry
)
1877 MM_SECTION_PAGEOUT_CONTEXT Context
;
1878 SWAPENTRY SwapEntry
;
1881 ULONGLONG FileOffset
;
1882 PFILE_OBJECT FileObject
;
1883 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1884 BOOLEAN IsImageSection
;
1886 BOOLEAN DirectMapped
;
1887 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1890 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1893 * Get the segment and section.
1895 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1896 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1897 Context
.SectionEntry
= Entry
;
1898 Context
.CallingProcess
= Process
;
1900 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
1901 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1903 DirectMapped
= FALSE
;
1905 MmLockSectionSegment(Context
.Segment
);
1908 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1909 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1910 FileObject
= Context
.Section
->FileObject
;
1912 if (FileObject
!= NULL
&&
1913 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1915 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1918 * If the file system is letting us go directly to the cache and the
1919 * memory area was mapped at an offset in the file which is page aligned
1920 * then note this is a direct mapped page.
1922 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1923 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1925 DirectMapped
= TRUE
;
1932 * This should never happen since mappings of physical memory are never
1933 * placed in the rmap lists.
1935 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1937 DPRINT1("Trying to page out from physical memory section address 0x%p "
1938 "process %p\n", Address
,
1939 Process
? Process
->UniqueProcessId
: 0);
1940 KeBugCheck(MEMORY_MANAGEMENT
);
1944 * Get the section segment entry and the physical address.
1946 if (!MmIsPagePresent(Process
, Address
))
1948 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1949 Process
? Process
->UniqueProcessId
: 0, Address
);
1950 KeBugCheck(MEMORY_MANAGEMENT
);
1952 Page
= MmGetPfnForProcess(Process
, Address
);
1953 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1956 * Check the reference count to ensure this page can be paged out
1958 if (MmGetReferenceCountPage(Page
) != 1)
1960 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1961 Page
, MmGetReferenceCountPage(Page
));
1962 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1963 MmUnlockSectionSegment(Context
.Segment
);
1964 return STATUS_UNSUCCESSFUL
;
1968 * Prepare the context structure for the rmap delete call.
1970 MmUnlockSectionSegment(Context
.Segment
);
1971 Context
.WasDirty
= FALSE
;
1972 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1973 IS_SWAP_FROM_SSE(Entry
) ||
1974 PFN_FROM_SSE(Entry
) != Page
)
1976 Context
.Private
= TRUE
;
1980 Context
.Private
= FALSE
;
1984 * Take an additional reference to the page or the VACB.
1986 if (DirectMapped
&& !Context
.Private
)
1988 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
1990 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1991 KeBugCheck(MEMORY_MANAGEMENT
);
1996 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1997 MmReferencePage(Page
);
1998 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
2001 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2003 /* Since we passed in a surrogate, we'll get back the page entry
2004 * state in our context. This is intended to make intermediate
2005 * decrements of share count not release the wait entry.
2007 Entry
= Context
.SectionEntry
;
2010 * If this wasn't a private page then we should have reduced the entry to
2011 * zero by deleting all the rmaps.
2013 if (!Context
.Private
&& Entry
!= 0)
2015 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2016 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2018 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2023 * If the page wasn't dirty then we can just free it as for a readonly page.
2024 * Since we unmapped all the mappings above we know it will not suddenly
2026 * If the page is from a pagefile section and has no swap entry,
2027 * we can't free the page at this point.
2029 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2030 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2032 if (Context
.Private
)
2034 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2035 Context
.WasDirty
? "dirty" : "clean", Address
);
2036 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2038 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2040 MmSetSavedSwapEntryPage(Page
, 0);
2041 MmLockSectionSegment(Context
.Segment
);
2042 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2043 MmUnlockSectionSegment(Context
.Segment
);
2044 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2045 MiSetPageEvent(NULL
, NULL
);
2046 return(STATUS_SUCCESS
);
2049 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2051 if (Context
.Private
)
2053 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2054 Context
.WasDirty
? "dirty" : "clean", Address
);
2055 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2057 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2059 MmSetSavedSwapEntryPage(Page
, 0);
2062 MmLockSectionSegment(Context
.Segment
);
2063 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2064 MmUnlockSectionSegment(Context
.Segment
);
2066 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2067 MiSetPageEvent(NULL
, NULL
);
2068 return(STATUS_SUCCESS
);
2071 else if (!Context
.Private
&& DirectMapped
)
2075 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2077 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2080 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
, FALSE
);
2082 Status
= STATUS_SUCCESS
;
2085 if (!NT_SUCCESS(Status
))
2087 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2088 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2091 MiSetPageEvent(NULL
, NULL
);
2092 return(STATUS_SUCCESS
);
2094 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2098 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2100 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2102 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2103 MiSetPageEvent(NULL
, NULL
);
2104 return(STATUS_SUCCESS
);
2106 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2108 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2109 MmSetSavedSwapEntryPage(Page
, 0);
2110 MmLockAddressSpace(AddressSpace
);
2111 Status
= MmCreatePageFileMapping(Process
,
2114 MmUnlockAddressSpace(AddressSpace
);
2115 if (!NT_SUCCESS(Status
))
2117 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2118 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2120 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2121 MiSetPageEvent(NULL
, NULL
);
2122 return(STATUS_SUCCESS
);
2126 * If necessary, allocate an entry in the paging file for this page
2130 SwapEntry
= MmAllocSwapPage();
2133 MmShowOutOfSpaceMessagePagingFile();
2134 MmLockAddressSpace(AddressSpace
);
2136 * For private pages restore the old mappings.
2138 if (Context
.Private
)
2140 Status
= MmCreateVirtualMapping(Process
,
2142 MemoryArea
->Protect
,
2145 MmSetDirtyPage(Process
, Address
);
2154 * For non-private pages if the page wasn't direct mapped then
2155 * set it back into the section segment entry so we don't loose
2156 * our copy. Otherwise it will be handled by the cache manager.
2158 Status
= MmCreateVirtualMapping(Process
,
2160 MemoryArea
->Protect
,
2163 MmSetDirtyPage(Process
, Address
);
2167 // If we got here, the previous entry should have been a wait
2168 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2169 MmLockSectionSegment(Context
.Segment
);
2170 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2171 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2172 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2173 MmUnlockSectionSegment(Context
.Segment
);
2175 MmUnlockAddressSpace(AddressSpace
);
2176 MiSetPageEvent(NULL
, NULL
);
2177 return(STATUS_PAGEFILE_QUOTA
);
2182 * Write the page to the pagefile
2184 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2185 if (!NT_SUCCESS(Status
))
2187 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2190 * As above: undo our actions.
2191 * FIXME: Also free the swap page.
2193 MmLockAddressSpace(AddressSpace
);
2194 if (Context
.Private
)
2196 Status
= MmCreateVirtualMapping(Process
,
2198 MemoryArea
->Protect
,
2201 MmSetDirtyPage(Process
, Address
);
2208 Status
= MmCreateVirtualMapping(Process
,
2210 MemoryArea
->Protect
,
2213 MmSetDirtyPage(Process
, Address
);
2217 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2218 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2220 MmUnlockAddressSpace(AddressSpace
);
2221 MiSetPageEvent(NULL
, NULL
);
2222 return(STATUS_UNSUCCESSFUL
);
2226 * Otherwise we have succeeded.
2228 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2229 MmSetSavedSwapEntryPage(Page
, 0);
2230 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2231 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2233 MmLockSectionSegment(Context
.Segment
);
2234 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2235 MmUnlockSectionSegment(Context
.Segment
);
2239 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2242 if (Context
.Private
)
2244 MmLockAddressSpace(AddressSpace
);
2245 MmLockSectionSegment(Context
.Segment
);
2246 Status
= MmCreatePageFileMapping(Process
,
2249 /* We had placed a wait entry upon entry ... replace it before leaving */
2250 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2251 MmUnlockSectionSegment(Context
.Segment
);
2252 MmUnlockAddressSpace(AddressSpace
);
2253 if (!NT_SUCCESS(Status
))
2255 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2256 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2261 MmLockAddressSpace(AddressSpace
);
2262 MmLockSectionSegment(Context
.Segment
);
2263 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2264 /* We had placed a wait entry upon entry ... replace it before leaving */
2265 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2266 MmUnlockSectionSegment(Context
.Segment
);
2267 MmUnlockAddressSpace(AddressSpace
);
2270 MiSetPageEvent(NULL
, NULL
);
2271 return(STATUS_SUCCESS
);
2276 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2277 PMEMORY_AREA MemoryArea
,
2281 LARGE_INTEGER Offset
;
2282 PROS_SECTION_OBJECT Section
;
2283 PMM_SECTION_SEGMENT Segment
;
2285 SWAPENTRY SwapEntry
;
2289 PFILE_OBJECT FileObject
;
2291 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2293 BOOLEAN DirectMapped
;
2294 BOOLEAN IsImageSection
;
2295 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2297 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2299 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2300 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2303 * Get the segment and section.
2305 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2306 Section
= MemoryArea
->Data
.SectionData
.Section
;
2307 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2309 FileObject
= Section
->FileObject
;
2310 DirectMapped
= FALSE
;
2311 if (FileObject
!= NULL
&&
2312 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2315 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2319 * If the file system is letting us go directly to the cache and the
2320 * memory area was mapped at an offset in the file which is page aligned
2321 * then note this is a direct mapped page.
2323 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2324 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2326 DirectMapped
= TRUE
;
2331 * This should never happen since mappings of physical memory are never
2332 * placed in the rmap lists.
2334 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2336 DPRINT1("Trying to write back page from physical memory mapped at %p "
2337 "process %p\n", Address
,
2338 Process
? Process
->UniqueProcessId
: 0);
2339 KeBugCheck(MEMORY_MANAGEMENT
);
2343 * Get the section segment entry and the physical address.
2345 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2346 if (!MmIsPagePresent(Process
, Address
))
2348 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2349 Process
? Process
->UniqueProcessId
: 0, Address
);
2350 KeBugCheck(MEMORY_MANAGEMENT
);
2352 Page
= MmGetPfnForProcess(Process
, Address
);
2353 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2356 * Check for a private (COWed) page.
2358 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2359 IS_SWAP_FROM_SSE(Entry
) ||
2360 PFN_FROM_SSE(Entry
) != Page
)
2370 * Speculatively set all mappings of the page to clean.
2372 MmSetCleanAllRmaps(Page
);
2375 * If this page was direct mapped from the cache then the cache manager
2376 * will take care of writing it back to disk.
2378 if (DirectMapped
&& !Private
)
2380 //LARGE_INTEGER SOffset;
2381 ASSERT(SwapEntry
== 0);
2382 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2384 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
);
2386 MmLockSectionSegment(Segment
);
2387 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2388 MmUnlockSectionSegment(Segment
);
2389 MiSetPageEvent(NULL
, NULL
);
2390 return(STATUS_SUCCESS
);
2394 * If necessary, allocate an entry in the paging file for this page
2398 SwapEntry
= MmAllocSwapPage();
2401 MmSetDirtyAllRmaps(Page
);
2402 MiSetPageEvent(NULL
, NULL
);
2403 return(STATUS_PAGEFILE_QUOTA
);
2405 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2409 * Write the page to the pagefile
2411 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2412 if (!NT_SUCCESS(Status
))
2414 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2416 MmSetDirtyAllRmaps(Page
);
2417 MiSetPageEvent(NULL
, NULL
);
2418 return(STATUS_UNSUCCESSFUL
);
2422 * Otherwise we have succeeded.
2424 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2425 MiSetPageEvent(NULL
, NULL
);
2426 return(STATUS_SUCCESS
);
2430 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2438 PMEMORY_AREA MemoryArea
;
2439 PMM_SECTION_SEGMENT Segment
;
2440 BOOLEAN DoCOW
= FALSE
;
2442 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2444 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2445 ASSERT(MemoryArea
!= NULL
);
2446 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2447 MmLockSectionSegment(Segment
);
2449 if ((Segment
->WriteCopy
) &&
2450 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2455 if (OldProtect
!= NewProtect
)
2457 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2459 SWAPENTRY SwapEntry
;
2460 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2461 ULONG Protect
= NewProtect
;
2463 /* Wait for a wait entry to disappear */
2466 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2467 if (SwapEntry
!= MM_WAIT_ENTRY
)
2469 MiWaitForPageEvent(Process
, Address
);
2474 * If we doing COW for this segment then check if the page is
2477 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2479 LARGE_INTEGER Offset
;
2483 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2484 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2485 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2487 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2488 * IS_SWAP_FROM_SSE and we'll do the right thing.
2490 Page
= MmGetPfnForProcess(Process
, Address
);
2492 Protect
= PAGE_READONLY
;
2493 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2494 IS_SWAP_FROM_SSE(Entry
) ||
2495 PFN_FROM_SSE(Entry
) != Page
)
2497 Protect
= NewProtect
;
2501 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2503 MmSetPageProtect(Process
, Address
,
2509 MmUnlockSectionSegment(Segment
);
2514 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2515 PMEMORY_AREA MemoryArea
,
2523 ULONG_PTR MaxLength
;
2525 MaxLength
= MA_GetEndingAddress(MemoryArea
) - (ULONG_PTR
)BaseAddress
;
2526 if (Length
> MaxLength
)
2527 Length
= (ULONG
)MaxLength
;
2529 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2530 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2532 ASSERT(Region
!= NULL
);
2534 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2535 Region
->Protect
!= Protect
)
2537 return STATUS_INVALID_PAGE_PROTECTION
;
2540 *OldProtect
= Region
->Protect
;
2541 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
2542 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2543 BaseAddress
, Length
, Region
->Type
, Protect
,
2544 MmAlterViewAttributes
);
2550 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2552 PMEMORY_BASIC_INFORMATION Info
,
2553 PSIZE_T ResultLength
)
2556 PVOID RegionBaseAddress
;
2557 PROS_SECTION_OBJECT Section
;
2558 PMM_SECTION_SEGMENT Segment
;
2560 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2561 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2562 Address
, &RegionBaseAddress
);
2565 return STATUS_UNSUCCESSFUL
;
2568 Section
= MemoryArea
->Data
.SectionData
.Section
;
2569 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2571 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2572 Info
->AllocationBase
= (PUCHAR
)MA_GetStartingAddress(MemoryArea
) - Segment
->Image
.VirtualAddress
;
2573 Info
->Type
= MEM_IMAGE
;
2577 Info
->AllocationBase
= (PVOID
)MA_GetStartingAddress(MemoryArea
);
2578 Info
->Type
= MEM_MAPPED
;
2580 Info
->BaseAddress
= RegionBaseAddress
;
2581 Info
->AllocationProtect
= MemoryArea
->Protect
;
2582 Info
->RegionSize
= Region
->Length
;
2583 Info
->State
= MEM_COMMIT
;
2584 Info
->Protect
= Region
->Protect
;
2586 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2587 return(STATUS_SUCCESS
);
2592 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2595 LARGE_INTEGER Offset
;
2597 SWAPENTRY SavedSwapEntry
;
2602 MmLockSectionSegment(Segment
);
2604 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2605 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2607 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2610 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2611 if (IS_SWAP_FROM_SSE(Entry
))
2613 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2617 Page
= PFN_FROM_SSE(Entry
);
2618 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2619 if (SavedSwapEntry
!= 0)
2621 MmSetSavedSwapEntryPage(Page
, 0);
2622 MmFreeSwapPage(SavedSwapEntry
);
2624 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2629 MmUnlockSectionSegment(Segment
);
2633 MmpDeleteSection(PVOID ObjectBody
)
2635 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2637 /* Check if it's an ARM3, or ReactOS section */
2638 if (!MiIsRosSectionObject(Section
))
2640 MiDeleteARM3Section(ObjectBody
);
2644 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2645 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2650 PMM_SECTION_SEGMENT SectionSegments
;
2653 * NOTE: Section->ImageSection can be NULL for short time
2654 * during the section creating. If we fail for some reason
2655 * until the image section is properly initialized we shouldn't
2656 * process further here.
2658 if (Section
->ImageSection
== NULL
)
2661 SectionSegments
= Section
->ImageSection
->Segments
;
2662 NrSegments
= Section
->ImageSection
->NrSegments
;
2664 for (i
= 0; i
< NrSegments
; i
++)
2666 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2668 MmLockSectionSegment(&SectionSegments
[i
]);
2670 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2671 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2673 MmUnlockSectionSegment(&SectionSegments
[i
]);
2676 MmpFreePageFileSegment(&SectionSegments
[i
]);
2682 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2685 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2688 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2690 DPRINT("Freeing section segment\n");
2691 Section
->Segment
= NULL
;
2692 MmFinalizeSegment(Segment
);
2696 DPRINT("RefCount %d\n", RefCount
);
2703 * NOTE: Section->Segment can be NULL for short time
2704 * during the section creating.
2706 if (Section
->Segment
== NULL
)
2709 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2711 MmpFreePageFileSegment(Section
->Segment
);
2712 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2713 ExFreePool(Section
->Segment
);
2714 Section
->Segment
= NULL
;
2718 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2721 if (Section
->FileObject
!= NULL
)
2724 CcRosDereferenceCache(Section
->FileObject
);
2726 ObDereferenceObject(Section
->FileObject
);
2727 Section
->FileObject
= NULL
;
2732 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2734 IN ACCESS_MASK GrantedAccess
,
2735 IN ULONG ProcessHandleCount
,
2736 IN ULONG SystemHandleCount
)
2738 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2744 MmCreatePhysicalMemorySection(VOID
)
2746 PROS_SECTION_OBJECT PhysSection
;
2748 OBJECT_ATTRIBUTES Obj
;
2749 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2750 LARGE_INTEGER SectionSize
;
2754 * Create the section mapping physical memory
2756 SectionSize
.QuadPart
= 0xFFFFFFFF;
2757 InitializeObjectAttributes(&Obj
,
2762 Status
= MmCreateSection((PVOID
)&PhysSection
,
2766 PAGE_EXECUTE_READWRITE
,
2770 if (!NT_SUCCESS(Status
))
2772 DPRINT1("Failed to create PhysicalMemory section\n");
2773 KeBugCheck(MEMORY_MANAGEMENT
);
2775 Status
= ObInsertObject(PhysSection
,
2781 if (!NT_SUCCESS(Status
))
2783 ObDereferenceObject(PhysSection
);
2785 ObCloseHandle(Handle
, KernelMode
);
2786 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2787 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2789 return(STATUS_SUCCESS
);
2795 MmInitSectionImplementation(VOID
)
2797 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2798 UNICODE_STRING Name
;
2800 DPRINT("Creating Section Object Type\n");
2802 /* Initialize the section based root */
2803 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2804 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2806 /* Initialize the Section object type */
2807 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2808 RtlInitUnicodeString(&Name
, L
"Section");
2809 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2810 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2811 ObjectTypeInitializer
.PoolType
= PagedPool
;
2812 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2813 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2814 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2815 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2816 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2817 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2818 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2820 MmCreatePhysicalMemorySection();
2822 return(STATUS_SUCCESS
);
2827 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2828 ACCESS_MASK DesiredAccess
,
2829 POBJECT_ATTRIBUTES ObjectAttributes
,
2830 PLARGE_INTEGER UMaximumSize
,
2831 ULONG SectionPageProtection
,
2832 ULONG AllocationAttributes
)
2834 * Create a section which is backed by the pagefile
2837 LARGE_INTEGER MaximumSize
;
2838 PROS_SECTION_OBJECT Section
;
2839 PMM_SECTION_SEGMENT Segment
;
2842 if (UMaximumSize
== NULL
)
2844 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2845 return(STATUS_INVALID_PARAMETER
);
2847 MaximumSize
= *UMaximumSize
;
2850 * Create the section
2852 Status
= ObCreateObject(ExGetPreviousMode(),
2853 MmSectionObjectType
,
2855 ExGetPreviousMode(),
2857 sizeof(ROS_SECTION_OBJECT
),
2860 (PVOID
*)(PVOID
)&Section
);
2861 if (!NT_SUCCESS(Status
))
2863 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2870 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2871 Section
->Type
= 'SC';
2872 Section
->Size
= 'TN';
2873 Section
->SectionPageProtection
= SectionPageProtection
;
2874 Section
->AllocationAttributes
= AllocationAttributes
;
2875 Section
->MaximumSize
= MaximumSize
;
2876 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2877 TAG_MM_SECTION_SEGMENT
);
2878 if (Segment
== NULL
)
2880 ObDereferenceObject(Section
);
2881 return(STATUS_NO_MEMORY
);
2883 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2884 Section
->Segment
= Segment
;
2885 Segment
->ReferenceCount
= 1;
2886 ExInitializeFastMutex(&Segment
->Lock
);
2887 Segment
->Image
.FileOffset
= 0;
2888 Segment
->Protection
= SectionPageProtection
;
2889 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2890 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2891 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2892 Segment
->WriteCopy
= FALSE
;
2893 Segment
->Image
.VirtualAddress
= 0;
2894 Segment
->Image
.Characteristics
= 0;
2895 *SectionObject
= Section
;
2896 MiInitializeSectionPageTable(Segment
);
2897 return(STATUS_SUCCESS
);
2902 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2903 ACCESS_MASK DesiredAccess
,
2904 POBJECT_ATTRIBUTES ObjectAttributes
,
2905 PLARGE_INTEGER UMaximumSize
,
2906 ULONG SectionPageProtection
,
2907 ULONG AllocationAttributes
,
2910 * Create a section backed by a data file
2913 PROS_SECTION_OBJECT Section
;
2915 LARGE_INTEGER MaximumSize
;
2916 PFILE_OBJECT FileObject
;
2917 PMM_SECTION_SEGMENT Segment
;
2919 IO_STATUS_BLOCK Iosb
;
2920 LARGE_INTEGER Offset
;
2922 FILE_STANDARD_INFORMATION FileInfo
;
2926 * Create the section
2928 Status
= ObCreateObject(ExGetPreviousMode(),
2929 MmSectionObjectType
,
2931 ExGetPreviousMode(),
2933 sizeof(ROS_SECTION_OBJECT
),
2937 if (!NT_SUCCESS(Status
))
2944 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2945 Section
->Type
= 'SC';
2946 Section
->Size
= 'TN';
2947 Section
->SectionPageProtection
= SectionPageProtection
;
2948 Section
->AllocationAttributes
= AllocationAttributes
;
2951 * Reference the file handle
2953 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2954 Status
= ObReferenceObjectByHandle(FileHandle
,
2957 ExGetPreviousMode(),
2958 (PVOID
*)(PVOID
)&FileObject
,
2960 if (!NT_SUCCESS(Status
))
2962 ObDereferenceObject(Section
);
2967 * FIXME: This is propably not entirely correct. We can't look into
2968 * the standard FCB header because it might not be initialized yet
2969 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2970 * standard file information is filled on first request).
2972 Status
= IoQueryFileInformation(FileObject
,
2973 FileStandardInformation
,
2974 sizeof(FILE_STANDARD_INFORMATION
),
2977 Iosb
.Information
= Length
;
2978 if (!NT_SUCCESS(Status
))
2980 ObDereferenceObject(Section
);
2981 ObDereferenceObject(FileObject
);
2986 * FIXME: Revise this once a locking order for file size changes is
2989 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2991 MaximumSize
= *UMaximumSize
;
2995 MaximumSize
= FileInfo
.EndOfFile
;
2996 /* Mapping zero-sized files isn't allowed. */
2997 if (MaximumSize
.QuadPart
== 0)
2999 ObDereferenceObject(Section
);
3000 ObDereferenceObject(FileObject
);
3001 return STATUS_FILE_INVALID
;
3005 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3007 Status
= IoSetInformation(FileObject
,
3008 FileAllocationInformation
,
3009 sizeof(LARGE_INTEGER
),
3011 if (!NT_SUCCESS(Status
))
3013 ObDereferenceObject(Section
);
3014 ObDereferenceObject(FileObject
);
3015 return(STATUS_SECTION_NOT_EXTENDED
);
3019 if (FileObject
->SectionObjectPointer
== NULL
||
3020 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3023 * Read a bit so caching is initiated for the file object.
3024 * This is only needed because MiReadPage currently cannot
3025 * handle non-cached streams.
3027 Offset
.QuadPart
= 0;
3028 Status
= ZwReadFile(FileHandle
,
3037 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3039 ObDereferenceObject(Section
);
3040 ObDereferenceObject(FileObject
);
3043 if (FileObject
->SectionObjectPointer
== NULL
||
3044 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3046 /* FIXME: handle this situation */
3047 ObDereferenceObject(Section
);
3048 ObDereferenceObject(FileObject
);
3049 return STATUS_INVALID_PARAMETER
;
3056 Status
= MmspWaitForFileLock(FileObject
);
3057 if (Status
!= STATUS_SUCCESS
)
3059 ObDereferenceObject(Section
);
3060 ObDereferenceObject(FileObject
);
3065 * If this file hasn't been mapped as a data file before then allocate a
3066 * section segment to describe the data file mapping
3068 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3070 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3071 TAG_MM_SECTION_SEGMENT
);
3072 if (Segment
== NULL
)
3074 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3075 ObDereferenceObject(Section
);
3076 ObDereferenceObject(FileObject
);
3077 return(STATUS_NO_MEMORY
);
3079 Section
->Segment
= Segment
;
3080 Segment
->ReferenceCount
= 1;
3081 ExInitializeFastMutex(&Segment
->Lock
);
3083 * Set the lock before assigning the segment to the file object
3085 ExAcquireFastMutex(&Segment
->Lock
);
3086 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3088 Segment
->Image
.FileOffset
= 0;
3089 Segment
->Protection
= SectionPageProtection
;
3090 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3091 Segment
->Image
.Characteristics
= 0;
3092 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3093 if (AllocationAttributes
& SEC_RESERVE
)
3095 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3099 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3100 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3102 Segment
->Image
.VirtualAddress
= 0;
3103 Segment
->Locked
= TRUE
;
3104 MiInitializeSectionPageTable(Segment
);
3109 * If the file is already mapped as a data file then we may need
3113 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3115 Section
->Segment
= Segment
;
3116 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3117 MmLockSectionSegment(Segment
);
3119 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3120 !(AllocationAttributes
& SEC_RESERVE
))
3122 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3123 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3126 MmUnlockSectionSegment(Segment
);
3127 Section
->FileObject
= FileObject
;
3128 Section
->MaximumSize
= MaximumSize
;
3130 CcRosReferenceCache(FileObject
);
3132 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3133 *SectionObject
= Section
;
3134 return(STATUS_SUCCESS
);
3138 TODO: not that great (declaring loaders statically, having to declare all of
3139 them, having to keep them extern, etc.), will fix in the future
3141 extern NTSTATUS NTAPI PeFmtCreateSection
3143 IN CONST VOID
* FileHeader
,
3144 IN SIZE_T FileHeaderSize
,
3146 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3148 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3149 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3152 extern NTSTATUS NTAPI ElfFmtCreateSection
3154 IN CONST VOID
* FileHeader
,
3155 IN SIZE_T FileHeaderSize
,
3157 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3159 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3160 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3163 /* TODO: this is a standard DDK/PSDK macro */
3164 #ifndef RTL_NUMBER_OF
3165 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3168 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3179 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3181 SIZE_T SizeOfSegments
;
3182 PMM_SECTION_SEGMENT Segments
;
3184 /* TODO: check for integer overflow */
3185 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3187 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3189 TAG_MM_SECTION_SEGMENT
);
3192 RtlZeroMemory(Segments
, SizeOfSegments
);
3200 ExeFmtpReadFile(IN PVOID File
,
3201 IN PLARGE_INTEGER Offset
,
3204 OUT PVOID
* AllocBase
,
3205 OUT PULONG ReadSize
)
3208 LARGE_INTEGER FileOffset
;
3210 ULONG OffsetAdjustment
;
3214 PFILE_OBJECT FileObject
= File
;
3215 IO_STATUS_BLOCK Iosb
;
3217 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3221 KeBugCheck(MEMORY_MANAGEMENT
);
3224 FileOffset
= *Offset
;
3226 /* Negative/special offset: it cannot be used in this context */
3227 if(FileOffset
.u
.HighPart
< 0)
3229 KeBugCheck(MEMORY_MANAGEMENT
);
3232 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3233 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3234 FileOffset
.u
.LowPart
= AdjustOffset
;
3236 BufferSize
= Length
+ OffsetAdjustment
;
3237 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3240 * It's ok to use paged pool, because this is a temporary buffer only used in
3241 * the loading of executables. The assumption is that MmCreateSection is
3242 * always called at low IRQLs and that these buffers don't survive a brief
3243 * initialization phase
3245 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3250 KeBugCheck(MEMORY_MANAGEMENT
);
3255 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3257 UsedSize
= (ULONG
)Iosb
.Information
;
3259 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3261 Status
= STATUS_IN_PAGE_ERROR
;
3262 ASSERT(!NT_SUCCESS(Status
));
3265 if(NT_SUCCESS(Status
))
3267 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3268 *AllocBase
= Buffer
;
3269 *ReadSize
= UsedSize
- OffsetAdjustment
;
3273 ExFreePoolWithTag(Buffer
, 'rXmM');
3280 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3281 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3282 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3287 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3291 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3293 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3294 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3301 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3305 MmspAssertSegmentsSorted(ImageSectionObject
);
3307 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3309 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3313 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3314 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3315 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3323 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3327 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3329 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3330 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3338 MmspCompareSegments(const void * x
,
3341 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3342 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3345 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3346 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3350 * Ensures an image section's segments are sorted in memory
3355 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3358 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3360 MmspAssertSegmentsSorted(ImageSectionObject
);
3364 qsort(ImageSectionObject
->Segments
,
3365 ImageSectionObject
->NrSegments
,
3366 sizeof(ImageSectionObject
->Segments
[0]),
3367 MmspCompareSegments
);
3373 * Ensures an image section's segments don't overlap in memory and don't have
3374 * gaps and don't have a null size. We let them map to overlapping file regions,
3375 * though - that's not necessarily an error
3380 MmspCheckSegmentBounds
3382 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3388 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3390 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3394 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3396 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3398 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3406 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3407 * page could be OK (Windows seems to be OK with them), and larger gaps
3408 * could lead to image sections spanning several discontiguous regions
3409 * (NtMapViewOfSection could then refuse to map them, and they could
3410 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3412 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3413 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3414 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3425 * Merges and pads an image section's segments until they all are page-aligned
3426 * and have a size that is a multiple of the page size
3431 MmspPageAlignSegments
3433 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3439 PMM_SECTION_SEGMENT EffectiveSegment
;
3441 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3443 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3448 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3450 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3453 * The first segment requires special handling
3457 ULONG_PTR VirtualAddress
;
3458 ULONG_PTR VirtualOffset
;
3460 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3462 /* Round down the virtual address to the nearest page */
3463 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3465 /* Round up the virtual size to the nearest page */
3466 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3467 EffectiveSegment
->Image
.VirtualAddress
;
3469 /* Adjust the raw address and size */
3470 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3472 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3478 * Garbage in, garbage out: unaligned base addresses make the file
3479 * offset point in curious and odd places, but that's what we were
3482 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3483 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3487 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3488 ULONG_PTR EndOfEffectiveSegment
;
3490 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3491 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3494 * The current segment begins exactly where the current effective
3495 * segment ended, therefore beginning a new effective segment
3497 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3500 ASSERT(LastSegment
<= i
);
3501 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3503 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3505 if (LastSegment
!= i
)
3508 * Copy the current segment. If necessary, the effective segment
3509 * will be expanded later
3511 *EffectiveSegment
= *Segment
;
3515 * Page-align the virtual size. We know for sure the virtual address
3518 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3519 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3522 * The current segment is still part of the current effective segment:
3523 * extend the effective segment to reflect this
3525 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3527 static const ULONG FlagsToProtection
[16] =
3535 PAGE_EXECUTE_READWRITE
,
3536 PAGE_EXECUTE_READWRITE
,
3541 PAGE_EXECUTE_WRITECOPY
,
3542 PAGE_EXECUTE_WRITECOPY
,
3543 PAGE_EXECUTE_WRITECOPY
,
3544 PAGE_EXECUTE_WRITECOPY
3547 unsigned ProtectionFlags
;
3550 * Extend the file size
3553 /* Unaligned segments must be contiguous within the file */
3554 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3555 EffectiveSegment
->RawLength
.QuadPart
))
3560 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3563 * Extend the virtual size
3565 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3567 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3568 EffectiveSegment
->Image
.VirtualAddress
;
3571 * Merge the protection
3573 EffectiveSegment
->Protection
|= Segment
->Protection
;
3575 /* Clean up redundance */
3576 ProtectionFlags
= 0;
3578 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3579 ProtectionFlags
|= 1 << 0;
3581 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3582 ProtectionFlags
|= 1 << 1;
3584 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3585 ProtectionFlags
|= 1 << 2;
3587 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3588 ProtectionFlags
|= 1 << 3;
3590 ASSERT(ProtectionFlags
< 16);
3591 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3593 /* If a segment was required to be shared and cannot, fail */
3594 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3595 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3601 * We assume no holes between segments at this point
3605 KeBugCheck(MEMORY_MANAGEMENT
);
3609 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3615 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3616 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3618 LARGE_INTEGER Offset
;
3620 PVOID FileHeaderBuffer
;
3621 ULONG FileHeaderSize
;
3623 ULONG OldNrSegments
;
3628 * Read the beginning of the file (2 pages). Should be enough to contain
3629 * all (or most) of the headers
3631 Offset
.QuadPart
= 0;
3633 /* FIXME: use FileObject instead of FileHandle */
3634 Status
= ExeFmtpReadFile (FileHandle
,
3641 if (!NT_SUCCESS(Status
))
3644 if (FileHeaderSize
== 0)
3646 ExFreePool(FileHeaderBuffer
);
3647 return STATUS_UNSUCCESSFUL
;
3651 * Look for a loader that can handle this executable
3653 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3655 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3658 /* FIXME: use FileObject instead of FileHandle */
3659 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3665 ExeFmtpAllocateSegments
);
3667 if (!NT_SUCCESS(Status
))
3669 if (ImageSectionObject
->Segments
)
3671 ExFreePool(ImageSectionObject
->Segments
);
3672 ImageSectionObject
->Segments
= NULL
;
3676 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3680 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3683 * No loader handled the format
3685 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3687 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3688 ASSERT(!NT_SUCCESS(Status
));
3691 if (!NT_SUCCESS(Status
))
3694 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3699 /* FIXME? are these values platform-dependent? */
3700 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3701 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3703 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3704 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3706 if(ImageSectionObject
->BasedAddress
== NULL
)
3708 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3709 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3711 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3715 * And now the fun part: fixing the segments
3718 /* Sort them by virtual address */
3719 MmspSortSegments(ImageSectionObject
, Flags
);
3721 /* Ensure they don't overlap in memory */
3722 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3723 return STATUS_INVALID_IMAGE_FORMAT
;
3725 /* Ensure they are aligned */
3726 OldNrSegments
= ImageSectionObject
->NrSegments
;
3728 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3729 return STATUS_INVALID_IMAGE_FORMAT
;
3731 /* Trim them if the alignment phase merged some of them */
3732 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3734 PMM_SECTION_SEGMENT Segments
;
3735 SIZE_T SizeOfSegments
;
3737 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3739 Segments
= ExAllocatePoolWithTag(PagedPool
,
3741 TAG_MM_SECTION_SEGMENT
);
3743 if (Segments
== NULL
)
3744 return STATUS_INSUFFICIENT_RESOURCES
;
3746 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3747 ExFreePool(ImageSectionObject
->Segments
);
3748 ImageSectionObject
->Segments
= Segments
;
3751 /* And finish their initialization */
3752 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3754 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3755 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3756 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3759 ASSERT(NT_SUCCESS(Status
));
3764 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3765 ACCESS_MASK DesiredAccess
,
3766 POBJECT_ATTRIBUTES ObjectAttributes
,
3767 PLARGE_INTEGER UMaximumSize
,
3768 ULONG SectionPageProtection
,
3769 ULONG AllocationAttributes
,
3770 PFILE_OBJECT FileObject
)
3772 PROS_SECTION_OBJECT Section
;
3774 PMM_SECTION_SEGMENT SectionSegments
;
3775 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3778 if (FileObject
== NULL
)
3779 return STATUS_INVALID_FILE_FOR_SECTION
;
3782 * Create the section
3784 Status
= ObCreateObject (ExGetPreviousMode(),
3785 MmSectionObjectType
,
3787 ExGetPreviousMode(),
3789 sizeof(ROS_SECTION_OBJECT
),
3792 (PVOID
*)(PVOID
)&Section
);
3793 if (!NT_SUCCESS(Status
))
3795 ObDereferenceObject(FileObject
);
3802 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3803 Section
->Type
= 'SC';
3804 Section
->Size
= 'TN';
3805 Section
->SectionPageProtection
= SectionPageProtection
;
3806 Section
->AllocationAttributes
= AllocationAttributes
;
3810 * Initialized caching for this file object if previously caching
3811 * was initialized for the same on disk file
3813 Status
= CcTryToInitializeFileCache(FileObject
);
3815 Status
= STATUS_SUCCESS
;
3818 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3820 NTSTATUS StatusExeFmt
;
3822 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3823 if (ImageSectionObject
== NULL
)
3825 ObDereferenceObject(FileObject
);
3826 ObDereferenceObject(Section
);
3827 return(STATUS_NO_MEMORY
);
3830 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3832 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3834 if (!NT_SUCCESS(StatusExeFmt
))
3836 if(ImageSectionObject
->Segments
!= NULL
)
3837 ExFreePool(ImageSectionObject
->Segments
);
3839 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3840 ObDereferenceObject(Section
);
3841 ObDereferenceObject(FileObject
);
3842 return(StatusExeFmt
);
3845 Section
->ImageSection
= ImageSectionObject
;
3846 ASSERT(ImageSectionObject
->Segments
);
3851 Status
= MmspWaitForFileLock(FileObject
);
3852 if (!NT_SUCCESS(Status
))
3854 ExFreePool(ImageSectionObject
->Segments
);
3855 ExFreePool(ImageSectionObject
);
3856 ObDereferenceObject(Section
);
3857 ObDereferenceObject(FileObject
);
3861 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3862 ImageSectionObject
, NULL
))
3865 * An other thread has initialized the same image in the background
3867 ExFreePool(ImageSectionObject
->Segments
);
3868 ExFreePool(ImageSectionObject
);
3869 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3870 Section
->ImageSection
= ImageSectionObject
;
3871 SectionSegments
= ImageSectionObject
->Segments
;
3873 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3875 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3879 Status
= StatusExeFmt
;
3886 Status
= MmspWaitForFileLock(FileObject
);
3887 if (Status
!= STATUS_SUCCESS
)
3889 ObDereferenceObject(Section
);
3890 ObDereferenceObject(FileObject
);
3894 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3895 Section
->ImageSection
= ImageSectionObject
;
3896 SectionSegments
= ImageSectionObject
->Segments
;
3899 * Otherwise just reference all the section segments
3901 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3903 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3906 Status
= STATUS_SUCCESS
;
3908 Section
->FileObject
= FileObject
;
3910 CcRosReferenceCache(FileObject
);
3912 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3913 *SectionObject
= Section
;
3920 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3921 PROS_SECTION_OBJECT Section
,
3922 PMM_SECTION_SEGMENT Segment
,
3927 ULONG AllocationType
)
3933 if (Segment
->WriteCopy
)
3935 /* We have to do this because the not present fault
3936 * and access fault handlers depend on the protection
3937 * that should be granted AFTER the COW fault takes
3938 * place to be in Region->Protect. The not present fault
3939 * handler changes this to the correct protection for COW when
3940 * mapping the pages into the process's address space. If a COW
3941 * fault takes place, the access fault handler sets the page protection
3942 * to these values for the newly copied pages
3944 if (Protect
== PAGE_WRITECOPY
)
3945 Protect
= PAGE_READWRITE
;
3946 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3947 Protect
= PAGE_EXECUTE_READWRITE
;
3950 if (*BaseAddress
== NULL
)
3951 Granularity
= MM_ALLOCATION_GRANULARITY
;
3953 Granularity
= PAGE_SIZE
;
3956 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3958 LARGE_INTEGER FileOffset
;
3959 FileOffset
.QuadPart
= ViewOffset
;
3960 ObReferenceObject(Section
);
3961 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3964 Status
= MmCreateMemoryArea(AddressSpace
,
3965 MEMORY_AREA_SECTION_VIEW
,
3972 if (!NT_SUCCESS(Status
))
3974 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3975 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3979 ObReferenceObject((PVOID
)Section
);
3981 MArea
->Data
.SectionData
.Segment
= Segment
;
3982 MArea
->Data
.SectionData
.Section
= Section
;
3983 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3984 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3986 MArea
->VadNode
.u
.VadFlags
.VadType
= VadImageMap
;
3989 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3990 ViewSize
, 0, Protect
);
3992 return(STATUS_SUCCESS
);
3997 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3998 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4002 PFILE_OBJECT FileObject
;
4003 PROS_SHARED_CACHE_MAP SharedCacheMap
;
4005 LARGE_INTEGER Offset
;
4006 SWAPENTRY SavedSwapEntry
;
4007 PROS_SECTION_OBJECT Section
;
4008 PMM_SECTION_SEGMENT Segment
;
4009 PMMSUPPORT AddressSpace
;
4012 AddressSpace
= (PMMSUPPORT
)Context
;
4013 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4015 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4017 Offset
.QuadPart
= ((ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)) +
4018 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
4020 Section
= MemoryArea
->Data
.SectionData
.Section
;
4021 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4023 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4024 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
4026 MmUnlockSectionSegment(Segment
);
4027 MmUnlockAddressSpace(AddressSpace
);
4029 MiWaitForPageEvent(NULL
, NULL
);
4031 MmLockAddressSpace(AddressSpace
);
4032 MmLockSectionSegment(Segment
);
4033 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4037 * For a dirty, datafile, non-private page mark it as dirty in the
4040 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4042 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4045 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4046 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4047 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4049 ASSERT(SwapEntry
== 0);
4058 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4060 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4061 KeBugCheck(MEMORY_MANAGEMENT
);
4063 MmFreeSwapPage(SwapEntry
);
4067 if (IS_SWAP_FROM_SSE(Entry
) ||
4068 Page
!= PFN_FROM_SSE(Entry
))
4073 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4075 DPRINT1("Found a private page in a pagefile section.\n");
4076 KeBugCheck(MEMORY_MANAGEMENT
);
4079 * Just dereference private pages
4081 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4082 if (SavedSwapEntry
!= 0)
4084 MmFreeSwapPage(SavedSwapEntry
);
4085 MmSetSavedSwapEntryPage(Page
, 0);
4087 MmDeleteRmap(Page
, Process
, Address
);
4088 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4092 MmDeleteRmap(Page
, Process
, Address
);
4093 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4099 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4103 PMEMORY_AREA MemoryArea
;
4104 PROS_SECTION_OBJECT Section
;
4105 PMM_SECTION_SEGMENT Segment
;
4106 PLIST_ENTRY CurrentEntry
;
4107 PMM_REGION CurrentRegion
;
4108 PLIST_ENTRY RegionListHead
;
4110 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4112 if (MemoryArea
== NULL
)
4114 return(STATUS_UNSUCCESSFUL
);
4117 Section
= MemoryArea
->Data
.SectionData
.Section
;
4118 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4121 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4123 MmUnlockAddressSpace(AddressSpace
);
4124 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4125 MmLockAddressSpace(AddressSpace
);
4131 MemoryArea
->DeleteInProgress
= TRUE
;
4133 MmLockSectionSegment(Segment
);
4135 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4136 while (!IsListEmpty(RegionListHead
))
4138 CurrentEntry
= RemoveHeadList(RegionListHead
);
4139 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4140 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4143 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4145 Status
= MmFreeMemoryArea(AddressSpace
,
4152 Status
= MmFreeMemoryArea(AddressSpace
,
4157 MmUnlockSectionSegment(Segment
);
4158 ObDereferenceObject(Section
);
4164 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4165 IN PVOID BaseAddress
,
4169 PMEMORY_AREA MemoryArea
;
4170 PMMSUPPORT AddressSpace
;
4171 PROS_SECTION_OBJECT Section
;
4172 PVOID ImageBaseAddress
= 0;
4174 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4175 Process
, BaseAddress
);
4179 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4181 MmLockAddressSpace(AddressSpace
);
4182 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4184 if (MemoryArea
== NULL
||
4185 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4186 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4187 MemoryArea
->DeleteInProgress
)
4189 if (MemoryArea
) NT_ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4190 MmUnlockAddressSpace(AddressSpace
);
4191 return STATUS_NOT_MAPPED_VIEW
;
4194 Section
= MemoryArea
->Data
.SectionData
.Section
;
4196 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4200 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4201 PMM_SECTION_SEGMENT SectionSegments
;
4202 PMM_SECTION_SEGMENT Segment
;
4204 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4205 ImageSectionObject
= Section
->ImageSection
;
4206 SectionSegments
= ImageSectionObject
->Segments
;
4207 NrSegments
= ImageSectionObject
->NrSegments
;
4209 MemoryArea
->DeleteInProgress
= TRUE
;
4211 /* Search for the current segment within the section segments
4212 * and calculate the image base address */
4213 for (i
= 0; i
< NrSegments
; i
++)
4215 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4217 if (Segment
== &SectionSegments
[i
])
4219 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4224 if (i
>= NrSegments
)
4226 KeBugCheck(MEMORY_MANAGEMENT
);
4229 for (i
= 0; i
< NrSegments
; i
++)
4231 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4233 PVOID SBaseAddress
= (PVOID
)
4234 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4236 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4237 if (!NT_SUCCESS(Status
))
4239 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4240 SBaseAddress
, Process
, Status
);
4241 NT_ASSERT(NT_SUCCESS(Status
));
4248 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4249 if (!NT_SUCCESS(Status
))
4251 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4252 BaseAddress
, Process
, Status
);
4253 NT_ASSERT(NT_SUCCESS(Status
));
4257 MmUnlockAddressSpace(AddressSpace
);
4259 /* Notify debugger */
4260 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4262 return(STATUS_SUCCESS
);
4269 * Queries the information of a section object.
4271 * @param SectionHandle
4272 * Handle to the section object. It must be opened with SECTION_QUERY
4274 * @param SectionInformationClass
4275 * Index to a certain information structure. Can be either
4276 * SectionBasicInformation or SectionImageInformation. The latter
4277 * is valid only for sections that were created with the SEC_IMAGE
4279 * @param SectionInformation
4280 * Caller supplies storage for resulting information.
4282 * Size of the supplied storage.
4283 * @param ResultLength
4291 NtQuerySection(IN HANDLE SectionHandle
,
4292 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4293 OUT PVOID SectionInformation
,
4294 IN SIZE_T SectionInformationLength
,
4295 OUT PSIZE_T ResultLength OPTIONAL
)
4297 PROS_SECTION_OBJECT Section
;
4298 KPROCESSOR_MODE PreviousMode
;
4302 PreviousMode
= ExGetPreviousMode();
4304 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4306 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4308 (ULONG
)SectionInformationLength
,
4313 if(!NT_SUCCESS(Status
))
4315 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4319 Status
= ObReferenceObjectByHandle(SectionHandle
,
4321 MmSectionObjectType
,
4323 (PVOID
*)(PVOID
)&Section
,
4325 if (NT_SUCCESS(Status
))
4327 switch (SectionInformationClass
)
4329 case SectionBasicInformation
:
4331 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4335 Sbi
->Attributes
= Section
->AllocationAttributes
;
4336 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4338 Sbi
->BaseAddress
= 0;
4339 Sbi
->Size
.QuadPart
= 0;
4343 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4344 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4347 if (ResultLength
!= NULL
)
4349 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4351 Status
= STATUS_SUCCESS
;
4353 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4355 Status
= _SEH2_GetExceptionCode();
4362 case SectionImageInformation
:
4364 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4368 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4370 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4371 ImageSectionObject
= Section
->ImageSection
;
4373 *Sii
= ImageSectionObject
->ImageInformation
;
4376 if (ResultLength
!= NULL
)
4378 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4380 Status
= STATUS_SUCCESS
;
4382 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4384 Status
= _SEH2_GetExceptionCode();
4392 ObDereferenceObject(Section
);
4398 /**********************************************************************
4400 * MmMapViewOfSection
4403 * Maps a view of a section into the virtual address space of a
4408 * Pointer to the section object.
4411 * Pointer to the process.
4414 * Desired base address (or NULL) on entry;
4415 * Actual base address of the view on exit.
4418 * Number of high order address bits that must be zero.
4421 * Size in bytes of the initially committed section of
4425 * Offset in bytes from the beginning of the section
4426 * to the beginning of the view.
4429 * Desired length of map (or zero to map all) on entry
4430 * Actual length mapped on exit.
4432 * InheritDisposition
4433 * Specified how the view is to be shared with
4437 * Type of allocation for the pages.
4440 * Protection for the committed region of the view.
4448 MmMapViewOfSection(IN PVOID SectionObject
,
4449 IN PEPROCESS Process
,
4450 IN OUT PVOID
*BaseAddress
,
4451 IN ULONG_PTR ZeroBits
,
4452 IN SIZE_T CommitSize
,
4453 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4454 IN OUT PSIZE_T ViewSize
,
4455 IN SECTION_INHERIT InheritDisposition
,
4456 IN ULONG AllocationType
,
4459 PROS_SECTION_OBJECT Section
;
4460 PMMSUPPORT AddressSpace
;
4462 NTSTATUS Status
= STATUS_SUCCESS
;
4463 BOOLEAN NotAtBase
= FALSE
;
4465 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4467 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4468 return MmMapViewOfArm3Section(SectionObject
,
4482 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4484 return STATUS_INVALID_PAGE_PROTECTION
;
4487 /* FIXME: We should keep this, but it would break code checking equality */
4488 Protect
&= ~PAGE_NOCACHE
;
4490 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4491 AddressSpace
= &Process
->Vm
;
4493 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4495 MmLockAddressSpace(AddressSpace
);
4497 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4501 ULONG_PTR ImageBase
;
4503 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4504 PMM_SECTION_SEGMENT SectionSegments
;
4506 ImageSectionObject
= Section
->ImageSection
;
4507 SectionSegments
= ImageSectionObject
->Segments
;
4508 NrSegments
= ImageSectionObject
->NrSegments
;
4510 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4513 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4517 for (i
= 0; i
< NrSegments
; i
++)
4519 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4521 ULONG_PTR MaxExtent
;
4522 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4523 SectionSegments
[i
].Length
.QuadPart
);
4524 ImageSize
= max(ImageSize
, MaxExtent
);
4528 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4530 /* Check for an illegal base address */
4531 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4532 ((ImageBase
+ ImageSize
) < ImageSize
))
4534 NT_ASSERT(*BaseAddress
== NULL
);
4535 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4536 MM_VIRTMEM_GRANULARITY
);
4539 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4541 NT_ASSERT(*BaseAddress
== NULL
);
4542 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4546 /* Check there is enough space to map the section at that point. */
4547 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4548 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4550 /* Fail if the user requested a fixed base address. */
4551 if ((*BaseAddress
) != NULL
)
4553 MmUnlockAddressSpace(AddressSpace
);
4554 return(STATUS_CONFLICTING_ADDRESSES
);
4556 /* Otherwise find a gap to map the image. */
4557 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4560 MmUnlockAddressSpace(AddressSpace
);
4561 return(STATUS_CONFLICTING_ADDRESSES
);
4563 /* Remember that we loaded image at a different base address */
4567 for (i
= 0; i
< NrSegments
; i
++)
4569 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4571 PVOID SBaseAddress
= (PVOID
)
4572 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4573 MmLockSectionSegment(&SectionSegments
[i
]);
4574 Status
= MmMapViewOfSegment(AddressSpace
,
4576 &SectionSegments
[i
],
4578 SectionSegments
[i
].Length
.LowPart
,
4579 SectionSegments
[i
].Protection
,
4582 MmUnlockSectionSegment(&SectionSegments
[i
]);
4583 if (!NT_SUCCESS(Status
))
4585 MmUnlockAddressSpace(AddressSpace
);
4591 *BaseAddress
= (PVOID
)ImageBase
;
4592 *ViewSize
= ImageSize
;
4596 /* check for write access */
4597 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4598 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4600 MmUnlockAddressSpace(AddressSpace
);
4601 return STATUS_SECTION_PROTECTION
;
4603 /* check for read access */
4604 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4605 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4607 MmUnlockAddressSpace(AddressSpace
);
4608 return STATUS_SECTION_PROTECTION
;
4610 /* check for execute access */
4611 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4612 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4614 MmUnlockAddressSpace(AddressSpace
);
4615 return STATUS_SECTION_PROTECTION
;
4618 if (SectionOffset
== NULL
)
4624 ViewOffset
= SectionOffset
->u
.LowPart
;
4627 if ((ViewOffset
% PAGE_SIZE
) != 0)
4629 MmUnlockAddressSpace(AddressSpace
);
4630 return(STATUS_MAPPED_ALIGNMENT
);
4633 if ((*ViewSize
) == 0)
4635 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4637 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4639 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4642 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4644 MmLockSectionSegment(Section
->Segment
);
4645 Status
= MmMapViewOfSegment(AddressSpace
,
4652 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4653 MmUnlockSectionSegment(Section
->Segment
);
4654 if (!NT_SUCCESS(Status
))
4656 MmUnlockAddressSpace(AddressSpace
);
4661 MmUnlockAddressSpace(AddressSpace
);
4662 NT_ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4665 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4667 Status
= STATUS_SUCCESS
;
4676 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4677 IN PLARGE_INTEGER NewFileSize
)
4679 /* Check whether an ImageSectionObject exists */
4680 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4682 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4686 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4688 PMM_SECTION_SEGMENT Segment
;
4690 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4693 if (Segment
->ReferenceCount
!= 0)
4696 CC_FILE_SIZES FileSizes
;
4698 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4701 /* Check size of file */
4702 if (SectionObjectPointer
->SharedCacheMap
)
4704 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4709 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4718 /* Check size of file */
4719 if (SectionObjectPointer
->SharedCacheMap
)
4721 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4722 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4731 /* Something must gone wrong
4732 * how can we have a Section but no
4734 DPRINT("ERROR: DataSectionObject without reference!\n");
4738 DPRINT("FIXME: didn't check for outstanding write probes\n");
4750 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4751 IN MMFLUSH_TYPE FlushType
)
4753 BOOLEAN Result
= TRUE
;
4755 PMM_SECTION_SEGMENT Segment
;
4760 case MmFlushForDelete
:
4761 if (SectionObjectPointer
->ImageSectionObject
||
4762 SectionObjectPointer
->DataSectionObject
)
4767 CcRosRemoveIfClosed(SectionObjectPointer
);
4770 case MmFlushForWrite
:
4772 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4774 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4777 if (SectionObjectPointer
->ImageSectionObject
)
4779 DPRINT1("SectionObject has ImageSection\n");
4785 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4787 DPRINT("Result %d\n", Result
);
4799 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4800 OUT PVOID
* MappedBase
,
4801 IN OUT PSIZE_T ViewSize
)
4803 PROS_SECTION_OBJECT Section
;
4804 PMMSUPPORT AddressSpace
;
4808 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4810 return MiMapViewInSystemSpace(SectionObject
,
4816 DPRINT("MmMapViewInSystemSpace() called\n");
4818 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4819 AddressSpace
= MmGetKernelAddressSpace();
4821 MmLockAddressSpace(AddressSpace
);
4824 if ((*ViewSize
) == 0)
4826 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4828 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4830 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4833 MmLockSectionSegment(Section
->Segment
);
4836 Status
= MmMapViewOfSegment(AddressSpace
,
4845 MmUnlockSectionSegment(Section
->Segment
);
4846 MmUnlockAddressSpace(AddressSpace
);
4853 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4855 PMMSUPPORT AddressSpace
;
4858 DPRINT("MmUnmapViewInSystemSpace() called\n");
4860 AddressSpace
= MmGetKernelAddressSpace();
4862 MmLockAddressSpace(AddressSpace
);
4864 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4866 MmUnlockAddressSpace(AddressSpace
);
4871 /**********************************************************************
4876 * Creates a section object.
4879 * SectionObject (OUT)
4880 * Caller supplied storage for the resulting pointer
4881 * to a SECTION_OBJECT instance;
4884 * Specifies the desired access to the section can be a
4886 * STANDARD_RIGHTS_REQUIRED |
4888 * SECTION_MAP_WRITE |
4889 * SECTION_MAP_READ |
4890 * SECTION_MAP_EXECUTE
4892 * ObjectAttributes [OPTIONAL]
4893 * Initialized attributes for the object can be used
4894 * to create a named section;
4897 * Maximizes the size of the memory section. Must be
4898 * non-NULL for a page-file backed section.
4899 * If value specified for a mapped file and the file is
4900 * not large enough, file will be extended.
4902 * SectionPageProtection
4903 * Can be a combination of:
4909 * AllocationAttributes
4910 * Can be a combination of:
4915 * Handle to a file to create a section mapped to a file
4916 * instead of a memory backed section;
4927 MmCreateSection (OUT PVOID
* Section
,
4928 IN ACCESS_MASK DesiredAccess
,
4929 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4930 IN PLARGE_INTEGER MaximumSize
,
4931 IN ULONG SectionPageProtection
,
4932 IN ULONG AllocationAttributes
,
4933 IN HANDLE FileHandle OPTIONAL
,
4934 IN PFILE_OBJECT FileObject OPTIONAL
)
4938 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4940 /* Check if an ARM3 section is being created instead */
4941 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4943 if (!(FileObject
) && !(FileHandle
))
4945 return MmCreateArm3Section(Section
,
4949 SectionPageProtection
,
4950 AllocationAttributes
&~ 1,
4956 /* Convert section flag to page flag */
4957 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4959 /* Check to make sure the protection is correct. Nt* does this already */
4960 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4961 if (Protection
== MM_INVALID_PROTECTION
)
4963 DPRINT1("Page protection is invalid\n");
4964 return STATUS_INVALID_PAGE_PROTECTION
;
4967 /* Check if this is going to be a data or image backed file section */
4968 if ((FileHandle
) || (FileObject
))
4970 /* These cannot be mapped with large pages */
4971 if (AllocationAttributes
& SEC_LARGE_PAGES
)
4973 DPRINT1("Large pages cannot be used with an image mapping\n");
4974 return STATUS_INVALID_PARAMETER_6
;
4977 /* Did the caller pass an object? */
4980 /* Reference the object directly */
4981 ObReferenceObject(FileObject
);
4985 /* Reference the file handle to get the object */
4986 Status
= ObReferenceObjectByHandle(FileHandle
,
4987 MmMakeFileAccess
[Protection
],
4989 ExGetPreviousMode(),
4990 (PVOID
*)&FileObject
,
4992 if (!NT_SUCCESS(Status
))
4994 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
5001 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
5002 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
5005 #ifndef NEWCC // A hack for initializing caching.
5006 // This is needed only in the old case.
5009 IO_STATUS_BLOCK Iosb
;
5012 LARGE_INTEGER ByteOffset
;
5013 ByteOffset
.QuadPart
= 0;
5014 Status
= ZwReadFile(FileHandle
,
5023 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5025 DPRINT1("CC failure: %lx\n", Status
);
5028 // Caching is initialized...
5032 if (AllocationAttributes
& SEC_IMAGE
)
5034 Status
= MmCreateImageSection(SectionObject
,
5038 SectionPageProtection
,
5039 AllocationAttributes
,
5043 else if (FileHandle
!= NULL
)
5045 Status
= MmCreateDataFileSection(SectionObject
,
5049 SectionPageProtection
,
5050 AllocationAttributes
,
5053 ObDereferenceObject(FileObject
);
5056 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5058 Status
= MmCreateCacheSection(SectionObject
,
5062 SectionPageProtection
,
5063 AllocationAttributes
,
5069 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5071 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5073 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5074 Status
= MmCreatePageFileSection(SectionObject
,
5078 SectionPageProtection
,
5079 AllocationAttributes
);