2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
48 #include "../cache/newcc.h"
49 #include "../cache/section/newmm.h"
52 #include <reactos/exeformat.h>
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 #include "ARM3/miarm.h"
61 #undef MmSetPageEntrySectionSegment
62 #define MmSetPageEntrySectionSegment(S,O,E) do { \
63 DPRINT("SetPageEntrySectionSegment(old,%p,%x,%x)\n",(S),(O)->LowPart,E); \
64 _MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__); \
67 extern MMSESSION MmSession
;
71 MiMapViewInSystemSpace(IN PVOID Section
,
73 OUT PVOID
*MappedBase
,
74 IN OUT PSIZE_T ViewSize
);
78 MmCreateArm3Section(OUT PVOID
*SectionObject
,
79 IN ACCESS_MASK DesiredAccess
,
80 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
81 IN PLARGE_INTEGER InputMaximumSize
,
82 IN ULONG SectionPageProtection
,
83 IN ULONG AllocationAttributes
,
84 IN HANDLE FileHandle OPTIONAL
,
85 IN PFILE_OBJECT FileObject OPTIONAL
);
89 MmMapViewOfArm3Section(IN PVOID SectionObject
,
91 IN OUT PVOID
*BaseAddress
,
92 IN ULONG_PTR ZeroBits
,
94 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
95 IN OUT PSIZE_T ViewSize
,
96 IN SECTION_INHERIT InheritDisposition
,
97 IN ULONG AllocationType
,
101 // PeFmtCreateSection depends on the following:
103 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
104 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
106 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
107 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
108 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
110 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
111 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
112 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
113 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
114 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
115 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
116 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
117 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
118 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
120 /* TYPES *********************************************************************/
124 PROS_SECTION_OBJECT Section
;
125 PMM_SECTION_SEGMENT Segment
;
126 LARGE_INTEGER Offset
;
129 PEPROCESS CallingProcess
;
130 ULONG_PTR SectionEntry
;
132 MM_SECTION_PAGEOUT_CONTEXT
;
134 /* GLOBALS *******************************************************************/
136 POBJECT_TYPE MmSectionObjectType
= NULL
;
138 ULONG_PTR MmSubsectionBase
;
140 static ULONG SectionCharacteristicsToProtect
[16] =
142 PAGE_NOACCESS
, /* 0 = NONE */
143 PAGE_NOACCESS
, /* 1 = SHARED */
144 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
145 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
146 PAGE_READONLY
, /* 4 = READABLE */
147 PAGE_READONLY
, /* 5 = READABLE, SHARED */
148 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
149 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
151 * FIXME? do we really need the WriteCopy field in segments? can't we use
152 * PAGE_WRITECOPY here?
154 PAGE_READWRITE
, /* 8 = WRITABLE */
155 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
156 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
157 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
158 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
159 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
160 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
161 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
164 extern ULONG MmMakeFileAccess
[];
165 ACCESS_MASK NTAPI
MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection
);
166 static GENERIC_MAPPING MmpSectionMapping
= {
167 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
168 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
169 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
172 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
174 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
175 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
178 /* FUNCTIONS *****************************************************************/
183 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
184 File Format Specification", revision 6.0 (February 1999)
186 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
187 IN SIZE_T FileHeaderSize
,
189 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
191 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
192 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
195 ULONG cbFileHeaderOffsetSize
= 0;
196 ULONG cbSectionHeadersOffset
= 0;
197 ULONG cbSectionHeadersSize
;
198 ULONG cbSectionHeadersOffsetSize
= 0;
199 ULONG cbOptHeaderSize
;
200 ULONG cbHeadersSize
= 0;
201 ULONG nSectionAlignment
;
202 ULONG nFileAlignment
;
204 const IMAGE_DOS_HEADER
* pidhDosHeader
;
205 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
206 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
207 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
208 PMM_SECTION_SEGMENT pssSegments
;
209 LARGE_INTEGER lnOffset
;
211 SIZE_T nPrevVirtualEndOfSegment
= 0;
212 ULONG nFileSizeOfHeaders
= 0;
216 ASSERT(FileHeaderSize
> 0);
218 ASSERT(ImageSectionObject
);
220 ASSERT(AllocateSegmentsCb
);
222 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
224 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
226 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
229 pidhDosHeader
= FileHeader
;
232 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
234 /* image too small to be an MZ executable */
235 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
236 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
238 /* no MZ signature */
239 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
240 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
242 /* not a Windows executable */
243 if(pidhDosHeader
->e_lfanew
<= 0)
244 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
247 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
249 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
250 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
252 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
257 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
258 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
260 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
261 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
265 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
266 * need to read the header from the file
268 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
269 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
271 ULONG cbNtHeaderSize
;
275 l_ReadHeaderFromFile
:
277 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
279 /* read the header from the file */
280 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
282 if(!NT_SUCCESS(nStatus
))
284 NTSTATUS ReturnedStatus
= nStatus
;
286 /* If it attempted to read past the end of the file, it means e_lfanew is invalid */
287 if (ReturnedStatus
== STATUS_END_OF_FILE
) nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
289 DIE(("ReadFile failed, status %08X\n", ReturnedStatus
));
294 ASSERT(cbReadSize
> 0);
296 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
298 /* the buffer doesn't contain the file header */
299 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
300 DIE(("The file doesn't contain the PE file header\n"));
302 pinhNtHeader
= pData
;
304 /* object still not aligned: copy it to the beginning of the buffer */
305 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
307 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
308 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
309 pinhNtHeader
= pBuffer
;
312 /* invalid NT header */
313 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
315 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
316 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
318 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
320 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
321 DIE(("The full NT header is too large\n"));
323 /* the buffer doesn't contain the whole NT header */
324 if(cbReadSize
< cbNtHeaderSize
)
325 DIE(("The file doesn't contain the full NT header\n"));
329 ULONG cbOptHeaderOffsetSize
= 0;
331 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
333 /* don't trust an invalid NT header */
334 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
335 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
337 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
338 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
340 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
341 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
343 /* the buffer doesn't contain the whole NT header: read it from the file */
344 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
345 goto l_ReadHeaderFromFile
;
348 /* read information from the NT header */
349 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
350 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
352 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
354 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
355 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
357 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
359 switch(piohOptHeader
->Magic
)
361 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
362 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
366 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
369 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
370 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
372 /* See [1], section 3.4.2 */
373 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
375 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
376 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
378 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
379 DIE(("The section alignment is smaller than the file alignment\n"));
381 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
382 nFileAlignment
= piohOptHeader
->FileAlignment
;
384 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
385 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
389 nSectionAlignment
= PAGE_SIZE
;
390 nFileAlignment
= PAGE_SIZE
;
393 ASSERT(IsPowerOf2(nSectionAlignment
));
394 ASSERT(IsPowerOf2(nFileAlignment
));
396 switch(piohOptHeader
->Magic
)
399 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
401 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
402 ImageBase
= piohOptHeader
->ImageBase
;
404 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
405 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
407 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
408 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
410 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
411 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
413 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
415 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
417 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
418 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
420 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
421 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
425 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
427 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
428 piohOptHeader
->AddressOfEntryPoint
);
431 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
432 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
434 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
436 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
438 if (piohOptHeader
->AddressOfEntryPoint
== 0)
440 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
444 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
445 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
447 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
449 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
452 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
453 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
454 * magic to any binary.
456 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
457 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
458 * the SxS support -- at which point, duh, this should be removed.
460 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
462 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
469 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
471 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
473 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
475 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
477 ImageBase
= pioh64OptHeader
->ImageBase
;
478 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
479 DIE(("ImageBase exceeds the address space\n"));
482 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
484 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
485 DIE(("SizeOfImage exceeds the address space\n"));
487 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
490 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
492 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
493 DIE(("SizeOfStackReserve exceeds the address space\n"));
495 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
498 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
500 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
501 DIE(("SizeOfStackCommit exceeds the address space\n"));
503 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
506 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
508 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
510 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
511 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
513 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
514 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
518 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
520 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
521 pioh64OptHeader
->AddressOfEntryPoint
);
524 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
525 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
527 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
529 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
531 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
533 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
537 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
538 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
540 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
541 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
548 /* [1], section 3.4.2 */
549 if((ULONG_PTR
)ImageBase
% 0x10000)
550 DIE(("ImageBase is not aligned on a 64KB boundary"));
552 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
553 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
554 ImageSectionObject
->ImageInformation
.GpValue
= 0;
555 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
556 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
558 /* SECTION HEADERS */
559 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
561 /* see [1], section 3.3 */
562 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
563 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
566 * the additional segment is for the file's headers. They need to be present for
567 * the benefit of the dynamic loader (to locate exports, defaults for thread
568 * parameters, resources, etc.)
570 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
572 /* file offset for the section headers */
573 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
574 DIE(("Offset overflow\n"));
576 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
577 DIE(("Offset overflow\n"));
579 /* size of the section headers */
580 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
581 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
583 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
584 DIE(("Section headers too large\n"));
586 /* size of the executable's headers */
587 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
589 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
590 // DIE(("SizeOfHeaders is not aligned\n"));
592 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
593 DIE(("The section headers overflow SizeOfHeaders\n"));
595 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
597 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
598 DIE(("Overflow aligning the size of headers\n"));
605 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
606 /* WARNING: piohOptHeader IS NO LONGER USABLE */
607 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
609 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
610 pishSectionHeaders
= NULL
;
614 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
615 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
617 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
618 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
622 * the buffer doesn't contain the section headers, or the alignment is wrong:
623 * read the headers from the file
625 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
626 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
631 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
633 /* read the header from the file */
634 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
636 if(!NT_SUCCESS(nStatus
))
637 DIE(("ReadFile failed with status %08X\n", nStatus
));
641 ASSERT(cbReadSize
> 0);
643 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
645 /* the buffer doesn't contain all the section headers */
646 if(cbReadSize
< cbSectionHeadersSize
)
647 DIE(("The file doesn't contain all of the section headers\n"));
649 pishSectionHeaders
= pData
;
651 /* object still not aligned: copy it to the beginning of the buffer */
652 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
654 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
655 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
656 pishSectionHeaders
= pBuffer
;
661 /* allocate the segments */
662 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
663 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
665 if(ImageSectionObject
->Segments
== NULL
)
666 DIE(("AllocateSegments failed\n"));
668 /* initialize the headers segment */
669 pssSegments
= ImageSectionObject
->Segments
;
671 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
673 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
674 DIE(("Cannot align the size of the section headers\n"));
676 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
677 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
678 DIE(("Cannot align the size of the section headers\n"));
680 pssSegments
[0].Image
.FileOffset
= 0;
681 pssSegments
[0].Protection
= PAGE_READONLY
;
682 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
683 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
684 pssSegments
[0].Image
.VirtualAddress
= 0;
685 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
686 pssSegments
[0].WriteCopy
= TRUE
;
688 /* skip the headers segment */
691 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
693 /* convert the executable sections into segments. See also [1], section 4 */
694 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
696 ULONG nCharacteristics
;
698 /* validate the alignment */
699 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
700 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
702 /* sections must be contiguous, ordered by base address and non-overlapping */
703 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
704 DIE(("Memory gap between section %u and the previous\n", i
));
706 /* ignore explicit BSS sections */
707 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
709 /* validate the alignment */
711 /* Yes, this should be a multiple of FileAlignment, but there's
712 * stuff out there that isn't. We can cope with that
714 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
715 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
718 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
719 // DIE(("PointerToRawData[%u] is not aligned\n", i));
722 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
723 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
727 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
728 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
731 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
733 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
735 /* no explicit protection */
736 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
738 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
739 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
741 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
742 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
744 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
745 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
748 /* see table above */
749 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
750 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
752 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
753 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
755 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
757 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
758 /* FIXME: always false */
759 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
760 DIE(("Cannot align the virtual size of section %u\n", i
));
762 if(pssSegments
[i
].Length
.QuadPart
== 0)
763 DIE(("Virtual size of section %u is null\n", i
));
765 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
766 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
768 /* ensure the memory image is no larger than 4GB */
769 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
770 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
771 DIE(("The image is too large\n"));
774 if(nSectionAlignment
>= PAGE_SIZE
)
775 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
778 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
788 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
789 * ARGUMENTS: PFILE_OBJECT to wait for.
790 * RETURNS: Status of the wait.
793 MmspWaitForFileLock(PFILE_OBJECT File
)
795 return STATUS_SUCCESS
;
796 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
801 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
803 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
805 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
806 PMM_SECTION_SEGMENT SectionSegments
;
810 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
811 NrSegments
= ImageSectionObject
->NrSegments
;
812 SectionSegments
= ImageSectionObject
->Segments
;
813 for (i
= 0; i
< NrSegments
; i
++)
815 if (SectionSegments
[i
].ReferenceCount
!= 0)
817 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
818 SectionSegments
[i
].ReferenceCount
);
819 KeBugCheck(MEMORY_MANAGEMENT
);
821 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
823 ExFreePool(ImageSectionObject
->Segments
);
824 ExFreePool(ImageSectionObject
);
825 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
827 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
829 PMM_SECTION_SEGMENT Segment
;
831 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
834 if (Segment
->ReferenceCount
!= 0)
836 DPRINT1("Data segment still referenced\n");
837 KeBugCheck(MEMORY_MANAGEMENT
);
839 MmFreePageTablesSectionSegment(Segment
, NULL
);
841 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
847 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
848 PLARGE_INTEGER Offset
)
852 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
855 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
856 KeBugCheck(MEMORY_MANAGEMENT
);
858 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
860 DPRINT1("Maximum share count reached\n");
861 KeBugCheck(MEMORY_MANAGEMENT
);
863 if (IS_SWAP_FROM_SSE(Entry
))
865 KeBugCheck(MEMORY_MANAGEMENT
);
867 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
868 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
873 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
874 PMM_SECTION_SEGMENT Segment
,
875 PLARGE_INTEGER Offset
,
880 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
881 BOOLEAN IsDirectMapped
= FALSE
;
885 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
886 KeBugCheck(MEMORY_MANAGEMENT
);
888 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
890 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
891 KeBugCheck(MEMORY_MANAGEMENT
);
893 if (IS_SWAP_FROM_SSE(Entry
))
895 KeBugCheck(MEMORY_MANAGEMENT
);
897 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
899 * If we reducing the share count of this entry to zero then set the entry
900 * to zero and tell the cache the page is no longer mapped.
902 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
904 PFILE_OBJECT FileObject
;
906 PROS_SHARED_CACHE_MAP SharedCacheMap
;
908 SWAPENTRY SavedSwapEntry
;
910 BOOLEAN IsImageSection
;
911 LARGE_INTEGER FileOffset
;
913 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
915 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
917 Page
= PFN_FROM_SSE(Entry
);
918 FileObject
= Section
->FileObject
;
919 if (FileObject
!= NULL
&&
920 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
924 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
925 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
928 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
929 IsDirectMapped
= TRUE
;
931 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
.LowPart
, Dirty
);
933 Status
= STATUS_SUCCESS
;
935 if (!NT_SUCCESS(Status
))
937 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
938 KeBugCheck(MEMORY_MANAGEMENT
);
944 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
945 if (SavedSwapEntry
== 0)
948 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
949 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
953 * Try to page out this page and set the swap entry
954 * within the section segment. There exist no rmap entry
955 * for this page. The pager thread can't page out a
956 * page without a rmap entry.
958 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
959 if (InEntry
) *InEntry
= Entry
;
960 MiSetPageEvent(NULL
, NULL
);
964 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
965 if (InEntry
) *InEntry
= 0;
966 MiSetPageEvent(NULL
, NULL
);
969 MmReleasePageMemoryConsumer(MC_USER
, Page
);
975 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
976 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
984 * We hold all locks. Nobody can do something with the current
985 * process and the current segment (also not within an other process).
988 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
989 if (!NT_SUCCESS(Status
))
991 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
992 KeBugCheck(MEMORY_MANAGEMENT
);
995 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
996 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
997 MmSetSavedSwapEntryPage(Page
, 0);
998 MiSetPageEvent(NULL
, NULL
);
1000 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1004 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1005 KeBugCheck(MEMORY_MANAGEMENT
);
1014 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1016 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1019 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1023 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1025 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1027 SharedCacheMap
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1028 Vacb
= CcRosLookupVacb(SharedCacheMap
, (ULONG
)(SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
));
1031 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, FALSE
, TRUE
);
1041 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1045 PVOID DestAddress
, SrcAddress
;
1047 Process
= PsGetCurrentProcess();
1048 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1049 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1050 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1052 return(STATUS_NO_MEMORY
);
1054 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1055 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1056 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1057 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1058 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1059 return(STATUS_SUCCESS
);
1065 MiReadPage(PMEMORY_AREA MemoryArea
,
1066 ULONG_PTR SegOffset
,
1069 * FUNCTION: Read a page for a section backed memory area.
1071 * MemoryArea - Memory area to read the page for.
1072 * Offset - Offset of the page to read.
1073 * Page - Variable that receives a page contains the read data.
1076 ULONGLONG BaseOffset
;
1077 ULONGLONG FileOffset
;
1081 PFILE_OBJECT FileObject
;
1083 ULONG_PTR RawLength
;
1084 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1085 BOOLEAN IsImageSection
;
1088 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1089 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1090 RawLength
= (ULONG_PTR
)(MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
);
1091 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1092 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1094 ASSERT(SharedCacheMap
);
1096 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1099 * If the file system is letting us go directly to the cache and the
1100 * memory area was mapped at an offset in the file which is page aligned
1101 * then get the related VACB.
1103 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1104 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1105 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1109 * Get the related VACB; we use a lower level interface than
1110 * filesystems do because it is safe for us to use an offset with an
1111 * alignment less than the file system block size.
1113 Status
= CcRosGetVacb(SharedCacheMap
,
1119 if (!NT_SUCCESS(Status
))
1126 * If the VACB isn't up to date then call the file
1127 * system to read in the data.
1129 Status
= CcReadVirtualAddress(Vacb
);
1130 if (!NT_SUCCESS(Status
))
1132 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1137 /* Probe the page, since it's PDE might not be synced */
1138 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1141 * Retrieve the page from the view that we actually want.
1143 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1144 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1146 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, TRUE
);
1153 ULONG_PTR VacbOffset
;
1156 * Allocate a page, this is rather complicated by the possibility
1157 * we might have to move other things out of memory
1159 MI_SET_USAGE(MI_USAGE_SECTION
);
1160 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1161 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1162 if (!NT_SUCCESS(Status
))
1166 Status
= CcRosGetVacb(SharedCacheMap
,
1172 if (!NT_SUCCESS(Status
))
1179 * If the VACB isn't up to date then call the file
1180 * system to read in the data.
1182 Status
= CcReadVirtualAddress(Vacb
);
1183 if (!NT_SUCCESS(Status
))
1185 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1190 Process
= PsGetCurrentProcess();
1191 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1192 VacbOffset
= (ULONG_PTR
)(BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
);
1193 Length
= RawLength
- SegOffset
;
1194 if (Length
<= VacbOffset
&& Length
<= PAGE_SIZE
)
1196 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1198 else if (VacbOffset
>= PAGE_SIZE
)
1200 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1204 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, VacbOffset
);
1205 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1206 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1207 Status
= CcRosGetVacb(SharedCacheMap
,
1208 (ULONG
)(FileOffset
+ VacbOffset
),
1213 if (!NT_SUCCESS(Status
))
1220 * If the VACB isn't up to date then call the file
1221 * system to read in the data.
1223 Status
= CcReadVirtualAddress(Vacb
);
1224 if (!NT_SUCCESS(Status
))
1226 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1230 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1231 if (Length
< PAGE_SIZE
)
1233 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, Length
- VacbOffset
);
1237 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, PAGE_SIZE
- VacbOffset
);
1240 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1241 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1243 return(STATUS_SUCCESS
);
1248 MiReadPage(PMEMORY_AREA MemoryArea
,
1249 ULONG_PTR SegOffset
,
1252 * FUNCTION: Read a page for a section backed memory area.
1254 * MemoryArea - Memory area to read the page for.
1255 * Offset - Offset of the page to read.
1256 * Page - Variable that receives a page contains the read data.
1259 MM_REQUIRED_RESOURCES Resources
;
1262 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1264 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1265 Resources
.FileOffset
.QuadPart
= SegOffset
+
1266 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1267 Resources
.Consumer
= MC_USER
;
1268 Resources
.Amount
= PAGE_SIZE
;
1270 DPRINT("%S, offset 0x%x, len 0x%x, page 0x%x\n", ((PFILE_OBJECT
)Resources
.Context
)->FileName
.Buffer
, Resources
.FileOffset
.LowPart
, Resources
.Amount
, Resources
.Page
[0]);
1272 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1273 *Page
= Resources
.Page
[0];
1280 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1281 MEMORY_AREA
* MemoryArea
,
1285 LARGE_INTEGER Offset
;
1288 PROS_SECTION_OBJECT Section
;
1289 PMM_SECTION_SEGMENT Segment
;
1294 BOOLEAN HasSwapEntry
;
1296 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1297 SWAPENTRY SwapEntry
;
1300 * There is a window between taking the page fault and locking the
1301 * address space when another thread could load the page so we check
1304 if (MmIsPagePresent(Process
, Address
))
1306 return(STATUS_SUCCESS
);
1309 if (MmIsDisabledPage(Process
, Address
))
1311 return(STATUS_ACCESS_VIOLATION
);
1315 * Check for the virtual memory area being deleted.
1317 if (MemoryArea
->DeleteInProgress
)
1319 return(STATUS_UNSUCCESSFUL
);
1322 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1323 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1324 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1326 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1327 Section
= MemoryArea
->Data
.SectionData
.Section
;
1328 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1329 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1331 ASSERT(Region
!= NULL
);
1335 MmLockSectionSegment(Segment
);
1336 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1338 * Check if this page needs to be mapped COW
1340 if ((Segment
->WriteCopy
) &&
1341 (Region
->Protect
== PAGE_READWRITE
||
1342 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1344 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1348 Attributes
= Region
->Protect
;
1352 * Check if someone else is already handling this fault, if so wait
1355 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1357 MmUnlockSectionSegment(Segment
);
1358 MmUnlockAddressSpace(AddressSpace
);
1359 MiWaitForPageEvent(NULL
, NULL
);
1360 MmLockAddressSpace(AddressSpace
);
1361 DPRINT("Address 0x%p\n", Address
);
1362 return(STATUS_MM_RESTART_OPERATION
);
1365 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1369 SWAPENTRY DummyEntry
;
1372 * Is it a wait entry?
1374 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1376 if (SwapEntry
== MM_WAIT_ENTRY
)
1378 MmUnlockSectionSegment(Segment
);
1379 MmUnlockAddressSpace(AddressSpace
);
1380 MiWaitForPageEvent(NULL
, NULL
);
1381 MmLockAddressSpace(AddressSpace
);
1382 return STATUS_MM_RESTART_OPERATION
;
1386 * Must be private page we have swapped out.
1392 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1394 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1395 KeBugCheck(MEMORY_MANAGEMENT
);
1398 MmUnlockSectionSegment(Segment
);
1399 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1400 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1402 MmUnlockAddressSpace(AddressSpace
);
1403 MI_SET_USAGE(MI_USAGE_SECTION
);
1404 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1405 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1406 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1407 if (!NT_SUCCESS(Status
))
1409 KeBugCheck(MEMORY_MANAGEMENT
);
1412 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1413 if (!NT_SUCCESS(Status
))
1415 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1416 KeBugCheck(MEMORY_MANAGEMENT
);
1418 MmLockAddressSpace(AddressSpace
);
1419 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1420 Status
= MmCreateVirtualMapping(Process
,
1425 if (!NT_SUCCESS(Status
))
1427 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1428 KeBugCheck(MEMORY_MANAGEMENT
);
1433 * Store the swap entry for later use.
1435 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1438 * Add the page to the process's working set
1440 MmInsertRmap(Page
, Process
, Address
);
1442 * Finish the operation
1444 MiSetPageEvent(Process
, Address
);
1445 DPRINT("Address 0x%p\n", Address
);
1446 return(STATUS_SUCCESS
);
1450 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1452 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1454 MmUnlockSectionSegment(Segment
);
1456 * Just map the desired physical page
1458 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1459 Status
= MmCreateVirtualMappingUnsafe(Process
,
1464 if (!NT_SUCCESS(Status
))
1466 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1467 KeBugCheck(MEMORY_MANAGEMENT
);
1472 * Cleanup and release locks
1474 MiSetPageEvent(Process
, Address
);
1475 DPRINT("Address 0x%p\n", Address
);
1476 return(STATUS_SUCCESS
);
1480 * Get the entry corresponding to the offset within the section
1482 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1486 SWAPENTRY FakeSwapEntry
;
1489 * If the entry is zero (and it can't change because we have
1490 * locked the segment) then we need to load the page.
1494 * Release all our locks and read in the page from disk
1496 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1497 MmUnlockSectionSegment(Segment
);
1498 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1499 MmUnlockAddressSpace(AddressSpace
);
1501 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1502 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1503 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1505 MI_SET_USAGE(MI_USAGE_SECTION
);
1506 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1507 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1508 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1509 if (!NT_SUCCESS(Status
))
1511 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1517 Status
= MiReadPage(MemoryArea
, (ULONG_PTR
)Offset
.QuadPart
, &Page
);
1518 if (!NT_SUCCESS(Status
))
1520 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1523 if (!NT_SUCCESS(Status
))
1526 * FIXME: What do we know in this case?
1529 * Cleanup and release locks
1531 MmLockAddressSpace(AddressSpace
);
1532 MiSetPageEvent(Process
, Address
);
1533 DPRINT("Address 0x%p\n", Address
);
1538 * Mark the offset within the section as having valid, in-memory
1541 MmLockAddressSpace(AddressSpace
);
1542 MmLockSectionSegment(Segment
);
1543 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1544 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1545 MmUnlockSectionSegment(Segment
);
1547 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1548 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1549 Page
, Process
, PAddress
, Attributes
);
1550 Status
= MmCreateVirtualMapping(Process
,
1555 if (!NT_SUCCESS(Status
))
1557 DPRINT1("Unable to create virtual mapping\n");
1558 KeBugCheck(MEMORY_MANAGEMENT
);
1560 ASSERT(MmIsPagePresent(Process
, PAddress
));
1561 MmInsertRmap(Page
, Process
, Address
);
1563 MiSetPageEvent(Process
, Address
);
1564 DPRINT("Address 0x%p\n", Address
);
1565 return(STATUS_SUCCESS
);
1567 else if (IS_SWAP_FROM_SSE(Entry
))
1569 SWAPENTRY SwapEntry
;
1571 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1574 * Release all our locks and read in the page from disk
1576 MmUnlockSectionSegment(Segment
);
1578 MmUnlockAddressSpace(AddressSpace
);
1579 MI_SET_USAGE(MI_USAGE_SECTION
);
1580 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1581 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1582 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1583 if (!NT_SUCCESS(Status
))
1585 KeBugCheck(MEMORY_MANAGEMENT
);
1588 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1589 if (!NT_SUCCESS(Status
))
1591 KeBugCheck(MEMORY_MANAGEMENT
);
1595 * Relock the address space and segment
1597 MmLockAddressSpace(AddressSpace
);
1598 MmLockSectionSegment(Segment
);
1601 * Check the entry. No one should change the status of a page
1602 * that has a pending page-in.
1604 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1605 if (Entry
!= Entry1
)
1607 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1608 KeBugCheck(MEMORY_MANAGEMENT
);
1612 * Mark the offset within the section as having valid, in-memory
1615 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1616 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1617 MmUnlockSectionSegment(Segment
);
1620 * Save the swap entry.
1622 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1623 Status
= MmCreateVirtualMapping(Process
,
1628 if (!NT_SUCCESS(Status
))
1630 DPRINT1("Unable to create virtual mapping\n");
1631 KeBugCheck(MEMORY_MANAGEMENT
);
1633 MmInsertRmap(Page
, Process
, Address
);
1634 MiSetPageEvent(Process
, Address
);
1635 DPRINT("Address 0x%p\n", Address
);
1636 return(STATUS_SUCCESS
);
1641 * If the section offset is already in-memory and valid then just
1642 * take another reference to the page
1645 Page
= PFN_FROM_SSE(Entry
);
1647 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1648 MmUnlockSectionSegment(Segment
);
1650 Status
= MmCreateVirtualMapping(Process
,
1655 if (!NT_SUCCESS(Status
))
1657 DPRINT1("Unable to create virtual mapping\n");
1658 KeBugCheck(MEMORY_MANAGEMENT
);
1660 MmInsertRmap(Page
, Process
, Address
);
1661 MiSetPageEvent(Process
, Address
);
1662 DPRINT("Address 0x%p\n", Address
);
1663 return(STATUS_SUCCESS
);
1669 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1670 MEMORY_AREA
* MemoryArea
,
1673 PMM_SECTION_SEGMENT Segment
;
1674 PROS_SECTION_OBJECT Section
;
1679 LARGE_INTEGER Offset
;
1682 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1683 SWAPENTRY SwapEntry
;
1685 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1688 * Check if the page has already been set readwrite
1690 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1692 DPRINT("Address 0x%p\n", Address
);
1693 return(STATUS_SUCCESS
);
1697 * Find the offset of the page
1699 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1700 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1701 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1703 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1704 Section
= MemoryArea
->Data
.SectionData
.Section
;
1705 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1706 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1708 ASSERT(Region
!= NULL
);
1712 MmLockSectionSegment(Segment
);
1714 OldPage
= MmGetPfnForProcess(Process
, Address
);
1715 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1717 MmUnlockSectionSegment(Segment
);
1720 * Check if we are doing COW
1722 if (!((Segment
->WriteCopy
) &&
1723 (Region
->Protect
== PAGE_READWRITE
||
1724 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1726 DPRINT("Address 0x%p\n", Address
);
1727 return(STATUS_ACCESS_VIOLATION
);
1730 if (IS_SWAP_FROM_SSE(Entry
) ||
1731 PFN_FROM_SSE(Entry
) != OldPage
)
1733 /* This is a private page. We must only change the page protection. */
1734 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1735 return(STATUS_SUCCESS
);
1739 DPRINT("OldPage == 0!\n");
1742 * Get or create a pageop
1744 MmLockSectionSegment(Segment
);
1745 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1748 * Wait for any other operations to complete
1750 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1752 MmUnlockSectionSegment(Segment
);
1753 MmUnlockAddressSpace(AddressSpace
);
1754 MiWaitForPageEvent(NULL
, NULL
);
1756 * Restart the operation
1758 MmLockAddressSpace(AddressSpace
);
1759 DPRINT("Address 0x%p\n", Address
);
1760 return(STATUS_MM_RESTART_OPERATION
);
1763 MmDeleteRmap(OldPage
, Process
, PAddress
);
1764 MmDeleteVirtualMapping(Process
, PAddress
, FALSE
, NULL
, NULL
);
1765 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1768 * Release locks now we have the pageop
1770 MmUnlockSectionSegment(Segment
);
1771 MmUnlockAddressSpace(AddressSpace
);
1776 MI_SET_USAGE(MI_USAGE_SECTION
);
1777 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1778 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1779 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1780 if (!NT_SUCCESS(Status
))
1782 KeBugCheck(MEMORY_MANAGEMENT
);
1788 MiCopyFromUserPage(NewPage
, OldPage
);
1790 MmLockAddressSpace(AddressSpace
);
1793 * Set the PTE to point to the new page
1795 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1796 Status
= MmCreateVirtualMapping(Process
,
1801 if (!NT_SUCCESS(Status
))
1803 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1804 KeBugCheck(MEMORY_MANAGEMENT
);
1809 * Unshare the old page.
1811 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1812 MmInsertRmap(NewPage
, Process
, PAddress
);
1813 MmLockSectionSegment(Segment
);
1814 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1815 MmUnlockSectionSegment(Segment
);
1817 MiSetPageEvent(Process
, Address
);
1818 DPRINT("Address 0x%p\n", Address
);
1819 return(STATUS_SUCCESS
);
1823 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1825 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1827 PFN_NUMBER Page
= 0;
1829 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1832 MmLockAddressSpace(&Process
->Vm
);
1835 MmDeleteVirtualMapping(Process
,
1842 PageOutContext
->WasDirty
= TRUE
;
1844 if (!PageOutContext
->Private
)
1846 MmLockSectionSegment(PageOutContext
->Segment
);
1847 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1848 PageOutContext
->Segment
,
1849 &PageOutContext
->Offset
,
1850 PageOutContext
->WasDirty
,
1852 &PageOutContext
->SectionEntry
);
1853 MmUnlockSectionSegment(PageOutContext
->Segment
);
1857 MmUnlockAddressSpace(&Process
->Vm
);
1860 if (PageOutContext
->Private
)
1862 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1868 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1869 MEMORY_AREA
* MemoryArea
,
1870 PVOID Address
, ULONG_PTR Entry
)
1873 MM_SECTION_PAGEOUT_CONTEXT Context
;
1874 SWAPENTRY SwapEntry
;
1875 ULONGLONG FileOffset
;
1877 PFILE_OBJECT FileObject
;
1879 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1881 BOOLEAN DirectMapped
;
1882 BOOLEAN IsImageSection
;
1883 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1886 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1889 * Get the segment and section.
1891 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1892 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1893 Context
.SectionEntry
= Entry
;
1894 Context
.CallingProcess
= Process
;
1896 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1897 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1898 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1900 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1902 FileObject
= Context
.Section
->FileObject
;
1903 DirectMapped
= FALSE
;
1905 MmLockSectionSegment(Context
.Segment
);
1908 if (FileObject
!= NULL
&&
1909 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1911 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1914 * If the file system is letting us go directly to the cache and the
1915 * memory area was mapped at an offset in the file which is page aligned
1916 * then note this is a direct mapped page.
1918 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1919 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1921 DirectMapped
= TRUE
;
1928 * This should never happen since mappings of physical memory are never
1929 * placed in the rmap lists.
1931 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1933 DPRINT1("Trying to page out from physical memory section address 0x%p "
1934 "process %p\n", Address
,
1935 Process
? Process
->UniqueProcessId
: 0);
1936 KeBugCheck(MEMORY_MANAGEMENT
);
1940 * Get the section segment entry and the physical address.
1942 if (!MmIsPagePresent(Process
, Address
))
1944 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1945 Process
? Process
->UniqueProcessId
: 0, Address
);
1946 KeBugCheck(MEMORY_MANAGEMENT
);
1948 Page
= MmGetPfnForProcess(Process
, Address
);
1949 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1952 * Check the reference count to ensure this page can be paged out
1954 if (MmGetReferenceCountPage(Page
) != 1)
1956 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1957 Page
, MmGetReferenceCountPage(Page
));
1958 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1959 MmUnlockSectionSegment(Context
.Segment
);
1960 return STATUS_UNSUCCESSFUL
;
1964 * Prepare the context structure for the rmap delete call.
1966 MmUnlockSectionSegment(Context
.Segment
);
1967 Context
.WasDirty
= FALSE
;
1968 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1969 IS_SWAP_FROM_SSE(Entry
) ||
1970 PFN_FROM_SSE(Entry
) != Page
)
1972 Context
.Private
= TRUE
;
1976 Context
.Private
= FALSE
;
1980 * Take an additional reference to the page or the VACB.
1982 if (DirectMapped
&& !Context
.Private
)
1984 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
1986 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1987 KeBugCheck(MEMORY_MANAGEMENT
);
1992 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1993 MmReferencePage(Page
);
1994 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1997 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1999 /* Since we passed in a surrogate, we'll get back the page entry
2000 * state in our context. This is intended to make intermediate
2001 * decrements of share count not release the wait entry.
2003 Entry
= Context
.SectionEntry
;
2006 * If this wasn't a private page then we should have reduced the entry to
2007 * zero by deleting all the rmaps.
2009 if (!Context
.Private
&& Entry
!= 0)
2011 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2012 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2014 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2019 * If the page wasn't dirty then we can just free it as for a readonly page.
2020 * Since we unmapped all the mappings above we know it will not suddenly
2022 * If the page is from a pagefile section and has no swap entry,
2023 * we can't free the page at this point.
2025 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2026 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2028 if (Context
.Private
)
2030 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2031 Context
.WasDirty
? "dirty" : "clean", Address
);
2032 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2034 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2036 MmSetSavedSwapEntryPage(Page
, 0);
2037 MmLockSectionSegment(Context
.Segment
);
2038 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2039 MmUnlockSectionSegment(Context
.Segment
);
2040 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2041 MiSetPageEvent(NULL
, NULL
);
2042 return(STATUS_SUCCESS
);
2045 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2047 if (Context
.Private
)
2049 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2050 Context
.WasDirty
? "dirty" : "clean", Address
);
2051 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2053 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2055 MmSetSavedSwapEntryPage(Page
, 0);
2058 MmLockSectionSegment(Context
.Segment
);
2059 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2060 MmUnlockSectionSegment(Context
.Segment
);
2062 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2063 MiSetPageEvent(NULL
, NULL
);
2064 return(STATUS_SUCCESS
);
2067 else if (!Context
.Private
&& DirectMapped
)
2071 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2073 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2076 Status
= CcRosUnmapVacb(SharedCacheMap
, (ULONG
)FileOffset
, FALSE
);
2078 Status
= STATUS_SUCCESS
;
2081 if (!NT_SUCCESS(Status
))
2083 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2084 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2087 MiSetPageEvent(NULL
, NULL
);
2088 return(STATUS_SUCCESS
);
2090 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2094 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2096 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2098 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2099 MiSetPageEvent(NULL
, NULL
);
2100 return(STATUS_SUCCESS
);
2102 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2104 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2105 MmSetSavedSwapEntryPage(Page
, 0);
2106 MmLockAddressSpace(AddressSpace
);
2107 Status
= MmCreatePageFileMapping(Process
,
2110 MmUnlockAddressSpace(AddressSpace
);
2111 if (!NT_SUCCESS(Status
))
2113 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2114 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2116 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2117 MiSetPageEvent(NULL
, NULL
);
2118 return(STATUS_SUCCESS
);
2122 * If necessary, allocate an entry in the paging file for this page
2126 SwapEntry
= MmAllocSwapPage();
2129 MmShowOutOfSpaceMessagePagingFile();
2130 MmLockAddressSpace(AddressSpace
);
2132 * For private pages restore the old mappings.
2134 if (Context
.Private
)
2136 Status
= MmCreateVirtualMapping(Process
,
2138 MemoryArea
->Protect
,
2141 MmSetDirtyPage(Process
, Address
);
2150 * For non-private pages if the page wasn't direct mapped then
2151 * set it back into the section segment entry so we don't loose
2152 * our copy. Otherwise it will be handled by the cache manager.
2154 Status
= MmCreateVirtualMapping(Process
,
2156 MemoryArea
->Protect
,
2159 MmSetDirtyPage(Process
, Address
);
2163 // If we got here, the previous entry should have been a wait
2164 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2165 MmLockSectionSegment(Context
.Segment
);
2166 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2167 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2168 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2169 MmUnlockSectionSegment(Context
.Segment
);
2171 MmUnlockAddressSpace(AddressSpace
);
2172 MiSetPageEvent(NULL
, NULL
);
2173 return(STATUS_PAGEFILE_QUOTA
);
2178 * Write the page to the pagefile
2180 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2181 if (!NT_SUCCESS(Status
))
2183 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2186 * As above: undo our actions.
2187 * FIXME: Also free the swap page.
2189 MmLockAddressSpace(AddressSpace
);
2190 if (Context
.Private
)
2192 Status
= MmCreateVirtualMapping(Process
,
2194 MemoryArea
->Protect
,
2197 MmSetDirtyPage(Process
, Address
);
2204 Status
= MmCreateVirtualMapping(Process
,
2206 MemoryArea
->Protect
,
2209 MmSetDirtyPage(Process
, Address
);
2213 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2214 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2216 MmUnlockAddressSpace(AddressSpace
);
2217 MiSetPageEvent(NULL
, NULL
);
2218 return(STATUS_UNSUCCESSFUL
);
2222 * Otherwise we have succeeded.
2224 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2225 MmSetSavedSwapEntryPage(Page
, 0);
2226 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2227 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2229 MmLockSectionSegment(Context
.Segment
);
2230 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2231 MmUnlockSectionSegment(Context
.Segment
);
2235 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2238 if (Context
.Private
)
2240 MmLockAddressSpace(AddressSpace
);
2241 MmLockSectionSegment(Context
.Segment
);
2242 Status
= MmCreatePageFileMapping(Process
,
2245 /* We had placed a wait entry upon entry ... replace it before leaving */
2246 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2247 MmUnlockSectionSegment(Context
.Segment
);
2248 MmUnlockAddressSpace(AddressSpace
);
2249 if (!NT_SUCCESS(Status
))
2251 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2252 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2257 MmLockAddressSpace(AddressSpace
);
2258 MmLockSectionSegment(Context
.Segment
);
2259 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2260 /* We had placed a wait entry upon entry ... replace it before leaving */
2261 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2262 MmUnlockSectionSegment(Context
.Segment
);
2263 MmUnlockAddressSpace(AddressSpace
);
2266 MiSetPageEvent(NULL
, NULL
);
2267 return(STATUS_SUCCESS
);
2272 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2273 PMEMORY_AREA MemoryArea
,
2277 LARGE_INTEGER Offset
;
2278 PROS_SECTION_OBJECT Section
;
2279 PMM_SECTION_SEGMENT Segment
;
2281 SWAPENTRY SwapEntry
;
2285 PFILE_OBJECT FileObject
;
2286 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2287 BOOLEAN DirectMapped
;
2288 BOOLEAN IsImageSection
;
2289 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2291 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2293 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2294 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2297 * Get the segment and section.
2299 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2300 Section
= MemoryArea
->Data
.SectionData
.Section
;
2301 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2303 FileObject
= Section
->FileObject
;
2304 DirectMapped
= FALSE
;
2305 if (FileObject
!= NULL
&&
2306 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2308 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2311 * If the file system is letting us go directly to the cache and the
2312 * memory area was mapped at an offset in the file which is page aligned
2313 * then note this is a direct mapped page.
2315 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2316 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2318 DirectMapped
= TRUE
;
2323 * This should never happen since mappings of physical memory are never
2324 * placed in the rmap lists.
2326 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2328 DPRINT1("Trying to write back page from physical memory mapped at %p "
2329 "process %p\n", Address
,
2330 Process
? Process
->UniqueProcessId
: 0);
2331 KeBugCheck(MEMORY_MANAGEMENT
);
2335 * Get the section segment entry and the physical address.
2337 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2338 if (!MmIsPagePresent(Process
, Address
))
2340 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2341 Process
? Process
->UniqueProcessId
: 0, Address
);
2342 KeBugCheck(MEMORY_MANAGEMENT
);
2344 Page
= MmGetPfnForProcess(Process
, Address
);
2345 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2348 * Check for a private (COWed) page.
2350 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2351 IS_SWAP_FROM_SSE(Entry
) ||
2352 PFN_FROM_SSE(Entry
) != Page
)
2362 * Speculatively set all mappings of the page to clean.
2364 MmSetCleanAllRmaps(Page
);
2367 * If this page was direct mapped from the cache then the cache manager
2368 * will take care of writing it back to disk.
2370 if (DirectMapped
&& !Private
)
2372 //LARGE_INTEGER SOffset;
2373 ASSERT(SwapEntry
== 0);
2374 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2376 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.LowPart
);
2378 MmLockSectionSegment(Segment
);
2379 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2380 MmUnlockSectionSegment(Segment
);
2381 MiSetPageEvent(NULL
, NULL
);
2382 return(STATUS_SUCCESS
);
2386 * If necessary, allocate an entry in the paging file for this page
2390 SwapEntry
= MmAllocSwapPage();
2393 MmSetDirtyAllRmaps(Page
);
2394 MiSetPageEvent(NULL
, NULL
);
2395 return(STATUS_PAGEFILE_QUOTA
);
2397 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2401 * Write the page to the pagefile
2403 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2404 if (!NT_SUCCESS(Status
))
2406 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2408 MmSetDirtyAllRmaps(Page
);
2409 MiSetPageEvent(NULL
, NULL
);
2410 return(STATUS_UNSUCCESSFUL
);
2414 * Otherwise we have succeeded.
2416 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2417 MiSetPageEvent(NULL
, NULL
);
2418 return(STATUS_SUCCESS
);
2422 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2430 PMEMORY_AREA MemoryArea
;
2431 PMM_SECTION_SEGMENT Segment
;
2432 BOOLEAN DoCOW
= FALSE
;
2434 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2436 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2437 ASSERT(MemoryArea
!= NULL
);
2438 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2439 MmLockSectionSegment(Segment
);
2441 if ((Segment
->WriteCopy
) &&
2442 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2447 if (OldProtect
!= NewProtect
)
2449 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2451 SWAPENTRY SwapEntry
;
2452 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2453 ULONG Protect
= NewProtect
;
2455 /* Wait for a wait entry to disappear */
2457 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2458 if (SwapEntry
!= MM_WAIT_ENTRY
)
2460 MiWaitForPageEvent(Process
, Address
);
2464 * If we doing COW for this segment then check if the page is
2467 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2469 LARGE_INTEGER Offset
;
2473 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2474 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2475 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2477 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2478 * IS_SWAP_FROM_SSE and we'll do the right thing.
2480 Page
= MmGetPfnForProcess(Process
, Address
);
2482 Protect
= PAGE_READONLY
;
2483 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2484 IS_SWAP_FROM_SSE(Entry
) ||
2485 PFN_FROM_SSE(Entry
) != Page
)
2487 Protect
= NewProtect
;
2491 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2493 MmSetPageProtect(Process
, Address
,
2499 MmUnlockSectionSegment(Segment
);
2504 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2505 PMEMORY_AREA MemoryArea
,
2513 ULONG_PTR MaxLength
;
2515 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2516 if (Length
> MaxLength
)
2517 Length
= (ULONG
)MaxLength
;
2519 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2520 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2522 ASSERT(Region
!= NULL
);
2524 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2525 Region
->Protect
!= Protect
)
2527 return STATUS_INVALID_PAGE_PROTECTION
;
2530 *OldProtect
= Region
->Protect
;
2531 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2532 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2533 BaseAddress
, Length
, Region
->Type
, Protect
,
2534 MmAlterViewAttributes
);
2540 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2542 PMEMORY_BASIC_INFORMATION Info
,
2543 PSIZE_T ResultLength
)
2546 PVOID RegionBaseAddress
;
2547 PROS_SECTION_OBJECT Section
;
2548 PMM_SECTION_SEGMENT Segment
;
2550 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2551 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2552 Address
, &RegionBaseAddress
);
2555 return STATUS_UNSUCCESSFUL
;
2558 Section
= MemoryArea
->Data
.SectionData
.Section
;
2559 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2561 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2562 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2563 Info
->Type
= MEM_IMAGE
;
2567 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2568 Info
->Type
= MEM_MAPPED
;
2570 Info
->BaseAddress
= RegionBaseAddress
;
2571 Info
->AllocationProtect
= MemoryArea
->Protect
;
2572 Info
->RegionSize
= Region
->Length
;
2573 Info
->State
= MEM_COMMIT
;
2574 Info
->Protect
= Region
->Protect
;
2576 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2577 return(STATUS_SUCCESS
);
2582 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2585 LARGE_INTEGER Offset
;
2587 SWAPENTRY SavedSwapEntry
;
2592 MmLockSectionSegment(Segment
);
2594 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2595 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2597 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2600 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2601 if (IS_SWAP_FROM_SSE(Entry
))
2603 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2607 Page
= PFN_FROM_SSE(Entry
);
2608 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2609 if (SavedSwapEntry
!= 0)
2611 MmSetSavedSwapEntryPage(Page
, 0);
2612 MmFreeSwapPage(SavedSwapEntry
);
2614 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2619 MmUnlockSectionSegment(Segment
);
2623 MmpDeleteSection(PVOID ObjectBody
)
2625 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2627 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2628 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2633 PMM_SECTION_SEGMENT SectionSegments
;
2636 * NOTE: Section->ImageSection can be NULL for short time
2637 * during the section creating. If we fail for some reason
2638 * until the image section is properly initialized we shouldn't
2639 * process further here.
2641 if (Section
->ImageSection
== NULL
)
2644 SectionSegments
= Section
->ImageSection
->Segments
;
2645 NrSegments
= Section
->ImageSection
->NrSegments
;
2647 for (i
= 0; i
< NrSegments
; i
++)
2649 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2651 MmLockSectionSegment(&SectionSegments
[i
]);
2653 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2654 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2656 MmUnlockSectionSegment(&SectionSegments
[i
]);
2659 MmpFreePageFileSegment(&SectionSegments
[i
]);
2665 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2668 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2671 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2673 DPRINT("Freeing section segment\n");
2674 Section
->Segment
= NULL
;
2675 MmFinalizeSegment(Segment
);
2679 DPRINT("RefCount %d\n", RefCount
);
2686 * NOTE: Section->Segment can be NULL for short time
2687 * during the section creating.
2689 if (Section
->Segment
== NULL
)
2692 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2694 MmpFreePageFileSegment(Section
->Segment
);
2695 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2696 ExFreePool(Section
->Segment
);
2697 Section
->Segment
= NULL
;
2701 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2704 if (Section
->FileObject
!= NULL
)
2707 CcRosDereferenceCache(Section
->FileObject
);
2709 ObDereferenceObject(Section
->FileObject
);
2710 Section
->FileObject
= NULL
;
2715 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2717 IN ACCESS_MASK GrantedAccess
,
2718 IN ULONG ProcessHandleCount
,
2719 IN ULONG SystemHandleCount
)
2721 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2727 MmCreatePhysicalMemorySection(VOID
)
2729 PROS_SECTION_OBJECT PhysSection
;
2731 OBJECT_ATTRIBUTES Obj
;
2732 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2733 LARGE_INTEGER SectionSize
;
2737 * Create the section mapping physical memory
2739 SectionSize
.QuadPart
= 0xFFFFFFFF;
2740 InitializeObjectAttributes(&Obj
,
2745 Status
= MmCreateSection((PVOID
)&PhysSection
,
2749 PAGE_EXECUTE_READWRITE
,
2753 if (!NT_SUCCESS(Status
))
2755 DPRINT1("Failed to create PhysicalMemory section\n");
2756 KeBugCheck(MEMORY_MANAGEMENT
);
2758 Status
= ObInsertObject(PhysSection
,
2764 if (!NT_SUCCESS(Status
))
2766 ObDereferenceObject(PhysSection
);
2768 ObCloseHandle(Handle
, KernelMode
);
2769 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2770 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2772 return(STATUS_SUCCESS
);
2778 MmInitSectionImplementation(VOID
)
2780 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2781 UNICODE_STRING Name
;
2783 DPRINT("Creating Section Object Type\n");
2785 /* Initialize the section based root */
2786 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2787 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2789 /* Initialize the Section object type */
2790 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2791 RtlInitUnicodeString(&Name
, L
"Section");
2792 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2793 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2794 ObjectTypeInitializer
.PoolType
= PagedPool
;
2795 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2796 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2797 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2798 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2799 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2800 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2801 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2803 MmCreatePhysicalMemorySection();
2805 return(STATUS_SUCCESS
);
2810 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2811 ACCESS_MASK DesiredAccess
,
2812 POBJECT_ATTRIBUTES ObjectAttributes
,
2813 PLARGE_INTEGER UMaximumSize
,
2814 ULONG SectionPageProtection
,
2815 ULONG AllocationAttributes
)
2817 * Create a section which is backed by the pagefile
2820 LARGE_INTEGER MaximumSize
;
2821 PROS_SECTION_OBJECT Section
;
2822 PMM_SECTION_SEGMENT Segment
;
2825 if (UMaximumSize
== NULL
)
2827 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2828 return(STATUS_INVALID_PARAMETER
);
2830 MaximumSize
= *UMaximumSize
;
2833 * Create the section
2835 Status
= ObCreateObject(ExGetPreviousMode(),
2836 MmSectionObjectType
,
2838 ExGetPreviousMode(),
2840 sizeof(ROS_SECTION_OBJECT
),
2843 (PVOID
*)(PVOID
)&Section
);
2844 if (!NT_SUCCESS(Status
))
2846 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2853 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2854 Section
->Type
= 'SC';
2855 Section
->Size
= 'TN';
2856 Section
->SectionPageProtection
= SectionPageProtection
;
2857 Section
->AllocationAttributes
= AllocationAttributes
;
2858 Section
->MaximumSize
= MaximumSize
;
2859 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2860 TAG_MM_SECTION_SEGMENT
);
2861 if (Segment
== NULL
)
2863 ObDereferenceObject(Section
);
2864 return(STATUS_NO_MEMORY
);
2866 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2867 Section
->Segment
= Segment
;
2868 Segment
->ReferenceCount
= 1;
2869 ExInitializeFastMutex(&Segment
->Lock
);
2870 Segment
->Image
.FileOffset
= 0;
2871 Segment
->Protection
= SectionPageProtection
;
2872 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2873 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2874 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2875 Segment
->WriteCopy
= FALSE
;
2876 Segment
->Image
.VirtualAddress
= 0;
2877 Segment
->Image
.Characteristics
= 0;
2878 *SectionObject
= Section
;
2879 MiInitializeSectionPageTable(Segment
);
2880 return(STATUS_SUCCESS
);
2885 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2886 ACCESS_MASK DesiredAccess
,
2887 POBJECT_ATTRIBUTES ObjectAttributes
,
2888 PLARGE_INTEGER UMaximumSize
,
2889 ULONG SectionPageProtection
,
2890 ULONG AllocationAttributes
,
2893 * Create a section backed by a data file
2896 PROS_SECTION_OBJECT Section
;
2898 LARGE_INTEGER MaximumSize
;
2899 PFILE_OBJECT FileObject
;
2900 PMM_SECTION_SEGMENT Segment
;
2902 IO_STATUS_BLOCK Iosb
;
2903 LARGE_INTEGER Offset
;
2905 FILE_STANDARD_INFORMATION FileInfo
;
2909 * Create the section
2911 Status
= ObCreateObject(ExGetPreviousMode(),
2912 MmSectionObjectType
,
2914 ExGetPreviousMode(),
2916 sizeof(ROS_SECTION_OBJECT
),
2920 if (!NT_SUCCESS(Status
))
2927 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2928 Section
->Type
= 'SC';
2929 Section
->Size
= 'TN';
2930 Section
->SectionPageProtection
= SectionPageProtection
;
2931 Section
->AllocationAttributes
= AllocationAttributes
;
2934 * Reference the file handle
2936 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2937 Status
= ObReferenceObjectByHandle(FileHandle
,
2940 ExGetPreviousMode(),
2941 (PVOID
*)(PVOID
)&FileObject
,
2943 if (!NT_SUCCESS(Status
))
2945 ObDereferenceObject(Section
);
2950 * FIXME: This is propably not entirely correct. We can't look into
2951 * the standard FCB header because it might not be initialized yet
2952 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2953 * standard file information is filled on first request).
2955 Status
= IoQueryFileInformation(FileObject
,
2956 FileStandardInformation
,
2957 sizeof(FILE_STANDARD_INFORMATION
),
2960 Iosb
.Information
= Length
;
2961 if (!NT_SUCCESS(Status
))
2963 ObDereferenceObject(Section
);
2964 ObDereferenceObject(FileObject
);
2969 * FIXME: Revise this once a locking order for file size changes is
2972 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2974 MaximumSize
= *UMaximumSize
;
2978 MaximumSize
= FileInfo
.EndOfFile
;
2979 /* Mapping zero-sized files isn't allowed. */
2980 if (MaximumSize
.QuadPart
== 0)
2982 ObDereferenceObject(Section
);
2983 ObDereferenceObject(FileObject
);
2984 return STATUS_FILE_INVALID
;
2988 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2990 Status
= IoSetInformation(FileObject
,
2991 FileAllocationInformation
,
2992 sizeof(LARGE_INTEGER
),
2994 if (!NT_SUCCESS(Status
))
2996 ObDereferenceObject(Section
);
2997 ObDereferenceObject(FileObject
);
2998 return(STATUS_SECTION_NOT_EXTENDED
);
3002 if (FileObject
->SectionObjectPointer
== NULL
||
3003 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3006 * Read a bit so caching is initiated for the file object.
3007 * This is only needed because MiReadPage currently cannot
3008 * handle non-cached streams.
3010 Offset
.QuadPart
= 0;
3011 Status
= ZwReadFile(FileHandle
,
3020 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3022 ObDereferenceObject(Section
);
3023 ObDereferenceObject(FileObject
);
3026 if (FileObject
->SectionObjectPointer
== NULL
||
3027 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3029 /* FIXME: handle this situation */
3030 ObDereferenceObject(Section
);
3031 ObDereferenceObject(FileObject
);
3032 return STATUS_INVALID_PARAMETER
;
3039 Status
= MmspWaitForFileLock(FileObject
);
3040 if (Status
!= STATUS_SUCCESS
)
3042 ObDereferenceObject(Section
);
3043 ObDereferenceObject(FileObject
);
3048 * If this file hasn't been mapped as a data file before then allocate a
3049 * section segment to describe the data file mapping
3051 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3053 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3054 TAG_MM_SECTION_SEGMENT
);
3055 if (Segment
== NULL
)
3057 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3058 ObDereferenceObject(Section
);
3059 ObDereferenceObject(FileObject
);
3060 return(STATUS_NO_MEMORY
);
3062 Section
->Segment
= Segment
;
3063 Segment
->ReferenceCount
= 1;
3064 ExInitializeFastMutex(&Segment
->Lock
);
3066 * Set the lock before assigning the segment to the file object
3068 ExAcquireFastMutex(&Segment
->Lock
);
3069 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3071 Segment
->Image
.FileOffset
= 0;
3072 Segment
->Protection
= SectionPageProtection
;
3073 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3074 Segment
->Image
.Characteristics
= 0;
3075 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3076 if (AllocationAttributes
& SEC_RESERVE
)
3078 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3082 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3083 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3085 Segment
->Image
.VirtualAddress
= 0;
3086 Segment
->Locked
= TRUE
;
3087 MiInitializeSectionPageTable(Segment
);
3092 * If the file is already mapped as a data file then we may need
3096 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3098 Section
->Segment
= Segment
;
3099 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3100 MmLockSectionSegment(Segment
);
3102 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3103 !(AllocationAttributes
& SEC_RESERVE
))
3105 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3106 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3109 MmUnlockSectionSegment(Segment
);
3110 Section
->FileObject
= FileObject
;
3111 Section
->MaximumSize
= MaximumSize
;
3113 CcRosReferenceCache(FileObject
);
3115 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3116 *SectionObject
= Section
;
3117 return(STATUS_SUCCESS
);
3121 TODO: not that great (declaring loaders statically, having to declare all of
3122 them, having to keep them extern, etc.), will fix in the future
3124 extern NTSTATUS NTAPI PeFmtCreateSection
3126 IN CONST VOID
* FileHeader
,
3127 IN SIZE_T FileHeaderSize
,
3129 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3131 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3132 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3135 extern NTSTATUS NTAPI ElfFmtCreateSection
3137 IN CONST VOID
* FileHeader
,
3138 IN SIZE_T FileHeaderSize
,
3140 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3142 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3143 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3146 /* TODO: this is a standard DDK/PSDK macro */
3147 #ifndef RTL_NUMBER_OF
3148 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3151 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3162 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3164 SIZE_T SizeOfSegments
;
3165 PMM_SECTION_SEGMENT Segments
;
3167 /* TODO: check for integer overflow */
3168 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3170 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3172 TAG_MM_SECTION_SEGMENT
);
3175 RtlZeroMemory(Segments
, SizeOfSegments
);
3183 ExeFmtpReadFile(IN PVOID File
,
3184 IN PLARGE_INTEGER Offset
,
3187 OUT PVOID
* AllocBase
,
3188 OUT PULONG ReadSize
)
3191 LARGE_INTEGER FileOffset
;
3193 ULONG OffsetAdjustment
;
3197 PFILE_OBJECT FileObject
= File
;
3198 IO_STATUS_BLOCK Iosb
;
3200 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3204 KeBugCheck(MEMORY_MANAGEMENT
);
3207 FileOffset
= *Offset
;
3209 /* Negative/special offset: it cannot be used in this context */
3210 if(FileOffset
.u
.HighPart
< 0)
3212 KeBugCheck(MEMORY_MANAGEMENT
);
3215 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3216 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3217 FileOffset
.u
.LowPart
= AdjustOffset
;
3219 BufferSize
= Length
+ OffsetAdjustment
;
3220 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3223 * It's ok to use paged pool, because this is a temporary buffer only used in
3224 * the loading of executables. The assumption is that MmCreateSection is
3225 * always called at low IRQLs and that these buffers don't survive a brief
3226 * initialization phase
3228 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3233 KeBugCheck(MEMORY_MANAGEMENT
);
3238 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3240 UsedSize
= (ULONG
)Iosb
.Information
;
3242 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3244 Status
= STATUS_IN_PAGE_ERROR
;
3245 ASSERT(!NT_SUCCESS(Status
));
3248 if(NT_SUCCESS(Status
))
3250 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3251 *AllocBase
= Buffer
;
3252 *ReadSize
= UsedSize
- OffsetAdjustment
;
3256 ExFreePoolWithTag(Buffer
, 'rXmM');
3263 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3264 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3265 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3270 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3274 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3276 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3277 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3284 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3288 MmspAssertSegmentsSorted(ImageSectionObject
);
3290 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3292 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3296 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3297 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3298 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3306 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3310 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3312 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3313 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3321 MmspCompareSegments(const void * x
,
3324 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3325 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3328 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3329 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3333 * Ensures an image section's segments are sorted in memory
3338 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3341 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3343 MmspAssertSegmentsSorted(ImageSectionObject
);
3347 qsort(ImageSectionObject
->Segments
,
3348 ImageSectionObject
->NrSegments
,
3349 sizeof(ImageSectionObject
->Segments
[0]),
3350 MmspCompareSegments
);
3356 * Ensures an image section's segments don't overlap in memory and don't have
3357 * gaps and don't have a null size. We let them map to overlapping file regions,
3358 * though - that's not necessarily an error
3363 MmspCheckSegmentBounds
3365 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3371 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3373 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3377 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3379 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3381 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3389 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3390 * page could be OK (Windows seems to be OK with them), and larger gaps
3391 * could lead to image sections spanning several discontiguous regions
3392 * (NtMapViewOfSection could then refuse to map them, and they could
3393 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3395 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3396 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3397 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3408 * Merges and pads an image section's segments until they all are page-aligned
3409 * and have a size that is a multiple of the page size
3414 MmspPageAlignSegments
3416 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3422 PMM_SECTION_SEGMENT EffectiveSegment
;
3424 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3426 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3431 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3433 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3436 * The first segment requires special handling
3440 ULONG_PTR VirtualAddress
;
3441 ULONG_PTR VirtualOffset
;
3443 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3445 /* Round down the virtual address to the nearest page */
3446 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3448 /* Round up the virtual size to the nearest page */
3449 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3450 EffectiveSegment
->Image
.VirtualAddress
;
3452 /* Adjust the raw address and size */
3453 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3455 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3461 * Garbage in, garbage out: unaligned base addresses make the file
3462 * offset point in curious and odd places, but that's what we were
3465 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3466 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3470 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3471 ULONG_PTR EndOfEffectiveSegment
;
3473 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3474 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3477 * The current segment begins exactly where the current effective
3478 * segment ended, therefore beginning a new effective segment
3480 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3483 ASSERT(LastSegment
<= i
);
3484 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3486 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3488 if (LastSegment
!= i
)
3491 * Copy the current segment. If necessary, the effective segment
3492 * will be expanded later
3494 *EffectiveSegment
= *Segment
;
3498 * Page-align the virtual size. We know for sure the virtual address
3501 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3502 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3505 * The current segment is still part of the current effective segment:
3506 * extend the effective segment to reflect this
3508 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3510 static const ULONG FlagsToProtection
[16] =
3518 PAGE_EXECUTE_READWRITE
,
3519 PAGE_EXECUTE_READWRITE
,
3524 PAGE_EXECUTE_WRITECOPY
,
3525 PAGE_EXECUTE_WRITECOPY
,
3526 PAGE_EXECUTE_WRITECOPY
,
3527 PAGE_EXECUTE_WRITECOPY
3530 unsigned ProtectionFlags
;
3533 * Extend the file size
3536 /* Unaligned segments must be contiguous within the file */
3537 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3538 EffectiveSegment
->RawLength
.QuadPart
))
3543 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3546 * Extend the virtual size
3548 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3550 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3551 EffectiveSegment
->Image
.VirtualAddress
;
3554 * Merge the protection
3556 EffectiveSegment
->Protection
|= Segment
->Protection
;
3558 /* Clean up redundance */
3559 ProtectionFlags
= 0;
3561 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3562 ProtectionFlags
|= 1 << 0;
3564 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3565 ProtectionFlags
|= 1 << 1;
3567 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3568 ProtectionFlags
|= 1 << 2;
3570 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3571 ProtectionFlags
|= 1 << 3;
3573 ASSERT(ProtectionFlags
< 16);
3574 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3576 /* If a segment was required to be shared and cannot, fail */
3577 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3578 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3584 * We assume no holes between segments at this point
3588 KeBugCheck(MEMORY_MANAGEMENT
);
3592 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3598 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3599 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3601 LARGE_INTEGER Offset
;
3603 PVOID FileHeaderBuffer
;
3604 ULONG FileHeaderSize
;
3606 ULONG OldNrSegments
;
3611 * Read the beginning of the file (2 pages). Should be enough to contain
3612 * all (or most) of the headers
3614 Offset
.QuadPart
= 0;
3616 /* FIXME: use FileObject instead of FileHandle */
3617 Status
= ExeFmtpReadFile (FileHandle
,
3624 if (!NT_SUCCESS(Status
))
3627 if (FileHeaderSize
== 0)
3629 ExFreePool(FileHeaderBuffer
);
3630 return STATUS_UNSUCCESSFUL
;
3634 * Look for a loader that can handle this executable
3636 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3638 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3641 /* FIXME: use FileObject instead of FileHandle */
3642 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3648 ExeFmtpAllocateSegments
);
3650 if (!NT_SUCCESS(Status
))
3652 if (ImageSectionObject
->Segments
)
3654 ExFreePool(ImageSectionObject
->Segments
);
3655 ImageSectionObject
->Segments
= NULL
;
3659 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3663 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3666 * No loader handled the format
3668 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3670 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3671 ASSERT(!NT_SUCCESS(Status
));
3674 if (!NT_SUCCESS(Status
))
3677 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3682 /* FIXME? are these values platform-dependent? */
3683 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3684 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3686 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3687 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3689 if(ImageSectionObject
->BasedAddress
== NULL
)
3691 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3692 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3694 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3698 * And now the fun part: fixing the segments
3701 /* Sort them by virtual address */
3702 MmspSortSegments(ImageSectionObject
, Flags
);
3704 /* Ensure they don't overlap in memory */
3705 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3706 return STATUS_INVALID_IMAGE_FORMAT
;
3708 /* Ensure they are aligned */
3709 OldNrSegments
= ImageSectionObject
->NrSegments
;
3711 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3712 return STATUS_INVALID_IMAGE_FORMAT
;
3714 /* Trim them if the alignment phase merged some of them */
3715 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3717 PMM_SECTION_SEGMENT Segments
;
3718 SIZE_T SizeOfSegments
;
3720 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3722 Segments
= ExAllocatePoolWithTag(PagedPool
,
3724 TAG_MM_SECTION_SEGMENT
);
3726 if (Segments
== NULL
)
3727 return STATUS_INSUFFICIENT_RESOURCES
;
3729 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3730 ExFreePool(ImageSectionObject
->Segments
);
3731 ImageSectionObject
->Segments
= Segments
;
3734 /* And finish their initialization */
3735 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3737 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3738 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3739 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3742 ASSERT(NT_SUCCESS(Status
));
3747 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3748 ACCESS_MASK DesiredAccess
,
3749 POBJECT_ATTRIBUTES ObjectAttributes
,
3750 PLARGE_INTEGER UMaximumSize
,
3751 ULONG SectionPageProtection
,
3752 ULONG AllocationAttributes
,
3753 PFILE_OBJECT FileObject
)
3755 PROS_SECTION_OBJECT Section
;
3757 PMM_SECTION_SEGMENT SectionSegments
;
3758 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3761 if (FileObject
== NULL
)
3762 return STATUS_INVALID_FILE_FOR_SECTION
;
3765 * Create the section
3767 Status
= ObCreateObject (ExGetPreviousMode(),
3768 MmSectionObjectType
,
3770 ExGetPreviousMode(),
3772 sizeof(ROS_SECTION_OBJECT
),
3775 (PVOID
*)(PVOID
)&Section
);
3776 if (!NT_SUCCESS(Status
))
3778 ObDereferenceObject(FileObject
);
3785 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3786 Section
->Type
= 'SC';
3787 Section
->Size
= 'TN';
3788 Section
->SectionPageProtection
= SectionPageProtection
;
3789 Section
->AllocationAttributes
= AllocationAttributes
;
3793 * Initialized caching for this file object if previously caching
3794 * was initialized for the same on disk file
3796 Status
= CcTryToInitializeFileCache(FileObject
);
3798 Status
= STATUS_SUCCESS
;
3801 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3803 NTSTATUS StatusExeFmt
;
3805 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3806 if (ImageSectionObject
== NULL
)
3808 ObDereferenceObject(FileObject
);
3809 ObDereferenceObject(Section
);
3810 return(STATUS_NO_MEMORY
);
3813 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3815 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3817 if (!NT_SUCCESS(StatusExeFmt
))
3819 if(ImageSectionObject
->Segments
!= NULL
)
3820 ExFreePool(ImageSectionObject
->Segments
);
3822 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3823 ObDereferenceObject(Section
);
3824 ObDereferenceObject(FileObject
);
3825 return(StatusExeFmt
);
3828 Section
->ImageSection
= ImageSectionObject
;
3829 ASSERT(ImageSectionObject
->Segments
);
3834 Status
= MmspWaitForFileLock(FileObject
);
3835 if (!NT_SUCCESS(Status
))
3837 ExFreePool(ImageSectionObject
->Segments
);
3838 ExFreePool(ImageSectionObject
);
3839 ObDereferenceObject(Section
);
3840 ObDereferenceObject(FileObject
);
3844 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3845 ImageSectionObject
, NULL
))
3848 * An other thread has initialized the same image in the background
3850 ExFreePool(ImageSectionObject
->Segments
);
3851 ExFreePool(ImageSectionObject
);
3852 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3853 Section
->ImageSection
= ImageSectionObject
;
3854 SectionSegments
= ImageSectionObject
->Segments
;
3856 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3858 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3862 Status
= StatusExeFmt
;
3869 Status
= MmspWaitForFileLock(FileObject
);
3870 if (Status
!= STATUS_SUCCESS
)
3872 ObDereferenceObject(Section
);
3873 ObDereferenceObject(FileObject
);
3877 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3878 Section
->ImageSection
= ImageSectionObject
;
3879 SectionSegments
= ImageSectionObject
->Segments
;
3882 * Otherwise just reference all the section segments
3884 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3886 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3889 Status
= STATUS_SUCCESS
;
3891 Section
->FileObject
= FileObject
;
3893 CcRosReferenceCache(FileObject
);
3895 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3896 *SectionObject
= Section
;
3903 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3904 PROS_SECTION_OBJECT Section
,
3905 PMM_SECTION_SEGMENT Segment
,
3910 ULONG AllocationType
)
3916 if (Segment
->WriteCopy
)
3918 /* We have to do this because the not present fault
3919 * and access fault handlers depend on the protection
3920 * that should be granted AFTER the COW fault takes
3921 * place to be in Region->Protect. The not present fault
3922 * handler changes this to the correct protection for COW when
3923 * mapping the pages into the process's address space. If a COW
3924 * fault takes place, the access fault handler sets the page protection
3925 * to these values for the newly copied pages
3927 if (Protect
== PAGE_WRITECOPY
)
3928 Protect
= PAGE_READWRITE
;
3929 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3930 Protect
= PAGE_EXECUTE_READWRITE
;
3933 if (*BaseAddress
== NULL
)
3934 Granularity
= MM_ALLOCATION_GRANULARITY
;
3936 Granularity
= PAGE_SIZE
;
3939 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
3940 LARGE_INTEGER FileOffset
;
3941 FileOffset
.QuadPart
= ViewOffset
;
3942 ObReferenceObject(Section
);
3943 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3946 Status
= MmCreateMemoryArea(AddressSpace
,
3947 MEMORY_AREA_SECTION_VIEW
,
3955 if (!NT_SUCCESS(Status
))
3957 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3958 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3962 ObReferenceObject((PVOID
)Section
);
3964 MArea
->Data
.SectionData
.Segment
= Segment
;
3965 MArea
->Data
.SectionData
.Section
= Section
;
3966 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3967 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3968 ViewSize
, 0, Protect
);
3970 return(STATUS_SUCCESS
);
3975 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3976 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3979 PFILE_OBJECT FileObject
;
3980 PROS_SHARED_CACHE_MAP SharedCacheMap
;
3981 LARGE_INTEGER Offset
;
3982 SWAPENTRY SavedSwapEntry
;
3983 PROS_SECTION_OBJECT Section
;
3984 PMM_SECTION_SEGMENT Segment
;
3985 PMMSUPPORT AddressSpace
;
3988 AddressSpace
= (PMMSUPPORT
)Context
;
3989 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3991 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3993 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3994 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3996 Section
= MemoryArea
->Data
.SectionData
.Section
;
3997 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3999 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4000 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
4002 MmUnlockSectionSegment(Segment
);
4003 MmUnlockAddressSpace(AddressSpace
);
4005 MiWaitForPageEvent(NULL
, NULL
);
4007 MmLockAddressSpace(AddressSpace
);
4008 MmLockSectionSegment(Segment
);
4009 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4013 * For a dirty, datafile, non-private page mark it as dirty in the
4016 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4018 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4020 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4021 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4023 CcRosMarkDirtyVacb(SharedCacheMap
, (ULONG
)(Offset
.QuadPart
+ Segment
->Image
.FileOffset
));
4025 ASSERT(SwapEntry
== 0);
4034 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4036 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4037 KeBugCheck(MEMORY_MANAGEMENT
);
4039 MmFreeSwapPage(SwapEntry
);
4043 if (IS_SWAP_FROM_SSE(Entry
) ||
4044 Page
!= PFN_FROM_SSE(Entry
))
4049 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4051 DPRINT1("Found a private page in a pagefile section.\n");
4052 KeBugCheck(MEMORY_MANAGEMENT
);
4055 * Just dereference private pages
4057 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4058 if (SavedSwapEntry
!= 0)
4060 MmFreeSwapPage(SavedSwapEntry
);
4061 MmSetSavedSwapEntryPage(Page
, 0);
4063 MmDeleteRmap(Page
, Process
, Address
);
4064 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4068 MmDeleteRmap(Page
, Process
, Address
);
4069 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4075 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4079 PMEMORY_AREA MemoryArea
;
4080 PROS_SECTION_OBJECT Section
;
4081 PMM_SECTION_SEGMENT Segment
;
4082 PLIST_ENTRY CurrentEntry
;
4083 PMM_REGION CurrentRegion
;
4084 PLIST_ENTRY RegionListHead
;
4086 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4088 if (MemoryArea
== NULL
)
4090 return(STATUS_UNSUCCESSFUL
);
4093 Section
= MemoryArea
->Data
.SectionData
.Section
;
4094 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4097 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4099 MmUnlockAddressSpace(AddressSpace
);
4100 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4101 MmLockAddressSpace(AddressSpace
);
4107 MemoryArea
->DeleteInProgress
= TRUE
;
4109 MmLockSectionSegment(Segment
);
4111 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4112 while (!IsListEmpty(RegionListHead
))
4114 CurrentEntry
= RemoveHeadList(RegionListHead
);
4115 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4116 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4119 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4121 Status
= MmFreeMemoryArea(AddressSpace
,
4128 Status
= MmFreeMemoryArea(AddressSpace
,
4133 MmUnlockSectionSegment(Segment
);
4134 ObDereferenceObject(Section
);
4140 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4141 IN PVOID BaseAddress
,
4145 PMEMORY_AREA MemoryArea
;
4146 PMMSUPPORT AddressSpace
;
4147 PROS_SECTION_OBJECT Section
;
4148 PVOID ImageBaseAddress
= 0;
4150 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4151 Process
, BaseAddress
);
4155 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4157 MmLockAddressSpace(AddressSpace
);
4158 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4160 if (MemoryArea
== NULL
||
4161 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4162 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4163 MemoryArea
->DeleteInProgress
)
4165 if (MemoryArea
) NT_ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4166 MmUnlockAddressSpace(AddressSpace
);
4167 return STATUS_NOT_MAPPED_VIEW
;
4170 Section
= MemoryArea
->Data
.SectionData
.Section
;
4172 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4176 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4177 PMM_SECTION_SEGMENT SectionSegments
;
4178 PMM_SECTION_SEGMENT Segment
;
4180 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4181 ImageSectionObject
= Section
->ImageSection
;
4182 SectionSegments
= ImageSectionObject
->Segments
;
4183 NrSegments
= ImageSectionObject
->NrSegments
;
4185 MemoryArea
->DeleteInProgress
= TRUE
;
4187 /* Search for the current segment within the section segments
4188 * and calculate the image base address */
4189 for (i
= 0; i
< NrSegments
; i
++)
4191 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4193 if (Segment
== &SectionSegments
[i
])
4195 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4200 if (i
>= NrSegments
)
4202 KeBugCheck(MEMORY_MANAGEMENT
);
4205 for (i
= 0; i
< NrSegments
; i
++)
4207 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4209 PVOID SBaseAddress
= (PVOID
)
4210 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4212 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4213 NT_ASSERT(NT_SUCCESS(Status
));
4219 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4220 NT_ASSERT(NT_SUCCESS(Status
));
4223 MmUnlockAddressSpace(AddressSpace
);
4225 /* Notify debugger */
4226 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4228 return(STATUS_SUCCESS
);
4235 * Queries the information of a section object.
4237 * @param SectionHandle
4238 * Handle to the section object. It must be opened with SECTION_QUERY
4240 * @param SectionInformationClass
4241 * Index to a certain information structure. Can be either
4242 * SectionBasicInformation or SectionImageInformation. The latter
4243 * is valid only for sections that were created with the SEC_IMAGE
4245 * @param SectionInformation
4246 * Caller supplies storage for resulting information.
4248 * Size of the supplied storage.
4249 * @param ResultLength
4257 NtQuerySection(IN HANDLE SectionHandle
,
4258 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4259 OUT PVOID SectionInformation
,
4260 IN SIZE_T SectionInformationLength
,
4261 OUT PSIZE_T ResultLength OPTIONAL
)
4263 PROS_SECTION_OBJECT Section
;
4264 KPROCESSOR_MODE PreviousMode
;
4268 PreviousMode
= ExGetPreviousMode();
4270 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4272 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4274 (ULONG
)SectionInformationLength
,
4279 if(!NT_SUCCESS(Status
))
4281 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4285 Status
= ObReferenceObjectByHandle(SectionHandle
,
4287 MmSectionObjectType
,
4289 (PVOID
*)(PVOID
)&Section
,
4291 if (NT_SUCCESS(Status
))
4293 switch (SectionInformationClass
)
4295 case SectionBasicInformation
:
4297 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4301 Sbi
->Attributes
= Section
->AllocationAttributes
;
4302 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4304 Sbi
->BaseAddress
= 0;
4305 Sbi
->Size
.QuadPart
= 0;
4309 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4310 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4313 if (ResultLength
!= NULL
)
4315 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4317 Status
= STATUS_SUCCESS
;
4319 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4321 Status
= _SEH2_GetExceptionCode();
4328 case SectionImageInformation
:
4330 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4334 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4336 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4337 ImageSectionObject
= Section
->ImageSection
;
4339 *Sii
= ImageSectionObject
->ImageInformation
;
4342 if (ResultLength
!= NULL
)
4344 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4346 Status
= STATUS_SUCCESS
;
4348 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4350 Status
= _SEH2_GetExceptionCode();
4358 ObDereferenceObject(Section
);
4364 /**********************************************************************
4366 * MmMapViewOfSection
4369 * Maps a view of a section into the virtual address space of a
4374 * Pointer to the section object.
4377 * Pointer to the process.
4380 * Desired base address (or NULL) on entry;
4381 * Actual base address of the view on exit.
4384 * Number of high order address bits that must be zero.
4387 * Size in bytes of the initially committed section of
4391 * Offset in bytes from the beginning of the section
4392 * to the beginning of the view.
4395 * Desired length of map (or zero to map all) on entry
4396 * Actual length mapped on exit.
4398 * InheritDisposition
4399 * Specified how the view is to be shared with
4403 * Type of allocation for the pages.
4406 * Protection for the committed region of the view.
4414 MmMapViewOfSection(IN PVOID SectionObject
,
4415 IN PEPROCESS Process
,
4416 IN OUT PVOID
*BaseAddress
,
4417 IN ULONG_PTR ZeroBits
,
4418 IN SIZE_T CommitSize
,
4419 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4420 IN OUT PSIZE_T ViewSize
,
4421 IN SECTION_INHERIT InheritDisposition
,
4422 IN ULONG AllocationType
,
4425 PROS_SECTION_OBJECT Section
;
4426 PMMSUPPORT AddressSpace
;
4428 NTSTATUS Status
= STATUS_SUCCESS
;
4429 BOOLEAN NotAtBase
= FALSE
;
4431 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4433 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4434 return MmMapViewOfArm3Section(SectionObject
,
4448 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4450 return STATUS_INVALID_PAGE_PROTECTION
;
4454 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4455 AddressSpace
= &Process
->Vm
;
4457 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4459 MmLockAddressSpace(AddressSpace
);
4461 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4465 ULONG_PTR ImageBase
;
4467 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4468 PMM_SECTION_SEGMENT SectionSegments
;
4470 ImageSectionObject
= Section
->ImageSection
;
4471 SectionSegments
= ImageSectionObject
->Segments
;
4472 NrSegments
= ImageSectionObject
->NrSegments
;
4474 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4477 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4481 for (i
= 0; i
< NrSegments
; i
++)
4483 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4485 ULONG_PTR MaxExtent
;
4486 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4487 SectionSegments
[i
].Length
.QuadPart
);
4488 ImageSize
= max(ImageSize
, MaxExtent
);
4492 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4494 /* Check for an illegal base address */
4495 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4496 ((ImageBase
+ ImageSize
) < ImageSize
))
4498 NT_ASSERT(*BaseAddress
== NULL
);
4499 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4500 MM_VIRTMEM_GRANULARITY
);
4503 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4505 NT_ASSERT(*BaseAddress
== NULL
);
4506 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4510 /* Check there is enough space to map the section at that point. */
4511 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4512 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4514 /* Fail if the user requested a fixed base address. */
4515 if ((*BaseAddress
) != NULL
)
4517 MmUnlockAddressSpace(AddressSpace
);
4518 return(STATUS_CONFLICTING_ADDRESSES
);
4520 /* Otherwise find a gap to map the image. */
4521 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4524 MmUnlockAddressSpace(AddressSpace
);
4525 return(STATUS_CONFLICTING_ADDRESSES
);
4527 /* Remember that we loaded image at a different base address */
4531 for (i
= 0; i
< NrSegments
; i
++)
4533 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4535 PVOID SBaseAddress
= (PVOID
)
4536 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4537 MmLockSectionSegment(&SectionSegments
[i
]);
4538 Status
= MmMapViewOfSegment(AddressSpace
,
4540 &SectionSegments
[i
],
4542 SectionSegments
[i
].Length
.LowPart
,
4543 SectionSegments
[i
].Protection
,
4546 MmUnlockSectionSegment(&SectionSegments
[i
]);
4547 if (!NT_SUCCESS(Status
))
4549 MmUnlockAddressSpace(AddressSpace
);
4555 *BaseAddress
= (PVOID
)ImageBase
;
4556 *ViewSize
= ImageSize
;
4560 /* check for write access */
4561 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4562 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4564 MmUnlockAddressSpace(AddressSpace
);
4565 return STATUS_SECTION_PROTECTION
;
4567 /* check for read access */
4568 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4569 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4571 MmUnlockAddressSpace(AddressSpace
);
4572 return STATUS_SECTION_PROTECTION
;
4574 /* check for execute access */
4575 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4576 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4578 MmUnlockAddressSpace(AddressSpace
);
4579 return STATUS_SECTION_PROTECTION
;
4582 if (ViewSize
== NULL
)
4584 /* Following this pointer would lead to us to the dark side */
4585 /* What to do? Bugcheck? Return status? Do the mambo? */
4586 KeBugCheck(MEMORY_MANAGEMENT
);
4589 if (SectionOffset
== NULL
)
4595 ViewOffset
= SectionOffset
->u
.LowPart
;
4598 if ((ViewOffset
% PAGE_SIZE
) != 0)
4600 MmUnlockAddressSpace(AddressSpace
);
4601 return(STATUS_MAPPED_ALIGNMENT
);
4604 if ((*ViewSize
) == 0)
4606 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4608 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4610 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4613 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4615 MmLockSectionSegment(Section
->Segment
);
4616 Status
= MmMapViewOfSegment(AddressSpace
,
4623 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4624 MmUnlockSectionSegment(Section
->Segment
);
4625 if (!NT_SUCCESS(Status
))
4627 MmUnlockAddressSpace(AddressSpace
);
4632 MmUnlockAddressSpace(AddressSpace
);
4633 NT_ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4636 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4638 Status
= STATUS_SUCCESS
;
4647 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4648 IN PLARGE_INTEGER NewFileSize
)
4650 /* Check whether an ImageSectionObject exists */
4651 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4653 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4657 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4659 PMM_SECTION_SEGMENT Segment
;
4661 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4664 if (Segment
->ReferenceCount
!= 0)
4667 CC_FILE_SIZES FileSizes
;
4669 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4672 /* Check size of file */
4673 if (SectionObjectPointer
->SharedCacheMap
)
4675 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4680 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4689 /* Check size of file */
4690 if (SectionObjectPointer
->SharedCacheMap
)
4692 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4693 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4702 /* Something must gone wrong
4703 * how can we have a Section but no
4705 DPRINT("ERROR: DataSectionObject without reference!\n");
4709 DPRINT("FIXME: didn't check for outstanding write probes\n");
4721 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4722 IN MMFLUSH_TYPE FlushType
)
4724 BOOLEAN Result
= TRUE
;
4726 PMM_SECTION_SEGMENT Segment
;
4731 case MmFlushForDelete
:
4732 if (SectionObjectPointer
->ImageSectionObject
||
4733 SectionObjectPointer
->DataSectionObject
)
4738 CcRosRemoveIfClosed(SectionObjectPointer
);
4741 case MmFlushForWrite
:
4743 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4745 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4748 if (SectionObjectPointer
->ImageSectionObject
) {
4749 DPRINT1("SectionObject has ImageSection\n");
4755 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4757 DPRINT("Result %d\n", Result
);
4769 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4770 OUT PVOID
* MappedBase
,
4771 IN OUT PSIZE_T ViewSize
)
4773 PROS_SECTION_OBJECT Section
;
4774 PMMSUPPORT AddressSpace
;
4778 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4780 return MiMapViewInSystemSpace(SectionObject
,
4786 DPRINT("MmMapViewInSystemSpace() called\n");
4788 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4789 AddressSpace
= MmGetKernelAddressSpace();
4791 MmLockAddressSpace(AddressSpace
);
4794 if ((*ViewSize
) == 0)
4796 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4798 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4800 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4803 MmLockSectionSegment(Section
->Segment
);
4806 Status
= MmMapViewOfSegment(AddressSpace
,
4815 MmUnlockSectionSegment(Section
->Segment
);
4816 MmUnlockAddressSpace(AddressSpace
);
4823 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4825 PMMSUPPORT AddressSpace
;
4828 DPRINT("MmUnmapViewInSystemSpace() called\n");
4830 AddressSpace
= MmGetKernelAddressSpace();
4832 MmLockAddressSpace(AddressSpace
);
4834 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4836 MmUnlockAddressSpace(AddressSpace
);
4841 /**********************************************************************
4846 * Creates a section object.
4849 * SectionObject (OUT)
4850 * Caller supplied storage for the resulting pointer
4851 * to a SECTION_OBJECT instance;
4854 * Specifies the desired access to the section can be a
4856 * STANDARD_RIGHTS_REQUIRED |
4858 * SECTION_MAP_WRITE |
4859 * SECTION_MAP_READ |
4860 * SECTION_MAP_EXECUTE
4862 * ObjectAttributes [OPTIONAL]
4863 * Initialized attributes for the object can be used
4864 * to create a named section;
4867 * Maximizes the size of the memory section. Must be
4868 * non-NULL for a page-file backed section.
4869 * If value specified for a mapped file and the file is
4870 * not large enough, file will be extended.
4872 * SectionPageProtection
4873 * Can be a combination of:
4879 * AllocationAttributes
4880 * Can be a combination of:
4885 * Handle to a file to create a section mapped to a file
4886 * instead of a memory backed section;
4897 MmCreateSection (OUT PVOID
* Section
,
4898 IN ACCESS_MASK DesiredAccess
,
4899 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4900 IN PLARGE_INTEGER MaximumSize
,
4901 IN ULONG SectionPageProtection
,
4902 IN ULONG AllocationAttributes
,
4903 IN HANDLE FileHandle OPTIONAL
,
4904 IN PFILE_OBJECT FileObject OPTIONAL
)
4908 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4910 /* Check if an ARM3 section is being created instead */
4911 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4913 if (!(FileObject
) && !(FileHandle
))
4915 return MmCreateArm3Section(Section
,
4919 SectionPageProtection
,
4920 AllocationAttributes
&~ 1,
4926 /* Convert section flag to page flag */
4927 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4929 /* Check to make sure the protection is correct. Nt* does this already */
4930 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4931 if (Protection
== MM_INVALID_PROTECTION
)
4933 DPRINT1("Page protection is invalid\n");
4934 return STATUS_INVALID_PAGE_PROTECTION
;
4937 /* Check if this is going to be a data or image backed file section */
4938 if ((FileHandle
) || (FileObject
))
4940 /* These cannot be mapped with large pages */
4941 if (AllocationAttributes
& SEC_LARGE_PAGES
)
4943 DPRINT1("Large pages cannot be used with an image mapping\n");
4944 return STATUS_INVALID_PARAMETER_6
;
4947 /* Did the caller pass an object? */
4950 /* Reference the object directly */
4951 ObReferenceObject(FileObject
);
4955 /* Reference the file handle to get the object */
4956 Status
= ObReferenceObjectByHandle(FileHandle
,
4957 MmMakeFileAccess
[Protection
],
4959 ExGetPreviousMode(),
4960 (PVOID
*)&FileObject
,
4962 if (!NT_SUCCESS(Status
))
4964 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
4971 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
4972 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
4975 #ifndef NEWCC // A hack for initializing caching.
4976 // This is needed only in the old case.
4979 IO_STATUS_BLOCK Iosb
;
4982 LARGE_INTEGER ByteOffset
;
4983 ByteOffset
.QuadPart
= 0;
4984 Status
= ZwReadFile(FileHandle
,
4993 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
4995 DPRINT1("CC failure: %lx\n", Status
);
4998 // Caching is initialized...
5002 if (AllocationAttributes
& SEC_IMAGE
)
5004 Status
= MmCreateImageSection(SectionObject
,
5008 SectionPageProtection
,
5009 AllocationAttributes
,
5013 else if (FileHandle
!= NULL
)
5015 Status
= MmCreateDataFileSection(SectionObject
,
5019 SectionPageProtection
,
5020 AllocationAttributes
,
5023 ObDereferenceObject(FileObject
);
5026 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5028 Status
= MmCreateCacheSection(SectionObject
,
5032 SectionPageProtection
,
5033 AllocationAttributes
,
5039 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5041 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5043 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5044 Status
= MmCreatePageFileSection(SectionObject
,
5048 SectionPageProtection
,
5049 AllocationAttributes
);