2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
48 #include "../cache/newcc.h"
49 #include "../cache/section/newmm.h"
52 #include <reactos/exeformat.h>
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 #include "ARM3/miarm.h"
61 #undef MmSetPageEntrySectionSegment
62 #define MmSetPageEntrySectionSegment(S,O,E) do { \
63 DPRINT("SetPageEntrySectionSegment(old,%p,%x,%x)\n",(S),(O)->LowPart,E); \
64 _MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__); \
67 extern MMSESSION MmSession
;
71 MiMapViewInSystemSpace(IN PVOID Section
,
73 OUT PVOID
*MappedBase
,
74 IN OUT PSIZE_T ViewSize
);
78 MmCreateArm3Section(OUT PVOID
*SectionObject
,
79 IN ACCESS_MASK DesiredAccess
,
80 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
81 IN PLARGE_INTEGER InputMaximumSize
,
82 IN ULONG SectionPageProtection
,
83 IN ULONG AllocationAttributes
,
84 IN HANDLE FileHandle OPTIONAL
,
85 IN PFILE_OBJECT FileObject OPTIONAL
);
89 MmMapViewOfArm3Section(IN PVOID SectionObject
,
91 IN OUT PVOID
*BaseAddress
,
92 IN ULONG_PTR ZeroBits
,
94 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
95 IN OUT PSIZE_T ViewSize
,
96 IN SECTION_INHERIT InheritDisposition
,
97 IN ULONG AllocationType
,
101 // PeFmtCreateSection depends on the following:
103 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
104 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
106 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
107 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
108 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
110 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
111 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
112 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
113 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
114 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
115 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
116 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
117 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
118 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
120 /* TYPES *********************************************************************/
124 PROS_SECTION_OBJECT Section
;
125 PMM_SECTION_SEGMENT Segment
;
126 LARGE_INTEGER Offset
;
129 PEPROCESS CallingProcess
;
130 ULONG_PTR SectionEntry
;
132 MM_SECTION_PAGEOUT_CONTEXT
;
134 /* GLOBALS *******************************************************************/
136 POBJECT_TYPE MmSectionObjectType
= NULL
;
138 ULONG_PTR MmSubsectionBase
;
140 static ULONG SectionCharacteristicsToProtect
[16] =
142 PAGE_NOACCESS
, /* 0 = NONE */
143 PAGE_NOACCESS
, /* 1 = SHARED */
144 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
145 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
146 PAGE_READONLY
, /* 4 = READABLE */
147 PAGE_READONLY
, /* 5 = READABLE, SHARED */
148 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
149 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
151 * FIXME? do we really need the WriteCopy field in segments? can't we use
152 * PAGE_WRITECOPY here?
154 PAGE_READWRITE
, /* 8 = WRITABLE */
155 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
156 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
157 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
158 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
159 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
160 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
161 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
164 extern ULONG MmMakeFileAccess
[];
165 ACCESS_MASK NTAPI
MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection
);
166 static GENERIC_MAPPING MmpSectionMapping
=
168 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
169 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
170 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
174 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
176 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
177 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
180 /* FUNCTIONS *****************************************************************/
185 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
186 File Format Specification", revision 6.0 (February 1999)
188 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
189 IN SIZE_T FileHeaderSize
,
191 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
193 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
194 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
197 ULONG cbFileHeaderOffsetSize
= 0;
198 ULONG cbSectionHeadersOffset
= 0;
199 ULONG cbSectionHeadersSize
;
200 ULONG cbSectionHeadersOffsetSize
= 0;
201 ULONG cbOptHeaderSize
;
202 ULONG cbHeadersSize
= 0;
203 ULONG nSectionAlignment
;
204 ULONG nFileAlignment
;
206 const IMAGE_DOS_HEADER
* pidhDosHeader
;
207 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
208 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
209 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
210 PMM_SECTION_SEGMENT pssSegments
;
211 LARGE_INTEGER lnOffset
;
213 SIZE_T nPrevVirtualEndOfSegment
= 0;
214 ULONG nFileSizeOfHeaders
= 0;
218 ASSERT(FileHeaderSize
> 0);
220 ASSERT(ImageSectionObject
);
222 ASSERT(AllocateSegmentsCb
);
224 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
226 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
228 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
231 pidhDosHeader
= FileHeader
;
234 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
236 /* image too small to be an MZ executable */
237 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
238 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
240 /* no MZ signature */
241 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
242 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
244 /* not a Windows executable */
245 if(pidhDosHeader
->e_lfanew
<= 0)
246 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
249 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
251 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
252 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
254 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
259 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
260 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
262 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
263 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
267 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
268 * need to read the header from the file
270 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
271 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
273 ULONG cbNtHeaderSize
;
277 l_ReadHeaderFromFile
:
279 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
281 /* read the header from the file */
282 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
284 if(!NT_SUCCESS(nStatus
))
286 NTSTATUS ReturnedStatus
= nStatus
;
288 /* If it attempted to read past the end of the file, it means e_lfanew is invalid */
289 if (ReturnedStatus
== STATUS_END_OF_FILE
) nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
291 DIE(("ReadFile failed, status %08X\n", ReturnedStatus
));
296 ASSERT(cbReadSize
> 0);
298 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
300 /* the buffer doesn't contain the file header */
301 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
302 DIE(("The file doesn't contain the PE file header\n"));
304 pinhNtHeader
= pData
;
306 /* object still not aligned: copy it to the beginning of the buffer */
307 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
309 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
310 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
311 pinhNtHeader
= pBuffer
;
314 /* invalid NT header */
315 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
317 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
318 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
320 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
322 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
323 DIE(("The full NT header is too large\n"));
325 /* the buffer doesn't contain the whole NT header */
326 if(cbReadSize
< cbNtHeaderSize
)
327 DIE(("The file doesn't contain the full NT header\n"));
331 ULONG cbOptHeaderOffsetSize
= 0;
333 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
335 /* don't trust an invalid NT header */
336 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
337 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
339 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
340 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
342 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
343 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
345 /* the buffer doesn't contain the whole NT header: read it from the file */
346 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
347 goto l_ReadHeaderFromFile
;
350 /* read information from the NT header */
351 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
352 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
354 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
356 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
357 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
359 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
361 switch(piohOptHeader
->Magic
)
363 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
364 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
368 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
371 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
372 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
374 /* See [1], section 3.4.2 */
375 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
377 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
378 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
380 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
381 DIE(("The section alignment is smaller than the file alignment\n"));
383 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
384 nFileAlignment
= piohOptHeader
->FileAlignment
;
386 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
387 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
391 nSectionAlignment
= PAGE_SIZE
;
392 nFileAlignment
= PAGE_SIZE
;
395 ASSERT(IsPowerOf2(nSectionAlignment
));
396 ASSERT(IsPowerOf2(nFileAlignment
));
398 switch(piohOptHeader
->Magic
)
401 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
403 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
404 ImageBase
= piohOptHeader
->ImageBase
;
406 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
407 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
409 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
410 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
412 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
413 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
415 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
417 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
419 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
420 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
422 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
423 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
427 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
429 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
430 piohOptHeader
->AddressOfEntryPoint
);
433 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
434 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
436 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
438 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
440 if (piohOptHeader
->AddressOfEntryPoint
== 0)
442 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
446 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
447 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
449 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
451 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
454 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
455 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
456 * magic to any binary.
458 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
459 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
460 * the SxS support -- at which point, duh, this should be removed.
462 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
464 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
471 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
473 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
475 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
477 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
479 ImageBase
= pioh64OptHeader
->ImageBase
;
480 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
481 DIE(("ImageBase exceeds the address space\n"));
484 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
486 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
487 DIE(("SizeOfImage exceeds the address space\n"));
489 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
492 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
494 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
495 DIE(("SizeOfStackReserve exceeds the address space\n"));
497 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
500 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
502 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
503 DIE(("SizeOfStackCommit exceeds the address space\n"));
505 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
508 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
510 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
512 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
513 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
515 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
516 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
520 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
522 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
523 pioh64OptHeader
->AddressOfEntryPoint
);
526 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
527 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
529 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
531 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
533 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
535 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
539 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
540 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
542 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
543 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
550 /* [1], section 3.4.2 */
551 if((ULONG_PTR
)ImageBase
% 0x10000)
552 DIE(("ImageBase is not aligned on a 64KB boundary"));
554 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
555 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
556 ImageSectionObject
->ImageInformation
.GpValue
= 0;
557 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
558 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
560 /* SECTION HEADERS */
561 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
563 /* see [1], section 3.3 */
564 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
565 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
568 * the additional segment is for the file's headers. They need to be present for
569 * the benefit of the dynamic loader (to locate exports, defaults for thread
570 * parameters, resources, etc.)
572 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
574 /* file offset for the section headers */
575 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
576 DIE(("Offset overflow\n"));
578 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
579 DIE(("Offset overflow\n"));
581 /* size of the section headers */
582 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
583 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
585 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
586 DIE(("Section headers too large\n"));
588 /* size of the executable's headers */
589 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
591 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
592 // DIE(("SizeOfHeaders is not aligned\n"));
594 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
595 DIE(("The section headers overflow SizeOfHeaders\n"));
597 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
599 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
600 DIE(("Overflow aligning the size of headers\n"));
607 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
608 /* WARNING: piohOptHeader IS NO LONGER USABLE */
609 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
611 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
612 pishSectionHeaders
= NULL
;
616 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
617 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
619 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
620 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
624 * the buffer doesn't contain the section headers, or the alignment is wrong:
625 * read the headers from the file
627 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
628 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
633 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
635 /* read the header from the file */
636 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
638 if(!NT_SUCCESS(nStatus
))
639 DIE(("ReadFile failed with status %08X\n", nStatus
));
643 ASSERT(cbReadSize
> 0);
645 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
647 /* the buffer doesn't contain all the section headers */
648 if(cbReadSize
< cbSectionHeadersSize
)
649 DIE(("The file doesn't contain all of the section headers\n"));
651 pishSectionHeaders
= pData
;
653 /* object still not aligned: copy it to the beginning of the buffer */
654 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
656 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
657 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
658 pishSectionHeaders
= pBuffer
;
663 /* allocate the segments */
664 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
665 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
667 if(ImageSectionObject
->Segments
== NULL
)
668 DIE(("AllocateSegments failed\n"));
670 /* initialize the headers segment */
671 pssSegments
= ImageSectionObject
->Segments
;
673 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
675 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
676 DIE(("Cannot align the size of the section headers\n"));
678 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
679 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
680 DIE(("Cannot align the size of the section headers\n"));
682 pssSegments
[0].Image
.FileOffset
= 0;
683 pssSegments
[0].Protection
= PAGE_READONLY
;
684 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
685 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
686 pssSegments
[0].Image
.VirtualAddress
= 0;
687 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
688 pssSegments
[0].WriteCopy
= TRUE
;
690 /* skip the headers segment */
693 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
695 /* convert the executable sections into segments. See also [1], section 4 */
696 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
698 ULONG nCharacteristics
;
700 /* validate the alignment */
701 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
702 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
704 /* sections must be contiguous, ordered by base address and non-overlapping */
705 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
706 DIE(("Memory gap between section %u and the previous\n", i
));
708 /* ignore explicit BSS sections */
709 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
711 /* validate the alignment */
713 /* Yes, this should be a multiple of FileAlignment, but there's
714 * stuff out there that isn't. We can cope with that
716 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
717 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
720 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
721 // DIE(("PointerToRawData[%u] is not aligned\n", i));
724 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
725 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
729 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
730 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
733 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
735 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
737 /* no explicit protection */
738 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
740 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
741 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
743 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
744 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
746 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
747 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
750 /* see table above */
751 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
752 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
754 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
755 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
757 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
759 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
760 /* FIXME: always false */
761 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
762 DIE(("Cannot align the virtual size of section %u\n", i
));
764 if(pssSegments
[i
].Length
.QuadPart
== 0)
765 DIE(("Virtual size of section %u is null\n", i
));
767 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
768 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
770 /* ensure the memory image is no larger than 4GB */
771 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
772 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
773 DIE(("The image is too large\n"));
776 if(nSectionAlignment
>= PAGE_SIZE
)
777 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
780 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
790 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
791 * ARGUMENTS: PFILE_OBJECT to wait for.
792 * RETURNS: Status of the wait.
795 MmspWaitForFileLock(PFILE_OBJECT File
)
797 return STATUS_SUCCESS
;
798 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
803 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
805 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
807 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
808 PMM_SECTION_SEGMENT SectionSegments
;
812 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
813 NrSegments
= ImageSectionObject
->NrSegments
;
814 SectionSegments
= ImageSectionObject
->Segments
;
815 for (i
= 0; i
< NrSegments
; i
++)
817 if (SectionSegments
[i
].ReferenceCount
!= 0)
819 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
820 SectionSegments
[i
].ReferenceCount
);
821 KeBugCheck(MEMORY_MANAGEMENT
);
823 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
825 ExFreePool(ImageSectionObject
->Segments
);
826 ExFreePool(ImageSectionObject
);
827 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
829 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
831 PMM_SECTION_SEGMENT Segment
;
833 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
836 if (Segment
->ReferenceCount
!= 0)
838 DPRINT1("Data segment still referenced\n");
839 KeBugCheck(MEMORY_MANAGEMENT
);
841 MmFreePageTablesSectionSegment(Segment
, NULL
);
843 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
849 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
850 PLARGE_INTEGER Offset
)
854 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
857 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
858 KeBugCheck(MEMORY_MANAGEMENT
);
860 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
862 DPRINT1("Maximum share count reached\n");
863 KeBugCheck(MEMORY_MANAGEMENT
);
865 if (IS_SWAP_FROM_SSE(Entry
))
867 KeBugCheck(MEMORY_MANAGEMENT
);
869 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
870 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
875 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
876 PMM_SECTION_SEGMENT Segment
,
877 PLARGE_INTEGER Offset
,
882 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
883 BOOLEAN IsDirectMapped
= FALSE
;
887 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
888 KeBugCheck(MEMORY_MANAGEMENT
);
890 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
892 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
893 KeBugCheck(MEMORY_MANAGEMENT
);
895 if (IS_SWAP_FROM_SSE(Entry
))
897 KeBugCheck(MEMORY_MANAGEMENT
);
899 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
901 * If we reducing the share count of this entry to zero then set the entry
902 * to zero and tell the cache the page is no longer mapped.
904 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
906 PFILE_OBJECT FileObject
;
908 PROS_SHARED_CACHE_MAP SharedCacheMap
;
910 SWAPENTRY SavedSwapEntry
;
912 BOOLEAN IsImageSection
;
913 LARGE_INTEGER FileOffset
;
915 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
917 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
919 Page
= PFN_FROM_SSE(Entry
);
920 FileObject
= Section
->FileObject
;
921 if (FileObject
!= NULL
&&
922 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
926 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
927 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
930 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
931 IsDirectMapped
= TRUE
;
933 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
.QuadPart
, Dirty
);
935 Status
= STATUS_SUCCESS
;
937 if (!NT_SUCCESS(Status
))
939 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
940 KeBugCheck(MEMORY_MANAGEMENT
);
946 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
947 if (SavedSwapEntry
== 0)
950 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
951 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
955 * Try to page out this page and set the swap entry
956 * within the section segment. There exist no rmap entry
957 * for this page. The pager thread can't page out a
958 * page without a rmap entry.
960 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
961 if (InEntry
) *InEntry
= Entry
;
962 MiSetPageEvent(NULL
, NULL
);
966 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
967 if (InEntry
) *InEntry
= 0;
968 MiSetPageEvent(NULL
, NULL
);
971 MmReleasePageMemoryConsumer(MC_USER
, Page
);
977 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
978 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
986 * We hold all locks. Nobody can do something with the current
987 * process and the current segment (also not within an other process).
990 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
991 if (!NT_SUCCESS(Status
))
993 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
994 KeBugCheck(MEMORY_MANAGEMENT
);
997 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
998 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
999 MmSetSavedSwapEntryPage(Page
, 0);
1000 MiSetPageEvent(NULL
, NULL
);
1002 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1006 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1007 KeBugCheck(MEMORY_MANAGEMENT
);
1016 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1018 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1021 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1025 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1027 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1029 SharedCacheMap
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1030 Vacb
= CcRosLookupVacb(SharedCacheMap
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
);
1033 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, FALSE
, TRUE
);
1043 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1047 PVOID DestAddress
, SrcAddress
;
1049 Process
= PsGetCurrentProcess();
1050 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1051 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1052 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1054 return(STATUS_NO_MEMORY
);
1056 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1057 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1058 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1059 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1060 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1061 return(STATUS_SUCCESS
);
1067 MiReadPage(PMEMORY_AREA MemoryArea
,
1071 * FUNCTION: Read a page for a section backed memory area.
1073 * MemoryArea - Memory area to read the page for.
1074 * Offset - Offset of the page to read.
1075 * Page - Variable that receives a page contains the read data.
1078 LONGLONG BaseOffset
;
1079 LONGLONG FileOffset
;
1083 PFILE_OBJECT FileObject
;
1086 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1087 BOOLEAN IsImageSection
;
1090 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1091 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1092 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
;
1093 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1094 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1096 ASSERT(SharedCacheMap
);
1098 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1101 * If the file system is letting us go directly to the cache and the
1102 * memory area was mapped at an offset in the file which is page aligned
1103 * then get the related VACB.
1105 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1106 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1107 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1111 * Get the related VACB; we use a lower level interface than
1112 * filesystems do because it is safe for us to use an offset with an
1113 * alignment less than the file system block size.
1115 Status
= CcRosGetVacb(SharedCacheMap
,
1121 if (!NT_SUCCESS(Status
))
1128 * If the VACB isn't up to date then call the file
1129 * system to read in the data.
1131 Status
= CcReadVirtualAddress(Vacb
);
1132 if (!NT_SUCCESS(Status
))
1134 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1139 /* Probe the page, since it's PDE might not be synced */
1140 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1143 * Retrieve the page from the view that we actually want.
1145 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1146 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1148 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, TRUE
);
1155 LONGLONG VacbOffset
;
1158 * Allocate a page, this is rather complicated by the possibility
1159 * we might have to move other things out of memory
1161 MI_SET_USAGE(MI_USAGE_SECTION
);
1162 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1163 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1164 if (!NT_SUCCESS(Status
))
1168 Status
= CcRosGetVacb(SharedCacheMap
,
1174 if (!NT_SUCCESS(Status
))
1181 * If the VACB isn't up to date then call the file
1182 * system to read in the data.
1184 Status
= CcReadVirtualAddress(Vacb
);
1185 if (!NT_SUCCESS(Status
))
1187 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1192 Process
= PsGetCurrentProcess();
1193 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1194 VacbOffset
= BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
;
1195 Length
= RawLength
- SegOffset
;
1196 if (Length
<= VacbOffset
&& Length
<= PAGE_SIZE
)
1198 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1200 else if (VacbOffset
>= PAGE_SIZE
)
1202 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1206 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, VacbOffset
);
1207 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1208 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1209 Status
= CcRosGetVacb(SharedCacheMap
,
1210 FileOffset
+ VacbOffset
,
1215 if (!NT_SUCCESS(Status
))
1222 * If the VACB isn't up to date then call the file
1223 * system to read in the data.
1225 Status
= CcReadVirtualAddress(Vacb
);
1226 if (!NT_SUCCESS(Status
))
1228 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1232 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1233 if (Length
< PAGE_SIZE
)
1235 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, Length
- VacbOffset
);
1239 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, PAGE_SIZE
- VacbOffset
);
1242 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1243 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1245 return(STATUS_SUCCESS
);
1250 MiReadPage(PMEMORY_AREA MemoryArea
,
1254 * FUNCTION: Read a page for a section backed memory area.
1256 * MemoryArea - Memory area to read the page for.
1257 * Offset - Offset of the page to read.
1258 * Page - Variable that receives a page contains the read data.
1261 MM_REQUIRED_RESOURCES Resources
;
1264 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1266 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1267 Resources
.FileOffset
.QuadPart
= SegOffset
+
1268 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1269 Resources
.Consumer
= MC_USER
;
1270 Resources
.Amount
= PAGE_SIZE
;
1272 DPRINT("%S, offset 0x%x, len 0x%x, page 0x%x\n", ((PFILE_OBJECT
)Resources
.Context
)->FileName
.Buffer
, Resources
.FileOffset
.LowPart
, Resources
.Amount
, Resources
.Page
[0]);
1274 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1275 *Page
= Resources
.Page
[0];
1282 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1283 MEMORY_AREA
* MemoryArea
,
1287 LARGE_INTEGER Offset
;
1290 PROS_SECTION_OBJECT Section
;
1291 PMM_SECTION_SEGMENT Segment
;
1296 BOOLEAN HasSwapEntry
;
1298 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1299 SWAPENTRY SwapEntry
;
1302 * There is a window between taking the page fault and locking the
1303 * address space when another thread could load the page so we check
1306 if (MmIsPagePresent(Process
, Address
))
1308 return(STATUS_SUCCESS
);
1311 if (MmIsDisabledPage(Process
, Address
))
1313 return(STATUS_ACCESS_VIOLATION
);
1317 * Check for the virtual memory area being deleted.
1319 if (MemoryArea
->DeleteInProgress
)
1321 return(STATUS_UNSUCCESSFUL
);
1324 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1325 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1326 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1328 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1329 Section
= MemoryArea
->Data
.SectionData
.Section
;
1330 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1331 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1333 ASSERT(Region
!= NULL
);
1337 MmLockSectionSegment(Segment
);
1338 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1340 * Check if this page needs to be mapped COW
1342 if ((Segment
->WriteCopy
) &&
1343 (Region
->Protect
== PAGE_READWRITE
||
1344 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1346 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1350 Attributes
= Region
->Protect
;
1354 * Check if someone else is already handling this fault, if so wait
1357 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1359 MmUnlockSectionSegment(Segment
);
1360 MmUnlockAddressSpace(AddressSpace
);
1361 MiWaitForPageEvent(NULL
, NULL
);
1362 MmLockAddressSpace(AddressSpace
);
1363 DPRINT("Address 0x%p\n", Address
);
1364 return(STATUS_MM_RESTART_OPERATION
);
1367 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1371 SWAPENTRY DummyEntry
;
1374 * Is it a wait entry?
1376 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1378 if (SwapEntry
== MM_WAIT_ENTRY
)
1380 MmUnlockSectionSegment(Segment
);
1381 MmUnlockAddressSpace(AddressSpace
);
1382 MiWaitForPageEvent(NULL
, NULL
);
1383 MmLockAddressSpace(AddressSpace
);
1384 return STATUS_MM_RESTART_OPERATION
;
1388 * Must be private page we have swapped out.
1394 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1396 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1397 KeBugCheck(MEMORY_MANAGEMENT
);
1400 MmUnlockSectionSegment(Segment
);
1401 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1402 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1404 MmUnlockAddressSpace(AddressSpace
);
1405 MI_SET_USAGE(MI_USAGE_SECTION
);
1406 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1407 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1408 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1409 if (!NT_SUCCESS(Status
))
1411 KeBugCheck(MEMORY_MANAGEMENT
);
1414 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1415 if (!NT_SUCCESS(Status
))
1417 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1418 KeBugCheck(MEMORY_MANAGEMENT
);
1420 MmLockAddressSpace(AddressSpace
);
1421 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1422 Status
= MmCreateVirtualMapping(Process
,
1427 if (!NT_SUCCESS(Status
))
1429 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1430 KeBugCheck(MEMORY_MANAGEMENT
);
1435 * Store the swap entry for later use.
1437 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1440 * Add the page to the process's working set
1442 MmInsertRmap(Page
, Process
, Address
);
1444 * Finish the operation
1446 MiSetPageEvent(Process
, Address
);
1447 DPRINT("Address 0x%p\n", Address
);
1448 return(STATUS_SUCCESS
);
1452 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1454 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1456 MmUnlockSectionSegment(Segment
);
1458 * Just map the desired physical page
1460 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1461 Status
= MmCreateVirtualMappingUnsafe(Process
,
1466 if (!NT_SUCCESS(Status
))
1468 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1469 KeBugCheck(MEMORY_MANAGEMENT
);
1474 * Cleanup and release locks
1476 MiSetPageEvent(Process
, Address
);
1477 DPRINT("Address 0x%p\n", Address
);
1478 return(STATUS_SUCCESS
);
1482 * Get the entry corresponding to the offset within the section
1484 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1488 SWAPENTRY FakeSwapEntry
;
1491 * If the entry is zero (and it can't change because we have
1492 * locked the segment) then we need to load the page.
1496 * Release all our locks and read in the page from disk
1498 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1499 MmUnlockSectionSegment(Segment
);
1500 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1501 MmUnlockAddressSpace(AddressSpace
);
1503 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1504 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1505 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1507 MI_SET_USAGE(MI_USAGE_SECTION
);
1508 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1509 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1510 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1511 if (!NT_SUCCESS(Status
))
1513 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1519 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1520 if (!NT_SUCCESS(Status
))
1522 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1525 if (!NT_SUCCESS(Status
))
1528 * FIXME: What do we know in this case?
1531 * Cleanup and release locks
1533 MmLockAddressSpace(AddressSpace
);
1534 MiSetPageEvent(Process
, Address
);
1535 DPRINT("Address 0x%p\n", Address
);
1540 * Mark the offset within the section as having valid, in-memory
1543 MmLockAddressSpace(AddressSpace
);
1544 MmLockSectionSegment(Segment
);
1545 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1546 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1547 MmUnlockSectionSegment(Segment
);
1549 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1550 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1551 Page
, Process
, PAddress
, Attributes
);
1552 Status
= MmCreateVirtualMapping(Process
,
1557 if (!NT_SUCCESS(Status
))
1559 DPRINT1("Unable to create virtual mapping\n");
1560 KeBugCheck(MEMORY_MANAGEMENT
);
1562 ASSERT(MmIsPagePresent(Process
, PAddress
));
1563 MmInsertRmap(Page
, Process
, Address
);
1565 MiSetPageEvent(Process
, Address
);
1566 DPRINT("Address 0x%p\n", Address
);
1567 return(STATUS_SUCCESS
);
1569 else if (IS_SWAP_FROM_SSE(Entry
))
1571 SWAPENTRY SwapEntry
;
1573 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1576 * Release all our locks and read in the page from disk
1578 MmUnlockSectionSegment(Segment
);
1580 MmUnlockAddressSpace(AddressSpace
);
1581 MI_SET_USAGE(MI_USAGE_SECTION
);
1582 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1583 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1584 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1585 if (!NT_SUCCESS(Status
))
1587 KeBugCheck(MEMORY_MANAGEMENT
);
1590 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1591 if (!NT_SUCCESS(Status
))
1593 KeBugCheck(MEMORY_MANAGEMENT
);
1597 * Relock the address space and segment
1599 MmLockAddressSpace(AddressSpace
);
1600 MmLockSectionSegment(Segment
);
1603 * Check the entry. No one should change the status of a page
1604 * that has a pending page-in.
1606 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1607 if (Entry
!= Entry1
)
1609 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1610 KeBugCheck(MEMORY_MANAGEMENT
);
1614 * Mark the offset within the section as having valid, in-memory
1617 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1618 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1619 MmUnlockSectionSegment(Segment
);
1622 * Save the swap entry.
1624 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1625 Status
= MmCreateVirtualMapping(Process
,
1630 if (!NT_SUCCESS(Status
))
1632 DPRINT1("Unable to create virtual mapping\n");
1633 KeBugCheck(MEMORY_MANAGEMENT
);
1635 MmInsertRmap(Page
, Process
, Address
);
1636 MiSetPageEvent(Process
, Address
);
1637 DPRINT("Address 0x%p\n", Address
);
1638 return(STATUS_SUCCESS
);
1643 * If the section offset is already in-memory and valid then just
1644 * take another reference to the page
1647 Page
= PFN_FROM_SSE(Entry
);
1649 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1650 MmUnlockSectionSegment(Segment
);
1652 Status
= MmCreateVirtualMapping(Process
,
1657 if (!NT_SUCCESS(Status
))
1659 DPRINT1("Unable to create virtual mapping\n");
1660 KeBugCheck(MEMORY_MANAGEMENT
);
1662 MmInsertRmap(Page
, Process
, Address
);
1663 MiSetPageEvent(Process
, Address
);
1664 DPRINT("Address 0x%p\n", Address
);
1665 return(STATUS_SUCCESS
);
1671 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1672 MEMORY_AREA
* MemoryArea
,
1675 PMM_SECTION_SEGMENT Segment
;
1676 PROS_SECTION_OBJECT Section
;
1681 LARGE_INTEGER Offset
;
1684 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1685 SWAPENTRY SwapEntry
;
1687 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1690 * Check if the page has already been set readwrite
1692 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1694 DPRINT("Address 0x%p\n", Address
);
1695 return(STATUS_SUCCESS
);
1699 * Find the offset of the page
1701 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1702 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1703 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1705 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1706 Section
= MemoryArea
->Data
.SectionData
.Section
;
1707 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1708 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1710 ASSERT(Region
!= NULL
);
1714 MmLockSectionSegment(Segment
);
1716 OldPage
= MmGetPfnForProcess(Process
, Address
);
1717 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1719 MmUnlockSectionSegment(Segment
);
1722 * Check if we are doing COW
1724 if (!((Segment
->WriteCopy
) &&
1725 (Region
->Protect
== PAGE_READWRITE
||
1726 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1728 DPRINT("Address 0x%p\n", Address
);
1729 return(STATUS_ACCESS_VIOLATION
);
1732 if (IS_SWAP_FROM_SSE(Entry
) ||
1733 PFN_FROM_SSE(Entry
) != OldPage
)
1735 /* This is a private page. We must only change the page protection. */
1736 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1737 return(STATUS_SUCCESS
);
1741 DPRINT("OldPage == 0!\n");
1744 * Get or create a pageop
1746 MmLockSectionSegment(Segment
);
1747 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1750 * Wait for any other operations to complete
1752 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1754 MmUnlockSectionSegment(Segment
);
1755 MmUnlockAddressSpace(AddressSpace
);
1756 MiWaitForPageEvent(NULL
, NULL
);
1758 * Restart the operation
1760 MmLockAddressSpace(AddressSpace
);
1761 DPRINT("Address 0x%p\n", Address
);
1762 return(STATUS_MM_RESTART_OPERATION
);
1765 MmDeleteRmap(OldPage
, Process
, PAddress
);
1766 MmDeleteVirtualMapping(Process
, PAddress
, FALSE
, NULL
, NULL
);
1767 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1770 * Release locks now we have the pageop
1772 MmUnlockSectionSegment(Segment
);
1773 MmUnlockAddressSpace(AddressSpace
);
1778 MI_SET_USAGE(MI_USAGE_SECTION
);
1779 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1780 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1781 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1782 if (!NT_SUCCESS(Status
))
1784 KeBugCheck(MEMORY_MANAGEMENT
);
1790 MiCopyFromUserPage(NewPage
, OldPage
);
1792 MmLockAddressSpace(AddressSpace
);
1795 * Set the PTE to point to the new page
1797 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1798 Status
= MmCreateVirtualMapping(Process
,
1803 if (!NT_SUCCESS(Status
))
1805 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1806 KeBugCheck(MEMORY_MANAGEMENT
);
1811 * Unshare the old page.
1813 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1814 MmInsertRmap(NewPage
, Process
, PAddress
);
1815 MmLockSectionSegment(Segment
);
1816 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1817 MmUnlockSectionSegment(Segment
);
1819 MiSetPageEvent(Process
, Address
);
1820 DPRINT("Address 0x%p\n", Address
);
1821 return(STATUS_SUCCESS
);
1825 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1827 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1829 PFN_NUMBER Page
= 0;
1831 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1834 MmLockAddressSpace(&Process
->Vm
);
1837 MmDeleteVirtualMapping(Process
,
1844 PageOutContext
->WasDirty
= TRUE
;
1846 if (!PageOutContext
->Private
)
1848 MmLockSectionSegment(PageOutContext
->Segment
);
1849 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1850 PageOutContext
->Segment
,
1851 &PageOutContext
->Offset
,
1852 PageOutContext
->WasDirty
,
1854 &PageOutContext
->SectionEntry
);
1855 MmUnlockSectionSegment(PageOutContext
->Segment
);
1859 MmUnlockAddressSpace(&Process
->Vm
);
1862 if (PageOutContext
->Private
)
1864 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1870 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1871 MEMORY_AREA
* MemoryArea
,
1872 PVOID Address
, ULONG_PTR Entry
)
1875 MM_SECTION_PAGEOUT_CONTEXT Context
;
1876 SWAPENTRY SwapEntry
;
1877 ULONGLONG FileOffset
;
1879 PFILE_OBJECT FileObject
;
1881 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1883 BOOLEAN DirectMapped
;
1884 BOOLEAN IsImageSection
;
1885 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1888 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1891 * Get the segment and section.
1893 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1894 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1895 Context
.SectionEntry
= Entry
;
1896 Context
.CallingProcess
= Process
;
1898 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1899 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1900 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1902 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1904 FileObject
= Context
.Section
->FileObject
;
1905 DirectMapped
= FALSE
;
1907 MmLockSectionSegment(Context
.Segment
);
1910 if (FileObject
!= NULL
&&
1911 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1913 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1916 * If the file system is letting us go directly to the cache and the
1917 * memory area was mapped at an offset in the file which is page aligned
1918 * then note this is a direct mapped page.
1920 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1921 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1923 DirectMapped
= TRUE
;
1930 * This should never happen since mappings of physical memory are never
1931 * placed in the rmap lists.
1933 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1935 DPRINT1("Trying to page out from physical memory section address 0x%p "
1936 "process %p\n", Address
,
1937 Process
? Process
->UniqueProcessId
: 0);
1938 KeBugCheck(MEMORY_MANAGEMENT
);
1942 * Get the section segment entry and the physical address.
1944 if (!MmIsPagePresent(Process
, Address
))
1946 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1947 Process
? Process
->UniqueProcessId
: 0, Address
);
1948 KeBugCheck(MEMORY_MANAGEMENT
);
1950 Page
= MmGetPfnForProcess(Process
, Address
);
1951 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1954 * Check the reference count to ensure this page can be paged out
1956 if (MmGetReferenceCountPage(Page
) != 1)
1958 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1959 Page
, MmGetReferenceCountPage(Page
));
1960 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1961 MmUnlockSectionSegment(Context
.Segment
);
1962 return STATUS_UNSUCCESSFUL
;
1966 * Prepare the context structure for the rmap delete call.
1968 MmUnlockSectionSegment(Context
.Segment
);
1969 Context
.WasDirty
= FALSE
;
1970 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1971 IS_SWAP_FROM_SSE(Entry
) ||
1972 PFN_FROM_SSE(Entry
) != Page
)
1974 Context
.Private
= TRUE
;
1978 Context
.Private
= FALSE
;
1982 * Take an additional reference to the page or the VACB.
1984 if (DirectMapped
&& !Context
.Private
)
1986 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
1988 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1989 KeBugCheck(MEMORY_MANAGEMENT
);
1994 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1995 MmReferencePage(Page
);
1996 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1999 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2001 /* Since we passed in a surrogate, we'll get back the page entry
2002 * state in our context. This is intended to make intermediate
2003 * decrements of share count not release the wait entry.
2005 Entry
= Context
.SectionEntry
;
2008 * If this wasn't a private page then we should have reduced the entry to
2009 * zero by deleting all the rmaps.
2011 if (!Context
.Private
&& Entry
!= 0)
2013 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2014 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2016 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2021 * If the page wasn't dirty then we can just free it as for a readonly page.
2022 * Since we unmapped all the mappings above we know it will not suddenly
2024 * If the page is from a pagefile section and has no swap entry,
2025 * we can't free the page at this point.
2027 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2028 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2030 if (Context
.Private
)
2032 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2033 Context
.WasDirty
? "dirty" : "clean", Address
);
2034 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2036 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2038 MmSetSavedSwapEntryPage(Page
, 0);
2039 MmLockSectionSegment(Context
.Segment
);
2040 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2041 MmUnlockSectionSegment(Context
.Segment
);
2042 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2043 MiSetPageEvent(NULL
, NULL
);
2044 return(STATUS_SUCCESS
);
2047 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2049 if (Context
.Private
)
2051 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2052 Context
.WasDirty
? "dirty" : "clean", Address
);
2053 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2055 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2057 MmSetSavedSwapEntryPage(Page
, 0);
2060 MmLockSectionSegment(Context
.Segment
);
2061 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2062 MmUnlockSectionSegment(Context
.Segment
);
2064 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2065 MiSetPageEvent(NULL
, NULL
);
2066 return(STATUS_SUCCESS
);
2069 else if (!Context
.Private
&& DirectMapped
)
2073 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2075 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2078 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
, FALSE
);
2080 Status
= STATUS_SUCCESS
;
2083 if (!NT_SUCCESS(Status
))
2085 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2086 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2089 MiSetPageEvent(NULL
, NULL
);
2090 return(STATUS_SUCCESS
);
2092 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2096 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2098 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2100 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2101 MiSetPageEvent(NULL
, NULL
);
2102 return(STATUS_SUCCESS
);
2104 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2106 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2107 MmSetSavedSwapEntryPage(Page
, 0);
2108 MmLockAddressSpace(AddressSpace
);
2109 Status
= MmCreatePageFileMapping(Process
,
2112 MmUnlockAddressSpace(AddressSpace
);
2113 if (!NT_SUCCESS(Status
))
2115 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2116 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2118 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2119 MiSetPageEvent(NULL
, NULL
);
2120 return(STATUS_SUCCESS
);
2124 * If necessary, allocate an entry in the paging file for this page
2128 SwapEntry
= MmAllocSwapPage();
2131 MmShowOutOfSpaceMessagePagingFile();
2132 MmLockAddressSpace(AddressSpace
);
2134 * For private pages restore the old mappings.
2136 if (Context
.Private
)
2138 Status
= MmCreateVirtualMapping(Process
,
2140 MemoryArea
->Protect
,
2143 MmSetDirtyPage(Process
, Address
);
2152 * For non-private pages if the page wasn't direct mapped then
2153 * set it back into the section segment entry so we don't loose
2154 * our copy. Otherwise it will be handled by the cache manager.
2156 Status
= MmCreateVirtualMapping(Process
,
2158 MemoryArea
->Protect
,
2161 MmSetDirtyPage(Process
, Address
);
2165 // If we got here, the previous entry should have been a wait
2166 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2167 MmLockSectionSegment(Context
.Segment
);
2168 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2169 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2170 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2171 MmUnlockSectionSegment(Context
.Segment
);
2173 MmUnlockAddressSpace(AddressSpace
);
2174 MiSetPageEvent(NULL
, NULL
);
2175 return(STATUS_PAGEFILE_QUOTA
);
2180 * Write the page to the pagefile
2182 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2183 if (!NT_SUCCESS(Status
))
2185 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2188 * As above: undo our actions.
2189 * FIXME: Also free the swap page.
2191 MmLockAddressSpace(AddressSpace
);
2192 if (Context
.Private
)
2194 Status
= MmCreateVirtualMapping(Process
,
2196 MemoryArea
->Protect
,
2199 MmSetDirtyPage(Process
, Address
);
2206 Status
= MmCreateVirtualMapping(Process
,
2208 MemoryArea
->Protect
,
2211 MmSetDirtyPage(Process
, Address
);
2215 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2216 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2218 MmUnlockAddressSpace(AddressSpace
);
2219 MiSetPageEvent(NULL
, NULL
);
2220 return(STATUS_UNSUCCESSFUL
);
2224 * Otherwise we have succeeded.
2226 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2227 MmSetSavedSwapEntryPage(Page
, 0);
2228 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2229 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2231 MmLockSectionSegment(Context
.Segment
);
2232 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2233 MmUnlockSectionSegment(Context
.Segment
);
2237 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2240 if (Context
.Private
)
2242 MmLockAddressSpace(AddressSpace
);
2243 MmLockSectionSegment(Context
.Segment
);
2244 Status
= MmCreatePageFileMapping(Process
,
2247 /* We had placed a wait entry upon entry ... replace it before leaving */
2248 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2249 MmUnlockSectionSegment(Context
.Segment
);
2250 MmUnlockAddressSpace(AddressSpace
);
2251 if (!NT_SUCCESS(Status
))
2253 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2254 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2259 MmLockAddressSpace(AddressSpace
);
2260 MmLockSectionSegment(Context
.Segment
);
2261 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2262 /* We had placed a wait entry upon entry ... replace it before leaving */
2263 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2264 MmUnlockSectionSegment(Context
.Segment
);
2265 MmUnlockAddressSpace(AddressSpace
);
2268 MiSetPageEvent(NULL
, NULL
);
2269 return(STATUS_SUCCESS
);
2274 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2275 PMEMORY_AREA MemoryArea
,
2279 LARGE_INTEGER Offset
;
2280 PROS_SECTION_OBJECT Section
;
2281 PMM_SECTION_SEGMENT Segment
;
2283 SWAPENTRY SwapEntry
;
2287 PFILE_OBJECT FileObject
;
2288 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2289 BOOLEAN DirectMapped
;
2290 BOOLEAN IsImageSection
;
2291 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2293 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2295 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2296 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2299 * Get the segment and section.
2301 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2302 Section
= MemoryArea
->Data
.SectionData
.Section
;
2303 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2305 FileObject
= Section
->FileObject
;
2306 DirectMapped
= FALSE
;
2307 if (FileObject
!= NULL
&&
2308 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2310 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2313 * If the file system is letting us go directly to the cache and the
2314 * memory area was mapped at an offset in the file which is page aligned
2315 * then note this is a direct mapped page.
2317 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2318 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2320 DirectMapped
= TRUE
;
2325 * This should never happen since mappings of physical memory are never
2326 * placed in the rmap lists.
2328 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2330 DPRINT1("Trying to write back page from physical memory mapped at %p "
2331 "process %p\n", Address
,
2332 Process
? Process
->UniqueProcessId
: 0);
2333 KeBugCheck(MEMORY_MANAGEMENT
);
2337 * Get the section segment entry and the physical address.
2339 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2340 if (!MmIsPagePresent(Process
, Address
))
2342 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2343 Process
? Process
->UniqueProcessId
: 0, Address
);
2344 KeBugCheck(MEMORY_MANAGEMENT
);
2346 Page
= MmGetPfnForProcess(Process
, Address
);
2347 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2350 * Check for a private (COWed) page.
2352 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2353 IS_SWAP_FROM_SSE(Entry
) ||
2354 PFN_FROM_SSE(Entry
) != Page
)
2364 * Speculatively set all mappings of the page to clean.
2366 MmSetCleanAllRmaps(Page
);
2369 * If this page was direct mapped from the cache then the cache manager
2370 * will take care of writing it back to disk.
2372 if (DirectMapped
&& !Private
)
2374 //LARGE_INTEGER SOffset;
2375 ASSERT(SwapEntry
== 0);
2376 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2378 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
);
2380 MmLockSectionSegment(Segment
);
2381 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2382 MmUnlockSectionSegment(Segment
);
2383 MiSetPageEvent(NULL
, NULL
);
2384 return(STATUS_SUCCESS
);
2388 * If necessary, allocate an entry in the paging file for this page
2392 SwapEntry
= MmAllocSwapPage();
2395 MmSetDirtyAllRmaps(Page
);
2396 MiSetPageEvent(NULL
, NULL
);
2397 return(STATUS_PAGEFILE_QUOTA
);
2399 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2403 * Write the page to the pagefile
2405 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2406 if (!NT_SUCCESS(Status
))
2408 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2410 MmSetDirtyAllRmaps(Page
);
2411 MiSetPageEvent(NULL
, NULL
);
2412 return(STATUS_UNSUCCESSFUL
);
2416 * Otherwise we have succeeded.
2418 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2419 MiSetPageEvent(NULL
, NULL
);
2420 return(STATUS_SUCCESS
);
2424 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2432 PMEMORY_AREA MemoryArea
;
2433 PMM_SECTION_SEGMENT Segment
;
2434 BOOLEAN DoCOW
= FALSE
;
2436 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2438 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2439 ASSERT(MemoryArea
!= NULL
);
2440 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2441 MmLockSectionSegment(Segment
);
2443 if ((Segment
->WriteCopy
) &&
2444 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2449 if (OldProtect
!= NewProtect
)
2451 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2453 SWAPENTRY SwapEntry
;
2454 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2455 ULONG Protect
= NewProtect
;
2457 /* Wait for a wait entry to disappear */
2460 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2461 if (SwapEntry
!= MM_WAIT_ENTRY
)
2463 MiWaitForPageEvent(Process
, Address
);
2468 * If we doing COW for this segment then check if the page is
2471 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2473 LARGE_INTEGER Offset
;
2477 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2478 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2479 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2481 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2482 * IS_SWAP_FROM_SSE and we'll do the right thing.
2484 Page
= MmGetPfnForProcess(Process
, Address
);
2486 Protect
= PAGE_READONLY
;
2487 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2488 IS_SWAP_FROM_SSE(Entry
) ||
2489 PFN_FROM_SSE(Entry
) != Page
)
2491 Protect
= NewProtect
;
2495 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2497 MmSetPageProtect(Process
, Address
,
2503 MmUnlockSectionSegment(Segment
);
2508 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2509 PMEMORY_AREA MemoryArea
,
2517 ULONG_PTR MaxLength
;
2519 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2520 if (Length
> MaxLength
)
2521 Length
= (ULONG
)MaxLength
;
2523 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2524 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2526 ASSERT(Region
!= NULL
);
2528 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2529 Region
->Protect
!= Protect
)
2531 return STATUS_INVALID_PAGE_PROTECTION
;
2534 *OldProtect
= Region
->Protect
;
2535 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2536 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2537 BaseAddress
, Length
, Region
->Type
, Protect
,
2538 MmAlterViewAttributes
);
2544 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2546 PMEMORY_BASIC_INFORMATION Info
,
2547 PSIZE_T ResultLength
)
2550 PVOID RegionBaseAddress
;
2551 PROS_SECTION_OBJECT Section
;
2552 PMM_SECTION_SEGMENT Segment
;
2554 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2555 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2556 Address
, &RegionBaseAddress
);
2559 return STATUS_UNSUCCESSFUL
;
2562 Section
= MemoryArea
->Data
.SectionData
.Section
;
2563 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2565 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2566 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2567 Info
->Type
= MEM_IMAGE
;
2571 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2572 Info
->Type
= MEM_MAPPED
;
2574 Info
->BaseAddress
= RegionBaseAddress
;
2575 Info
->AllocationProtect
= MemoryArea
->Protect
;
2576 Info
->RegionSize
= Region
->Length
;
2577 Info
->State
= MEM_COMMIT
;
2578 Info
->Protect
= Region
->Protect
;
2580 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2581 return(STATUS_SUCCESS
);
2586 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2589 LARGE_INTEGER Offset
;
2591 SWAPENTRY SavedSwapEntry
;
2596 MmLockSectionSegment(Segment
);
2598 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2599 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2601 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2604 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2605 if (IS_SWAP_FROM_SSE(Entry
))
2607 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2611 Page
= PFN_FROM_SSE(Entry
);
2612 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2613 if (SavedSwapEntry
!= 0)
2615 MmSetSavedSwapEntryPage(Page
, 0);
2616 MmFreeSwapPage(SavedSwapEntry
);
2618 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2623 MmUnlockSectionSegment(Segment
);
2627 MmpDeleteSection(PVOID ObjectBody
)
2629 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2631 /* Check if it's an ARM3, or ReactOS section */
2632 if (!MiIsRosSectionObject(Section
))
2634 MiDeleteARM3Section(ObjectBody
);
2638 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2639 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2644 PMM_SECTION_SEGMENT SectionSegments
;
2647 * NOTE: Section->ImageSection can be NULL for short time
2648 * during the section creating. If we fail for some reason
2649 * until the image section is properly initialized we shouldn't
2650 * process further here.
2652 if (Section
->ImageSection
== NULL
)
2655 SectionSegments
= Section
->ImageSection
->Segments
;
2656 NrSegments
= Section
->ImageSection
->NrSegments
;
2658 for (i
= 0; i
< NrSegments
; i
++)
2660 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2662 MmLockSectionSegment(&SectionSegments
[i
]);
2664 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2665 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2667 MmUnlockSectionSegment(&SectionSegments
[i
]);
2670 MmpFreePageFileSegment(&SectionSegments
[i
]);
2676 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2679 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2682 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2684 DPRINT("Freeing section segment\n");
2685 Section
->Segment
= NULL
;
2686 MmFinalizeSegment(Segment
);
2690 DPRINT("RefCount %d\n", RefCount
);
2697 * NOTE: Section->Segment can be NULL for short time
2698 * during the section creating.
2700 if (Section
->Segment
== NULL
)
2703 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2705 MmpFreePageFileSegment(Section
->Segment
);
2706 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2707 ExFreePool(Section
->Segment
);
2708 Section
->Segment
= NULL
;
2712 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2715 if (Section
->FileObject
!= NULL
)
2718 CcRosDereferenceCache(Section
->FileObject
);
2720 ObDereferenceObject(Section
->FileObject
);
2721 Section
->FileObject
= NULL
;
2726 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2728 IN ACCESS_MASK GrantedAccess
,
2729 IN ULONG ProcessHandleCount
,
2730 IN ULONG SystemHandleCount
)
2732 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2738 MmCreatePhysicalMemorySection(VOID
)
2740 PROS_SECTION_OBJECT PhysSection
;
2742 OBJECT_ATTRIBUTES Obj
;
2743 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2744 LARGE_INTEGER SectionSize
;
2748 * Create the section mapping physical memory
2750 SectionSize
.QuadPart
= 0xFFFFFFFF;
2751 InitializeObjectAttributes(&Obj
,
2756 Status
= MmCreateSection((PVOID
)&PhysSection
,
2760 PAGE_EXECUTE_READWRITE
,
2764 if (!NT_SUCCESS(Status
))
2766 DPRINT1("Failed to create PhysicalMemory section\n");
2767 KeBugCheck(MEMORY_MANAGEMENT
);
2769 Status
= ObInsertObject(PhysSection
,
2775 if (!NT_SUCCESS(Status
))
2777 ObDereferenceObject(PhysSection
);
2779 ObCloseHandle(Handle
, KernelMode
);
2780 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2781 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2783 return(STATUS_SUCCESS
);
2789 MmInitSectionImplementation(VOID
)
2791 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2792 UNICODE_STRING Name
;
2794 DPRINT("Creating Section Object Type\n");
2796 /* Initialize the section based root */
2797 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2798 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2800 /* Initialize the Section object type */
2801 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2802 RtlInitUnicodeString(&Name
, L
"Section");
2803 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2804 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2805 ObjectTypeInitializer
.PoolType
= PagedPool
;
2806 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2807 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2808 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2809 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2810 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2811 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2812 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2814 MmCreatePhysicalMemorySection();
2816 return(STATUS_SUCCESS
);
2821 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2822 ACCESS_MASK DesiredAccess
,
2823 POBJECT_ATTRIBUTES ObjectAttributes
,
2824 PLARGE_INTEGER UMaximumSize
,
2825 ULONG SectionPageProtection
,
2826 ULONG AllocationAttributes
)
2828 * Create a section which is backed by the pagefile
2831 LARGE_INTEGER MaximumSize
;
2832 PROS_SECTION_OBJECT Section
;
2833 PMM_SECTION_SEGMENT Segment
;
2836 if (UMaximumSize
== NULL
)
2838 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2839 return(STATUS_INVALID_PARAMETER
);
2841 MaximumSize
= *UMaximumSize
;
2844 * Create the section
2846 Status
= ObCreateObject(ExGetPreviousMode(),
2847 MmSectionObjectType
,
2849 ExGetPreviousMode(),
2851 sizeof(ROS_SECTION_OBJECT
),
2854 (PVOID
*)(PVOID
)&Section
);
2855 if (!NT_SUCCESS(Status
))
2857 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2864 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2865 Section
->Type
= 'SC';
2866 Section
->Size
= 'TN';
2867 Section
->SectionPageProtection
= SectionPageProtection
;
2868 Section
->AllocationAttributes
= AllocationAttributes
;
2869 Section
->MaximumSize
= MaximumSize
;
2870 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2871 TAG_MM_SECTION_SEGMENT
);
2872 if (Segment
== NULL
)
2874 ObDereferenceObject(Section
);
2875 return(STATUS_NO_MEMORY
);
2877 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2878 Section
->Segment
= Segment
;
2879 Segment
->ReferenceCount
= 1;
2880 ExInitializeFastMutex(&Segment
->Lock
);
2881 Segment
->Image
.FileOffset
= 0;
2882 Segment
->Protection
= SectionPageProtection
;
2883 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2884 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2885 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2886 Segment
->WriteCopy
= FALSE
;
2887 Segment
->Image
.VirtualAddress
= 0;
2888 Segment
->Image
.Characteristics
= 0;
2889 *SectionObject
= Section
;
2890 MiInitializeSectionPageTable(Segment
);
2891 return(STATUS_SUCCESS
);
2896 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2897 ACCESS_MASK DesiredAccess
,
2898 POBJECT_ATTRIBUTES ObjectAttributes
,
2899 PLARGE_INTEGER UMaximumSize
,
2900 ULONG SectionPageProtection
,
2901 ULONG AllocationAttributes
,
2904 * Create a section backed by a data file
2907 PROS_SECTION_OBJECT Section
;
2909 LARGE_INTEGER MaximumSize
;
2910 PFILE_OBJECT FileObject
;
2911 PMM_SECTION_SEGMENT Segment
;
2913 IO_STATUS_BLOCK Iosb
;
2914 LARGE_INTEGER Offset
;
2916 FILE_STANDARD_INFORMATION FileInfo
;
2920 * Create the section
2922 Status
= ObCreateObject(ExGetPreviousMode(),
2923 MmSectionObjectType
,
2925 ExGetPreviousMode(),
2927 sizeof(ROS_SECTION_OBJECT
),
2931 if (!NT_SUCCESS(Status
))
2938 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2939 Section
->Type
= 'SC';
2940 Section
->Size
= 'TN';
2941 Section
->SectionPageProtection
= SectionPageProtection
;
2942 Section
->AllocationAttributes
= AllocationAttributes
;
2945 * Reference the file handle
2947 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2948 Status
= ObReferenceObjectByHandle(FileHandle
,
2951 ExGetPreviousMode(),
2952 (PVOID
*)(PVOID
)&FileObject
,
2954 if (!NT_SUCCESS(Status
))
2956 ObDereferenceObject(Section
);
2961 * FIXME: This is propably not entirely correct. We can't look into
2962 * the standard FCB header because it might not be initialized yet
2963 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2964 * standard file information is filled on first request).
2966 Status
= IoQueryFileInformation(FileObject
,
2967 FileStandardInformation
,
2968 sizeof(FILE_STANDARD_INFORMATION
),
2971 Iosb
.Information
= Length
;
2972 if (!NT_SUCCESS(Status
))
2974 ObDereferenceObject(Section
);
2975 ObDereferenceObject(FileObject
);
2980 * FIXME: Revise this once a locking order for file size changes is
2983 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2985 MaximumSize
= *UMaximumSize
;
2989 MaximumSize
= FileInfo
.EndOfFile
;
2990 /* Mapping zero-sized files isn't allowed. */
2991 if (MaximumSize
.QuadPart
== 0)
2993 ObDereferenceObject(Section
);
2994 ObDereferenceObject(FileObject
);
2995 return STATUS_FILE_INVALID
;
2999 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3001 Status
= IoSetInformation(FileObject
,
3002 FileAllocationInformation
,
3003 sizeof(LARGE_INTEGER
),
3005 if (!NT_SUCCESS(Status
))
3007 ObDereferenceObject(Section
);
3008 ObDereferenceObject(FileObject
);
3009 return(STATUS_SECTION_NOT_EXTENDED
);
3013 if (FileObject
->SectionObjectPointer
== NULL
||
3014 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3017 * Read a bit so caching is initiated for the file object.
3018 * This is only needed because MiReadPage currently cannot
3019 * handle non-cached streams.
3021 Offset
.QuadPart
= 0;
3022 Status
= ZwReadFile(FileHandle
,
3031 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3033 ObDereferenceObject(Section
);
3034 ObDereferenceObject(FileObject
);
3037 if (FileObject
->SectionObjectPointer
== NULL
||
3038 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3040 /* FIXME: handle this situation */
3041 ObDereferenceObject(Section
);
3042 ObDereferenceObject(FileObject
);
3043 return STATUS_INVALID_PARAMETER
;
3050 Status
= MmspWaitForFileLock(FileObject
);
3051 if (Status
!= STATUS_SUCCESS
)
3053 ObDereferenceObject(Section
);
3054 ObDereferenceObject(FileObject
);
3059 * If this file hasn't been mapped as a data file before then allocate a
3060 * section segment to describe the data file mapping
3062 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3064 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3065 TAG_MM_SECTION_SEGMENT
);
3066 if (Segment
== NULL
)
3068 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3069 ObDereferenceObject(Section
);
3070 ObDereferenceObject(FileObject
);
3071 return(STATUS_NO_MEMORY
);
3073 Section
->Segment
= Segment
;
3074 Segment
->ReferenceCount
= 1;
3075 ExInitializeFastMutex(&Segment
->Lock
);
3077 * Set the lock before assigning the segment to the file object
3079 ExAcquireFastMutex(&Segment
->Lock
);
3080 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3082 Segment
->Image
.FileOffset
= 0;
3083 Segment
->Protection
= SectionPageProtection
;
3084 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3085 Segment
->Image
.Characteristics
= 0;
3086 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3087 if (AllocationAttributes
& SEC_RESERVE
)
3089 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3093 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3094 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3096 Segment
->Image
.VirtualAddress
= 0;
3097 Segment
->Locked
= TRUE
;
3098 MiInitializeSectionPageTable(Segment
);
3103 * If the file is already mapped as a data file then we may need
3107 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3109 Section
->Segment
= Segment
;
3110 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3111 MmLockSectionSegment(Segment
);
3113 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3114 !(AllocationAttributes
& SEC_RESERVE
))
3116 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3117 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3120 MmUnlockSectionSegment(Segment
);
3121 Section
->FileObject
= FileObject
;
3122 Section
->MaximumSize
= MaximumSize
;
3124 CcRosReferenceCache(FileObject
);
3126 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3127 *SectionObject
= Section
;
3128 return(STATUS_SUCCESS
);
3132 TODO: not that great (declaring loaders statically, having to declare all of
3133 them, having to keep them extern, etc.), will fix in the future
3135 extern NTSTATUS NTAPI PeFmtCreateSection
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 extern NTSTATUS NTAPI ElfFmtCreateSection
3148 IN CONST VOID
* FileHeader
,
3149 IN SIZE_T FileHeaderSize
,
3151 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3153 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3154 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3157 /* TODO: this is a standard DDK/PSDK macro */
3158 #ifndef RTL_NUMBER_OF
3159 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3162 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3173 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3175 SIZE_T SizeOfSegments
;
3176 PMM_SECTION_SEGMENT Segments
;
3178 /* TODO: check for integer overflow */
3179 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3181 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3183 TAG_MM_SECTION_SEGMENT
);
3186 RtlZeroMemory(Segments
, SizeOfSegments
);
3194 ExeFmtpReadFile(IN PVOID File
,
3195 IN PLARGE_INTEGER Offset
,
3198 OUT PVOID
* AllocBase
,
3199 OUT PULONG ReadSize
)
3202 LARGE_INTEGER FileOffset
;
3204 ULONG OffsetAdjustment
;
3208 PFILE_OBJECT FileObject
= File
;
3209 IO_STATUS_BLOCK Iosb
;
3211 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3215 KeBugCheck(MEMORY_MANAGEMENT
);
3218 FileOffset
= *Offset
;
3220 /* Negative/special offset: it cannot be used in this context */
3221 if(FileOffset
.u
.HighPart
< 0)
3223 KeBugCheck(MEMORY_MANAGEMENT
);
3226 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3227 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3228 FileOffset
.u
.LowPart
= AdjustOffset
;
3230 BufferSize
= Length
+ OffsetAdjustment
;
3231 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3234 * It's ok to use paged pool, because this is a temporary buffer only used in
3235 * the loading of executables. The assumption is that MmCreateSection is
3236 * always called at low IRQLs and that these buffers don't survive a brief
3237 * initialization phase
3239 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3244 KeBugCheck(MEMORY_MANAGEMENT
);
3249 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3251 UsedSize
= (ULONG
)Iosb
.Information
;
3253 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3255 Status
= STATUS_IN_PAGE_ERROR
;
3256 ASSERT(!NT_SUCCESS(Status
));
3259 if(NT_SUCCESS(Status
))
3261 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3262 *AllocBase
= Buffer
;
3263 *ReadSize
= UsedSize
- OffsetAdjustment
;
3267 ExFreePoolWithTag(Buffer
, 'rXmM');
3274 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3275 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3276 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3281 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3285 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3287 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3288 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3295 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3299 MmspAssertSegmentsSorted(ImageSectionObject
);
3301 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3303 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3307 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3308 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3309 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3317 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3321 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3323 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3324 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3332 MmspCompareSegments(const void * x
,
3335 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3336 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3339 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3340 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3344 * Ensures an image section's segments are sorted in memory
3349 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3352 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3354 MmspAssertSegmentsSorted(ImageSectionObject
);
3358 qsort(ImageSectionObject
->Segments
,
3359 ImageSectionObject
->NrSegments
,
3360 sizeof(ImageSectionObject
->Segments
[0]),
3361 MmspCompareSegments
);
3367 * Ensures an image section's segments don't overlap in memory and don't have
3368 * gaps and don't have a null size. We let them map to overlapping file regions,
3369 * though - that's not necessarily an error
3374 MmspCheckSegmentBounds
3376 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3382 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3384 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3388 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3390 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3392 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3400 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3401 * page could be OK (Windows seems to be OK with them), and larger gaps
3402 * could lead to image sections spanning several discontiguous regions
3403 * (NtMapViewOfSection could then refuse to map them, and they could
3404 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3406 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3407 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3408 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3419 * Merges and pads an image section's segments until they all are page-aligned
3420 * and have a size that is a multiple of the page size
3425 MmspPageAlignSegments
3427 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3433 PMM_SECTION_SEGMENT EffectiveSegment
;
3435 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3437 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3442 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3444 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3447 * The first segment requires special handling
3451 ULONG_PTR VirtualAddress
;
3452 ULONG_PTR VirtualOffset
;
3454 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3456 /* Round down the virtual address to the nearest page */
3457 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3459 /* Round up the virtual size to the nearest page */
3460 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3461 EffectiveSegment
->Image
.VirtualAddress
;
3463 /* Adjust the raw address and size */
3464 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3466 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3472 * Garbage in, garbage out: unaligned base addresses make the file
3473 * offset point in curious and odd places, but that's what we were
3476 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3477 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3481 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3482 ULONG_PTR EndOfEffectiveSegment
;
3484 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3485 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3488 * The current segment begins exactly where the current effective
3489 * segment ended, therefore beginning a new effective segment
3491 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3494 ASSERT(LastSegment
<= i
);
3495 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3497 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3499 if (LastSegment
!= i
)
3502 * Copy the current segment. If necessary, the effective segment
3503 * will be expanded later
3505 *EffectiveSegment
= *Segment
;
3509 * Page-align the virtual size. We know for sure the virtual address
3512 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3513 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3516 * The current segment is still part of the current effective segment:
3517 * extend the effective segment to reflect this
3519 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3521 static const ULONG FlagsToProtection
[16] =
3529 PAGE_EXECUTE_READWRITE
,
3530 PAGE_EXECUTE_READWRITE
,
3535 PAGE_EXECUTE_WRITECOPY
,
3536 PAGE_EXECUTE_WRITECOPY
,
3537 PAGE_EXECUTE_WRITECOPY
,
3538 PAGE_EXECUTE_WRITECOPY
3541 unsigned ProtectionFlags
;
3544 * Extend the file size
3547 /* Unaligned segments must be contiguous within the file */
3548 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3549 EffectiveSegment
->RawLength
.QuadPart
))
3554 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3557 * Extend the virtual size
3559 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3561 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3562 EffectiveSegment
->Image
.VirtualAddress
;
3565 * Merge the protection
3567 EffectiveSegment
->Protection
|= Segment
->Protection
;
3569 /* Clean up redundance */
3570 ProtectionFlags
= 0;
3572 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3573 ProtectionFlags
|= 1 << 0;
3575 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3576 ProtectionFlags
|= 1 << 1;
3578 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3579 ProtectionFlags
|= 1 << 2;
3581 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3582 ProtectionFlags
|= 1 << 3;
3584 ASSERT(ProtectionFlags
< 16);
3585 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3587 /* If a segment was required to be shared and cannot, fail */
3588 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3589 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3595 * We assume no holes between segments at this point
3599 KeBugCheck(MEMORY_MANAGEMENT
);
3603 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3609 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3610 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3612 LARGE_INTEGER Offset
;
3614 PVOID FileHeaderBuffer
;
3615 ULONG FileHeaderSize
;
3617 ULONG OldNrSegments
;
3622 * Read the beginning of the file (2 pages). Should be enough to contain
3623 * all (or most) of the headers
3625 Offset
.QuadPart
= 0;
3627 /* FIXME: use FileObject instead of FileHandle */
3628 Status
= ExeFmtpReadFile (FileHandle
,
3635 if (!NT_SUCCESS(Status
))
3638 if (FileHeaderSize
== 0)
3640 ExFreePool(FileHeaderBuffer
);
3641 return STATUS_UNSUCCESSFUL
;
3645 * Look for a loader that can handle this executable
3647 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3649 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3652 /* FIXME: use FileObject instead of FileHandle */
3653 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3659 ExeFmtpAllocateSegments
);
3661 if (!NT_SUCCESS(Status
))
3663 if (ImageSectionObject
->Segments
)
3665 ExFreePool(ImageSectionObject
->Segments
);
3666 ImageSectionObject
->Segments
= NULL
;
3670 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3674 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3677 * No loader handled the format
3679 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3681 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3682 ASSERT(!NT_SUCCESS(Status
));
3685 if (!NT_SUCCESS(Status
))
3688 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3693 /* FIXME? are these values platform-dependent? */
3694 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3695 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3697 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3698 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3700 if(ImageSectionObject
->BasedAddress
== NULL
)
3702 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3703 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3705 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3709 * And now the fun part: fixing the segments
3712 /* Sort them by virtual address */
3713 MmspSortSegments(ImageSectionObject
, Flags
);
3715 /* Ensure they don't overlap in memory */
3716 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3717 return STATUS_INVALID_IMAGE_FORMAT
;
3719 /* Ensure they are aligned */
3720 OldNrSegments
= ImageSectionObject
->NrSegments
;
3722 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3723 return STATUS_INVALID_IMAGE_FORMAT
;
3725 /* Trim them if the alignment phase merged some of them */
3726 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3728 PMM_SECTION_SEGMENT Segments
;
3729 SIZE_T SizeOfSegments
;
3731 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3733 Segments
= ExAllocatePoolWithTag(PagedPool
,
3735 TAG_MM_SECTION_SEGMENT
);
3737 if (Segments
== NULL
)
3738 return STATUS_INSUFFICIENT_RESOURCES
;
3740 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3741 ExFreePool(ImageSectionObject
->Segments
);
3742 ImageSectionObject
->Segments
= Segments
;
3745 /* And finish their initialization */
3746 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3748 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3749 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3750 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3753 ASSERT(NT_SUCCESS(Status
));
3758 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3759 ACCESS_MASK DesiredAccess
,
3760 POBJECT_ATTRIBUTES ObjectAttributes
,
3761 PLARGE_INTEGER UMaximumSize
,
3762 ULONG SectionPageProtection
,
3763 ULONG AllocationAttributes
,
3764 PFILE_OBJECT FileObject
)
3766 PROS_SECTION_OBJECT Section
;
3768 PMM_SECTION_SEGMENT SectionSegments
;
3769 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3772 if (FileObject
== NULL
)
3773 return STATUS_INVALID_FILE_FOR_SECTION
;
3776 * Create the section
3778 Status
= ObCreateObject (ExGetPreviousMode(),
3779 MmSectionObjectType
,
3781 ExGetPreviousMode(),
3783 sizeof(ROS_SECTION_OBJECT
),
3786 (PVOID
*)(PVOID
)&Section
);
3787 if (!NT_SUCCESS(Status
))
3789 ObDereferenceObject(FileObject
);
3796 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3797 Section
->Type
= 'SC';
3798 Section
->Size
= 'TN';
3799 Section
->SectionPageProtection
= SectionPageProtection
;
3800 Section
->AllocationAttributes
= AllocationAttributes
;
3804 * Initialized caching for this file object if previously caching
3805 * was initialized for the same on disk file
3807 Status
= CcTryToInitializeFileCache(FileObject
);
3809 Status
= STATUS_SUCCESS
;
3812 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3814 NTSTATUS StatusExeFmt
;
3816 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3817 if (ImageSectionObject
== NULL
)
3819 ObDereferenceObject(FileObject
);
3820 ObDereferenceObject(Section
);
3821 return(STATUS_NO_MEMORY
);
3824 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3826 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3828 if (!NT_SUCCESS(StatusExeFmt
))
3830 if(ImageSectionObject
->Segments
!= NULL
)
3831 ExFreePool(ImageSectionObject
->Segments
);
3833 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3834 ObDereferenceObject(Section
);
3835 ObDereferenceObject(FileObject
);
3836 return(StatusExeFmt
);
3839 Section
->ImageSection
= ImageSectionObject
;
3840 ASSERT(ImageSectionObject
->Segments
);
3845 Status
= MmspWaitForFileLock(FileObject
);
3846 if (!NT_SUCCESS(Status
))
3848 ExFreePool(ImageSectionObject
->Segments
);
3849 ExFreePool(ImageSectionObject
);
3850 ObDereferenceObject(Section
);
3851 ObDereferenceObject(FileObject
);
3855 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3856 ImageSectionObject
, NULL
))
3859 * An other thread has initialized the same image in the background
3861 ExFreePool(ImageSectionObject
->Segments
);
3862 ExFreePool(ImageSectionObject
);
3863 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3864 Section
->ImageSection
= ImageSectionObject
;
3865 SectionSegments
= ImageSectionObject
->Segments
;
3867 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3869 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3873 Status
= StatusExeFmt
;
3880 Status
= MmspWaitForFileLock(FileObject
);
3881 if (Status
!= STATUS_SUCCESS
)
3883 ObDereferenceObject(Section
);
3884 ObDereferenceObject(FileObject
);
3888 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3889 Section
->ImageSection
= ImageSectionObject
;
3890 SectionSegments
= ImageSectionObject
->Segments
;
3893 * Otherwise just reference all the section segments
3895 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3897 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3900 Status
= STATUS_SUCCESS
;
3902 Section
->FileObject
= FileObject
;
3904 CcRosReferenceCache(FileObject
);
3906 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3907 *SectionObject
= Section
;
3914 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3915 PROS_SECTION_OBJECT Section
,
3916 PMM_SECTION_SEGMENT Segment
,
3921 ULONG AllocationType
)
3927 if (Segment
->WriteCopy
)
3929 /* We have to do this because the not present fault
3930 * and access fault handlers depend on the protection
3931 * that should be granted AFTER the COW fault takes
3932 * place to be in Region->Protect. The not present fault
3933 * handler changes this to the correct protection for COW when
3934 * mapping the pages into the process's address space. If a COW
3935 * fault takes place, the access fault handler sets the page protection
3936 * to these values for the newly copied pages
3938 if (Protect
== PAGE_WRITECOPY
)
3939 Protect
= PAGE_READWRITE
;
3940 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3941 Protect
= PAGE_EXECUTE_READWRITE
;
3944 if (*BaseAddress
== NULL
)
3945 Granularity
= MM_ALLOCATION_GRANULARITY
;
3947 Granularity
= PAGE_SIZE
;
3950 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3952 LARGE_INTEGER FileOffset
;
3953 FileOffset
.QuadPart
= ViewOffset
;
3954 ObReferenceObject(Section
);
3955 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3958 Status
= MmCreateMemoryArea(AddressSpace
,
3959 MEMORY_AREA_SECTION_VIEW
,
3967 if (!NT_SUCCESS(Status
))
3969 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3970 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3974 ObReferenceObject((PVOID
)Section
);
3976 MArea
->Data
.SectionData
.Segment
= Segment
;
3977 MArea
->Data
.SectionData
.Section
= Section
;
3978 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3979 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3980 ViewSize
, 0, Protect
);
3982 return(STATUS_SUCCESS
);
3987 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3988 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3991 PFILE_OBJECT FileObject
;
3992 PROS_SHARED_CACHE_MAP SharedCacheMap
;
3993 LARGE_INTEGER Offset
;
3994 SWAPENTRY SavedSwapEntry
;
3995 PROS_SECTION_OBJECT Section
;
3996 PMM_SECTION_SEGMENT Segment
;
3997 PMMSUPPORT AddressSpace
;
4000 AddressSpace
= (PMMSUPPORT
)Context
;
4001 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4003 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4005 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
4006 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
4008 Section
= MemoryArea
->Data
.SectionData
.Section
;
4009 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4011 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4012 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
4014 MmUnlockSectionSegment(Segment
);
4015 MmUnlockAddressSpace(AddressSpace
);
4017 MiWaitForPageEvent(NULL
, NULL
);
4019 MmLockAddressSpace(AddressSpace
);
4020 MmLockSectionSegment(Segment
);
4021 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4025 * For a dirty, datafile, non-private page mark it as dirty in the
4028 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4030 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4032 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4033 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4035 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4037 ASSERT(SwapEntry
== 0);
4046 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4048 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4049 KeBugCheck(MEMORY_MANAGEMENT
);
4051 MmFreeSwapPage(SwapEntry
);
4055 if (IS_SWAP_FROM_SSE(Entry
) ||
4056 Page
!= PFN_FROM_SSE(Entry
))
4061 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4063 DPRINT1("Found a private page in a pagefile section.\n");
4064 KeBugCheck(MEMORY_MANAGEMENT
);
4067 * Just dereference private pages
4069 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4070 if (SavedSwapEntry
!= 0)
4072 MmFreeSwapPage(SavedSwapEntry
);
4073 MmSetSavedSwapEntryPage(Page
, 0);
4075 MmDeleteRmap(Page
, Process
, Address
);
4076 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4080 MmDeleteRmap(Page
, Process
, Address
);
4081 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4087 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4091 PMEMORY_AREA MemoryArea
;
4092 PROS_SECTION_OBJECT Section
;
4093 PMM_SECTION_SEGMENT Segment
;
4094 PLIST_ENTRY CurrentEntry
;
4095 PMM_REGION CurrentRegion
;
4096 PLIST_ENTRY RegionListHead
;
4098 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4100 if (MemoryArea
== NULL
)
4102 return(STATUS_UNSUCCESSFUL
);
4105 Section
= MemoryArea
->Data
.SectionData
.Section
;
4106 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4109 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4111 MmUnlockAddressSpace(AddressSpace
);
4112 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4113 MmLockAddressSpace(AddressSpace
);
4119 MemoryArea
->DeleteInProgress
= TRUE
;
4121 MmLockSectionSegment(Segment
);
4123 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4124 while (!IsListEmpty(RegionListHead
))
4126 CurrentEntry
= RemoveHeadList(RegionListHead
);
4127 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4128 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4131 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4133 Status
= MmFreeMemoryArea(AddressSpace
,
4140 Status
= MmFreeMemoryArea(AddressSpace
,
4145 MmUnlockSectionSegment(Segment
);
4146 ObDereferenceObject(Section
);
4152 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4153 IN PVOID BaseAddress
,
4157 PMEMORY_AREA MemoryArea
;
4158 PMMSUPPORT AddressSpace
;
4159 PROS_SECTION_OBJECT Section
;
4160 PVOID ImageBaseAddress
= 0;
4162 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4163 Process
, BaseAddress
);
4167 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4169 MmLockAddressSpace(AddressSpace
);
4170 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4172 if (MemoryArea
== NULL
||
4173 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4174 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4175 MemoryArea
->DeleteInProgress
)
4177 if (MemoryArea
) NT_ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4178 MmUnlockAddressSpace(AddressSpace
);
4179 return STATUS_NOT_MAPPED_VIEW
;
4182 Section
= MemoryArea
->Data
.SectionData
.Section
;
4184 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4188 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4189 PMM_SECTION_SEGMENT SectionSegments
;
4190 PMM_SECTION_SEGMENT Segment
;
4192 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4193 ImageSectionObject
= Section
->ImageSection
;
4194 SectionSegments
= ImageSectionObject
->Segments
;
4195 NrSegments
= ImageSectionObject
->NrSegments
;
4197 MemoryArea
->DeleteInProgress
= TRUE
;
4199 /* Search for the current segment within the section segments
4200 * and calculate the image base address */
4201 for (i
= 0; i
< NrSegments
; i
++)
4203 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4205 if (Segment
== &SectionSegments
[i
])
4207 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4212 if (i
>= NrSegments
)
4214 KeBugCheck(MEMORY_MANAGEMENT
);
4217 for (i
= 0; i
< NrSegments
; i
++)
4219 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4221 PVOID SBaseAddress
= (PVOID
)
4222 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4224 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4225 NT_ASSERT(NT_SUCCESS(Status
));
4231 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4232 NT_ASSERT(NT_SUCCESS(Status
));
4235 MmUnlockAddressSpace(AddressSpace
);
4237 /* Notify debugger */
4238 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4240 return(STATUS_SUCCESS
);
4247 * Queries the information of a section object.
4249 * @param SectionHandle
4250 * Handle to the section object. It must be opened with SECTION_QUERY
4252 * @param SectionInformationClass
4253 * Index to a certain information structure. Can be either
4254 * SectionBasicInformation or SectionImageInformation. The latter
4255 * is valid only for sections that were created with the SEC_IMAGE
4257 * @param SectionInformation
4258 * Caller supplies storage for resulting information.
4260 * Size of the supplied storage.
4261 * @param ResultLength
4269 NtQuerySection(IN HANDLE SectionHandle
,
4270 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4271 OUT PVOID SectionInformation
,
4272 IN SIZE_T SectionInformationLength
,
4273 OUT PSIZE_T ResultLength OPTIONAL
)
4275 PROS_SECTION_OBJECT Section
;
4276 KPROCESSOR_MODE PreviousMode
;
4280 PreviousMode
= ExGetPreviousMode();
4282 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4284 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4286 (ULONG
)SectionInformationLength
,
4291 if(!NT_SUCCESS(Status
))
4293 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4297 Status
= ObReferenceObjectByHandle(SectionHandle
,
4299 MmSectionObjectType
,
4301 (PVOID
*)(PVOID
)&Section
,
4303 if (NT_SUCCESS(Status
))
4305 switch (SectionInformationClass
)
4307 case SectionBasicInformation
:
4309 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4313 Sbi
->Attributes
= Section
->AllocationAttributes
;
4314 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4316 Sbi
->BaseAddress
= 0;
4317 Sbi
->Size
.QuadPart
= 0;
4321 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4322 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4325 if (ResultLength
!= NULL
)
4327 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4329 Status
= STATUS_SUCCESS
;
4331 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4333 Status
= _SEH2_GetExceptionCode();
4340 case SectionImageInformation
:
4342 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4346 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4348 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4349 ImageSectionObject
= Section
->ImageSection
;
4351 *Sii
= ImageSectionObject
->ImageInformation
;
4354 if (ResultLength
!= NULL
)
4356 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4358 Status
= STATUS_SUCCESS
;
4360 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4362 Status
= _SEH2_GetExceptionCode();
4370 ObDereferenceObject(Section
);
4376 /**********************************************************************
4378 * MmMapViewOfSection
4381 * Maps a view of a section into the virtual address space of a
4386 * Pointer to the section object.
4389 * Pointer to the process.
4392 * Desired base address (or NULL) on entry;
4393 * Actual base address of the view on exit.
4396 * Number of high order address bits that must be zero.
4399 * Size in bytes of the initially committed section of
4403 * Offset in bytes from the beginning of the section
4404 * to the beginning of the view.
4407 * Desired length of map (or zero to map all) on entry
4408 * Actual length mapped on exit.
4410 * InheritDisposition
4411 * Specified how the view is to be shared with
4415 * Type of allocation for the pages.
4418 * Protection for the committed region of the view.
4426 MmMapViewOfSection(IN PVOID SectionObject
,
4427 IN PEPROCESS Process
,
4428 IN OUT PVOID
*BaseAddress
,
4429 IN ULONG_PTR ZeroBits
,
4430 IN SIZE_T CommitSize
,
4431 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4432 IN OUT PSIZE_T ViewSize
,
4433 IN SECTION_INHERIT InheritDisposition
,
4434 IN ULONG AllocationType
,
4437 PROS_SECTION_OBJECT Section
;
4438 PMMSUPPORT AddressSpace
;
4440 NTSTATUS Status
= STATUS_SUCCESS
;
4441 BOOLEAN NotAtBase
= FALSE
;
4443 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4445 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4446 return MmMapViewOfArm3Section(SectionObject
,
4460 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4462 return STATUS_INVALID_PAGE_PROTECTION
;
4466 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4467 AddressSpace
= &Process
->Vm
;
4469 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4471 MmLockAddressSpace(AddressSpace
);
4473 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4477 ULONG_PTR ImageBase
;
4479 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4480 PMM_SECTION_SEGMENT SectionSegments
;
4482 ImageSectionObject
= Section
->ImageSection
;
4483 SectionSegments
= ImageSectionObject
->Segments
;
4484 NrSegments
= ImageSectionObject
->NrSegments
;
4486 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4489 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4493 for (i
= 0; i
< NrSegments
; i
++)
4495 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4497 ULONG_PTR MaxExtent
;
4498 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4499 SectionSegments
[i
].Length
.QuadPart
);
4500 ImageSize
= max(ImageSize
, MaxExtent
);
4504 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4506 /* Check for an illegal base address */
4507 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4508 ((ImageBase
+ ImageSize
) < ImageSize
))
4510 NT_ASSERT(*BaseAddress
== NULL
);
4511 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4512 MM_VIRTMEM_GRANULARITY
);
4515 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4517 NT_ASSERT(*BaseAddress
== NULL
);
4518 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4522 /* Check there is enough space to map the section at that point. */
4523 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4524 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4526 /* Fail if the user requested a fixed base address. */
4527 if ((*BaseAddress
) != NULL
)
4529 MmUnlockAddressSpace(AddressSpace
);
4530 return(STATUS_CONFLICTING_ADDRESSES
);
4532 /* Otherwise find a gap to map the image. */
4533 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4536 MmUnlockAddressSpace(AddressSpace
);
4537 return(STATUS_CONFLICTING_ADDRESSES
);
4539 /* Remember that we loaded image at a different base address */
4543 for (i
= 0; i
< NrSegments
; i
++)
4545 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4547 PVOID SBaseAddress
= (PVOID
)
4548 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4549 MmLockSectionSegment(&SectionSegments
[i
]);
4550 Status
= MmMapViewOfSegment(AddressSpace
,
4552 &SectionSegments
[i
],
4554 SectionSegments
[i
].Length
.LowPart
,
4555 SectionSegments
[i
].Protection
,
4558 MmUnlockSectionSegment(&SectionSegments
[i
]);
4559 if (!NT_SUCCESS(Status
))
4561 MmUnlockAddressSpace(AddressSpace
);
4567 *BaseAddress
= (PVOID
)ImageBase
;
4568 *ViewSize
= ImageSize
;
4572 /* check for write access */
4573 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4574 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4576 MmUnlockAddressSpace(AddressSpace
);
4577 return STATUS_SECTION_PROTECTION
;
4579 /* check for read access */
4580 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4581 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4583 MmUnlockAddressSpace(AddressSpace
);
4584 return STATUS_SECTION_PROTECTION
;
4586 /* check for execute access */
4587 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4588 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4590 MmUnlockAddressSpace(AddressSpace
);
4591 return STATUS_SECTION_PROTECTION
;
4594 if (ViewSize
== NULL
)
4596 /* Following this pointer would lead to us to the dark side */
4597 /* What to do? Bugcheck? Return status? Do the mambo? */
4598 KeBugCheck(MEMORY_MANAGEMENT
);
4601 if (SectionOffset
== NULL
)
4607 ViewOffset
= SectionOffset
->u
.LowPart
;
4610 if ((ViewOffset
% PAGE_SIZE
) != 0)
4612 MmUnlockAddressSpace(AddressSpace
);
4613 return(STATUS_MAPPED_ALIGNMENT
);
4616 if ((*ViewSize
) == 0)
4618 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4620 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4622 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4625 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4627 MmLockSectionSegment(Section
->Segment
);
4628 Status
= MmMapViewOfSegment(AddressSpace
,
4635 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4636 MmUnlockSectionSegment(Section
->Segment
);
4637 if (!NT_SUCCESS(Status
))
4639 MmUnlockAddressSpace(AddressSpace
);
4644 MmUnlockAddressSpace(AddressSpace
);
4645 NT_ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4648 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4650 Status
= STATUS_SUCCESS
;
4659 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4660 IN PLARGE_INTEGER NewFileSize
)
4662 /* Check whether an ImageSectionObject exists */
4663 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4665 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4669 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4671 PMM_SECTION_SEGMENT Segment
;
4673 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4676 if (Segment
->ReferenceCount
!= 0)
4679 CC_FILE_SIZES FileSizes
;
4681 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4684 /* Check size of file */
4685 if (SectionObjectPointer
->SharedCacheMap
)
4687 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4692 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4701 /* Check size of file */
4702 if (SectionObjectPointer
->SharedCacheMap
)
4704 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4705 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4714 /* Something must gone wrong
4715 * how can we have a Section but no
4717 DPRINT("ERROR: DataSectionObject without reference!\n");
4721 DPRINT("FIXME: didn't check for outstanding write probes\n");
4733 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4734 IN MMFLUSH_TYPE FlushType
)
4736 BOOLEAN Result
= TRUE
;
4738 PMM_SECTION_SEGMENT Segment
;
4743 case MmFlushForDelete
:
4744 if (SectionObjectPointer
->ImageSectionObject
||
4745 SectionObjectPointer
->DataSectionObject
)
4750 CcRosRemoveIfClosed(SectionObjectPointer
);
4753 case MmFlushForWrite
:
4755 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4757 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4760 if (SectionObjectPointer
->ImageSectionObject
)
4762 DPRINT1("SectionObject has ImageSection\n");
4768 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4770 DPRINT("Result %d\n", Result
);
4782 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4783 OUT PVOID
* MappedBase
,
4784 IN OUT PSIZE_T ViewSize
)
4786 PROS_SECTION_OBJECT Section
;
4787 PMMSUPPORT AddressSpace
;
4791 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4793 return MiMapViewInSystemSpace(SectionObject
,
4799 DPRINT("MmMapViewInSystemSpace() called\n");
4801 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4802 AddressSpace
= MmGetKernelAddressSpace();
4804 MmLockAddressSpace(AddressSpace
);
4807 if ((*ViewSize
) == 0)
4809 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4811 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4813 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4816 MmLockSectionSegment(Section
->Segment
);
4819 Status
= MmMapViewOfSegment(AddressSpace
,
4828 MmUnlockSectionSegment(Section
->Segment
);
4829 MmUnlockAddressSpace(AddressSpace
);
4836 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4838 PMMSUPPORT AddressSpace
;
4841 DPRINT("MmUnmapViewInSystemSpace() called\n");
4843 AddressSpace
= MmGetKernelAddressSpace();
4845 MmLockAddressSpace(AddressSpace
);
4847 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4849 MmUnlockAddressSpace(AddressSpace
);
4854 /**********************************************************************
4859 * Creates a section object.
4862 * SectionObject (OUT)
4863 * Caller supplied storage for the resulting pointer
4864 * to a SECTION_OBJECT instance;
4867 * Specifies the desired access to the section can be a
4869 * STANDARD_RIGHTS_REQUIRED |
4871 * SECTION_MAP_WRITE |
4872 * SECTION_MAP_READ |
4873 * SECTION_MAP_EXECUTE
4875 * ObjectAttributes [OPTIONAL]
4876 * Initialized attributes for the object can be used
4877 * to create a named section;
4880 * Maximizes the size of the memory section. Must be
4881 * non-NULL for a page-file backed section.
4882 * If value specified for a mapped file and the file is
4883 * not large enough, file will be extended.
4885 * SectionPageProtection
4886 * Can be a combination of:
4892 * AllocationAttributes
4893 * Can be a combination of:
4898 * Handle to a file to create a section mapped to a file
4899 * instead of a memory backed section;
4910 MmCreateSection (OUT PVOID
* Section
,
4911 IN ACCESS_MASK DesiredAccess
,
4912 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4913 IN PLARGE_INTEGER MaximumSize
,
4914 IN ULONG SectionPageProtection
,
4915 IN ULONG AllocationAttributes
,
4916 IN HANDLE FileHandle OPTIONAL
,
4917 IN PFILE_OBJECT FileObject OPTIONAL
)
4921 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4923 /* Check if an ARM3 section is being created instead */
4924 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4926 if (!(FileObject
) && !(FileHandle
))
4928 return MmCreateArm3Section(Section
,
4932 SectionPageProtection
,
4933 AllocationAttributes
&~ 1,
4939 /* Convert section flag to page flag */
4940 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4942 /* Check to make sure the protection is correct. Nt* does this already */
4943 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4944 if (Protection
== MM_INVALID_PROTECTION
)
4946 DPRINT1("Page protection is invalid\n");
4947 return STATUS_INVALID_PAGE_PROTECTION
;
4950 /* Check if this is going to be a data or image backed file section */
4951 if ((FileHandle
) || (FileObject
))
4953 /* These cannot be mapped with large pages */
4954 if (AllocationAttributes
& SEC_LARGE_PAGES
)
4956 DPRINT1("Large pages cannot be used with an image mapping\n");
4957 return STATUS_INVALID_PARAMETER_6
;
4960 /* Did the caller pass an object? */
4963 /* Reference the object directly */
4964 ObReferenceObject(FileObject
);
4968 /* Reference the file handle to get the object */
4969 Status
= ObReferenceObjectByHandle(FileHandle
,
4970 MmMakeFileAccess
[Protection
],
4972 ExGetPreviousMode(),
4973 (PVOID
*)&FileObject
,
4975 if (!NT_SUCCESS(Status
))
4977 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
4984 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
4985 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
4988 #ifndef NEWCC // A hack for initializing caching.
4989 // This is needed only in the old case.
4992 IO_STATUS_BLOCK Iosb
;
4995 LARGE_INTEGER ByteOffset
;
4996 ByteOffset
.QuadPart
= 0;
4997 Status
= ZwReadFile(FileHandle
,
5006 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5008 DPRINT1("CC failure: %lx\n", Status
);
5011 // Caching is initialized...
5015 if (AllocationAttributes
& SEC_IMAGE
)
5017 Status
= MmCreateImageSection(SectionObject
,
5021 SectionPageProtection
,
5022 AllocationAttributes
,
5026 else if (FileHandle
!= NULL
)
5028 Status
= MmCreateDataFileSection(SectionObject
,
5032 SectionPageProtection
,
5033 AllocationAttributes
,
5036 ObDereferenceObject(FileObject
);
5039 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5041 Status
= MmCreateCacheSection(SectionObject
,
5045 SectionPageProtection
,
5046 AllocationAttributes
,
5052 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5054 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5056 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5057 Status
= MmCreatePageFileSection(SectionObject
,
5061 SectionPageProtection
,
5062 AllocationAttributes
);