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_INVALID_IMAGE_PROTECT
;
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_PROTECT
;
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 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
341 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
342 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
344 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
345 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
347 /* the buffer doesn't contain the whole NT header: read it from the file */
348 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
349 goto l_ReadHeaderFromFile
;
352 /* read information from the NT header */
353 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
354 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
356 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
358 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
359 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
361 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
363 switch(piohOptHeader
->Magic
)
365 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
366 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
370 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
373 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
374 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
376 /* See [1], section 3.4.2 */
377 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
379 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
380 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
382 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
383 DIE(("The section alignment is smaller than the file alignment\n"));
385 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
386 nFileAlignment
= piohOptHeader
->FileAlignment
;
388 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
389 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
393 nSectionAlignment
= PAGE_SIZE
;
394 nFileAlignment
= PAGE_SIZE
;
397 ASSERT(IsPowerOf2(nSectionAlignment
));
398 ASSERT(IsPowerOf2(nFileAlignment
));
400 switch(piohOptHeader
->Magic
)
403 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
405 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
406 ImageBase
= piohOptHeader
->ImageBase
;
408 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
409 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
411 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
412 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
414 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
415 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
417 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
419 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
421 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
422 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
424 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
425 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
429 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
431 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
432 piohOptHeader
->AddressOfEntryPoint
);
435 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
436 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
438 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
440 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
442 if (piohOptHeader
->AddressOfEntryPoint
== 0)
444 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
448 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
449 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
451 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
453 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
456 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
457 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
458 * magic to any binary.
460 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
461 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
462 * the SxS support -- at which point, duh, this should be removed.
464 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
466 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
473 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
475 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
477 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
479 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
481 ImageBase
= pioh64OptHeader
->ImageBase
;
482 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
483 DIE(("ImageBase exceeds the address space\n"));
486 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
488 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
489 DIE(("SizeOfImage exceeds the address space\n"));
491 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
494 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
496 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
497 DIE(("SizeOfStackReserve exceeds the address space\n"));
499 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
502 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
504 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
505 DIE(("SizeOfStackCommit exceeds the address space\n"));
507 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
510 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
512 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
514 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
515 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
517 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
518 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
522 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
524 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
525 pioh64OptHeader
->AddressOfEntryPoint
);
528 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
529 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
531 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
533 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
535 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
537 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
541 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
542 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
544 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
545 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
552 /* [1], section 3.4.2 */
553 if((ULONG_PTR
)ImageBase
% 0x10000)
554 DIE(("ImageBase is not aligned on a 64KB boundary"));
556 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
557 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
558 ImageSectionObject
->ImageInformation
.GpValue
= 0;
559 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
560 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
562 /* SECTION HEADERS */
563 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
565 /* see [1], section 3.3 */
566 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
567 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
570 * the additional segment is for the file's headers. They need to be present for
571 * the benefit of the dynamic loader (to locate exports, defaults for thread
572 * parameters, resources, etc.)
574 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
576 /* file offset for the section headers */
577 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
578 DIE(("Offset overflow\n"));
580 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
581 DIE(("Offset overflow\n"));
583 /* size of the section headers */
584 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
585 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
587 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
588 DIE(("Section headers too large\n"));
590 /* size of the executable's headers */
591 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
593 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
594 // DIE(("SizeOfHeaders is not aligned\n"));
596 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
597 DIE(("The section headers overflow SizeOfHeaders\n"));
599 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
601 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
602 DIE(("Overflow aligning the size of headers\n"));
609 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
610 /* WARNING: piohOptHeader IS NO LONGER USABLE */
611 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
613 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
614 pishSectionHeaders
= NULL
;
618 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
619 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
621 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
622 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
626 * the buffer doesn't contain the section headers, or the alignment is wrong:
627 * read the headers from the file
629 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
630 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
635 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
637 /* read the header from the file */
638 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
640 if(!NT_SUCCESS(nStatus
))
641 DIE(("ReadFile failed with status %08X\n", nStatus
));
645 ASSERT(cbReadSize
> 0);
647 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
649 /* the buffer doesn't contain all the section headers */
650 if(cbReadSize
< cbSectionHeadersSize
)
651 DIE(("The file doesn't contain all of the section headers\n"));
653 pishSectionHeaders
= pData
;
655 /* object still not aligned: copy it to the beginning of the buffer */
656 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
658 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
659 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
660 pishSectionHeaders
= pBuffer
;
665 /* allocate the segments */
666 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
667 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
669 if(ImageSectionObject
->Segments
== NULL
)
670 DIE(("AllocateSegments failed\n"));
672 /* initialize the headers segment */
673 pssSegments
= ImageSectionObject
->Segments
;
675 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
677 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
678 DIE(("Cannot align the size of the section headers\n"));
680 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
681 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
682 DIE(("Cannot align the size of the section headers\n"));
684 pssSegments
[0].Image
.FileOffset
= 0;
685 pssSegments
[0].Protection
= PAGE_READONLY
;
686 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
687 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
688 pssSegments
[0].Image
.VirtualAddress
= 0;
689 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
690 pssSegments
[0].WriteCopy
= TRUE
;
692 /* skip the headers segment */
695 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
697 /* convert the executable sections into segments. See also [1], section 4 */
698 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
700 ULONG nCharacteristics
;
702 /* validate the alignment */
703 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
704 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
706 /* sections must be contiguous, ordered by base address and non-overlapping */
707 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
708 DIE(("Memory gap between section %u and the previous\n", i
));
710 /* ignore explicit BSS sections */
711 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
713 /* validate the alignment */
715 /* Yes, this should be a multiple of FileAlignment, but there's
716 * stuff out there that isn't. We can cope with that
718 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
719 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
722 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
723 // DIE(("PointerToRawData[%u] is not aligned\n", i));
726 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
727 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
731 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
732 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
735 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
737 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
739 /* no explicit protection */
740 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
742 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
743 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
745 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
746 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
748 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
749 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
752 /* see table above */
753 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
754 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
756 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
757 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
759 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
761 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
762 /* FIXME: always false */
763 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
764 DIE(("Cannot align the virtual size of section %u\n", i
));
766 if(pssSegments
[i
].Length
.QuadPart
== 0)
767 DIE(("Virtual size of section %u is null\n", i
));
769 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
770 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
772 /* ensure the memory image is no larger than 4GB */
773 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
774 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
775 DIE(("The image is too large\n"));
778 if(nSectionAlignment
>= PAGE_SIZE
)
779 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
782 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
792 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
793 * ARGUMENTS: PFILE_OBJECT to wait for.
794 * RETURNS: Status of the wait.
797 MmspWaitForFileLock(PFILE_OBJECT File
)
799 return STATUS_SUCCESS
;
800 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
805 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
807 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
809 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
810 PMM_SECTION_SEGMENT SectionSegments
;
814 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
815 NrSegments
= ImageSectionObject
->NrSegments
;
816 SectionSegments
= ImageSectionObject
->Segments
;
817 for (i
= 0; i
< NrSegments
; i
++)
819 if (SectionSegments
[i
].ReferenceCount
!= 0)
821 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
822 SectionSegments
[i
].ReferenceCount
);
823 KeBugCheck(MEMORY_MANAGEMENT
);
825 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
827 ExFreePool(ImageSectionObject
->Segments
);
828 ExFreePool(ImageSectionObject
);
829 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
831 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
833 PMM_SECTION_SEGMENT Segment
;
835 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
838 if (Segment
->ReferenceCount
!= 0)
840 DPRINT1("Data segment still referenced\n");
841 KeBugCheck(MEMORY_MANAGEMENT
);
843 MmFreePageTablesSectionSegment(Segment
, NULL
);
845 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
851 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
852 PLARGE_INTEGER Offset
)
856 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
859 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
860 KeBugCheck(MEMORY_MANAGEMENT
);
862 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
864 DPRINT1("Maximum share count reached\n");
865 KeBugCheck(MEMORY_MANAGEMENT
);
867 if (IS_SWAP_FROM_SSE(Entry
))
869 KeBugCheck(MEMORY_MANAGEMENT
);
871 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
872 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
877 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
878 PMM_SECTION_SEGMENT Segment
,
879 PLARGE_INTEGER Offset
,
884 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
885 BOOLEAN IsDirectMapped
= FALSE
;
889 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
890 KeBugCheck(MEMORY_MANAGEMENT
);
892 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
894 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
895 KeBugCheck(MEMORY_MANAGEMENT
);
897 if (IS_SWAP_FROM_SSE(Entry
))
899 KeBugCheck(MEMORY_MANAGEMENT
);
901 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
903 * If we reducing the share count of this entry to zero then set the entry
904 * to zero and tell the cache the page is no longer mapped.
906 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
908 PFILE_OBJECT FileObject
;
909 SWAPENTRY SavedSwapEntry
;
912 PROS_SHARED_CACHE_MAP SharedCacheMap
;
913 BOOLEAN IsImageSection
;
914 LARGE_INTEGER FileOffset
;
916 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
917 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
920 Page
= PFN_FROM_SSE(Entry
);
921 FileObject
= Section
->FileObject
;
922 if (FileObject
!= NULL
&&
923 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
927 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
928 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
931 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
932 IsDirectMapped
= TRUE
;
934 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
.QuadPart
, Dirty
);
936 Status
= STATUS_SUCCESS
;
938 if (!NT_SUCCESS(Status
))
940 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
941 KeBugCheck(MEMORY_MANAGEMENT
);
947 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
948 if (SavedSwapEntry
== 0)
951 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
952 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
956 * Try to page out this page and set the swap entry
957 * within the section segment. There exist no rmap entry
958 * for this page. The pager thread can't page out a
959 * page without a rmap entry.
961 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
962 if (InEntry
) *InEntry
= Entry
;
963 MiSetPageEvent(NULL
, NULL
);
967 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
968 if (InEntry
) *InEntry
= 0;
969 MiSetPageEvent(NULL
, NULL
);
972 MmReleasePageMemoryConsumer(MC_USER
, Page
);
978 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
979 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
987 * We hold all locks. Nobody can do something with the current
988 * process and the current segment (also not within an other process).
991 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
992 if (!NT_SUCCESS(Status
))
994 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
995 KeBugCheck(MEMORY_MANAGEMENT
);
998 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
999 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
1000 MmSetSavedSwapEntryPage(Page
, 0);
1001 MiSetPageEvent(NULL
, NULL
);
1003 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1007 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1008 KeBugCheck(MEMORY_MANAGEMENT
);
1017 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1019 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1022 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1026 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1028 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1030 SharedCacheMap
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1031 Vacb
= CcRosLookupVacb(SharedCacheMap
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
);
1034 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, FALSE
, TRUE
);
1044 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1048 PVOID DestAddress
, SrcAddress
;
1050 Process
= PsGetCurrentProcess();
1051 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1052 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1053 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1055 return(STATUS_NO_MEMORY
);
1057 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1058 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1059 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1060 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1061 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1062 return(STATUS_SUCCESS
);
1068 MiReadPage(PMEMORY_AREA MemoryArea
,
1072 * FUNCTION: Read a page for a section backed memory area.
1074 * MemoryArea - Memory area to read the page for.
1075 * Offset - Offset of the page to read.
1076 * Page - Variable that receives a page contains the read data.
1079 LONGLONG BaseOffset
;
1080 LONGLONG FileOffset
;
1084 PFILE_OBJECT FileObject
;
1087 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1088 BOOLEAN IsImageSection
;
1091 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1092 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1093 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
;
1094 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1095 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1097 ASSERT(SharedCacheMap
);
1099 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1102 * If the file system is letting us go directly to the cache and the
1103 * memory area was mapped at an offset in the file which is page aligned
1104 * then get the related VACB.
1106 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1107 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1108 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1112 * Get the related VACB; we use a lower level interface than
1113 * filesystems do because it is safe for us to use an offset with an
1114 * alignment less than the file system block size.
1116 Status
= CcRosGetVacb(SharedCacheMap
,
1122 if (!NT_SUCCESS(Status
))
1129 * If the VACB isn't up to date then call the file
1130 * system to read in the data.
1132 Status
= CcReadVirtualAddress(Vacb
);
1133 if (!NT_SUCCESS(Status
))
1135 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1140 /* Probe the page, since it's PDE might not be synced */
1141 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1144 * Retrieve the page from the view that we actually want.
1146 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1147 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1149 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, TRUE
);
1156 LONGLONG VacbOffset
;
1159 * Allocate a page, this is rather complicated by the possibility
1160 * we might have to move other things out of memory
1162 MI_SET_USAGE(MI_USAGE_SECTION
);
1163 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1164 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1165 if (!NT_SUCCESS(Status
))
1169 Status
= CcRosGetVacb(SharedCacheMap
,
1175 if (!NT_SUCCESS(Status
))
1182 * If the VACB isn't up to date then call the file
1183 * system to read in the data.
1185 Status
= CcReadVirtualAddress(Vacb
);
1186 if (!NT_SUCCESS(Status
))
1188 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1193 Process
= PsGetCurrentProcess();
1194 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1195 VacbOffset
= BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
;
1196 Length
= RawLength
- SegOffset
;
1197 if (Length
<= VacbOffset
&& Length
<= PAGE_SIZE
)
1199 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1201 else if (VacbOffset
>= PAGE_SIZE
)
1203 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1207 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, VacbOffset
);
1208 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1209 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1210 Status
= CcRosGetVacb(SharedCacheMap
,
1211 FileOffset
+ VacbOffset
,
1216 if (!NT_SUCCESS(Status
))
1223 * If the VACB isn't up to date then call the file
1224 * system to read in the data.
1226 Status
= CcReadVirtualAddress(Vacb
);
1227 if (!NT_SUCCESS(Status
))
1229 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1233 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1234 if (Length
< PAGE_SIZE
)
1236 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, Length
- VacbOffset
);
1240 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, PAGE_SIZE
- VacbOffset
);
1243 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1244 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1246 return(STATUS_SUCCESS
);
1251 MiReadPage(PMEMORY_AREA MemoryArea
,
1255 * FUNCTION: Read a page for a section backed memory area.
1257 * MemoryArea - Memory area to read the page for.
1258 * Offset - Offset of the page to read.
1259 * Page - Variable that receives a page contains the read data.
1262 MM_REQUIRED_RESOURCES Resources
;
1265 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1267 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1268 Resources
.FileOffset
.QuadPart
= SegOffset
+
1269 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1270 Resources
.Consumer
= MC_USER
;
1271 Resources
.Amount
= PAGE_SIZE
;
1273 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]);
1275 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1276 *Page
= Resources
.Page
[0];
1283 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1284 MEMORY_AREA
* MemoryArea
,
1288 LARGE_INTEGER Offset
;
1291 PROS_SECTION_OBJECT Section
;
1292 PMM_SECTION_SEGMENT Segment
;
1297 BOOLEAN HasSwapEntry
;
1299 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1300 SWAPENTRY SwapEntry
;
1303 * There is a window between taking the page fault and locking the
1304 * address space when another thread could load the page so we check
1307 if (MmIsPagePresent(Process
, Address
))
1309 return(STATUS_SUCCESS
);
1312 if (MmIsDisabledPage(Process
, Address
))
1314 return(STATUS_ACCESS_VIOLATION
);
1318 * Check for the virtual memory area being deleted.
1320 if (MemoryArea
->DeleteInProgress
)
1322 return(STATUS_UNSUCCESSFUL
);
1325 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1326 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1327 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1329 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1330 Section
= MemoryArea
->Data
.SectionData
.Section
;
1331 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1332 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1334 ASSERT(Region
!= NULL
);
1338 MmLockSectionSegment(Segment
);
1339 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1341 * Check if this page needs to be mapped COW
1343 if ((Segment
->WriteCopy
) &&
1344 (Region
->Protect
== PAGE_READWRITE
||
1345 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1347 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1351 Attributes
= Region
->Protect
;
1355 * Check if someone else is already handling this fault, if so wait
1358 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1360 MmUnlockSectionSegment(Segment
);
1361 MmUnlockAddressSpace(AddressSpace
);
1362 MiWaitForPageEvent(NULL
, NULL
);
1363 MmLockAddressSpace(AddressSpace
);
1364 DPRINT("Address 0x%p\n", Address
);
1365 return(STATUS_MM_RESTART_OPERATION
);
1368 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1372 SWAPENTRY DummyEntry
;
1375 * Is it a wait entry?
1377 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1379 if (SwapEntry
== MM_WAIT_ENTRY
)
1381 MmUnlockSectionSegment(Segment
);
1382 MmUnlockAddressSpace(AddressSpace
);
1383 MiWaitForPageEvent(NULL
, NULL
);
1384 MmLockAddressSpace(AddressSpace
);
1385 return STATUS_MM_RESTART_OPERATION
;
1389 * Must be private page we have swapped out.
1395 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1397 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1398 KeBugCheck(MEMORY_MANAGEMENT
);
1401 MmUnlockSectionSegment(Segment
);
1402 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1403 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1405 MmUnlockAddressSpace(AddressSpace
);
1406 MI_SET_USAGE(MI_USAGE_SECTION
);
1407 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1408 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1409 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1410 if (!NT_SUCCESS(Status
))
1412 KeBugCheck(MEMORY_MANAGEMENT
);
1415 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1416 if (!NT_SUCCESS(Status
))
1418 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1419 KeBugCheck(MEMORY_MANAGEMENT
);
1421 MmLockAddressSpace(AddressSpace
);
1422 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1423 Status
= MmCreateVirtualMapping(Process
,
1428 if (!NT_SUCCESS(Status
))
1430 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1431 KeBugCheck(MEMORY_MANAGEMENT
);
1436 * Store the swap entry for later use.
1438 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1441 * Add the page to the process's working set
1443 MmInsertRmap(Page
, Process
, Address
);
1445 * Finish the operation
1447 MiSetPageEvent(Process
, Address
);
1448 DPRINT("Address 0x%p\n", Address
);
1449 return(STATUS_SUCCESS
);
1453 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1455 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1457 MmUnlockSectionSegment(Segment
);
1459 * Just map the desired physical page
1461 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1462 Status
= MmCreateVirtualMappingUnsafe(Process
,
1467 if (!NT_SUCCESS(Status
))
1469 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1470 KeBugCheck(MEMORY_MANAGEMENT
);
1475 * Cleanup and release locks
1477 MiSetPageEvent(Process
, Address
);
1478 DPRINT("Address 0x%p\n", Address
);
1479 return(STATUS_SUCCESS
);
1483 * Get the entry corresponding to the offset within the section
1485 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1489 SWAPENTRY FakeSwapEntry
;
1492 * If the entry is zero (and it can't change because we have
1493 * locked the segment) then we need to load the page.
1497 * Release all our locks and read in the page from disk
1499 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1500 MmUnlockSectionSegment(Segment
);
1501 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1502 MmUnlockAddressSpace(AddressSpace
);
1504 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1505 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1506 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1508 MI_SET_USAGE(MI_USAGE_SECTION
);
1509 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1510 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1511 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1512 if (!NT_SUCCESS(Status
))
1514 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1520 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1521 if (!NT_SUCCESS(Status
))
1523 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1526 if (!NT_SUCCESS(Status
))
1529 * FIXME: What do we know in this case?
1532 * Cleanup and release locks
1534 MmLockAddressSpace(AddressSpace
);
1535 MiSetPageEvent(Process
, Address
);
1536 DPRINT("Address 0x%p\n", Address
);
1541 * Mark the offset within the section as having valid, in-memory
1544 MmLockAddressSpace(AddressSpace
);
1545 MmLockSectionSegment(Segment
);
1546 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1547 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1548 MmUnlockSectionSegment(Segment
);
1550 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1551 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1552 Page
, Process
, PAddress
, Attributes
);
1553 Status
= MmCreateVirtualMapping(Process
,
1558 if (!NT_SUCCESS(Status
))
1560 DPRINT1("Unable to create virtual mapping\n");
1561 KeBugCheck(MEMORY_MANAGEMENT
);
1563 ASSERT(MmIsPagePresent(Process
, PAddress
));
1564 MmInsertRmap(Page
, Process
, Address
);
1566 MiSetPageEvent(Process
, Address
);
1567 DPRINT("Address 0x%p\n", Address
);
1568 return(STATUS_SUCCESS
);
1570 else if (IS_SWAP_FROM_SSE(Entry
))
1572 SWAPENTRY SwapEntry
;
1574 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1577 * Release all our locks and read in the page from disk
1579 MmUnlockSectionSegment(Segment
);
1581 MmUnlockAddressSpace(AddressSpace
);
1582 MI_SET_USAGE(MI_USAGE_SECTION
);
1583 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1584 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1585 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1586 if (!NT_SUCCESS(Status
))
1588 KeBugCheck(MEMORY_MANAGEMENT
);
1591 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1592 if (!NT_SUCCESS(Status
))
1594 KeBugCheck(MEMORY_MANAGEMENT
);
1598 * Relock the address space and segment
1600 MmLockAddressSpace(AddressSpace
);
1601 MmLockSectionSegment(Segment
);
1604 * Check the entry. No one should change the status of a page
1605 * that has a pending page-in.
1607 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1608 if (Entry
!= Entry1
)
1610 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1611 KeBugCheck(MEMORY_MANAGEMENT
);
1615 * Mark the offset within the section as having valid, in-memory
1618 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1619 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1620 MmUnlockSectionSegment(Segment
);
1623 * Save the swap entry.
1625 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1626 Status
= MmCreateVirtualMapping(Process
,
1631 if (!NT_SUCCESS(Status
))
1633 DPRINT1("Unable to create virtual mapping\n");
1634 KeBugCheck(MEMORY_MANAGEMENT
);
1636 MmInsertRmap(Page
, Process
, Address
);
1637 MiSetPageEvent(Process
, Address
);
1638 DPRINT("Address 0x%p\n", Address
);
1639 return(STATUS_SUCCESS
);
1644 * If the section offset is already in-memory and valid then just
1645 * take another reference to the page
1648 Page
= PFN_FROM_SSE(Entry
);
1650 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1651 MmUnlockSectionSegment(Segment
);
1653 Status
= MmCreateVirtualMapping(Process
,
1658 if (!NT_SUCCESS(Status
))
1660 DPRINT1("Unable to create virtual mapping\n");
1661 KeBugCheck(MEMORY_MANAGEMENT
);
1663 MmInsertRmap(Page
, Process
, Address
);
1664 MiSetPageEvent(Process
, Address
);
1665 DPRINT("Address 0x%p\n", Address
);
1666 return(STATUS_SUCCESS
);
1672 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1673 MEMORY_AREA
* MemoryArea
,
1676 PMM_SECTION_SEGMENT Segment
;
1677 PROS_SECTION_OBJECT Section
;
1682 LARGE_INTEGER Offset
;
1685 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1686 SWAPENTRY SwapEntry
;
1688 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1691 * Check if the page has already been set readwrite
1693 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1695 DPRINT("Address 0x%p\n", Address
);
1696 return(STATUS_SUCCESS
);
1700 * Find the offset of the page
1702 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1703 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1704 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1706 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1707 Section
= MemoryArea
->Data
.SectionData
.Section
;
1708 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1709 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1711 ASSERT(Region
!= NULL
);
1715 MmLockSectionSegment(Segment
);
1717 OldPage
= MmGetPfnForProcess(Process
, Address
);
1718 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1720 MmUnlockSectionSegment(Segment
);
1723 * Check if we are doing COW
1725 if (!((Segment
->WriteCopy
) &&
1726 (Region
->Protect
== PAGE_READWRITE
||
1727 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1729 DPRINT("Address 0x%p\n", Address
);
1730 return(STATUS_ACCESS_VIOLATION
);
1733 if (IS_SWAP_FROM_SSE(Entry
) ||
1734 PFN_FROM_SSE(Entry
) != OldPage
)
1736 /* This is a private page. We must only change the page protection. */
1737 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1738 return(STATUS_SUCCESS
);
1742 DPRINT("OldPage == 0!\n");
1745 * Get or create a pageop
1747 MmLockSectionSegment(Segment
);
1748 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1751 * Wait for any other operations to complete
1753 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1755 MmUnlockSectionSegment(Segment
);
1756 MmUnlockAddressSpace(AddressSpace
);
1757 MiWaitForPageEvent(NULL
, NULL
);
1759 * Restart the operation
1761 MmLockAddressSpace(AddressSpace
);
1762 DPRINT("Address 0x%p\n", Address
);
1763 return(STATUS_MM_RESTART_OPERATION
);
1766 MmDeleteRmap(OldPage
, Process
, PAddress
);
1767 MmDeleteVirtualMapping(Process
, PAddress
, NULL
, NULL
);
1768 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1771 * Release locks now we have the pageop
1773 MmUnlockSectionSegment(Segment
);
1774 MmUnlockAddressSpace(AddressSpace
);
1779 MI_SET_USAGE(MI_USAGE_SECTION
);
1780 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1781 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1782 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1783 if (!NT_SUCCESS(Status
))
1785 KeBugCheck(MEMORY_MANAGEMENT
);
1791 MiCopyFromUserPage(NewPage
, OldPage
);
1793 MmLockAddressSpace(AddressSpace
);
1796 * Set the PTE to point to the new page
1798 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1799 Status
= MmCreateVirtualMapping(Process
,
1804 if (!NT_SUCCESS(Status
))
1806 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1807 KeBugCheck(MEMORY_MANAGEMENT
);
1812 * Unshare the old page.
1814 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1815 MmInsertRmap(NewPage
, Process
, PAddress
);
1816 MmLockSectionSegment(Segment
);
1817 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1818 MmUnlockSectionSegment(Segment
);
1820 MiSetPageEvent(Process
, Address
);
1821 DPRINT("Address 0x%p\n", Address
);
1822 return(STATUS_SUCCESS
);
1826 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1828 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1830 PFN_NUMBER Page
= 0;
1832 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1835 MmLockAddressSpace(&Process
->Vm
);
1838 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
;
1879 ULONGLONG FileOffset
;
1880 PFILE_OBJECT FileObject
;
1881 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1882 BOOLEAN IsImageSection
;
1884 BOOLEAN DirectMapped
;
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
- MA_GetStartingAddress(MemoryArea
)
1899 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1901 DirectMapped
= FALSE
;
1903 MmLockSectionSegment(Context
.Segment
);
1906 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1907 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1908 FileObject
= Context
.Section
->FileObject
;
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
;
2289 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2291 BOOLEAN DirectMapped
;
2292 BOOLEAN IsImageSection
;
2293 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2295 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2297 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2298 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2301 * Get the segment and section.
2303 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2304 Section
= MemoryArea
->Data
.SectionData
.Section
;
2305 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2307 FileObject
= Section
->FileObject
;
2308 DirectMapped
= FALSE
;
2309 if (FileObject
!= NULL
&&
2310 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2313 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2317 * If the file system is letting us go directly to the cache and the
2318 * memory area was mapped at an offset in the file which is page aligned
2319 * then note this is a direct mapped page.
2321 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2322 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2324 DirectMapped
= TRUE
;
2329 * This should never happen since mappings of physical memory are never
2330 * placed in the rmap lists.
2332 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2334 DPRINT1("Trying to write back page from physical memory mapped at %p "
2335 "process %p\n", Address
,
2336 Process
? Process
->UniqueProcessId
: 0);
2337 KeBugCheck(MEMORY_MANAGEMENT
);
2341 * Get the section segment entry and the physical address.
2343 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2344 if (!MmIsPagePresent(Process
, Address
))
2346 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2347 Process
? Process
->UniqueProcessId
: 0, Address
);
2348 KeBugCheck(MEMORY_MANAGEMENT
);
2350 Page
= MmGetPfnForProcess(Process
, Address
);
2351 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2354 * Check for a private (COWed) page.
2356 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2357 IS_SWAP_FROM_SSE(Entry
) ||
2358 PFN_FROM_SSE(Entry
) != Page
)
2368 * Speculatively set all mappings of the page to clean.
2370 MmSetCleanAllRmaps(Page
);
2373 * If this page was direct mapped from the cache then the cache manager
2374 * will take care of writing it back to disk.
2376 if (DirectMapped
&& !Private
)
2378 //LARGE_INTEGER SOffset;
2379 ASSERT(SwapEntry
== 0);
2380 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2382 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
);
2384 MmLockSectionSegment(Segment
);
2385 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2386 MmUnlockSectionSegment(Segment
);
2387 MiSetPageEvent(NULL
, NULL
);
2388 return(STATUS_SUCCESS
);
2392 * If necessary, allocate an entry in the paging file for this page
2396 SwapEntry
= MmAllocSwapPage();
2399 MmSetDirtyAllRmaps(Page
);
2400 MiSetPageEvent(NULL
, NULL
);
2401 return(STATUS_PAGEFILE_QUOTA
);
2403 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2407 * Write the page to the pagefile
2409 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2410 if (!NT_SUCCESS(Status
))
2412 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2414 MmSetDirtyAllRmaps(Page
);
2415 MiSetPageEvent(NULL
, NULL
);
2416 return(STATUS_UNSUCCESSFUL
);
2420 * Otherwise we have succeeded.
2422 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2423 MiSetPageEvent(NULL
, NULL
);
2424 return(STATUS_SUCCESS
);
2428 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2436 PMEMORY_AREA MemoryArea
;
2437 PMM_SECTION_SEGMENT Segment
;
2438 BOOLEAN DoCOW
= FALSE
;
2440 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2442 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2443 ASSERT(MemoryArea
!= NULL
);
2444 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2445 MmLockSectionSegment(Segment
);
2447 if ((Segment
->WriteCopy
) &&
2448 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2453 if (OldProtect
!= NewProtect
)
2455 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2457 SWAPENTRY SwapEntry
;
2458 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2459 ULONG Protect
= NewProtect
;
2461 /* Wait for a wait entry to disappear */
2464 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2465 if (SwapEntry
!= MM_WAIT_ENTRY
)
2467 MiWaitForPageEvent(Process
, Address
);
2472 * If we doing COW for this segment then check if the page is
2475 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2477 LARGE_INTEGER Offset
;
2481 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2482 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2483 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2485 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2486 * IS_SWAP_FROM_SSE and we'll do the right thing.
2488 Page
= MmGetPfnForProcess(Process
, Address
);
2490 Protect
= PAGE_READONLY
;
2491 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2492 IS_SWAP_FROM_SSE(Entry
) ||
2493 PFN_FROM_SSE(Entry
) != Page
)
2495 Protect
= NewProtect
;
2499 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2501 MmSetPageProtect(Process
, Address
,
2507 MmUnlockSectionSegment(Segment
);
2512 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2513 PMEMORY_AREA MemoryArea
,
2521 ULONG_PTR MaxLength
;
2523 MaxLength
= MA_GetEndingAddress(MemoryArea
) - (ULONG_PTR
)BaseAddress
;
2524 if (Length
> MaxLength
)
2525 Length
= (ULONG
)MaxLength
;
2527 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2528 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2530 ASSERT(Region
!= NULL
);
2532 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2533 Region
->Protect
!= Protect
)
2535 return STATUS_INVALID_PAGE_PROTECTION
;
2538 *OldProtect
= Region
->Protect
;
2539 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
2540 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2541 BaseAddress
, Length
, Region
->Type
, Protect
,
2542 MmAlterViewAttributes
);
2548 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2550 PMEMORY_BASIC_INFORMATION Info
,
2551 PSIZE_T ResultLength
)
2554 PVOID RegionBaseAddress
;
2555 PROS_SECTION_OBJECT Section
;
2556 PMM_SECTION_SEGMENT Segment
;
2558 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2559 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2560 Address
, &RegionBaseAddress
);
2563 return STATUS_UNSUCCESSFUL
;
2566 Section
= MemoryArea
->Data
.SectionData
.Section
;
2567 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2569 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2570 Info
->AllocationBase
= (PUCHAR
)MA_GetStartingAddress(MemoryArea
) - Segment
->Image
.VirtualAddress
;
2571 Info
->Type
= MEM_IMAGE
;
2575 Info
->AllocationBase
= (PVOID
)MA_GetStartingAddress(MemoryArea
);
2576 Info
->Type
= MEM_MAPPED
;
2578 Info
->BaseAddress
= RegionBaseAddress
;
2579 Info
->AllocationProtect
= MemoryArea
->Protect
;
2580 Info
->RegionSize
= Region
->Length
;
2581 Info
->State
= MEM_COMMIT
;
2582 Info
->Protect
= Region
->Protect
;
2584 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2585 return(STATUS_SUCCESS
);
2590 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2593 LARGE_INTEGER Offset
;
2595 SWAPENTRY SavedSwapEntry
;
2600 MmLockSectionSegment(Segment
);
2602 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2603 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2605 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2608 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2609 if (IS_SWAP_FROM_SSE(Entry
))
2611 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2615 Page
= PFN_FROM_SSE(Entry
);
2616 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2617 if (SavedSwapEntry
!= 0)
2619 MmSetSavedSwapEntryPage(Page
, 0);
2620 MmFreeSwapPage(SavedSwapEntry
);
2622 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2627 MmUnlockSectionSegment(Segment
);
2631 MmpDeleteSection(PVOID ObjectBody
)
2633 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2635 /* Check if it's an ARM3, or ReactOS section */
2636 if (!MiIsRosSectionObject(Section
))
2638 MiDeleteARM3Section(ObjectBody
);
2642 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2643 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2648 PMM_SECTION_SEGMENT SectionSegments
;
2651 * NOTE: Section->ImageSection can be NULL for short time
2652 * during the section creating. If we fail for some reason
2653 * until the image section is properly initialized we shouldn't
2654 * process further here.
2656 if (Section
->ImageSection
== NULL
)
2659 SectionSegments
= Section
->ImageSection
->Segments
;
2660 NrSegments
= Section
->ImageSection
->NrSegments
;
2662 for (i
= 0; i
< NrSegments
; i
++)
2664 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2666 MmLockSectionSegment(&SectionSegments
[i
]);
2668 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2669 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2671 MmUnlockSectionSegment(&SectionSegments
[i
]);
2674 MmpFreePageFileSegment(&SectionSegments
[i
]);
2680 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2683 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2686 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2688 DPRINT("Freeing section segment\n");
2689 Section
->Segment
= NULL
;
2690 MmFinalizeSegment(Segment
);
2694 DPRINT("RefCount %d\n", RefCount
);
2701 * NOTE: Section->Segment can be NULL for short time
2702 * during the section creating.
2704 if (Section
->Segment
== NULL
)
2707 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2709 MmpFreePageFileSegment(Section
->Segment
);
2710 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2711 ExFreePool(Section
->Segment
);
2712 Section
->Segment
= NULL
;
2716 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2719 if (Section
->FileObject
!= NULL
)
2722 CcRosDereferenceCache(Section
->FileObject
);
2724 ObDereferenceObject(Section
->FileObject
);
2725 Section
->FileObject
= NULL
;
2730 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2732 IN ACCESS_MASK GrantedAccess
,
2733 IN ULONG ProcessHandleCount
,
2734 IN ULONG SystemHandleCount
)
2736 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2742 MmCreatePhysicalMemorySection(VOID
)
2744 PROS_SECTION_OBJECT PhysSection
;
2746 OBJECT_ATTRIBUTES Obj
;
2747 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2748 LARGE_INTEGER SectionSize
;
2752 * Create the section mapping physical memory
2754 SectionSize
.QuadPart
= 0xFFFFFFFF;
2755 InitializeObjectAttributes(&Obj
,
2760 Status
= MmCreateSection((PVOID
)&PhysSection
,
2764 PAGE_EXECUTE_READWRITE
,
2768 if (!NT_SUCCESS(Status
))
2770 DPRINT1("Failed to create PhysicalMemory section\n");
2771 KeBugCheck(MEMORY_MANAGEMENT
);
2773 Status
= ObInsertObject(PhysSection
,
2779 if (!NT_SUCCESS(Status
))
2781 ObDereferenceObject(PhysSection
);
2783 ObCloseHandle(Handle
, KernelMode
);
2784 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2785 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2787 return(STATUS_SUCCESS
);
2793 MmInitSectionImplementation(VOID
)
2795 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2796 UNICODE_STRING Name
;
2798 DPRINT("Creating Section Object Type\n");
2800 /* Initialize the section based root */
2801 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2802 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2804 /* Initialize the Section object type */
2805 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2806 RtlInitUnicodeString(&Name
, L
"Section");
2807 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2808 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2809 ObjectTypeInitializer
.PoolType
= PagedPool
;
2810 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2811 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2812 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2813 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2814 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2815 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2816 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2818 MmCreatePhysicalMemorySection();
2820 return(STATUS_SUCCESS
);
2825 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2826 ACCESS_MASK DesiredAccess
,
2827 POBJECT_ATTRIBUTES ObjectAttributes
,
2828 PLARGE_INTEGER UMaximumSize
,
2829 ULONG SectionPageProtection
,
2830 ULONG AllocationAttributes
)
2832 * Create a section which is backed by the pagefile
2835 LARGE_INTEGER MaximumSize
;
2836 PROS_SECTION_OBJECT Section
;
2837 PMM_SECTION_SEGMENT Segment
;
2840 if (UMaximumSize
== NULL
)
2842 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2843 return(STATUS_INVALID_PARAMETER
);
2845 MaximumSize
= *UMaximumSize
;
2848 * Create the section
2850 Status
= ObCreateObject(ExGetPreviousMode(),
2851 MmSectionObjectType
,
2853 ExGetPreviousMode(),
2855 sizeof(ROS_SECTION_OBJECT
),
2858 (PVOID
*)(PVOID
)&Section
);
2859 if (!NT_SUCCESS(Status
))
2861 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2868 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2869 Section
->Type
= 'SC';
2870 Section
->Size
= 'TN';
2871 Section
->SectionPageProtection
= SectionPageProtection
;
2872 Section
->AllocationAttributes
= AllocationAttributes
;
2873 Section
->MaximumSize
= MaximumSize
;
2874 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2875 TAG_MM_SECTION_SEGMENT
);
2876 if (Segment
== NULL
)
2878 ObDereferenceObject(Section
);
2879 return(STATUS_NO_MEMORY
);
2881 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2882 Section
->Segment
= Segment
;
2883 Segment
->ReferenceCount
= 1;
2884 ExInitializeFastMutex(&Segment
->Lock
);
2885 Segment
->Image
.FileOffset
= 0;
2886 Segment
->Protection
= SectionPageProtection
;
2887 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2888 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2889 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2890 Segment
->WriteCopy
= FALSE
;
2891 Segment
->Image
.VirtualAddress
= 0;
2892 Segment
->Image
.Characteristics
= 0;
2893 *SectionObject
= Section
;
2894 MiInitializeSectionPageTable(Segment
);
2895 return(STATUS_SUCCESS
);
2900 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2901 ACCESS_MASK DesiredAccess
,
2902 POBJECT_ATTRIBUTES ObjectAttributes
,
2903 PLARGE_INTEGER UMaximumSize
,
2904 ULONG SectionPageProtection
,
2905 ULONG AllocationAttributes
,
2908 * Create a section backed by a data file
2911 PROS_SECTION_OBJECT Section
;
2913 LARGE_INTEGER MaximumSize
;
2914 PFILE_OBJECT FileObject
;
2915 PMM_SECTION_SEGMENT Segment
;
2917 IO_STATUS_BLOCK Iosb
;
2918 LARGE_INTEGER Offset
;
2920 FILE_STANDARD_INFORMATION FileInfo
;
2924 * Create the section
2926 Status
= ObCreateObject(ExGetPreviousMode(),
2927 MmSectionObjectType
,
2929 ExGetPreviousMode(),
2931 sizeof(ROS_SECTION_OBJECT
),
2935 if (!NT_SUCCESS(Status
))
2942 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2943 Section
->Type
= 'SC';
2944 Section
->Size
= 'TN';
2945 Section
->SectionPageProtection
= SectionPageProtection
;
2946 Section
->AllocationAttributes
= AllocationAttributes
;
2949 * Reference the file handle
2951 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2952 Status
= ObReferenceObjectByHandle(FileHandle
,
2955 ExGetPreviousMode(),
2956 (PVOID
*)(PVOID
)&FileObject
,
2958 if (!NT_SUCCESS(Status
))
2960 ObDereferenceObject(Section
);
2965 * FIXME: This is propably not entirely correct. We can't look into
2966 * the standard FCB header because it might not be initialized yet
2967 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2968 * standard file information is filled on first request).
2970 Status
= IoQueryFileInformation(FileObject
,
2971 FileStandardInformation
,
2972 sizeof(FILE_STANDARD_INFORMATION
),
2975 Iosb
.Information
= Length
;
2976 if (!NT_SUCCESS(Status
))
2978 ObDereferenceObject(Section
);
2979 ObDereferenceObject(FileObject
);
2984 * FIXME: Revise this once a locking order for file size changes is
2987 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2989 MaximumSize
= *UMaximumSize
;
2993 MaximumSize
= FileInfo
.EndOfFile
;
2994 /* Mapping zero-sized files isn't allowed. */
2995 if (MaximumSize
.QuadPart
== 0)
2997 ObDereferenceObject(Section
);
2998 ObDereferenceObject(FileObject
);
2999 return STATUS_FILE_INVALID
;
3003 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3005 Status
= IoSetInformation(FileObject
,
3006 FileAllocationInformation
,
3007 sizeof(LARGE_INTEGER
),
3009 if (!NT_SUCCESS(Status
))
3011 ObDereferenceObject(Section
);
3012 ObDereferenceObject(FileObject
);
3013 return(STATUS_SECTION_NOT_EXTENDED
);
3017 if (FileObject
->SectionObjectPointer
== NULL
||
3018 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3021 * Read a bit so caching is initiated for the file object.
3022 * This is only needed because MiReadPage currently cannot
3023 * handle non-cached streams.
3025 Offset
.QuadPart
= 0;
3026 Status
= ZwReadFile(FileHandle
,
3035 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3037 ObDereferenceObject(Section
);
3038 ObDereferenceObject(FileObject
);
3041 if (FileObject
->SectionObjectPointer
== NULL
||
3042 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3044 /* FIXME: handle this situation */
3045 ObDereferenceObject(Section
);
3046 ObDereferenceObject(FileObject
);
3047 return STATUS_INVALID_PARAMETER
;
3054 Status
= MmspWaitForFileLock(FileObject
);
3055 if (Status
!= STATUS_SUCCESS
)
3057 ObDereferenceObject(Section
);
3058 ObDereferenceObject(FileObject
);
3063 * If this file hasn't been mapped as a data file before then allocate a
3064 * section segment to describe the data file mapping
3066 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3068 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3069 TAG_MM_SECTION_SEGMENT
);
3070 if (Segment
== NULL
)
3072 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3073 ObDereferenceObject(Section
);
3074 ObDereferenceObject(FileObject
);
3075 return(STATUS_NO_MEMORY
);
3077 Section
->Segment
= Segment
;
3078 Segment
->ReferenceCount
= 1;
3079 ExInitializeFastMutex(&Segment
->Lock
);
3081 * Set the lock before assigning the segment to the file object
3083 ExAcquireFastMutex(&Segment
->Lock
);
3084 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3086 Segment
->Image
.FileOffset
= 0;
3087 Segment
->Protection
= SectionPageProtection
;
3088 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3089 Segment
->Image
.Characteristics
= 0;
3090 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3091 if (AllocationAttributes
& SEC_RESERVE
)
3093 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3097 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3098 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3100 Segment
->Image
.VirtualAddress
= 0;
3101 Segment
->Locked
= TRUE
;
3102 MiInitializeSectionPageTable(Segment
);
3107 * If the file is already mapped as a data file then we may need
3111 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3113 Section
->Segment
= Segment
;
3114 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3115 MmLockSectionSegment(Segment
);
3117 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3118 !(AllocationAttributes
& SEC_RESERVE
))
3120 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3121 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3124 MmUnlockSectionSegment(Segment
);
3125 Section
->FileObject
= FileObject
;
3126 Section
->MaximumSize
= MaximumSize
;
3128 CcRosReferenceCache(FileObject
);
3130 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3131 *SectionObject
= Section
;
3132 return(STATUS_SUCCESS
);
3136 TODO: not that great (declaring loaders statically, having to declare all of
3137 them, having to keep them extern, etc.), will fix in the future
3139 extern NTSTATUS NTAPI PeFmtCreateSection
3141 IN CONST VOID
* FileHeader
,
3142 IN SIZE_T FileHeaderSize
,
3144 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3146 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3147 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3150 extern NTSTATUS NTAPI ElfFmtCreateSection
3152 IN CONST VOID
* FileHeader
,
3153 IN SIZE_T FileHeaderSize
,
3155 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3157 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3158 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3161 /* TODO: this is a standard DDK/PSDK macro */
3162 #ifndef RTL_NUMBER_OF
3163 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3166 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3177 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3179 SIZE_T SizeOfSegments
;
3180 PMM_SECTION_SEGMENT Segments
;
3182 /* TODO: check for integer overflow */
3183 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3185 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3187 TAG_MM_SECTION_SEGMENT
);
3190 RtlZeroMemory(Segments
, SizeOfSegments
);
3198 ExeFmtpReadFile(IN PVOID File
,
3199 IN PLARGE_INTEGER Offset
,
3202 OUT PVOID
* AllocBase
,
3203 OUT PULONG ReadSize
)
3206 LARGE_INTEGER FileOffset
;
3208 ULONG OffsetAdjustment
;
3212 PFILE_OBJECT FileObject
= File
;
3213 IO_STATUS_BLOCK Iosb
;
3215 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3219 KeBugCheck(MEMORY_MANAGEMENT
);
3222 FileOffset
= *Offset
;
3224 /* Negative/special offset: it cannot be used in this context */
3225 if(FileOffset
.u
.HighPart
< 0)
3227 KeBugCheck(MEMORY_MANAGEMENT
);
3230 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3231 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3232 FileOffset
.u
.LowPart
= AdjustOffset
;
3234 BufferSize
= Length
+ OffsetAdjustment
;
3235 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3238 * It's ok to use paged pool, because this is a temporary buffer only used in
3239 * the loading of executables. The assumption is that MmCreateSection is
3240 * always called at low IRQLs and that these buffers don't survive a brief
3241 * initialization phase
3243 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3248 KeBugCheck(MEMORY_MANAGEMENT
);
3253 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3255 UsedSize
= (ULONG
)Iosb
.Information
;
3257 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3259 Status
= STATUS_IN_PAGE_ERROR
;
3260 ASSERT(!NT_SUCCESS(Status
));
3263 if(NT_SUCCESS(Status
))
3265 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3266 *AllocBase
= Buffer
;
3267 *ReadSize
= UsedSize
- OffsetAdjustment
;
3271 ExFreePoolWithTag(Buffer
, 'rXmM');
3278 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3279 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3280 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3285 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3289 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3291 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3292 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3299 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3303 MmspAssertSegmentsSorted(ImageSectionObject
);
3305 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3307 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3311 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3312 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3313 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3321 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3325 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3327 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3328 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3336 MmspCompareSegments(const void * x
,
3339 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3340 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3343 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3344 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3348 * Ensures an image section's segments are sorted in memory
3353 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3356 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3358 MmspAssertSegmentsSorted(ImageSectionObject
);
3362 qsort(ImageSectionObject
->Segments
,
3363 ImageSectionObject
->NrSegments
,
3364 sizeof(ImageSectionObject
->Segments
[0]),
3365 MmspCompareSegments
);
3371 * Ensures an image section's segments don't overlap in memory and don't have
3372 * gaps and don't have a null size. We let them map to overlapping file regions,
3373 * though - that's not necessarily an error
3378 MmspCheckSegmentBounds
3380 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3386 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3388 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3392 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3394 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3396 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3404 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3405 * page could be OK (Windows seems to be OK with them), and larger gaps
3406 * could lead to image sections spanning several discontiguous regions
3407 * (NtMapViewOfSection could then refuse to map them, and they could
3408 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3410 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3411 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3412 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3423 * Merges and pads an image section's segments until they all are page-aligned
3424 * and have a size that is a multiple of the page size
3429 MmspPageAlignSegments
3431 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3437 PMM_SECTION_SEGMENT EffectiveSegment
;
3439 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3441 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3446 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3448 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3451 * The first segment requires special handling
3455 ULONG_PTR VirtualAddress
;
3456 ULONG_PTR VirtualOffset
;
3458 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3460 /* Round down the virtual address to the nearest page */
3461 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3463 /* Round up the virtual size to the nearest page */
3464 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3465 EffectiveSegment
->Image
.VirtualAddress
;
3467 /* Adjust the raw address and size */
3468 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3470 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3476 * Garbage in, garbage out: unaligned base addresses make the file
3477 * offset point in curious and odd places, but that's what we were
3480 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3481 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3485 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3486 ULONG_PTR EndOfEffectiveSegment
;
3488 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3489 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3492 * The current segment begins exactly where the current effective
3493 * segment ended, therefore beginning a new effective segment
3495 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3498 ASSERT(LastSegment
<= i
);
3499 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3501 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3503 if (LastSegment
!= i
)
3506 * Copy the current segment. If necessary, the effective segment
3507 * will be expanded later
3509 *EffectiveSegment
= *Segment
;
3513 * Page-align the virtual size. We know for sure the virtual address
3516 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3517 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3520 * The current segment is still part of the current effective segment:
3521 * extend the effective segment to reflect this
3523 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3525 static const ULONG FlagsToProtection
[16] =
3533 PAGE_EXECUTE_READWRITE
,
3534 PAGE_EXECUTE_READWRITE
,
3539 PAGE_EXECUTE_WRITECOPY
,
3540 PAGE_EXECUTE_WRITECOPY
,
3541 PAGE_EXECUTE_WRITECOPY
,
3542 PAGE_EXECUTE_WRITECOPY
3545 unsigned ProtectionFlags
;
3548 * Extend the file size
3551 /* Unaligned segments must be contiguous within the file */
3552 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3553 EffectiveSegment
->RawLength
.QuadPart
))
3558 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3561 * Extend the virtual size
3563 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3565 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3566 EffectiveSegment
->Image
.VirtualAddress
;
3569 * Merge the protection
3571 EffectiveSegment
->Protection
|= Segment
->Protection
;
3573 /* Clean up redundance */
3574 ProtectionFlags
= 0;
3576 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3577 ProtectionFlags
|= 1 << 0;
3579 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3580 ProtectionFlags
|= 1 << 1;
3582 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3583 ProtectionFlags
|= 1 << 2;
3585 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3586 ProtectionFlags
|= 1 << 3;
3588 ASSERT(ProtectionFlags
< 16);
3589 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3591 /* If a segment was required to be shared and cannot, fail */
3592 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3593 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3599 * We assume no holes between segments at this point
3603 KeBugCheck(MEMORY_MANAGEMENT
);
3607 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3613 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3614 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3616 LARGE_INTEGER Offset
;
3618 PVOID FileHeaderBuffer
;
3619 ULONG FileHeaderSize
;
3621 ULONG OldNrSegments
;
3626 * Read the beginning of the file (2 pages). Should be enough to contain
3627 * all (or most) of the headers
3629 Offset
.QuadPart
= 0;
3631 /* FIXME: use FileObject instead of FileHandle */
3632 Status
= ExeFmtpReadFile (FileHandle
,
3639 if (!NT_SUCCESS(Status
))
3642 if (FileHeaderSize
== 0)
3644 ExFreePool(FileHeaderBuffer
);
3645 return STATUS_UNSUCCESSFUL
;
3649 * Look for a loader that can handle this executable
3651 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3653 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3656 /* FIXME: use FileObject instead of FileHandle */
3657 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3663 ExeFmtpAllocateSegments
);
3665 if (!NT_SUCCESS(Status
))
3667 if (ImageSectionObject
->Segments
)
3669 ExFreePool(ImageSectionObject
->Segments
);
3670 ImageSectionObject
->Segments
= NULL
;
3674 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3678 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3681 * No loader handled the format
3683 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3685 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3686 ASSERT(!NT_SUCCESS(Status
));
3689 if (!NT_SUCCESS(Status
))
3692 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3697 /* FIXME? are these values platform-dependent? */
3698 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3699 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3701 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3702 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3704 if(ImageSectionObject
->BasedAddress
== NULL
)
3706 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3707 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3709 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3713 * And now the fun part: fixing the segments
3716 /* Sort them by virtual address */
3717 MmspSortSegments(ImageSectionObject
, Flags
);
3719 /* Ensure they don't overlap in memory */
3720 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3721 return STATUS_INVALID_IMAGE_FORMAT
;
3723 /* Ensure they are aligned */
3724 OldNrSegments
= ImageSectionObject
->NrSegments
;
3726 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3727 return STATUS_INVALID_IMAGE_FORMAT
;
3729 /* Trim them if the alignment phase merged some of them */
3730 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3732 PMM_SECTION_SEGMENT Segments
;
3733 SIZE_T SizeOfSegments
;
3735 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3737 Segments
= ExAllocatePoolWithTag(PagedPool
,
3739 TAG_MM_SECTION_SEGMENT
);
3741 if (Segments
== NULL
)
3742 return STATUS_INSUFFICIENT_RESOURCES
;
3744 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3745 ExFreePool(ImageSectionObject
->Segments
);
3746 ImageSectionObject
->Segments
= Segments
;
3749 /* And finish their initialization */
3750 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3752 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3753 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3754 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3757 ASSERT(NT_SUCCESS(Status
));
3762 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3763 ACCESS_MASK DesiredAccess
,
3764 POBJECT_ATTRIBUTES ObjectAttributes
,
3765 PLARGE_INTEGER UMaximumSize
,
3766 ULONG SectionPageProtection
,
3767 ULONG AllocationAttributes
,
3768 PFILE_OBJECT FileObject
)
3770 PROS_SECTION_OBJECT Section
;
3772 PMM_SECTION_SEGMENT SectionSegments
;
3773 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3776 if (FileObject
== NULL
)
3777 return STATUS_INVALID_FILE_FOR_SECTION
;
3780 * Create the section
3782 Status
= ObCreateObject (ExGetPreviousMode(),
3783 MmSectionObjectType
,
3785 ExGetPreviousMode(),
3787 sizeof(ROS_SECTION_OBJECT
),
3790 (PVOID
*)(PVOID
)&Section
);
3791 if (!NT_SUCCESS(Status
))
3793 ObDereferenceObject(FileObject
);
3800 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3801 Section
->Type
= 'SC';
3802 Section
->Size
= 'TN';
3803 Section
->SectionPageProtection
= SectionPageProtection
;
3804 Section
->AllocationAttributes
= AllocationAttributes
;
3808 * Initialized caching for this file object if previously caching
3809 * was initialized for the same on disk file
3811 Status
= CcTryToInitializeFileCache(FileObject
);
3813 Status
= STATUS_SUCCESS
;
3816 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3818 NTSTATUS StatusExeFmt
;
3820 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3821 if (ImageSectionObject
== NULL
)
3823 ObDereferenceObject(FileObject
);
3824 ObDereferenceObject(Section
);
3825 return(STATUS_NO_MEMORY
);
3828 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3830 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3832 if (!NT_SUCCESS(StatusExeFmt
))
3834 if(ImageSectionObject
->Segments
!= NULL
)
3835 ExFreePool(ImageSectionObject
->Segments
);
3837 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3838 ObDereferenceObject(Section
);
3839 ObDereferenceObject(FileObject
);
3840 return(StatusExeFmt
);
3843 Section
->ImageSection
= ImageSectionObject
;
3844 ASSERT(ImageSectionObject
->Segments
);
3849 Status
= MmspWaitForFileLock(FileObject
);
3850 if (!NT_SUCCESS(Status
))
3852 ExFreePool(ImageSectionObject
->Segments
);
3853 ExFreePool(ImageSectionObject
);
3854 ObDereferenceObject(Section
);
3855 ObDereferenceObject(FileObject
);
3859 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3860 ImageSectionObject
, NULL
))
3863 * An other thread has initialized the same image in the background
3865 ExFreePool(ImageSectionObject
->Segments
);
3866 ExFreePool(ImageSectionObject
);
3867 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3868 Section
->ImageSection
= ImageSectionObject
;
3869 SectionSegments
= ImageSectionObject
->Segments
;
3871 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3873 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3877 Status
= StatusExeFmt
;
3884 Status
= MmspWaitForFileLock(FileObject
);
3885 if (Status
!= STATUS_SUCCESS
)
3887 ObDereferenceObject(Section
);
3888 ObDereferenceObject(FileObject
);
3892 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3893 Section
->ImageSection
= ImageSectionObject
;
3894 SectionSegments
= ImageSectionObject
->Segments
;
3897 * Otherwise just reference all the section segments
3899 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3901 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3904 Status
= STATUS_SUCCESS
;
3906 Section
->FileObject
= FileObject
;
3908 CcRosReferenceCache(FileObject
);
3910 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3911 *SectionObject
= Section
;
3918 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3919 PROS_SECTION_OBJECT Section
,
3920 PMM_SECTION_SEGMENT Segment
,
3925 ULONG AllocationType
)
3931 if (Segment
->WriteCopy
)
3933 /* We have to do this because the not present fault
3934 * and access fault handlers depend on the protection
3935 * that should be granted AFTER the COW fault takes
3936 * place to be in Region->Protect. The not present fault
3937 * handler changes this to the correct protection for COW when
3938 * mapping the pages into the process's address space. If a COW
3939 * fault takes place, the access fault handler sets the page protection
3940 * to these values for the newly copied pages
3942 if (Protect
== PAGE_WRITECOPY
)
3943 Protect
= PAGE_READWRITE
;
3944 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3945 Protect
= PAGE_EXECUTE_READWRITE
;
3948 if (*BaseAddress
== NULL
)
3949 Granularity
= MM_ALLOCATION_GRANULARITY
;
3951 Granularity
= PAGE_SIZE
;
3954 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3956 LARGE_INTEGER FileOffset
;
3957 FileOffset
.QuadPart
= ViewOffset
;
3958 ObReferenceObject(Section
);
3959 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3962 Status
= MmCreateMemoryArea(AddressSpace
,
3963 MEMORY_AREA_SECTION_VIEW
,
3970 if (!NT_SUCCESS(Status
))
3972 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3973 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3977 ObReferenceObject((PVOID
)Section
);
3979 MArea
->Data
.SectionData
.Segment
= Segment
;
3980 MArea
->Data
.SectionData
.Section
= Section
;
3981 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3982 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3984 MArea
->VadNode
.u
.VadFlags
.VadType
= VadImageMap
;
3987 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3988 ViewSize
, 0, Protect
);
3990 return(STATUS_SUCCESS
);
3995 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3996 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4000 PFILE_OBJECT FileObject
;
4001 PROS_SHARED_CACHE_MAP SharedCacheMap
;
4003 LARGE_INTEGER Offset
;
4004 SWAPENTRY SavedSwapEntry
;
4005 PROS_SECTION_OBJECT Section
;
4006 PMM_SECTION_SEGMENT Segment
;
4007 PMMSUPPORT AddressSpace
;
4010 AddressSpace
= (PMMSUPPORT
)Context
;
4011 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4013 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4015 Offset
.QuadPart
= ((ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)) +
4016 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
4018 Section
= MemoryArea
->Data
.SectionData
.Section
;
4019 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4021 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4022 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
4024 MmUnlockSectionSegment(Segment
);
4025 MmUnlockAddressSpace(AddressSpace
);
4027 MiWaitForPageEvent(NULL
, NULL
);
4029 MmLockAddressSpace(AddressSpace
);
4030 MmLockSectionSegment(Segment
);
4031 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4035 * For a dirty, datafile, non-private page mark it as dirty in the
4038 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4040 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4043 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4044 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4045 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4047 ASSERT(SwapEntry
== 0);
4056 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4058 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4059 KeBugCheck(MEMORY_MANAGEMENT
);
4061 MmFreeSwapPage(SwapEntry
);
4065 if (IS_SWAP_FROM_SSE(Entry
) ||
4066 Page
!= PFN_FROM_SSE(Entry
))
4071 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4073 DPRINT1("Found a private page in a pagefile section.\n");
4074 KeBugCheck(MEMORY_MANAGEMENT
);
4077 * Just dereference private pages
4079 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4080 if (SavedSwapEntry
!= 0)
4082 MmFreeSwapPage(SavedSwapEntry
);
4083 MmSetSavedSwapEntryPage(Page
, 0);
4085 MmDeleteRmap(Page
, Process
, Address
);
4086 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4090 MmDeleteRmap(Page
, Process
, Address
);
4091 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4097 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4101 PMEMORY_AREA MemoryArea
;
4102 PROS_SECTION_OBJECT Section
;
4103 PMM_SECTION_SEGMENT Segment
;
4104 PLIST_ENTRY CurrentEntry
;
4105 PMM_REGION CurrentRegion
;
4106 PLIST_ENTRY RegionListHead
;
4108 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4110 if (MemoryArea
== NULL
)
4112 return(STATUS_UNSUCCESSFUL
);
4115 Section
= MemoryArea
->Data
.SectionData
.Section
;
4116 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4119 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4121 MmUnlockAddressSpace(AddressSpace
);
4122 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4123 MmLockAddressSpace(AddressSpace
);
4129 MemoryArea
->DeleteInProgress
= TRUE
;
4131 MmLockSectionSegment(Segment
);
4133 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4134 while (!IsListEmpty(RegionListHead
))
4136 CurrentEntry
= RemoveHeadList(RegionListHead
);
4137 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4138 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4141 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4143 Status
= MmFreeMemoryArea(AddressSpace
,
4150 Status
= MmFreeMemoryArea(AddressSpace
,
4155 MmUnlockSectionSegment(Segment
);
4156 ObDereferenceObject(Section
);
4162 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4163 IN PVOID BaseAddress
,
4167 PMEMORY_AREA MemoryArea
;
4168 PMMSUPPORT AddressSpace
;
4169 PROS_SECTION_OBJECT Section
;
4170 PVOID ImageBaseAddress
= 0;
4172 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4173 Process
, BaseAddress
);
4177 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4179 MmLockAddressSpace(AddressSpace
);
4180 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4182 if (MemoryArea
== NULL
||
4183 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4184 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4185 MemoryArea
->DeleteInProgress
)
4187 if (MemoryArea
) NT_ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4188 MmUnlockAddressSpace(AddressSpace
);
4189 return STATUS_NOT_MAPPED_VIEW
;
4192 Section
= MemoryArea
->Data
.SectionData
.Section
;
4194 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4198 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4199 PMM_SECTION_SEGMENT SectionSegments
;
4200 PMM_SECTION_SEGMENT Segment
;
4202 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4203 ImageSectionObject
= Section
->ImageSection
;
4204 SectionSegments
= ImageSectionObject
->Segments
;
4205 NrSegments
= ImageSectionObject
->NrSegments
;
4207 MemoryArea
->DeleteInProgress
= TRUE
;
4209 /* Search for the current segment within the section segments
4210 * and calculate the image base address */
4211 for (i
= 0; i
< NrSegments
; i
++)
4213 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4215 if (Segment
== &SectionSegments
[i
])
4217 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4222 if (i
>= NrSegments
)
4224 KeBugCheck(MEMORY_MANAGEMENT
);
4227 for (i
= 0; i
< NrSegments
; i
++)
4229 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4231 PVOID SBaseAddress
= (PVOID
)
4232 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4234 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4235 NT_ASSERT(NT_SUCCESS(Status
));
4241 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4242 NT_ASSERT(NT_SUCCESS(Status
));
4245 MmUnlockAddressSpace(AddressSpace
);
4247 /* Notify debugger */
4248 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4250 return(STATUS_SUCCESS
);
4257 * Queries the information of a section object.
4259 * @param SectionHandle
4260 * Handle to the section object. It must be opened with SECTION_QUERY
4262 * @param SectionInformationClass
4263 * Index to a certain information structure. Can be either
4264 * SectionBasicInformation or SectionImageInformation. The latter
4265 * is valid only for sections that were created with the SEC_IMAGE
4267 * @param SectionInformation
4268 * Caller supplies storage for resulting information.
4270 * Size of the supplied storage.
4271 * @param ResultLength
4279 NtQuerySection(IN HANDLE SectionHandle
,
4280 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4281 OUT PVOID SectionInformation
,
4282 IN SIZE_T SectionInformationLength
,
4283 OUT PSIZE_T ResultLength OPTIONAL
)
4285 PROS_SECTION_OBJECT Section
;
4286 KPROCESSOR_MODE PreviousMode
;
4290 PreviousMode
= ExGetPreviousMode();
4292 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4294 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4296 (ULONG
)SectionInformationLength
,
4301 if(!NT_SUCCESS(Status
))
4303 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4307 Status
= ObReferenceObjectByHandle(SectionHandle
,
4309 MmSectionObjectType
,
4311 (PVOID
*)(PVOID
)&Section
,
4313 if (NT_SUCCESS(Status
))
4315 switch (SectionInformationClass
)
4317 case SectionBasicInformation
:
4319 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4323 Sbi
->Attributes
= Section
->AllocationAttributes
;
4324 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4326 Sbi
->BaseAddress
= 0;
4327 Sbi
->Size
.QuadPart
= 0;
4331 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4332 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4335 if (ResultLength
!= NULL
)
4337 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4339 Status
= STATUS_SUCCESS
;
4341 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4343 Status
= _SEH2_GetExceptionCode();
4350 case SectionImageInformation
:
4352 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4356 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4358 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4359 ImageSectionObject
= Section
->ImageSection
;
4361 *Sii
= ImageSectionObject
->ImageInformation
;
4364 if (ResultLength
!= NULL
)
4366 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4368 Status
= STATUS_SUCCESS
;
4370 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4372 Status
= _SEH2_GetExceptionCode();
4380 ObDereferenceObject(Section
);
4386 /**********************************************************************
4388 * MmMapViewOfSection
4391 * Maps a view of a section into the virtual address space of a
4396 * Pointer to the section object.
4399 * Pointer to the process.
4402 * Desired base address (or NULL) on entry;
4403 * Actual base address of the view on exit.
4406 * Number of high order address bits that must be zero.
4409 * Size in bytes of the initially committed section of
4413 * Offset in bytes from the beginning of the section
4414 * to the beginning of the view.
4417 * Desired length of map (or zero to map all) on entry
4418 * Actual length mapped on exit.
4420 * InheritDisposition
4421 * Specified how the view is to be shared with
4425 * Type of allocation for the pages.
4428 * Protection for the committed region of the view.
4436 MmMapViewOfSection(IN PVOID SectionObject
,
4437 IN PEPROCESS Process
,
4438 IN OUT PVOID
*BaseAddress
,
4439 IN ULONG_PTR ZeroBits
,
4440 IN SIZE_T CommitSize
,
4441 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4442 IN OUT PSIZE_T ViewSize
,
4443 IN SECTION_INHERIT InheritDisposition
,
4444 IN ULONG AllocationType
,
4447 PROS_SECTION_OBJECT Section
;
4448 PMMSUPPORT AddressSpace
;
4450 NTSTATUS Status
= STATUS_SUCCESS
;
4451 BOOLEAN NotAtBase
= FALSE
;
4453 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4455 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4456 return MmMapViewOfArm3Section(SectionObject
,
4470 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4472 return STATUS_INVALID_PAGE_PROTECTION
;
4476 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4477 AddressSpace
= &Process
->Vm
;
4479 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4481 MmLockAddressSpace(AddressSpace
);
4483 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4487 ULONG_PTR ImageBase
;
4489 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4490 PMM_SECTION_SEGMENT SectionSegments
;
4492 ImageSectionObject
= Section
->ImageSection
;
4493 SectionSegments
= ImageSectionObject
->Segments
;
4494 NrSegments
= ImageSectionObject
->NrSegments
;
4496 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4499 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4503 for (i
= 0; i
< NrSegments
; i
++)
4505 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4507 ULONG_PTR MaxExtent
;
4508 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4509 SectionSegments
[i
].Length
.QuadPart
);
4510 ImageSize
= max(ImageSize
, MaxExtent
);
4514 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4516 /* Check for an illegal base address */
4517 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4518 ((ImageBase
+ ImageSize
) < ImageSize
))
4520 NT_ASSERT(*BaseAddress
== NULL
);
4521 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4522 MM_VIRTMEM_GRANULARITY
);
4525 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4527 NT_ASSERT(*BaseAddress
== NULL
);
4528 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4532 /* Check there is enough space to map the section at that point. */
4533 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4534 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4536 /* Fail if the user requested a fixed base address. */
4537 if ((*BaseAddress
) != NULL
)
4539 MmUnlockAddressSpace(AddressSpace
);
4540 return(STATUS_CONFLICTING_ADDRESSES
);
4542 /* Otherwise find a gap to map the image. */
4543 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4546 MmUnlockAddressSpace(AddressSpace
);
4547 return(STATUS_CONFLICTING_ADDRESSES
);
4549 /* Remember that we loaded image at a different base address */
4553 for (i
= 0; i
< NrSegments
; i
++)
4555 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4557 PVOID SBaseAddress
= (PVOID
)
4558 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4559 MmLockSectionSegment(&SectionSegments
[i
]);
4560 Status
= MmMapViewOfSegment(AddressSpace
,
4562 &SectionSegments
[i
],
4564 SectionSegments
[i
].Length
.LowPart
,
4565 SectionSegments
[i
].Protection
,
4568 MmUnlockSectionSegment(&SectionSegments
[i
]);
4569 if (!NT_SUCCESS(Status
))
4571 MmUnlockAddressSpace(AddressSpace
);
4577 *BaseAddress
= (PVOID
)ImageBase
;
4578 *ViewSize
= ImageSize
;
4582 /* check for write access */
4583 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4584 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4586 MmUnlockAddressSpace(AddressSpace
);
4587 return STATUS_SECTION_PROTECTION
;
4589 /* check for read access */
4590 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4591 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4593 MmUnlockAddressSpace(AddressSpace
);
4594 return STATUS_SECTION_PROTECTION
;
4596 /* check for execute access */
4597 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4598 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4600 MmUnlockAddressSpace(AddressSpace
);
4601 return STATUS_SECTION_PROTECTION
;
4604 if (ViewSize
== NULL
)
4606 /* Following this pointer would lead to us to the dark side */
4607 /* What to do? Bugcheck? Return status? Do the mambo? */
4608 KeBugCheck(MEMORY_MANAGEMENT
);
4611 if (SectionOffset
== NULL
)
4617 ViewOffset
= SectionOffset
->u
.LowPart
;
4620 if ((ViewOffset
% PAGE_SIZE
) != 0)
4622 MmUnlockAddressSpace(AddressSpace
);
4623 return(STATUS_MAPPED_ALIGNMENT
);
4626 if ((*ViewSize
) == 0)
4628 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4630 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4632 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4635 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4637 MmLockSectionSegment(Section
->Segment
);
4638 Status
= MmMapViewOfSegment(AddressSpace
,
4645 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4646 MmUnlockSectionSegment(Section
->Segment
);
4647 if (!NT_SUCCESS(Status
))
4649 MmUnlockAddressSpace(AddressSpace
);
4654 MmUnlockAddressSpace(AddressSpace
);
4655 NT_ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4658 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4660 Status
= STATUS_SUCCESS
;
4669 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4670 IN PLARGE_INTEGER NewFileSize
)
4672 /* Check whether an ImageSectionObject exists */
4673 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4675 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4679 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4681 PMM_SECTION_SEGMENT Segment
;
4683 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4686 if (Segment
->ReferenceCount
!= 0)
4689 CC_FILE_SIZES FileSizes
;
4691 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4694 /* Check size of file */
4695 if (SectionObjectPointer
->SharedCacheMap
)
4697 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4702 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4711 /* Check size of file */
4712 if (SectionObjectPointer
->SharedCacheMap
)
4714 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4715 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4724 /* Something must gone wrong
4725 * how can we have a Section but no
4727 DPRINT("ERROR: DataSectionObject without reference!\n");
4731 DPRINT("FIXME: didn't check for outstanding write probes\n");
4743 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4744 IN MMFLUSH_TYPE FlushType
)
4746 BOOLEAN Result
= TRUE
;
4748 PMM_SECTION_SEGMENT Segment
;
4753 case MmFlushForDelete
:
4754 if (SectionObjectPointer
->ImageSectionObject
||
4755 SectionObjectPointer
->DataSectionObject
)
4760 CcRosRemoveIfClosed(SectionObjectPointer
);
4763 case MmFlushForWrite
:
4765 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4767 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4770 if (SectionObjectPointer
->ImageSectionObject
)
4772 DPRINT1("SectionObject has ImageSection\n");
4778 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4780 DPRINT("Result %d\n", Result
);
4792 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4793 OUT PVOID
* MappedBase
,
4794 IN OUT PSIZE_T ViewSize
)
4796 PROS_SECTION_OBJECT Section
;
4797 PMMSUPPORT AddressSpace
;
4801 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4803 return MiMapViewInSystemSpace(SectionObject
,
4809 DPRINT("MmMapViewInSystemSpace() called\n");
4811 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4812 AddressSpace
= MmGetKernelAddressSpace();
4814 MmLockAddressSpace(AddressSpace
);
4817 if ((*ViewSize
) == 0)
4819 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4821 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4823 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4826 MmLockSectionSegment(Section
->Segment
);
4829 Status
= MmMapViewOfSegment(AddressSpace
,
4838 MmUnlockSectionSegment(Section
->Segment
);
4839 MmUnlockAddressSpace(AddressSpace
);
4846 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4848 PMMSUPPORT AddressSpace
;
4851 DPRINT("MmUnmapViewInSystemSpace() called\n");
4853 AddressSpace
= MmGetKernelAddressSpace();
4855 MmLockAddressSpace(AddressSpace
);
4857 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4859 MmUnlockAddressSpace(AddressSpace
);
4864 /**********************************************************************
4869 * Creates a section object.
4872 * SectionObject (OUT)
4873 * Caller supplied storage for the resulting pointer
4874 * to a SECTION_OBJECT instance;
4877 * Specifies the desired access to the section can be a
4879 * STANDARD_RIGHTS_REQUIRED |
4881 * SECTION_MAP_WRITE |
4882 * SECTION_MAP_READ |
4883 * SECTION_MAP_EXECUTE
4885 * ObjectAttributes [OPTIONAL]
4886 * Initialized attributes for the object can be used
4887 * to create a named section;
4890 * Maximizes the size of the memory section. Must be
4891 * non-NULL for a page-file backed section.
4892 * If value specified for a mapped file and the file is
4893 * not large enough, file will be extended.
4895 * SectionPageProtection
4896 * Can be a combination of:
4902 * AllocationAttributes
4903 * Can be a combination of:
4908 * Handle to a file to create a section mapped to a file
4909 * instead of a memory backed section;
4920 MmCreateSection (OUT PVOID
* Section
,
4921 IN ACCESS_MASK DesiredAccess
,
4922 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4923 IN PLARGE_INTEGER MaximumSize
,
4924 IN ULONG SectionPageProtection
,
4925 IN ULONG AllocationAttributes
,
4926 IN HANDLE FileHandle OPTIONAL
,
4927 IN PFILE_OBJECT FileObject OPTIONAL
)
4931 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4933 /* Check if an ARM3 section is being created instead */
4934 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4936 if (!(FileObject
) && !(FileHandle
))
4938 return MmCreateArm3Section(Section
,
4942 SectionPageProtection
,
4943 AllocationAttributes
&~ 1,
4949 /* Convert section flag to page flag */
4950 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4952 /* Check to make sure the protection is correct. Nt* does this already */
4953 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4954 if (Protection
== MM_INVALID_PROTECTION
)
4956 DPRINT1("Page protection is invalid\n");
4957 return STATUS_INVALID_PAGE_PROTECTION
;
4960 /* Check if this is going to be a data or image backed file section */
4961 if ((FileHandle
) || (FileObject
))
4963 /* These cannot be mapped with large pages */
4964 if (AllocationAttributes
& SEC_LARGE_PAGES
)
4966 DPRINT1("Large pages cannot be used with an image mapping\n");
4967 return STATUS_INVALID_PARAMETER_6
;
4970 /* Did the caller pass an object? */
4973 /* Reference the object directly */
4974 ObReferenceObject(FileObject
);
4978 /* Reference the file handle to get the object */
4979 Status
= ObReferenceObjectByHandle(FileHandle
,
4980 MmMakeFileAccess
[Protection
],
4982 ExGetPreviousMode(),
4983 (PVOID
*)&FileObject
,
4985 if (!NT_SUCCESS(Status
))
4987 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
4994 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
4995 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
4998 #ifndef NEWCC // A hack for initializing caching.
4999 // This is needed only in the old case.
5002 IO_STATUS_BLOCK Iosb
;
5005 LARGE_INTEGER ByteOffset
;
5006 ByteOffset
.QuadPart
= 0;
5007 Status
= ZwReadFile(FileHandle
,
5016 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5018 DPRINT1("CC failure: %lx\n", Status
);
5021 // Caching is initialized...
5025 if (AllocationAttributes
& SEC_IMAGE
)
5027 Status
= MmCreateImageSection(SectionObject
,
5031 SectionPageProtection
,
5032 AllocationAttributes
,
5036 else if (FileHandle
!= NULL
)
5038 Status
= MmCreateDataFileSection(SectionObject
,
5042 SectionPageProtection
,
5043 AllocationAttributes
,
5046 ObDereferenceObject(FileObject
);
5049 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5051 Status
= MmCreateCacheSection(SectionObject
,
5055 SectionPageProtection
,
5056 AllocationAttributes
,
5062 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5064 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5066 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5067 Status
= MmCreatePageFileSection(SectionObject
,
5071 SectionPageProtection
,
5072 AllocationAttributes
);