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
,
175 /* FUNCTIONS *****************************************************************/
180 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
181 File Format Specification", revision 6.0 (February 1999)
183 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
184 IN SIZE_T FileHeaderSize
,
186 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
188 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
189 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
192 ULONG cbFileHeaderOffsetSize
= 0;
193 ULONG cbSectionHeadersOffset
= 0;
194 ULONG cbSectionHeadersSize
;
195 ULONG cbSectionHeadersOffsetSize
= 0;
196 ULONG cbOptHeaderSize
;
197 ULONG cbHeadersSize
= 0;
198 ULONG nSectionAlignment
;
199 ULONG nFileAlignment
;
201 const IMAGE_DOS_HEADER
* pidhDosHeader
;
202 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
203 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
204 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
205 PMM_SECTION_SEGMENT pssSegments
;
206 LARGE_INTEGER lnOffset
;
208 SIZE_T nPrevVirtualEndOfSegment
= 0;
209 ULONG nFileSizeOfHeaders
= 0;
214 ASSERT(FileHeaderSize
> 0);
216 ASSERT(ImageSectionObject
);
218 ASSERT(AllocateSegmentsCb
);
220 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
222 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
224 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
227 pidhDosHeader
= FileHeader
;
230 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
232 /* image too small to be an MZ executable */
233 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
234 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
236 /* no MZ signature */
237 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
238 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
241 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
243 /* not a Windows executable */
244 if(pidhDosHeader
->e_lfanew
<= 0)
245 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
247 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
248 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
250 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
255 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
256 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
258 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
259 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
263 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
264 * need to read the header from the file
266 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
267 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
269 ULONG cbNtHeaderSize
;
273 l_ReadHeaderFromFile
:
275 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
277 /* read the header from the file */
278 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
280 if(!NT_SUCCESS(nStatus
))
282 NTSTATUS ReturnedStatus
= nStatus
;
284 /* If it attempted to read past the end of the file, it means e_lfanew is invalid */
285 if (ReturnedStatus
== STATUS_END_OF_FILE
) nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
287 DIE(("ReadFile failed, status %08X\n", ReturnedStatus
));
292 ASSERT(cbReadSize
> 0);
294 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
296 /* the buffer doesn't contain the file header */
297 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
298 DIE(("The file doesn't contain the PE file header\n"));
300 pinhNtHeader
= pData
;
302 /* object still not aligned: copy it to the beginning of the buffer */
303 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
305 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
306 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
307 pinhNtHeader
= pBuffer
;
310 /* invalid NT header */
311 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
313 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
314 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
316 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
318 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
319 DIE(("The full NT header is too large\n"));
321 /* the buffer doesn't contain the whole NT header */
322 if(cbReadSize
< cbNtHeaderSize
)
323 DIE(("The file doesn't contain the full NT header\n"));
327 ULONG cbOptHeaderOffsetSize
= 0;
329 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
331 /* don't trust an invalid NT header */
332 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
333 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
335 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
336 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
338 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
340 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
341 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
343 /* the buffer doesn't contain the whole NT header: read it from the file */
344 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
345 goto l_ReadHeaderFromFile
;
348 /* read information from the NT header */
349 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
350 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
352 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
354 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
355 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
357 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
359 switch(piohOptHeader
->Magic
)
361 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
363 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
368 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
371 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
372 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
374 /* See [1], section 3.4.2 */
375 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
377 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
378 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
380 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
381 DIE(("The section alignment is smaller than the file alignment\n"));
383 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
384 nFileAlignment
= piohOptHeader
->FileAlignment
;
386 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
387 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
391 nSectionAlignment
= PAGE_SIZE
;
392 nFileAlignment
= PAGE_SIZE
;
395 ASSERT(IsPowerOf2(nSectionAlignment
));
396 ASSERT(IsPowerOf2(nFileAlignment
));
398 switch(piohOptHeader
->Magic
)
401 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
403 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
404 ImageBase
= piohOptHeader
->ImageBase
;
406 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
407 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
409 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
410 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
412 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
413 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
415 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
417 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
419 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
420 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
422 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
423 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
427 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
429 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
430 piohOptHeader
->AddressOfEntryPoint
);
433 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
434 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
436 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
438 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
440 if (piohOptHeader
->AddressOfEntryPoint
== 0)
442 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
446 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
447 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
449 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
451 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
454 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
455 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
456 * magic to any binary.
458 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
459 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
460 * the SxS support -- at which point, duh, this should be removed.
462 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
464 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
471 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
473 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
475 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
477 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
479 ImageBase
= pioh64OptHeader
->ImageBase
;
480 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
481 DIE(("ImageBase exceeds the address space\n"));
484 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
486 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
487 DIE(("SizeOfImage exceeds the address space\n"));
489 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
492 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
494 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
495 DIE(("SizeOfStackReserve exceeds the address space\n"));
497 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
500 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
502 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
503 DIE(("SizeOfStackCommit exceeds the address space\n"));
505 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
508 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
510 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
512 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
513 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
515 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
516 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
520 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
522 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
523 pioh64OptHeader
->AddressOfEntryPoint
);
526 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
527 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
529 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
531 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
533 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
535 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
539 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
540 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
542 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
543 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
550 /* [1], section 3.4.2 */
551 if((ULONG_PTR
)ImageBase
% 0x10000)
552 DIE(("ImageBase is not aligned on a 64KB boundary"));
554 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
555 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
556 ImageSectionObject
->ImageInformation
.GpValue
= 0;
557 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
558 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
560 /* SECTION HEADERS */
561 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
563 /* see [1], section 3.3 */
564 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
565 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
568 * the additional segment is for the file's headers. They need to be present for
569 * the benefit of the dynamic loader (to locate exports, defaults for thread
570 * parameters, resources, etc.)
572 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
574 /* file offset for the section headers */
575 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
576 DIE(("Offset overflow\n"));
578 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
579 DIE(("Offset overflow\n"));
581 /* size of the section headers */
582 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
583 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
585 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
586 DIE(("Section headers too large\n"));
588 /* size of the executable's headers */
589 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
591 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
592 // DIE(("SizeOfHeaders is not aligned\n"));
594 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
595 DIE(("The section headers overflow SizeOfHeaders\n"));
597 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
599 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
600 DIE(("Overflow aligning the size of headers\n"));
607 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
608 /* WARNING: piohOptHeader IS NO LONGER USABLE */
609 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
611 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
612 pishSectionHeaders
= NULL
;
616 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
617 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
619 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
620 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
624 * the buffer doesn't contain the section headers, or the alignment is wrong:
625 * read the headers from the file
627 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
628 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
633 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
635 /* read the header from the file */
636 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
638 if(!NT_SUCCESS(nStatus
))
639 DIE(("ReadFile failed with status %08X\n", nStatus
));
643 ASSERT(cbReadSize
> 0);
645 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
647 /* the buffer doesn't contain all the section headers */
648 if(cbReadSize
< cbSectionHeadersSize
)
649 DIE(("The file doesn't contain all of the section headers\n"));
651 pishSectionHeaders
= pData
;
653 /* object still not aligned: copy it to the beginning of the buffer */
654 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
656 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
657 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
658 pishSectionHeaders
= pBuffer
;
663 /* allocate the segments */
664 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
665 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
667 if(ImageSectionObject
->Segments
== NULL
)
668 DIE(("AllocateSegments failed\n"));
670 /* initialize the headers segment */
671 pssSegments
= ImageSectionObject
->Segments
;
673 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
675 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
676 DIE(("Cannot align the size of the section headers\n"));
678 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
679 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
680 DIE(("Cannot align the size of the section headers\n"));
682 pssSegments
[0].Image
.FileOffset
= 0;
683 pssSegments
[0].Protection
= PAGE_READONLY
;
684 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
685 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
686 pssSegments
[0].Image
.VirtualAddress
= 0;
687 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
688 pssSegments
[0].WriteCopy
= TRUE
;
690 /* skip the headers segment */
693 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
695 /* convert the executable sections into segments. See also [1], section 4 */
696 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
698 ULONG nCharacteristics
;
700 /* validate the alignment */
701 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
702 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
704 /* sections must be contiguous, ordered by base address and non-overlapping */
705 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
706 DIE(("Memory gap between section %u and the previous\n", i
));
708 /* ignore explicit BSS sections */
709 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
711 /* validate the alignment */
713 /* Yes, this should be a multiple of FileAlignment, but there's
714 * stuff out there that isn't. We can cope with that
716 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
717 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
720 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
721 // DIE(("PointerToRawData[%u] is not aligned\n", i));
724 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
725 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
729 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
730 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
733 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
735 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
737 /* no explicit protection */
738 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
740 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
741 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
743 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
744 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
746 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
747 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
750 /* see table above */
751 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
752 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
754 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
755 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
757 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
759 AlignedLength
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
760 if(AlignedLength
< pssSegments
[i
].Length
.LowPart
)
761 DIE(("Cannot align the virtual size of section %u\n", i
));
763 pssSegments
[i
].Length
.LowPart
= AlignedLength
;
765 if(pssSegments
[i
].Length
.QuadPart
== 0)
766 DIE(("Virtual size of section %u is null\n", i
));
768 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
769 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
771 /* ensure the memory image is no larger than 4GB */
772 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
773 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
774 DIE(("The image is too large\n"));
777 if(nSectionAlignment
>= PAGE_SIZE
)
778 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
781 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
791 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
792 * ARGUMENTS: PFILE_OBJECT to wait for.
793 * RETURNS: Status of the wait.
796 MmspWaitForFileLock(PFILE_OBJECT File
)
798 return STATUS_SUCCESS
;
799 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
804 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
806 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
808 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
809 PMM_SECTION_SEGMENT SectionSegments
;
813 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
814 NrSegments
= ImageSectionObject
->NrSegments
;
815 SectionSegments
= ImageSectionObject
->Segments
;
816 for (i
= 0; i
< NrSegments
; i
++)
818 if (SectionSegments
[i
].ReferenceCount
!= 0)
820 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
821 SectionSegments
[i
].ReferenceCount
);
822 KeBugCheck(MEMORY_MANAGEMENT
);
824 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
826 ExFreePool(ImageSectionObject
->Segments
);
827 ExFreePool(ImageSectionObject
);
828 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
830 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
832 PMM_SECTION_SEGMENT Segment
;
834 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
837 if (Segment
->ReferenceCount
!= 0)
839 DPRINT1("Data segment still referenced\n");
840 KeBugCheck(MEMORY_MANAGEMENT
);
842 MmFreePageTablesSectionSegment(Segment
, NULL
);
844 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
850 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
851 PLARGE_INTEGER Offset
)
855 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
858 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
859 KeBugCheck(MEMORY_MANAGEMENT
);
861 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
863 DPRINT1("Maximum share count reached\n");
864 KeBugCheck(MEMORY_MANAGEMENT
);
866 if (IS_SWAP_FROM_SSE(Entry
))
868 KeBugCheck(MEMORY_MANAGEMENT
);
870 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
871 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
876 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
877 PMM_SECTION_SEGMENT Segment
,
878 PLARGE_INTEGER Offset
,
883 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
884 BOOLEAN IsDirectMapped
= FALSE
;
888 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
889 KeBugCheck(MEMORY_MANAGEMENT
);
891 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
893 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
894 KeBugCheck(MEMORY_MANAGEMENT
);
896 if (IS_SWAP_FROM_SSE(Entry
))
898 KeBugCheck(MEMORY_MANAGEMENT
);
900 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
902 * If we reducing the share count of this entry to zero then set the entry
903 * to zero and tell the cache the page is no longer mapped.
905 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
907 PFILE_OBJECT FileObject
;
908 SWAPENTRY SavedSwapEntry
;
911 PROS_SHARED_CACHE_MAP SharedCacheMap
;
912 BOOLEAN IsImageSection
;
913 LARGE_INTEGER FileOffset
;
915 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
916 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
919 Page
= PFN_FROM_SSE(Entry
);
920 FileObject
= Section
->FileObject
;
921 if (FileObject
!= NULL
&&
922 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
926 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
927 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
930 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
931 IsDirectMapped
= TRUE
;
933 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
.QuadPart
, Dirty
);
935 Status
= STATUS_SUCCESS
;
937 if (!NT_SUCCESS(Status
))
939 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
940 KeBugCheck(MEMORY_MANAGEMENT
);
946 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
947 if (SavedSwapEntry
== 0)
950 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
951 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
955 * Try to page out this page and set the swap entry
956 * within the section segment. There exist no rmap entry
957 * for this page. The pager thread can't page out a
958 * page without a rmap entry.
960 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
961 if (InEntry
) *InEntry
= Entry
;
962 MiSetPageEvent(NULL
, NULL
);
966 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
967 if (InEntry
) *InEntry
= 0;
968 MiSetPageEvent(NULL
, NULL
);
971 MmReleasePageMemoryConsumer(MC_USER
, Page
);
977 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
978 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
986 * We hold all locks. Nobody can do something with the current
987 * process and the current segment (also not within an other process).
990 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
991 if (!NT_SUCCESS(Status
))
993 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
994 KeBugCheck(MEMORY_MANAGEMENT
);
997 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
998 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
999 MmSetSavedSwapEntryPage(Page
, 0);
1000 MiSetPageEvent(NULL
, NULL
);
1002 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1006 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1007 KeBugCheck(MEMORY_MANAGEMENT
);
1016 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1018 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1021 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1025 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1027 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1029 SharedCacheMap
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1030 Vacb
= CcRosLookupVacb(SharedCacheMap
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
);
1033 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, FALSE
, TRUE
);
1043 MiCopyFromUserPage(PFN_NUMBER DestPage
, const VOID
*SrcAddress
)
1049 Process
= PsGetCurrentProcess();
1050 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1051 if (DestAddress
== NULL
)
1053 return(STATUS_NO_MEMORY
);
1055 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1056 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1057 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1058 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1059 return(STATUS_SUCCESS
);
1065 MiReadPage(PMEMORY_AREA MemoryArea
,
1069 * FUNCTION: Read a page for a section backed memory area.
1071 * MemoryArea - Memory area to read the page for.
1072 * Offset - Offset of the page to read.
1073 * Page - Variable that receives a page contains the read data.
1076 LONGLONG BaseOffset
;
1077 LONGLONG FileOffset
;
1081 PFILE_OBJECT FileObject
;
1084 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1085 BOOLEAN IsImageSection
;
1088 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1089 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1090 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
;
1091 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1092 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1094 ASSERT(SharedCacheMap
);
1096 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1099 * If the file system is letting us go directly to the cache and the
1100 * memory area was mapped at an offset in the file which is page aligned
1101 * then get the related VACB.
1103 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1104 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1105 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1109 * Get the related VACB; we use a lower level interface than
1110 * filesystems do because it is safe for us to use an offset with an
1111 * alignment less than the file system block size.
1113 Status
= CcRosGetVacb(SharedCacheMap
,
1119 if (!NT_SUCCESS(Status
))
1126 * If the VACB isn't up to date then call the file
1127 * system to read in the data.
1129 Status
= CcReadVirtualAddress(Vacb
);
1130 if (!NT_SUCCESS(Status
))
1132 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1137 /* Probe the page, since it's PDE might not be synced */
1138 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1141 * Retrieve the page from the view that we actually want.
1143 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1144 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1146 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, TRUE
);
1153 LONGLONG VacbOffset
;
1156 * Allocate a page, this is rather complicated by the possibility
1157 * we might have to move other things out of memory
1159 MI_SET_USAGE(MI_USAGE_SECTION
);
1160 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1161 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1162 if (!NT_SUCCESS(Status
))
1166 Status
= CcRosGetVacb(SharedCacheMap
,
1172 if (!NT_SUCCESS(Status
))
1179 * If the VACB isn't up to date then call the file
1180 * system to read in the data.
1182 Status
= CcReadVirtualAddress(Vacb
);
1183 if (!NT_SUCCESS(Status
))
1185 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1190 Process
= PsGetCurrentProcess();
1191 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1192 VacbOffset
= BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
;
1193 Length
= RawLength
- SegOffset
;
1194 if (Length
<= VacbOffset
&& Length
<= PAGE_SIZE
)
1196 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1198 else if (VacbOffset
>= PAGE_SIZE
)
1200 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1204 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, VacbOffset
);
1205 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1206 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1207 Status
= CcRosGetVacb(SharedCacheMap
,
1208 FileOffset
+ VacbOffset
,
1213 if (!NT_SUCCESS(Status
))
1220 * If the VACB isn't up to date then call the file
1221 * system to read in the data.
1223 Status
= CcReadVirtualAddress(Vacb
);
1224 if (!NT_SUCCESS(Status
))
1226 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1230 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1231 if (Length
< PAGE_SIZE
)
1233 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, Length
- VacbOffset
);
1237 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, PAGE_SIZE
- VacbOffset
);
1240 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1241 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1243 return(STATUS_SUCCESS
);
1248 MiReadPage(PMEMORY_AREA MemoryArea
,
1252 * FUNCTION: Read a page for a section backed memory area.
1254 * MemoryArea - Memory area to read the page for.
1255 * Offset - Offset of the page to read.
1256 * Page - Variable that receives a page contains the read data.
1259 MM_REQUIRED_RESOURCES Resources
;
1262 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1264 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1265 Resources
.FileOffset
.QuadPart
= SegOffset
+
1266 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1267 Resources
.Consumer
= MC_USER
;
1268 Resources
.Amount
= PAGE_SIZE
;
1270 DPRINT("%S, offset 0x%x, len 0x%x, page 0x%x\n", ((PFILE_OBJECT
)Resources
.Context
)->FileName
.Buffer
, Resources
.FileOffset
.LowPart
, Resources
.Amount
, Resources
.Page
[0]);
1272 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1273 *Page
= Resources
.Page
[0];
1280 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1281 MEMORY_AREA
* MemoryArea
,
1285 LARGE_INTEGER Offset
;
1288 PROS_SECTION_OBJECT Section
;
1289 PMM_SECTION_SEGMENT Segment
;
1294 BOOLEAN HasSwapEntry
;
1296 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1297 SWAPENTRY SwapEntry
;
1300 * There is a window between taking the page fault and locking the
1301 * address space when another thread could load the page so we check
1304 if (MmIsPagePresent(Process
, Address
))
1306 return(STATUS_SUCCESS
);
1309 if (MmIsDisabledPage(Process
, Address
))
1311 return(STATUS_ACCESS_VIOLATION
);
1315 * Check for the virtual memory area being deleted.
1317 if (MemoryArea
->DeleteInProgress
)
1319 return(STATUS_UNSUCCESSFUL
);
1322 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1323 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1324 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1326 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1327 Section
= MemoryArea
->Data
.SectionData
.Section
;
1328 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1329 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1331 ASSERT(Region
!= NULL
);
1335 MmLockSectionSegment(Segment
);
1336 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1338 * Check if this page needs to be mapped COW
1340 if ((Segment
->WriteCopy
) &&
1341 (Region
->Protect
== PAGE_READWRITE
||
1342 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1344 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1348 Attributes
= Region
->Protect
;
1352 * Check if someone else is already handling this fault, if so wait
1355 if (Entry
&& MM_IS_WAIT_PTE(Entry
))
1357 MmUnlockSectionSegment(Segment
);
1358 MmUnlockAddressSpace(AddressSpace
);
1359 MiWaitForPageEvent(NULL
, NULL
);
1360 MmLockAddressSpace(AddressSpace
);
1361 DPRINT("Address 0x%p\n", Address
);
1362 return(STATUS_MM_RESTART_OPERATION
);
1365 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1367 /* See if we should use a private page */
1368 if ((HasSwapEntry
) || (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
))
1370 SWAPENTRY DummyEntry
;
1373 * 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
);
1400 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1403 MmUnlockSectionSegment(Segment
);
1405 /* Tell everyone else we are serving the fault. */
1406 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1408 MmUnlockAddressSpace(AddressSpace
);
1409 MI_SET_USAGE(MI_USAGE_SECTION
);
1410 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1411 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1412 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1413 if (!NT_SUCCESS(Status
))
1415 KeBugCheck(MEMORY_MANAGEMENT
);
1420 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1421 if (!NT_SUCCESS(Status
))
1423 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1424 KeBugCheck(MEMORY_MANAGEMENT
);
1428 MmLockAddressSpace(AddressSpace
);
1429 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1430 Status
= MmCreateVirtualMapping(Process
,
1435 if (!NT_SUCCESS(Status
))
1437 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1438 KeBugCheck(MEMORY_MANAGEMENT
);
1443 * Store the swap entry for later use.
1446 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1449 * Add the page to the process's working set
1451 MmInsertRmap(Page
, Process
, Address
);
1453 * Finish the operation
1455 MiSetPageEvent(Process
, Address
);
1456 DPRINT("Address 0x%p\n", Address
);
1457 return(STATUS_SUCCESS
);
1461 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1463 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1465 MmUnlockSectionSegment(Segment
);
1467 * Just map the desired physical page
1469 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1470 Status
= MmCreateVirtualMappingUnsafe(Process
,
1475 if (!NT_SUCCESS(Status
))
1477 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1478 KeBugCheck(MEMORY_MANAGEMENT
);
1483 * Cleanup and release locks
1485 MiSetPageEvent(Process
, Address
);
1486 DPRINT("Address 0x%p\n", Address
);
1487 return(STATUS_SUCCESS
);
1491 * Get the entry corresponding to the offset within the section
1493 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1497 SWAPENTRY FakeSwapEntry
;
1500 * If the entry is zero (and it can't change because we have
1501 * locked the segment) then we need to load the page.
1505 * Release all our locks and read in the page from disk
1507 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1508 MmUnlockSectionSegment(Segment
);
1509 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1510 MmUnlockAddressSpace(AddressSpace
);
1512 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1513 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1514 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1516 MI_SET_USAGE(MI_USAGE_SECTION
);
1517 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1518 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1519 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1520 if (!NT_SUCCESS(Status
))
1522 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1528 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1529 if (!NT_SUCCESS(Status
))
1531 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1534 if (!NT_SUCCESS(Status
))
1537 * FIXME: What do we know in this case?
1540 * Cleanup and release locks
1542 MmLockAddressSpace(AddressSpace
);
1543 MiSetPageEvent(Process
, Address
);
1544 DPRINT("Address 0x%p\n", Address
);
1548 /* Lock both segment and process address space while we proceed. */
1549 MmLockAddressSpace(AddressSpace
);
1550 MmLockSectionSegment(Segment
);
1552 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1553 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1554 Page
, Process
, PAddress
, Attributes
);
1555 Status
= MmCreateVirtualMapping(Process
,
1560 if (!NT_SUCCESS(Status
))
1562 DPRINT1("Unable to create virtual mapping\n");
1563 KeBugCheck(MEMORY_MANAGEMENT
);
1565 ASSERT(MmIsPagePresent(Process
, PAddress
));
1566 MmInsertRmap(Page
, Process
, Address
);
1568 /* Set this section offset has being backed by our new page. */
1569 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1570 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1571 MmUnlockSectionSegment(Segment
);
1573 MiSetPageEvent(Process
, Address
);
1574 DPRINT("Address 0x%p\n", Address
);
1575 return(STATUS_SUCCESS
);
1577 else if (IS_SWAP_FROM_SSE(Entry
))
1579 SWAPENTRY SwapEntry
;
1581 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1583 /* See if a page op is running on this segment. */
1584 if (SwapEntry
== MM_WAIT_ENTRY
)
1586 MmUnlockSectionSegment(Segment
);
1587 MmUnlockAddressSpace(AddressSpace
);
1588 MiWaitForPageEvent(NULL
, NULL
);
1589 MmLockAddressSpace(AddressSpace
);
1590 return STATUS_MM_RESTART_OPERATION
;
1594 * Release all our locks and read in the page from disk
1596 MmUnlockSectionSegment(Segment
);
1598 MmUnlockAddressSpace(AddressSpace
);
1599 MI_SET_USAGE(MI_USAGE_SECTION
);
1600 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1601 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1602 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1603 if (!NT_SUCCESS(Status
))
1605 KeBugCheck(MEMORY_MANAGEMENT
);
1608 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1609 if (!NT_SUCCESS(Status
))
1611 KeBugCheck(MEMORY_MANAGEMENT
);
1615 * Relock the address space and segment
1617 MmLockAddressSpace(AddressSpace
);
1618 MmLockSectionSegment(Segment
);
1621 * Check the entry. No one should change the status of a page
1622 * that has a pending page-in.
1624 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1625 if (Entry
!= Entry1
)
1627 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1628 KeBugCheck(MEMORY_MANAGEMENT
);
1632 * Save the swap entry.
1634 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1636 /* Map the page into the process address space */
1637 Status
= MmCreateVirtualMapping(Process
,
1642 if (!NT_SUCCESS(Status
))
1644 DPRINT1("Unable to create virtual mapping\n");
1645 KeBugCheck(MEMORY_MANAGEMENT
);
1647 MmInsertRmap(Page
, Process
, Address
);
1650 * Mark the offset within the section as having valid, in-memory
1653 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1654 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1655 MmUnlockSectionSegment(Segment
);
1657 MiSetPageEvent(Process
, Address
);
1658 DPRINT("Address 0x%p\n", Address
);
1659 return(STATUS_SUCCESS
);
1663 /* We already have a page on this section offset. Map it into the process address space. */
1664 Page
= PFN_FROM_SSE(Entry
);
1666 Status
= MmCreateVirtualMapping(Process
,
1671 if (!NT_SUCCESS(Status
))
1673 DPRINT1("Unable to create virtual mapping\n");
1674 KeBugCheck(MEMORY_MANAGEMENT
);
1676 MmInsertRmap(Page
, Process
, Address
);
1678 /* Take a reference on it */
1679 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1680 MmUnlockSectionSegment(Segment
);
1682 MiSetPageEvent(Process
, Address
);
1683 DPRINT("Address 0x%p\n", Address
);
1684 return(STATUS_SUCCESS
);
1690 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1691 MEMORY_AREA
* MemoryArea
,
1694 PMM_SECTION_SEGMENT Segment
;
1695 PROS_SECTION_OBJECT Section
;
1700 LARGE_INTEGER Offset
;
1703 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1705 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1707 /* Make sure we have a page mapping for this address. */
1708 Status
= MmNotPresentFaultSectionView(AddressSpace
, MemoryArea
, Address
, TRUE
);
1709 if (!NT_SUCCESS(Status
))
1711 /* This is invalid access ! */
1716 * Check if the page has already been set readwrite
1718 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1720 DPRINT("Address 0x%p\n", Address
);
1721 return(STATUS_SUCCESS
);
1725 * Find the offset of the page
1727 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1728 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1729 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1731 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1732 Section
= MemoryArea
->Data
.SectionData
.Section
;
1733 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1734 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1736 ASSERT(Region
!= NULL
);
1739 * Check if we are doing COW
1741 if (!((Segment
->WriteCopy
) &&
1742 (Region
->Protect
== PAGE_READWRITE
||
1743 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1745 DPRINT("Address 0x%p\n", Address
);
1746 return(STATUS_ACCESS_VIOLATION
);
1749 /* Get the page mapping this section offset. */
1750 MmLockSectionSegment(Segment
);
1751 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1753 /* Get the current page mapping for the process */
1754 ASSERT(MmIsPagePresent(Process
, PAddress
));
1755 OldPage
= MmGetPfnForProcess(Process
, PAddress
);
1756 ASSERT(OldPage
!= 0);
1758 if (IS_SWAP_FROM_SSE(Entry
) ||
1759 PFN_FROM_SSE(Entry
) != OldPage
)
1761 MmUnlockSectionSegment(Segment
);
1762 /* This is a private page. We must only change the page protection. */
1763 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1764 return(STATUS_SUCCESS
);
1770 MI_SET_USAGE(MI_USAGE_SECTION
);
1771 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1772 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1773 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1774 if (!NT_SUCCESS(Status
))
1776 KeBugCheck(MEMORY_MANAGEMENT
);
1782 NT_VERIFY(NT_SUCCESS(MiCopyFromUserPage(NewPage
, PAddress
)));
1785 * Unshare the old page.
1787 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1788 MmDeleteVirtualMapping(Process
, PAddress
, NULL
, NULL
);
1789 MmDeleteRmap(OldPage
, Process
, PAddress
);
1790 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1791 MmUnlockSectionSegment(Segment
);
1794 * Set the PTE to point to the new page
1796 Status
= MmCreateVirtualMapping(Process
,
1801 if (!NT_SUCCESS(Status
))
1803 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1804 KeBugCheck(MEMORY_MANAGEMENT
);
1807 MmInsertRmap(NewPage
, Process
, PAddress
);
1809 MiSetPageEvent(Process
, Address
);
1810 DPRINT("Address 0x%p\n", Address
);
1811 return(STATUS_SUCCESS
);
1815 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1817 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1819 PFN_NUMBER Page
= 0;
1821 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1824 MmLockAddressSpace(&Process
->Vm
);
1827 MmDeleteVirtualMapping(Process
,
1833 PageOutContext
->WasDirty
= TRUE
;
1835 if (!PageOutContext
->Private
)
1837 MmLockSectionSegment(PageOutContext
->Segment
);
1838 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1839 PageOutContext
->Segment
,
1840 &PageOutContext
->Offset
,
1841 PageOutContext
->WasDirty
,
1843 &PageOutContext
->SectionEntry
);
1844 MmUnlockSectionSegment(PageOutContext
->Segment
);
1848 MmUnlockAddressSpace(&Process
->Vm
);
1851 if (PageOutContext
->Private
)
1853 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1859 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1860 MEMORY_AREA
* MemoryArea
,
1861 PVOID Address
, ULONG_PTR Entry
)
1864 MM_SECTION_PAGEOUT_CONTEXT Context
;
1865 SWAPENTRY SwapEntry
;
1868 ULONGLONG FileOffset
;
1869 PFILE_OBJECT FileObject
;
1870 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1871 BOOLEAN IsImageSection
;
1873 BOOLEAN DirectMapped
;
1874 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1877 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1880 * Get the segment and section.
1882 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1883 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1884 Context
.SectionEntry
= Entry
;
1885 Context
.CallingProcess
= Process
;
1887 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
1888 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1890 DirectMapped
= FALSE
;
1892 MmLockSectionSegment(Context
.Segment
);
1895 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1896 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1897 FileObject
= Context
.Section
->FileObject
;
1899 if (FileObject
!= NULL
&&
1900 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1902 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1905 * If the file system is letting us go directly to the cache and the
1906 * memory area was mapped at an offset in the file which is page aligned
1907 * then note this is a direct mapped page.
1909 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1910 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1912 DirectMapped
= TRUE
;
1919 * This should never happen since mappings of physical memory are never
1920 * placed in the rmap lists.
1922 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1924 DPRINT1("Trying to page out from physical memory section address 0x%p "
1925 "process %p\n", Address
,
1926 Process
? Process
->UniqueProcessId
: 0);
1927 KeBugCheck(MEMORY_MANAGEMENT
);
1931 * Get the section segment entry and the physical address.
1933 if (!MmIsPagePresent(Process
, Address
))
1935 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1936 Process
? Process
->UniqueProcessId
: 0, Address
);
1937 KeBugCheck(MEMORY_MANAGEMENT
);
1939 Page
= MmGetPfnForProcess(Process
, Address
);
1940 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1943 * Check the reference count to ensure this page can be paged out
1945 if (MmGetReferenceCountPage(Page
) != 1)
1947 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1948 Page
, MmGetReferenceCountPage(Page
));
1949 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1950 MmUnlockSectionSegment(Context
.Segment
);
1951 return STATUS_UNSUCCESSFUL
;
1955 * Prepare the context structure for the rmap delete call.
1957 MmUnlockSectionSegment(Context
.Segment
);
1958 Context
.WasDirty
= FALSE
;
1959 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1960 IS_SWAP_FROM_SSE(Entry
) ||
1961 PFN_FROM_SSE(Entry
) != Page
)
1963 Context
.Private
= TRUE
;
1967 Context
.Private
= FALSE
;
1971 * Take an additional reference to the page or the VACB.
1973 if (DirectMapped
&& !Context
.Private
)
1975 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
1977 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1978 KeBugCheck(MEMORY_MANAGEMENT
);
1983 OldIrql
= MiAcquirePfnLock();
1984 MmReferencePage(Page
);
1985 MiReleasePfnLock(OldIrql
);
1988 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1990 /* Since we passed in a surrogate, we'll get back the page entry
1991 * state in our context. This is intended to make intermediate
1992 * decrements of share count not release the wait entry.
1994 Entry
= Context
.SectionEntry
;
1997 * If this wasn't a private page then we should have reduced the entry to
1998 * zero by deleting all the rmaps.
2000 if (!Context
.Private
&& Entry
!= 0)
2002 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2003 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2005 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2010 * If the page wasn't dirty then we can just free it as for a readonly page.
2011 * Since we unmapped all the mappings above we know it will not suddenly
2013 * If the page is from a pagefile section and has no swap entry,
2014 * we can't free the page at this point.
2016 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2017 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2019 if (Context
.Private
)
2021 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2022 Context
.WasDirty
? "dirty" : "clean", Address
);
2023 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2025 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2027 MmSetSavedSwapEntryPage(Page
, 0);
2028 MmLockSectionSegment(Context
.Segment
);
2029 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2030 MmUnlockSectionSegment(Context
.Segment
);
2031 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2032 MiSetPageEvent(NULL
, NULL
);
2033 return(STATUS_SUCCESS
);
2036 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2038 if (Context
.Private
)
2040 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2041 Context
.WasDirty
? "dirty" : "clean", Address
);
2042 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2044 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2046 MmSetSavedSwapEntryPage(Page
, 0);
2049 MmLockSectionSegment(Context
.Segment
);
2050 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2051 MmUnlockSectionSegment(Context
.Segment
);
2053 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2054 MiSetPageEvent(NULL
, NULL
);
2055 return(STATUS_SUCCESS
);
2058 else if (!Context
.Private
&& DirectMapped
)
2062 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2064 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2067 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
, FALSE
);
2069 Status
= STATUS_SUCCESS
;
2072 if (!NT_SUCCESS(Status
))
2074 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2075 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2078 MiSetPageEvent(NULL
, NULL
);
2079 return(STATUS_SUCCESS
);
2081 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2085 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2087 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2089 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2090 MiSetPageEvent(NULL
, NULL
);
2091 return(STATUS_SUCCESS
);
2093 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2095 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2096 MmSetSavedSwapEntryPage(Page
, 0);
2097 MmLockAddressSpace(AddressSpace
);
2098 Status
= MmCreatePageFileMapping(Process
,
2101 MmUnlockAddressSpace(AddressSpace
);
2102 if (!NT_SUCCESS(Status
))
2104 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2105 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2107 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2108 MiSetPageEvent(NULL
, NULL
);
2109 return(STATUS_SUCCESS
);
2113 * If necessary, allocate an entry in the paging file for this page
2117 SwapEntry
= MmAllocSwapPage();
2120 MmShowOutOfSpaceMessagePagingFile();
2121 MmLockAddressSpace(AddressSpace
);
2123 * For private pages restore the old mappings.
2125 if (Context
.Private
)
2127 Status
= MmCreateVirtualMapping(Process
,
2129 MemoryArea
->Protect
,
2132 MmSetDirtyPage(Process
, Address
);
2141 MmLockSectionSegment(Context
.Segment
);
2144 * For non-private pages if the page wasn't direct mapped then
2145 * set it back into the section segment entry so we don't loose
2146 * our copy. Otherwise it will be handled by the cache manager.
2148 Status
= MmCreateVirtualMapping(Process
,
2150 MemoryArea
->Protect
,
2153 MmSetDirtyPage(Process
, Address
);
2157 // If we got here, the previous entry should have been a wait
2158 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2159 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2160 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2161 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2162 MmUnlockSectionSegment(Context
.Segment
);
2164 MmUnlockAddressSpace(AddressSpace
);
2165 MiSetPageEvent(NULL
, NULL
);
2166 return(STATUS_PAGEFILE_QUOTA
);
2171 * Write the page to the pagefile
2173 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2174 if (!NT_SUCCESS(Status
))
2176 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2179 * As above: undo our actions.
2180 * FIXME: Also free the swap page.
2182 MmLockAddressSpace(AddressSpace
);
2183 if (Context
.Private
)
2185 Status
= MmCreateVirtualMapping(Process
,
2187 MemoryArea
->Protect
,
2190 MmSetDirtyPage(Process
, Address
);
2197 MmLockSectionSegment(Context
.Segment
);
2198 Status
= MmCreateVirtualMapping(Process
,
2200 MemoryArea
->Protect
,
2203 MmSetDirtyPage(Process
, Address
);
2207 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2208 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2209 MmUnlockSectionSegment(Context
.Segment
);
2211 MmUnlockAddressSpace(AddressSpace
);
2212 MiSetPageEvent(NULL
, NULL
);
2213 return(STATUS_UNSUCCESSFUL
);
2217 * Otherwise we have succeeded.
2219 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2220 MmSetSavedSwapEntryPage(Page
, 0);
2221 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2222 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2224 MmLockSectionSegment(Context
.Segment
);
2225 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2226 MmUnlockSectionSegment(Context
.Segment
);
2230 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2233 if (Context
.Private
)
2235 MmLockAddressSpace(AddressSpace
);
2236 MmLockSectionSegment(Context
.Segment
);
2237 Status
= MmCreatePageFileMapping(Process
,
2240 /* We had placed a wait entry upon entry ... replace it before leaving */
2241 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2242 MmUnlockSectionSegment(Context
.Segment
);
2243 MmUnlockAddressSpace(AddressSpace
);
2244 if (!NT_SUCCESS(Status
))
2246 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2247 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2252 MmLockAddressSpace(AddressSpace
);
2253 MmLockSectionSegment(Context
.Segment
);
2254 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2255 /* We had placed a wait entry upon entry ... replace it before leaving */
2256 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2257 MmUnlockSectionSegment(Context
.Segment
);
2258 MmUnlockAddressSpace(AddressSpace
);
2261 MiSetPageEvent(NULL
, NULL
);
2262 return(STATUS_SUCCESS
);
2267 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2268 PMEMORY_AREA MemoryArea
,
2272 LARGE_INTEGER Offset
;
2273 PROS_SECTION_OBJECT Section
;
2274 PMM_SECTION_SEGMENT Segment
;
2276 SWAPENTRY SwapEntry
;
2280 PFILE_OBJECT FileObject
;
2282 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2284 BOOLEAN DirectMapped
;
2285 BOOLEAN IsImageSection
;
2286 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2288 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2290 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2291 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2294 * Get the segment and section.
2296 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2297 Section
= MemoryArea
->Data
.SectionData
.Section
;
2298 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2300 FileObject
= Section
->FileObject
;
2301 DirectMapped
= FALSE
;
2302 if (FileObject
!= NULL
&&
2303 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2306 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2310 * If the file system is letting us go directly to the cache and the
2311 * memory area was mapped at an offset in the file which is page aligned
2312 * then note this is a direct mapped page.
2314 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2315 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2317 DirectMapped
= TRUE
;
2322 * This should never happen since mappings of physical memory are never
2323 * placed in the rmap lists.
2325 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2327 DPRINT1("Trying to write back page from physical memory mapped at %p "
2328 "process %p\n", Address
,
2329 Process
? Process
->UniqueProcessId
: 0);
2330 KeBugCheck(MEMORY_MANAGEMENT
);
2334 * Get the section segment entry and the physical address.
2336 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2337 if (!MmIsPagePresent(Process
, Address
))
2339 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2340 Process
? Process
->UniqueProcessId
: 0, Address
);
2341 KeBugCheck(MEMORY_MANAGEMENT
);
2343 Page
= MmGetPfnForProcess(Process
, Address
);
2344 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2347 * Check for a private (COWed) page.
2349 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2350 IS_SWAP_FROM_SSE(Entry
) ||
2351 PFN_FROM_SSE(Entry
) != Page
)
2361 * Speculatively set all mappings of the page to clean.
2363 MmSetCleanAllRmaps(Page
);
2366 * If this page was direct mapped from the cache then the cache manager
2367 * will take care of writing it back to disk.
2369 if (DirectMapped
&& !Private
)
2371 //LARGE_INTEGER SOffset;
2372 ASSERT(SwapEntry
== 0);
2373 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2375 CcRosMarkDirtyFile(SharedCacheMap
, Offset
.QuadPart
);
2377 MmLockSectionSegment(Segment
);
2378 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2379 MmUnlockSectionSegment(Segment
);
2380 MiSetPageEvent(NULL
, NULL
);
2381 return(STATUS_SUCCESS
);
2385 * If necessary, allocate an entry in the paging file for this page
2389 SwapEntry
= MmAllocSwapPage();
2392 MmSetDirtyAllRmaps(Page
);
2393 MiSetPageEvent(NULL
, NULL
);
2394 return(STATUS_PAGEFILE_QUOTA
);
2396 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2400 * Write the page to the pagefile
2402 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2403 if (!NT_SUCCESS(Status
))
2405 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2407 MmSetDirtyAllRmaps(Page
);
2408 MiSetPageEvent(NULL
, NULL
);
2409 return(STATUS_UNSUCCESSFUL
);
2413 * Otherwise we have succeeded.
2415 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2416 MiSetPageEvent(NULL
, NULL
);
2417 return(STATUS_SUCCESS
);
2421 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2429 PMEMORY_AREA MemoryArea
;
2430 PMM_SECTION_SEGMENT Segment
;
2431 BOOLEAN DoCOW
= FALSE
;
2433 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2435 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2436 ASSERT(MemoryArea
!= NULL
);
2437 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2438 MmLockSectionSegment(Segment
);
2440 if ((Segment
->WriteCopy
) &&
2441 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2446 if (OldProtect
!= NewProtect
)
2448 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2450 SWAPENTRY SwapEntry
;
2451 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2452 ULONG Protect
= NewProtect
;
2454 /* Wait for a wait entry to disappear */
2457 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2458 if (SwapEntry
!= MM_WAIT_ENTRY
)
2460 MiWaitForPageEvent(Process
, Address
);
2465 * If we doing COW for this segment then check if the page is
2468 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2470 LARGE_INTEGER Offset
;
2474 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2475 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2476 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2478 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2479 * IS_SWAP_FROM_SSE and we'll do the right thing.
2481 Page
= MmGetPfnForProcess(Process
, Address
);
2483 Protect
= PAGE_READONLY
;
2484 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2485 IS_SWAP_FROM_SSE(Entry
) ||
2486 PFN_FROM_SSE(Entry
) != Page
)
2488 Protect
= NewProtect
;
2492 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2494 MmSetPageProtect(Process
, Address
,
2500 MmUnlockSectionSegment(Segment
);
2505 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2506 PMEMORY_AREA MemoryArea
,
2514 ULONG_PTR MaxLength
;
2516 MaxLength
= MA_GetEndingAddress(MemoryArea
) - (ULONG_PTR
)BaseAddress
;
2517 if (Length
> MaxLength
)
2518 Length
= (ULONG
)MaxLength
;
2520 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2521 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2523 ASSERT(Region
!= NULL
);
2525 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2526 Region
->Protect
!= Protect
)
2528 return STATUS_INVALID_PAGE_PROTECTION
;
2531 *OldProtect
= Region
->Protect
;
2532 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
2533 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2534 BaseAddress
, Length
, Region
->Type
, Protect
,
2535 MmAlterViewAttributes
);
2541 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2543 PMEMORY_BASIC_INFORMATION Info
,
2544 PSIZE_T ResultLength
)
2547 PVOID RegionBaseAddress
;
2548 PROS_SECTION_OBJECT Section
;
2549 PMM_SECTION_SEGMENT Segment
;
2551 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2552 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2553 Address
, &RegionBaseAddress
);
2556 return STATUS_UNSUCCESSFUL
;
2559 Section
= MemoryArea
->Data
.SectionData
.Section
;
2560 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2562 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2563 Info
->AllocationBase
= (PUCHAR
)MA_GetStartingAddress(MemoryArea
) - Segment
->Image
.VirtualAddress
;
2564 Info
->Type
= MEM_IMAGE
;
2568 Info
->AllocationBase
= (PVOID
)MA_GetStartingAddress(MemoryArea
);
2569 Info
->Type
= MEM_MAPPED
;
2571 Info
->BaseAddress
= RegionBaseAddress
;
2572 Info
->AllocationProtect
= MemoryArea
->Protect
;
2573 Info
->RegionSize
= Region
->Length
;
2574 Info
->State
= MEM_COMMIT
;
2575 Info
->Protect
= Region
->Protect
;
2577 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2578 return(STATUS_SUCCESS
);
2583 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2586 LARGE_INTEGER Offset
;
2588 SWAPENTRY SavedSwapEntry
;
2593 MmLockSectionSegment(Segment
);
2595 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2596 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2598 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2601 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2602 if (IS_SWAP_FROM_SSE(Entry
))
2604 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2608 Page
= PFN_FROM_SSE(Entry
);
2609 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2610 if (SavedSwapEntry
!= 0)
2612 MmSetSavedSwapEntryPage(Page
, 0);
2613 MmFreeSwapPage(SavedSwapEntry
);
2615 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2620 MmUnlockSectionSegment(Segment
);
2624 MmpDeleteSection(PVOID ObjectBody
)
2626 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2628 /* Check if it's an ARM3, or ReactOS section */
2629 if (!MiIsRosSectionObject(Section
))
2631 MiDeleteARM3Section(ObjectBody
);
2635 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2636 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2641 PMM_SECTION_SEGMENT SectionSegments
;
2644 * NOTE: Section->ImageSection can be NULL for short time
2645 * during the section creating. If we fail for some reason
2646 * until the image section is properly initialized we shouldn't
2647 * process further here.
2649 if (Section
->ImageSection
== NULL
)
2652 SectionSegments
= Section
->ImageSection
->Segments
;
2653 NrSegments
= Section
->ImageSection
->NrSegments
;
2655 for (i
= 0; i
< NrSegments
; i
++)
2657 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2659 MmLockSectionSegment(&SectionSegments
[i
]);
2661 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2662 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2664 MmUnlockSectionSegment(&SectionSegments
[i
]);
2667 MmpFreePageFileSegment(&SectionSegments
[i
]);
2673 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2676 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2679 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2681 DPRINT("Freeing section segment\n");
2682 Section
->Segment
= NULL
;
2683 MmFinalizeSegment(Segment
);
2687 DPRINT("RefCount %d\n", RefCount
);
2694 * NOTE: Section->Segment can be NULL for short time
2695 * during the section creating.
2697 if (Section
->Segment
== NULL
)
2700 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2702 MmpFreePageFileSegment(Section
->Segment
);
2703 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2704 ExFreePool(Section
->Segment
);
2705 Section
->Segment
= NULL
;
2709 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2712 if (Section
->FileObject
!= NULL
)
2715 CcRosDereferenceCache(Section
->FileObject
);
2717 ObDereferenceObject(Section
->FileObject
);
2718 Section
->FileObject
= NULL
;
2723 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2725 IN ACCESS_MASK GrantedAccess
,
2726 IN ULONG ProcessHandleCount
,
2727 IN ULONG SystemHandleCount
)
2729 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2735 MmCreatePhysicalMemorySection(VOID
)
2737 PROS_SECTION_OBJECT PhysSection
;
2739 OBJECT_ATTRIBUTES Obj
;
2740 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2741 LARGE_INTEGER SectionSize
;
2745 * Create the section mapping physical memory
2747 SectionSize
.QuadPart
= 0xFFFFFFFF;
2748 InitializeObjectAttributes(&Obj
,
2750 OBJ_PERMANENT
| OBJ_KERNEL_EXCLUSIVE
,
2753 Status
= MmCreateSection((PVOID
)&PhysSection
,
2757 PAGE_EXECUTE_READWRITE
,
2761 if (!NT_SUCCESS(Status
))
2763 DPRINT1("Failed to create PhysicalMemory section\n");
2764 KeBugCheck(MEMORY_MANAGEMENT
);
2766 Status
= ObInsertObject(PhysSection
,
2772 if (!NT_SUCCESS(Status
))
2774 ObDereferenceObject(PhysSection
);
2776 ObCloseHandle(Handle
, KernelMode
);
2777 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2778 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2780 return(STATUS_SUCCESS
);
2786 MmInitSectionImplementation(VOID
)
2788 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2789 UNICODE_STRING Name
;
2791 DPRINT("Creating Section Object Type\n");
2793 /* Initialize the section based root */
2794 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2795 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2797 /* Initialize the Section object type */
2798 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2799 RtlInitUnicodeString(&Name
, L
"Section");
2800 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2801 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2802 ObjectTypeInitializer
.PoolType
= PagedPool
;
2803 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2804 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2805 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2806 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2807 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2808 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2809 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2811 MmCreatePhysicalMemorySection();
2813 return(STATUS_SUCCESS
);
2818 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2819 ACCESS_MASK DesiredAccess
,
2820 POBJECT_ATTRIBUTES ObjectAttributes
,
2821 PLARGE_INTEGER UMaximumSize
,
2822 ULONG SectionPageProtection
,
2823 ULONG AllocationAttributes
)
2825 * Create a section which is backed by the pagefile
2828 LARGE_INTEGER MaximumSize
;
2829 PROS_SECTION_OBJECT Section
;
2830 PMM_SECTION_SEGMENT Segment
;
2833 if (UMaximumSize
== NULL
)
2835 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2836 return(STATUS_INVALID_PARAMETER
);
2838 MaximumSize
= *UMaximumSize
;
2841 * Create the section
2843 Status
= ObCreateObject(ExGetPreviousMode(),
2844 MmSectionObjectType
,
2846 ExGetPreviousMode(),
2848 sizeof(ROS_SECTION_OBJECT
),
2851 (PVOID
*)(PVOID
)&Section
);
2852 if (!NT_SUCCESS(Status
))
2854 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2861 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2862 Section
->Type
= 'SC';
2863 Section
->Size
= 'TN';
2864 Section
->SectionPageProtection
= SectionPageProtection
;
2865 Section
->AllocationAttributes
= AllocationAttributes
;
2866 Section
->MaximumSize
= MaximumSize
;
2867 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2868 TAG_MM_SECTION_SEGMENT
);
2869 if (Segment
== NULL
)
2871 ObDereferenceObject(Section
);
2872 return(STATUS_NO_MEMORY
);
2874 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2875 Section
->Segment
= Segment
;
2876 Segment
->ReferenceCount
= 1;
2877 ExInitializeFastMutex(&Segment
->Lock
);
2878 Segment
->Image
.FileOffset
= 0;
2879 Segment
->Protection
= SectionPageProtection
;
2880 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2881 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2882 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2883 Segment
->WriteCopy
= FALSE
;
2884 Segment
->Image
.VirtualAddress
= 0;
2885 Segment
->Image
.Characteristics
= 0;
2886 *SectionObject
= Section
;
2887 MiInitializeSectionPageTable(Segment
);
2888 return(STATUS_SUCCESS
);
2893 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2894 ACCESS_MASK DesiredAccess
,
2895 POBJECT_ATTRIBUTES ObjectAttributes
,
2896 PLARGE_INTEGER UMaximumSize
,
2897 ULONG SectionPageProtection
,
2898 ULONG AllocationAttributes
,
2899 PFILE_OBJECT FileObject
)
2901 * Create a section backed by a data file
2904 PROS_SECTION_OBJECT Section
;
2906 LARGE_INTEGER MaximumSize
;
2907 PMM_SECTION_SEGMENT Segment
;
2908 FILE_STANDARD_INFORMATION FileInfo
;
2912 * Create the section
2914 Status
= ObCreateObject(ExGetPreviousMode(),
2915 MmSectionObjectType
,
2917 ExGetPreviousMode(),
2919 sizeof(ROS_SECTION_OBJECT
),
2923 if (!NT_SUCCESS(Status
))
2925 ObDereferenceObject(FileObject
);
2931 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2932 Section
->Type
= 'SC';
2933 Section
->Size
= 'TN';
2934 Section
->SectionPageProtection
= SectionPageProtection
;
2935 Section
->AllocationAttributes
= AllocationAttributes
;
2938 * FIXME: This is propably not entirely correct. We can't look into
2939 * the standard FCB header because it might not be initialized yet
2940 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2941 * standard file information is filled on first request).
2943 Status
= IoQueryFileInformation(FileObject
,
2944 FileStandardInformation
,
2945 sizeof(FILE_STANDARD_INFORMATION
),
2948 if (!NT_SUCCESS(Status
))
2950 ObDereferenceObject(Section
);
2951 ObDereferenceObject(FileObject
);
2956 * FIXME: Revise this once a locking order for file size changes is
2959 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2961 MaximumSize
= *UMaximumSize
;
2965 MaximumSize
= FileInfo
.EndOfFile
;
2966 /* Mapping zero-sized files isn't allowed. */
2967 if (MaximumSize
.QuadPart
== 0)
2969 ObDereferenceObject(Section
);
2970 ObDereferenceObject(FileObject
);
2971 return STATUS_MAPPED_FILE_SIZE_ZERO
;
2975 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2977 Status
= IoSetInformation(FileObject
,
2978 FileEndOfFileInformation
,
2979 sizeof(LARGE_INTEGER
),
2981 if (!NT_SUCCESS(Status
))
2983 ObDereferenceObject(Section
);
2984 ObDereferenceObject(FileObject
);
2985 return(STATUS_SECTION_NOT_EXTENDED
);
2989 if (FileObject
->SectionObjectPointer
== NULL
||
2990 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2992 ObDereferenceObject(Section
);
2993 ObDereferenceObject(FileObject
);
2994 return STATUS_INVALID_FILE_FOR_SECTION
;
3000 Status
= MmspWaitForFileLock(FileObject
);
3001 if (Status
!= STATUS_SUCCESS
)
3003 ObDereferenceObject(Section
);
3004 ObDereferenceObject(FileObject
);
3009 * If this file hasn't been mapped as a data file before then allocate a
3010 * section segment to describe the data file mapping
3012 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3014 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3015 TAG_MM_SECTION_SEGMENT
);
3016 if (Segment
== NULL
)
3018 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3019 ObDereferenceObject(Section
);
3020 ObDereferenceObject(FileObject
);
3021 return(STATUS_NO_MEMORY
);
3023 Section
->Segment
= Segment
;
3024 Segment
->ReferenceCount
= 1;
3025 ExInitializeFastMutex(&Segment
->Lock
);
3027 * Set the lock before assigning the segment to the file object
3029 ExAcquireFastMutex(&Segment
->Lock
);
3030 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3032 Segment
->Image
.FileOffset
= 0;
3033 Segment
->Protection
= SectionPageProtection
;
3034 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3035 Segment
->Image
.Characteristics
= 0;
3036 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3037 if (AllocationAttributes
& SEC_RESERVE
)
3039 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3043 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3044 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3046 Segment
->Image
.VirtualAddress
= 0;
3047 Segment
->Locked
= TRUE
;
3048 MiInitializeSectionPageTable(Segment
);
3053 * If the file is already mapped as a data file then we may need
3057 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3059 Section
->Segment
= Segment
;
3060 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3061 MmLockSectionSegment(Segment
);
3063 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3064 !(AllocationAttributes
& SEC_RESERVE
))
3066 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3067 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3070 MmUnlockSectionSegment(Segment
);
3071 Section
->FileObject
= FileObject
;
3072 Section
->MaximumSize
= MaximumSize
;
3074 CcRosReferenceCache(FileObject
);
3076 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3077 *SectionObject
= Section
;
3078 return(STATUS_SUCCESS
);
3082 TODO: not that great (declaring loaders statically, having to declare all of
3083 them, having to keep them extern, etc.), will fix in the future
3085 extern NTSTATUS NTAPI PeFmtCreateSection
3087 IN CONST VOID
* FileHeader
,
3088 IN SIZE_T FileHeaderSize
,
3090 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3092 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3093 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3096 extern NTSTATUS NTAPI ElfFmtCreateSection
3098 IN CONST VOID
* FileHeader
,
3099 IN SIZE_T FileHeaderSize
,
3101 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3103 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3104 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3107 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3118 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3120 SIZE_T SizeOfSegments
;
3121 PMM_SECTION_SEGMENT Segments
;
3123 /* TODO: check for integer overflow */
3124 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3126 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3128 TAG_MM_SECTION_SEGMENT
);
3131 RtlZeroMemory(Segments
, SizeOfSegments
);
3139 ExeFmtpReadFile(IN PVOID File
,
3140 IN PLARGE_INTEGER Offset
,
3143 OUT PVOID
* AllocBase
,
3144 OUT PULONG ReadSize
)
3147 LARGE_INTEGER FileOffset
;
3149 ULONG OffsetAdjustment
;
3153 PFILE_OBJECT FileObject
= File
;
3154 IO_STATUS_BLOCK Iosb
;
3156 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3160 KeBugCheck(MEMORY_MANAGEMENT
);
3163 FileOffset
= *Offset
;
3165 /* Negative/special offset: it cannot be used in this context */
3166 if(FileOffset
.u
.HighPart
< 0)
3168 KeBugCheck(MEMORY_MANAGEMENT
);
3171 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3172 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3173 FileOffset
.u
.LowPart
= AdjustOffset
;
3175 BufferSize
= Length
+ OffsetAdjustment
;
3176 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3178 /* Flush data since we're about to perform a non-cached read */
3179 CcFlushCache(FileObject
->SectionObjectPointer
,
3185 * It's ok to use paged pool, because this is a temporary buffer only used in
3186 * the loading of executables. The assumption is that MmCreateSection is
3187 * always called at low IRQLs and that these buffers don't survive a brief
3188 * initialization phase
3190 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3195 return STATUS_INSUFFICIENT_RESOURCES
;
3200 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3202 UsedSize
= (ULONG
)Iosb
.Information
;
3204 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3206 Status
= STATUS_IN_PAGE_ERROR
;
3207 ASSERT(!NT_SUCCESS(Status
));
3210 if(NT_SUCCESS(Status
))
3212 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3213 *AllocBase
= Buffer
;
3214 *ReadSize
= UsedSize
- OffsetAdjustment
;
3218 ExFreePoolWithTag(Buffer
, 'rXmM');
3225 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3226 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3227 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3232 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3236 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3238 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3239 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3246 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3250 MmspAssertSegmentsSorted(ImageSectionObject
);
3252 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3254 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3258 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3259 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3260 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3268 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3272 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3274 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3275 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3283 MmspCompareSegments(const void * x
,
3286 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3287 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3290 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3291 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3295 * Ensures an image section's segments are sorted in memory
3300 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3303 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3305 MmspAssertSegmentsSorted(ImageSectionObject
);
3309 qsort(ImageSectionObject
->Segments
,
3310 ImageSectionObject
->NrSegments
,
3311 sizeof(ImageSectionObject
->Segments
[0]),
3312 MmspCompareSegments
);
3318 * Ensures an image section's segments don't overlap in memory and don't have
3319 * gaps and don't have a null size. We let them map to overlapping file regions,
3320 * though - that's not necessarily an error
3325 MmspCheckSegmentBounds
3327 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3333 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3335 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3339 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3341 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3343 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3351 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3352 * page could be OK (Windows seems to be OK with them), and larger gaps
3353 * could lead to image sections spanning several discontiguous regions
3354 * (NtMapViewOfSection could then refuse to map them, and they could
3355 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3357 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3358 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3359 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3370 * Merges and pads an image section's segments until they all are page-aligned
3371 * and have a size that is a multiple of the page size
3376 MmspPageAlignSegments
3378 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3384 PMM_SECTION_SEGMENT EffectiveSegment
;
3386 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3388 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3393 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3395 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3398 * The first segment requires special handling
3402 ULONG_PTR VirtualAddress
;
3403 ULONG_PTR VirtualOffset
;
3405 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3407 /* Round down the virtual address to the nearest page */
3408 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3410 /* Round up the virtual size to the nearest page */
3411 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3412 EffectiveSegment
->Image
.VirtualAddress
;
3414 /* Adjust the raw address and size */
3415 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3417 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3423 * Garbage in, garbage out: unaligned base addresses make the file
3424 * offset point in curious and odd places, but that's what we were
3427 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3428 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3432 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3433 ULONG_PTR EndOfEffectiveSegment
;
3435 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3436 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3439 * The current segment begins exactly where the current effective
3440 * segment ended, therefore beginning a new effective segment
3442 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3445 ASSERT(LastSegment
<= i
);
3446 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3448 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3450 if (LastSegment
!= i
)
3453 * Copy the current segment. If necessary, the effective segment
3454 * will be expanded later
3456 *EffectiveSegment
= *Segment
;
3460 * Page-align the virtual size. We know for sure the virtual address
3463 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3464 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3467 * The current segment is still part of the current effective segment:
3468 * extend the effective segment to reflect this
3470 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3472 static const ULONG FlagsToProtection
[16] =
3480 PAGE_EXECUTE_READWRITE
,
3481 PAGE_EXECUTE_READWRITE
,
3486 PAGE_EXECUTE_WRITECOPY
,
3487 PAGE_EXECUTE_WRITECOPY
,
3488 PAGE_EXECUTE_WRITECOPY
,
3489 PAGE_EXECUTE_WRITECOPY
3492 unsigned ProtectionFlags
;
3495 * Extend the file size
3498 /* Unaligned segments must be contiguous within the file */
3499 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3500 EffectiveSegment
->RawLength
.QuadPart
))
3505 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3508 * Extend the virtual size
3510 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3512 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3513 EffectiveSegment
->Image
.VirtualAddress
;
3516 * Merge the protection
3518 EffectiveSegment
->Protection
|= Segment
->Protection
;
3520 /* Clean up redundance */
3521 ProtectionFlags
= 0;
3523 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3524 ProtectionFlags
|= 1 << 0;
3526 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3527 ProtectionFlags
|= 1 << 1;
3529 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3530 ProtectionFlags
|= 1 << 2;
3532 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3533 ProtectionFlags
|= 1 << 3;
3535 ASSERT(ProtectionFlags
< 16);
3536 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3538 /* If a segment was required to be shared and cannot, fail */
3539 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3540 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3546 * We assume no holes between segments at this point
3550 KeBugCheck(MEMORY_MANAGEMENT
);
3554 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3560 ExeFmtpCreateImageSection(PFILE_OBJECT FileObject
,
3561 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3563 LARGE_INTEGER Offset
;
3565 PVOID FileHeaderBuffer
;
3566 ULONG FileHeaderSize
;
3568 ULONG OldNrSegments
;
3573 * Read the beginning of the file (2 pages). Should be enough to contain
3574 * all (or most) of the headers
3576 Offset
.QuadPart
= 0;
3578 Status
= ExeFmtpReadFile (FileObject
,
3585 if (!NT_SUCCESS(Status
))
3588 if (FileHeaderSize
== 0)
3590 ExFreePool(FileHeaderBuffer
);
3591 return STATUS_UNSUCCESSFUL
;
3595 * Look for a loader that can handle this executable
3597 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3599 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3602 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3608 ExeFmtpAllocateSegments
);
3610 if (!NT_SUCCESS(Status
))
3612 if (ImageSectionObject
->Segments
)
3614 ExFreePool(ImageSectionObject
->Segments
);
3615 ImageSectionObject
->Segments
= NULL
;
3619 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3623 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3626 * No loader handled the format
3628 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3630 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3631 ASSERT(!NT_SUCCESS(Status
));
3634 if (!NT_SUCCESS(Status
))
3637 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3642 /* FIXME? are these values platform-dependent? */
3643 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3644 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3646 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3647 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3649 if(ImageSectionObject
->BasedAddress
== NULL
)
3651 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3652 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3654 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3658 * And now the fun part: fixing the segments
3661 /* Sort them by virtual address */
3662 MmspSortSegments(ImageSectionObject
, Flags
);
3664 /* Ensure they don't overlap in memory */
3665 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3666 return STATUS_INVALID_IMAGE_FORMAT
;
3668 /* Ensure they are aligned */
3669 OldNrSegments
= ImageSectionObject
->NrSegments
;
3671 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3672 return STATUS_INVALID_IMAGE_FORMAT
;
3674 /* Trim them if the alignment phase merged some of them */
3675 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3677 PMM_SECTION_SEGMENT Segments
;
3678 SIZE_T SizeOfSegments
;
3680 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3682 Segments
= ExAllocatePoolWithTag(PagedPool
,
3684 TAG_MM_SECTION_SEGMENT
);
3686 if (Segments
== NULL
)
3687 return STATUS_INSUFFICIENT_RESOURCES
;
3689 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3690 ExFreePool(ImageSectionObject
->Segments
);
3691 ImageSectionObject
->Segments
= Segments
;
3694 /* And finish their initialization */
3695 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3697 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3698 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3699 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3702 ASSERT(NT_SUCCESS(Status
));
3707 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3708 ACCESS_MASK DesiredAccess
,
3709 POBJECT_ATTRIBUTES ObjectAttributes
,
3710 PLARGE_INTEGER UMaximumSize
,
3711 ULONG SectionPageProtection
,
3712 ULONG AllocationAttributes
,
3713 PFILE_OBJECT FileObject
)
3715 PROS_SECTION_OBJECT Section
;
3717 PMM_SECTION_SEGMENT SectionSegments
;
3718 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3721 if (FileObject
== NULL
)
3722 return STATUS_INVALID_FILE_FOR_SECTION
;
3725 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3727 DPRINT1("Denying section creation due to missing cache initialization\n");
3728 return STATUS_INVALID_FILE_FOR_SECTION
;
3733 * Create the section
3735 Status
= ObCreateObject (ExGetPreviousMode(),
3736 MmSectionObjectType
,
3738 ExGetPreviousMode(),
3740 sizeof(ROS_SECTION_OBJECT
),
3743 (PVOID
*)(PVOID
)&Section
);
3744 if (!NT_SUCCESS(Status
))
3746 ObDereferenceObject(FileObject
);
3753 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3754 Section
->Type
= 'SC';
3755 Section
->Size
= 'TN';
3756 Section
->SectionPageProtection
= SectionPageProtection
;
3757 Section
->AllocationAttributes
= AllocationAttributes
;
3759 if (FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3761 NTSTATUS StatusExeFmt
;
3763 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3764 if (ImageSectionObject
== NULL
)
3766 ObDereferenceObject(FileObject
);
3767 ObDereferenceObject(Section
);
3768 return(STATUS_NO_MEMORY
);
3771 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3773 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3775 if (!NT_SUCCESS(StatusExeFmt
))
3777 if(ImageSectionObject
->Segments
!= NULL
)
3778 ExFreePool(ImageSectionObject
->Segments
);
3781 * If image file is empty, then return that the file is invalid for section
3783 Status
= StatusExeFmt
;
3784 if (StatusExeFmt
== STATUS_END_OF_FILE
)
3786 Status
= STATUS_INVALID_FILE_FOR_SECTION
;
3789 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3790 ObDereferenceObject(Section
);
3791 ObDereferenceObject(FileObject
);
3795 Section
->ImageSection
= ImageSectionObject
;
3796 ASSERT(ImageSectionObject
->Segments
);
3801 Status
= MmspWaitForFileLock(FileObject
);
3802 if (!NT_SUCCESS(Status
))
3804 ExFreePool(ImageSectionObject
->Segments
);
3805 ExFreePool(ImageSectionObject
);
3806 ObDereferenceObject(Section
);
3807 ObDereferenceObject(FileObject
);
3811 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3812 ImageSectionObject
, NULL
))
3815 * An other thread has initialized the same image in the background
3817 ExFreePool(ImageSectionObject
->Segments
);
3818 ExFreePool(ImageSectionObject
);
3819 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3820 Section
->ImageSection
= ImageSectionObject
;
3821 SectionSegments
= ImageSectionObject
->Segments
;
3823 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3825 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3829 Status
= StatusExeFmt
;
3836 Status
= MmspWaitForFileLock(FileObject
);
3837 if (Status
!= STATUS_SUCCESS
)
3839 ObDereferenceObject(Section
);
3840 ObDereferenceObject(FileObject
);
3844 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3845 Section
->ImageSection
= ImageSectionObject
;
3846 SectionSegments
= ImageSectionObject
->Segments
;
3849 * Otherwise just reference all the section segments
3851 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3853 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3856 Status
= STATUS_SUCCESS
;
3858 Section
->FileObject
= FileObject
;
3860 CcRosReferenceCache(FileObject
);
3862 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3863 *SectionObject
= Section
;
3870 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3871 PROS_SECTION_OBJECT Section
,
3872 PMM_SECTION_SEGMENT Segment
,
3877 ULONG AllocationType
)
3883 if (Segment
->WriteCopy
)
3885 /* We have to do this because the not present fault
3886 * and access fault handlers depend on the protection
3887 * that should be granted AFTER the COW fault takes
3888 * place to be in Region->Protect. The not present fault
3889 * handler changes this to the correct protection for COW when
3890 * mapping the pages into the process's address space. If a COW
3891 * fault takes place, the access fault handler sets the page protection
3892 * to these values for the newly copied pages
3894 if (Protect
== PAGE_WRITECOPY
)
3895 Protect
= PAGE_READWRITE
;
3896 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3897 Protect
= PAGE_EXECUTE_READWRITE
;
3900 if (*BaseAddress
== NULL
)
3901 Granularity
= MM_ALLOCATION_GRANULARITY
;
3903 Granularity
= PAGE_SIZE
;
3906 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3908 LARGE_INTEGER FileOffset
;
3909 FileOffset
.QuadPart
= ViewOffset
;
3910 ObReferenceObject(Section
);
3911 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3914 Status
= MmCreateMemoryArea(AddressSpace
,
3915 MEMORY_AREA_SECTION_VIEW
,
3922 if (!NT_SUCCESS(Status
))
3924 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3925 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3929 ObReferenceObject((PVOID
)Section
);
3931 MArea
->Data
.SectionData
.Segment
= Segment
;
3932 MArea
->Data
.SectionData
.Section
= Section
;
3933 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3934 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3936 MArea
->VadNode
.u
.VadFlags
.VadType
= VadImageMap
;
3939 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3940 ViewSize
, 0, Protect
);
3942 return(STATUS_SUCCESS
);
3947 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3948 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3952 PFILE_OBJECT FileObject
;
3953 PROS_SHARED_CACHE_MAP SharedCacheMap
;
3955 LARGE_INTEGER Offset
;
3956 SWAPENTRY SavedSwapEntry
;
3957 PROS_SECTION_OBJECT Section
;
3958 PMM_SECTION_SEGMENT Segment
;
3959 PMMSUPPORT AddressSpace
;
3962 AddressSpace
= (PMMSUPPORT
)Context
;
3963 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3965 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3967 Offset
.QuadPart
= ((ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)) +
3968 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3970 Section
= MemoryArea
->Data
.SectionData
.Section
;
3971 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3973 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3974 while (Entry
&& MM_IS_WAIT_PTE(Entry
))
3976 MmUnlockSectionSegment(Segment
);
3977 MmUnlockAddressSpace(AddressSpace
);
3979 MiWaitForPageEvent(NULL
, NULL
);
3981 MmLockAddressSpace(AddressSpace
);
3982 MmLockSectionSegment(Segment
);
3983 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3987 * For a dirty, datafile, non-private page mark it as dirty in the
3990 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3992 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3995 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3996 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3997 CcRosMarkDirtyFile(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
3999 ASSERT(SwapEntry
== 0);
4008 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4010 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4011 KeBugCheck(MEMORY_MANAGEMENT
);
4013 MmFreeSwapPage(SwapEntry
);
4017 if (IS_SWAP_FROM_SSE(Entry
) ||
4018 Page
!= PFN_FROM_SSE(Entry
))
4023 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4025 DPRINT1("Found a private page in a pagefile section.\n");
4026 KeBugCheck(MEMORY_MANAGEMENT
);
4029 * Just dereference private pages
4031 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4032 if (SavedSwapEntry
!= 0)
4034 MmFreeSwapPage(SavedSwapEntry
);
4035 MmSetSavedSwapEntryPage(Page
, 0);
4037 MmDeleteRmap(Page
, Process
, Address
);
4038 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4042 MmDeleteRmap(Page
, Process
, Address
);
4043 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4049 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4053 PMEMORY_AREA MemoryArea
;
4054 PROS_SECTION_OBJECT Section
;
4055 PMM_SECTION_SEGMENT Segment
;
4056 PLIST_ENTRY CurrentEntry
;
4057 PMM_REGION CurrentRegion
;
4058 PLIST_ENTRY RegionListHead
;
4060 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4062 if (MemoryArea
== NULL
)
4064 return(STATUS_UNSUCCESSFUL
);
4067 Section
= MemoryArea
->Data
.SectionData
.Section
;
4068 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4071 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4073 MmUnlockAddressSpace(AddressSpace
);
4074 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4075 MmLockAddressSpace(AddressSpace
);
4081 MemoryArea
->DeleteInProgress
= TRUE
;
4083 MmLockSectionSegment(Segment
);
4085 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4086 while (!IsListEmpty(RegionListHead
))
4088 CurrentEntry
= RemoveHeadList(RegionListHead
);
4089 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4090 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4093 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4095 Status
= MmFreeMemoryArea(AddressSpace
,
4102 Status
= MmFreeMemoryArea(AddressSpace
,
4107 MmUnlockSectionSegment(Segment
);
4108 ObDereferenceObject(Section
);
4114 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4115 IN PVOID BaseAddress
,
4116 IN BOOLEAN SkipDebuggerNotify
)
4119 PMEMORY_AREA MemoryArea
;
4120 PMMSUPPORT AddressSpace
;
4121 PROS_SECTION_OBJECT Section
;
4122 PVOID ImageBaseAddress
= 0;
4124 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4125 Process
, BaseAddress
);
4129 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4131 MmLockAddressSpace(AddressSpace
);
4132 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4134 if (MemoryArea
== NULL
||
4135 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4136 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4137 MemoryArea
->DeleteInProgress
)
4139 if (MemoryArea
) ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4140 MmUnlockAddressSpace(AddressSpace
);
4141 return STATUS_NOT_MAPPED_VIEW
;
4144 Section
= MemoryArea
->Data
.SectionData
.Section
;
4146 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4150 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4151 PMM_SECTION_SEGMENT SectionSegments
;
4152 PMM_SECTION_SEGMENT Segment
;
4154 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4155 ImageSectionObject
= Section
->ImageSection
;
4156 SectionSegments
= ImageSectionObject
->Segments
;
4157 NrSegments
= ImageSectionObject
->NrSegments
;
4159 MemoryArea
->DeleteInProgress
= TRUE
;
4161 /* Search for the current segment within the section segments
4162 * and calculate the image base address */
4163 for (i
= 0; i
< NrSegments
; i
++)
4165 if (Segment
== &SectionSegments
[i
])
4167 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4171 if (i
>= NrSegments
)
4173 KeBugCheck(MEMORY_MANAGEMENT
);
4176 for (i
= 0; i
< NrSegments
; i
++)
4178 PVOID SBaseAddress
= (PVOID
)
4179 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4181 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4182 if (!NT_SUCCESS(Status
))
4184 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4185 SBaseAddress
, Process
, Status
);
4186 ASSERT(NT_SUCCESS(Status
));
4192 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4193 if (!NT_SUCCESS(Status
))
4195 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4196 BaseAddress
, Process
, Status
);
4197 ASSERT(NT_SUCCESS(Status
));
4201 MmUnlockAddressSpace(AddressSpace
);
4203 /* Notify debugger */
4204 if (ImageBaseAddress
&& !SkipDebuggerNotify
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4206 return(STATUS_SUCCESS
);
4213 * Queries the information of a section object.
4215 * @param SectionHandle
4216 * Handle to the section object. It must be opened with SECTION_QUERY
4218 * @param SectionInformationClass
4219 * Index to a certain information structure. Can be either
4220 * SectionBasicInformation or SectionImageInformation. The latter
4221 * is valid only for sections that were created with the SEC_IMAGE
4223 * @param SectionInformation
4224 * Caller supplies storage for resulting information.
4226 * Size of the supplied storage.
4227 * @param ResultLength
4237 _In_ HANDLE SectionHandle
,
4238 _In_ SECTION_INFORMATION_CLASS SectionInformationClass
,
4239 _Out_ PVOID SectionInformation
,
4240 _In_ SIZE_T SectionInformationLength
,
4241 _Out_opt_ PSIZE_T ResultLength
)
4244 KPROCESSOR_MODE PreviousMode
;
4248 PreviousMode
= ExGetPreviousMode();
4249 if (PreviousMode
!= KernelMode
)
4253 ProbeForWrite(SectionInformation
,
4254 SectionInformationLength
,
4256 if (ResultLength
!= NULL
)
4258 ProbeForWrite(ResultLength
,
4259 sizeof(*ResultLength
),
4263 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4265 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4270 if (SectionInformationClass
== SectionBasicInformation
)
4272 if (SectionInformationLength
< sizeof(SECTION_BASIC_INFORMATION
))
4274 return STATUS_INFO_LENGTH_MISMATCH
;
4277 else if (SectionInformationClass
== SectionImageInformation
)
4279 if (SectionInformationLength
< sizeof(SECTION_IMAGE_INFORMATION
))
4281 return STATUS_INFO_LENGTH_MISMATCH
;
4286 return STATUS_INVALID_INFO_CLASS
;
4289 Status
= ObReferenceObjectByHandle(SectionHandle
,
4291 MmSectionObjectType
,
4293 (PVOID
*)(PVOID
)&Section
,
4295 if (!NT_SUCCESS(Status
))
4297 DPRINT1("Failed to reference section: 0x%lx\n", Status
);
4301 if (MiIsRosSectionObject(Section
))
4303 PROS_SECTION_OBJECT RosSection
= (PROS_SECTION_OBJECT
)Section
;
4305 switch (SectionInformationClass
)
4307 case SectionBasicInformation
:
4309 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4313 Sbi
->Attributes
= RosSection
->AllocationAttributes
;
4314 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4316 Sbi
->BaseAddress
= 0;
4317 Sbi
->Size
.QuadPart
= 0;
4321 Sbi
->BaseAddress
= (PVOID
)RosSection
->Segment
->Image
.VirtualAddress
;
4322 Sbi
->Size
.QuadPart
= RosSection
->Segment
->Length
.QuadPart
;
4325 if (ResultLength
!= NULL
)
4327 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4329 Status
= STATUS_SUCCESS
;
4331 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4333 Status
= _SEH2_GetExceptionCode();
4340 case SectionImageInformation
:
4342 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4346 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4348 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4349 ImageSectionObject
= RosSection
->ImageSection
;
4351 *Sii
= ImageSectionObject
->ImageInformation
;
4354 if (ResultLength
!= NULL
)
4356 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4358 Status
= STATUS_SUCCESS
;
4360 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4362 Status
= _SEH2_GetExceptionCode();
4372 switch(SectionInformationClass
)
4374 case SectionBasicInformation
:
4376 SECTION_BASIC_INFORMATION Sbi
;
4378 Sbi
.Size
= Section
->SizeOfSection
;
4379 Sbi
.BaseAddress
= (PVOID
)Section
->Address
.StartingVpn
;
4382 if (Section
->u
.Flags
.Image
)
4383 Sbi
.Attributes
|= SEC_IMAGE
;
4384 if (Section
->u
.Flags
.Commit
)
4385 Sbi
.Attributes
|= SEC_COMMIT
;
4386 if (Section
->u
.Flags
.Reserve
)
4387 Sbi
.Attributes
|= SEC_RESERVE
;
4388 if (Section
->u
.Flags
.File
)
4389 Sbi
.Attributes
|= SEC_FILE
;
4390 if (Section
->u
.Flags
.Image
)
4391 Sbi
.Attributes
|= SEC_IMAGE
;
4393 /* FIXME : Complete/test the list of flags passed back from NtCreateSection */
4397 *((SECTION_BASIC_INFORMATION
*)SectionInformation
) = Sbi
;
4399 *ResultLength
= sizeof(Sbi
);
4401 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4403 Status
= _SEH2_GetExceptionCode();
4408 case SectionImageInformation
:
4410 if (!Section
->u
.Flags
.Image
)
4412 Status
= STATUS_SECTION_NOT_IMAGE
;
4416 /* Currently not supported */
4424 ObDereferenceObject(Section
);
4429 /**********************************************************************
4431 * MmMapViewOfSection
4434 * Maps a view of a section into the virtual address space of a
4439 * Pointer to the section object.
4442 * Pointer to the process.
4445 * Desired base address (or NULL) on entry;
4446 * Actual base address of the view on exit.
4449 * Number of high order address bits that must be zero.
4452 * Size in bytes of the initially committed section of
4456 * Offset in bytes from the beginning of the section
4457 * to the beginning of the view.
4460 * Desired length of map (or zero to map all) on entry
4461 * Actual length mapped on exit.
4463 * InheritDisposition
4464 * Specified how the view is to be shared with
4468 * Type of allocation for the pages.
4471 * Protection for the committed region of the view.
4479 MmMapViewOfSection(IN PVOID SectionObject
,
4480 IN PEPROCESS Process
,
4481 IN OUT PVOID
*BaseAddress
,
4482 IN ULONG_PTR ZeroBits
,
4483 IN SIZE_T CommitSize
,
4484 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4485 IN OUT PSIZE_T ViewSize
,
4486 IN SECTION_INHERIT InheritDisposition
,
4487 IN ULONG AllocationType
,
4490 PROS_SECTION_OBJECT Section
;
4491 PMMSUPPORT AddressSpace
;
4493 NTSTATUS Status
= STATUS_SUCCESS
;
4494 BOOLEAN NotAtBase
= FALSE
;
4496 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4498 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4499 return MmMapViewOfArm3Section(SectionObject
,
4513 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4515 return STATUS_INVALID_PAGE_PROTECTION
;
4518 /* FIXME: We should keep this, but it would break code checking equality */
4519 Protect
&= ~PAGE_NOCACHE
;
4521 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4522 AddressSpace
= &Process
->Vm
;
4524 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4526 MmLockAddressSpace(AddressSpace
);
4528 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4532 ULONG_PTR ImageBase
;
4534 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4535 PMM_SECTION_SEGMENT SectionSegments
;
4537 ImageSectionObject
= Section
->ImageSection
;
4538 SectionSegments
= ImageSectionObject
->Segments
;
4539 NrSegments
= ImageSectionObject
->NrSegments
;
4541 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4544 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4548 for (i
= 0; i
< NrSegments
; i
++)
4550 ULONG_PTR MaxExtent
;
4551 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4552 SectionSegments
[i
].Length
.QuadPart
);
4553 ImageSize
= max(ImageSize
, MaxExtent
);
4556 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4558 /* Check for an illegal base address */
4559 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4560 ((ImageBase
+ ImageSize
) < ImageSize
))
4562 ASSERT(*BaseAddress
== NULL
);
4563 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4564 MM_VIRTMEM_GRANULARITY
);
4567 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4569 ASSERT(*BaseAddress
== NULL
);
4570 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4574 /* Check there is enough space to map the section at that point. */
4575 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4576 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4578 /* Fail if the user requested a fixed base address. */
4579 if ((*BaseAddress
) != NULL
)
4581 MmUnlockAddressSpace(AddressSpace
);
4582 return(STATUS_CONFLICTING_ADDRESSES
);
4584 /* Otherwise find a gap to map the image. */
4585 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4588 MmUnlockAddressSpace(AddressSpace
);
4589 return(STATUS_CONFLICTING_ADDRESSES
);
4591 /* Remember that we loaded image at a different base address */
4595 for (i
= 0; i
< NrSegments
; i
++)
4597 PVOID SBaseAddress
= (PVOID
)
4598 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4599 MmLockSectionSegment(&SectionSegments
[i
]);
4600 Status
= MmMapViewOfSegment(AddressSpace
,
4602 &SectionSegments
[i
],
4604 SectionSegments
[i
].Length
.LowPart
,
4605 SectionSegments
[i
].Protection
,
4608 MmUnlockSectionSegment(&SectionSegments
[i
]);
4609 if (!NT_SUCCESS(Status
))
4611 MmUnlockAddressSpace(AddressSpace
);
4616 *BaseAddress
= (PVOID
)ImageBase
;
4617 *ViewSize
= ImageSize
;
4621 /* check for write access */
4622 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4623 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4625 MmUnlockAddressSpace(AddressSpace
);
4626 return STATUS_SECTION_PROTECTION
;
4628 /* check for read access */
4629 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4630 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4632 MmUnlockAddressSpace(AddressSpace
);
4633 return STATUS_SECTION_PROTECTION
;
4635 /* check for execute access */
4636 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4637 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4639 MmUnlockAddressSpace(AddressSpace
);
4640 return STATUS_SECTION_PROTECTION
;
4643 if (SectionOffset
== NULL
)
4649 ViewOffset
= SectionOffset
->u
.LowPart
;
4652 if ((ViewOffset
% PAGE_SIZE
) != 0)
4654 MmUnlockAddressSpace(AddressSpace
);
4655 return(STATUS_MAPPED_ALIGNMENT
);
4658 if ((*ViewSize
) == 0)
4660 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4662 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4664 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4667 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4669 MmLockSectionSegment(Section
->Segment
);
4670 Status
= MmMapViewOfSegment(AddressSpace
,
4677 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4678 MmUnlockSectionSegment(Section
->Segment
);
4679 if (!NT_SUCCESS(Status
))
4681 MmUnlockAddressSpace(AddressSpace
);
4686 MmUnlockAddressSpace(AddressSpace
);
4687 ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4690 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4692 Status
= STATUS_SUCCESS
;
4701 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4702 IN PLARGE_INTEGER NewFileSize
)
4704 /* Check whether an ImageSectionObject exists */
4705 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4707 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4711 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4713 PMM_SECTION_SEGMENT Segment
;
4715 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4718 if (Segment
->ReferenceCount
!= 0)
4721 CC_FILE_SIZES FileSizes
;
4723 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4726 /* Check size of file */
4727 if (SectionObjectPointer
->SharedCacheMap
)
4729 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4734 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4743 /* Check size of file */
4744 if (SectionObjectPointer
->SharedCacheMap
)
4746 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4747 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4756 /* Something must gone wrong
4757 * how can we have a Section but no
4759 DPRINT("ERROR: DataSectionObject without reference!\n");
4763 DPRINT("FIXME: didn't check for outstanding write probes\n");
4775 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4776 IN MMFLUSH_TYPE FlushType
)
4778 BOOLEAN Result
= TRUE
;
4780 PMM_SECTION_SEGMENT Segment
;
4785 case MmFlushForDelete
:
4786 if (SectionObjectPointer
->ImageSectionObject
||
4787 SectionObjectPointer
->DataSectionObject
)
4792 CcRosRemoveIfClosed(SectionObjectPointer
);
4795 case MmFlushForWrite
:
4797 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4799 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4802 if (SectionObjectPointer
->ImageSectionObject
)
4804 DPRINT1("SectionObject has ImageSection\n");
4810 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4812 DPRINT("Result %d\n", Result
);
4824 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4825 OUT PVOID
* MappedBase
,
4826 IN OUT PSIZE_T ViewSize
)
4828 PROS_SECTION_OBJECT Section
;
4829 PMMSUPPORT AddressSpace
;
4833 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4835 return MiMapViewInSystemSpace(SectionObject
,
4841 DPRINT("MmMapViewInSystemSpace() called\n");
4843 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4844 AddressSpace
= MmGetKernelAddressSpace();
4846 MmLockAddressSpace(AddressSpace
);
4849 if ((*ViewSize
) == 0)
4851 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4853 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4855 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4858 MmLockSectionSegment(Section
->Segment
);
4861 Status
= MmMapViewOfSegment(AddressSpace
,
4870 MmUnlockSectionSegment(Section
->Segment
);
4871 MmUnlockAddressSpace(AddressSpace
);
4878 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4880 PMMSUPPORT AddressSpace
;
4883 DPRINT("MmUnmapViewInSystemSpace() called\n");
4885 AddressSpace
= MmGetKernelAddressSpace();
4887 MmLockAddressSpace(AddressSpace
);
4889 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4891 MmUnlockAddressSpace(AddressSpace
);
4896 /**********************************************************************
4901 * Creates a section object.
4904 * SectionObject (OUT)
4905 * Caller supplied storage for the resulting pointer
4906 * to a SECTION_OBJECT instance;
4909 * Specifies the desired access to the section can be a
4911 * STANDARD_RIGHTS_REQUIRED |
4913 * SECTION_MAP_WRITE |
4914 * SECTION_MAP_READ |
4915 * SECTION_MAP_EXECUTE
4917 * ObjectAttributes [OPTIONAL]
4918 * Initialized attributes for the object can be used
4919 * to create a named section;
4922 * Maximizes the size of the memory section. Must be
4923 * non-NULL for a page-file backed section.
4924 * If value specified for a mapped file and the file is
4925 * not large enough, file will be extended.
4927 * SectionPageProtection
4928 * Can be a combination of:
4934 * AllocationAttributes
4935 * Can be a combination of:
4940 * Handle to a file to create a section mapped to a file
4941 * instead of a memory backed section;
4952 MmCreateSection (OUT PVOID
* Section
,
4953 IN ACCESS_MASK DesiredAccess
,
4954 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4955 IN PLARGE_INTEGER MaximumSize
,
4956 IN ULONG SectionPageProtection
,
4957 IN ULONG AllocationAttributes
,
4958 IN HANDLE FileHandle OPTIONAL
,
4959 IN PFILE_OBJECT FileObject OPTIONAL
)
4963 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4965 /* Check if an ARM3 section is being created instead */
4966 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4968 if (!(FileObject
) && !(FileHandle
))
4970 return MmCreateArm3Section(Section
,
4974 SectionPageProtection
,
4975 AllocationAttributes
&~ 1,
4981 /* Convert section flag to page flag */
4982 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4984 /* Check to make sure the protection is correct. Nt* does this already */
4985 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4986 if (Protection
== MM_INVALID_PROTECTION
)
4988 DPRINT1("Page protection is invalid\n");
4989 return STATUS_INVALID_PAGE_PROTECTION
;
4992 /* Check if this is going to be a data or image backed file section */
4993 if ((FileHandle
) || (FileObject
))
4995 /* These cannot be mapped with large pages */
4996 if (AllocationAttributes
& SEC_LARGE_PAGES
)
4998 DPRINT1("Large pages cannot be used with an image mapping\n");
4999 return STATUS_INVALID_PARAMETER_6
;
5002 /* Did the caller pass an object? */
5005 /* Reference the object directly */
5006 ObReferenceObject(FileObject
);
5010 /* Reference the file handle to get the object */
5011 Status
= ObReferenceObjectByHandle(FileHandle
,
5012 MmMakeFileAccess
[Protection
],
5014 ExGetPreviousMode(),
5015 (PVOID
*)&FileObject
,
5017 if (!NT_SUCCESS(Status
))
5019 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
5026 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
5027 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
5030 #ifndef NEWCC // A hack for initializing caching.
5031 // This is needed only in the old case.
5034 IO_STATUS_BLOCK Iosb
;
5037 LARGE_INTEGER ByteOffset
;
5038 ByteOffset
.QuadPart
= 0;
5039 Status
= ZwReadFile(FileHandle
,
5048 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5050 DPRINT1("CC failure: %lx\n", Status
);
5052 ObDereferenceObject(FileObject
);
5055 // Caching is initialized...
5057 // Hack of the hack: actually, it might not be initialized if FSD init on effective right and if file is null-size
5058 // In such case, force cache by initiating a write IRP
5059 if (Status
== STATUS_END_OF_FILE
&& !(AllocationAttributes
& SEC_IMAGE
) && FileObject
!= NULL
&&
5060 (FileObject
->SectionObjectPointer
== NULL
|| FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
))
5063 Status
= ZwWriteFile(FileHandle
,
5072 if (NT_SUCCESS(Status
))
5075 Zero
.QuadPart
= 0LL;
5077 Status
= IoSetInformation(FileObject
,
5078 FileEndOfFileInformation
,
5079 sizeof(LARGE_INTEGER
),
5081 ASSERT(NT_SUCCESS(Status
));
5087 if (AllocationAttributes
& SEC_IMAGE
)
5089 Status
= MmCreateImageSection(SectionObject
,
5093 SectionPageProtection
,
5094 AllocationAttributes
,
5098 else if (FileHandle
!= NULL
)
5100 Status
= MmCreateDataFileSection(SectionObject
,
5104 SectionPageProtection
,
5105 AllocationAttributes
,
5109 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5111 Status
= MmCreateCacheSection(SectionObject
,
5115 SectionPageProtection
,
5116 AllocationAttributes
,
5122 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5124 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5126 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5127 Status
= MmCreatePageFileSection(SectionObject
,
5131 SectionPageProtection
,
5132 AllocationAttributes
);
5134 ObDereferenceObject(FileObject
);