2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
48 #include "../cache/newcc.h"
49 #include "../cache/section/newmm.h"
52 #include <reactos/exeformat.h>
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 #include "ARM3/miarm.h"
61 #undef MmSetPageEntrySectionSegment
62 #define MmSetPageEntrySectionSegment(S,O,E) do { \
63 DPRINT("SetPageEntrySectionSegment(old,%p,%x,%x)\n",(S),(O)->LowPart,E); \
64 _MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__); \
67 extern MMSESSION MmSession
;
71 MiMapViewInSystemSpace(IN PVOID Section
,
73 OUT PVOID
*MappedBase
,
74 IN OUT PSIZE_T ViewSize
);
78 MmCreateArm3Section(OUT PVOID
*SectionObject
,
79 IN ACCESS_MASK DesiredAccess
,
80 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
81 IN PLARGE_INTEGER InputMaximumSize
,
82 IN ULONG SectionPageProtection
,
83 IN ULONG AllocationAttributes
,
84 IN HANDLE FileHandle OPTIONAL
,
85 IN PFILE_OBJECT FileObject OPTIONAL
);
89 MmMapViewOfArm3Section(IN PVOID SectionObject
,
91 IN OUT PVOID
*BaseAddress
,
92 IN ULONG_PTR ZeroBits
,
94 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
95 IN OUT PSIZE_T ViewSize
,
96 IN SECTION_INHERIT InheritDisposition
,
97 IN ULONG AllocationType
,
101 // PeFmtCreateSection depends on the following:
103 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
104 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
106 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
107 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
108 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
110 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
111 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
112 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
113 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
114 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
115 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
116 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
117 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
118 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
120 /* TYPES *********************************************************************/
124 PROS_SECTION_OBJECT Section
;
125 PMM_SECTION_SEGMENT Segment
;
126 LARGE_INTEGER Offset
;
129 PEPROCESS CallingProcess
;
130 ULONG_PTR SectionEntry
;
132 MM_SECTION_PAGEOUT_CONTEXT
;
134 /* GLOBALS *******************************************************************/
136 POBJECT_TYPE MmSectionObjectType
= NULL
;
138 ULONG_PTR MmSubsectionBase
;
140 static ULONG SectionCharacteristicsToProtect
[16] =
142 PAGE_NOACCESS
, /* 0 = NONE */
143 PAGE_NOACCESS
, /* 1 = SHARED */
144 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
145 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
146 PAGE_READONLY
, /* 4 = READABLE */
147 PAGE_READONLY
, /* 5 = READABLE, SHARED */
148 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
149 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
151 * FIXME? do we really need the WriteCopy field in segments? can't we use
152 * PAGE_WRITECOPY here?
154 PAGE_READWRITE
, /* 8 = WRITABLE */
155 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
156 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
157 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
158 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
159 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
160 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
161 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
164 extern ULONG MmMakeFileAccess
[];
165 ACCESS_MASK NTAPI
MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection
);
166 static GENERIC_MAPPING MmpSectionMapping
=
168 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
169 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
170 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
174 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
176 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
177 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
180 /* FUNCTIONS *****************************************************************/
185 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
186 File Format Specification", revision 6.0 (February 1999)
188 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
189 IN SIZE_T FileHeaderSize
,
191 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
193 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
194 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
197 ULONG cbFileHeaderOffsetSize
= 0;
198 ULONG cbSectionHeadersOffset
= 0;
199 ULONG cbSectionHeadersSize
;
200 ULONG cbSectionHeadersOffsetSize
= 0;
201 ULONG cbOptHeaderSize
;
202 ULONG cbHeadersSize
= 0;
203 ULONG nSectionAlignment
;
204 ULONG nFileAlignment
;
206 const IMAGE_DOS_HEADER
* pidhDosHeader
;
207 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
208 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
209 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
210 PMM_SECTION_SEGMENT pssSegments
;
211 LARGE_INTEGER lnOffset
;
213 SIZE_T nPrevVirtualEndOfSegment
= 0;
214 ULONG nFileSizeOfHeaders
= 0;
218 ASSERT(FileHeaderSize
> 0);
220 ASSERT(ImageSectionObject
);
222 ASSERT(AllocateSegmentsCb
);
224 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
226 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
228 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
231 pidhDosHeader
= FileHeader
;
234 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
236 /* image too small to be an MZ executable */
237 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
238 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
240 /* no MZ signature */
241 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
242 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
244 /* not a Windows executable */
245 if(pidhDosHeader
->e_lfanew
<= 0)
246 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
249 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
251 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
252 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
254 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
259 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
260 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
262 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
263 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
267 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
268 * need to read the header from the file
270 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
271 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
273 ULONG cbNtHeaderSize
;
277 l_ReadHeaderFromFile
:
279 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
281 /* read the header from the file */
282 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
284 if(!NT_SUCCESS(nStatus
))
286 NTSTATUS ReturnedStatus
= nStatus
;
288 /* If it attempted to read past the end of the file, it means e_lfanew is invalid */
289 if (ReturnedStatus
== STATUS_END_OF_FILE
) nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
291 DIE(("ReadFile failed, status %08X\n", ReturnedStatus
));
296 ASSERT(cbReadSize
> 0);
298 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
300 /* the buffer doesn't contain the file header */
301 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
302 DIE(("The file doesn't contain the PE file header\n"));
304 pinhNtHeader
= pData
;
306 /* object still not aligned: copy it to the beginning of the buffer */
307 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
309 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
310 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
311 pinhNtHeader
= pBuffer
;
314 /* invalid NT header */
315 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
317 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
318 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
320 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
322 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
323 DIE(("The full NT header is too large\n"));
325 /* the buffer doesn't contain the whole NT header */
326 if(cbReadSize
< cbNtHeaderSize
)
327 DIE(("The file doesn't contain the full NT header\n"));
331 ULONG cbOptHeaderOffsetSize
= 0;
333 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
335 /* don't trust an invalid NT header */
336 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
337 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
339 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
340 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
342 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
343 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
345 /* the buffer doesn't contain the whole NT header: read it from the file */
346 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
347 goto l_ReadHeaderFromFile
;
350 /* read information from the NT header */
351 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
352 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
354 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
356 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
357 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
359 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
361 switch(piohOptHeader
->Magic
)
363 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
364 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
368 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
371 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
372 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
374 /* See [1], section 3.4.2 */
375 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
377 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
378 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
380 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
381 DIE(("The section alignment is smaller than the file alignment\n"));
383 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
384 nFileAlignment
= piohOptHeader
->FileAlignment
;
386 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
387 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
391 nSectionAlignment
= PAGE_SIZE
;
392 nFileAlignment
= PAGE_SIZE
;
395 ASSERT(IsPowerOf2(nSectionAlignment
));
396 ASSERT(IsPowerOf2(nFileAlignment
));
398 switch(piohOptHeader
->Magic
)
401 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
403 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
404 ImageBase
= piohOptHeader
->ImageBase
;
406 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
407 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
409 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
410 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
412 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
413 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
415 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
417 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
419 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
420 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
422 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
423 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
427 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
429 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
430 piohOptHeader
->AddressOfEntryPoint
);
433 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
434 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
436 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
438 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
440 if (piohOptHeader
->AddressOfEntryPoint
== 0)
442 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
446 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
447 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
449 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
451 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
454 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
455 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
456 * magic to any binary.
458 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
459 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
460 * the SxS support -- at which point, duh, this should be removed.
462 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
464 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
471 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
473 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
475 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
477 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
479 ImageBase
= pioh64OptHeader
->ImageBase
;
480 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
481 DIE(("ImageBase exceeds the address space\n"));
484 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
486 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
487 DIE(("SizeOfImage exceeds the address space\n"));
489 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
492 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
494 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
495 DIE(("SizeOfStackReserve exceeds the address space\n"));
497 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
500 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
502 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
503 DIE(("SizeOfStackCommit exceeds the address space\n"));
505 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
508 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
510 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
512 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
513 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
515 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
516 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
520 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
522 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
523 pioh64OptHeader
->AddressOfEntryPoint
);
526 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
527 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
529 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
531 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
533 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
535 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
539 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
540 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
542 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
543 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
550 /* [1], section 3.4.2 */
551 if((ULONG_PTR
)ImageBase
% 0x10000)
552 DIE(("ImageBase is not aligned on a 64KB boundary"));
554 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
555 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
556 ImageSectionObject
->ImageInformation
.GpValue
= 0;
557 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
558 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
560 /* SECTION HEADERS */
561 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
563 /* see [1], section 3.3 */
564 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
565 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
568 * the additional segment is for the file's headers. They need to be present for
569 * the benefit of the dynamic loader (to locate exports, defaults for thread
570 * parameters, resources, etc.)
572 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
574 /* file offset for the section headers */
575 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
576 DIE(("Offset overflow\n"));
578 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
579 DIE(("Offset overflow\n"));
581 /* size of the section headers */
582 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
583 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
585 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
586 DIE(("Section headers too large\n"));
588 /* size of the executable's headers */
589 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
591 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
592 // DIE(("SizeOfHeaders is not aligned\n"));
594 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
595 DIE(("The section headers overflow SizeOfHeaders\n"));
597 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
599 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
600 DIE(("Overflow aligning the size of headers\n"));
607 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
608 /* WARNING: piohOptHeader IS NO LONGER USABLE */
609 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
611 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
612 pishSectionHeaders
= NULL
;
616 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
617 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
619 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
620 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
624 * the buffer doesn't contain the section headers, or the alignment is wrong:
625 * read the headers from the file
627 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
628 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
633 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
635 /* read the header from the file */
636 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
638 if(!NT_SUCCESS(nStatus
))
639 DIE(("ReadFile failed with status %08X\n", nStatus
));
643 ASSERT(cbReadSize
> 0);
645 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
647 /* the buffer doesn't contain all the section headers */
648 if(cbReadSize
< cbSectionHeadersSize
)
649 DIE(("The file doesn't contain all of the section headers\n"));
651 pishSectionHeaders
= pData
;
653 /* object still not aligned: copy it to the beginning of the buffer */
654 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
656 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
657 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
658 pishSectionHeaders
= pBuffer
;
663 /* allocate the segments */
664 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
665 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
667 if(ImageSectionObject
->Segments
== NULL
)
668 DIE(("AllocateSegments failed\n"));
670 /* initialize the headers segment */
671 pssSegments
= ImageSectionObject
->Segments
;
673 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
675 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
676 DIE(("Cannot align the size of the section headers\n"));
678 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
679 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
680 DIE(("Cannot align the size of the section headers\n"));
682 pssSegments
[0].Image
.FileOffset
= 0;
683 pssSegments
[0].Protection
= PAGE_READONLY
;
684 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
685 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
686 pssSegments
[0].Image
.VirtualAddress
= 0;
687 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
688 pssSegments
[0].WriteCopy
= TRUE
;
690 /* skip the headers segment */
693 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
695 /* convert the executable sections into segments. See also [1], section 4 */
696 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
698 ULONG nCharacteristics
;
700 /* validate the alignment */
701 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
702 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
704 /* sections must be contiguous, ordered by base address and non-overlapping */
705 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
706 DIE(("Memory gap between section %u and the previous\n", i
));
708 /* ignore explicit BSS sections */
709 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
711 /* validate the alignment */
713 /* Yes, this should be a multiple of FileAlignment, but there's
714 * stuff out there that isn't. We can cope with that
716 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
717 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
720 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
721 // DIE(("PointerToRawData[%u] is not aligned\n", i));
724 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
725 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
729 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
730 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
733 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
735 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
737 /* no explicit protection */
738 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
740 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
741 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
743 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
744 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
746 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
747 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
750 /* see table above */
751 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
752 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
754 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
755 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
757 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
759 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
760 /* FIXME: always false */
761 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
762 DIE(("Cannot align the virtual size of section %u\n", i
));
764 if(pssSegments
[i
].Length
.QuadPart
== 0)
765 DIE(("Virtual size of section %u is null\n", i
));
767 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
768 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
770 /* ensure the memory image is no larger than 4GB */
771 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
772 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
773 DIE(("The image is too large\n"));
776 if(nSectionAlignment
>= PAGE_SIZE
)
777 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
780 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
790 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
791 * ARGUMENTS: PFILE_OBJECT to wait for.
792 * RETURNS: Status of the wait.
795 MmspWaitForFileLock(PFILE_OBJECT File
)
797 return STATUS_SUCCESS
;
798 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
803 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
805 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
807 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
808 PMM_SECTION_SEGMENT SectionSegments
;
812 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
813 NrSegments
= ImageSectionObject
->NrSegments
;
814 SectionSegments
= ImageSectionObject
->Segments
;
815 for (i
= 0; i
< NrSegments
; i
++)
817 if (SectionSegments
[i
].ReferenceCount
!= 0)
819 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
820 SectionSegments
[i
].ReferenceCount
);
821 KeBugCheck(MEMORY_MANAGEMENT
);
823 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
825 ExFreePool(ImageSectionObject
->Segments
);
826 ExFreePool(ImageSectionObject
);
827 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
829 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
831 PMM_SECTION_SEGMENT Segment
;
833 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
836 if (Segment
->ReferenceCount
!= 0)
838 DPRINT1("Data segment still referenced\n");
839 KeBugCheck(MEMORY_MANAGEMENT
);
841 MmFreePageTablesSectionSegment(Segment
, NULL
);
843 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
849 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
850 PLARGE_INTEGER Offset
)
854 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
857 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
858 KeBugCheck(MEMORY_MANAGEMENT
);
860 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
862 DPRINT1("Maximum share count reached\n");
863 KeBugCheck(MEMORY_MANAGEMENT
);
865 if (IS_SWAP_FROM_SSE(Entry
))
867 KeBugCheck(MEMORY_MANAGEMENT
);
869 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
870 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
875 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
876 PMM_SECTION_SEGMENT Segment
,
877 PLARGE_INTEGER Offset
,
882 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
883 BOOLEAN IsDirectMapped
= FALSE
;
887 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
888 KeBugCheck(MEMORY_MANAGEMENT
);
890 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
892 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
893 KeBugCheck(MEMORY_MANAGEMENT
);
895 if (IS_SWAP_FROM_SSE(Entry
))
897 KeBugCheck(MEMORY_MANAGEMENT
);
899 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
901 * If we reducing the share count of this entry to zero then set the entry
902 * to zero and tell the cache the page is no longer mapped.
904 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
906 PFILE_OBJECT FileObject
;
908 PROS_SHARED_CACHE_MAP SharedCacheMap
;
910 SWAPENTRY SavedSwapEntry
;
912 BOOLEAN IsImageSection
;
913 LARGE_INTEGER FileOffset
;
915 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
917 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
919 Page
= PFN_FROM_SSE(Entry
);
920 FileObject
= Section
->FileObject
;
921 if (FileObject
!= NULL
&&
922 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
926 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
927 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
930 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
931 IsDirectMapped
= TRUE
;
933 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
.QuadPart
, Dirty
);
935 Status
= STATUS_SUCCESS
;
937 if (!NT_SUCCESS(Status
))
939 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
940 KeBugCheck(MEMORY_MANAGEMENT
);
946 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
947 if (SavedSwapEntry
== 0)
950 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
951 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
955 * Try to page out this page and set the swap entry
956 * within the section segment. There exist no rmap entry
957 * for this page. The pager thread can't page out a
958 * page without a rmap entry.
960 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
961 if (InEntry
) *InEntry
= Entry
;
962 MiSetPageEvent(NULL
, NULL
);
966 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
967 if (InEntry
) *InEntry
= 0;
968 MiSetPageEvent(NULL
, NULL
);
971 MmReleasePageMemoryConsumer(MC_USER
, Page
);
977 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
978 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
986 * We hold all locks. Nobody can do something with the current
987 * process and the current segment (also not within an other process).
990 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
991 if (!NT_SUCCESS(Status
))
993 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
994 KeBugCheck(MEMORY_MANAGEMENT
);
997 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
998 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
999 MmSetSavedSwapEntryPage(Page
, 0);
1000 MiSetPageEvent(NULL
, NULL
);
1002 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1006 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1007 KeBugCheck(MEMORY_MANAGEMENT
);
1016 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1018 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1021 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1025 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1027 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1029 SharedCacheMap
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1030 Vacb
= CcRosLookupVacb(SharedCacheMap
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
);
1033 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, FALSE
, TRUE
);
1043 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1047 PVOID DestAddress
, SrcAddress
;
1049 Process
= PsGetCurrentProcess();
1050 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1051 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1052 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1054 return(STATUS_NO_MEMORY
);
1056 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1057 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1058 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1059 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1060 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1061 return(STATUS_SUCCESS
);
1067 MiReadPage(PMEMORY_AREA MemoryArea
,
1071 * FUNCTION: Read a page for a section backed memory area.
1073 * MemoryArea - Memory area to read the page for.
1074 * Offset - Offset of the page to read.
1075 * Page - Variable that receives a page contains the read data.
1078 LONGLONG BaseOffset
;
1079 LONGLONG FileOffset
;
1083 PFILE_OBJECT FileObject
;
1086 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1087 BOOLEAN IsImageSection
;
1090 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1091 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1092 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
;
1093 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1094 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1096 ASSERT(SharedCacheMap
);
1098 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1101 * If the file system is letting us go directly to the cache and the
1102 * memory area was mapped at an offset in the file which is page aligned
1103 * then get the related VACB.
1105 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1106 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1107 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1111 * Get the related VACB; we use a lower level interface than
1112 * filesystems do because it is safe for us to use an offset with an
1113 * alignment less than the file system block size.
1115 Status
= CcRosGetVacb(SharedCacheMap
,
1121 if (!NT_SUCCESS(Status
))
1128 * If the VACB isn't up to date then call the file
1129 * system to read in the data.
1131 Status
= CcReadVirtualAddress(Vacb
);
1132 if (!NT_SUCCESS(Status
))
1134 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1139 /* Probe the page, since it's PDE might not be synced */
1140 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1143 * Retrieve the page from the view that we actually want.
1145 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1146 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1148 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, TRUE
);
1155 LONGLONG VacbOffset
;
1158 * Allocate a page, this is rather complicated by the possibility
1159 * we might have to move other things out of memory
1161 MI_SET_USAGE(MI_USAGE_SECTION
);
1162 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1163 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1164 if (!NT_SUCCESS(Status
))
1168 Status
= CcRosGetVacb(SharedCacheMap
,
1174 if (!NT_SUCCESS(Status
))
1181 * If the VACB isn't up to date then call the file
1182 * system to read in the data.
1184 Status
= CcReadVirtualAddress(Vacb
);
1185 if (!NT_SUCCESS(Status
))
1187 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1192 Process
= PsGetCurrentProcess();
1193 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1194 VacbOffset
= BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
;
1195 Length
= RawLength
- SegOffset
;
1196 if (Length
<= VacbOffset
&& Length
<= PAGE_SIZE
)
1198 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1200 else if (VacbOffset
>= PAGE_SIZE
)
1202 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1206 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, VacbOffset
);
1207 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1208 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1209 Status
= CcRosGetVacb(SharedCacheMap
,
1210 FileOffset
+ VacbOffset
,
1215 if (!NT_SUCCESS(Status
))
1222 * If the VACB isn't up to date then call the file
1223 * system to read in the data.
1225 Status
= CcReadVirtualAddress(Vacb
);
1226 if (!NT_SUCCESS(Status
))
1228 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1232 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1233 if (Length
< PAGE_SIZE
)
1235 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, Length
- VacbOffset
);
1239 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, PAGE_SIZE
- VacbOffset
);
1242 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1243 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1245 return(STATUS_SUCCESS
);
1250 MiReadPage(PMEMORY_AREA MemoryArea
,
1254 * FUNCTION: Read a page for a section backed memory area.
1256 * MemoryArea - Memory area to read the page for.
1257 * Offset - Offset of the page to read.
1258 * Page - Variable that receives a page contains the read data.
1261 MM_REQUIRED_RESOURCES Resources
;
1264 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1266 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1267 Resources
.FileOffset
.QuadPart
= SegOffset
+
1268 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1269 Resources
.Consumer
= MC_USER
;
1270 Resources
.Amount
= PAGE_SIZE
;
1272 DPRINT("%S, offset 0x%x, len 0x%x, page 0x%x\n", ((PFILE_OBJECT
)Resources
.Context
)->FileName
.Buffer
, Resources
.FileOffset
.LowPart
, Resources
.Amount
, Resources
.Page
[0]);
1274 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1275 *Page
= Resources
.Page
[0];
1282 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1283 MEMORY_AREA
* MemoryArea
,
1287 LARGE_INTEGER Offset
;
1290 PROS_SECTION_OBJECT Section
;
1291 PMM_SECTION_SEGMENT Segment
;
1296 BOOLEAN HasSwapEntry
;
1298 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1299 SWAPENTRY SwapEntry
;
1302 * There is a window between taking the page fault and locking the
1303 * address space when another thread could load the page so we check
1306 if (MmIsPagePresent(Process
, Address
))
1308 return(STATUS_SUCCESS
);
1311 if (MmIsDisabledPage(Process
, Address
))
1313 return(STATUS_ACCESS_VIOLATION
);
1317 * Check for the virtual memory area being deleted.
1319 if (MemoryArea
->DeleteInProgress
)
1321 return(STATUS_UNSUCCESSFUL
);
1324 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1325 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1326 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1328 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1329 Section
= MemoryArea
->Data
.SectionData
.Section
;
1330 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1331 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1333 ASSERT(Region
!= NULL
);
1337 MmLockSectionSegment(Segment
);
1338 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1340 * Check if this page needs to be mapped COW
1342 if ((Segment
->WriteCopy
) &&
1343 (Region
->Protect
== PAGE_READWRITE
||
1344 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1346 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1350 Attributes
= Region
->Protect
;
1354 * Check if someone else is already handling this fault, if so wait
1357 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1359 MmUnlockSectionSegment(Segment
);
1360 MmUnlockAddressSpace(AddressSpace
);
1361 MiWaitForPageEvent(NULL
, NULL
);
1362 MmLockAddressSpace(AddressSpace
);
1363 DPRINT("Address 0x%p\n", Address
);
1364 return(STATUS_MM_RESTART_OPERATION
);
1367 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1371 SWAPENTRY DummyEntry
;
1374 * Is it a wait entry?
1376 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1378 if (SwapEntry
== MM_WAIT_ENTRY
)
1380 MmUnlockSectionSegment(Segment
);
1381 MmUnlockAddressSpace(AddressSpace
);
1382 MiWaitForPageEvent(NULL
, NULL
);
1383 MmLockAddressSpace(AddressSpace
);
1384 return STATUS_MM_RESTART_OPERATION
;
1388 * Must be private page we have swapped out.
1394 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1396 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1397 KeBugCheck(MEMORY_MANAGEMENT
);
1400 MmUnlockSectionSegment(Segment
);
1401 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1402 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1404 MmUnlockAddressSpace(AddressSpace
);
1405 MI_SET_USAGE(MI_USAGE_SECTION
);
1406 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1407 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1408 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1409 if (!NT_SUCCESS(Status
))
1411 KeBugCheck(MEMORY_MANAGEMENT
);
1414 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1415 if (!NT_SUCCESS(Status
))
1417 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1418 KeBugCheck(MEMORY_MANAGEMENT
);
1420 MmLockAddressSpace(AddressSpace
);
1421 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1422 Status
= MmCreateVirtualMapping(Process
,
1427 if (!NT_SUCCESS(Status
))
1429 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1430 KeBugCheck(MEMORY_MANAGEMENT
);
1435 * Store the swap entry for later use.
1437 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1440 * Add the page to the process's working set
1442 MmInsertRmap(Page
, Process
, Address
);
1444 * Finish the operation
1446 MiSetPageEvent(Process
, Address
);
1447 DPRINT("Address 0x%p\n", Address
);
1448 return(STATUS_SUCCESS
);
1452 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1454 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1456 MmUnlockSectionSegment(Segment
);
1458 * Just map the desired physical page
1460 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1461 Status
= MmCreateVirtualMappingUnsafe(Process
,
1466 if (!NT_SUCCESS(Status
))
1468 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1469 KeBugCheck(MEMORY_MANAGEMENT
);
1474 * Cleanup and release locks
1476 MiSetPageEvent(Process
, Address
);
1477 DPRINT("Address 0x%p\n", Address
);
1478 return(STATUS_SUCCESS
);
1482 * Get the entry corresponding to the offset within the section
1484 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1488 SWAPENTRY FakeSwapEntry
;
1491 * If the entry is zero (and it can't change because we have
1492 * locked the segment) then we need to load the page.
1496 * Release all our locks and read in the page from disk
1498 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1499 MmUnlockSectionSegment(Segment
);
1500 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1501 MmUnlockAddressSpace(AddressSpace
);
1503 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1504 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1505 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1507 MI_SET_USAGE(MI_USAGE_SECTION
);
1508 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1509 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1510 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1511 if (!NT_SUCCESS(Status
))
1513 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1519 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1520 if (!NT_SUCCESS(Status
))
1522 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1525 if (!NT_SUCCESS(Status
))
1528 * FIXME: What do we know in this case?
1531 * Cleanup and release locks
1533 MmLockAddressSpace(AddressSpace
);
1534 MiSetPageEvent(Process
, Address
);
1535 DPRINT("Address 0x%p\n", Address
);
1540 * Mark the offset within the section as having valid, in-memory
1543 MmLockAddressSpace(AddressSpace
);
1544 MmLockSectionSegment(Segment
);
1545 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1546 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1547 MmUnlockSectionSegment(Segment
);
1549 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1550 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1551 Page
, Process
, PAddress
, Attributes
);
1552 Status
= MmCreateVirtualMapping(Process
,
1557 if (!NT_SUCCESS(Status
))
1559 DPRINT1("Unable to create virtual mapping\n");
1560 KeBugCheck(MEMORY_MANAGEMENT
);
1562 ASSERT(MmIsPagePresent(Process
, PAddress
));
1563 MmInsertRmap(Page
, Process
, Address
);
1565 MiSetPageEvent(Process
, Address
);
1566 DPRINT("Address 0x%p\n", Address
);
1567 return(STATUS_SUCCESS
);
1569 else if (IS_SWAP_FROM_SSE(Entry
))
1571 SWAPENTRY SwapEntry
;
1573 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1576 * Release all our locks and read in the page from disk
1578 MmUnlockSectionSegment(Segment
);
1580 MmUnlockAddressSpace(AddressSpace
);
1581 MI_SET_USAGE(MI_USAGE_SECTION
);
1582 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1583 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1584 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1585 if (!NT_SUCCESS(Status
))
1587 KeBugCheck(MEMORY_MANAGEMENT
);
1590 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1591 if (!NT_SUCCESS(Status
))
1593 KeBugCheck(MEMORY_MANAGEMENT
);
1597 * Relock the address space and segment
1599 MmLockAddressSpace(AddressSpace
);
1600 MmLockSectionSegment(Segment
);
1603 * Check the entry. No one should change the status of a page
1604 * that has a pending page-in.
1606 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1607 if (Entry
!= Entry1
)
1609 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1610 KeBugCheck(MEMORY_MANAGEMENT
);
1614 * Mark the offset within the section as having valid, in-memory
1617 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1618 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1619 MmUnlockSectionSegment(Segment
);
1622 * Save the swap entry.
1624 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1625 Status
= MmCreateVirtualMapping(Process
,
1630 if (!NT_SUCCESS(Status
))
1632 DPRINT1("Unable to create virtual mapping\n");
1633 KeBugCheck(MEMORY_MANAGEMENT
);
1635 MmInsertRmap(Page
, Process
, Address
);
1636 MiSetPageEvent(Process
, Address
);
1637 DPRINT("Address 0x%p\n", Address
);
1638 return(STATUS_SUCCESS
);
1643 * If the section offset is already in-memory and valid then just
1644 * take another reference to the page
1647 Page
= PFN_FROM_SSE(Entry
);
1649 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1650 MmUnlockSectionSegment(Segment
);
1652 Status
= MmCreateVirtualMapping(Process
,
1657 if (!NT_SUCCESS(Status
))
1659 DPRINT1("Unable to create virtual mapping\n");
1660 KeBugCheck(MEMORY_MANAGEMENT
);
1662 MmInsertRmap(Page
, Process
, Address
);
1663 MiSetPageEvent(Process
, Address
);
1664 DPRINT("Address 0x%p\n", Address
);
1665 return(STATUS_SUCCESS
);
1671 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1672 MEMORY_AREA
* MemoryArea
,
1675 PMM_SECTION_SEGMENT Segment
;
1676 PROS_SECTION_OBJECT Section
;
1681 LARGE_INTEGER Offset
;
1684 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1685 SWAPENTRY SwapEntry
;
1687 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1690 * Check if the page has already been set readwrite
1692 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1694 DPRINT("Address 0x%p\n", Address
);
1695 return(STATUS_SUCCESS
);
1699 * Find the offset of the page
1701 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1702 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1703 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1705 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1706 Section
= MemoryArea
->Data
.SectionData
.Section
;
1707 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1708 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1710 ASSERT(Region
!= NULL
);
1714 MmLockSectionSegment(Segment
);
1716 OldPage
= MmGetPfnForProcess(Process
, Address
);
1717 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1719 MmUnlockSectionSegment(Segment
);
1722 * Check if we are doing COW
1724 if (!((Segment
->WriteCopy
) &&
1725 (Region
->Protect
== PAGE_READWRITE
||
1726 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1728 DPRINT("Address 0x%p\n", Address
);
1729 return(STATUS_ACCESS_VIOLATION
);
1732 if (IS_SWAP_FROM_SSE(Entry
) ||
1733 PFN_FROM_SSE(Entry
) != OldPage
)
1735 /* This is a private page. We must only change the page protection. */
1736 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1737 return(STATUS_SUCCESS
);
1741 DPRINT("OldPage == 0!\n");
1744 * Get or create a pageop
1746 MmLockSectionSegment(Segment
);
1747 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1750 * Wait for any other operations to complete
1752 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1754 MmUnlockSectionSegment(Segment
);
1755 MmUnlockAddressSpace(AddressSpace
);
1756 MiWaitForPageEvent(NULL
, NULL
);
1758 * Restart the operation
1760 MmLockAddressSpace(AddressSpace
);
1761 DPRINT("Address 0x%p\n", Address
);
1762 return(STATUS_MM_RESTART_OPERATION
);
1765 MmDeleteRmap(OldPage
, Process
, PAddress
);
1766 MmDeleteVirtualMapping(Process
, PAddress
, NULL
, NULL
);
1767 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1770 * Release locks now we have the pageop
1772 MmUnlockSectionSegment(Segment
);
1773 MmUnlockAddressSpace(AddressSpace
);
1778 MI_SET_USAGE(MI_USAGE_SECTION
);
1779 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1780 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1781 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1782 if (!NT_SUCCESS(Status
))
1784 KeBugCheck(MEMORY_MANAGEMENT
);
1790 MiCopyFromUserPage(NewPage
, OldPage
);
1792 MmLockAddressSpace(AddressSpace
);
1795 * Set the PTE to point to the new page
1797 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1798 Status
= MmCreateVirtualMapping(Process
,
1803 if (!NT_SUCCESS(Status
))
1805 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1806 KeBugCheck(MEMORY_MANAGEMENT
);
1811 * Unshare the old page.
1813 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1814 MmInsertRmap(NewPage
, Process
, PAddress
);
1815 MmLockSectionSegment(Segment
);
1816 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1817 MmUnlockSectionSegment(Segment
);
1819 MiSetPageEvent(Process
, Address
);
1820 DPRINT("Address 0x%p\n", Address
);
1821 return(STATUS_SUCCESS
);
1825 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1827 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1829 PFN_NUMBER Page
= 0;
1831 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1834 MmLockAddressSpace(&Process
->Vm
);
1837 MmDeleteVirtualMapping(Process
,
1843 PageOutContext
->WasDirty
= TRUE
;
1845 if (!PageOutContext
->Private
)
1847 MmLockSectionSegment(PageOutContext
->Segment
);
1848 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1849 PageOutContext
->Segment
,
1850 &PageOutContext
->Offset
,
1851 PageOutContext
->WasDirty
,
1853 &PageOutContext
->SectionEntry
);
1854 MmUnlockSectionSegment(PageOutContext
->Segment
);
1858 MmUnlockAddressSpace(&Process
->Vm
);
1861 if (PageOutContext
->Private
)
1863 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1869 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1870 MEMORY_AREA
* MemoryArea
,
1871 PVOID Address
, ULONG_PTR Entry
)
1874 MM_SECTION_PAGEOUT_CONTEXT Context
;
1875 SWAPENTRY SwapEntry
;
1876 ULONGLONG FileOffset
;
1878 PFILE_OBJECT FileObject
;
1880 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1882 BOOLEAN DirectMapped
;
1883 BOOLEAN IsImageSection
;
1884 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1887 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1890 * Get the segment and section.
1892 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1893 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1894 Context
.SectionEntry
= Entry
;
1895 Context
.CallingProcess
= Process
;
1897 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1898 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1899 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1901 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1903 FileObject
= Context
.Section
->FileObject
;
1904 DirectMapped
= FALSE
;
1906 MmLockSectionSegment(Context
.Segment
);
1909 if (FileObject
!= NULL
&&
1910 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1912 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1915 * If the file system is letting us go directly to the cache and the
1916 * memory area was mapped at an offset in the file which is page aligned
1917 * then note this is a direct mapped page.
1919 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1920 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1922 DirectMapped
= TRUE
;
1929 * This should never happen since mappings of physical memory are never
1930 * placed in the rmap lists.
1932 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1934 DPRINT1("Trying to page out from physical memory section address 0x%p "
1935 "process %p\n", Address
,
1936 Process
? Process
->UniqueProcessId
: 0);
1937 KeBugCheck(MEMORY_MANAGEMENT
);
1941 * Get the section segment entry and the physical address.
1943 if (!MmIsPagePresent(Process
, Address
))
1945 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1946 Process
? Process
->UniqueProcessId
: 0, Address
);
1947 KeBugCheck(MEMORY_MANAGEMENT
);
1949 Page
= MmGetPfnForProcess(Process
, Address
);
1950 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1953 * Check the reference count to ensure this page can be paged out
1955 if (MmGetReferenceCountPage(Page
) != 1)
1957 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1958 Page
, MmGetReferenceCountPage(Page
));
1959 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1960 MmUnlockSectionSegment(Context
.Segment
);
1961 return STATUS_UNSUCCESSFUL
;
1965 * Prepare the context structure for the rmap delete call.
1967 MmUnlockSectionSegment(Context
.Segment
);
1968 Context
.WasDirty
= FALSE
;
1969 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1970 IS_SWAP_FROM_SSE(Entry
) ||
1971 PFN_FROM_SSE(Entry
) != Page
)
1973 Context
.Private
= TRUE
;
1977 Context
.Private
= FALSE
;
1981 * Take an additional reference to the page or the VACB.
1983 if (DirectMapped
&& !Context
.Private
)
1985 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
1987 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1988 KeBugCheck(MEMORY_MANAGEMENT
);
1993 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1994 MmReferencePage(Page
);
1995 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1998 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2000 /* Since we passed in a surrogate, we'll get back the page entry
2001 * state in our context. This is intended to make intermediate
2002 * decrements of share count not release the wait entry.
2004 Entry
= Context
.SectionEntry
;
2007 * If this wasn't a private page then we should have reduced the entry to
2008 * zero by deleting all the rmaps.
2010 if (!Context
.Private
&& Entry
!= 0)
2012 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2013 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2015 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2020 * If the page wasn't dirty then we can just free it as for a readonly page.
2021 * Since we unmapped all the mappings above we know it will not suddenly
2023 * If the page is from a pagefile section and has no swap entry,
2024 * we can't free the page at this point.
2026 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2027 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2029 if (Context
.Private
)
2031 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2032 Context
.WasDirty
? "dirty" : "clean", Address
);
2033 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2035 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2037 MmSetSavedSwapEntryPage(Page
, 0);
2038 MmLockSectionSegment(Context
.Segment
);
2039 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2040 MmUnlockSectionSegment(Context
.Segment
);
2041 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2042 MiSetPageEvent(NULL
, NULL
);
2043 return(STATUS_SUCCESS
);
2046 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2048 if (Context
.Private
)
2050 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2051 Context
.WasDirty
? "dirty" : "clean", Address
);
2052 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2054 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2056 MmSetSavedSwapEntryPage(Page
, 0);
2059 MmLockSectionSegment(Context
.Segment
);
2060 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2061 MmUnlockSectionSegment(Context
.Segment
);
2063 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2064 MiSetPageEvent(NULL
, NULL
);
2065 return(STATUS_SUCCESS
);
2068 else if (!Context
.Private
&& DirectMapped
)
2072 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2074 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2077 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
, FALSE
);
2079 Status
= STATUS_SUCCESS
;
2082 if (!NT_SUCCESS(Status
))
2084 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2085 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2088 MiSetPageEvent(NULL
, NULL
);
2089 return(STATUS_SUCCESS
);
2091 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2095 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2097 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2099 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2100 MiSetPageEvent(NULL
, NULL
);
2101 return(STATUS_SUCCESS
);
2103 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2105 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2106 MmSetSavedSwapEntryPage(Page
, 0);
2107 MmLockAddressSpace(AddressSpace
);
2108 Status
= MmCreatePageFileMapping(Process
,
2111 MmUnlockAddressSpace(AddressSpace
);
2112 if (!NT_SUCCESS(Status
))
2114 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2115 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2117 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2118 MiSetPageEvent(NULL
, NULL
);
2119 return(STATUS_SUCCESS
);
2123 * If necessary, allocate an entry in the paging file for this page
2127 SwapEntry
= MmAllocSwapPage();
2130 MmShowOutOfSpaceMessagePagingFile();
2131 MmLockAddressSpace(AddressSpace
);
2133 * For private pages restore the old mappings.
2135 if (Context
.Private
)
2137 Status
= MmCreateVirtualMapping(Process
,
2139 MemoryArea
->Protect
,
2142 MmSetDirtyPage(Process
, Address
);
2151 * For non-private pages if the page wasn't direct mapped then
2152 * set it back into the section segment entry so we don't loose
2153 * our copy. Otherwise it will be handled by the cache manager.
2155 Status
= MmCreateVirtualMapping(Process
,
2157 MemoryArea
->Protect
,
2160 MmSetDirtyPage(Process
, Address
);
2164 // If we got here, the previous entry should have been a wait
2165 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2166 MmLockSectionSegment(Context
.Segment
);
2167 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2168 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2169 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2170 MmUnlockSectionSegment(Context
.Segment
);
2172 MmUnlockAddressSpace(AddressSpace
);
2173 MiSetPageEvent(NULL
, NULL
);
2174 return(STATUS_PAGEFILE_QUOTA
);
2179 * Write the page to the pagefile
2181 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2182 if (!NT_SUCCESS(Status
))
2184 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2187 * As above: undo our actions.
2188 * FIXME: Also free the swap page.
2190 MmLockAddressSpace(AddressSpace
);
2191 if (Context
.Private
)
2193 Status
= MmCreateVirtualMapping(Process
,
2195 MemoryArea
->Protect
,
2198 MmSetDirtyPage(Process
, Address
);
2205 Status
= MmCreateVirtualMapping(Process
,
2207 MemoryArea
->Protect
,
2210 MmSetDirtyPage(Process
, Address
);
2214 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2215 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2217 MmUnlockAddressSpace(AddressSpace
);
2218 MiSetPageEvent(NULL
, NULL
);
2219 return(STATUS_UNSUCCESSFUL
);
2223 * Otherwise we have succeeded.
2225 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2226 MmSetSavedSwapEntryPage(Page
, 0);
2227 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2228 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2230 MmLockSectionSegment(Context
.Segment
);
2231 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2232 MmUnlockSectionSegment(Context
.Segment
);
2236 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2239 if (Context
.Private
)
2241 MmLockAddressSpace(AddressSpace
);
2242 MmLockSectionSegment(Context
.Segment
);
2243 Status
= MmCreatePageFileMapping(Process
,
2246 /* We had placed a wait entry upon entry ... replace it before leaving */
2247 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2248 MmUnlockSectionSegment(Context
.Segment
);
2249 MmUnlockAddressSpace(AddressSpace
);
2250 if (!NT_SUCCESS(Status
))
2252 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2253 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2258 MmLockAddressSpace(AddressSpace
);
2259 MmLockSectionSegment(Context
.Segment
);
2260 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2261 /* We had placed a wait entry upon entry ... replace it before leaving */
2262 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2263 MmUnlockSectionSegment(Context
.Segment
);
2264 MmUnlockAddressSpace(AddressSpace
);
2267 MiSetPageEvent(NULL
, NULL
);
2268 return(STATUS_SUCCESS
);
2273 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2274 PMEMORY_AREA MemoryArea
,
2278 LARGE_INTEGER Offset
;
2279 PROS_SECTION_OBJECT Section
;
2280 PMM_SECTION_SEGMENT Segment
;
2282 SWAPENTRY SwapEntry
;
2286 PFILE_OBJECT FileObject
;
2287 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2288 BOOLEAN DirectMapped
;
2289 BOOLEAN IsImageSection
;
2290 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2292 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2294 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2295 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2298 * Get the segment and section.
2300 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2301 Section
= MemoryArea
->Data
.SectionData
.Section
;
2302 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2304 FileObject
= Section
->FileObject
;
2305 DirectMapped
= FALSE
;
2306 if (FileObject
!= NULL
&&
2307 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2309 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2312 * If the file system is letting us go directly to the cache and the
2313 * memory area was mapped at an offset in the file which is page aligned
2314 * then note this is a direct mapped page.
2316 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2317 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2319 DirectMapped
= TRUE
;
2324 * This should never happen since mappings of physical memory are never
2325 * placed in the rmap lists.
2327 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2329 DPRINT1("Trying to write back page from physical memory mapped at %p "
2330 "process %p\n", Address
,
2331 Process
? Process
->UniqueProcessId
: 0);
2332 KeBugCheck(MEMORY_MANAGEMENT
);
2336 * Get the section segment entry and the physical address.
2338 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2339 if (!MmIsPagePresent(Process
, Address
))
2341 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2342 Process
? Process
->UniqueProcessId
: 0, Address
);
2343 KeBugCheck(MEMORY_MANAGEMENT
);
2345 Page
= MmGetPfnForProcess(Process
, Address
);
2346 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2349 * Check for a private (COWed) page.
2351 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2352 IS_SWAP_FROM_SSE(Entry
) ||
2353 PFN_FROM_SSE(Entry
) != Page
)
2363 * Speculatively set all mappings of the page to clean.
2365 MmSetCleanAllRmaps(Page
);
2368 * If this page was direct mapped from the cache then the cache manager
2369 * will take care of writing it back to disk.
2371 if (DirectMapped
&& !Private
)
2373 //LARGE_INTEGER SOffset;
2374 ASSERT(SwapEntry
== 0);
2375 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2377 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
);
2379 MmLockSectionSegment(Segment
);
2380 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2381 MmUnlockSectionSegment(Segment
);
2382 MiSetPageEvent(NULL
, NULL
);
2383 return(STATUS_SUCCESS
);
2387 * If necessary, allocate an entry in the paging file for this page
2391 SwapEntry
= MmAllocSwapPage();
2394 MmSetDirtyAllRmaps(Page
);
2395 MiSetPageEvent(NULL
, NULL
);
2396 return(STATUS_PAGEFILE_QUOTA
);
2398 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2402 * Write the page to the pagefile
2404 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2405 if (!NT_SUCCESS(Status
))
2407 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2409 MmSetDirtyAllRmaps(Page
);
2410 MiSetPageEvent(NULL
, NULL
);
2411 return(STATUS_UNSUCCESSFUL
);
2415 * Otherwise we have succeeded.
2417 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2418 MiSetPageEvent(NULL
, NULL
);
2419 return(STATUS_SUCCESS
);
2423 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2431 PMEMORY_AREA MemoryArea
;
2432 PMM_SECTION_SEGMENT Segment
;
2433 BOOLEAN DoCOW
= FALSE
;
2435 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2437 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2438 ASSERT(MemoryArea
!= NULL
);
2439 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2440 MmLockSectionSegment(Segment
);
2442 if ((Segment
->WriteCopy
) &&
2443 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2448 if (OldProtect
!= NewProtect
)
2450 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2452 SWAPENTRY SwapEntry
;
2453 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2454 ULONG Protect
= NewProtect
;
2456 /* Wait for a wait entry to disappear */
2459 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2460 if (SwapEntry
!= MM_WAIT_ENTRY
)
2462 MiWaitForPageEvent(Process
, Address
);
2467 * If we doing COW for this segment then check if the page is
2470 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2472 LARGE_INTEGER Offset
;
2476 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2477 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2478 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2480 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2481 * IS_SWAP_FROM_SSE and we'll do the right thing.
2483 Page
= MmGetPfnForProcess(Process
, Address
);
2485 Protect
= PAGE_READONLY
;
2486 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2487 IS_SWAP_FROM_SSE(Entry
) ||
2488 PFN_FROM_SSE(Entry
) != Page
)
2490 Protect
= NewProtect
;
2494 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2496 MmSetPageProtect(Process
, Address
,
2502 MmUnlockSectionSegment(Segment
);
2507 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2508 PMEMORY_AREA MemoryArea
,
2516 ULONG_PTR MaxLength
;
2518 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2519 if (Length
> MaxLength
)
2520 Length
= (ULONG
)MaxLength
;
2522 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2523 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2525 ASSERT(Region
!= NULL
);
2527 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2528 Region
->Protect
!= Protect
)
2530 return STATUS_INVALID_PAGE_PROTECTION
;
2533 *OldProtect
= Region
->Protect
;
2534 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2535 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2536 BaseAddress
, Length
, Region
->Type
, Protect
,
2537 MmAlterViewAttributes
);
2543 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2545 PMEMORY_BASIC_INFORMATION Info
,
2546 PSIZE_T ResultLength
)
2549 PVOID RegionBaseAddress
;
2550 PROS_SECTION_OBJECT Section
;
2551 PMM_SECTION_SEGMENT Segment
;
2553 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2554 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2555 Address
, &RegionBaseAddress
);
2558 return STATUS_UNSUCCESSFUL
;
2561 Section
= MemoryArea
->Data
.SectionData
.Section
;
2562 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2564 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2565 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2566 Info
->Type
= MEM_IMAGE
;
2570 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2571 Info
->Type
= MEM_MAPPED
;
2573 Info
->BaseAddress
= RegionBaseAddress
;
2574 Info
->AllocationProtect
= MemoryArea
->Protect
;
2575 Info
->RegionSize
= Region
->Length
;
2576 Info
->State
= MEM_COMMIT
;
2577 Info
->Protect
= Region
->Protect
;
2579 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2580 return(STATUS_SUCCESS
);
2585 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2588 LARGE_INTEGER Offset
;
2590 SWAPENTRY SavedSwapEntry
;
2595 MmLockSectionSegment(Segment
);
2597 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2598 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2600 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2603 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2604 if (IS_SWAP_FROM_SSE(Entry
))
2606 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2610 Page
= PFN_FROM_SSE(Entry
);
2611 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2612 if (SavedSwapEntry
!= 0)
2614 MmSetSavedSwapEntryPage(Page
, 0);
2615 MmFreeSwapPage(SavedSwapEntry
);
2617 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2622 MmUnlockSectionSegment(Segment
);
2626 MmpDeleteSection(PVOID ObjectBody
)
2628 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2630 /* Check if it's an ARM3, or ReactOS section */
2631 if (!MiIsRosSectionObject(Section
))
2633 MiDeleteARM3Section(ObjectBody
);
2637 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2638 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2643 PMM_SECTION_SEGMENT SectionSegments
;
2646 * NOTE: Section->ImageSection can be NULL for short time
2647 * during the section creating. If we fail for some reason
2648 * until the image section is properly initialized we shouldn't
2649 * process further here.
2651 if (Section
->ImageSection
== NULL
)
2654 SectionSegments
= Section
->ImageSection
->Segments
;
2655 NrSegments
= Section
->ImageSection
->NrSegments
;
2657 for (i
= 0; i
< NrSegments
; i
++)
2659 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2661 MmLockSectionSegment(&SectionSegments
[i
]);
2663 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2664 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2666 MmUnlockSectionSegment(&SectionSegments
[i
]);
2669 MmpFreePageFileSegment(&SectionSegments
[i
]);
2675 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2678 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2681 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2683 DPRINT("Freeing section segment\n");
2684 Section
->Segment
= NULL
;
2685 MmFinalizeSegment(Segment
);
2689 DPRINT("RefCount %d\n", RefCount
);
2696 * NOTE: Section->Segment can be NULL for short time
2697 * during the section creating.
2699 if (Section
->Segment
== NULL
)
2702 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2704 MmpFreePageFileSegment(Section
->Segment
);
2705 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2706 ExFreePool(Section
->Segment
);
2707 Section
->Segment
= NULL
;
2711 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2714 if (Section
->FileObject
!= NULL
)
2717 CcRosDereferenceCache(Section
->FileObject
);
2719 ObDereferenceObject(Section
->FileObject
);
2720 Section
->FileObject
= NULL
;
2725 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2727 IN ACCESS_MASK GrantedAccess
,
2728 IN ULONG ProcessHandleCount
,
2729 IN ULONG SystemHandleCount
)
2731 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2737 MmCreatePhysicalMemorySection(VOID
)
2739 PROS_SECTION_OBJECT PhysSection
;
2741 OBJECT_ATTRIBUTES Obj
;
2742 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2743 LARGE_INTEGER SectionSize
;
2747 * Create the section mapping physical memory
2749 SectionSize
.QuadPart
= 0xFFFFFFFF;
2750 InitializeObjectAttributes(&Obj
,
2755 Status
= MmCreateSection((PVOID
)&PhysSection
,
2759 PAGE_EXECUTE_READWRITE
,
2763 if (!NT_SUCCESS(Status
))
2765 DPRINT1("Failed to create PhysicalMemory section\n");
2766 KeBugCheck(MEMORY_MANAGEMENT
);
2768 Status
= ObInsertObject(PhysSection
,
2774 if (!NT_SUCCESS(Status
))
2776 ObDereferenceObject(PhysSection
);
2778 ObCloseHandle(Handle
, KernelMode
);
2779 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2780 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2782 return(STATUS_SUCCESS
);
2788 MmInitSectionImplementation(VOID
)
2790 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2791 UNICODE_STRING Name
;
2793 DPRINT("Creating Section Object Type\n");
2795 /* Initialize the section based root */
2796 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2797 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2799 /* Initialize the Section object type */
2800 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2801 RtlInitUnicodeString(&Name
, L
"Section");
2802 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2803 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2804 ObjectTypeInitializer
.PoolType
= PagedPool
;
2805 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2806 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2807 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2808 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2809 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2810 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2811 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2813 MmCreatePhysicalMemorySection();
2815 return(STATUS_SUCCESS
);
2820 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2821 ACCESS_MASK DesiredAccess
,
2822 POBJECT_ATTRIBUTES ObjectAttributes
,
2823 PLARGE_INTEGER UMaximumSize
,
2824 ULONG SectionPageProtection
,
2825 ULONG AllocationAttributes
)
2827 * Create a section which is backed by the pagefile
2830 LARGE_INTEGER MaximumSize
;
2831 PROS_SECTION_OBJECT Section
;
2832 PMM_SECTION_SEGMENT Segment
;
2835 if (UMaximumSize
== NULL
)
2837 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2838 return(STATUS_INVALID_PARAMETER
);
2840 MaximumSize
= *UMaximumSize
;
2843 * Create the section
2845 Status
= ObCreateObject(ExGetPreviousMode(),
2846 MmSectionObjectType
,
2848 ExGetPreviousMode(),
2850 sizeof(ROS_SECTION_OBJECT
),
2853 (PVOID
*)(PVOID
)&Section
);
2854 if (!NT_SUCCESS(Status
))
2856 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2863 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2864 Section
->Type
= 'SC';
2865 Section
->Size
= 'TN';
2866 Section
->SectionPageProtection
= SectionPageProtection
;
2867 Section
->AllocationAttributes
= AllocationAttributes
;
2868 Section
->MaximumSize
= MaximumSize
;
2869 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2870 TAG_MM_SECTION_SEGMENT
);
2871 if (Segment
== NULL
)
2873 ObDereferenceObject(Section
);
2874 return(STATUS_NO_MEMORY
);
2876 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2877 Section
->Segment
= Segment
;
2878 Segment
->ReferenceCount
= 1;
2879 ExInitializeFastMutex(&Segment
->Lock
);
2880 Segment
->Image
.FileOffset
= 0;
2881 Segment
->Protection
= SectionPageProtection
;
2882 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2883 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2884 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2885 Segment
->WriteCopy
= FALSE
;
2886 Segment
->Image
.VirtualAddress
= 0;
2887 Segment
->Image
.Characteristics
= 0;
2888 *SectionObject
= Section
;
2889 MiInitializeSectionPageTable(Segment
);
2890 return(STATUS_SUCCESS
);
2895 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2896 ACCESS_MASK DesiredAccess
,
2897 POBJECT_ATTRIBUTES ObjectAttributes
,
2898 PLARGE_INTEGER UMaximumSize
,
2899 ULONG SectionPageProtection
,
2900 ULONG AllocationAttributes
,
2903 * Create a section backed by a data file
2906 PROS_SECTION_OBJECT Section
;
2908 LARGE_INTEGER MaximumSize
;
2909 PFILE_OBJECT FileObject
;
2910 PMM_SECTION_SEGMENT Segment
;
2912 IO_STATUS_BLOCK Iosb
;
2913 LARGE_INTEGER Offset
;
2915 FILE_STANDARD_INFORMATION FileInfo
;
2919 * Create the section
2921 Status
= ObCreateObject(ExGetPreviousMode(),
2922 MmSectionObjectType
,
2924 ExGetPreviousMode(),
2926 sizeof(ROS_SECTION_OBJECT
),
2930 if (!NT_SUCCESS(Status
))
2937 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2938 Section
->Type
= 'SC';
2939 Section
->Size
= 'TN';
2940 Section
->SectionPageProtection
= SectionPageProtection
;
2941 Section
->AllocationAttributes
= AllocationAttributes
;
2944 * Reference the file handle
2946 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2947 Status
= ObReferenceObjectByHandle(FileHandle
,
2950 ExGetPreviousMode(),
2951 (PVOID
*)(PVOID
)&FileObject
,
2953 if (!NT_SUCCESS(Status
))
2955 ObDereferenceObject(Section
);
2960 * FIXME: This is propably not entirely correct. We can't look into
2961 * the standard FCB header because it might not be initialized yet
2962 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2963 * standard file information is filled on first request).
2965 Status
= IoQueryFileInformation(FileObject
,
2966 FileStandardInformation
,
2967 sizeof(FILE_STANDARD_INFORMATION
),
2970 Iosb
.Information
= Length
;
2971 if (!NT_SUCCESS(Status
))
2973 ObDereferenceObject(Section
);
2974 ObDereferenceObject(FileObject
);
2979 * FIXME: Revise this once a locking order for file size changes is
2982 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2984 MaximumSize
= *UMaximumSize
;
2988 MaximumSize
= FileInfo
.EndOfFile
;
2989 /* Mapping zero-sized files isn't allowed. */
2990 if (MaximumSize
.QuadPart
== 0)
2992 ObDereferenceObject(Section
);
2993 ObDereferenceObject(FileObject
);
2994 return STATUS_FILE_INVALID
;
2998 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3000 Status
= IoSetInformation(FileObject
,
3001 FileAllocationInformation
,
3002 sizeof(LARGE_INTEGER
),
3004 if (!NT_SUCCESS(Status
))
3006 ObDereferenceObject(Section
);
3007 ObDereferenceObject(FileObject
);
3008 return(STATUS_SECTION_NOT_EXTENDED
);
3012 if (FileObject
->SectionObjectPointer
== NULL
||
3013 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3016 * Read a bit so caching is initiated for the file object.
3017 * This is only needed because MiReadPage currently cannot
3018 * handle non-cached streams.
3020 Offset
.QuadPart
= 0;
3021 Status
= ZwReadFile(FileHandle
,
3030 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3032 ObDereferenceObject(Section
);
3033 ObDereferenceObject(FileObject
);
3036 if (FileObject
->SectionObjectPointer
== NULL
||
3037 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3039 /* FIXME: handle this situation */
3040 ObDereferenceObject(Section
);
3041 ObDereferenceObject(FileObject
);
3042 return STATUS_INVALID_PARAMETER
;
3049 Status
= MmspWaitForFileLock(FileObject
);
3050 if (Status
!= STATUS_SUCCESS
)
3052 ObDereferenceObject(Section
);
3053 ObDereferenceObject(FileObject
);
3058 * If this file hasn't been mapped as a data file before then allocate a
3059 * section segment to describe the data file mapping
3061 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3063 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3064 TAG_MM_SECTION_SEGMENT
);
3065 if (Segment
== NULL
)
3067 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3068 ObDereferenceObject(Section
);
3069 ObDereferenceObject(FileObject
);
3070 return(STATUS_NO_MEMORY
);
3072 Section
->Segment
= Segment
;
3073 Segment
->ReferenceCount
= 1;
3074 ExInitializeFastMutex(&Segment
->Lock
);
3076 * Set the lock before assigning the segment to the file object
3078 ExAcquireFastMutex(&Segment
->Lock
);
3079 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3081 Segment
->Image
.FileOffset
= 0;
3082 Segment
->Protection
= SectionPageProtection
;
3083 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3084 Segment
->Image
.Characteristics
= 0;
3085 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3086 if (AllocationAttributes
& SEC_RESERVE
)
3088 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3092 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3093 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3095 Segment
->Image
.VirtualAddress
= 0;
3096 Segment
->Locked
= TRUE
;
3097 MiInitializeSectionPageTable(Segment
);
3102 * If the file is already mapped as a data file then we may need
3106 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3108 Section
->Segment
= Segment
;
3109 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3110 MmLockSectionSegment(Segment
);
3112 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3113 !(AllocationAttributes
& SEC_RESERVE
))
3115 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3116 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3119 MmUnlockSectionSegment(Segment
);
3120 Section
->FileObject
= FileObject
;
3121 Section
->MaximumSize
= MaximumSize
;
3123 CcRosReferenceCache(FileObject
);
3125 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3126 *SectionObject
= Section
;
3127 return(STATUS_SUCCESS
);
3131 TODO: not that great (declaring loaders statically, having to declare all of
3132 them, having to keep them extern, etc.), will fix in the future
3134 extern NTSTATUS NTAPI PeFmtCreateSection
3136 IN CONST VOID
* FileHeader
,
3137 IN SIZE_T FileHeaderSize
,
3139 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3141 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3142 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3145 extern NTSTATUS NTAPI ElfFmtCreateSection
3147 IN CONST VOID
* FileHeader
,
3148 IN SIZE_T FileHeaderSize
,
3150 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3152 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3153 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3156 /* TODO: this is a standard DDK/PSDK macro */
3157 #ifndef RTL_NUMBER_OF
3158 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3161 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3172 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3174 SIZE_T SizeOfSegments
;
3175 PMM_SECTION_SEGMENT Segments
;
3177 /* TODO: check for integer overflow */
3178 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3180 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3182 TAG_MM_SECTION_SEGMENT
);
3185 RtlZeroMemory(Segments
, SizeOfSegments
);
3193 ExeFmtpReadFile(IN PVOID File
,
3194 IN PLARGE_INTEGER Offset
,
3197 OUT PVOID
* AllocBase
,
3198 OUT PULONG ReadSize
)
3201 LARGE_INTEGER FileOffset
;
3203 ULONG OffsetAdjustment
;
3207 PFILE_OBJECT FileObject
= File
;
3208 IO_STATUS_BLOCK Iosb
;
3210 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3214 KeBugCheck(MEMORY_MANAGEMENT
);
3217 FileOffset
= *Offset
;
3219 /* Negative/special offset: it cannot be used in this context */
3220 if(FileOffset
.u
.HighPart
< 0)
3222 KeBugCheck(MEMORY_MANAGEMENT
);
3225 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3226 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3227 FileOffset
.u
.LowPart
= AdjustOffset
;
3229 BufferSize
= Length
+ OffsetAdjustment
;
3230 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3233 * It's ok to use paged pool, because this is a temporary buffer only used in
3234 * the loading of executables. The assumption is that MmCreateSection is
3235 * always called at low IRQLs and that these buffers don't survive a brief
3236 * initialization phase
3238 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3243 KeBugCheck(MEMORY_MANAGEMENT
);
3248 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3250 UsedSize
= (ULONG
)Iosb
.Information
;
3252 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3254 Status
= STATUS_IN_PAGE_ERROR
;
3255 ASSERT(!NT_SUCCESS(Status
));
3258 if(NT_SUCCESS(Status
))
3260 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3261 *AllocBase
= Buffer
;
3262 *ReadSize
= UsedSize
- OffsetAdjustment
;
3266 ExFreePoolWithTag(Buffer
, 'rXmM');
3273 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3274 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3275 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3280 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3284 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3286 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3287 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3294 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3298 MmspAssertSegmentsSorted(ImageSectionObject
);
3300 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3302 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3306 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3307 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3308 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3316 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3320 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3322 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3323 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3331 MmspCompareSegments(const void * x
,
3334 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3335 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3338 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3339 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3343 * Ensures an image section's segments are sorted in memory
3348 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3351 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3353 MmspAssertSegmentsSorted(ImageSectionObject
);
3357 qsort(ImageSectionObject
->Segments
,
3358 ImageSectionObject
->NrSegments
,
3359 sizeof(ImageSectionObject
->Segments
[0]),
3360 MmspCompareSegments
);
3366 * Ensures an image section's segments don't overlap in memory and don't have
3367 * gaps and don't have a null size. We let them map to overlapping file regions,
3368 * though - that's not necessarily an error
3373 MmspCheckSegmentBounds
3375 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3381 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3383 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3387 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3389 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3391 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3399 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3400 * page could be OK (Windows seems to be OK with them), and larger gaps
3401 * could lead to image sections spanning several discontiguous regions
3402 * (NtMapViewOfSection could then refuse to map them, and they could
3403 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3405 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3406 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3407 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3418 * Merges and pads an image section's segments until they all are page-aligned
3419 * and have a size that is a multiple of the page size
3424 MmspPageAlignSegments
3426 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3432 PMM_SECTION_SEGMENT EffectiveSegment
;
3434 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3436 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3441 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3443 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3446 * The first segment requires special handling
3450 ULONG_PTR VirtualAddress
;
3451 ULONG_PTR VirtualOffset
;
3453 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3455 /* Round down the virtual address to the nearest page */
3456 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3458 /* Round up the virtual size to the nearest page */
3459 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3460 EffectiveSegment
->Image
.VirtualAddress
;
3462 /* Adjust the raw address and size */
3463 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3465 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3471 * Garbage in, garbage out: unaligned base addresses make the file
3472 * offset point in curious and odd places, but that's what we were
3475 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3476 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3480 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3481 ULONG_PTR EndOfEffectiveSegment
;
3483 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3484 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3487 * The current segment begins exactly where the current effective
3488 * segment ended, therefore beginning a new effective segment
3490 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3493 ASSERT(LastSegment
<= i
);
3494 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3496 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3498 if (LastSegment
!= i
)
3501 * Copy the current segment. If necessary, the effective segment
3502 * will be expanded later
3504 *EffectiveSegment
= *Segment
;
3508 * Page-align the virtual size. We know for sure the virtual address
3511 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3512 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3515 * The current segment is still part of the current effective segment:
3516 * extend the effective segment to reflect this
3518 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3520 static const ULONG FlagsToProtection
[16] =
3528 PAGE_EXECUTE_READWRITE
,
3529 PAGE_EXECUTE_READWRITE
,
3534 PAGE_EXECUTE_WRITECOPY
,
3535 PAGE_EXECUTE_WRITECOPY
,
3536 PAGE_EXECUTE_WRITECOPY
,
3537 PAGE_EXECUTE_WRITECOPY
3540 unsigned ProtectionFlags
;
3543 * Extend the file size
3546 /* Unaligned segments must be contiguous within the file */
3547 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3548 EffectiveSegment
->RawLength
.QuadPart
))
3553 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3556 * Extend the virtual size
3558 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3560 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3561 EffectiveSegment
->Image
.VirtualAddress
;
3564 * Merge the protection
3566 EffectiveSegment
->Protection
|= Segment
->Protection
;
3568 /* Clean up redundance */
3569 ProtectionFlags
= 0;
3571 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3572 ProtectionFlags
|= 1 << 0;
3574 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3575 ProtectionFlags
|= 1 << 1;
3577 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3578 ProtectionFlags
|= 1 << 2;
3580 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3581 ProtectionFlags
|= 1 << 3;
3583 ASSERT(ProtectionFlags
< 16);
3584 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3586 /* If a segment was required to be shared and cannot, fail */
3587 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3588 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3594 * We assume no holes between segments at this point
3598 KeBugCheck(MEMORY_MANAGEMENT
);
3602 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3608 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3609 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3611 LARGE_INTEGER Offset
;
3613 PVOID FileHeaderBuffer
;
3614 ULONG FileHeaderSize
;
3616 ULONG OldNrSegments
;
3621 * Read the beginning of the file (2 pages). Should be enough to contain
3622 * all (or most) of the headers
3624 Offset
.QuadPart
= 0;
3626 /* FIXME: use FileObject instead of FileHandle */
3627 Status
= ExeFmtpReadFile (FileHandle
,
3634 if (!NT_SUCCESS(Status
))
3637 if (FileHeaderSize
== 0)
3639 ExFreePool(FileHeaderBuffer
);
3640 return STATUS_UNSUCCESSFUL
;
3644 * Look for a loader that can handle this executable
3646 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3648 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3651 /* FIXME: use FileObject instead of FileHandle */
3652 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3658 ExeFmtpAllocateSegments
);
3660 if (!NT_SUCCESS(Status
))
3662 if (ImageSectionObject
->Segments
)
3664 ExFreePool(ImageSectionObject
->Segments
);
3665 ImageSectionObject
->Segments
= NULL
;
3669 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3673 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3676 * No loader handled the format
3678 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3680 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3681 ASSERT(!NT_SUCCESS(Status
));
3684 if (!NT_SUCCESS(Status
))
3687 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3692 /* FIXME? are these values platform-dependent? */
3693 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3694 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3696 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3697 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3699 if(ImageSectionObject
->BasedAddress
== NULL
)
3701 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3702 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3704 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3708 * And now the fun part: fixing the segments
3711 /* Sort them by virtual address */
3712 MmspSortSegments(ImageSectionObject
, Flags
);
3714 /* Ensure they don't overlap in memory */
3715 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3716 return STATUS_INVALID_IMAGE_FORMAT
;
3718 /* Ensure they are aligned */
3719 OldNrSegments
= ImageSectionObject
->NrSegments
;
3721 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3722 return STATUS_INVALID_IMAGE_FORMAT
;
3724 /* Trim them if the alignment phase merged some of them */
3725 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3727 PMM_SECTION_SEGMENT Segments
;
3728 SIZE_T SizeOfSegments
;
3730 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3732 Segments
= ExAllocatePoolWithTag(PagedPool
,
3734 TAG_MM_SECTION_SEGMENT
);
3736 if (Segments
== NULL
)
3737 return STATUS_INSUFFICIENT_RESOURCES
;
3739 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3740 ExFreePool(ImageSectionObject
->Segments
);
3741 ImageSectionObject
->Segments
= Segments
;
3744 /* And finish their initialization */
3745 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3747 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3748 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3749 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3752 ASSERT(NT_SUCCESS(Status
));
3757 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3758 ACCESS_MASK DesiredAccess
,
3759 POBJECT_ATTRIBUTES ObjectAttributes
,
3760 PLARGE_INTEGER UMaximumSize
,
3761 ULONG SectionPageProtection
,
3762 ULONG AllocationAttributes
,
3763 PFILE_OBJECT FileObject
)
3765 PROS_SECTION_OBJECT Section
;
3767 PMM_SECTION_SEGMENT SectionSegments
;
3768 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3771 if (FileObject
== NULL
)
3772 return STATUS_INVALID_FILE_FOR_SECTION
;
3775 * Create the section
3777 Status
= ObCreateObject (ExGetPreviousMode(),
3778 MmSectionObjectType
,
3780 ExGetPreviousMode(),
3782 sizeof(ROS_SECTION_OBJECT
),
3785 (PVOID
*)(PVOID
)&Section
);
3786 if (!NT_SUCCESS(Status
))
3788 ObDereferenceObject(FileObject
);
3795 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3796 Section
->Type
= 'SC';
3797 Section
->Size
= 'TN';
3798 Section
->SectionPageProtection
= SectionPageProtection
;
3799 Section
->AllocationAttributes
= AllocationAttributes
;
3803 * Initialized caching for this file object if previously caching
3804 * was initialized for the same on disk file
3806 Status
= CcTryToInitializeFileCache(FileObject
);
3808 Status
= STATUS_SUCCESS
;
3811 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3813 NTSTATUS StatusExeFmt
;
3815 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3816 if (ImageSectionObject
== NULL
)
3818 ObDereferenceObject(FileObject
);
3819 ObDereferenceObject(Section
);
3820 return(STATUS_NO_MEMORY
);
3823 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3825 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3827 if (!NT_SUCCESS(StatusExeFmt
))
3829 if(ImageSectionObject
->Segments
!= NULL
)
3830 ExFreePool(ImageSectionObject
->Segments
);
3832 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3833 ObDereferenceObject(Section
);
3834 ObDereferenceObject(FileObject
);
3835 return(StatusExeFmt
);
3838 Section
->ImageSection
= ImageSectionObject
;
3839 ASSERT(ImageSectionObject
->Segments
);
3844 Status
= MmspWaitForFileLock(FileObject
);
3845 if (!NT_SUCCESS(Status
))
3847 ExFreePool(ImageSectionObject
->Segments
);
3848 ExFreePool(ImageSectionObject
);
3849 ObDereferenceObject(Section
);
3850 ObDereferenceObject(FileObject
);
3854 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3855 ImageSectionObject
, NULL
))
3858 * An other thread has initialized the same image in the background
3860 ExFreePool(ImageSectionObject
->Segments
);
3861 ExFreePool(ImageSectionObject
);
3862 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3863 Section
->ImageSection
= ImageSectionObject
;
3864 SectionSegments
= ImageSectionObject
->Segments
;
3866 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3868 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3872 Status
= StatusExeFmt
;
3879 Status
= MmspWaitForFileLock(FileObject
);
3880 if (Status
!= STATUS_SUCCESS
)
3882 ObDereferenceObject(Section
);
3883 ObDereferenceObject(FileObject
);
3887 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3888 Section
->ImageSection
= ImageSectionObject
;
3889 SectionSegments
= ImageSectionObject
->Segments
;
3892 * Otherwise just reference all the section segments
3894 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3896 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3899 Status
= STATUS_SUCCESS
;
3901 Section
->FileObject
= FileObject
;
3903 CcRosReferenceCache(FileObject
);
3905 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3906 *SectionObject
= Section
;
3913 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3914 PROS_SECTION_OBJECT Section
,
3915 PMM_SECTION_SEGMENT Segment
,
3920 ULONG AllocationType
)
3926 if (Segment
->WriteCopy
)
3928 /* We have to do this because the not present fault
3929 * and access fault handlers depend on the protection
3930 * that should be granted AFTER the COW fault takes
3931 * place to be in Region->Protect. The not present fault
3932 * handler changes this to the correct protection for COW when
3933 * mapping the pages into the process's address space. If a COW
3934 * fault takes place, the access fault handler sets the page protection
3935 * to these values for the newly copied pages
3937 if (Protect
== PAGE_WRITECOPY
)
3938 Protect
= PAGE_READWRITE
;
3939 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3940 Protect
= PAGE_EXECUTE_READWRITE
;
3943 if (*BaseAddress
== NULL
)
3944 Granularity
= MM_ALLOCATION_GRANULARITY
;
3946 Granularity
= PAGE_SIZE
;
3949 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3951 LARGE_INTEGER FileOffset
;
3952 FileOffset
.QuadPart
= ViewOffset
;
3953 ObReferenceObject(Section
);
3954 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3957 Status
= MmCreateMemoryArea(AddressSpace
,
3958 MEMORY_AREA_SECTION_VIEW
,
3966 if (!NT_SUCCESS(Status
))
3968 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3969 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3973 ObReferenceObject((PVOID
)Section
);
3975 MArea
->Data
.SectionData
.Segment
= Segment
;
3976 MArea
->Data
.SectionData
.Section
= Section
;
3977 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3978 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3979 ViewSize
, 0, Protect
);
3981 return(STATUS_SUCCESS
);
3986 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3987 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3990 PFILE_OBJECT FileObject
;
3991 PROS_SHARED_CACHE_MAP SharedCacheMap
;
3992 LARGE_INTEGER Offset
;
3993 SWAPENTRY SavedSwapEntry
;
3994 PROS_SECTION_OBJECT Section
;
3995 PMM_SECTION_SEGMENT Segment
;
3996 PMMSUPPORT AddressSpace
;
3999 AddressSpace
= (PMMSUPPORT
)Context
;
4000 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4002 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4004 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
4005 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
4007 Section
= MemoryArea
->Data
.SectionData
.Section
;
4008 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4010 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4011 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
4013 MmUnlockSectionSegment(Segment
);
4014 MmUnlockAddressSpace(AddressSpace
);
4016 MiWaitForPageEvent(NULL
, NULL
);
4018 MmLockAddressSpace(AddressSpace
);
4019 MmLockSectionSegment(Segment
);
4020 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4024 * For a dirty, datafile, non-private page mark it as dirty in the
4027 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4029 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4031 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4032 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4034 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4036 ASSERT(SwapEntry
== 0);
4045 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4047 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4048 KeBugCheck(MEMORY_MANAGEMENT
);
4050 MmFreeSwapPage(SwapEntry
);
4054 if (IS_SWAP_FROM_SSE(Entry
) ||
4055 Page
!= PFN_FROM_SSE(Entry
))
4060 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4062 DPRINT1("Found a private page in a pagefile section.\n");
4063 KeBugCheck(MEMORY_MANAGEMENT
);
4066 * Just dereference private pages
4068 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4069 if (SavedSwapEntry
!= 0)
4071 MmFreeSwapPage(SavedSwapEntry
);
4072 MmSetSavedSwapEntryPage(Page
, 0);
4074 MmDeleteRmap(Page
, Process
, Address
);
4075 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4079 MmDeleteRmap(Page
, Process
, Address
);
4080 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4086 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4090 PMEMORY_AREA MemoryArea
;
4091 PROS_SECTION_OBJECT Section
;
4092 PMM_SECTION_SEGMENT Segment
;
4093 PLIST_ENTRY CurrentEntry
;
4094 PMM_REGION CurrentRegion
;
4095 PLIST_ENTRY RegionListHead
;
4097 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4099 if (MemoryArea
== NULL
)
4101 return(STATUS_UNSUCCESSFUL
);
4104 Section
= MemoryArea
->Data
.SectionData
.Section
;
4105 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4108 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4110 MmUnlockAddressSpace(AddressSpace
);
4111 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4112 MmLockAddressSpace(AddressSpace
);
4118 MemoryArea
->DeleteInProgress
= TRUE
;
4120 MmLockSectionSegment(Segment
);
4122 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4123 while (!IsListEmpty(RegionListHead
))
4125 CurrentEntry
= RemoveHeadList(RegionListHead
);
4126 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4127 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4130 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4132 Status
= MmFreeMemoryArea(AddressSpace
,
4139 Status
= MmFreeMemoryArea(AddressSpace
,
4144 MmUnlockSectionSegment(Segment
);
4145 ObDereferenceObject(Section
);
4151 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4152 IN PVOID BaseAddress
,
4156 PMEMORY_AREA MemoryArea
;
4157 PMMSUPPORT AddressSpace
;
4158 PROS_SECTION_OBJECT Section
;
4159 PVOID ImageBaseAddress
= 0;
4161 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4162 Process
, BaseAddress
);
4166 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4168 MmLockAddressSpace(AddressSpace
);
4169 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4171 if (MemoryArea
== NULL
||
4172 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4173 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4174 MemoryArea
->DeleteInProgress
)
4176 if (MemoryArea
) NT_ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4177 MmUnlockAddressSpace(AddressSpace
);
4178 return STATUS_NOT_MAPPED_VIEW
;
4181 Section
= MemoryArea
->Data
.SectionData
.Section
;
4183 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4187 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4188 PMM_SECTION_SEGMENT SectionSegments
;
4189 PMM_SECTION_SEGMENT Segment
;
4191 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4192 ImageSectionObject
= Section
->ImageSection
;
4193 SectionSegments
= ImageSectionObject
->Segments
;
4194 NrSegments
= ImageSectionObject
->NrSegments
;
4196 MemoryArea
->DeleteInProgress
= TRUE
;
4198 /* Search for the current segment within the section segments
4199 * and calculate the image base address */
4200 for (i
= 0; i
< NrSegments
; i
++)
4202 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4204 if (Segment
== &SectionSegments
[i
])
4206 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4211 if (i
>= NrSegments
)
4213 KeBugCheck(MEMORY_MANAGEMENT
);
4216 for (i
= 0; i
< NrSegments
; i
++)
4218 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4220 PVOID SBaseAddress
= (PVOID
)
4221 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4223 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4224 NT_ASSERT(NT_SUCCESS(Status
));
4230 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4231 NT_ASSERT(NT_SUCCESS(Status
));
4234 MmUnlockAddressSpace(AddressSpace
);
4236 /* Notify debugger */
4237 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4239 return(STATUS_SUCCESS
);
4246 * Queries the information of a section object.
4248 * @param SectionHandle
4249 * Handle to the section object. It must be opened with SECTION_QUERY
4251 * @param SectionInformationClass
4252 * Index to a certain information structure. Can be either
4253 * SectionBasicInformation or SectionImageInformation. The latter
4254 * is valid only for sections that were created with the SEC_IMAGE
4256 * @param SectionInformation
4257 * Caller supplies storage for resulting information.
4259 * Size of the supplied storage.
4260 * @param ResultLength
4268 NtQuerySection(IN HANDLE SectionHandle
,
4269 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4270 OUT PVOID SectionInformation
,
4271 IN SIZE_T SectionInformationLength
,
4272 OUT PSIZE_T ResultLength OPTIONAL
)
4274 PROS_SECTION_OBJECT Section
;
4275 KPROCESSOR_MODE PreviousMode
;
4279 PreviousMode
= ExGetPreviousMode();
4281 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4283 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4285 (ULONG
)SectionInformationLength
,
4290 if(!NT_SUCCESS(Status
))
4292 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4296 Status
= ObReferenceObjectByHandle(SectionHandle
,
4298 MmSectionObjectType
,
4300 (PVOID
*)(PVOID
)&Section
,
4302 if (NT_SUCCESS(Status
))
4304 switch (SectionInformationClass
)
4306 case SectionBasicInformation
:
4308 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4312 Sbi
->Attributes
= Section
->AllocationAttributes
;
4313 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4315 Sbi
->BaseAddress
= 0;
4316 Sbi
->Size
.QuadPart
= 0;
4320 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4321 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4324 if (ResultLength
!= NULL
)
4326 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4328 Status
= STATUS_SUCCESS
;
4330 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4332 Status
= _SEH2_GetExceptionCode();
4339 case SectionImageInformation
:
4341 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4345 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4347 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4348 ImageSectionObject
= Section
->ImageSection
;
4350 *Sii
= ImageSectionObject
->ImageInformation
;
4353 if (ResultLength
!= NULL
)
4355 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4357 Status
= STATUS_SUCCESS
;
4359 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4361 Status
= _SEH2_GetExceptionCode();
4369 ObDereferenceObject(Section
);
4375 /**********************************************************************
4377 * MmMapViewOfSection
4380 * Maps a view of a section into the virtual address space of a
4385 * Pointer to the section object.
4388 * Pointer to the process.
4391 * Desired base address (or NULL) on entry;
4392 * Actual base address of the view on exit.
4395 * Number of high order address bits that must be zero.
4398 * Size in bytes of the initially committed section of
4402 * Offset in bytes from the beginning of the section
4403 * to the beginning of the view.
4406 * Desired length of map (or zero to map all) on entry
4407 * Actual length mapped on exit.
4409 * InheritDisposition
4410 * Specified how the view is to be shared with
4414 * Type of allocation for the pages.
4417 * Protection for the committed region of the view.
4425 MmMapViewOfSection(IN PVOID SectionObject
,
4426 IN PEPROCESS Process
,
4427 IN OUT PVOID
*BaseAddress
,
4428 IN ULONG_PTR ZeroBits
,
4429 IN SIZE_T CommitSize
,
4430 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4431 IN OUT PSIZE_T ViewSize
,
4432 IN SECTION_INHERIT InheritDisposition
,
4433 IN ULONG AllocationType
,
4436 PROS_SECTION_OBJECT Section
;
4437 PMMSUPPORT AddressSpace
;
4439 NTSTATUS Status
= STATUS_SUCCESS
;
4440 BOOLEAN NotAtBase
= FALSE
;
4442 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4444 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4445 return MmMapViewOfArm3Section(SectionObject
,
4459 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4461 return STATUS_INVALID_PAGE_PROTECTION
;
4465 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4466 AddressSpace
= &Process
->Vm
;
4468 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4470 MmLockAddressSpace(AddressSpace
);
4472 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4476 ULONG_PTR ImageBase
;
4478 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4479 PMM_SECTION_SEGMENT SectionSegments
;
4481 ImageSectionObject
= Section
->ImageSection
;
4482 SectionSegments
= ImageSectionObject
->Segments
;
4483 NrSegments
= ImageSectionObject
->NrSegments
;
4485 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4488 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4492 for (i
= 0; i
< NrSegments
; i
++)
4494 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4496 ULONG_PTR MaxExtent
;
4497 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4498 SectionSegments
[i
].Length
.QuadPart
);
4499 ImageSize
= max(ImageSize
, MaxExtent
);
4503 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4505 /* Check for an illegal base address */
4506 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4507 ((ImageBase
+ ImageSize
) < ImageSize
))
4509 NT_ASSERT(*BaseAddress
== NULL
);
4510 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4511 MM_VIRTMEM_GRANULARITY
);
4514 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4516 NT_ASSERT(*BaseAddress
== NULL
);
4517 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4521 /* Check there is enough space to map the section at that point. */
4522 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4523 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4525 /* Fail if the user requested a fixed base address. */
4526 if ((*BaseAddress
) != NULL
)
4528 MmUnlockAddressSpace(AddressSpace
);
4529 return(STATUS_CONFLICTING_ADDRESSES
);
4531 /* Otherwise find a gap to map the image. */
4532 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4535 MmUnlockAddressSpace(AddressSpace
);
4536 return(STATUS_CONFLICTING_ADDRESSES
);
4538 /* Remember that we loaded image at a different base address */
4542 for (i
= 0; i
< NrSegments
; i
++)
4544 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4546 PVOID SBaseAddress
= (PVOID
)
4547 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4548 MmLockSectionSegment(&SectionSegments
[i
]);
4549 Status
= MmMapViewOfSegment(AddressSpace
,
4551 &SectionSegments
[i
],
4553 SectionSegments
[i
].Length
.LowPart
,
4554 SectionSegments
[i
].Protection
,
4557 MmUnlockSectionSegment(&SectionSegments
[i
]);
4558 if (!NT_SUCCESS(Status
))
4560 MmUnlockAddressSpace(AddressSpace
);
4566 *BaseAddress
= (PVOID
)ImageBase
;
4567 *ViewSize
= ImageSize
;
4571 /* check for write access */
4572 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4573 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4575 MmUnlockAddressSpace(AddressSpace
);
4576 return STATUS_SECTION_PROTECTION
;
4578 /* check for read access */
4579 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4580 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4582 MmUnlockAddressSpace(AddressSpace
);
4583 return STATUS_SECTION_PROTECTION
;
4585 /* check for execute access */
4586 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4587 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4589 MmUnlockAddressSpace(AddressSpace
);
4590 return STATUS_SECTION_PROTECTION
;
4593 if (ViewSize
== NULL
)
4595 /* Following this pointer would lead to us to the dark side */
4596 /* What to do? Bugcheck? Return status? Do the mambo? */
4597 KeBugCheck(MEMORY_MANAGEMENT
);
4600 if (SectionOffset
== NULL
)
4606 ViewOffset
= SectionOffset
->u
.LowPart
;
4609 if ((ViewOffset
% PAGE_SIZE
) != 0)
4611 MmUnlockAddressSpace(AddressSpace
);
4612 return(STATUS_MAPPED_ALIGNMENT
);
4615 if ((*ViewSize
) == 0)
4617 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4619 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4621 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4624 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4626 MmLockSectionSegment(Section
->Segment
);
4627 Status
= MmMapViewOfSegment(AddressSpace
,
4634 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4635 MmUnlockSectionSegment(Section
->Segment
);
4636 if (!NT_SUCCESS(Status
))
4638 MmUnlockAddressSpace(AddressSpace
);
4643 MmUnlockAddressSpace(AddressSpace
);
4644 NT_ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4647 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4649 Status
= STATUS_SUCCESS
;
4658 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4659 IN PLARGE_INTEGER NewFileSize
)
4661 /* Check whether an ImageSectionObject exists */
4662 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4664 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4668 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4670 PMM_SECTION_SEGMENT Segment
;
4672 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4675 if (Segment
->ReferenceCount
!= 0)
4678 CC_FILE_SIZES FileSizes
;
4680 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4683 /* Check size of file */
4684 if (SectionObjectPointer
->SharedCacheMap
)
4686 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4691 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4700 /* Check size of file */
4701 if (SectionObjectPointer
->SharedCacheMap
)
4703 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4704 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4713 /* Something must gone wrong
4714 * how can we have a Section but no
4716 DPRINT("ERROR: DataSectionObject without reference!\n");
4720 DPRINT("FIXME: didn't check for outstanding write probes\n");
4732 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4733 IN MMFLUSH_TYPE FlushType
)
4735 BOOLEAN Result
= TRUE
;
4737 PMM_SECTION_SEGMENT Segment
;
4742 case MmFlushForDelete
:
4743 if (SectionObjectPointer
->ImageSectionObject
||
4744 SectionObjectPointer
->DataSectionObject
)
4749 CcRosRemoveIfClosed(SectionObjectPointer
);
4752 case MmFlushForWrite
:
4754 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4756 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4759 if (SectionObjectPointer
->ImageSectionObject
)
4761 DPRINT1("SectionObject has ImageSection\n");
4767 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4769 DPRINT("Result %d\n", Result
);
4781 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4782 OUT PVOID
* MappedBase
,
4783 IN OUT PSIZE_T ViewSize
)
4785 PROS_SECTION_OBJECT Section
;
4786 PMMSUPPORT AddressSpace
;
4790 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4792 return MiMapViewInSystemSpace(SectionObject
,
4798 DPRINT("MmMapViewInSystemSpace() called\n");
4800 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4801 AddressSpace
= MmGetKernelAddressSpace();
4803 MmLockAddressSpace(AddressSpace
);
4806 if ((*ViewSize
) == 0)
4808 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4810 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4812 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4815 MmLockSectionSegment(Section
->Segment
);
4818 Status
= MmMapViewOfSegment(AddressSpace
,
4827 MmUnlockSectionSegment(Section
->Segment
);
4828 MmUnlockAddressSpace(AddressSpace
);
4835 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4837 PMMSUPPORT AddressSpace
;
4840 DPRINT("MmUnmapViewInSystemSpace() called\n");
4842 AddressSpace
= MmGetKernelAddressSpace();
4844 MmLockAddressSpace(AddressSpace
);
4846 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4848 MmUnlockAddressSpace(AddressSpace
);
4853 /**********************************************************************
4858 * Creates a section object.
4861 * SectionObject (OUT)
4862 * Caller supplied storage for the resulting pointer
4863 * to a SECTION_OBJECT instance;
4866 * Specifies the desired access to the section can be a
4868 * STANDARD_RIGHTS_REQUIRED |
4870 * SECTION_MAP_WRITE |
4871 * SECTION_MAP_READ |
4872 * SECTION_MAP_EXECUTE
4874 * ObjectAttributes [OPTIONAL]
4875 * Initialized attributes for the object can be used
4876 * to create a named section;
4879 * Maximizes the size of the memory section. Must be
4880 * non-NULL for a page-file backed section.
4881 * If value specified for a mapped file and the file is
4882 * not large enough, file will be extended.
4884 * SectionPageProtection
4885 * Can be a combination of:
4891 * AllocationAttributes
4892 * Can be a combination of:
4897 * Handle to a file to create a section mapped to a file
4898 * instead of a memory backed section;
4909 MmCreateSection (OUT PVOID
* Section
,
4910 IN ACCESS_MASK DesiredAccess
,
4911 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4912 IN PLARGE_INTEGER MaximumSize
,
4913 IN ULONG SectionPageProtection
,
4914 IN ULONG AllocationAttributes
,
4915 IN HANDLE FileHandle OPTIONAL
,
4916 IN PFILE_OBJECT FileObject OPTIONAL
)
4920 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4922 /* Check if an ARM3 section is being created instead */
4923 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4925 if (!(FileObject
) && !(FileHandle
))
4927 return MmCreateArm3Section(Section
,
4931 SectionPageProtection
,
4932 AllocationAttributes
&~ 1,
4938 /* Convert section flag to page flag */
4939 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4941 /* Check to make sure the protection is correct. Nt* does this already */
4942 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4943 if (Protection
== MM_INVALID_PROTECTION
)
4945 DPRINT1("Page protection is invalid\n");
4946 return STATUS_INVALID_PAGE_PROTECTION
;
4949 /* Check if this is going to be a data or image backed file section */
4950 if ((FileHandle
) || (FileObject
))
4952 /* These cannot be mapped with large pages */
4953 if (AllocationAttributes
& SEC_LARGE_PAGES
)
4955 DPRINT1("Large pages cannot be used with an image mapping\n");
4956 return STATUS_INVALID_PARAMETER_6
;
4959 /* Did the caller pass an object? */
4962 /* Reference the object directly */
4963 ObReferenceObject(FileObject
);
4967 /* Reference the file handle to get the object */
4968 Status
= ObReferenceObjectByHandle(FileHandle
,
4969 MmMakeFileAccess
[Protection
],
4971 ExGetPreviousMode(),
4972 (PVOID
*)&FileObject
,
4974 if (!NT_SUCCESS(Status
))
4976 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
4983 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
4984 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
4987 #ifndef NEWCC // A hack for initializing caching.
4988 // This is needed only in the old case.
4991 IO_STATUS_BLOCK Iosb
;
4994 LARGE_INTEGER ByteOffset
;
4995 ByteOffset
.QuadPart
= 0;
4996 Status
= ZwReadFile(FileHandle
,
5005 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5007 DPRINT1("CC failure: %lx\n", Status
);
5010 // Caching is initialized...
5014 if (AllocationAttributes
& SEC_IMAGE
)
5016 Status
= MmCreateImageSection(SectionObject
,
5020 SectionPageProtection
,
5021 AllocationAttributes
,
5025 else if (FileHandle
!= NULL
)
5027 Status
= MmCreateDataFileSection(SectionObject
,
5031 SectionPageProtection
,
5032 AllocationAttributes
,
5035 ObDereferenceObject(FileObject
);
5038 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5040 Status
= MmCreateCacheSection(SectionObject
,
5044 SectionPageProtection
,
5045 AllocationAttributes
,
5051 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5053 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5055 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5056 Status
= MmCreatePageFileSection(SectionObject
,
5060 SectionPageProtection
,
5061 AllocationAttributes
);