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
= {
167 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
168 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
169 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
172 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
174 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
175 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
178 /* FUNCTIONS *****************************************************************/
183 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
184 File Format Specification", revision 6.0 (February 1999)
186 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
187 IN SIZE_T FileHeaderSize
,
189 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
191 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
192 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
195 ULONG cbFileHeaderOffsetSize
= 0;
196 ULONG cbSectionHeadersOffset
= 0;
197 ULONG cbSectionHeadersSize
;
198 ULONG cbSectionHeadersOffsetSize
= 0;
199 ULONG cbOptHeaderSize
;
200 ULONG cbHeadersSize
= 0;
201 ULONG nSectionAlignment
;
202 ULONG nFileAlignment
;
204 const IMAGE_DOS_HEADER
* pidhDosHeader
;
205 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
206 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
207 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
208 PMM_SECTION_SEGMENT pssSegments
;
209 LARGE_INTEGER lnOffset
;
211 SIZE_T nPrevVirtualEndOfSegment
= 0;
212 ULONG nFileSizeOfHeaders
= 0;
216 ASSERT(FileHeaderSize
> 0);
218 ASSERT(ImageSectionObject
);
220 ASSERT(AllocateSegmentsCb
);
222 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
224 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
226 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
229 pidhDosHeader
= FileHeader
;
232 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
234 /* image too small to be an MZ executable */
235 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
236 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
238 /* no MZ signature */
239 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
240 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
242 /* check if this is an old MZ executable */
243 if(pidhDosHeader
->e_lfarlc
< 0x40)
244 DIE(("Old-style MZ executable found, e_lfarlc is %d\n", pidhDosHeader
->e_lfarlc
));
246 /* not a Windows executable */
247 if(pidhDosHeader
->e_lfanew
<= 0)
248 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
251 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
253 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
254 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
256 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
261 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
262 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
264 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
265 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
269 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
270 * need to read the header from the file
272 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
273 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
275 ULONG cbNtHeaderSize
;
279 l_ReadHeaderFromFile
:
281 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
283 /* read the header from the file */
284 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
286 if(!NT_SUCCESS(nStatus
))
288 NTSTATUS ReturnedStatus
= nStatus
;
290 /* If it attempted to read past the end of the file, it means e_lfanew is invalid */
291 if (ReturnedStatus
== STATUS_END_OF_FILE
) nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
293 DIE(("ReadFile failed, status %08X\n", ReturnedStatus
));
298 ASSERT(cbReadSize
> 0);
300 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
302 /* the buffer doesn't contain the file header */
303 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
304 DIE(("The file doesn't contain the PE file header\n"));
306 pinhNtHeader
= pData
;
308 /* object still not aligned: copy it to the beginning of the buffer */
309 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
311 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
312 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
313 pinhNtHeader
= pBuffer
;
316 /* invalid NT header */
317 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
319 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
320 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
322 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
324 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
325 DIE(("The full NT header is too large\n"));
327 /* the buffer doesn't contain the whole NT header */
328 if(cbReadSize
< cbNtHeaderSize
)
329 DIE(("The file doesn't contain the full NT header\n"));
333 ULONG cbOptHeaderOffsetSize
= 0;
335 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
337 /* don't trust an invalid NT header */
338 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
339 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
341 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
342 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
344 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
345 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
347 /* the buffer doesn't contain the whole NT header: read it from the file */
348 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
349 goto l_ReadHeaderFromFile
;
352 /* read information from the NT header */
353 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
354 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
356 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
358 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
359 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
361 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
363 switch(piohOptHeader
->Magic
)
365 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
366 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
370 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
373 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
374 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
376 /* See [1], section 3.4.2 */
377 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
379 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
380 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
382 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
383 DIE(("The section alignment is smaller than the file alignment\n"));
385 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
386 nFileAlignment
= piohOptHeader
->FileAlignment
;
388 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
389 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
393 nSectionAlignment
= PAGE_SIZE
;
394 nFileAlignment
= PAGE_SIZE
;
397 ASSERT(IsPowerOf2(nSectionAlignment
));
398 ASSERT(IsPowerOf2(nFileAlignment
));
400 switch(piohOptHeader
->Magic
)
403 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
405 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
406 ImageBase
= piohOptHeader
->ImageBase
;
408 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
409 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
411 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
412 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
414 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
415 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
417 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
419 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
421 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
422 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
424 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
425 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
429 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
431 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
432 piohOptHeader
->AddressOfEntryPoint
);
435 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
436 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
438 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
440 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
442 if (piohOptHeader
->AddressOfEntryPoint
== 0)
444 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
448 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
449 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
451 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
453 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
456 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
457 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
458 * magic to any binary.
460 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
461 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
462 * the SxS support -- at which point, duh, this should be removed.
464 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
466 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
473 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
475 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
477 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
479 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
481 ImageBase
= pioh64OptHeader
->ImageBase
;
482 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
483 DIE(("ImageBase exceeds the address space\n"));
486 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
488 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
489 DIE(("SizeOfImage exceeds the address space\n"));
491 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
494 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
496 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
497 DIE(("SizeOfStackReserve exceeds the address space\n"));
499 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
502 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
504 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
505 DIE(("SizeOfStackCommit exceeds the address space\n"));
507 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
510 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
512 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
514 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
515 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
517 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
518 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
522 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
524 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
525 pioh64OptHeader
->AddressOfEntryPoint
);
528 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
529 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
531 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
533 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
535 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
537 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
541 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
542 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
544 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
545 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
552 /* [1], section 3.4.2 */
553 if((ULONG_PTR
)ImageBase
% 0x10000)
554 DIE(("ImageBase is not aligned on a 64KB boundary"));
556 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
557 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
558 ImageSectionObject
->ImageInformation
.GpValue
= 0;
559 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
560 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
562 /* SECTION HEADERS */
563 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
565 /* see [1], section 3.3 */
566 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
567 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
570 * the additional segment is for the file's headers. They need to be present for
571 * the benefit of the dynamic loader (to locate exports, defaults for thread
572 * parameters, resources, etc.)
574 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
576 /* file offset for the section headers */
577 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
578 DIE(("Offset overflow\n"));
580 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
581 DIE(("Offset overflow\n"));
583 /* size of the section headers */
584 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
585 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
587 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
588 DIE(("Section headers too large\n"));
590 /* size of the executable's headers */
591 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
593 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
594 // DIE(("SizeOfHeaders is not aligned\n"));
596 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
597 DIE(("The section headers overflow SizeOfHeaders\n"));
599 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
601 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
602 DIE(("Overflow aligning the size of headers\n"));
609 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
610 /* WARNING: piohOptHeader IS NO LONGER USABLE */
611 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
613 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
614 pishSectionHeaders
= NULL
;
618 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
619 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
621 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
622 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
626 * the buffer doesn't contain the section headers, or the alignment is wrong:
627 * read the headers from the file
629 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
630 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
635 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
637 /* read the header from the file */
638 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
640 if(!NT_SUCCESS(nStatus
))
641 DIE(("ReadFile failed with status %08X\n", nStatus
));
645 ASSERT(cbReadSize
> 0);
647 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
649 /* the buffer doesn't contain all the section headers */
650 if(cbReadSize
< cbSectionHeadersSize
)
651 DIE(("The file doesn't contain all of the section headers\n"));
653 pishSectionHeaders
= pData
;
655 /* object still not aligned: copy it to the beginning of the buffer */
656 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
658 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
659 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
660 pishSectionHeaders
= pBuffer
;
665 /* allocate the segments */
666 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
667 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
669 if(ImageSectionObject
->Segments
== NULL
)
670 DIE(("AllocateSegments failed\n"));
672 /* initialize the headers segment */
673 pssSegments
= ImageSectionObject
->Segments
;
675 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
677 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
678 DIE(("Cannot align the size of the section headers\n"));
680 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
681 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
682 DIE(("Cannot align the size of the section headers\n"));
684 pssSegments
[0].Image
.FileOffset
= 0;
685 pssSegments
[0].Protection
= PAGE_READONLY
;
686 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
687 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
688 pssSegments
[0].Image
.VirtualAddress
= 0;
689 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
690 pssSegments
[0].WriteCopy
= TRUE
;
692 /* skip the headers segment */
695 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
697 /* convert the executable sections into segments. See also [1], section 4 */
698 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
700 ULONG nCharacteristics
;
702 /* validate the alignment */
703 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
704 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
706 /* sections must be contiguous, ordered by base address and non-overlapping */
707 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
708 DIE(("Memory gap between section %u and the previous\n", i
));
710 /* ignore explicit BSS sections */
711 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
713 /* validate the alignment */
715 /* Yes, this should be a multiple of FileAlignment, but there's
716 * stuff out there that isn't. We can cope with that
718 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
719 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
722 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
723 // DIE(("PointerToRawData[%u] is not aligned\n", i));
726 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
727 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
731 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
732 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
735 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
737 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
739 /* no explicit protection */
740 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
742 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
743 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
745 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
746 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
748 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
749 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
752 /* see table above */
753 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
754 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
756 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
757 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
759 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
761 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
762 /* FIXME: always false */
763 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
764 DIE(("Cannot align the virtual size of section %u\n", i
));
766 if(pssSegments
[i
].Length
.QuadPart
== 0)
767 DIE(("Virtual size of section %u is null\n", i
));
769 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
770 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
772 /* ensure the memory image is no larger than 4GB */
773 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
774 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
775 DIE(("The image is too large\n"));
778 if(nSectionAlignment
>= PAGE_SIZE
)
779 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
782 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
792 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
793 * ARGUMENTS: PFILE_OBJECT to wait for.
794 * RETURNS: Status of the wait.
797 MmspWaitForFileLock(PFILE_OBJECT File
)
799 return STATUS_SUCCESS
;
800 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
805 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
807 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
809 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
810 PMM_SECTION_SEGMENT SectionSegments
;
814 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
815 NrSegments
= ImageSectionObject
->NrSegments
;
816 SectionSegments
= ImageSectionObject
->Segments
;
817 for (i
= 0; i
< NrSegments
; i
++)
819 if (SectionSegments
[i
].ReferenceCount
!= 0)
821 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
822 SectionSegments
[i
].ReferenceCount
);
823 KeBugCheck(MEMORY_MANAGEMENT
);
825 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
827 ExFreePool(ImageSectionObject
->Segments
);
828 ExFreePool(ImageSectionObject
);
829 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
831 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
833 PMM_SECTION_SEGMENT Segment
;
835 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
838 if (Segment
->ReferenceCount
!= 0)
840 DPRINT1("Data segment still referenced\n");
841 KeBugCheck(MEMORY_MANAGEMENT
);
843 MmFreePageTablesSectionSegment(Segment
, NULL
);
845 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
851 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
852 PLARGE_INTEGER Offset
)
856 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
859 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
860 KeBugCheck(MEMORY_MANAGEMENT
);
862 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
864 DPRINT1("Maximum share count reached\n");
865 KeBugCheck(MEMORY_MANAGEMENT
);
867 if (IS_SWAP_FROM_SSE(Entry
))
869 KeBugCheck(MEMORY_MANAGEMENT
);
871 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
872 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
877 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
878 PMM_SECTION_SEGMENT Segment
,
879 PLARGE_INTEGER Offset
,
884 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
885 BOOLEAN IsDirectMapped
= FALSE
;
889 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
890 KeBugCheck(MEMORY_MANAGEMENT
);
892 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
894 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
895 KeBugCheck(MEMORY_MANAGEMENT
);
897 if (IS_SWAP_FROM_SSE(Entry
))
899 KeBugCheck(MEMORY_MANAGEMENT
);
901 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
903 * If we reducing the share count of this entry to zero then set the entry
904 * to zero and tell the cache the page is no longer mapped.
906 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
908 PFILE_OBJECT FileObject
;
910 PROS_SHARED_CACHE_MAP SharedCacheMap
;
912 SWAPENTRY SavedSwapEntry
;
914 BOOLEAN IsImageSection
;
915 LARGE_INTEGER FileOffset
;
917 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
919 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
921 Page
= PFN_FROM_SSE(Entry
);
922 FileObject
= Section
->FileObject
;
923 if (FileObject
!= NULL
&&
924 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
928 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
929 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
932 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
933 IsDirectMapped
= TRUE
;
935 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
.LowPart
, Dirty
);
937 Status
= STATUS_SUCCESS
;
939 if (!NT_SUCCESS(Status
))
941 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
942 KeBugCheck(MEMORY_MANAGEMENT
);
948 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
949 if (SavedSwapEntry
== 0)
952 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
953 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
957 * Try to page out this page and set the swap entry
958 * within the section segment. There exist no rmap entry
959 * for this page. The pager thread can't page out a
960 * page without a rmap entry.
962 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
963 if (InEntry
) *InEntry
= Entry
;
964 MiSetPageEvent(NULL
, NULL
);
968 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
969 if (InEntry
) *InEntry
= 0;
970 MiSetPageEvent(NULL
, NULL
);
973 MmReleasePageMemoryConsumer(MC_USER
, Page
);
979 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
980 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
988 * We hold all locks. Nobody can do something with the current
989 * process and the current segment (also not within an other process).
992 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
993 if (!NT_SUCCESS(Status
))
995 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
996 KeBugCheck(MEMORY_MANAGEMENT
);
999 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
1000 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
1001 MmSetSavedSwapEntryPage(Page
, 0);
1002 MiSetPageEvent(NULL
, NULL
);
1004 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1008 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1009 KeBugCheck(MEMORY_MANAGEMENT
);
1018 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1020 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1023 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1027 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1029 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1031 SharedCacheMap
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1032 Vacb
= CcRosLookupVacb(SharedCacheMap
, (ULONG
)(SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
));
1035 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, FALSE
, TRUE
);
1045 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1049 PVOID DestAddress
, SrcAddress
;
1051 Process
= PsGetCurrentProcess();
1052 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1053 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1054 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1056 return(STATUS_NO_MEMORY
);
1058 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1059 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1060 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1061 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1062 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1063 return(STATUS_SUCCESS
);
1069 MiReadPage(PMEMORY_AREA MemoryArea
,
1070 ULONG_PTR SegOffset
,
1073 * FUNCTION: Read a page for a section backed memory area.
1075 * MemoryArea - Memory area to read the page for.
1076 * Offset - Offset of the page to read.
1077 * Page - Variable that receives a page contains the read data.
1080 ULONGLONG BaseOffset
;
1081 ULONGLONG FileOffset
;
1085 PFILE_OBJECT FileObject
;
1087 ULONG_PTR RawLength
;
1088 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1089 BOOLEAN IsImageSection
;
1092 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1093 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1094 RawLength
= (ULONG_PTR
)(MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
);
1095 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1096 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1098 ASSERT(SharedCacheMap
);
1100 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1103 * If the file system is letting us go directly to the cache and the
1104 * memory area was mapped at an offset in the file which is page aligned
1105 * then get the related VACB.
1107 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1108 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1109 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1113 * Get the related VACB; we use a lower level interface than
1114 * filesystems do because it is safe for us to use an offset with an
1115 * alignment less than the file system block size.
1117 Status
= CcRosGetVacb(SharedCacheMap
,
1123 if (!NT_SUCCESS(Status
))
1130 * If the VACB isn't up to date then call the file
1131 * system to read in the data.
1133 Status
= CcReadVirtualAddress(Vacb
);
1134 if (!NT_SUCCESS(Status
))
1136 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1141 /* Probe the page, since it's PDE might not be synced */
1142 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1145 * Retrieve the page from the view that we actually want.
1147 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1148 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1150 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, TRUE
);
1157 ULONG_PTR VacbOffset
;
1160 * Allocate a page, this is rather complicated by the possibility
1161 * we might have to move other things out of memory
1163 MI_SET_USAGE(MI_USAGE_SECTION
);
1164 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1165 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1166 if (!NT_SUCCESS(Status
))
1170 Status
= CcRosGetVacb(SharedCacheMap
,
1176 if (!NT_SUCCESS(Status
))
1183 * If the VACB isn't up to date then call the file
1184 * system to read in the data.
1186 Status
= CcReadVirtualAddress(Vacb
);
1187 if (!NT_SUCCESS(Status
))
1189 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1194 Process
= PsGetCurrentProcess();
1195 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1196 VacbOffset
= (ULONG_PTR
)(BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
);
1197 Length
= RawLength
- SegOffset
;
1198 if (Length
<= VacbOffset
&& Length
<= PAGE_SIZE
)
1200 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1202 else if (VacbOffset
>= PAGE_SIZE
)
1204 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1208 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, VacbOffset
);
1209 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1210 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1211 Status
= CcRosGetVacb(SharedCacheMap
,
1212 (ULONG
)(FileOffset
+ VacbOffset
),
1217 if (!NT_SUCCESS(Status
))
1224 * If the VACB isn't up to date then call the file
1225 * system to read in the data.
1227 Status
= CcReadVirtualAddress(Vacb
);
1228 if (!NT_SUCCESS(Status
))
1230 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1234 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1235 if (Length
< PAGE_SIZE
)
1237 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, Length
- VacbOffset
);
1241 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, PAGE_SIZE
- VacbOffset
);
1244 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1245 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1247 return(STATUS_SUCCESS
);
1252 MiReadPage(PMEMORY_AREA MemoryArea
,
1253 ULONG_PTR SegOffset
,
1256 * FUNCTION: Read a page for a section backed memory area.
1258 * MemoryArea - Memory area to read the page for.
1259 * Offset - Offset of the page to read.
1260 * Page - Variable that receives a page contains the read data.
1263 MM_REQUIRED_RESOURCES Resources
;
1266 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1268 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1269 Resources
.FileOffset
.QuadPart
= SegOffset
+
1270 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1271 Resources
.Consumer
= MC_USER
;
1272 Resources
.Amount
= PAGE_SIZE
;
1274 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]);
1276 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1277 *Page
= Resources
.Page
[0];
1284 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1285 MEMORY_AREA
* MemoryArea
,
1289 LARGE_INTEGER Offset
;
1292 PROS_SECTION_OBJECT Section
;
1293 PMM_SECTION_SEGMENT Segment
;
1298 BOOLEAN HasSwapEntry
;
1300 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1301 SWAPENTRY SwapEntry
;
1304 * There is a window between taking the page fault and locking the
1305 * address space when another thread could load the page so we check
1308 if (MmIsPagePresent(Process
, Address
))
1310 return(STATUS_SUCCESS
);
1313 if (MmIsDisabledPage(Process
, Address
))
1315 return(STATUS_ACCESS_VIOLATION
);
1319 * Check for the virtual memory area being deleted.
1321 if (MemoryArea
->DeleteInProgress
)
1323 return(STATUS_UNSUCCESSFUL
);
1326 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1327 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1328 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1330 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1331 Section
= MemoryArea
->Data
.SectionData
.Section
;
1332 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1333 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1335 ASSERT(Region
!= NULL
);
1339 MmLockSectionSegment(Segment
);
1340 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1342 * Check if this page needs to be mapped COW
1344 if ((Segment
->WriteCopy
) &&
1345 (Region
->Protect
== PAGE_READWRITE
||
1346 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1348 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1352 Attributes
= Region
->Protect
;
1356 * Check if someone else is already handling this fault, if so wait
1359 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1361 MmUnlockSectionSegment(Segment
);
1362 MmUnlockAddressSpace(AddressSpace
);
1363 MiWaitForPageEvent(NULL
, NULL
);
1364 MmLockAddressSpace(AddressSpace
);
1365 DPRINT("Address 0x%p\n", Address
);
1366 return(STATUS_MM_RESTART_OPERATION
);
1369 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1373 SWAPENTRY DummyEntry
;
1376 * Is it a wait entry?
1378 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1380 if (SwapEntry
== MM_WAIT_ENTRY
)
1382 MmUnlockSectionSegment(Segment
);
1383 MmUnlockAddressSpace(AddressSpace
);
1384 MiWaitForPageEvent(NULL
, NULL
);
1385 MmLockAddressSpace(AddressSpace
);
1386 return STATUS_MM_RESTART_OPERATION
;
1390 * Must be private page we have swapped out.
1396 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1398 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1399 KeBugCheck(MEMORY_MANAGEMENT
);
1402 MmUnlockSectionSegment(Segment
);
1403 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1404 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1406 MmUnlockAddressSpace(AddressSpace
);
1407 MI_SET_USAGE(MI_USAGE_SECTION
);
1408 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1409 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1410 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1411 if (!NT_SUCCESS(Status
))
1413 KeBugCheck(MEMORY_MANAGEMENT
);
1416 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1417 if (!NT_SUCCESS(Status
))
1419 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1420 KeBugCheck(MEMORY_MANAGEMENT
);
1422 MmLockAddressSpace(AddressSpace
);
1423 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1424 Status
= MmCreateVirtualMapping(Process
,
1429 if (!NT_SUCCESS(Status
))
1431 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1432 KeBugCheck(MEMORY_MANAGEMENT
);
1437 * Store the swap entry for later use.
1439 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1442 * Add the page to the process's working set
1444 MmInsertRmap(Page
, Process
, Address
);
1446 * Finish the operation
1448 MiSetPageEvent(Process
, Address
);
1449 DPRINT("Address 0x%p\n", Address
);
1450 return(STATUS_SUCCESS
);
1454 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1456 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1458 MmUnlockSectionSegment(Segment
);
1460 * Just map the desired physical page
1462 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1463 Status
= MmCreateVirtualMappingUnsafe(Process
,
1468 if (!NT_SUCCESS(Status
))
1470 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1471 KeBugCheck(MEMORY_MANAGEMENT
);
1476 * Cleanup and release locks
1478 MiSetPageEvent(Process
, Address
);
1479 DPRINT("Address 0x%p\n", Address
);
1480 return(STATUS_SUCCESS
);
1484 * Get the entry corresponding to the offset within the section
1486 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1490 SWAPENTRY FakeSwapEntry
;
1493 * If the entry is zero (and it can't change because we have
1494 * locked the segment) then we need to load the page.
1498 * Release all our locks and read in the page from disk
1500 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1501 MmUnlockSectionSegment(Segment
);
1502 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1503 MmUnlockAddressSpace(AddressSpace
);
1505 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1506 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1507 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1509 MI_SET_USAGE(MI_USAGE_SECTION
);
1510 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1511 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1512 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1513 if (!NT_SUCCESS(Status
))
1515 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1521 Status
= MiReadPage(MemoryArea
, (ULONG_PTR
)Offset
.QuadPart
, &Page
);
1522 if (!NT_SUCCESS(Status
))
1524 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1527 if (!NT_SUCCESS(Status
))
1530 * FIXME: What do we know in this case?
1533 * Cleanup and release locks
1535 MmLockAddressSpace(AddressSpace
);
1536 MiSetPageEvent(Process
, Address
);
1537 DPRINT("Address 0x%p\n", Address
);
1542 * Mark the offset within the section as having valid, in-memory
1545 MmLockAddressSpace(AddressSpace
);
1546 MmLockSectionSegment(Segment
);
1547 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1548 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1549 MmUnlockSectionSegment(Segment
);
1551 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1552 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1553 Page
, Process
, PAddress
, Attributes
);
1554 Status
= MmCreateVirtualMapping(Process
,
1559 if (!NT_SUCCESS(Status
))
1561 DPRINT1("Unable to create virtual mapping\n");
1562 KeBugCheck(MEMORY_MANAGEMENT
);
1564 ASSERT(MmIsPagePresent(Process
, PAddress
));
1565 MmInsertRmap(Page
, Process
, Address
);
1567 MiSetPageEvent(Process
, Address
);
1568 DPRINT("Address 0x%p\n", Address
);
1569 return(STATUS_SUCCESS
);
1571 else if (IS_SWAP_FROM_SSE(Entry
))
1573 SWAPENTRY SwapEntry
;
1575 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1578 * Release all our locks and read in the page from disk
1580 MmUnlockSectionSegment(Segment
);
1582 MmUnlockAddressSpace(AddressSpace
);
1583 MI_SET_USAGE(MI_USAGE_SECTION
);
1584 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1585 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1586 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1587 if (!NT_SUCCESS(Status
))
1589 KeBugCheck(MEMORY_MANAGEMENT
);
1592 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1593 if (!NT_SUCCESS(Status
))
1595 KeBugCheck(MEMORY_MANAGEMENT
);
1599 * Relock the address space and segment
1601 MmLockAddressSpace(AddressSpace
);
1602 MmLockSectionSegment(Segment
);
1605 * Check the entry. No one should change the status of a page
1606 * that has a pending page-in.
1608 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1609 if (Entry
!= Entry1
)
1611 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1612 KeBugCheck(MEMORY_MANAGEMENT
);
1616 * Mark the offset within the section as having valid, in-memory
1619 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1620 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1621 MmUnlockSectionSegment(Segment
);
1624 * Save the swap entry.
1626 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1627 Status
= MmCreateVirtualMapping(Process
,
1632 if (!NT_SUCCESS(Status
))
1634 DPRINT1("Unable to create virtual mapping\n");
1635 KeBugCheck(MEMORY_MANAGEMENT
);
1637 MmInsertRmap(Page
, Process
, Address
);
1638 MiSetPageEvent(Process
, Address
);
1639 DPRINT("Address 0x%p\n", Address
);
1640 return(STATUS_SUCCESS
);
1645 * If the section offset is already in-memory and valid then just
1646 * take another reference to the page
1649 Page
= PFN_FROM_SSE(Entry
);
1651 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1652 MmUnlockSectionSegment(Segment
);
1654 Status
= MmCreateVirtualMapping(Process
,
1659 if (!NT_SUCCESS(Status
))
1661 DPRINT1("Unable to create virtual mapping\n");
1662 KeBugCheck(MEMORY_MANAGEMENT
);
1664 MmInsertRmap(Page
, Process
, Address
);
1665 MiSetPageEvent(Process
, Address
);
1666 DPRINT("Address 0x%p\n", Address
);
1667 return(STATUS_SUCCESS
);
1673 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1674 MEMORY_AREA
* MemoryArea
,
1677 PMM_SECTION_SEGMENT Segment
;
1678 PROS_SECTION_OBJECT Section
;
1683 LARGE_INTEGER Offset
;
1686 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1687 SWAPENTRY SwapEntry
;
1689 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1692 * Check if the page has already been set readwrite
1694 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1696 DPRINT("Address 0x%p\n", Address
);
1697 return(STATUS_SUCCESS
);
1701 * Find the offset of the page
1703 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1704 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1705 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1707 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1708 Section
= MemoryArea
->Data
.SectionData
.Section
;
1709 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1710 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1712 ASSERT(Region
!= NULL
);
1716 MmLockSectionSegment(Segment
);
1718 OldPage
= MmGetPfnForProcess(Process
, Address
);
1719 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1721 MmUnlockSectionSegment(Segment
);
1724 * Check if we are doing COW
1726 if (!((Segment
->WriteCopy
) &&
1727 (Region
->Protect
== PAGE_READWRITE
||
1728 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1730 DPRINT("Address 0x%p\n", Address
);
1731 return(STATUS_ACCESS_VIOLATION
);
1734 if (IS_SWAP_FROM_SSE(Entry
) ||
1735 PFN_FROM_SSE(Entry
) != OldPage
)
1737 /* This is a private page. We must only change the page protection. */
1738 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1739 return(STATUS_SUCCESS
);
1743 DPRINT("OldPage == 0!\n");
1746 * Get or create a pageop
1748 MmLockSectionSegment(Segment
);
1749 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1752 * Wait for any other operations to complete
1754 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1756 MmUnlockSectionSegment(Segment
);
1757 MmUnlockAddressSpace(AddressSpace
);
1758 MiWaitForPageEvent(NULL
, NULL
);
1760 * Restart the operation
1762 MmLockAddressSpace(AddressSpace
);
1763 DPRINT("Address 0x%p\n", Address
);
1764 return(STATUS_MM_RESTART_OPERATION
);
1767 MmDeleteRmap(OldPage
, Process
, PAddress
);
1768 MmDeleteVirtualMapping(Process
, PAddress
, FALSE
, NULL
, NULL
);
1769 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1772 * Release locks now we have the pageop
1774 MmUnlockSectionSegment(Segment
);
1775 MmUnlockAddressSpace(AddressSpace
);
1780 MI_SET_USAGE(MI_USAGE_SECTION
);
1781 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1782 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1783 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1784 if (!NT_SUCCESS(Status
))
1786 KeBugCheck(MEMORY_MANAGEMENT
);
1792 MiCopyFromUserPage(NewPage
, OldPage
);
1794 MmLockAddressSpace(AddressSpace
);
1797 * Set the PTE to point to the new page
1799 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1800 Status
= MmCreateVirtualMapping(Process
,
1805 if (!NT_SUCCESS(Status
))
1807 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1808 KeBugCheck(MEMORY_MANAGEMENT
);
1813 * Unshare the old page.
1815 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1816 MmInsertRmap(NewPage
, Process
, PAddress
);
1817 MmLockSectionSegment(Segment
);
1818 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1819 MmUnlockSectionSegment(Segment
);
1821 MiSetPageEvent(Process
, Address
);
1822 DPRINT("Address 0x%p\n", Address
);
1823 return(STATUS_SUCCESS
);
1827 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1829 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1831 PFN_NUMBER Page
= 0;
1833 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1836 MmLockAddressSpace(&Process
->Vm
);
1839 MmDeleteVirtualMapping(Process
,
1846 PageOutContext
->WasDirty
= TRUE
;
1848 if (!PageOutContext
->Private
)
1850 MmLockSectionSegment(PageOutContext
->Segment
);
1851 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1852 PageOutContext
->Segment
,
1853 &PageOutContext
->Offset
,
1854 PageOutContext
->WasDirty
,
1856 &PageOutContext
->SectionEntry
);
1857 MmUnlockSectionSegment(PageOutContext
->Segment
);
1861 MmUnlockAddressSpace(&Process
->Vm
);
1864 if (PageOutContext
->Private
)
1866 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1872 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1873 MEMORY_AREA
* MemoryArea
,
1874 PVOID Address
, ULONG_PTR Entry
)
1877 MM_SECTION_PAGEOUT_CONTEXT Context
;
1878 SWAPENTRY SwapEntry
;
1879 ULONGLONG FileOffset
;
1881 PFILE_OBJECT FileObject
;
1883 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1885 BOOLEAN DirectMapped
;
1886 BOOLEAN IsImageSection
;
1887 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1890 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1893 * Get the segment and section.
1895 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1896 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1897 Context
.SectionEntry
= Entry
;
1898 Context
.CallingProcess
= Process
;
1900 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1901 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1902 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1904 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1906 FileObject
= Context
.Section
->FileObject
;
1907 DirectMapped
= FALSE
;
1909 MmLockSectionSegment(Context
.Segment
);
1912 if (FileObject
!= NULL
&&
1913 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1915 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1918 * If the file system is letting us go directly to the cache and the
1919 * memory area was mapped at an offset in the file which is page aligned
1920 * then note this is a direct mapped page.
1922 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1923 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1925 DirectMapped
= TRUE
;
1932 * This should never happen since mappings of physical memory are never
1933 * placed in the rmap lists.
1935 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1937 DPRINT1("Trying to page out from physical memory section address 0x%p "
1938 "process %p\n", Address
,
1939 Process
? Process
->UniqueProcessId
: 0);
1940 KeBugCheck(MEMORY_MANAGEMENT
);
1944 * Get the section segment entry and the physical address.
1946 if (!MmIsPagePresent(Process
, Address
))
1948 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1949 Process
? Process
->UniqueProcessId
: 0, Address
);
1950 KeBugCheck(MEMORY_MANAGEMENT
);
1952 Page
= MmGetPfnForProcess(Process
, Address
);
1953 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1956 * Check the reference count to ensure this page can be paged out
1958 if (MmGetReferenceCountPage(Page
) != 1)
1960 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1961 Page
, MmGetReferenceCountPage(Page
));
1962 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1963 MmUnlockSectionSegment(Context
.Segment
);
1964 return STATUS_UNSUCCESSFUL
;
1968 * Prepare the context structure for the rmap delete call.
1970 MmUnlockSectionSegment(Context
.Segment
);
1971 Context
.WasDirty
= FALSE
;
1972 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1973 IS_SWAP_FROM_SSE(Entry
) ||
1974 PFN_FROM_SSE(Entry
) != Page
)
1976 Context
.Private
= TRUE
;
1980 Context
.Private
= FALSE
;
1984 * Take an additional reference to the page or the VACB.
1986 if (DirectMapped
&& !Context
.Private
)
1988 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
1990 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1991 KeBugCheck(MEMORY_MANAGEMENT
);
1996 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1997 MmReferencePage(Page
);
1998 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
2001 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2003 /* Since we passed in a surrogate, we'll get back the page entry
2004 * state in our context. This is intended to make intermediate
2005 * decrements of share count not release the wait entry.
2007 Entry
= Context
.SectionEntry
;
2010 * If this wasn't a private page then we should have reduced the entry to
2011 * zero by deleting all the rmaps.
2013 if (!Context
.Private
&& Entry
!= 0)
2015 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2016 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2018 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2023 * If the page wasn't dirty then we can just free it as for a readonly page.
2024 * Since we unmapped all the mappings above we know it will not suddenly
2026 * If the page is from a pagefile section and has no swap entry,
2027 * we can't free the page at this point.
2029 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2030 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2032 if (Context
.Private
)
2034 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2035 Context
.WasDirty
? "dirty" : "clean", Address
);
2036 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2038 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2040 MmSetSavedSwapEntryPage(Page
, 0);
2041 MmLockSectionSegment(Context
.Segment
);
2042 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2043 MmUnlockSectionSegment(Context
.Segment
);
2044 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2045 MiSetPageEvent(NULL
, NULL
);
2046 return(STATUS_SUCCESS
);
2049 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2051 if (Context
.Private
)
2053 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2054 Context
.WasDirty
? "dirty" : "clean", Address
);
2055 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2057 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2059 MmSetSavedSwapEntryPage(Page
, 0);
2062 MmLockSectionSegment(Context
.Segment
);
2063 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2064 MmUnlockSectionSegment(Context
.Segment
);
2066 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2067 MiSetPageEvent(NULL
, NULL
);
2068 return(STATUS_SUCCESS
);
2071 else if (!Context
.Private
&& DirectMapped
)
2075 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2077 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2080 Status
= CcRosUnmapVacb(SharedCacheMap
, (ULONG
)FileOffset
, FALSE
);
2082 Status
= STATUS_SUCCESS
;
2085 if (!NT_SUCCESS(Status
))
2087 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2088 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2091 MiSetPageEvent(NULL
, NULL
);
2092 return(STATUS_SUCCESS
);
2094 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2098 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2100 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2102 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2103 MiSetPageEvent(NULL
, NULL
);
2104 return(STATUS_SUCCESS
);
2106 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2108 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2109 MmSetSavedSwapEntryPage(Page
, 0);
2110 MmLockAddressSpace(AddressSpace
);
2111 Status
= MmCreatePageFileMapping(Process
,
2114 MmUnlockAddressSpace(AddressSpace
);
2115 if (!NT_SUCCESS(Status
))
2117 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2118 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2120 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2121 MiSetPageEvent(NULL
, NULL
);
2122 return(STATUS_SUCCESS
);
2126 * If necessary, allocate an entry in the paging file for this page
2130 SwapEntry
= MmAllocSwapPage();
2133 MmShowOutOfSpaceMessagePagingFile();
2134 MmLockAddressSpace(AddressSpace
);
2136 * For private pages restore the old mappings.
2138 if (Context
.Private
)
2140 Status
= MmCreateVirtualMapping(Process
,
2142 MemoryArea
->Protect
,
2145 MmSetDirtyPage(Process
, Address
);
2154 * For non-private pages if the page wasn't direct mapped then
2155 * set it back into the section segment entry so we don't loose
2156 * our copy. Otherwise it will be handled by the cache manager.
2158 Status
= MmCreateVirtualMapping(Process
,
2160 MemoryArea
->Protect
,
2163 MmSetDirtyPage(Process
, Address
);
2167 // If we got here, the previous entry should have been a wait
2168 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2169 MmLockSectionSegment(Context
.Segment
);
2170 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2171 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2172 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2173 MmUnlockSectionSegment(Context
.Segment
);
2175 MmUnlockAddressSpace(AddressSpace
);
2176 MiSetPageEvent(NULL
, NULL
);
2177 return(STATUS_PAGEFILE_QUOTA
);
2182 * Write the page to the pagefile
2184 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2185 if (!NT_SUCCESS(Status
))
2187 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2190 * As above: undo our actions.
2191 * FIXME: Also free the swap page.
2193 MmLockAddressSpace(AddressSpace
);
2194 if (Context
.Private
)
2196 Status
= MmCreateVirtualMapping(Process
,
2198 MemoryArea
->Protect
,
2201 MmSetDirtyPage(Process
, Address
);
2208 Status
= MmCreateVirtualMapping(Process
,
2210 MemoryArea
->Protect
,
2213 MmSetDirtyPage(Process
, Address
);
2217 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2218 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2220 MmUnlockAddressSpace(AddressSpace
);
2221 MiSetPageEvent(NULL
, NULL
);
2222 return(STATUS_UNSUCCESSFUL
);
2226 * Otherwise we have succeeded.
2228 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2229 MmSetSavedSwapEntryPage(Page
, 0);
2230 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2231 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2233 MmLockSectionSegment(Context
.Segment
);
2234 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2235 MmUnlockSectionSegment(Context
.Segment
);
2239 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2242 if (Context
.Private
)
2244 MmLockAddressSpace(AddressSpace
);
2245 MmLockSectionSegment(Context
.Segment
);
2246 Status
= MmCreatePageFileMapping(Process
,
2249 /* We had placed a wait entry upon entry ... replace it before leaving */
2250 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2251 MmUnlockSectionSegment(Context
.Segment
);
2252 MmUnlockAddressSpace(AddressSpace
);
2253 if (!NT_SUCCESS(Status
))
2255 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2256 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2261 MmLockAddressSpace(AddressSpace
);
2262 MmLockSectionSegment(Context
.Segment
);
2263 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2264 /* We had placed a wait entry upon entry ... replace it before leaving */
2265 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2266 MmUnlockSectionSegment(Context
.Segment
);
2267 MmUnlockAddressSpace(AddressSpace
);
2270 MiSetPageEvent(NULL
, NULL
);
2271 return(STATUS_SUCCESS
);
2276 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2277 PMEMORY_AREA MemoryArea
,
2281 LARGE_INTEGER Offset
;
2282 PROS_SECTION_OBJECT Section
;
2283 PMM_SECTION_SEGMENT Segment
;
2285 SWAPENTRY SwapEntry
;
2289 PFILE_OBJECT FileObject
;
2290 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2291 BOOLEAN DirectMapped
;
2292 BOOLEAN IsImageSection
;
2293 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2295 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2297 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2298 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2301 * Get the segment and section.
2303 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2304 Section
= MemoryArea
->Data
.SectionData
.Section
;
2305 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2307 FileObject
= Section
->FileObject
;
2308 DirectMapped
= FALSE
;
2309 if (FileObject
!= NULL
&&
2310 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2312 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2315 * If the file system is letting us go directly to the cache and the
2316 * memory area was mapped at an offset in the file which is page aligned
2317 * then note this is a direct mapped page.
2319 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2320 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2322 DirectMapped
= TRUE
;
2327 * This should never happen since mappings of physical memory are never
2328 * placed in the rmap lists.
2330 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2332 DPRINT1("Trying to write back page from physical memory mapped at %p "
2333 "process %p\n", Address
,
2334 Process
? Process
->UniqueProcessId
: 0);
2335 KeBugCheck(MEMORY_MANAGEMENT
);
2339 * Get the section segment entry and the physical address.
2341 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2342 if (!MmIsPagePresent(Process
, Address
))
2344 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2345 Process
? Process
->UniqueProcessId
: 0, Address
);
2346 KeBugCheck(MEMORY_MANAGEMENT
);
2348 Page
= MmGetPfnForProcess(Process
, Address
);
2349 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2352 * Check for a private (COWed) page.
2354 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2355 IS_SWAP_FROM_SSE(Entry
) ||
2356 PFN_FROM_SSE(Entry
) != Page
)
2366 * Speculatively set all mappings of the page to clean.
2368 MmSetCleanAllRmaps(Page
);
2371 * If this page was direct mapped from the cache then the cache manager
2372 * will take care of writing it back to disk.
2374 if (DirectMapped
&& !Private
)
2376 //LARGE_INTEGER SOffset;
2377 ASSERT(SwapEntry
== 0);
2378 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2380 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.LowPart
);
2382 MmLockSectionSegment(Segment
);
2383 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2384 MmUnlockSectionSegment(Segment
);
2385 MiSetPageEvent(NULL
, NULL
);
2386 return(STATUS_SUCCESS
);
2390 * If necessary, allocate an entry in the paging file for this page
2394 SwapEntry
= MmAllocSwapPage();
2397 MmSetDirtyAllRmaps(Page
);
2398 MiSetPageEvent(NULL
, NULL
);
2399 return(STATUS_PAGEFILE_QUOTA
);
2401 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2405 * Write the page to the pagefile
2407 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2408 if (!NT_SUCCESS(Status
))
2410 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2412 MmSetDirtyAllRmaps(Page
);
2413 MiSetPageEvent(NULL
, NULL
);
2414 return(STATUS_UNSUCCESSFUL
);
2418 * Otherwise we have succeeded.
2420 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2421 MiSetPageEvent(NULL
, NULL
);
2422 return(STATUS_SUCCESS
);
2426 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2434 PMEMORY_AREA MemoryArea
;
2435 PMM_SECTION_SEGMENT Segment
;
2436 BOOLEAN DoCOW
= FALSE
;
2438 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2440 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2441 ASSERT(MemoryArea
!= NULL
);
2442 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2443 MmLockSectionSegment(Segment
);
2445 if ((Segment
->WriteCopy
) &&
2446 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2451 if (OldProtect
!= NewProtect
)
2453 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2455 SWAPENTRY SwapEntry
;
2456 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2457 ULONG Protect
= NewProtect
;
2459 /* Wait for a wait entry to disappear */
2461 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2462 if (SwapEntry
!= MM_WAIT_ENTRY
)
2464 MiWaitForPageEvent(Process
, Address
);
2468 * If we doing COW for this segment then check if the page is
2471 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2473 LARGE_INTEGER Offset
;
2477 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2478 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2479 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2481 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2482 * IS_SWAP_FROM_SSE and we'll do the right thing.
2484 Page
= MmGetPfnForProcess(Process
, Address
);
2486 Protect
= PAGE_READONLY
;
2487 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2488 IS_SWAP_FROM_SSE(Entry
) ||
2489 PFN_FROM_SSE(Entry
) != Page
)
2491 Protect
= NewProtect
;
2495 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2497 MmSetPageProtect(Process
, Address
,
2503 MmUnlockSectionSegment(Segment
);
2508 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2509 PMEMORY_AREA MemoryArea
,
2517 ULONG_PTR MaxLength
;
2519 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2520 if (Length
> MaxLength
)
2521 Length
= (ULONG
)MaxLength
;
2523 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2524 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2526 ASSERT(Region
!= NULL
);
2528 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2529 Region
->Protect
!= Protect
)
2531 return STATUS_INVALID_PAGE_PROTECTION
;
2534 *OldProtect
= Region
->Protect
;
2535 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2536 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2537 BaseAddress
, Length
, Region
->Type
, Protect
,
2538 MmAlterViewAttributes
);
2544 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2546 PMEMORY_BASIC_INFORMATION Info
,
2547 PSIZE_T ResultLength
)
2550 PVOID RegionBaseAddress
;
2551 PROS_SECTION_OBJECT Section
;
2552 PMM_SECTION_SEGMENT Segment
;
2554 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2555 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2556 Address
, &RegionBaseAddress
);
2559 return STATUS_UNSUCCESSFUL
;
2562 Section
= MemoryArea
->Data
.SectionData
.Section
;
2563 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2565 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2566 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2567 Info
->Type
= MEM_IMAGE
;
2571 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2572 Info
->Type
= MEM_MAPPED
;
2574 Info
->BaseAddress
= RegionBaseAddress
;
2575 Info
->AllocationProtect
= MemoryArea
->Protect
;
2576 Info
->RegionSize
= Region
->Length
;
2577 Info
->State
= MEM_COMMIT
;
2578 Info
->Protect
= Region
->Protect
;
2580 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2581 return(STATUS_SUCCESS
);
2586 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2589 LARGE_INTEGER Offset
;
2591 SWAPENTRY SavedSwapEntry
;
2596 MmLockSectionSegment(Segment
);
2598 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2599 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2601 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2604 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2605 if (IS_SWAP_FROM_SSE(Entry
))
2607 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2611 Page
= PFN_FROM_SSE(Entry
);
2612 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2613 if (SavedSwapEntry
!= 0)
2615 MmSetSavedSwapEntryPage(Page
, 0);
2616 MmFreeSwapPage(SavedSwapEntry
);
2618 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2623 MmUnlockSectionSegment(Segment
);
2627 MmpDeleteSection(PVOID ObjectBody
)
2629 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2631 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2632 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2637 PMM_SECTION_SEGMENT SectionSegments
;
2640 * NOTE: Section->ImageSection can be NULL for short time
2641 * during the section creating. If we fail for some reason
2642 * until the image section is properly initialized we shouldn't
2643 * process further here.
2645 if (Section
->ImageSection
== NULL
)
2648 SectionSegments
= Section
->ImageSection
->Segments
;
2649 NrSegments
= Section
->ImageSection
->NrSegments
;
2651 for (i
= 0; i
< NrSegments
; i
++)
2653 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2655 MmLockSectionSegment(&SectionSegments
[i
]);
2657 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2658 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2660 MmUnlockSectionSegment(&SectionSegments
[i
]);
2663 MmpFreePageFileSegment(&SectionSegments
[i
]);
2669 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2672 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2675 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2677 DPRINT("Freeing section segment\n");
2678 Section
->Segment
= NULL
;
2679 MmFinalizeSegment(Segment
);
2683 DPRINT("RefCount %d\n", RefCount
);
2690 * NOTE: Section->Segment can be NULL for short time
2691 * during the section creating.
2693 if (Section
->Segment
== NULL
)
2696 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2698 MmpFreePageFileSegment(Section
->Segment
);
2699 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2700 ExFreePool(Section
->Segment
);
2701 Section
->Segment
= NULL
;
2705 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2708 if (Section
->FileObject
!= NULL
)
2711 CcRosDereferenceCache(Section
->FileObject
);
2713 ObDereferenceObject(Section
->FileObject
);
2714 Section
->FileObject
= NULL
;
2719 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2721 IN ACCESS_MASK GrantedAccess
,
2722 IN ULONG ProcessHandleCount
,
2723 IN ULONG SystemHandleCount
)
2725 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2731 MmCreatePhysicalMemorySection(VOID
)
2733 PROS_SECTION_OBJECT PhysSection
;
2735 OBJECT_ATTRIBUTES Obj
;
2736 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2737 LARGE_INTEGER SectionSize
;
2741 * Create the section mapping physical memory
2743 SectionSize
.QuadPart
= 0xFFFFFFFF;
2744 InitializeObjectAttributes(&Obj
,
2749 Status
= MmCreateSection((PVOID
)&PhysSection
,
2753 PAGE_EXECUTE_READWRITE
,
2757 if (!NT_SUCCESS(Status
))
2759 DPRINT1("Failed to create PhysicalMemory section\n");
2760 KeBugCheck(MEMORY_MANAGEMENT
);
2762 Status
= ObInsertObject(PhysSection
,
2768 if (!NT_SUCCESS(Status
))
2770 ObDereferenceObject(PhysSection
);
2772 ObCloseHandle(Handle
, KernelMode
);
2773 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2774 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2776 return(STATUS_SUCCESS
);
2782 MmInitSectionImplementation(VOID
)
2784 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2785 UNICODE_STRING Name
;
2787 DPRINT("Creating Section Object Type\n");
2789 /* Initialize the section based root */
2790 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2791 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2793 /* Initialize the Section object type */
2794 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2795 RtlInitUnicodeString(&Name
, L
"Section");
2796 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2797 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2798 ObjectTypeInitializer
.PoolType
= PagedPool
;
2799 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2800 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2801 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2802 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2803 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2804 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2805 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2807 MmCreatePhysicalMemorySection();
2809 return(STATUS_SUCCESS
);
2814 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2815 ACCESS_MASK DesiredAccess
,
2816 POBJECT_ATTRIBUTES ObjectAttributes
,
2817 PLARGE_INTEGER UMaximumSize
,
2818 ULONG SectionPageProtection
,
2819 ULONG AllocationAttributes
)
2821 * Create a section which is backed by the pagefile
2824 LARGE_INTEGER MaximumSize
;
2825 PROS_SECTION_OBJECT Section
;
2826 PMM_SECTION_SEGMENT Segment
;
2829 if (UMaximumSize
== NULL
)
2831 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2832 return(STATUS_INVALID_PARAMETER
);
2834 MaximumSize
= *UMaximumSize
;
2837 * Create the section
2839 Status
= ObCreateObject(ExGetPreviousMode(),
2840 MmSectionObjectType
,
2842 ExGetPreviousMode(),
2844 sizeof(ROS_SECTION_OBJECT
),
2847 (PVOID
*)(PVOID
)&Section
);
2848 if (!NT_SUCCESS(Status
))
2850 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2857 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2858 Section
->Type
= 'SC';
2859 Section
->Size
= 'TN';
2860 Section
->SectionPageProtection
= SectionPageProtection
;
2861 Section
->AllocationAttributes
= AllocationAttributes
;
2862 Section
->MaximumSize
= MaximumSize
;
2863 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2864 TAG_MM_SECTION_SEGMENT
);
2865 if (Segment
== NULL
)
2867 ObDereferenceObject(Section
);
2868 return(STATUS_NO_MEMORY
);
2870 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2871 Section
->Segment
= Segment
;
2872 Segment
->ReferenceCount
= 1;
2873 ExInitializeFastMutex(&Segment
->Lock
);
2874 Segment
->Image
.FileOffset
= 0;
2875 Segment
->Protection
= SectionPageProtection
;
2876 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2877 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2878 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2879 Segment
->WriteCopy
= FALSE
;
2880 Segment
->Image
.VirtualAddress
= 0;
2881 Segment
->Image
.Characteristics
= 0;
2882 *SectionObject
= Section
;
2883 MiInitializeSectionPageTable(Segment
);
2884 return(STATUS_SUCCESS
);
2889 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2890 ACCESS_MASK DesiredAccess
,
2891 POBJECT_ATTRIBUTES ObjectAttributes
,
2892 PLARGE_INTEGER UMaximumSize
,
2893 ULONG SectionPageProtection
,
2894 ULONG AllocationAttributes
,
2897 * Create a section backed by a data file
2900 PROS_SECTION_OBJECT Section
;
2902 LARGE_INTEGER MaximumSize
;
2903 PFILE_OBJECT FileObject
;
2904 PMM_SECTION_SEGMENT Segment
;
2906 IO_STATUS_BLOCK Iosb
;
2907 LARGE_INTEGER Offset
;
2909 FILE_STANDARD_INFORMATION FileInfo
;
2913 * Create the section
2915 Status
= ObCreateObject(ExGetPreviousMode(),
2916 MmSectionObjectType
,
2918 ExGetPreviousMode(),
2920 sizeof(ROS_SECTION_OBJECT
),
2924 if (!NT_SUCCESS(Status
))
2931 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2932 Section
->Type
= 'SC';
2933 Section
->Size
= 'TN';
2934 Section
->SectionPageProtection
= SectionPageProtection
;
2935 Section
->AllocationAttributes
= AllocationAttributes
;
2938 * Reference the file handle
2940 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2941 Status
= ObReferenceObjectByHandle(FileHandle
,
2944 ExGetPreviousMode(),
2945 (PVOID
*)(PVOID
)&FileObject
,
2947 if (!NT_SUCCESS(Status
))
2949 ObDereferenceObject(Section
);
2954 * FIXME: This is propably not entirely correct. We can't look into
2955 * the standard FCB header because it might not be initialized yet
2956 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2957 * standard file information is filled on first request).
2959 Status
= IoQueryFileInformation(FileObject
,
2960 FileStandardInformation
,
2961 sizeof(FILE_STANDARD_INFORMATION
),
2964 Iosb
.Information
= Length
;
2965 if (!NT_SUCCESS(Status
))
2967 ObDereferenceObject(Section
);
2968 ObDereferenceObject(FileObject
);
2973 * FIXME: Revise this once a locking order for file size changes is
2976 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2978 MaximumSize
= *UMaximumSize
;
2982 MaximumSize
= FileInfo
.EndOfFile
;
2983 /* Mapping zero-sized files isn't allowed. */
2984 if (MaximumSize
.QuadPart
== 0)
2986 ObDereferenceObject(Section
);
2987 ObDereferenceObject(FileObject
);
2988 return STATUS_FILE_INVALID
;
2992 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2994 Status
= IoSetInformation(FileObject
,
2995 FileAllocationInformation
,
2996 sizeof(LARGE_INTEGER
),
2998 if (!NT_SUCCESS(Status
))
3000 ObDereferenceObject(Section
);
3001 ObDereferenceObject(FileObject
);
3002 return(STATUS_SECTION_NOT_EXTENDED
);
3006 if (FileObject
->SectionObjectPointer
== NULL
||
3007 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3010 * Read a bit so caching is initiated for the file object.
3011 * This is only needed because MiReadPage currently cannot
3012 * handle non-cached streams.
3014 Offset
.QuadPart
= 0;
3015 Status
= ZwReadFile(FileHandle
,
3024 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3026 ObDereferenceObject(Section
);
3027 ObDereferenceObject(FileObject
);
3030 if (FileObject
->SectionObjectPointer
== NULL
||
3031 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3033 /* FIXME: handle this situation */
3034 ObDereferenceObject(Section
);
3035 ObDereferenceObject(FileObject
);
3036 return STATUS_INVALID_PARAMETER
;
3043 Status
= MmspWaitForFileLock(FileObject
);
3044 if (Status
!= STATUS_SUCCESS
)
3046 ObDereferenceObject(Section
);
3047 ObDereferenceObject(FileObject
);
3052 * If this file hasn't been mapped as a data file before then allocate a
3053 * section segment to describe the data file mapping
3055 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3057 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3058 TAG_MM_SECTION_SEGMENT
);
3059 if (Segment
== NULL
)
3061 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3062 ObDereferenceObject(Section
);
3063 ObDereferenceObject(FileObject
);
3064 return(STATUS_NO_MEMORY
);
3066 Section
->Segment
= Segment
;
3067 Segment
->ReferenceCount
= 1;
3068 ExInitializeFastMutex(&Segment
->Lock
);
3070 * Set the lock before assigning the segment to the file object
3072 ExAcquireFastMutex(&Segment
->Lock
);
3073 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3075 Segment
->Image
.FileOffset
= 0;
3076 Segment
->Protection
= SectionPageProtection
;
3077 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3078 Segment
->Image
.Characteristics
= 0;
3079 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3080 if (AllocationAttributes
& SEC_RESERVE
)
3082 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3086 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3087 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3089 Segment
->Image
.VirtualAddress
= 0;
3090 Segment
->Locked
= TRUE
;
3091 MiInitializeSectionPageTable(Segment
);
3096 * If the file is already mapped as a data file then we may need
3100 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3102 Section
->Segment
= Segment
;
3103 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3104 MmLockSectionSegment(Segment
);
3106 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3107 !(AllocationAttributes
& SEC_RESERVE
))
3109 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3110 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3113 MmUnlockSectionSegment(Segment
);
3114 Section
->FileObject
= FileObject
;
3115 Section
->MaximumSize
= MaximumSize
;
3117 CcRosReferenceCache(FileObject
);
3119 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3120 *SectionObject
= Section
;
3121 return(STATUS_SUCCESS
);
3125 TODO: not that great (declaring loaders statically, having to declare all of
3126 them, having to keep them extern, etc.), will fix in the future
3128 extern NTSTATUS NTAPI PeFmtCreateSection
3130 IN CONST VOID
* FileHeader
,
3131 IN SIZE_T FileHeaderSize
,
3133 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3135 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3136 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3139 extern NTSTATUS NTAPI ElfFmtCreateSection
3141 IN CONST VOID
* FileHeader
,
3142 IN SIZE_T FileHeaderSize
,
3144 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3146 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3147 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3150 /* TODO: this is a standard DDK/PSDK macro */
3151 #ifndef RTL_NUMBER_OF
3152 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3155 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3166 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3168 SIZE_T SizeOfSegments
;
3169 PMM_SECTION_SEGMENT Segments
;
3171 /* TODO: check for integer overflow */
3172 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3174 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3176 TAG_MM_SECTION_SEGMENT
);
3179 RtlZeroMemory(Segments
, SizeOfSegments
);
3187 ExeFmtpReadFile(IN PVOID File
,
3188 IN PLARGE_INTEGER Offset
,
3191 OUT PVOID
* AllocBase
,
3192 OUT PULONG ReadSize
)
3195 LARGE_INTEGER FileOffset
;
3197 ULONG OffsetAdjustment
;
3201 PFILE_OBJECT FileObject
= File
;
3202 IO_STATUS_BLOCK Iosb
;
3204 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3208 KeBugCheck(MEMORY_MANAGEMENT
);
3211 FileOffset
= *Offset
;
3213 /* Negative/special offset: it cannot be used in this context */
3214 if(FileOffset
.u
.HighPart
< 0)
3216 KeBugCheck(MEMORY_MANAGEMENT
);
3219 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3220 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3221 FileOffset
.u
.LowPart
= AdjustOffset
;
3223 BufferSize
= Length
+ OffsetAdjustment
;
3224 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3227 * It's ok to use paged pool, because this is a temporary buffer only used in
3228 * the loading of executables. The assumption is that MmCreateSection is
3229 * always called at low IRQLs and that these buffers don't survive a brief
3230 * initialization phase
3232 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3237 KeBugCheck(MEMORY_MANAGEMENT
);
3242 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3244 UsedSize
= (ULONG
)Iosb
.Information
;
3246 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3248 Status
= STATUS_IN_PAGE_ERROR
;
3249 ASSERT(!NT_SUCCESS(Status
));
3252 if(NT_SUCCESS(Status
))
3254 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3255 *AllocBase
= Buffer
;
3256 *ReadSize
= UsedSize
- OffsetAdjustment
;
3260 ExFreePoolWithTag(Buffer
, 'rXmM');
3267 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3268 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3269 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3274 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3278 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3280 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3281 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3288 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3292 MmspAssertSegmentsSorted(ImageSectionObject
);
3294 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3296 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3300 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3301 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3302 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3310 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3314 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3316 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3317 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3325 MmspCompareSegments(const void * x
,
3328 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3329 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3332 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3333 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3337 * Ensures an image section's segments are sorted in memory
3342 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3345 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3347 MmspAssertSegmentsSorted(ImageSectionObject
);
3351 qsort(ImageSectionObject
->Segments
,
3352 ImageSectionObject
->NrSegments
,
3353 sizeof(ImageSectionObject
->Segments
[0]),
3354 MmspCompareSegments
);
3360 * Ensures an image section's segments don't overlap in memory and don't have
3361 * gaps and don't have a null size. We let them map to overlapping file regions,
3362 * though - that's not necessarily an error
3367 MmspCheckSegmentBounds
3369 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3375 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3377 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3381 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3383 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3385 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3393 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3394 * page could be OK (Windows seems to be OK with them), and larger gaps
3395 * could lead to image sections spanning several discontiguous regions
3396 * (NtMapViewOfSection could then refuse to map them, and they could
3397 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3399 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3400 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3401 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3412 * Merges and pads an image section's segments until they all are page-aligned
3413 * and have a size that is a multiple of the page size
3418 MmspPageAlignSegments
3420 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3426 PMM_SECTION_SEGMENT EffectiveSegment
;
3428 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3430 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3435 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3437 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3440 * The first segment requires special handling
3444 ULONG_PTR VirtualAddress
;
3445 ULONG_PTR VirtualOffset
;
3447 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3449 /* Round down the virtual address to the nearest page */
3450 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3452 /* Round up the virtual size to the nearest page */
3453 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3454 EffectiveSegment
->Image
.VirtualAddress
;
3456 /* Adjust the raw address and size */
3457 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3459 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3465 * Garbage in, garbage out: unaligned base addresses make the file
3466 * offset point in curious and odd places, but that's what we were
3469 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3470 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3474 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3475 ULONG_PTR EndOfEffectiveSegment
;
3477 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3478 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3481 * The current segment begins exactly where the current effective
3482 * segment ended, therefore beginning a new effective segment
3484 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3487 ASSERT(LastSegment
<= i
);
3488 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3490 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3492 if (LastSegment
!= i
)
3495 * Copy the current segment. If necessary, the effective segment
3496 * will be expanded later
3498 *EffectiveSegment
= *Segment
;
3502 * Page-align the virtual size. We know for sure the virtual address
3505 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3506 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3509 * The current segment is still part of the current effective segment:
3510 * extend the effective segment to reflect this
3512 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3514 static const ULONG FlagsToProtection
[16] =
3522 PAGE_EXECUTE_READWRITE
,
3523 PAGE_EXECUTE_READWRITE
,
3528 PAGE_EXECUTE_WRITECOPY
,
3529 PAGE_EXECUTE_WRITECOPY
,
3530 PAGE_EXECUTE_WRITECOPY
,
3531 PAGE_EXECUTE_WRITECOPY
3534 unsigned ProtectionFlags
;
3537 * Extend the file size
3540 /* Unaligned segments must be contiguous within the file */
3541 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3542 EffectiveSegment
->RawLength
.QuadPart
))
3547 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3550 * Extend the virtual size
3552 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3554 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3555 EffectiveSegment
->Image
.VirtualAddress
;
3558 * Merge the protection
3560 EffectiveSegment
->Protection
|= Segment
->Protection
;
3562 /* Clean up redundance */
3563 ProtectionFlags
= 0;
3565 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3566 ProtectionFlags
|= 1 << 0;
3568 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3569 ProtectionFlags
|= 1 << 1;
3571 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3572 ProtectionFlags
|= 1 << 2;
3574 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3575 ProtectionFlags
|= 1 << 3;
3577 ASSERT(ProtectionFlags
< 16);
3578 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3580 /* If a segment was required to be shared and cannot, fail */
3581 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3582 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3588 * We assume no holes between segments at this point
3592 KeBugCheck(MEMORY_MANAGEMENT
);
3596 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3602 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3603 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3605 LARGE_INTEGER Offset
;
3607 PVOID FileHeaderBuffer
;
3608 ULONG FileHeaderSize
;
3610 ULONG OldNrSegments
;
3615 * Read the beginning of the file (2 pages). Should be enough to contain
3616 * all (or most) of the headers
3618 Offset
.QuadPart
= 0;
3620 /* FIXME: use FileObject instead of FileHandle */
3621 Status
= ExeFmtpReadFile (FileHandle
,
3628 if (!NT_SUCCESS(Status
))
3631 if (FileHeaderSize
== 0)
3633 ExFreePool(FileHeaderBuffer
);
3634 return STATUS_UNSUCCESSFUL
;
3638 * Look for a loader that can handle this executable
3640 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3642 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3645 /* FIXME: use FileObject instead of FileHandle */
3646 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3652 ExeFmtpAllocateSegments
);
3654 if (!NT_SUCCESS(Status
))
3656 if (ImageSectionObject
->Segments
)
3658 ExFreePool(ImageSectionObject
->Segments
);
3659 ImageSectionObject
->Segments
= NULL
;
3663 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3667 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3670 * No loader handled the format
3672 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3674 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3675 ASSERT(!NT_SUCCESS(Status
));
3678 if (!NT_SUCCESS(Status
))
3681 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3686 /* FIXME? are these values platform-dependent? */
3687 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3688 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3690 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3691 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3693 if(ImageSectionObject
->BasedAddress
== NULL
)
3695 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3696 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3698 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3702 * And now the fun part: fixing the segments
3705 /* Sort them by virtual address */
3706 MmspSortSegments(ImageSectionObject
, Flags
);
3708 /* Ensure they don't overlap in memory */
3709 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3710 return STATUS_INVALID_IMAGE_FORMAT
;
3712 /* Ensure they are aligned */
3713 OldNrSegments
= ImageSectionObject
->NrSegments
;
3715 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3716 return STATUS_INVALID_IMAGE_FORMAT
;
3718 /* Trim them if the alignment phase merged some of them */
3719 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3721 PMM_SECTION_SEGMENT Segments
;
3722 SIZE_T SizeOfSegments
;
3724 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3726 Segments
= ExAllocatePoolWithTag(PagedPool
,
3728 TAG_MM_SECTION_SEGMENT
);
3730 if (Segments
== NULL
)
3731 return STATUS_INSUFFICIENT_RESOURCES
;
3733 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3734 ExFreePool(ImageSectionObject
->Segments
);
3735 ImageSectionObject
->Segments
= Segments
;
3738 /* And finish their initialization */
3739 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3741 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3742 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3743 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3746 ASSERT(NT_SUCCESS(Status
));
3751 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3752 ACCESS_MASK DesiredAccess
,
3753 POBJECT_ATTRIBUTES ObjectAttributes
,
3754 PLARGE_INTEGER UMaximumSize
,
3755 ULONG SectionPageProtection
,
3756 ULONG AllocationAttributes
,
3757 PFILE_OBJECT FileObject
)
3759 PROS_SECTION_OBJECT Section
;
3761 PMM_SECTION_SEGMENT SectionSegments
;
3762 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3765 if (FileObject
== NULL
)
3766 return STATUS_INVALID_FILE_FOR_SECTION
;
3769 * Create the section
3771 Status
= ObCreateObject (ExGetPreviousMode(),
3772 MmSectionObjectType
,
3774 ExGetPreviousMode(),
3776 sizeof(ROS_SECTION_OBJECT
),
3779 (PVOID
*)(PVOID
)&Section
);
3780 if (!NT_SUCCESS(Status
))
3782 ObDereferenceObject(FileObject
);
3789 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3790 Section
->Type
= 'SC';
3791 Section
->Size
= 'TN';
3792 Section
->SectionPageProtection
= SectionPageProtection
;
3793 Section
->AllocationAttributes
= AllocationAttributes
;
3797 * Initialized caching for this file object if previously caching
3798 * was initialized for the same on disk file
3800 Status
= CcTryToInitializeFileCache(FileObject
);
3802 Status
= STATUS_SUCCESS
;
3805 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3807 NTSTATUS StatusExeFmt
;
3809 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3810 if (ImageSectionObject
== NULL
)
3812 ObDereferenceObject(FileObject
);
3813 ObDereferenceObject(Section
);
3814 return(STATUS_NO_MEMORY
);
3817 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3819 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3821 if (!NT_SUCCESS(StatusExeFmt
))
3823 if(ImageSectionObject
->Segments
!= NULL
)
3824 ExFreePool(ImageSectionObject
->Segments
);
3826 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3827 ObDereferenceObject(Section
);
3828 ObDereferenceObject(FileObject
);
3829 return(StatusExeFmt
);
3832 Section
->ImageSection
= ImageSectionObject
;
3833 ASSERT(ImageSectionObject
->Segments
);
3838 Status
= MmspWaitForFileLock(FileObject
);
3839 if (!NT_SUCCESS(Status
))
3841 ExFreePool(ImageSectionObject
->Segments
);
3842 ExFreePool(ImageSectionObject
);
3843 ObDereferenceObject(Section
);
3844 ObDereferenceObject(FileObject
);
3848 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3849 ImageSectionObject
, NULL
))
3852 * An other thread has initialized the same image in the background
3854 ExFreePool(ImageSectionObject
->Segments
);
3855 ExFreePool(ImageSectionObject
);
3856 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3857 Section
->ImageSection
= ImageSectionObject
;
3858 SectionSegments
= ImageSectionObject
->Segments
;
3860 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3862 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3866 Status
= StatusExeFmt
;
3873 Status
= MmspWaitForFileLock(FileObject
);
3874 if (Status
!= STATUS_SUCCESS
)
3876 ObDereferenceObject(Section
);
3877 ObDereferenceObject(FileObject
);
3881 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3882 Section
->ImageSection
= ImageSectionObject
;
3883 SectionSegments
= ImageSectionObject
->Segments
;
3886 * Otherwise just reference all the section segments
3888 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3890 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3893 Status
= STATUS_SUCCESS
;
3895 Section
->FileObject
= FileObject
;
3897 CcRosReferenceCache(FileObject
);
3899 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3900 *SectionObject
= Section
;
3907 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3908 PROS_SECTION_OBJECT Section
,
3909 PMM_SECTION_SEGMENT Segment
,
3914 ULONG AllocationType
)
3920 if (Segment
->WriteCopy
)
3922 /* We have to do this because the not present fault
3923 * and access fault handlers depend on the protection
3924 * that should be granted AFTER the COW fault takes
3925 * place to be in Region->Protect. The not present fault
3926 * handler changes this to the correct protection for COW when
3927 * mapping the pages into the process's address space. If a COW
3928 * fault takes place, the access fault handler sets the page protection
3929 * to these values for the newly copied pages
3931 if (Protect
== PAGE_WRITECOPY
)
3932 Protect
= PAGE_READWRITE
;
3933 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3934 Protect
= PAGE_EXECUTE_READWRITE
;
3937 if (*BaseAddress
== NULL
)
3938 Granularity
= MM_ALLOCATION_GRANULARITY
;
3940 Granularity
= PAGE_SIZE
;
3943 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
3944 LARGE_INTEGER FileOffset
;
3945 FileOffset
.QuadPart
= ViewOffset
;
3946 ObReferenceObject(Section
);
3947 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3950 Status
= MmCreateMemoryArea(AddressSpace
,
3951 MEMORY_AREA_SECTION_VIEW
,
3959 if (!NT_SUCCESS(Status
))
3961 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3962 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3966 ObReferenceObject((PVOID
)Section
);
3968 MArea
->Data
.SectionData
.Segment
= Segment
;
3969 MArea
->Data
.SectionData
.Section
= Section
;
3970 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3971 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3972 ViewSize
, 0, Protect
);
3974 return(STATUS_SUCCESS
);
3979 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3980 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3983 PFILE_OBJECT FileObject
;
3984 PROS_SHARED_CACHE_MAP SharedCacheMap
;
3985 LARGE_INTEGER Offset
;
3986 SWAPENTRY SavedSwapEntry
;
3987 PROS_SECTION_OBJECT Section
;
3988 PMM_SECTION_SEGMENT Segment
;
3989 PMMSUPPORT AddressSpace
;
3992 AddressSpace
= (PMMSUPPORT
)Context
;
3993 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3995 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3997 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3998 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
4000 Section
= MemoryArea
->Data
.SectionData
.Section
;
4001 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4003 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4004 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
4006 MmUnlockSectionSegment(Segment
);
4007 MmUnlockAddressSpace(AddressSpace
);
4009 MiWaitForPageEvent(NULL
, NULL
);
4011 MmLockAddressSpace(AddressSpace
);
4012 MmLockSectionSegment(Segment
);
4013 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4017 * For a dirty, datafile, non-private page mark it as dirty in the
4020 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4022 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4024 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4025 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4027 CcRosMarkDirtyVacb(SharedCacheMap
, (ULONG
)(Offset
.QuadPart
+ Segment
->Image
.FileOffset
));
4029 ASSERT(SwapEntry
== 0);
4038 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4040 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4041 KeBugCheck(MEMORY_MANAGEMENT
);
4043 MmFreeSwapPage(SwapEntry
);
4047 if (IS_SWAP_FROM_SSE(Entry
) ||
4048 Page
!= PFN_FROM_SSE(Entry
))
4053 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4055 DPRINT1("Found a private page in a pagefile section.\n");
4056 KeBugCheck(MEMORY_MANAGEMENT
);
4059 * Just dereference private pages
4061 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4062 if (SavedSwapEntry
!= 0)
4064 MmFreeSwapPage(SavedSwapEntry
);
4065 MmSetSavedSwapEntryPage(Page
, 0);
4067 MmDeleteRmap(Page
, Process
, Address
);
4068 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4072 MmDeleteRmap(Page
, Process
, Address
);
4073 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4079 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4083 PMEMORY_AREA MemoryArea
;
4084 PROS_SECTION_OBJECT Section
;
4085 PMM_SECTION_SEGMENT Segment
;
4086 PLIST_ENTRY CurrentEntry
;
4087 PMM_REGION CurrentRegion
;
4088 PLIST_ENTRY RegionListHead
;
4090 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4092 if (MemoryArea
== NULL
)
4094 return(STATUS_UNSUCCESSFUL
);
4097 MemoryArea
->DeleteInProgress
= TRUE
;
4098 Section
= MemoryArea
->Data
.SectionData
.Section
;
4099 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4102 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4103 return MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4106 MmLockSectionSegment(Segment
);
4108 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4109 while (!IsListEmpty(RegionListHead
))
4111 CurrentEntry
= RemoveHeadList(RegionListHead
);
4112 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4113 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4116 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4118 Status
= MmFreeMemoryArea(AddressSpace
,
4125 Status
= MmFreeMemoryArea(AddressSpace
,
4130 MmUnlockSectionSegment(Segment
);
4131 ObDereferenceObject(Section
);
4137 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4138 IN PVOID BaseAddress
,
4142 PMEMORY_AREA MemoryArea
;
4143 PMMSUPPORT AddressSpace
;
4144 PROS_SECTION_OBJECT Section
;
4145 PVOID ImageBaseAddress
= 0;
4147 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4148 Process
, BaseAddress
);
4152 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4154 MmLockAddressSpace(AddressSpace
);
4155 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4157 if (MemoryArea
== NULL
||
4158 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4159 MemoryArea
->DeleteInProgress
)
4161 if (MemoryArea
) NT_ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4162 MmUnlockAddressSpace(AddressSpace
);
4163 return STATUS_NOT_MAPPED_VIEW
;
4166 MemoryArea
->DeleteInProgress
= TRUE
;
4168 Section
= MemoryArea
->Data
.SectionData
.Section
;
4170 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4174 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4175 PMM_SECTION_SEGMENT SectionSegments
;
4176 PMM_SECTION_SEGMENT Segment
;
4178 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4179 ImageSectionObject
= Section
->ImageSection
;
4180 SectionSegments
= ImageSectionObject
->Segments
;
4181 NrSegments
= ImageSectionObject
->NrSegments
;
4183 /* Search for the current segment within the section segments
4184 * and calculate the image base address */
4185 for (i
= 0; i
< NrSegments
; i
++)
4187 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4189 if (Segment
== &SectionSegments
[i
])
4191 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4196 if (i
>= NrSegments
)
4198 KeBugCheck(MEMORY_MANAGEMENT
);
4201 for (i
= 0; i
< NrSegments
; i
++)
4203 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4205 PVOID SBaseAddress
= (PVOID
)
4206 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4208 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4209 NT_ASSERT(NT_SUCCESS(Status
));
4215 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4216 NT_ASSERT(NT_SUCCESS(Status
));
4219 MmUnlockAddressSpace(AddressSpace
);
4221 /* Notify debugger */
4222 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4224 return(STATUS_SUCCESS
);
4231 * Queries the information of a section object.
4233 * @param SectionHandle
4234 * Handle to the section object. It must be opened with SECTION_QUERY
4236 * @param SectionInformationClass
4237 * Index to a certain information structure. Can be either
4238 * SectionBasicInformation or SectionImageInformation. The latter
4239 * is valid only for sections that were created with the SEC_IMAGE
4241 * @param SectionInformation
4242 * Caller supplies storage for resulting information.
4244 * Size of the supplied storage.
4245 * @param ResultLength
4253 NtQuerySection(IN HANDLE SectionHandle
,
4254 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4255 OUT PVOID SectionInformation
,
4256 IN SIZE_T SectionInformationLength
,
4257 OUT PSIZE_T ResultLength OPTIONAL
)
4259 PROS_SECTION_OBJECT Section
;
4260 KPROCESSOR_MODE PreviousMode
;
4264 PreviousMode
= ExGetPreviousMode();
4266 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4268 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4270 (ULONG
)SectionInformationLength
,
4275 if(!NT_SUCCESS(Status
))
4277 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4281 Status
= ObReferenceObjectByHandle(SectionHandle
,
4283 MmSectionObjectType
,
4285 (PVOID
*)(PVOID
)&Section
,
4287 if (NT_SUCCESS(Status
))
4289 switch (SectionInformationClass
)
4291 case SectionBasicInformation
:
4293 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4297 Sbi
->Attributes
= Section
->AllocationAttributes
;
4298 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4300 Sbi
->BaseAddress
= 0;
4301 Sbi
->Size
.QuadPart
= 0;
4305 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4306 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4309 if (ResultLength
!= NULL
)
4311 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4313 Status
= STATUS_SUCCESS
;
4315 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4317 Status
= _SEH2_GetExceptionCode();
4324 case SectionImageInformation
:
4326 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4330 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4332 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4333 ImageSectionObject
= Section
->ImageSection
;
4335 *Sii
= ImageSectionObject
->ImageInformation
;
4338 if (ResultLength
!= NULL
)
4340 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4342 Status
= STATUS_SUCCESS
;
4344 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4346 Status
= _SEH2_GetExceptionCode();
4354 ObDereferenceObject(Section
);
4360 /**********************************************************************
4362 * MmMapViewOfSection
4365 * Maps a view of a section into the virtual address space of a
4370 * Pointer to the section object.
4373 * Pointer to the process.
4376 * Desired base address (or NULL) on entry;
4377 * Actual base address of the view on exit.
4380 * Number of high order address bits that must be zero.
4383 * Size in bytes of the initially committed section of
4387 * Offset in bytes from the beginning of the section
4388 * to the beginning of the view.
4391 * Desired length of map (or zero to map all) on entry
4392 * Actual length mapped on exit.
4394 * InheritDisposition
4395 * Specified how the view is to be shared with
4399 * Type of allocation for the pages.
4402 * Protection for the committed region of the view.
4410 MmMapViewOfSection(IN PVOID SectionObject
,
4411 IN PEPROCESS Process
,
4412 IN OUT PVOID
*BaseAddress
,
4413 IN ULONG_PTR ZeroBits
,
4414 IN SIZE_T CommitSize
,
4415 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4416 IN OUT PSIZE_T ViewSize
,
4417 IN SECTION_INHERIT InheritDisposition
,
4418 IN ULONG AllocationType
,
4421 PROS_SECTION_OBJECT Section
;
4422 PMMSUPPORT AddressSpace
;
4424 NTSTATUS Status
= STATUS_SUCCESS
;
4425 BOOLEAN NotAtBase
= FALSE
;
4427 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4429 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4430 return MmMapViewOfArm3Section(SectionObject
,
4444 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4446 return STATUS_INVALID_PAGE_PROTECTION
;
4450 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4451 AddressSpace
= &Process
->Vm
;
4453 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4455 MmLockAddressSpace(AddressSpace
);
4457 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4461 ULONG_PTR ImageBase
;
4463 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4464 PMM_SECTION_SEGMENT SectionSegments
;
4466 ImageSectionObject
= Section
->ImageSection
;
4467 SectionSegments
= ImageSectionObject
->Segments
;
4468 NrSegments
= ImageSectionObject
->NrSegments
;
4470 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4473 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4477 for (i
= 0; i
< NrSegments
; i
++)
4479 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4481 ULONG_PTR MaxExtent
;
4482 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4483 SectionSegments
[i
].Length
.QuadPart
);
4484 ImageSize
= max(ImageSize
, MaxExtent
);
4488 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4490 /* Check for an illegal base address */
4491 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4492 ((ImageBase
+ ImageSize
) < ImageSize
))
4494 NT_ASSERT(*BaseAddress
== NULL
);
4495 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4496 MM_VIRTMEM_GRANULARITY
);
4499 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4501 NT_ASSERT(*BaseAddress
== NULL
);
4502 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4506 /* Check there is enough space to map the section at that point. */
4507 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4508 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4510 /* Fail if the user requested a fixed base address. */
4511 if ((*BaseAddress
) != NULL
)
4513 MmUnlockAddressSpace(AddressSpace
);
4514 return(STATUS_CONFLICTING_ADDRESSES
);
4516 /* Otherwise find a gap to map the image. */
4517 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4520 MmUnlockAddressSpace(AddressSpace
);
4521 return(STATUS_CONFLICTING_ADDRESSES
);
4523 /* Remember that we loaded image at a different base address */
4527 for (i
= 0; i
< NrSegments
; i
++)
4529 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4531 PVOID SBaseAddress
= (PVOID
)
4532 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4533 MmLockSectionSegment(&SectionSegments
[i
]);
4534 Status
= MmMapViewOfSegment(AddressSpace
,
4536 &SectionSegments
[i
],
4538 SectionSegments
[i
].Length
.LowPart
,
4539 SectionSegments
[i
].Protection
,
4542 MmUnlockSectionSegment(&SectionSegments
[i
]);
4543 if (!NT_SUCCESS(Status
))
4545 MmUnlockAddressSpace(AddressSpace
);
4551 *BaseAddress
= (PVOID
)ImageBase
;
4552 *ViewSize
= ImageSize
;
4556 /* check for write access */
4557 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4558 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4560 MmUnlockAddressSpace(AddressSpace
);
4561 return STATUS_SECTION_PROTECTION
;
4563 /* check for read access */
4564 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4565 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4567 MmUnlockAddressSpace(AddressSpace
);
4568 return STATUS_SECTION_PROTECTION
;
4570 /* check for execute access */
4571 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4572 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4574 MmUnlockAddressSpace(AddressSpace
);
4575 return STATUS_SECTION_PROTECTION
;
4578 if (ViewSize
== NULL
)
4580 /* Following this pointer would lead to us to the dark side */
4581 /* What to do? Bugcheck? Return status? Do the mambo? */
4582 KeBugCheck(MEMORY_MANAGEMENT
);
4585 if (SectionOffset
== NULL
)
4591 ViewOffset
= SectionOffset
->u
.LowPart
;
4594 if ((ViewOffset
% PAGE_SIZE
) != 0)
4596 MmUnlockAddressSpace(AddressSpace
);
4597 return(STATUS_MAPPED_ALIGNMENT
);
4600 if ((*ViewSize
) == 0)
4602 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4604 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4606 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4609 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4611 MmLockSectionSegment(Section
->Segment
);
4612 Status
= MmMapViewOfSegment(AddressSpace
,
4619 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4620 MmUnlockSectionSegment(Section
->Segment
);
4621 if (!NT_SUCCESS(Status
))
4623 MmUnlockAddressSpace(AddressSpace
);
4628 MmUnlockAddressSpace(AddressSpace
);
4629 NT_ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4632 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4634 Status
= STATUS_SUCCESS
;
4643 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4644 IN PLARGE_INTEGER NewFileSize
)
4646 /* Check whether an ImageSectionObject exists */
4647 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4649 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4653 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4655 PMM_SECTION_SEGMENT Segment
;
4657 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4660 if (Segment
->ReferenceCount
!= 0)
4663 CC_FILE_SIZES FileSizes
;
4665 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4668 /* Check size of file */
4669 if (SectionObjectPointer
->SharedCacheMap
)
4671 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4676 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4685 /* Check size of file */
4686 if (SectionObjectPointer
->SharedCacheMap
)
4688 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4689 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4698 /* Something must gone wrong
4699 * how can we have a Section but no
4701 DPRINT("ERROR: DataSectionObject without reference!\n");
4705 DPRINT("FIXME: didn't check for outstanding write probes\n");
4717 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4718 IN MMFLUSH_TYPE FlushType
)
4720 BOOLEAN Result
= TRUE
;
4722 PMM_SECTION_SEGMENT Segment
;
4727 case MmFlushForDelete
:
4728 if (SectionObjectPointer
->ImageSectionObject
||
4729 SectionObjectPointer
->DataSectionObject
)
4734 CcRosRemoveIfClosed(SectionObjectPointer
);
4737 case MmFlushForWrite
:
4739 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4741 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4744 if (SectionObjectPointer
->ImageSectionObject
) {
4745 DPRINT1("SectionObject has ImageSection\n");
4751 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4753 DPRINT("Result %d\n", Result
);
4765 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4766 OUT PVOID
* MappedBase
,
4767 IN OUT PSIZE_T ViewSize
)
4769 PROS_SECTION_OBJECT Section
;
4770 PMMSUPPORT AddressSpace
;
4774 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4776 return MiMapViewInSystemSpace(SectionObject
,
4782 DPRINT("MmMapViewInSystemSpace() called\n");
4784 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4785 AddressSpace
= MmGetKernelAddressSpace();
4787 MmLockAddressSpace(AddressSpace
);
4790 if ((*ViewSize
) == 0)
4792 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4794 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4796 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4799 MmLockSectionSegment(Section
->Segment
);
4802 Status
= MmMapViewOfSegment(AddressSpace
,
4811 MmUnlockSectionSegment(Section
->Segment
);
4812 MmUnlockAddressSpace(AddressSpace
);
4819 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4821 PMMSUPPORT AddressSpace
;
4824 DPRINT("MmUnmapViewInSystemSpace() called\n");
4826 AddressSpace
= MmGetKernelAddressSpace();
4828 MmLockAddressSpace(AddressSpace
);
4830 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4832 MmUnlockAddressSpace(AddressSpace
);
4837 /**********************************************************************
4842 * Creates a section object.
4845 * SectionObject (OUT)
4846 * Caller supplied storage for the resulting pointer
4847 * to a SECTION_OBJECT instance;
4850 * Specifies the desired access to the section can be a
4852 * STANDARD_RIGHTS_REQUIRED |
4854 * SECTION_MAP_WRITE |
4855 * SECTION_MAP_READ |
4856 * SECTION_MAP_EXECUTE
4858 * ObjectAttributes [OPTIONAL]
4859 * Initialized attributes for the object can be used
4860 * to create a named section;
4863 * Maximizes the size of the memory section. Must be
4864 * non-NULL for a page-file backed section.
4865 * If value specified for a mapped file and the file is
4866 * not large enough, file will be extended.
4868 * SectionPageProtection
4869 * Can be a combination of:
4875 * AllocationAttributes
4876 * Can be a combination of:
4881 * Handle to a file to create a section mapped to a file
4882 * instead of a memory backed section;
4893 MmCreateSection (OUT PVOID
* Section
,
4894 IN ACCESS_MASK DesiredAccess
,
4895 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4896 IN PLARGE_INTEGER MaximumSize
,
4897 IN ULONG SectionPageProtection
,
4898 IN ULONG AllocationAttributes
,
4899 IN HANDLE FileHandle OPTIONAL
,
4900 IN PFILE_OBJECT FileObject OPTIONAL
)
4904 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4906 /* Check if an ARM3 section is being created instead */
4907 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4909 if (!(FileObject
) && !(FileHandle
))
4911 return MmCreateArm3Section(Section
,
4915 SectionPageProtection
,
4916 AllocationAttributes
&~ 1,
4922 /* Convert section flag to page flag */
4923 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4925 /* Check to make sure the protection is correct. Nt* does this already */
4926 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4927 if (Protection
== MM_INVALID_PROTECTION
)
4929 DPRINT1("Page protection is invalid\n");
4930 return STATUS_INVALID_PAGE_PROTECTION
;
4933 /* Check if this is going to be a data or image backed file section */
4934 if ((FileHandle
) || (FileObject
))
4936 /* These cannot be mapped with large pages */
4937 if (AllocationAttributes
& SEC_LARGE_PAGES
)
4939 DPRINT1("Large pages cannot be used with an image mapping\n");
4940 return STATUS_INVALID_PARAMETER_6
;
4943 /* Did the caller pass an object? */
4946 /* Reference the object directly */
4947 ObReferenceObject(FileObject
);
4951 /* Reference the file handle to get the object */
4952 Status
= ObReferenceObjectByHandle(FileHandle
,
4953 MmMakeFileAccess
[Protection
],
4955 ExGetPreviousMode(),
4956 (PVOID
*)&FileObject
,
4958 if (!NT_SUCCESS(Status
))
4960 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
4967 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
4968 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
4971 #ifndef NEWCC // A hack for initializing caching.
4972 // This is needed only in the old case.
4975 IO_STATUS_BLOCK Iosb
;
4978 LARGE_INTEGER ByteOffset
;
4979 ByteOffset
.QuadPart
= 0;
4980 Status
= ZwReadFile(FileHandle
,
4989 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
4991 DPRINT1("CC failure: %lx\n", Status
);
4994 // Caching is initialized...
4998 if (AllocationAttributes
& SEC_IMAGE
)
5000 Status
= MmCreateImageSection(SectionObject
,
5004 SectionPageProtection
,
5005 AllocationAttributes
,
5009 else if (FileHandle
!= NULL
)
5011 Status
= MmCreateDataFileSection(SectionObject
,
5015 SectionPageProtection
,
5016 AllocationAttributes
,
5019 ObDereferenceObject(FileObject
);
5022 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5024 Status
= MmCreateCacheSection(SectionObject
,
5028 SectionPageProtection
,
5029 AllocationAttributes
,
5035 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5037 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5039 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5040 Status
= MmCreatePageFileSection(SectionObject
,
5044 SectionPageProtection
,
5045 AllocationAttributes
);