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
,
175 /* FUNCTIONS *****************************************************************/
180 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
181 File Format Specification", revision 6.0 (February 1999)
183 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
184 IN SIZE_T FileHeaderSize
,
186 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
188 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
189 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
192 ULONG cbFileHeaderOffsetSize
= 0;
193 ULONG cbSectionHeadersOffset
= 0;
194 ULONG cbSectionHeadersSize
;
195 ULONG cbSectionHeadersOffsetSize
= 0;
196 ULONG cbOptHeaderSize
;
197 ULONG cbHeadersSize
= 0;
198 ULONG nSectionAlignment
;
199 ULONG nFileAlignment
;
201 const IMAGE_DOS_HEADER
* pidhDosHeader
;
202 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
203 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
204 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
205 PMM_SECTION_SEGMENT pssSegments
;
206 LARGE_INTEGER lnOffset
;
208 SIZE_T nPrevVirtualEndOfSegment
= 0;
209 ULONG nFileSizeOfHeaders
= 0;
213 ASSERT(FileHeaderSize
> 0);
215 ASSERT(ImageSectionObject
);
217 ASSERT(AllocateSegmentsCb
);
219 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
221 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
223 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
226 pidhDosHeader
= FileHeader
;
229 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
231 /* image too small to be an MZ executable */
232 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
233 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
235 /* no MZ signature */
236 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
237 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
240 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
242 /* not a Windows executable */
243 if(pidhDosHeader
->e_lfanew
<= 0)
244 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
246 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
247 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
249 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
254 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
255 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
257 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
258 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
262 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
263 * need to read the header from the file
265 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
266 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
268 ULONG cbNtHeaderSize
;
272 l_ReadHeaderFromFile
:
274 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
276 /* read the header from the file */
277 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
279 if(!NT_SUCCESS(nStatus
))
281 NTSTATUS ReturnedStatus
= nStatus
;
283 /* If it attempted to read past the end of the file, it means e_lfanew is invalid */
284 if (ReturnedStatus
== STATUS_END_OF_FILE
) nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
286 DIE(("ReadFile failed, status %08X\n", ReturnedStatus
));
291 ASSERT(cbReadSize
> 0);
293 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
295 /* the buffer doesn't contain the file header */
296 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
297 DIE(("The file doesn't contain the PE file header\n"));
299 pinhNtHeader
= pData
;
301 /* object still not aligned: copy it to the beginning of the buffer */
302 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
304 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
305 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
306 pinhNtHeader
= pBuffer
;
309 /* invalid NT header */
310 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
312 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
313 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
315 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
317 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
318 DIE(("The full NT header is too large\n"));
320 /* the buffer doesn't contain the whole NT header */
321 if(cbReadSize
< cbNtHeaderSize
)
322 DIE(("The file doesn't contain the full NT header\n"));
326 ULONG cbOptHeaderOffsetSize
= 0;
328 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
330 /* don't trust an invalid NT header */
331 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
332 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
334 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
335 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
337 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
339 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
340 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
342 /* the buffer doesn't contain the whole NT header: read it from the file */
343 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
344 goto l_ReadHeaderFromFile
;
347 /* read information from the NT header */
348 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
349 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
351 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
353 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
354 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
356 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
358 switch(piohOptHeader
->Magic
)
360 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
362 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
367 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
370 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
371 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
373 /* See [1], section 3.4.2 */
374 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
376 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
377 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
379 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
380 DIE(("The section alignment is smaller than the file alignment\n"));
382 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
383 nFileAlignment
= piohOptHeader
->FileAlignment
;
385 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
386 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
390 nSectionAlignment
= PAGE_SIZE
;
391 nFileAlignment
= PAGE_SIZE
;
394 ASSERT(IsPowerOf2(nSectionAlignment
));
395 ASSERT(IsPowerOf2(nFileAlignment
));
397 switch(piohOptHeader
->Magic
)
400 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
402 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
403 ImageBase
= piohOptHeader
->ImageBase
;
405 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
406 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
408 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
409 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
411 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
412 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
414 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
416 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
418 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
419 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
421 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
422 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
426 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
428 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
429 piohOptHeader
->AddressOfEntryPoint
);
432 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
433 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
435 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
437 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
439 if (piohOptHeader
->AddressOfEntryPoint
== 0)
441 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
445 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
446 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
448 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
450 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
453 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
454 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
455 * magic to any binary.
457 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
458 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
459 * the SxS support -- at which point, duh, this should be removed.
461 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
463 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
470 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
472 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
474 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
476 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
478 ImageBase
= pioh64OptHeader
->ImageBase
;
479 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
480 DIE(("ImageBase exceeds the address space\n"));
483 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
485 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
486 DIE(("SizeOfImage exceeds the address space\n"));
488 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
491 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
493 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
494 DIE(("SizeOfStackReserve exceeds the address space\n"));
496 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
499 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
501 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
502 DIE(("SizeOfStackCommit exceeds the address space\n"));
504 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
507 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
509 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
511 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
512 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
514 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
515 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
519 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
521 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
522 pioh64OptHeader
->AddressOfEntryPoint
);
525 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
526 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
528 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
530 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
532 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
534 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
538 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
539 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
541 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
542 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
549 /* [1], section 3.4.2 */
550 if((ULONG_PTR
)ImageBase
% 0x10000)
551 DIE(("ImageBase is not aligned on a 64KB boundary"));
553 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
554 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
555 ImageSectionObject
->ImageInformation
.GpValue
= 0;
556 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
557 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
559 /* SECTION HEADERS */
560 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
562 /* see [1], section 3.3 */
563 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
564 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
567 * the additional segment is for the file's headers. They need to be present for
568 * the benefit of the dynamic loader (to locate exports, defaults for thread
569 * parameters, resources, etc.)
571 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
573 /* file offset for the section headers */
574 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
575 DIE(("Offset overflow\n"));
577 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
578 DIE(("Offset overflow\n"));
580 /* size of the section headers */
581 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
582 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
584 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
585 DIE(("Section headers too large\n"));
587 /* size of the executable's headers */
588 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
590 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
591 // DIE(("SizeOfHeaders is not aligned\n"));
593 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
594 DIE(("The section headers overflow SizeOfHeaders\n"));
596 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
598 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
599 DIE(("Overflow aligning the size of headers\n"));
606 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
607 /* WARNING: piohOptHeader IS NO LONGER USABLE */
608 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
610 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
611 pishSectionHeaders
= NULL
;
615 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
616 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
618 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
619 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
623 * the buffer doesn't contain the section headers, or the alignment is wrong:
624 * read the headers from the file
626 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
627 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
632 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
634 /* read the header from the file */
635 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
637 if(!NT_SUCCESS(nStatus
))
638 DIE(("ReadFile failed with status %08X\n", nStatus
));
642 ASSERT(cbReadSize
> 0);
644 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
646 /* the buffer doesn't contain all the section headers */
647 if(cbReadSize
< cbSectionHeadersSize
)
648 DIE(("The file doesn't contain all of the section headers\n"));
650 pishSectionHeaders
= pData
;
652 /* object still not aligned: copy it to the beginning of the buffer */
653 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
655 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
656 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
657 pishSectionHeaders
= pBuffer
;
662 /* allocate the segments */
663 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
664 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
666 if(ImageSectionObject
->Segments
== NULL
)
667 DIE(("AllocateSegments failed\n"));
669 /* initialize the headers segment */
670 pssSegments
= ImageSectionObject
->Segments
;
672 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
674 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
675 DIE(("Cannot align the size of the section headers\n"));
677 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
678 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
679 DIE(("Cannot align the size of the section headers\n"));
681 pssSegments
[0].Image
.FileOffset
= 0;
682 pssSegments
[0].Protection
= PAGE_READONLY
;
683 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
684 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
685 pssSegments
[0].Image
.VirtualAddress
= 0;
686 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
687 pssSegments
[0].WriteCopy
= TRUE
;
689 /* skip the headers segment */
692 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
694 /* convert the executable sections into segments. See also [1], section 4 */
695 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
697 ULONG nCharacteristics
;
699 /* validate the alignment */
700 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
701 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
703 /* sections must be contiguous, ordered by base address and non-overlapping */
704 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
705 DIE(("Memory gap between section %u and the previous\n", i
));
707 /* ignore explicit BSS sections */
708 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
710 /* validate the alignment */
712 /* Yes, this should be a multiple of FileAlignment, but there's
713 * stuff out there that isn't. We can cope with that
715 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
716 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
719 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
720 // DIE(("PointerToRawData[%u] is not aligned\n", i));
723 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
724 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
728 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
729 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
732 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
734 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
736 /* no explicit protection */
737 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
739 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
740 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
742 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
743 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
745 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
746 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
749 /* see table above */
750 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
751 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
753 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
754 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
756 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
758 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
759 /* FIXME: always false */
760 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
761 DIE(("Cannot align the virtual size of section %u\n", i
));
763 if(pssSegments
[i
].Length
.QuadPart
== 0)
764 DIE(("Virtual size of section %u is null\n", i
));
766 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
767 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
769 /* ensure the memory image is no larger than 4GB */
770 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
771 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
772 DIE(("The image is too large\n"));
775 if(nSectionAlignment
>= PAGE_SIZE
)
776 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
779 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
789 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
790 * ARGUMENTS: PFILE_OBJECT to wait for.
791 * RETURNS: Status of the wait.
794 MmspWaitForFileLock(PFILE_OBJECT File
)
796 return STATUS_SUCCESS
;
797 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
802 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
804 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
806 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
807 PMM_SECTION_SEGMENT SectionSegments
;
811 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
812 NrSegments
= ImageSectionObject
->NrSegments
;
813 SectionSegments
= ImageSectionObject
->Segments
;
814 for (i
= 0; i
< NrSegments
; i
++)
816 if (SectionSegments
[i
].ReferenceCount
!= 0)
818 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
819 SectionSegments
[i
].ReferenceCount
);
820 KeBugCheck(MEMORY_MANAGEMENT
);
822 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
824 ExFreePool(ImageSectionObject
->Segments
);
825 ExFreePool(ImageSectionObject
);
826 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
828 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
830 PMM_SECTION_SEGMENT Segment
;
832 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
835 if (Segment
->ReferenceCount
!= 0)
837 DPRINT1("Data segment still referenced\n");
838 KeBugCheck(MEMORY_MANAGEMENT
);
840 MmFreePageTablesSectionSegment(Segment
, NULL
);
842 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
848 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
849 PLARGE_INTEGER Offset
)
853 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
856 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
857 KeBugCheck(MEMORY_MANAGEMENT
);
859 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
861 DPRINT1("Maximum share count reached\n");
862 KeBugCheck(MEMORY_MANAGEMENT
);
864 if (IS_SWAP_FROM_SSE(Entry
))
866 KeBugCheck(MEMORY_MANAGEMENT
);
868 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
869 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
874 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
875 PMM_SECTION_SEGMENT Segment
,
876 PLARGE_INTEGER Offset
,
881 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
882 BOOLEAN IsDirectMapped
= FALSE
;
886 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
887 KeBugCheck(MEMORY_MANAGEMENT
);
889 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
891 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
892 KeBugCheck(MEMORY_MANAGEMENT
);
894 if (IS_SWAP_FROM_SSE(Entry
))
896 KeBugCheck(MEMORY_MANAGEMENT
);
898 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
900 * If we reducing the share count of this entry to zero then set the entry
901 * to zero and tell the cache the page is no longer mapped.
903 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
905 PFILE_OBJECT FileObject
;
906 SWAPENTRY SavedSwapEntry
;
909 PROS_SHARED_CACHE_MAP SharedCacheMap
;
910 BOOLEAN IsImageSection
;
911 LARGE_INTEGER FileOffset
;
913 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
914 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
917 Page
= PFN_FROM_SSE(Entry
);
918 FileObject
= Section
->FileObject
;
919 if (FileObject
!= NULL
&&
920 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
924 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
925 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
928 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
929 IsDirectMapped
= TRUE
;
931 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
.QuadPart
, Dirty
);
933 Status
= STATUS_SUCCESS
;
935 if (!NT_SUCCESS(Status
))
937 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
938 KeBugCheck(MEMORY_MANAGEMENT
);
944 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
945 if (SavedSwapEntry
== 0)
948 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
949 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
953 * Try to page out this page and set the swap entry
954 * within the section segment. There exist no rmap entry
955 * for this page. The pager thread can't page out a
956 * page without a rmap entry.
958 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
959 if (InEntry
) *InEntry
= Entry
;
960 MiSetPageEvent(NULL
, NULL
);
964 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
965 if (InEntry
) *InEntry
= 0;
966 MiSetPageEvent(NULL
, NULL
);
969 MmReleasePageMemoryConsumer(MC_USER
, Page
);
975 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
976 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
984 * We hold all locks. Nobody can do something with the current
985 * process and the current segment (also not within an other process).
988 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
989 if (!NT_SUCCESS(Status
))
991 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
992 KeBugCheck(MEMORY_MANAGEMENT
);
995 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
996 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
997 MmSetSavedSwapEntryPage(Page
, 0);
998 MiSetPageEvent(NULL
, NULL
);
1000 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1004 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1005 KeBugCheck(MEMORY_MANAGEMENT
);
1014 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1016 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1019 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1023 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1025 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1027 SharedCacheMap
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1028 Vacb
= CcRosLookupVacb(SharedCacheMap
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
);
1031 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, FALSE
, TRUE
);
1041 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1045 PVOID DestAddress
, SrcAddress
;
1047 Process
= PsGetCurrentProcess();
1048 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1049 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1050 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1052 return(STATUS_NO_MEMORY
);
1054 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1055 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1056 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1057 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1058 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1059 return(STATUS_SUCCESS
);
1065 MiReadPage(PMEMORY_AREA MemoryArea
,
1069 * FUNCTION: Read a page for a section backed memory area.
1071 * MemoryArea - Memory area to read the page for.
1072 * Offset - Offset of the page to read.
1073 * Page - Variable that receives a page contains the read data.
1076 LONGLONG BaseOffset
;
1077 LONGLONG FileOffset
;
1081 PFILE_OBJECT FileObject
;
1084 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1085 BOOLEAN IsImageSection
;
1088 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1089 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1090 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
;
1091 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1092 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1094 ASSERT(SharedCacheMap
);
1096 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1099 * If the file system is letting us go directly to the cache and the
1100 * memory area was mapped at an offset in the file which is page aligned
1101 * then get the related VACB.
1103 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1104 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1105 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1109 * Get the related VACB; we use a lower level interface than
1110 * filesystems do because it is safe for us to use an offset with an
1111 * alignment less than the file system block size.
1113 Status
= CcRosGetVacb(SharedCacheMap
,
1119 if (!NT_SUCCESS(Status
))
1126 * If the VACB isn't up to date then call the file
1127 * system to read in the data.
1129 Status
= CcReadVirtualAddress(Vacb
);
1130 if (!NT_SUCCESS(Status
))
1132 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1137 /* Probe the page, since it's PDE might not be synced */
1138 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1141 * Retrieve the page from the view that we actually want.
1143 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1144 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1146 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, TRUE
);
1153 LONGLONG VacbOffset
;
1156 * Allocate a page, this is rather complicated by the possibility
1157 * we might have to move other things out of memory
1159 MI_SET_USAGE(MI_USAGE_SECTION
);
1160 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1161 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1162 if (!NT_SUCCESS(Status
))
1166 Status
= CcRosGetVacb(SharedCacheMap
,
1172 if (!NT_SUCCESS(Status
))
1179 * If the VACB isn't up to date then call the file
1180 * system to read in the data.
1182 Status
= CcReadVirtualAddress(Vacb
);
1183 if (!NT_SUCCESS(Status
))
1185 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1190 Process
= PsGetCurrentProcess();
1191 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1192 VacbOffset
= BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
;
1193 Length
= RawLength
- SegOffset
;
1194 if (Length
<= VacbOffset
&& Length
<= PAGE_SIZE
)
1196 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1198 else if (VacbOffset
>= PAGE_SIZE
)
1200 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1204 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, VacbOffset
);
1205 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1206 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1207 Status
= CcRosGetVacb(SharedCacheMap
,
1208 FileOffset
+ VacbOffset
,
1213 if (!NT_SUCCESS(Status
))
1220 * If the VACB isn't up to date then call the file
1221 * system to read in the data.
1223 Status
= CcReadVirtualAddress(Vacb
);
1224 if (!NT_SUCCESS(Status
))
1226 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1230 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1231 if (Length
< PAGE_SIZE
)
1233 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, Length
- VacbOffset
);
1237 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, PAGE_SIZE
- VacbOffset
);
1240 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1241 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1243 return(STATUS_SUCCESS
);
1248 MiReadPage(PMEMORY_AREA MemoryArea
,
1252 * FUNCTION: Read a page for a section backed memory area.
1254 * MemoryArea - Memory area to read the page for.
1255 * Offset - Offset of the page to read.
1256 * Page - Variable that receives a page contains the read data.
1259 MM_REQUIRED_RESOURCES Resources
;
1262 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1264 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1265 Resources
.FileOffset
.QuadPart
= SegOffset
+
1266 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1267 Resources
.Consumer
= MC_USER
;
1268 Resources
.Amount
= PAGE_SIZE
;
1270 DPRINT("%S, offset 0x%x, len 0x%x, page 0x%x\n", ((PFILE_OBJECT
)Resources
.Context
)->FileName
.Buffer
, Resources
.FileOffset
.LowPart
, Resources
.Amount
, Resources
.Page
[0]);
1272 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1273 *Page
= Resources
.Page
[0];
1280 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1281 MEMORY_AREA
* MemoryArea
,
1285 LARGE_INTEGER Offset
;
1288 PROS_SECTION_OBJECT Section
;
1289 PMM_SECTION_SEGMENT Segment
;
1294 BOOLEAN HasSwapEntry
;
1296 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1297 SWAPENTRY SwapEntry
;
1300 * There is a window between taking the page fault and locking the
1301 * address space when another thread could load the page so we check
1304 if (MmIsPagePresent(Process
, Address
))
1306 return(STATUS_SUCCESS
);
1309 if (MmIsDisabledPage(Process
, Address
))
1311 return(STATUS_ACCESS_VIOLATION
);
1315 * Check for the virtual memory area being deleted.
1317 if (MemoryArea
->DeleteInProgress
)
1319 return(STATUS_UNSUCCESSFUL
);
1322 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1323 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1324 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1326 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1327 Section
= MemoryArea
->Data
.SectionData
.Section
;
1328 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1329 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1331 ASSERT(Region
!= NULL
);
1335 MmLockSectionSegment(Segment
);
1336 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1338 * Check if this page needs to be mapped COW
1340 if ((Segment
->WriteCopy
) &&
1341 (Region
->Protect
== PAGE_READWRITE
||
1342 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1344 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1348 Attributes
= Region
->Protect
;
1352 * Check if someone else is already handling this fault, if so wait
1355 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1357 MmUnlockSectionSegment(Segment
);
1358 MmUnlockAddressSpace(AddressSpace
);
1359 MiWaitForPageEvent(NULL
, NULL
);
1360 MmLockAddressSpace(AddressSpace
);
1361 DPRINT("Address 0x%p\n", Address
);
1362 return(STATUS_MM_RESTART_OPERATION
);
1365 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1369 SWAPENTRY DummyEntry
;
1372 * Is it a wait entry?
1374 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1376 if (SwapEntry
== MM_WAIT_ENTRY
)
1378 MmUnlockSectionSegment(Segment
);
1379 MmUnlockAddressSpace(AddressSpace
);
1380 MiWaitForPageEvent(NULL
, NULL
);
1381 MmLockAddressSpace(AddressSpace
);
1382 return STATUS_MM_RESTART_OPERATION
;
1386 * Must be private page we have swapped out.
1392 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1394 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1395 KeBugCheck(MEMORY_MANAGEMENT
);
1398 MmUnlockSectionSegment(Segment
);
1399 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1400 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1402 MmUnlockAddressSpace(AddressSpace
);
1403 MI_SET_USAGE(MI_USAGE_SECTION
);
1404 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1405 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1406 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1407 if (!NT_SUCCESS(Status
))
1409 KeBugCheck(MEMORY_MANAGEMENT
);
1412 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1413 if (!NT_SUCCESS(Status
))
1415 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1416 KeBugCheck(MEMORY_MANAGEMENT
);
1418 MmLockAddressSpace(AddressSpace
);
1419 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1420 Status
= MmCreateVirtualMapping(Process
,
1425 if (!NT_SUCCESS(Status
))
1427 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1428 KeBugCheck(MEMORY_MANAGEMENT
);
1433 * Store the swap entry for later use.
1435 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1438 * Add the page to the process's working set
1440 MmInsertRmap(Page
, Process
, Address
);
1442 * Finish the operation
1444 MiSetPageEvent(Process
, Address
);
1445 DPRINT("Address 0x%p\n", Address
);
1446 return(STATUS_SUCCESS
);
1450 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1452 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1454 MmUnlockSectionSegment(Segment
);
1456 * Just map the desired physical page
1458 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1459 Status
= MmCreateVirtualMappingUnsafe(Process
,
1464 if (!NT_SUCCESS(Status
))
1466 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1467 KeBugCheck(MEMORY_MANAGEMENT
);
1472 * Cleanup and release locks
1474 MiSetPageEvent(Process
, Address
);
1475 DPRINT("Address 0x%p\n", Address
);
1476 return(STATUS_SUCCESS
);
1480 * Get the entry corresponding to the offset within the section
1482 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1486 SWAPENTRY FakeSwapEntry
;
1489 * If the entry is zero (and it can't change because we have
1490 * locked the segment) then we need to load the page.
1494 * Release all our locks and read in the page from disk
1496 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1497 MmUnlockSectionSegment(Segment
);
1498 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1499 MmUnlockAddressSpace(AddressSpace
);
1501 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1502 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1503 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1505 MI_SET_USAGE(MI_USAGE_SECTION
);
1506 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1507 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1508 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1509 if (!NT_SUCCESS(Status
))
1511 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1517 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1518 if (!NT_SUCCESS(Status
))
1520 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1523 if (!NT_SUCCESS(Status
))
1526 * FIXME: What do we know in this case?
1529 * Cleanup and release locks
1531 MmLockAddressSpace(AddressSpace
);
1532 MiSetPageEvent(Process
, Address
);
1533 DPRINT("Address 0x%p\n", Address
);
1538 * Mark the offset within the section as having valid, in-memory
1541 MmLockAddressSpace(AddressSpace
);
1542 MmLockSectionSegment(Segment
);
1543 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1544 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1545 MmUnlockSectionSegment(Segment
);
1547 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1548 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1549 Page
, Process
, PAddress
, Attributes
);
1550 Status
= MmCreateVirtualMapping(Process
,
1555 if (!NT_SUCCESS(Status
))
1557 DPRINT1("Unable to create virtual mapping\n");
1558 KeBugCheck(MEMORY_MANAGEMENT
);
1560 ASSERT(MmIsPagePresent(Process
, PAddress
));
1561 MmInsertRmap(Page
, Process
, Address
);
1563 MiSetPageEvent(Process
, Address
);
1564 DPRINT("Address 0x%p\n", Address
);
1565 return(STATUS_SUCCESS
);
1567 else if (IS_SWAP_FROM_SSE(Entry
))
1569 SWAPENTRY SwapEntry
;
1571 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1574 * Release all our locks and read in the page from disk
1576 MmUnlockSectionSegment(Segment
);
1578 MmUnlockAddressSpace(AddressSpace
);
1579 MI_SET_USAGE(MI_USAGE_SECTION
);
1580 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1581 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1582 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1583 if (!NT_SUCCESS(Status
))
1585 KeBugCheck(MEMORY_MANAGEMENT
);
1588 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1589 if (!NT_SUCCESS(Status
))
1591 KeBugCheck(MEMORY_MANAGEMENT
);
1595 * Relock the address space and segment
1597 MmLockAddressSpace(AddressSpace
);
1598 MmLockSectionSegment(Segment
);
1601 * Check the entry. No one should change the status of a page
1602 * that has a pending page-in.
1604 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1605 if (Entry
!= Entry1
)
1607 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1608 KeBugCheck(MEMORY_MANAGEMENT
);
1612 * Mark the offset within the section as having valid, in-memory
1615 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1616 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1617 MmUnlockSectionSegment(Segment
);
1620 * Save the swap entry.
1622 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1623 Status
= MmCreateVirtualMapping(Process
,
1628 if (!NT_SUCCESS(Status
))
1630 DPRINT1("Unable to create virtual mapping\n");
1631 KeBugCheck(MEMORY_MANAGEMENT
);
1633 MmInsertRmap(Page
, Process
, Address
);
1634 MiSetPageEvent(Process
, Address
);
1635 DPRINT("Address 0x%p\n", Address
);
1636 return(STATUS_SUCCESS
);
1641 * If the section offset is already in-memory and valid then just
1642 * take another reference to the page
1645 Page
= PFN_FROM_SSE(Entry
);
1647 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1648 MmUnlockSectionSegment(Segment
);
1650 Status
= MmCreateVirtualMapping(Process
,
1655 if (!NT_SUCCESS(Status
))
1657 DPRINT1("Unable to create virtual mapping\n");
1658 KeBugCheck(MEMORY_MANAGEMENT
);
1660 MmInsertRmap(Page
, Process
, Address
);
1661 MiSetPageEvent(Process
, Address
);
1662 DPRINT("Address 0x%p\n", Address
);
1663 return(STATUS_SUCCESS
);
1669 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1670 MEMORY_AREA
* MemoryArea
,
1673 PMM_SECTION_SEGMENT Segment
;
1674 PROS_SECTION_OBJECT Section
;
1679 LARGE_INTEGER Offset
;
1682 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1683 SWAPENTRY SwapEntry
;
1685 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1688 * Check if the page has already been set readwrite
1690 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1692 DPRINT("Address 0x%p\n", Address
);
1693 return(STATUS_SUCCESS
);
1697 * Find the offset of the page
1699 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1700 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1701 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1703 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1704 Section
= MemoryArea
->Data
.SectionData
.Section
;
1705 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1706 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1708 ASSERT(Region
!= NULL
);
1712 MmLockSectionSegment(Segment
);
1714 OldPage
= MmGetPfnForProcess(Process
, Address
);
1715 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1717 MmUnlockSectionSegment(Segment
);
1720 * Check if we are doing COW
1722 if (!((Segment
->WriteCopy
) &&
1723 (Region
->Protect
== PAGE_READWRITE
||
1724 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1726 DPRINT("Address 0x%p\n", Address
);
1727 return(STATUS_ACCESS_VIOLATION
);
1730 if (IS_SWAP_FROM_SSE(Entry
) ||
1731 PFN_FROM_SSE(Entry
) != OldPage
)
1733 /* This is a private page. We must only change the page protection. */
1734 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1735 return(STATUS_SUCCESS
);
1739 DPRINT("OldPage == 0!\n");
1742 * Get or create a pageop
1744 MmLockSectionSegment(Segment
);
1745 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1748 * Wait for any other operations to complete
1750 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1752 MmUnlockSectionSegment(Segment
);
1753 MmUnlockAddressSpace(AddressSpace
);
1754 MiWaitForPageEvent(NULL
, NULL
);
1756 * Restart the operation
1758 MmLockAddressSpace(AddressSpace
);
1759 DPRINT("Address 0x%p\n", Address
);
1760 return(STATUS_MM_RESTART_OPERATION
);
1763 MmDeleteRmap(OldPage
, Process
, PAddress
);
1764 MmDeleteVirtualMapping(Process
, PAddress
, NULL
, NULL
);
1765 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1768 * Release locks now we have the pageop
1770 MmUnlockSectionSegment(Segment
);
1771 MmUnlockAddressSpace(AddressSpace
);
1776 MI_SET_USAGE(MI_USAGE_SECTION
);
1777 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1778 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1779 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1780 if (!NT_SUCCESS(Status
))
1782 KeBugCheck(MEMORY_MANAGEMENT
);
1788 MiCopyFromUserPage(NewPage
, OldPage
);
1790 MmLockAddressSpace(AddressSpace
);
1793 * Set the PTE to point to the new page
1795 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1796 Status
= MmCreateVirtualMapping(Process
,
1801 if (!NT_SUCCESS(Status
))
1803 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1804 KeBugCheck(MEMORY_MANAGEMENT
);
1809 * Unshare the old page.
1811 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1812 MmInsertRmap(NewPage
, Process
, PAddress
);
1813 MmLockSectionSegment(Segment
);
1814 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1815 MmUnlockSectionSegment(Segment
);
1817 MiSetPageEvent(Process
, Address
);
1818 DPRINT("Address 0x%p\n", Address
);
1819 return(STATUS_SUCCESS
);
1823 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1825 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1827 PFN_NUMBER Page
= 0;
1829 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1832 MmLockAddressSpace(&Process
->Vm
);
1835 MmDeleteVirtualMapping(Process
,
1841 PageOutContext
->WasDirty
= TRUE
;
1843 if (!PageOutContext
->Private
)
1845 MmLockSectionSegment(PageOutContext
->Segment
);
1846 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1847 PageOutContext
->Segment
,
1848 &PageOutContext
->Offset
,
1849 PageOutContext
->WasDirty
,
1851 &PageOutContext
->SectionEntry
);
1852 MmUnlockSectionSegment(PageOutContext
->Segment
);
1856 MmUnlockAddressSpace(&Process
->Vm
);
1859 if (PageOutContext
->Private
)
1861 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1867 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1868 MEMORY_AREA
* MemoryArea
,
1869 PVOID Address
, ULONG_PTR Entry
)
1872 MM_SECTION_PAGEOUT_CONTEXT Context
;
1873 SWAPENTRY SwapEntry
;
1876 ULONGLONG FileOffset
;
1877 PFILE_OBJECT FileObject
;
1878 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1879 BOOLEAN IsImageSection
;
1881 BOOLEAN DirectMapped
;
1882 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1885 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1888 * Get the segment and section.
1890 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1891 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1892 Context
.SectionEntry
= Entry
;
1893 Context
.CallingProcess
= Process
;
1895 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
1896 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1898 DirectMapped
= FALSE
;
1900 MmLockSectionSegment(Context
.Segment
);
1903 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1904 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1905 FileObject
= Context
.Section
->FileObject
;
1907 if (FileObject
!= NULL
&&
1908 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1910 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1913 * If the file system is letting us go directly to the cache and the
1914 * memory area was mapped at an offset in the file which is page aligned
1915 * then note this is a direct mapped page.
1917 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1918 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1920 DirectMapped
= TRUE
;
1927 * This should never happen since mappings of physical memory are never
1928 * placed in the rmap lists.
1930 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1932 DPRINT1("Trying to page out from physical memory section address 0x%p "
1933 "process %p\n", Address
,
1934 Process
? Process
->UniqueProcessId
: 0);
1935 KeBugCheck(MEMORY_MANAGEMENT
);
1939 * Get the section segment entry and the physical address.
1941 if (!MmIsPagePresent(Process
, Address
))
1943 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1944 Process
? Process
->UniqueProcessId
: 0, Address
);
1945 KeBugCheck(MEMORY_MANAGEMENT
);
1947 Page
= MmGetPfnForProcess(Process
, Address
);
1948 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1951 * Check the reference count to ensure this page can be paged out
1953 if (MmGetReferenceCountPage(Page
) != 1)
1955 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1956 Page
, MmGetReferenceCountPage(Page
));
1957 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1958 MmUnlockSectionSegment(Context
.Segment
);
1959 return STATUS_UNSUCCESSFUL
;
1963 * Prepare the context structure for the rmap delete call.
1965 MmUnlockSectionSegment(Context
.Segment
);
1966 Context
.WasDirty
= FALSE
;
1967 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1968 IS_SWAP_FROM_SSE(Entry
) ||
1969 PFN_FROM_SSE(Entry
) != Page
)
1971 Context
.Private
= TRUE
;
1975 Context
.Private
= FALSE
;
1979 * Take an additional reference to the page or the VACB.
1981 if (DirectMapped
&& !Context
.Private
)
1983 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
1985 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1986 KeBugCheck(MEMORY_MANAGEMENT
);
1991 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1992 MmReferencePage(Page
);
1993 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1996 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1998 /* Since we passed in a surrogate, we'll get back the page entry
1999 * state in our context. This is intended to make intermediate
2000 * decrements of share count not release the wait entry.
2002 Entry
= Context
.SectionEntry
;
2005 * If this wasn't a private page then we should have reduced the entry to
2006 * zero by deleting all the rmaps.
2008 if (!Context
.Private
&& Entry
!= 0)
2010 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2011 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2013 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2018 * If the page wasn't dirty then we can just free it as for a readonly page.
2019 * Since we unmapped all the mappings above we know it will not suddenly
2021 * If the page is from a pagefile section and has no swap entry,
2022 * we can't free the page at this point.
2024 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2025 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2027 if (Context
.Private
)
2029 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2030 Context
.WasDirty
? "dirty" : "clean", Address
);
2031 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2033 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2035 MmSetSavedSwapEntryPage(Page
, 0);
2036 MmLockSectionSegment(Context
.Segment
);
2037 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2038 MmUnlockSectionSegment(Context
.Segment
);
2039 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2040 MiSetPageEvent(NULL
, NULL
);
2041 return(STATUS_SUCCESS
);
2044 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2046 if (Context
.Private
)
2048 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2049 Context
.WasDirty
? "dirty" : "clean", Address
);
2050 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2052 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2054 MmSetSavedSwapEntryPage(Page
, 0);
2057 MmLockSectionSegment(Context
.Segment
);
2058 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2059 MmUnlockSectionSegment(Context
.Segment
);
2061 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2062 MiSetPageEvent(NULL
, NULL
);
2063 return(STATUS_SUCCESS
);
2066 else if (!Context
.Private
&& DirectMapped
)
2070 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2072 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2075 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
, FALSE
);
2077 Status
= STATUS_SUCCESS
;
2080 if (!NT_SUCCESS(Status
))
2082 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2083 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2086 MiSetPageEvent(NULL
, NULL
);
2087 return(STATUS_SUCCESS
);
2089 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2093 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2095 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2097 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2098 MiSetPageEvent(NULL
, NULL
);
2099 return(STATUS_SUCCESS
);
2101 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2103 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2104 MmSetSavedSwapEntryPage(Page
, 0);
2105 MmLockAddressSpace(AddressSpace
);
2106 Status
= MmCreatePageFileMapping(Process
,
2109 MmUnlockAddressSpace(AddressSpace
);
2110 if (!NT_SUCCESS(Status
))
2112 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2113 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2115 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2116 MiSetPageEvent(NULL
, NULL
);
2117 return(STATUS_SUCCESS
);
2121 * If necessary, allocate an entry in the paging file for this page
2125 SwapEntry
= MmAllocSwapPage();
2128 MmShowOutOfSpaceMessagePagingFile();
2129 MmLockAddressSpace(AddressSpace
);
2131 * For private pages restore the old mappings.
2133 if (Context
.Private
)
2135 Status
= MmCreateVirtualMapping(Process
,
2137 MemoryArea
->Protect
,
2140 MmSetDirtyPage(Process
, Address
);
2149 * For non-private pages if the page wasn't direct mapped then
2150 * set it back into the section segment entry so we don't loose
2151 * our copy. Otherwise it will be handled by the cache manager.
2153 Status
= MmCreateVirtualMapping(Process
,
2155 MemoryArea
->Protect
,
2158 MmSetDirtyPage(Process
, Address
);
2162 // If we got here, the previous entry should have been a wait
2163 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2164 MmLockSectionSegment(Context
.Segment
);
2165 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2166 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2167 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2168 MmUnlockSectionSegment(Context
.Segment
);
2170 MmUnlockAddressSpace(AddressSpace
);
2171 MiSetPageEvent(NULL
, NULL
);
2172 return(STATUS_PAGEFILE_QUOTA
);
2177 * Write the page to the pagefile
2179 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2180 if (!NT_SUCCESS(Status
))
2182 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2185 * As above: undo our actions.
2186 * FIXME: Also free the swap page.
2188 MmLockAddressSpace(AddressSpace
);
2189 if (Context
.Private
)
2191 Status
= MmCreateVirtualMapping(Process
,
2193 MemoryArea
->Protect
,
2196 MmSetDirtyPage(Process
, Address
);
2203 Status
= MmCreateVirtualMapping(Process
,
2205 MemoryArea
->Protect
,
2208 MmSetDirtyPage(Process
, Address
);
2212 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2213 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2215 MmUnlockAddressSpace(AddressSpace
);
2216 MiSetPageEvent(NULL
, NULL
);
2217 return(STATUS_UNSUCCESSFUL
);
2221 * Otherwise we have succeeded.
2223 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2224 MmSetSavedSwapEntryPage(Page
, 0);
2225 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2226 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2228 MmLockSectionSegment(Context
.Segment
);
2229 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2230 MmUnlockSectionSegment(Context
.Segment
);
2234 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2237 if (Context
.Private
)
2239 MmLockAddressSpace(AddressSpace
);
2240 MmLockSectionSegment(Context
.Segment
);
2241 Status
= MmCreatePageFileMapping(Process
,
2244 /* We had placed a wait entry upon entry ... replace it before leaving */
2245 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2246 MmUnlockSectionSegment(Context
.Segment
);
2247 MmUnlockAddressSpace(AddressSpace
);
2248 if (!NT_SUCCESS(Status
))
2250 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2251 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2256 MmLockAddressSpace(AddressSpace
);
2257 MmLockSectionSegment(Context
.Segment
);
2258 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2259 /* We had placed a wait entry upon entry ... replace it before leaving */
2260 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2261 MmUnlockSectionSegment(Context
.Segment
);
2262 MmUnlockAddressSpace(AddressSpace
);
2265 MiSetPageEvent(NULL
, NULL
);
2266 return(STATUS_SUCCESS
);
2271 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2272 PMEMORY_AREA MemoryArea
,
2276 LARGE_INTEGER Offset
;
2277 PROS_SECTION_OBJECT Section
;
2278 PMM_SECTION_SEGMENT Segment
;
2280 SWAPENTRY SwapEntry
;
2284 PFILE_OBJECT FileObject
;
2286 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2288 BOOLEAN DirectMapped
;
2289 BOOLEAN IsImageSection
;
2290 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2292 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2294 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2295 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2298 * Get the segment and section.
2300 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2301 Section
= MemoryArea
->Data
.SectionData
.Section
;
2302 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2304 FileObject
= Section
->FileObject
;
2305 DirectMapped
= FALSE
;
2306 if (FileObject
!= NULL
&&
2307 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2310 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2314 * If the file system is letting us go directly to the cache and the
2315 * memory area was mapped at an offset in the file which is page aligned
2316 * then note this is a direct mapped page.
2318 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2319 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2321 DirectMapped
= TRUE
;
2326 * This should never happen since mappings of physical memory are never
2327 * placed in the rmap lists.
2329 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2331 DPRINT1("Trying to write back page from physical memory mapped at %p "
2332 "process %p\n", Address
,
2333 Process
? Process
->UniqueProcessId
: 0);
2334 KeBugCheck(MEMORY_MANAGEMENT
);
2338 * Get the section segment entry and the physical address.
2340 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2341 if (!MmIsPagePresent(Process
, Address
))
2343 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2344 Process
? Process
->UniqueProcessId
: 0, Address
);
2345 KeBugCheck(MEMORY_MANAGEMENT
);
2347 Page
= MmGetPfnForProcess(Process
, Address
);
2348 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2351 * Check for a private (COWed) page.
2353 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2354 IS_SWAP_FROM_SSE(Entry
) ||
2355 PFN_FROM_SSE(Entry
) != Page
)
2365 * Speculatively set all mappings of the page to clean.
2367 MmSetCleanAllRmaps(Page
);
2370 * If this page was direct mapped from the cache then the cache manager
2371 * will take care of writing it back to disk.
2373 if (DirectMapped
&& !Private
)
2375 //LARGE_INTEGER SOffset;
2376 ASSERT(SwapEntry
== 0);
2377 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2379 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
);
2381 MmLockSectionSegment(Segment
);
2382 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2383 MmUnlockSectionSegment(Segment
);
2384 MiSetPageEvent(NULL
, NULL
);
2385 return(STATUS_SUCCESS
);
2389 * If necessary, allocate an entry in the paging file for this page
2393 SwapEntry
= MmAllocSwapPage();
2396 MmSetDirtyAllRmaps(Page
);
2397 MiSetPageEvent(NULL
, NULL
);
2398 return(STATUS_PAGEFILE_QUOTA
);
2400 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2404 * Write the page to the pagefile
2406 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2407 if (!NT_SUCCESS(Status
))
2409 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2411 MmSetDirtyAllRmaps(Page
);
2412 MiSetPageEvent(NULL
, NULL
);
2413 return(STATUS_UNSUCCESSFUL
);
2417 * Otherwise we have succeeded.
2419 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2420 MiSetPageEvent(NULL
, NULL
);
2421 return(STATUS_SUCCESS
);
2425 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2433 PMEMORY_AREA MemoryArea
;
2434 PMM_SECTION_SEGMENT Segment
;
2435 BOOLEAN DoCOW
= FALSE
;
2437 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2439 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2440 ASSERT(MemoryArea
!= NULL
);
2441 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2442 MmLockSectionSegment(Segment
);
2444 if ((Segment
->WriteCopy
) &&
2445 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2450 if (OldProtect
!= NewProtect
)
2452 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2454 SWAPENTRY SwapEntry
;
2455 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2456 ULONG Protect
= NewProtect
;
2458 /* Wait for a wait entry to disappear */
2461 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2462 if (SwapEntry
!= MM_WAIT_ENTRY
)
2464 MiWaitForPageEvent(Process
, Address
);
2469 * If we doing COW for this segment then check if the page is
2472 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2474 LARGE_INTEGER Offset
;
2478 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2479 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2480 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2482 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2483 * IS_SWAP_FROM_SSE and we'll do the right thing.
2485 Page
= MmGetPfnForProcess(Process
, Address
);
2487 Protect
= PAGE_READONLY
;
2488 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2489 IS_SWAP_FROM_SSE(Entry
) ||
2490 PFN_FROM_SSE(Entry
) != Page
)
2492 Protect
= NewProtect
;
2496 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2498 MmSetPageProtect(Process
, Address
,
2504 MmUnlockSectionSegment(Segment
);
2509 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2510 PMEMORY_AREA MemoryArea
,
2518 ULONG_PTR MaxLength
;
2520 MaxLength
= MA_GetEndingAddress(MemoryArea
) - (ULONG_PTR
)BaseAddress
;
2521 if (Length
> MaxLength
)
2522 Length
= (ULONG
)MaxLength
;
2524 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2525 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2527 ASSERT(Region
!= NULL
);
2529 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2530 Region
->Protect
!= Protect
)
2532 return STATUS_INVALID_PAGE_PROTECTION
;
2535 *OldProtect
= Region
->Protect
;
2536 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
2537 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2538 BaseAddress
, Length
, Region
->Type
, Protect
,
2539 MmAlterViewAttributes
);
2545 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2547 PMEMORY_BASIC_INFORMATION Info
,
2548 PSIZE_T ResultLength
)
2551 PVOID RegionBaseAddress
;
2552 PROS_SECTION_OBJECT Section
;
2553 PMM_SECTION_SEGMENT Segment
;
2555 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2556 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2557 Address
, &RegionBaseAddress
);
2560 return STATUS_UNSUCCESSFUL
;
2563 Section
= MemoryArea
->Data
.SectionData
.Section
;
2564 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2566 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2567 Info
->AllocationBase
= (PUCHAR
)MA_GetStartingAddress(MemoryArea
) - Segment
->Image
.VirtualAddress
;
2568 Info
->Type
= MEM_IMAGE
;
2572 Info
->AllocationBase
= (PVOID
)MA_GetStartingAddress(MemoryArea
);
2573 Info
->Type
= MEM_MAPPED
;
2575 Info
->BaseAddress
= RegionBaseAddress
;
2576 Info
->AllocationProtect
= MemoryArea
->Protect
;
2577 Info
->RegionSize
= Region
->Length
;
2578 Info
->State
= MEM_COMMIT
;
2579 Info
->Protect
= Region
->Protect
;
2581 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2582 return(STATUS_SUCCESS
);
2587 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2590 LARGE_INTEGER Offset
;
2592 SWAPENTRY SavedSwapEntry
;
2597 MmLockSectionSegment(Segment
);
2599 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2600 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2602 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2605 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2606 if (IS_SWAP_FROM_SSE(Entry
))
2608 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2612 Page
= PFN_FROM_SSE(Entry
);
2613 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2614 if (SavedSwapEntry
!= 0)
2616 MmSetSavedSwapEntryPage(Page
, 0);
2617 MmFreeSwapPage(SavedSwapEntry
);
2619 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2624 MmUnlockSectionSegment(Segment
);
2628 MmpDeleteSection(PVOID ObjectBody
)
2630 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2632 /* Check if it's an ARM3, or ReactOS section */
2633 if (!MiIsRosSectionObject(Section
))
2635 MiDeleteARM3Section(ObjectBody
);
2639 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2640 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2645 PMM_SECTION_SEGMENT SectionSegments
;
2648 * NOTE: Section->ImageSection can be NULL for short time
2649 * during the section creating. If we fail for some reason
2650 * until the image section is properly initialized we shouldn't
2651 * process further here.
2653 if (Section
->ImageSection
== NULL
)
2656 SectionSegments
= Section
->ImageSection
->Segments
;
2657 NrSegments
= Section
->ImageSection
->NrSegments
;
2659 for (i
= 0; i
< NrSegments
; i
++)
2661 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2663 MmLockSectionSegment(&SectionSegments
[i
]);
2665 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2666 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2668 MmUnlockSectionSegment(&SectionSegments
[i
]);
2671 MmpFreePageFileSegment(&SectionSegments
[i
]);
2677 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2680 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2683 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2685 DPRINT("Freeing section segment\n");
2686 Section
->Segment
= NULL
;
2687 MmFinalizeSegment(Segment
);
2691 DPRINT("RefCount %d\n", RefCount
);
2698 * NOTE: Section->Segment can be NULL for short time
2699 * during the section creating.
2701 if (Section
->Segment
== NULL
)
2704 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2706 MmpFreePageFileSegment(Section
->Segment
);
2707 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2708 ExFreePool(Section
->Segment
);
2709 Section
->Segment
= NULL
;
2713 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2716 if (Section
->FileObject
!= NULL
)
2719 CcRosDereferenceCache(Section
->FileObject
);
2721 ObDereferenceObject(Section
->FileObject
);
2722 Section
->FileObject
= NULL
;
2727 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2729 IN ACCESS_MASK GrantedAccess
,
2730 IN ULONG ProcessHandleCount
,
2731 IN ULONG SystemHandleCount
)
2733 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2739 MmCreatePhysicalMemorySection(VOID
)
2741 PROS_SECTION_OBJECT PhysSection
;
2743 OBJECT_ATTRIBUTES Obj
;
2744 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2745 LARGE_INTEGER SectionSize
;
2749 * Create the section mapping physical memory
2751 SectionSize
.QuadPart
= 0xFFFFFFFF;
2752 InitializeObjectAttributes(&Obj
,
2754 OBJ_PERMANENT
| OBJ_KERNEL_EXCLUSIVE
,
2757 Status
= MmCreateSection((PVOID
)&PhysSection
,
2761 PAGE_EXECUTE_READWRITE
,
2765 if (!NT_SUCCESS(Status
))
2767 DPRINT1("Failed to create PhysicalMemory section\n");
2768 KeBugCheck(MEMORY_MANAGEMENT
);
2770 Status
= ObInsertObject(PhysSection
,
2776 if (!NT_SUCCESS(Status
))
2778 ObDereferenceObject(PhysSection
);
2780 ObCloseHandle(Handle
, KernelMode
);
2781 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2782 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2784 return(STATUS_SUCCESS
);
2790 MmInitSectionImplementation(VOID
)
2792 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2793 UNICODE_STRING Name
;
2795 DPRINT("Creating Section Object Type\n");
2797 /* Initialize the section based root */
2798 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2799 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2801 /* Initialize the Section object type */
2802 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2803 RtlInitUnicodeString(&Name
, L
"Section");
2804 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2805 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2806 ObjectTypeInitializer
.PoolType
= PagedPool
;
2807 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2808 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2809 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2810 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2811 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2812 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2813 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2815 MmCreatePhysicalMemorySection();
2817 return(STATUS_SUCCESS
);
2822 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2823 ACCESS_MASK DesiredAccess
,
2824 POBJECT_ATTRIBUTES ObjectAttributes
,
2825 PLARGE_INTEGER UMaximumSize
,
2826 ULONG SectionPageProtection
,
2827 ULONG AllocationAttributes
)
2829 * Create a section which is backed by the pagefile
2832 LARGE_INTEGER MaximumSize
;
2833 PROS_SECTION_OBJECT Section
;
2834 PMM_SECTION_SEGMENT Segment
;
2837 if (UMaximumSize
== NULL
)
2839 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2840 return(STATUS_INVALID_PARAMETER
);
2842 MaximumSize
= *UMaximumSize
;
2845 * Create the section
2847 Status
= ObCreateObject(ExGetPreviousMode(),
2848 MmSectionObjectType
,
2850 ExGetPreviousMode(),
2852 sizeof(ROS_SECTION_OBJECT
),
2855 (PVOID
*)(PVOID
)&Section
);
2856 if (!NT_SUCCESS(Status
))
2858 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2865 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2866 Section
->Type
= 'SC';
2867 Section
->Size
= 'TN';
2868 Section
->SectionPageProtection
= SectionPageProtection
;
2869 Section
->AllocationAttributes
= AllocationAttributes
;
2870 Section
->MaximumSize
= MaximumSize
;
2871 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2872 TAG_MM_SECTION_SEGMENT
);
2873 if (Segment
== NULL
)
2875 ObDereferenceObject(Section
);
2876 return(STATUS_NO_MEMORY
);
2878 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2879 Section
->Segment
= Segment
;
2880 Segment
->ReferenceCount
= 1;
2881 ExInitializeFastMutex(&Segment
->Lock
);
2882 Segment
->Image
.FileOffset
= 0;
2883 Segment
->Protection
= SectionPageProtection
;
2884 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2885 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2886 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2887 Segment
->WriteCopy
= FALSE
;
2888 Segment
->Image
.VirtualAddress
= 0;
2889 Segment
->Image
.Characteristics
= 0;
2890 *SectionObject
= Section
;
2891 MiInitializeSectionPageTable(Segment
);
2892 return(STATUS_SUCCESS
);
2897 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2898 ACCESS_MASK DesiredAccess
,
2899 POBJECT_ATTRIBUTES ObjectAttributes
,
2900 PLARGE_INTEGER UMaximumSize
,
2901 ULONG SectionPageProtection
,
2902 ULONG AllocationAttributes
,
2905 * Create a section backed by a data file
2908 PROS_SECTION_OBJECT Section
;
2910 LARGE_INTEGER MaximumSize
;
2911 PFILE_OBJECT FileObject
;
2912 PMM_SECTION_SEGMENT Segment
;
2914 IO_STATUS_BLOCK Iosb
;
2915 LARGE_INTEGER Offset
;
2917 FILE_STANDARD_INFORMATION FileInfo
;
2921 * Create the section
2923 Status
= ObCreateObject(ExGetPreviousMode(),
2924 MmSectionObjectType
,
2926 ExGetPreviousMode(),
2928 sizeof(ROS_SECTION_OBJECT
),
2932 if (!NT_SUCCESS(Status
))
2939 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2940 Section
->Type
= 'SC';
2941 Section
->Size
= 'TN';
2942 Section
->SectionPageProtection
= SectionPageProtection
;
2943 Section
->AllocationAttributes
= AllocationAttributes
;
2946 * Reference the file handle
2948 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2949 Status
= ObReferenceObjectByHandle(FileHandle
,
2952 ExGetPreviousMode(),
2953 (PVOID
*)(PVOID
)&FileObject
,
2955 if (!NT_SUCCESS(Status
))
2957 ObDereferenceObject(Section
);
2962 * FIXME: This is propably not entirely correct. We can't look into
2963 * the standard FCB header because it might not be initialized yet
2964 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2965 * standard file information is filled on first request).
2967 Status
= IoQueryFileInformation(FileObject
,
2968 FileStandardInformation
,
2969 sizeof(FILE_STANDARD_INFORMATION
),
2972 Iosb
.Information
= Length
;
2973 if (!NT_SUCCESS(Status
))
2975 ObDereferenceObject(Section
);
2976 ObDereferenceObject(FileObject
);
2981 * FIXME: Revise this once a locking order for file size changes is
2984 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2986 MaximumSize
= *UMaximumSize
;
2990 MaximumSize
= FileInfo
.EndOfFile
;
2991 /* Mapping zero-sized files isn't allowed. */
2992 if (MaximumSize
.QuadPart
== 0)
2994 ObDereferenceObject(Section
);
2995 ObDereferenceObject(FileObject
);
2996 return STATUS_MAPPED_FILE_SIZE_ZERO
;
3000 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3002 Status
= IoSetInformation(FileObject
,
3003 FileAllocationInformation
,
3004 sizeof(LARGE_INTEGER
),
3006 if (!NT_SUCCESS(Status
))
3008 ObDereferenceObject(Section
);
3009 ObDereferenceObject(FileObject
);
3010 return(STATUS_SECTION_NOT_EXTENDED
);
3014 if (FileObject
->SectionObjectPointer
== NULL
||
3015 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3018 * Read a bit so caching is initiated for the file object.
3019 * This is only needed because MiReadPage currently cannot
3020 * handle non-cached streams.
3022 Offset
.QuadPart
= 0;
3023 Status
= ZwReadFile(FileHandle
,
3032 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3034 ObDereferenceObject(Section
);
3035 ObDereferenceObject(FileObject
);
3038 if (FileObject
->SectionObjectPointer
== NULL
||
3039 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3041 /* FIXME: handle this situation */
3042 ObDereferenceObject(Section
);
3043 ObDereferenceObject(FileObject
);
3044 return STATUS_INVALID_PARAMETER
;
3051 Status
= MmspWaitForFileLock(FileObject
);
3052 if (Status
!= STATUS_SUCCESS
)
3054 ObDereferenceObject(Section
);
3055 ObDereferenceObject(FileObject
);
3060 * If this file hasn't been mapped as a data file before then allocate a
3061 * section segment to describe the data file mapping
3063 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3065 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3066 TAG_MM_SECTION_SEGMENT
);
3067 if (Segment
== NULL
)
3069 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3070 ObDereferenceObject(Section
);
3071 ObDereferenceObject(FileObject
);
3072 return(STATUS_NO_MEMORY
);
3074 Section
->Segment
= Segment
;
3075 Segment
->ReferenceCount
= 1;
3076 ExInitializeFastMutex(&Segment
->Lock
);
3078 * Set the lock before assigning the segment to the file object
3080 ExAcquireFastMutex(&Segment
->Lock
);
3081 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3083 Segment
->Image
.FileOffset
= 0;
3084 Segment
->Protection
= SectionPageProtection
;
3085 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3086 Segment
->Image
.Characteristics
= 0;
3087 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3088 if (AllocationAttributes
& SEC_RESERVE
)
3090 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3094 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3095 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3097 Segment
->Image
.VirtualAddress
= 0;
3098 Segment
->Locked
= TRUE
;
3099 MiInitializeSectionPageTable(Segment
);
3104 * If the file is already mapped as a data file then we may need
3108 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3110 Section
->Segment
= Segment
;
3111 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3112 MmLockSectionSegment(Segment
);
3114 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3115 !(AllocationAttributes
& SEC_RESERVE
))
3117 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3118 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3121 MmUnlockSectionSegment(Segment
);
3122 Section
->FileObject
= FileObject
;
3123 Section
->MaximumSize
= MaximumSize
;
3125 CcRosReferenceCache(FileObject
);
3127 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3128 *SectionObject
= Section
;
3129 return(STATUS_SUCCESS
);
3133 TODO: not that great (declaring loaders statically, having to declare all of
3134 them, having to keep them extern, etc.), will fix in the future
3136 extern NTSTATUS NTAPI PeFmtCreateSection
3138 IN CONST VOID
* FileHeader
,
3139 IN SIZE_T FileHeaderSize
,
3141 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3143 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3144 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3147 extern NTSTATUS NTAPI ElfFmtCreateSection
3149 IN CONST VOID
* FileHeader
,
3150 IN SIZE_T FileHeaderSize
,
3152 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3154 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3155 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3158 /* TODO: this is a standard DDK/PSDK macro */
3159 #ifndef RTL_NUMBER_OF
3160 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3163 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3174 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3176 SIZE_T SizeOfSegments
;
3177 PMM_SECTION_SEGMENT Segments
;
3179 /* TODO: check for integer overflow */
3180 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3182 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3184 TAG_MM_SECTION_SEGMENT
);
3187 RtlZeroMemory(Segments
, SizeOfSegments
);
3195 ExeFmtpReadFile(IN PVOID File
,
3196 IN PLARGE_INTEGER Offset
,
3199 OUT PVOID
* AllocBase
,
3200 OUT PULONG ReadSize
)
3203 LARGE_INTEGER FileOffset
;
3205 ULONG OffsetAdjustment
;
3209 PFILE_OBJECT FileObject
= File
;
3210 IO_STATUS_BLOCK Iosb
;
3212 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3216 KeBugCheck(MEMORY_MANAGEMENT
);
3219 FileOffset
= *Offset
;
3221 /* Negative/special offset: it cannot be used in this context */
3222 if(FileOffset
.u
.HighPart
< 0)
3224 KeBugCheck(MEMORY_MANAGEMENT
);
3227 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3228 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3229 FileOffset
.u
.LowPart
= AdjustOffset
;
3231 BufferSize
= Length
+ OffsetAdjustment
;
3232 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3234 /* Flush data since we're about to perform a non-cached read */
3235 CcFlushCache(FileObject
->SectionObjectPointer
,
3241 * It's ok to use paged pool, because this is a temporary buffer only used in
3242 * the loading of executables. The assumption is that MmCreateSection is
3243 * always called at low IRQLs and that these buffers don't survive a brief
3244 * initialization phase
3246 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3251 return STATUS_INSUFFICIENT_RESOURCES
;
3256 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3258 UsedSize
= (ULONG
)Iosb
.Information
;
3260 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3262 Status
= STATUS_IN_PAGE_ERROR
;
3263 ASSERT(!NT_SUCCESS(Status
));
3266 if(NT_SUCCESS(Status
))
3268 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3269 *AllocBase
= Buffer
;
3270 *ReadSize
= UsedSize
- OffsetAdjustment
;
3274 ExFreePoolWithTag(Buffer
, 'rXmM');
3281 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3282 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3283 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3288 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3292 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3294 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3295 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3302 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3306 MmspAssertSegmentsSorted(ImageSectionObject
);
3308 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3310 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3314 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3315 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3316 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3324 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3328 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3330 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3331 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3339 MmspCompareSegments(const void * x
,
3342 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3343 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3346 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3347 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3351 * Ensures an image section's segments are sorted in memory
3356 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3359 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3361 MmspAssertSegmentsSorted(ImageSectionObject
);
3365 qsort(ImageSectionObject
->Segments
,
3366 ImageSectionObject
->NrSegments
,
3367 sizeof(ImageSectionObject
->Segments
[0]),
3368 MmspCompareSegments
);
3374 * Ensures an image section's segments don't overlap in memory and don't have
3375 * gaps and don't have a null size. We let them map to overlapping file regions,
3376 * though - that's not necessarily an error
3381 MmspCheckSegmentBounds
3383 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3389 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3391 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3395 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3397 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3399 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3407 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3408 * page could be OK (Windows seems to be OK with them), and larger gaps
3409 * could lead to image sections spanning several discontiguous regions
3410 * (NtMapViewOfSection could then refuse to map them, and they could
3411 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3413 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3414 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3415 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3426 * Merges and pads an image section's segments until they all are page-aligned
3427 * and have a size that is a multiple of the page size
3432 MmspPageAlignSegments
3434 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3440 PMM_SECTION_SEGMENT EffectiveSegment
;
3442 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3444 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3449 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3451 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3454 * The first segment requires special handling
3458 ULONG_PTR VirtualAddress
;
3459 ULONG_PTR VirtualOffset
;
3461 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3463 /* Round down the virtual address to the nearest page */
3464 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3466 /* Round up the virtual size to the nearest page */
3467 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3468 EffectiveSegment
->Image
.VirtualAddress
;
3470 /* Adjust the raw address and size */
3471 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3473 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3479 * Garbage in, garbage out: unaligned base addresses make the file
3480 * offset point in curious and odd places, but that's what we were
3483 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3484 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3488 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3489 ULONG_PTR EndOfEffectiveSegment
;
3491 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3492 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3495 * The current segment begins exactly where the current effective
3496 * segment ended, therefore beginning a new effective segment
3498 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3501 ASSERT(LastSegment
<= i
);
3502 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3504 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3506 if (LastSegment
!= i
)
3509 * Copy the current segment. If necessary, the effective segment
3510 * will be expanded later
3512 *EffectiveSegment
= *Segment
;
3516 * Page-align the virtual size. We know for sure the virtual address
3519 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3520 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3523 * The current segment is still part of the current effective segment:
3524 * extend the effective segment to reflect this
3526 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3528 static const ULONG FlagsToProtection
[16] =
3536 PAGE_EXECUTE_READWRITE
,
3537 PAGE_EXECUTE_READWRITE
,
3542 PAGE_EXECUTE_WRITECOPY
,
3543 PAGE_EXECUTE_WRITECOPY
,
3544 PAGE_EXECUTE_WRITECOPY
,
3545 PAGE_EXECUTE_WRITECOPY
3548 unsigned ProtectionFlags
;
3551 * Extend the file size
3554 /* Unaligned segments must be contiguous within the file */
3555 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3556 EffectiveSegment
->RawLength
.QuadPart
))
3561 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3564 * Extend the virtual size
3566 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3568 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3569 EffectiveSegment
->Image
.VirtualAddress
;
3572 * Merge the protection
3574 EffectiveSegment
->Protection
|= Segment
->Protection
;
3576 /* Clean up redundance */
3577 ProtectionFlags
= 0;
3579 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3580 ProtectionFlags
|= 1 << 0;
3582 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3583 ProtectionFlags
|= 1 << 1;
3585 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3586 ProtectionFlags
|= 1 << 2;
3588 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3589 ProtectionFlags
|= 1 << 3;
3591 ASSERT(ProtectionFlags
< 16);
3592 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3594 /* If a segment was required to be shared and cannot, fail */
3595 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3596 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3602 * We assume no holes between segments at this point
3606 KeBugCheck(MEMORY_MANAGEMENT
);
3610 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3616 ExeFmtpCreateImageSection(PFILE_OBJECT FileObject
,
3617 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3619 LARGE_INTEGER Offset
;
3621 PVOID FileHeaderBuffer
;
3622 ULONG FileHeaderSize
;
3624 ULONG OldNrSegments
;
3629 * Read the beginning of the file (2 pages). Should be enough to contain
3630 * all (or most) of the headers
3632 Offset
.QuadPart
= 0;
3634 Status
= ExeFmtpReadFile (FileObject
,
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 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3664 ExeFmtpAllocateSegments
);
3666 if (!NT_SUCCESS(Status
))
3668 if (ImageSectionObject
->Segments
)
3670 ExFreePool(ImageSectionObject
->Segments
);
3671 ImageSectionObject
->Segments
= NULL
;
3675 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3679 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3682 * No loader handled the format
3684 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3686 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3687 ASSERT(!NT_SUCCESS(Status
));
3690 if (!NT_SUCCESS(Status
))
3693 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3698 /* FIXME? are these values platform-dependent? */
3699 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3700 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3702 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3703 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3705 if(ImageSectionObject
->BasedAddress
== NULL
)
3707 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3708 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3710 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3714 * And now the fun part: fixing the segments
3717 /* Sort them by virtual address */
3718 MmspSortSegments(ImageSectionObject
, Flags
);
3720 /* Ensure they don't overlap in memory */
3721 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3722 return STATUS_INVALID_IMAGE_FORMAT
;
3724 /* Ensure they are aligned */
3725 OldNrSegments
= ImageSectionObject
->NrSegments
;
3727 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3728 return STATUS_INVALID_IMAGE_FORMAT
;
3730 /* Trim them if the alignment phase merged some of them */
3731 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3733 PMM_SECTION_SEGMENT Segments
;
3734 SIZE_T SizeOfSegments
;
3736 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3738 Segments
= ExAllocatePoolWithTag(PagedPool
,
3740 TAG_MM_SECTION_SEGMENT
);
3742 if (Segments
== NULL
)
3743 return STATUS_INSUFFICIENT_RESOURCES
;
3745 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3746 ExFreePool(ImageSectionObject
->Segments
);
3747 ImageSectionObject
->Segments
= Segments
;
3750 /* And finish their initialization */
3751 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3753 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3754 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3755 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3758 ASSERT(NT_SUCCESS(Status
));
3763 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3764 ACCESS_MASK DesiredAccess
,
3765 POBJECT_ATTRIBUTES ObjectAttributes
,
3766 PLARGE_INTEGER UMaximumSize
,
3767 ULONG SectionPageProtection
,
3768 ULONG AllocationAttributes
,
3769 PFILE_OBJECT FileObject
)
3771 PROS_SECTION_OBJECT Section
;
3773 PMM_SECTION_SEGMENT SectionSegments
;
3774 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3777 if (FileObject
== NULL
)
3778 return STATUS_INVALID_FILE_FOR_SECTION
;
3781 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3783 DPRINT1("Denying section creation due to missing cache initialization\n");
3784 return STATUS_INVALID_FILE_FOR_SECTION
;
3789 * Create the section
3791 Status
= ObCreateObject (ExGetPreviousMode(),
3792 MmSectionObjectType
,
3794 ExGetPreviousMode(),
3796 sizeof(ROS_SECTION_OBJECT
),
3799 (PVOID
*)(PVOID
)&Section
);
3800 if (!NT_SUCCESS(Status
))
3802 ObDereferenceObject(FileObject
);
3809 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3810 Section
->Type
= 'SC';
3811 Section
->Size
= 'TN';
3812 Section
->SectionPageProtection
= SectionPageProtection
;
3813 Section
->AllocationAttributes
= AllocationAttributes
;
3817 * Initialized caching for this file object if previously caching
3818 * was initialized for the same on disk file
3820 Status
= CcTryToInitializeFileCache(FileObject
);
3822 Status
= STATUS_SUCCESS
;
3825 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3827 NTSTATUS StatusExeFmt
;
3829 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3830 if (ImageSectionObject
== NULL
)
3832 ObDereferenceObject(FileObject
);
3833 ObDereferenceObject(Section
);
3834 return(STATUS_NO_MEMORY
);
3837 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3839 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3841 if (!NT_SUCCESS(StatusExeFmt
))
3843 if(ImageSectionObject
->Segments
!= NULL
)
3844 ExFreePool(ImageSectionObject
->Segments
);
3846 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3847 ObDereferenceObject(Section
);
3848 ObDereferenceObject(FileObject
);
3849 return(StatusExeFmt
);
3852 Section
->ImageSection
= ImageSectionObject
;
3853 ASSERT(ImageSectionObject
->Segments
);
3858 Status
= MmspWaitForFileLock(FileObject
);
3859 if (!NT_SUCCESS(Status
))
3861 ExFreePool(ImageSectionObject
->Segments
);
3862 ExFreePool(ImageSectionObject
);
3863 ObDereferenceObject(Section
);
3864 ObDereferenceObject(FileObject
);
3868 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3869 ImageSectionObject
, NULL
))
3872 * An other thread has initialized the same image in the background
3874 ExFreePool(ImageSectionObject
->Segments
);
3875 ExFreePool(ImageSectionObject
);
3876 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3877 Section
->ImageSection
= ImageSectionObject
;
3878 SectionSegments
= ImageSectionObject
->Segments
;
3880 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3882 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3886 Status
= StatusExeFmt
;
3893 Status
= MmspWaitForFileLock(FileObject
);
3894 if (Status
!= STATUS_SUCCESS
)
3896 ObDereferenceObject(Section
);
3897 ObDereferenceObject(FileObject
);
3901 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3902 Section
->ImageSection
= ImageSectionObject
;
3903 SectionSegments
= ImageSectionObject
->Segments
;
3906 * Otherwise just reference all the section segments
3908 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3910 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3913 Status
= STATUS_SUCCESS
;
3915 Section
->FileObject
= FileObject
;
3917 CcRosReferenceCache(FileObject
);
3919 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3920 *SectionObject
= Section
;
3927 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3928 PROS_SECTION_OBJECT Section
,
3929 PMM_SECTION_SEGMENT Segment
,
3934 ULONG AllocationType
)
3940 if (Segment
->WriteCopy
)
3942 /* We have to do this because the not present fault
3943 * and access fault handlers depend on the protection
3944 * that should be granted AFTER the COW fault takes
3945 * place to be in Region->Protect. The not present fault
3946 * handler changes this to the correct protection for COW when
3947 * mapping the pages into the process's address space. If a COW
3948 * fault takes place, the access fault handler sets the page protection
3949 * to these values for the newly copied pages
3951 if (Protect
== PAGE_WRITECOPY
)
3952 Protect
= PAGE_READWRITE
;
3953 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3954 Protect
= PAGE_EXECUTE_READWRITE
;
3957 if (*BaseAddress
== NULL
)
3958 Granularity
= MM_ALLOCATION_GRANULARITY
;
3960 Granularity
= PAGE_SIZE
;
3963 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3965 LARGE_INTEGER FileOffset
;
3966 FileOffset
.QuadPart
= ViewOffset
;
3967 ObReferenceObject(Section
);
3968 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3971 Status
= MmCreateMemoryArea(AddressSpace
,
3972 MEMORY_AREA_SECTION_VIEW
,
3979 if (!NT_SUCCESS(Status
))
3981 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3982 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3986 ObReferenceObject((PVOID
)Section
);
3988 MArea
->Data
.SectionData
.Segment
= Segment
;
3989 MArea
->Data
.SectionData
.Section
= Section
;
3990 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3991 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3993 MArea
->VadNode
.u
.VadFlags
.VadType
= VadImageMap
;
3996 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3997 ViewSize
, 0, Protect
);
3999 return(STATUS_SUCCESS
);
4004 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
4005 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4009 PFILE_OBJECT FileObject
;
4010 PROS_SHARED_CACHE_MAP SharedCacheMap
;
4012 LARGE_INTEGER Offset
;
4013 SWAPENTRY SavedSwapEntry
;
4014 PROS_SECTION_OBJECT Section
;
4015 PMM_SECTION_SEGMENT Segment
;
4016 PMMSUPPORT AddressSpace
;
4019 AddressSpace
= (PMMSUPPORT
)Context
;
4020 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4022 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4024 Offset
.QuadPart
= ((ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)) +
4025 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
4027 Section
= MemoryArea
->Data
.SectionData
.Section
;
4028 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4030 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4031 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
4033 MmUnlockSectionSegment(Segment
);
4034 MmUnlockAddressSpace(AddressSpace
);
4036 MiWaitForPageEvent(NULL
, NULL
);
4038 MmLockAddressSpace(AddressSpace
);
4039 MmLockSectionSegment(Segment
);
4040 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4044 * For a dirty, datafile, non-private page mark it as dirty in the
4047 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4049 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4052 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4053 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4054 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4056 ASSERT(SwapEntry
== 0);
4065 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4067 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4068 KeBugCheck(MEMORY_MANAGEMENT
);
4070 MmFreeSwapPage(SwapEntry
);
4074 if (IS_SWAP_FROM_SSE(Entry
) ||
4075 Page
!= PFN_FROM_SSE(Entry
))
4080 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4082 DPRINT1("Found a private page in a pagefile section.\n");
4083 KeBugCheck(MEMORY_MANAGEMENT
);
4086 * Just dereference private pages
4088 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4089 if (SavedSwapEntry
!= 0)
4091 MmFreeSwapPage(SavedSwapEntry
);
4092 MmSetSavedSwapEntryPage(Page
, 0);
4094 MmDeleteRmap(Page
, Process
, Address
);
4095 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4099 MmDeleteRmap(Page
, Process
, Address
);
4100 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4106 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4110 PMEMORY_AREA MemoryArea
;
4111 PROS_SECTION_OBJECT Section
;
4112 PMM_SECTION_SEGMENT Segment
;
4113 PLIST_ENTRY CurrentEntry
;
4114 PMM_REGION CurrentRegion
;
4115 PLIST_ENTRY RegionListHead
;
4117 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4119 if (MemoryArea
== NULL
)
4121 return(STATUS_UNSUCCESSFUL
);
4124 Section
= MemoryArea
->Data
.SectionData
.Section
;
4125 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4128 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4130 MmUnlockAddressSpace(AddressSpace
);
4131 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4132 MmLockAddressSpace(AddressSpace
);
4138 MemoryArea
->DeleteInProgress
= TRUE
;
4140 MmLockSectionSegment(Segment
);
4142 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4143 while (!IsListEmpty(RegionListHead
))
4145 CurrentEntry
= RemoveHeadList(RegionListHead
);
4146 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4147 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4150 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4152 Status
= MmFreeMemoryArea(AddressSpace
,
4159 Status
= MmFreeMemoryArea(AddressSpace
,
4164 MmUnlockSectionSegment(Segment
);
4165 ObDereferenceObject(Section
);
4171 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4172 IN PVOID BaseAddress
,
4176 PMEMORY_AREA MemoryArea
;
4177 PMMSUPPORT AddressSpace
;
4178 PROS_SECTION_OBJECT Section
;
4179 PVOID ImageBaseAddress
= 0;
4181 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4182 Process
, BaseAddress
);
4186 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4188 MmLockAddressSpace(AddressSpace
);
4189 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4191 if (MemoryArea
== NULL
||
4192 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4193 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4194 MemoryArea
->DeleteInProgress
)
4196 if (MemoryArea
) ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4197 MmUnlockAddressSpace(AddressSpace
);
4198 return STATUS_NOT_MAPPED_VIEW
;
4201 Section
= MemoryArea
->Data
.SectionData
.Section
;
4203 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4207 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4208 PMM_SECTION_SEGMENT SectionSegments
;
4209 PMM_SECTION_SEGMENT Segment
;
4211 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4212 ImageSectionObject
= Section
->ImageSection
;
4213 SectionSegments
= ImageSectionObject
->Segments
;
4214 NrSegments
= ImageSectionObject
->NrSegments
;
4216 MemoryArea
->DeleteInProgress
= TRUE
;
4218 /* Search for the current segment within the section segments
4219 * and calculate the image base address */
4220 for (i
= 0; i
< NrSegments
; i
++)
4222 if (Segment
== &SectionSegments
[i
])
4224 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4228 if (i
>= NrSegments
)
4230 KeBugCheck(MEMORY_MANAGEMENT
);
4233 for (i
= 0; i
< NrSegments
; i
++)
4235 PVOID SBaseAddress
= (PVOID
)
4236 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4238 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4239 if (!NT_SUCCESS(Status
))
4241 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4242 SBaseAddress
, Process
, Status
);
4243 ASSERT(NT_SUCCESS(Status
));
4249 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4250 if (!NT_SUCCESS(Status
))
4252 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4253 BaseAddress
, Process
, Status
);
4254 ASSERT(NT_SUCCESS(Status
));
4258 MmUnlockAddressSpace(AddressSpace
);
4260 /* Notify debugger */
4261 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4263 return(STATUS_SUCCESS
);
4270 * Queries the information of a section object.
4272 * @param SectionHandle
4273 * Handle to the section object. It must be opened with SECTION_QUERY
4275 * @param SectionInformationClass
4276 * Index to a certain information structure. Can be either
4277 * SectionBasicInformation or SectionImageInformation. The latter
4278 * is valid only for sections that were created with the SEC_IMAGE
4280 * @param SectionInformation
4281 * Caller supplies storage for resulting information.
4283 * Size of the supplied storage.
4284 * @param ResultLength
4294 _In_ HANDLE SectionHandle
,
4295 _In_ SECTION_INFORMATION_CLASS SectionInformationClass
,
4296 _Out_ PVOID SectionInformation
,
4297 _In_ SIZE_T SectionInformationLength
,
4298 _Out_opt_ PSIZE_T ResultLength
)
4300 PROS_SECTION_OBJECT Section
;
4301 KPROCESSOR_MODE PreviousMode
;
4305 PreviousMode
= ExGetPreviousMode();
4306 if (PreviousMode
!= KernelMode
)
4310 ProbeForWrite(SectionInformation
,
4311 SectionInformationLength
,
4313 if (ResultLength
!= NULL
)
4315 ProbeForWrite(ResultLength
,
4316 sizeof(*ResultLength
),
4320 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4322 return _SEH2_GetExceptionCode();
4327 if (SectionInformationClass
== SectionBasicInformation
)
4329 if (SectionInformationLength
< sizeof(SECTION_BASIC_INFORMATION
))
4331 return STATUS_INFO_LENGTH_MISMATCH
;
4334 else if (SectionInformationClass
== SectionImageInformation
)
4336 if (SectionInformationLength
< sizeof(SECTION_IMAGE_INFORMATION
))
4338 return STATUS_INFO_LENGTH_MISMATCH
;
4343 return STATUS_INVALID_INFO_CLASS
;
4346 Status
= ObReferenceObjectByHandle(SectionHandle
,
4348 MmSectionObjectType
,
4350 (PVOID
*)(PVOID
)&Section
,
4352 if (!NT_SUCCESS(Status
))
4354 DPRINT1("Failed to reference section: 0x%lx\n", Status
);
4358 switch (SectionInformationClass
)
4360 case SectionBasicInformation
:
4362 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4366 Sbi
->Attributes
= Section
->AllocationAttributes
;
4367 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4369 Sbi
->BaseAddress
= 0;
4370 Sbi
->Size
.QuadPart
= 0;
4374 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4375 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4378 if (ResultLength
!= NULL
)
4380 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4382 Status
= STATUS_SUCCESS
;
4384 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4386 Status
= _SEH2_GetExceptionCode();
4393 case SectionImageInformation
:
4395 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4399 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4401 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4402 ImageSectionObject
= Section
->ImageSection
;
4404 *Sii
= ImageSectionObject
->ImageInformation
;
4407 if (ResultLength
!= NULL
)
4409 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4411 Status
= STATUS_SUCCESS
;
4413 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4415 Status
= _SEH2_GetExceptionCode();
4423 ObDereferenceObject(Section
);
4428 /**********************************************************************
4430 * MmMapViewOfSection
4433 * Maps a view of a section into the virtual address space of a
4438 * Pointer to the section object.
4441 * Pointer to the process.
4444 * Desired base address (or NULL) on entry;
4445 * Actual base address of the view on exit.
4448 * Number of high order address bits that must be zero.
4451 * Size in bytes of the initially committed section of
4455 * Offset in bytes from the beginning of the section
4456 * to the beginning of the view.
4459 * Desired length of map (or zero to map all) on entry
4460 * Actual length mapped on exit.
4462 * InheritDisposition
4463 * Specified how the view is to be shared with
4467 * Type of allocation for the pages.
4470 * Protection for the committed region of the view.
4478 MmMapViewOfSection(IN PVOID SectionObject
,
4479 IN PEPROCESS Process
,
4480 IN OUT PVOID
*BaseAddress
,
4481 IN ULONG_PTR ZeroBits
,
4482 IN SIZE_T CommitSize
,
4483 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4484 IN OUT PSIZE_T ViewSize
,
4485 IN SECTION_INHERIT InheritDisposition
,
4486 IN ULONG AllocationType
,
4489 PROS_SECTION_OBJECT Section
;
4490 PMMSUPPORT AddressSpace
;
4492 NTSTATUS Status
= STATUS_SUCCESS
;
4493 BOOLEAN NotAtBase
= FALSE
;
4495 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4497 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4498 return MmMapViewOfArm3Section(SectionObject
,
4512 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4514 return STATUS_INVALID_PAGE_PROTECTION
;
4517 /* FIXME: We should keep this, but it would break code checking equality */
4518 Protect
&= ~PAGE_NOCACHE
;
4520 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4521 AddressSpace
= &Process
->Vm
;
4523 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4525 MmLockAddressSpace(AddressSpace
);
4527 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4531 ULONG_PTR ImageBase
;
4533 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4534 PMM_SECTION_SEGMENT SectionSegments
;
4536 ImageSectionObject
= Section
->ImageSection
;
4537 SectionSegments
= ImageSectionObject
->Segments
;
4538 NrSegments
= ImageSectionObject
->NrSegments
;
4540 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4543 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4547 for (i
= 0; i
< NrSegments
; i
++)
4549 ULONG_PTR MaxExtent
;
4550 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4551 SectionSegments
[i
].Length
.QuadPart
);
4552 ImageSize
= max(ImageSize
, MaxExtent
);
4555 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4557 /* Check for an illegal base address */
4558 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4559 ((ImageBase
+ ImageSize
) < ImageSize
))
4561 ASSERT(*BaseAddress
== NULL
);
4562 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4563 MM_VIRTMEM_GRANULARITY
);
4566 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4568 ASSERT(*BaseAddress
== NULL
);
4569 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4573 /* Check there is enough space to map the section at that point. */
4574 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4575 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4577 /* Fail if the user requested a fixed base address. */
4578 if ((*BaseAddress
) != NULL
)
4580 MmUnlockAddressSpace(AddressSpace
);
4581 return(STATUS_CONFLICTING_ADDRESSES
);
4583 /* Otherwise find a gap to map the image. */
4584 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4587 MmUnlockAddressSpace(AddressSpace
);
4588 return(STATUS_CONFLICTING_ADDRESSES
);
4590 /* Remember that we loaded image at a different base address */
4594 for (i
= 0; i
< NrSegments
; i
++)
4596 PVOID SBaseAddress
= (PVOID
)
4597 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4598 MmLockSectionSegment(&SectionSegments
[i
]);
4599 Status
= MmMapViewOfSegment(AddressSpace
,
4601 &SectionSegments
[i
],
4603 SectionSegments
[i
].Length
.LowPart
,
4604 SectionSegments
[i
].Protection
,
4607 MmUnlockSectionSegment(&SectionSegments
[i
]);
4608 if (!NT_SUCCESS(Status
))
4610 MmUnlockAddressSpace(AddressSpace
);
4615 *BaseAddress
= (PVOID
)ImageBase
;
4616 *ViewSize
= ImageSize
;
4620 /* check for write access */
4621 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4622 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4624 MmUnlockAddressSpace(AddressSpace
);
4625 return STATUS_SECTION_PROTECTION
;
4627 /* check for read access */
4628 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4629 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4631 MmUnlockAddressSpace(AddressSpace
);
4632 return STATUS_SECTION_PROTECTION
;
4634 /* check for execute access */
4635 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4636 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4638 MmUnlockAddressSpace(AddressSpace
);
4639 return STATUS_SECTION_PROTECTION
;
4642 if (SectionOffset
== NULL
)
4648 ViewOffset
= SectionOffset
->u
.LowPart
;
4651 if ((ViewOffset
% PAGE_SIZE
) != 0)
4653 MmUnlockAddressSpace(AddressSpace
);
4654 return(STATUS_MAPPED_ALIGNMENT
);
4657 if ((*ViewSize
) == 0)
4659 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4661 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4663 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4666 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4668 MmLockSectionSegment(Section
->Segment
);
4669 Status
= MmMapViewOfSegment(AddressSpace
,
4676 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4677 MmUnlockSectionSegment(Section
->Segment
);
4678 if (!NT_SUCCESS(Status
))
4680 MmUnlockAddressSpace(AddressSpace
);
4685 MmUnlockAddressSpace(AddressSpace
);
4686 ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4689 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4691 Status
= STATUS_SUCCESS
;
4700 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4701 IN PLARGE_INTEGER NewFileSize
)
4703 /* Check whether an ImageSectionObject exists */
4704 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4706 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4710 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4712 PMM_SECTION_SEGMENT Segment
;
4714 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4717 if (Segment
->ReferenceCount
!= 0)
4720 CC_FILE_SIZES FileSizes
;
4722 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4725 /* Check size of file */
4726 if (SectionObjectPointer
->SharedCacheMap
)
4728 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4733 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4742 /* Check size of file */
4743 if (SectionObjectPointer
->SharedCacheMap
)
4745 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4746 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4755 /* Something must gone wrong
4756 * how can we have a Section but no
4758 DPRINT("ERROR: DataSectionObject without reference!\n");
4762 DPRINT("FIXME: didn't check for outstanding write probes\n");
4774 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4775 IN MMFLUSH_TYPE FlushType
)
4777 BOOLEAN Result
= TRUE
;
4779 PMM_SECTION_SEGMENT Segment
;
4784 case MmFlushForDelete
:
4785 if (SectionObjectPointer
->ImageSectionObject
||
4786 SectionObjectPointer
->DataSectionObject
)
4791 CcRosRemoveIfClosed(SectionObjectPointer
);
4794 case MmFlushForWrite
:
4796 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4798 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4801 if (SectionObjectPointer
->ImageSectionObject
)
4803 DPRINT1("SectionObject has ImageSection\n");
4809 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4811 DPRINT("Result %d\n", Result
);
4823 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4824 OUT PVOID
* MappedBase
,
4825 IN OUT PSIZE_T ViewSize
)
4827 PROS_SECTION_OBJECT Section
;
4828 PMMSUPPORT AddressSpace
;
4832 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4834 return MiMapViewInSystemSpace(SectionObject
,
4840 DPRINT("MmMapViewInSystemSpace() called\n");
4842 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4843 AddressSpace
= MmGetKernelAddressSpace();
4845 MmLockAddressSpace(AddressSpace
);
4848 if ((*ViewSize
) == 0)
4850 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4852 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4854 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4857 MmLockSectionSegment(Section
->Segment
);
4860 Status
= MmMapViewOfSegment(AddressSpace
,
4869 MmUnlockSectionSegment(Section
->Segment
);
4870 MmUnlockAddressSpace(AddressSpace
);
4877 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4879 PMMSUPPORT AddressSpace
;
4882 DPRINT("MmUnmapViewInSystemSpace() called\n");
4884 AddressSpace
= MmGetKernelAddressSpace();
4886 MmLockAddressSpace(AddressSpace
);
4888 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4890 MmUnlockAddressSpace(AddressSpace
);
4895 /**********************************************************************
4900 * Creates a section object.
4903 * SectionObject (OUT)
4904 * Caller supplied storage for the resulting pointer
4905 * to a SECTION_OBJECT instance;
4908 * Specifies the desired access to the section can be a
4910 * STANDARD_RIGHTS_REQUIRED |
4912 * SECTION_MAP_WRITE |
4913 * SECTION_MAP_READ |
4914 * SECTION_MAP_EXECUTE
4916 * ObjectAttributes [OPTIONAL]
4917 * Initialized attributes for the object can be used
4918 * to create a named section;
4921 * Maximizes the size of the memory section. Must be
4922 * non-NULL for a page-file backed section.
4923 * If value specified for a mapped file and the file is
4924 * not large enough, file will be extended.
4926 * SectionPageProtection
4927 * Can be a combination of:
4933 * AllocationAttributes
4934 * Can be a combination of:
4939 * Handle to a file to create a section mapped to a file
4940 * instead of a memory backed section;
4951 MmCreateSection (OUT PVOID
* Section
,
4952 IN ACCESS_MASK DesiredAccess
,
4953 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4954 IN PLARGE_INTEGER MaximumSize
,
4955 IN ULONG SectionPageProtection
,
4956 IN ULONG AllocationAttributes
,
4957 IN HANDLE FileHandle OPTIONAL
,
4958 IN PFILE_OBJECT FileObject OPTIONAL
)
4962 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4964 /* Check if an ARM3 section is being created instead */
4965 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4967 if (!(FileObject
) && !(FileHandle
))
4969 return MmCreateArm3Section(Section
,
4973 SectionPageProtection
,
4974 AllocationAttributes
&~ 1,
4980 /* Convert section flag to page flag */
4981 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4983 /* Check to make sure the protection is correct. Nt* does this already */
4984 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4985 if (Protection
== MM_INVALID_PROTECTION
)
4987 DPRINT1("Page protection is invalid\n");
4988 return STATUS_INVALID_PAGE_PROTECTION
;
4991 /* Check if this is going to be a data or image backed file section */
4992 if ((FileHandle
) || (FileObject
))
4994 /* These cannot be mapped with large pages */
4995 if (AllocationAttributes
& SEC_LARGE_PAGES
)
4997 DPRINT1("Large pages cannot be used with an image mapping\n");
4998 return STATUS_INVALID_PARAMETER_6
;
5001 /* Did the caller pass an object? */
5004 /* Reference the object directly */
5005 ObReferenceObject(FileObject
);
5009 /* Reference the file handle to get the object */
5010 Status
= ObReferenceObjectByHandle(FileHandle
,
5011 MmMakeFileAccess
[Protection
],
5013 ExGetPreviousMode(),
5014 (PVOID
*)&FileObject
,
5016 if (!NT_SUCCESS(Status
))
5018 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
5025 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
5026 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
5029 #ifndef NEWCC // A hack for initializing caching.
5030 // This is needed only in the old case.
5033 IO_STATUS_BLOCK Iosb
;
5036 LARGE_INTEGER ByteOffset
;
5037 ByteOffset
.QuadPart
= 0;
5038 Status
= ZwReadFile(FileHandle
,
5047 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5049 DPRINT1("CC failure: %lx\n", Status
);
5052 // Caching is initialized...
5056 if (AllocationAttributes
& SEC_IMAGE
)
5058 Status
= MmCreateImageSection(SectionObject
,
5062 SectionPageProtection
,
5063 AllocationAttributes
,
5067 else if (FileHandle
!= NULL
)
5069 Status
= MmCreateDataFileSection(SectionObject
,
5073 SectionPageProtection
,
5074 AllocationAttributes
,
5077 ObDereferenceObject(FileObject
);
5080 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5082 Status
= MmCreateCacheSection(SectionObject
,
5086 SectionPageProtection
,
5087 AllocationAttributes
,
5093 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5095 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5097 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5098 Status
= MmCreatePageFileSection(SectionObject
,
5102 SectionPageProtection
,
5103 AllocationAttributes
);