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
= 0;
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 */
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 (IS_SWAP_FROM_SSE(Entry
) || PFN_FROM_SSE(Entry
) != Page
)
1961 Context
.Private
= TRUE
;
1965 Context
.Private
= FALSE
;
1969 * Take an additional reference to the page or the VACB.
1971 if (DirectMapped
&& !Context
.Private
)
1973 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
1975 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1976 KeBugCheck(MEMORY_MANAGEMENT
);
1981 OldIrql
= MiAcquirePfnLock();
1982 MmReferencePage(Page
);
1983 MiReleasePfnLock(OldIrql
);
1986 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1988 /* Since we passed in a surrogate, we'll get back the page entry
1989 * state in our context. This is intended to make intermediate
1990 * decrements of share count not release the wait entry.
1992 Entry
= Context
.SectionEntry
;
1995 * If this wasn't a private page then we should have reduced the entry to
1996 * zero by deleting all the rmaps.
1998 if (!Context
.Private
&& Entry
!= 0)
2000 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2001 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2003 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2008 * If the page wasn't dirty then we can just free it as for a readonly page.
2009 * Since we unmapped all the mappings above we know it will not suddenly
2011 * If the page is from a pagefile section and has no swap entry,
2012 * we can't free the page at this point.
2014 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2015 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2017 if (Context
.Private
)
2019 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2020 Context
.WasDirty
? "dirty" : "clean", Address
);
2021 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2023 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2025 MmSetSavedSwapEntryPage(Page
, 0);
2026 MmLockSectionSegment(Context
.Segment
);
2027 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2028 MmUnlockSectionSegment(Context
.Segment
);
2029 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2030 MiSetPageEvent(NULL
, NULL
);
2031 return(STATUS_SUCCESS
);
2034 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2036 if (Context
.Private
)
2038 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2039 Context
.WasDirty
? "dirty" : "clean", Address
);
2040 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2042 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2044 MmSetSavedSwapEntryPage(Page
, 0);
2047 MmLockSectionSegment(Context
.Segment
);
2048 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2049 MmUnlockSectionSegment(Context
.Segment
);
2051 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2052 MiSetPageEvent(NULL
, NULL
);
2053 return(STATUS_SUCCESS
);
2056 else if (!Context
.Private
&& DirectMapped
)
2060 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2062 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2065 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
, FALSE
);
2067 Status
= STATUS_SUCCESS
;
2070 if (!NT_SUCCESS(Status
))
2072 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2073 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2076 MiSetPageEvent(NULL
, NULL
);
2077 return(STATUS_SUCCESS
);
2079 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2083 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2085 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2087 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2088 MiSetPageEvent(NULL
, NULL
);
2089 return(STATUS_SUCCESS
);
2091 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2093 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2094 MmSetSavedSwapEntryPage(Page
, 0);
2095 MmLockAddressSpace(AddressSpace
);
2096 Status
= MmCreatePageFileMapping(Process
,
2099 MmUnlockAddressSpace(AddressSpace
);
2100 if (!NT_SUCCESS(Status
))
2102 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2103 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2105 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2106 MiSetPageEvent(NULL
, NULL
);
2107 return(STATUS_SUCCESS
);
2111 * If necessary, allocate an entry in the paging file for this page
2115 SwapEntry
= MmAllocSwapPage();
2118 MmShowOutOfSpaceMessagePagingFile();
2119 MmLockAddressSpace(AddressSpace
);
2121 * For private pages restore the old mappings.
2123 if (Context
.Private
)
2125 Status
= MmCreateVirtualMapping(Process
,
2127 MemoryArea
->Protect
,
2130 MmSetDirtyPage(Process
, Address
);
2139 MmLockSectionSegment(Context
.Segment
);
2142 * For non-private pages if the page wasn't direct mapped then
2143 * set it back into the section segment entry so we don't loose
2144 * our copy. Otherwise it will be handled by the cache manager.
2146 Status
= MmCreateVirtualMapping(Process
,
2148 MemoryArea
->Protect
,
2151 MmSetDirtyPage(Process
, Address
);
2155 // If we got here, the previous entry should have been a wait
2156 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2157 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2158 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2159 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2160 MmUnlockSectionSegment(Context
.Segment
);
2162 MmUnlockAddressSpace(AddressSpace
);
2163 MiSetPageEvent(NULL
, NULL
);
2164 return(STATUS_PAGEFILE_QUOTA
);
2169 * Write the page to the pagefile
2171 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2172 if (!NT_SUCCESS(Status
))
2174 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2177 * As above: undo our actions.
2178 * FIXME: Also free the swap page.
2180 MmLockAddressSpace(AddressSpace
);
2181 if (Context
.Private
)
2183 Status
= MmCreateVirtualMapping(Process
,
2185 MemoryArea
->Protect
,
2188 MmSetDirtyPage(Process
, Address
);
2195 MmLockSectionSegment(Context
.Segment
);
2196 Status
= MmCreateVirtualMapping(Process
,
2198 MemoryArea
->Protect
,
2201 MmSetDirtyPage(Process
, Address
);
2205 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2206 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2207 MmUnlockSectionSegment(Context
.Segment
);
2209 MmUnlockAddressSpace(AddressSpace
);
2210 MiSetPageEvent(NULL
, NULL
);
2211 return(STATUS_UNSUCCESSFUL
);
2215 * Otherwise we have succeeded.
2217 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2218 MmSetSavedSwapEntryPage(Page
, 0);
2219 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2220 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2222 MmLockSectionSegment(Context
.Segment
);
2223 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2224 MmUnlockSectionSegment(Context
.Segment
);
2228 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2231 if (Context
.Private
)
2233 MmLockAddressSpace(AddressSpace
);
2234 MmLockSectionSegment(Context
.Segment
);
2235 Status
= MmCreatePageFileMapping(Process
,
2238 /* We had placed a wait entry upon entry ... replace it before leaving */
2239 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2240 MmUnlockSectionSegment(Context
.Segment
);
2241 MmUnlockAddressSpace(AddressSpace
);
2242 if (!NT_SUCCESS(Status
))
2244 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2245 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2250 MmLockAddressSpace(AddressSpace
);
2251 MmLockSectionSegment(Context
.Segment
);
2252 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2253 /* We had placed a wait entry upon entry ... replace it before leaving */
2254 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2255 MmUnlockSectionSegment(Context
.Segment
);
2256 MmUnlockAddressSpace(AddressSpace
);
2259 MiSetPageEvent(NULL
, NULL
);
2260 return(STATUS_SUCCESS
);
2265 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2266 PMEMORY_AREA MemoryArea
,
2270 LARGE_INTEGER Offset
;
2271 PROS_SECTION_OBJECT Section
;
2272 PMM_SECTION_SEGMENT Segment
;
2274 SWAPENTRY SwapEntry
;
2278 PFILE_OBJECT FileObject
;
2280 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2282 BOOLEAN DirectMapped
;
2283 BOOLEAN IsImageSection
;
2284 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2286 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2288 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2289 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2292 * Get the segment and section.
2294 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2295 Section
= MemoryArea
->Data
.SectionData
.Section
;
2296 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2298 FileObject
= Section
->FileObject
;
2299 DirectMapped
= FALSE
;
2300 if (FileObject
!= NULL
&&
2301 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2304 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2308 * If the file system is letting us go directly to the cache and the
2309 * memory area was mapped at an offset in the file which is page aligned
2310 * then note this is a direct mapped page.
2312 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2313 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2315 DirectMapped
= TRUE
;
2320 * This should never happen since mappings of physical memory are never
2321 * placed in the rmap lists.
2323 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2325 DPRINT1("Trying to write back page from physical memory mapped at %p "
2326 "process %p\n", Address
,
2327 Process
? Process
->UniqueProcessId
: 0);
2328 KeBugCheck(MEMORY_MANAGEMENT
);
2332 * Get the section segment entry and the physical address.
2334 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2335 if (!MmIsPagePresent(Process
, Address
))
2337 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2338 Process
? Process
->UniqueProcessId
: 0, Address
);
2339 KeBugCheck(MEMORY_MANAGEMENT
);
2341 Page
= MmGetPfnForProcess(Process
, Address
);
2342 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2345 * Check for a private (COWed) page.
2347 if (IS_SWAP_FROM_SSE(Entry
) || PFN_FROM_SSE(Entry
) != Page
)
2357 * Speculatively set all mappings of the page to clean.
2359 MmSetCleanAllRmaps(Page
);
2362 * If this page was direct mapped from the cache then the cache manager
2363 * will take care of writing it back to disk.
2365 if (DirectMapped
&& !Private
)
2367 //LARGE_INTEGER SOffset;
2368 ASSERT(SwapEntry
== 0);
2369 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2371 CcRosMarkDirtyFile(SharedCacheMap
, Offset
.QuadPart
);
2373 MmLockSectionSegment(Segment
);
2374 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2375 MmUnlockSectionSegment(Segment
);
2376 MiSetPageEvent(NULL
, NULL
);
2377 return(STATUS_SUCCESS
);
2381 * If necessary, allocate an entry in the paging file for this page
2385 SwapEntry
= MmAllocSwapPage();
2388 MmSetDirtyAllRmaps(Page
);
2389 MiSetPageEvent(NULL
, NULL
);
2390 return(STATUS_PAGEFILE_QUOTA
);
2392 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2396 * Write the page to the pagefile
2398 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2399 if (!NT_SUCCESS(Status
))
2401 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2403 MmSetDirtyAllRmaps(Page
);
2404 MiSetPageEvent(NULL
, NULL
);
2405 return(STATUS_UNSUCCESSFUL
);
2409 * Otherwise we have succeeded.
2411 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2412 MiSetPageEvent(NULL
, NULL
);
2413 return(STATUS_SUCCESS
);
2417 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2425 PMEMORY_AREA MemoryArea
;
2426 PMM_SECTION_SEGMENT Segment
;
2427 BOOLEAN DoCOW
= FALSE
;
2429 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2431 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2432 ASSERT(MemoryArea
!= NULL
);
2433 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2434 MmLockSectionSegment(Segment
);
2436 if ((Segment
->WriteCopy
) &&
2437 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2442 if (OldProtect
!= NewProtect
)
2444 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2446 SWAPENTRY SwapEntry
;
2447 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2448 ULONG Protect
= NewProtect
;
2450 /* Wait for a wait entry to disappear */
2453 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2454 if (SwapEntry
!= MM_WAIT_ENTRY
)
2456 MiWaitForPageEvent(Process
, Address
);
2461 * If we doing COW for this segment then check if the page is
2464 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2466 LARGE_INTEGER Offset
;
2470 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2471 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2472 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2474 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2475 * IS_SWAP_FROM_SSE and we'll do the right thing.
2477 Page
= MmGetPfnForProcess(Process
, Address
);
2479 Protect
= PAGE_READONLY
;
2480 if (IS_SWAP_FROM_SSE(Entry
) || PFN_FROM_SSE(Entry
) != Page
)
2482 Protect
= NewProtect
;
2486 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2488 MmSetPageProtect(Process
, Address
,
2494 MmUnlockSectionSegment(Segment
);
2499 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2500 PMEMORY_AREA MemoryArea
,
2508 ULONG_PTR MaxLength
;
2510 MaxLength
= MA_GetEndingAddress(MemoryArea
) - (ULONG_PTR
)BaseAddress
;
2511 if (Length
> MaxLength
)
2512 Length
= (ULONG
)MaxLength
;
2514 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2515 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2517 ASSERT(Region
!= NULL
);
2519 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2520 Region
->Protect
!= Protect
)
2522 return STATUS_INVALID_PAGE_PROTECTION
;
2525 *OldProtect
= Region
->Protect
;
2526 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
2527 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2528 BaseAddress
, Length
, Region
->Type
, Protect
,
2529 MmAlterViewAttributes
);
2535 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2537 PMEMORY_BASIC_INFORMATION Info
,
2538 PSIZE_T ResultLength
)
2541 PVOID RegionBaseAddress
;
2542 PROS_SECTION_OBJECT Section
;
2543 PMM_SECTION_SEGMENT Segment
;
2545 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2546 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2547 Address
, &RegionBaseAddress
);
2550 return STATUS_UNSUCCESSFUL
;
2553 Section
= MemoryArea
->Data
.SectionData
.Section
;
2554 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2556 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2557 Info
->AllocationBase
= (PUCHAR
)MA_GetStartingAddress(MemoryArea
) - Segment
->Image
.VirtualAddress
;
2558 Info
->Type
= MEM_IMAGE
;
2562 Info
->AllocationBase
= (PVOID
)MA_GetStartingAddress(MemoryArea
);
2563 Info
->Type
= MEM_MAPPED
;
2565 Info
->BaseAddress
= RegionBaseAddress
;
2566 Info
->AllocationProtect
= MemoryArea
->Protect
;
2567 Info
->RegionSize
= Region
->Length
;
2568 Info
->State
= MEM_COMMIT
;
2569 Info
->Protect
= Region
->Protect
;
2571 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2572 return(STATUS_SUCCESS
);
2577 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2580 LARGE_INTEGER Offset
;
2582 SWAPENTRY SavedSwapEntry
;
2587 MmLockSectionSegment(Segment
);
2589 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2590 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2592 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2595 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2596 if (IS_SWAP_FROM_SSE(Entry
))
2598 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2602 Page
= PFN_FROM_SSE(Entry
);
2603 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2604 if (SavedSwapEntry
!= 0)
2606 MmSetSavedSwapEntryPage(Page
, 0);
2607 MmFreeSwapPage(SavedSwapEntry
);
2609 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2614 MmUnlockSectionSegment(Segment
);
2618 MmpDeleteSection(PVOID ObjectBody
)
2620 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2622 /* Check if it's an ARM3, or ReactOS section */
2623 if (!MiIsRosSectionObject(Section
))
2625 MiDeleteARM3Section(ObjectBody
);
2629 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2630 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2635 PMM_SECTION_SEGMENT SectionSegments
;
2638 * NOTE: Section->ImageSection can be NULL for short time
2639 * during the section creating. If we fail for some reason
2640 * until the image section is properly initialized we shouldn't
2641 * process further here.
2643 if (Section
->ImageSection
== NULL
)
2646 SectionSegments
= Section
->ImageSection
->Segments
;
2647 NrSegments
= Section
->ImageSection
->NrSegments
;
2649 for (i
= 0; i
< NrSegments
; i
++)
2651 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2653 MmLockSectionSegment(&SectionSegments
[i
]);
2655 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2656 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2658 MmUnlockSectionSegment(&SectionSegments
[i
]);
2661 MmpFreePageFileSegment(&SectionSegments
[i
]);
2667 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2670 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2673 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2675 DPRINT("Freeing section segment\n");
2676 Section
->Segment
= NULL
;
2677 MmFinalizeSegment(Segment
);
2681 DPRINT("RefCount %d\n", RefCount
);
2688 * NOTE: Section->Segment can be NULL for short time
2689 * during the section creating.
2691 if (Section
->Segment
== NULL
)
2694 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2696 MmpFreePageFileSegment(Section
->Segment
);
2697 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2698 ExFreePool(Section
->Segment
);
2699 Section
->Segment
= NULL
;
2703 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2706 if (Section
->FileObject
!= NULL
)
2709 CcRosDereferenceCache(Section
->FileObject
);
2711 ObDereferenceObject(Section
->FileObject
);
2712 Section
->FileObject
= NULL
;
2717 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2719 IN ACCESS_MASK GrantedAccess
,
2720 IN ULONG ProcessHandleCount
,
2721 IN ULONG SystemHandleCount
)
2723 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2729 MmCreatePhysicalMemorySection(VOID
)
2731 PROS_SECTION_OBJECT PhysSection
;
2733 OBJECT_ATTRIBUTES Obj
;
2734 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2735 LARGE_INTEGER SectionSize
;
2739 * Create the section mapping physical memory
2741 SectionSize
.QuadPart
= 0xFFFFFFFF;
2742 InitializeObjectAttributes(&Obj
,
2744 OBJ_PERMANENT
| OBJ_KERNEL_EXCLUSIVE
,
2747 Status
= MmCreateSection((PVOID
)&PhysSection
,
2751 PAGE_EXECUTE_READWRITE
,
2755 if (!NT_SUCCESS(Status
))
2757 DPRINT1("Failed to create PhysicalMemory section\n");
2758 KeBugCheck(MEMORY_MANAGEMENT
);
2760 Status
= ObInsertObject(PhysSection
,
2766 if (!NT_SUCCESS(Status
))
2768 ObDereferenceObject(PhysSection
);
2770 ObCloseHandle(Handle
, KernelMode
);
2771 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2772 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2774 return(STATUS_SUCCESS
);
2780 MmInitSectionImplementation(VOID
)
2782 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2783 UNICODE_STRING Name
;
2785 DPRINT("Creating Section Object Type\n");
2787 /* Initialize the section based root */
2788 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2789 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2791 /* Initialize the Section object type */
2792 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2793 RtlInitUnicodeString(&Name
, L
"Section");
2794 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2795 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2796 ObjectTypeInitializer
.PoolType
= PagedPool
;
2797 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2798 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2799 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2800 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2801 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2802 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2803 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2805 MmCreatePhysicalMemorySection();
2807 return(STATUS_SUCCESS
);
2812 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2813 ACCESS_MASK DesiredAccess
,
2814 POBJECT_ATTRIBUTES ObjectAttributes
,
2815 PLARGE_INTEGER UMaximumSize
,
2816 ULONG SectionPageProtection
,
2817 ULONG AllocationAttributes
)
2819 * Create a section which is backed by the pagefile
2822 LARGE_INTEGER MaximumSize
;
2823 PROS_SECTION_OBJECT Section
;
2824 PMM_SECTION_SEGMENT Segment
;
2827 if (UMaximumSize
== NULL
)
2829 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2830 return(STATUS_INVALID_PARAMETER
);
2832 MaximumSize
= *UMaximumSize
;
2835 * Create the section
2837 Status
= ObCreateObject(ExGetPreviousMode(),
2838 MmSectionObjectType
,
2840 ExGetPreviousMode(),
2842 sizeof(ROS_SECTION_OBJECT
),
2845 (PVOID
*)(PVOID
)&Section
);
2846 if (!NT_SUCCESS(Status
))
2848 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2855 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2856 Section
->Type
= 'SC';
2857 Section
->Size
= 'TN';
2858 Section
->SectionPageProtection
= SectionPageProtection
;
2859 Section
->AllocationAttributes
= AllocationAttributes
;
2860 Section
->MaximumSize
= MaximumSize
;
2861 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2862 TAG_MM_SECTION_SEGMENT
);
2863 if (Segment
== NULL
)
2865 ObDereferenceObject(Section
);
2866 return(STATUS_NO_MEMORY
);
2868 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2869 Section
->Segment
= Segment
;
2870 Segment
->ReferenceCount
= 1;
2871 ExInitializeFastMutex(&Segment
->Lock
);
2872 Segment
->Image
.FileOffset
= 0;
2873 Segment
->Protection
= SectionPageProtection
;
2874 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2875 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2876 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2877 Segment
->WriteCopy
= FALSE
;
2878 Segment
->Image
.VirtualAddress
= 0;
2879 Segment
->Image
.Characteristics
= 0;
2880 *SectionObject
= Section
;
2881 MiInitializeSectionPageTable(Segment
);
2882 return(STATUS_SUCCESS
);
2887 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2888 ACCESS_MASK DesiredAccess
,
2889 POBJECT_ATTRIBUTES ObjectAttributes
,
2890 PLARGE_INTEGER UMaximumSize
,
2891 ULONG SectionPageProtection
,
2892 ULONG AllocationAttributes
,
2893 PFILE_OBJECT FileObject
)
2895 * Create a section backed by a data file
2898 PROS_SECTION_OBJECT Section
;
2900 LARGE_INTEGER MaximumSize
;
2901 PMM_SECTION_SEGMENT Segment
;
2902 FILE_STANDARD_INFORMATION FileInfo
;
2906 * Create the section
2908 Status
= ObCreateObject(ExGetPreviousMode(),
2909 MmSectionObjectType
,
2911 ExGetPreviousMode(),
2913 sizeof(ROS_SECTION_OBJECT
),
2917 if (!NT_SUCCESS(Status
))
2919 ObDereferenceObject(FileObject
);
2925 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2926 Section
->Type
= 'SC';
2927 Section
->Size
= 'TN';
2928 Section
->SectionPageProtection
= SectionPageProtection
;
2929 Section
->AllocationAttributes
= AllocationAttributes
;
2932 * FIXME: This is propably not entirely correct. We can't look into
2933 * the standard FCB header because it might not be initialized yet
2934 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2935 * standard file information is filled on first request).
2937 Status
= IoQueryFileInformation(FileObject
,
2938 FileStandardInformation
,
2939 sizeof(FILE_STANDARD_INFORMATION
),
2942 if (!NT_SUCCESS(Status
))
2944 ObDereferenceObject(Section
);
2945 ObDereferenceObject(FileObject
);
2950 * FIXME: Revise this once a locking order for file size changes is
2953 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2955 MaximumSize
= *UMaximumSize
;
2959 MaximumSize
= FileInfo
.EndOfFile
;
2960 /* Mapping zero-sized files isn't allowed. */
2961 if (MaximumSize
.QuadPart
== 0)
2963 ObDereferenceObject(Section
);
2964 ObDereferenceObject(FileObject
);
2965 return STATUS_MAPPED_FILE_SIZE_ZERO
;
2969 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2971 Status
= IoSetInformation(FileObject
,
2972 FileEndOfFileInformation
,
2973 sizeof(LARGE_INTEGER
),
2975 if (!NT_SUCCESS(Status
))
2977 ObDereferenceObject(Section
);
2978 ObDereferenceObject(FileObject
);
2979 return(STATUS_SECTION_NOT_EXTENDED
);
2983 if (FileObject
->SectionObjectPointer
== NULL
||
2984 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2986 ObDereferenceObject(Section
);
2987 ObDereferenceObject(FileObject
);
2988 return STATUS_INVALID_FILE_FOR_SECTION
;
2994 Status
= MmspWaitForFileLock(FileObject
);
2995 if (Status
!= STATUS_SUCCESS
)
2997 ObDereferenceObject(Section
);
2998 ObDereferenceObject(FileObject
);
3003 * If this file hasn't been mapped as a data file before then allocate a
3004 * section segment to describe the data file mapping
3006 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3008 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3009 TAG_MM_SECTION_SEGMENT
);
3010 if (Segment
== NULL
)
3012 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3013 ObDereferenceObject(Section
);
3014 ObDereferenceObject(FileObject
);
3015 return(STATUS_NO_MEMORY
);
3017 Section
->Segment
= Segment
;
3018 Segment
->ReferenceCount
= 1;
3019 ExInitializeFastMutex(&Segment
->Lock
);
3021 * Set the lock before assigning the segment to the file object
3023 ExAcquireFastMutex(&Segment
->Lock
);
3024 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3026 Segment
->Image
.FileOffset
= 0;
3027 Segment
->Protection
= SectionPageProtection
;
3028 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3029 Segment
->Image
.Characteristics
= 0;
3030 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3031 if (AllocationAttributes
& SEC_RESERVE
)
3033 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3037 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3038 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3040 Segment
->Image
.VirtualAddress
= 0;
3041 Segment
->Locked
= TRUE
;
3042 MiInitializeSectionPageTable(Segment
);
3047 * If the file is already mapped as a data file then we may need
3051 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3053 Section
->Segment
= Segment
;
3054 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3055 MmLockSectionSegment(Segment
);
3057 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3058 !(AllocationAttributes
& SEC_RESERVE
))
3060 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3061 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3064 MmUnlockSectionSegment(Segment
);
3065 Section
->FileObject
= FileObject
;
3066 Section
->MaximumSize
= MaximumSize
;
3068 CcRosReferenceCache(FileObject
);
3070 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3071 *SectionObject
= Section
;
3072 return(STATUS_SUCCESS
);
3076 TODO: not that great (declaring loaders statically, having to declare all of
3077 them, having to keep them extern, etc.), will fix in the future
3079 extern NTSTATUS NTAPI PeFmtCreateSection
3081 IN CONST VOID
* FileHeader
,
3082 IN SIZE_T FileHeaderSize
,
3084 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3086 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3087 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3090 extern NTSTATUS NTAPI ElfFmtCreateSection
3092 IN CONST VOID
* FileHeader
,
3093 IN SIZE_T FileHeaderSize
,
3095 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3097 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3098 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3101 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3112 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3114 SIZE_T SizeOfSegments
;
3115 PMM_SECTION_SEGMENT Segments
;
3117 /* TODO: check for integer overflow */
3118 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3120 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3122 TAG_MM_SECTION_SEGMENT
);
3125 RtlZeroMemory(Segments
, SizeOfSegments
);
3133 ExeFmtpReadFile(IN PVOID File
,
3134 IN PLARGE_INTEGER Offset
,
3137 OUT PVOID
* AllocBase
,
3138 OUT PULONG ReadSize
)
3141 LARGE_INTEGER FileOffset
;
3143 ULONG OffsetAdjustment
;
3147 PFILE_OBJECT FileObject
= File
;
3148 IO_STATUS_BLOCK Iosb
;
3150 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3154 KeBugCheck(MEMORY_MANAGEMENT
);
3157 FileOffset
= *Offset
;
3159 /* Negative/special offset: it cannot be used in this context */
3160 if(FileOffset
.u
.HighPart
< 0)
3162 KeBugCheck(MEMORY_MANAGEMENT
);
3165 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3166 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3167 FileOffset
.u
.LowPart
= AdjustOffset
;
3169 BufferSize
= Length
+ OffsetAdjustment
;
3170 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3172 /* Flush data since we're about to perform a non-cached read */
3173 CcFlushCache(FileObject
->SectionObjectPointer
,
3179 * It's ok to use paged pool, because this is a temporary buffer only used in
3180 * the loading of executables. The assumption is that MmCreateSection is
3181 * always called at low IRQLs and that these buffers don't survive a brief
3182 * initialization phase
3184 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3189 return STATUS_INSUFFICIENT_RESOURCES
;
3194 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3196 UsedSize
= (ULONG
)Iosb
.Information
;
3198 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3200 Status
= STATUS_IN_PAGE_ERROR
;
3201 ASSERT(!NT_SUCCESS(Status
));
3204 if(NT_SUCCESS(Status
))
3206 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3207 *AllocBase
= Buffer
;
3208 *ReadSize
= UsedSize
- OffsetAdjustment
;
3212 ExFreePoolWithTag(Buffer
, 'rXmM');
3219 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3220 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3221 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3226 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3230 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3232 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3233 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3240 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3244 MmspAssertSegmentsSorted(ImageSectionObject
);
3246 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3248 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3252 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3253 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3254 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3262 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3266 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3268 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3269 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3277 MmspCompareSegments(const void * x
,
3280 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3281 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3284 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3285 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3289 * Ensures an image section's segments are sorted in memory
3294 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3297 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3299 MmspAssertSegmentsSorted(ImageSectionObject
);
3303 qsort(ImageSectionObject
->Segments
,
3304 ImageSectionObject
->NrSegments
,
3305 sizeof(ImageSectionObject
->Segments
[0]),
3306 MmspCompareSegments
);
3312 * Ensures an image section's segments don't overlap in memory and don't have
3313 * gaps and don't have a null size. We let them map to overlapping file regions,
3314 * though - that's not necessarily an error
3319 MmspCheckSegmentBounds
3321 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3327 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3329 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3333 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3335 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3337 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3345 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3346 * page could be OK (Windows seems to be OK with them), and larger gaps
3347 * could lead to image sections spanning several discontiguous regions
3348 * (NtMapViewOfSection could then refuse to map them, and they could
3349 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3351 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3352 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3353 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3364 * Merges and pads an image section's segments until they all are page-aligned
3365 * and have a size that is a multiple of the page size
3370 MmspPageAlignSegments
3372 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3378 PMM_SECTION_SEGMENT EffectiveSegment
;
3380 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3382 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3387 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3389 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3392 * The first segment requires special handling
3396 ULONG_PTR VirtualAddress
;
3397 ULONG_PTR VirtualOffset
;
3399 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3401 /* Round down the virtual address to the nearest page */
3402 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3404 /* Round up the virtual size to the nearest page */
3405 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3406 EffectiveSegment
->Image
.VirtualAddress
;
3408 /* Adjust the raw address and size */
3409 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3411 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3417 * Garbage in, garbage out: unaligned base addresses make the file
3418 * offset point in curious and odd places, but that's what we were
3421 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3422 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3426 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3427 ULONG_PTR EndOfEffectiveSegment
;
3429 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3430 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3433 * The current segment begins exactly where the current effective
3434 * segment ended, therefore beginning a new effective segment
3436 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3439 ASSERT(LastSegment
<= i
);
3440 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3442 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3444 if (LastSegment
!= i
)
3447 * Copy the current segment. If necessary, the effective segment
3448 * will be expanded later
3450 *EffectiveSegment
= *Segment
;
3454 * Page-align the virtual size. We know for sure the virtual address
3457 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3458 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3461 * The current segment is still part of the current effective segment:
3462 * extend the effective segment to reflect this
3464 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3466 static const ULONG FlagsToProtection
[16] =
3474 PAGE_EXECUTE_READWRITE
,
3475 PAGE_EXECUTE_READWRITE
,
3480 PAGE_EXECUTE_WRITECOPY
,
3481 PAGE_EXECUTE_WRITECOPY
,
3482 PAGE_EXECUTE_WRITECOPY
,
3483 PAGE_EXECUTE_WRITECOPY
3486 unsigned ProtectionFlags
;
3489 * Extend the file size
3492 /* Unaligned segments must be contiguous within the file */
3493 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3494 EffectiveSegment
->RawLength
.QuadPart
))
3499 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3502 * Extend the virtual size
3504 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3506 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3507 EffectiveSegment
->Image
.VirtualAddress
;
3510 * Merge the protection
3512 EffectiveSegment
->Protection
|= Segment
->Protection
;
3514 /* Clean up redundance */
3515 ProtectionFlags
= 0;
3517 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3518 ProtectionFlags
|= 1 << 0;
3520 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3521 ProtectionFlags
|= 1 << 1;
3523 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3524 ProtectionFlags
|= 1 << 2;
3526 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3527 ProtectionFlags
|= 1 << 3;
3529 ASSERT(ProtectionFlags
< 16);
3530 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3532 /* If a segment was required to be shared and cannot, fail */
3533 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3534 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3540 * We assume no holes between segments at this point
3544 KeBugCheck(MEMORY_MANAGEMENT
);
3548 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3554 ExeFmtpCreateImageSection(PFILE_OBJECT FileObject
,
3555 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3557 LARGE_INTEGER Offset
;
3559 PVOID FileHeaderBuffer
;
3560 ULONG FileHeaderSize
;
3562 ULONG OldNrSegments
;
3567 * Read the beginning of the file (2 pages). Should be enough to contain
3568 * all (or most) of the headers
3570 Offset
.QuadPart
= 0;
3572 Status
= ExeFmtpReadFile (FileObject
,
3579 if (!NT_SUCCESS(Status
))
3582 if (FileHeaderSize
== 0)
3584 ExFreePool(FileHeaderBuffer
);
3585 return STATUS_UNSUCCESSFUL
;
3589 * Look for a loader that can handle this executable
3591 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3593 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3596 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3602 ExeFmtpAllocateSegments
);
3604 if (!NT_SUCCESS(Status
))
3606 if (ImageSectionObject
->Segments
)
3608 ExFreePool(ImageSectionObject
->Segments
);
3609 ImageSectionObject
->Segments
= NULL
;
3613 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3617 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3620 * No loader handled the format
3622 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3624 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3625 ASSERT(!NT_SUCCESS(Status
));
3628 if (!NT_SUCCESS(Status
))
3631 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3636 /* FIXME? are these values platform-dependent? */
3637 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3638 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3640 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3641 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3643 if(ImageSectionObject
->BasedAddress
== NULL
)
3645 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3646 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3648 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3652 * And now the fun part: fixing the segments
3655 /* Sort them by virtual address */
3656 MmspSortSegments(ImageSectionObject
, Flags
);
3658 /* Ensure they don't overlap in memory */
3659 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3660 return STATUS_INVALID_IMAGE_FORMAT
;
3662 /* Ensure they are aligned */
3663 OldNrSegments
= ImageSectionObject
->NrSegments
;
3665 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3666 return STATUS_INVALID_IMAGE_FORMAT
;
3668 /* Trim them if the alignment phase merged some of them */
3669 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3671 PMM_SECTION_SEGMENT Segments
;
3672 SIZE_T SizeOfSegments
;
3674 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3676 Segments
= ExAllocatePoolWithTag(PagedPool
,
3678 TAG_MM_SECTION_SEGMENT
);
3680 if (Segments
== NULL
)
3681 return STATUS_INSUFFICIENT_RESOURCES
;
3683 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3684 ExFreePool(ImageSectionObject
->Segments
);
3685 ImageSectionObject
->Segments
= Segments
;
3688 /* And finish their initialization */
3689 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3691 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3692 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3693 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3696 ASSERT(NT_SUCCESS(Status
));
3701 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3702 ACCESS_MASK DesiredAccess
,
3703 POBJECT_ATTRIBUTES ObjectAttributes
,
3704 PLARGE_INTEGER UMaximumSize
,
3705 ULONG SectionPageProtection
,
3706 ULONG AllocationAttributes
,
3707 PFILE_OBJECT FileObject
)
3709 PROS_SECTION_OBJECT Section
;
3711 PMM_SECTION_SEGMENT SectionSegments
;
3712 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3715 if (FileObject
== NULL
)
3716 return STATUS_INVALID_FILE_FOR_SECTION
;
3719 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3721 DPRINT1("Denying section creation due to missing cache initialization\n");
3722 return STATUS_INVALID_FILE_FOR_SECTION
;
3727 * Create the section
3729 Status
= ObCreateObject (ExGetPreviousMode(),
3730 MmSectionObjectType
,
3732 ExGetPreviousMode(),
3734 sizeof(ROS_SECTION_OBJECT
),
3737 (PVOID
*)(PVOID
)&Section
);
3738 if (!NT_SUCCESS(Status
))
3740 ObDereferenceObject(FileObject
);
3747 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3748 Section
->Type
= 'SC';
3749 Section
->Size
= 'TN';
3750 Section
->SectionPageProtection
= SectionPageProtection
;
3751 Section
->AllocationAttributes
= AllocationAttributes
;
3753 if (FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3755 NTSTATUS StatusExeFmt
;
3757 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3758 if (ImageSectionObject
== NULL
)
3760 ObDereferenceObject(FileObject
);
3761 ObDereferenceObject(Section
);
3762 return(STATUS_NO_MEMORY
);
3765 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3767 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3769 if (!NT_SUCCESS(StatusExeFmt
))
3771 if(ImageSectionObject
->Segments
!= NULL
)
3772 ExFreePool(ImageSectionObject
->Segments
);
3775 * If image file is empty, then return that the file is invalid for section
3777 Status
= StatusExeFmt
;
3778 if (StatusExeFmt
== STATUS_END_OF_FILE
)
3780 Status
= STATUS_INVALID_FILE_FOR_SECTION
;
3783 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3784 ObDereferenceObject(Section
);
3785 ObDereferenceObject(FileObject
);
3789 Section
->ImageSection
= ImageSectionObject
;
3790 ASSERT(ImageSectionObject
->Segments
);
3795 Status
= MmspWaitForFileLock(FileObject
);
3796 if (!NT_SUCCESS(Status
))
3798 ExFreePool(ImageSectionObject
->Segments
);
3799 ExFreePool(ImageSectionObject
);
3800 ObDereferenceObject(Section
);
3801 ObDereferenceObject(FileObject
);
3805 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3806 ImageSectionObject
, NULL
))
3809 * An other thread has initialized the same image in the background
3811 ExFreePool(ImageSectionObject
->Segments
);
3812 ExFreePool(ImageSectionObject
);
3813 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3814 Section
->ImageSection
= ImageSectionObject
;
3815 SectionSegments
= ImageSectionObject
->Segments
;
3817 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3819 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3823 Status
= StatusExeFmt
;
3830 Status
= MmspWaitForFileLock(FileObject
);
3831 if (Status
!= STATUS_SUCCESS
)
3833 ObDereferenceObject(Section
);
3834 ObDereferenceObject(FileObject
);
3838 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3839 Section
->ImageSection
= ImageSectionObject
;
3840 SectionSegments
= ImageSectionObject
->Segments
;
3843 * Otherwise just reference all the section segments
3845 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3847 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3850 Status
= STATUS_SUCCESS
;
3852 Section
->FileObject
= FileObject
;
3854 CcRosReferenceCache(FileObject
);
3856 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3857 *SectionObject
= Section
;
3864 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3865 PROS_SECTION_OBJECT Section
,
3866 PMM_SECTION_SEGMENT Segment
,
3871 ULONG AllocationType
)
3877 if (Segment
->WriteCopy
)
3879 /* We have to do this because the not present fault
3880 * and access fault handlers depend on the protection
3881 * that should be granted AFTER the COW fault takes
3882 * place to be in Region->Protect. The not present fault
3883 * handler changes this to the correct protection for COW when
3884 * mapping the pages into the process's address space. If a COW
3885 * fault takes place, the access fault handler sets the page protection
3886 * to these values for the newly copied pages
3888 if (Protect
== PAGE_WRITECOPY
)
3889 Protect
= PAGE_READWRITE
;
3890 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3891 Protect
= PAGE_EXECUTE_READWRITE
;
3894 if (*BaseAddress
== NULL
)
3895 Granularity
= MM_ALLOCATION_GRANULARITY
;
3897 Granularity
= PAGE_SIZE
;
3900 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3902 LARGE_INTEGER FileOffset
;
3903 FileOffset
.QuadPart
= ViewOffset
;
3904 ObReferenceObject(Section
);
3905 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3908 Status
= MmCreateMemoryArea(AddressSpace
,
3909 MEMORY_AREA_SECTION_VIEW
,
3916 if (!NT_SUCCESS(Status
))
3918 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3919 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3923 ObReferenceObject((PVOID
)Section
);
3925 MArea
->Data
.SectionData
.Segment
= Segment
;
3926 MArea
->Data
.SectionData
.Section
= Section
;
3927 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3928 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3930 MArea
->VadNode
.u
.VadFlags
.VadType
= VadImageMap
;
3933 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3934 ViewSize
, 0, Protect
);
3936 return(STATUS_SUCCESS
);
3941 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3942 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3946 PFILE_OBJECT FileObject
;
3947 PROS_SHARED_CACHE_MAP SharedCacheMap
;
3949 LARGE_INTEGER Offset
;
3950 SWAPENTRY SavedSwapEntry
;
3951 PROS_SECTION_OBJECT Section
;
3952 PMM_SECTION_SEGMENT Segment
;
3953 PMMSUPPORT AddressSpace
;
3956 AddressSpace
= (PMMSUPPORT
)Context
;
3957 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3959 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3961 Offset
.QuadPart
= ((ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)) +
3962 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3964 Section
= MemoryArea
->Data
.SectionData
.Section
;
3965 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3967 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3968 while (Entry
&& MM_IS_WAIT_PTE(Entry
))
3970 MmUnlockSectionSegment(Segment
);
3971 MmUnlockAddressSpace(AddressSpace
);
3973 MiWaitForPageEvent(NULL
, NULL
);
3975 MmLockAddressSpace(AddressSpace
);
3976 MmLockSectionSegment(Segment
);
3977 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3981 * For a dirty, datafile, non-private page mark it as dirty in the
3984 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3986 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3989 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3990 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3991 CcRosMarkDirtyFile(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
3993 ASSERT(SwapEntry
== 0);
4002 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4004 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4005 KeBugCheck(MEMORY_MANAGEMENT
);
4007 MmFreeSwapPage(SwapEntry
);
4011 if (IS_SWAP_FROM_SSE(Entry
) ||
4012 Page
!= PFN_FROM_SSE(Entry
))
4017 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4019 DPRINT1("Found a private page in a pagefile section.\n");
4020 KeBugCheck(MEMORY_MANAGEMENT
);
4023 * Just dereference private pages
4025 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4026 if (SavedSwapEntry
!= 0)
4028 MmFreeSwapPage(SavedSwapEntry
);
4029 MmSetSavedSwapEntryPage(Page
, 0);
4031 MmDeleteRmap(Page
, Process
, Address
);
4032 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4036 MmDeleteRmap(Page
, Process
, Address
);
4037 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4043 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4047 PMEMORY_AREA MemoryArea
;
4048 PROS_SECTION_OBJECT Section
;
4049 PMM_SECTION_SEGMENT Segment
;
4050 PLIST_ENTRY CurrentEntry
;
4051 PMM_REGION CurrentRegion
;
4052 PLIST_ENTRY RegionListHead
;
4054 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4056 if (MemoryArea
== NULL
)
4058 return(STATUS_UNSUCCESSFUL
);
4061 Section
= MemoryArea
->Data
.SectionData
.Section
;
4062 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4065 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4067 MmUnlockAddressSpace(AddressSpace
);
4068 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4069 MmLockAddressSpace(AddressSpace
);
4075 MemoryArea
->DeleteInProgress
= TRUE
;
4077 MmLockSectionSegment(Segment
);
4079 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4080 while (!IsListEmpty(RegionListHead
))
4082 CurrentEntry
= RemoveHeadList(RegionListHead
);
4083 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4084 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4087 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4089 Status
= MmFreeMemoryArea(AddressSpace
,
4096 Status
= MmFreeMemoryArea(AddressSpace
,
4101 MmUnlockSectionSegment(Segment
);
4102 ObDereferenceObject(Section
);
4108 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4109 IN PVOID BaseAddress
,
4110 IN BOOLEAN SkipDebuggerNotify
)
4113 PMEMORY_AREA MemoryArea
;
4114 PMMSUPPORT AddressSpace
;
4115 PROS_SECTION_OBJECT Section
;
4116 PVOID ImageBaseAddress
= 0;
4118 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4119 Process
, BaseAddress
);
4123 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4125 MmLockAddressSpace(AddressSpace
);
4126 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4128 if (MemoryArea
== NULL
||
4129 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4130 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4131 MemoryArea
->DeleteInProgress
)
4133 if (MemoryArea
) ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4134 MmUnlockAddressSpace(AddressSpace
);
4135 return STATUS_NOT_MAPPED_VIEW
;
4138 Section
= MemoryArea
->Data
.SectionData
.Section
;
4140 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4144 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4145 PMM_SECTION_SEGMENT SectionSegments
;
4146 PMM_SECTION_SEGMENT Segment
;
4148 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4149 ImageSectionObject
= Section
->ImageSection
;
4150 SectionSegments
= ImageSectionObject
->Segments
;
4151 NrSegments
= ImageSectionObject
->NrSegments
;
4153 MemoryArea
->DeleteInProgress
= TRUE
;
4155 /* Search for the current segment within the section segments
4156 * and calculate the image base address */
4157 for (i
= 0; i
< NrSegments
; i
++)
4159 if (Segment
== &SectionSegments
[i
])
4161 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4165 if (i
>= NrSegments
)
4167 KeBugCheck(MEMORY_MANAGEMENT
);
4170 for (i
= 0; i
< NrSegments
; i
++)
4172 PVOID SBaseAddress
= (PVOID
)
4173 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4175 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4176 if (!NT_SUCCESS(Status
))
4178 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4179 SBaseAddress
, Process
, Status
);
4180 ASSERT(NT_SUCCESS(Status
));
4186 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4187 if (!NT_SUCCESS(Status
))
4189 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4190 BaseAddress
, Process
, Status
);
4191 ASSERT(NT_SUCCESS(Status
));
4195 MmUnlockAddressSpace(AddressSpace
);
4197 /* Notify debugger */
4198 if (ImageBaseAddress
&& !SkipDebuggerNotify
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4200 return(STATUS_SUCCESS
);
4207 * Queries the information of a section object.
4209 * @param SectionHandle
4210 * Handle to the section object. It must be opened with SECTION_QUERY
4212 * @param SectionInformationClass
4213 * Index to a certain information structure. Can be either
4214 * SectionBasicInformation or SectionImageInformation. The latter
4215 * is valid only for sections that were created with the SEC_IMAGE
4217 * @param SectionInformation
4218 * Caller supplies storage for resulting information.
4220 * Size of the supplied storage.
4221 * @param ResultLength
4231 _In_ HANDLE SectionHandle
,
4232 _In_ SECTION_INFORMATION_CLASS SectionInformationClass
,
4233 _Out_ PVOID SectionInformation
,
4234 _In_ SIZE_T SectionInformationLength
,
4235 _Out_opt_ PSIZE_T ResultLength
)
4238 KPROCESSOR_MODE PreviousMode
;
4242 PreviousMode
= ExGetPreviousMode();
4243 if (PreviousMode
!= KernelMode
)
4247 ProbeForWrite(SectionInformation
,
4248 SectionInformationLength
,
4250 if (ResultLength
!= NULL
)
4252 ProbeForWrite(ResultLength
,
4253 sizeof(*ResultLength
),
4257 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4259 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4264 if (SectionInformationClass
== SectionBasicInformation
)
4266 if (SectionInformationLength
< sizeof(SECTION_BASIC_INFORMATION
))
4268 return STATUS_INFO_LENGTH_MISMATCH
;
4271 else if (SectionInformationClass
== SectionImageInformation
)
4273 if (SectionInformationLength
< sizeof(SECTION_IMAGE_INFORMATION
))
4275 return STATUS_INFO_LENGTH_MISMATCH
;
4280 return STATUS_INVALID_INFO_CLASS
;
4283 Status
= ObReferenceObjectByHandle(SectionHandle
,
4285 MmSectionObjectType
,
4287 (PVOID
*)(PVOID
)&Section
,
4289 if (!NT_SUCCESS(Status
))
4291 DPRINT1("Failed to reference section: 0x%lx\n", Status
);
4295 if (MiIsRosSectionObject(Section
))
4297 PROS_SECTION_OBJECT RosSection
= (PROS_SECTION_OBJECT
)Section
;
4299 switch (SectionInformationClass
)
4301 case SectionBasicInformation
:
4303 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4307 Sbi
->Attributes
= RosSection
->AllocationAttributes
;
4308 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4310 Sbi
->BaseAddress
= 0;
4311 Sbi
->Size
.QuadPart
= 0;
4315 Sbi
->BaseAddress
= (PVOID
)RosSection
->Segment
->Image
.VirtualAddress
;
4316 Sbi
->Size
.QuadPart
= RosSection
->Segment
->Length
.QuadPart
;
4319 if (ResultLength
!= NULL
)
4321 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4323 Status
= STATUS_SUCCESS
;
4325 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4327 Status
= _SEH2_GetExceptionCode();
4334 case SectionImageInformation
:
4336 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4340 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4342 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4343 ImageSectionObject
= RosSection
->ImageSection
;
4345 *Sii
= ImageSectionObject
->ImageInformation
;
4348 if (ResultLength
!= NULL
)
4350 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4352 Status
= STATUS_SUCCESS
;
4354 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4356 Status
= _SEH2_GetExceptionCode();
4366 switch(SectionInformationClass
)
4368 case SectionBasicInformation
:
4370 SECTION_BASIC_INFORMATION Sbi
;
4372 Sbi
.Size
= Section
->SizeOfSection
;
4373 Sbi
.BaseAddress
= (PVOID
)Section
->Address
.StartingVpn
;
4376 if (Section
->u
.Flags
.Image
)
4377 Sbi
.Attributes
|= SEC_IMAGE
;
4378 if (Section
->u
.Flags
.Commit
)
4379 Sbi
.Attributes
|= SEC_COMMIT
;
4380 if (Section
->u
.Flags
.Reserve
)
4381 Sbi
.Attributes
|= SEC_RESERVE
;
4382 if (Section
->u
.Flags
.File
)
4383 Sbi
.Attributes
|= SEC_FILE
;
4384 if (Section
->u
.Flags
.Image
)
4385 Sbi
.Attributes
|= SEC_IMAGE
;
4387 /* FIXME : Complete/test the list of flags passed back from NtCreateSection */
4391 *((SECTION_BASIC_INFORMATION
*)SectionInformation
) = Sbi
;
4393 *ResultLength
= sizeof(Sbi
);
4395 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4397 Status
= _SEH2_GetExceptionCode();
4402 case SectionImageInformation
:
4404 if (!Section
->u
.Flags
.Image
)
4406 Status
= STATUS_SECTION_NOT_IMAGE
;
4410 /* Currently not supported */
4418 ObDereferenceObject(Section
);
4423 /**********************************************************************
4425 * MmMapViewOfSection
4428 * Maps a view of a section into the virtual address space of a
4433 * Pointer to the section object.
4436 * Pointer to the process.
4439 * Desired base address (or NULL) on entry;
4440 * Actual base address of the view on exit.
4443 * Number of high order address bits that must be zero.
4446 * Size in bytes of the initially committed section of
4450 * Offset in bytes from the beginning of the section
4451 * to the beginning of the view.
4454 * Desired length of map (or zero to map all) on entry
4455 * Actual length mapped on exit.
4457 * InheritDisposition
4458 * Specified how the view is to be shared with
4462 * Type of allocation for the pages.
4465 * Protection for the committed region of the view.
4473 MmMapViewOfSection(IN PVOID SectionObject
,
4474 IN PEPROCESS Process
,
4475 IN OUT PVOID
*BaseAddress
,
4476 IN ULONG_PTR ZeroBits
,
4477 IN SIZE_T CommitSize
,
4478 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4479 IN OUT PSIZE_T ViewSize
,
4480 IN SECTION_INHERIT InheritDisposition
,
4481 IN ULONG AllocationType
,
4484 PROS_SECTION_OBJECT Section
;
4485 PMMSUPPORT AddressSpace
;
4487 NTSTATUS Status
= STATUS_SUCCESS
;
4488 BOOLEAN NotAtBase
= FALSE
;
4490 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4492 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4493 return MmMapViewOfArm3Section(SectionObject
,
4507 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4509 return STATUS_INVALID_PAGE_PROTECTION
;
4512 /* FIXME: We should keep this, but it would break code checking equality */
4513 Protect
&= ~PAGE_NOCACHE
;
4515 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4516 AddressSpace
= &Process
->Vm
;
4518 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4520 MmLockAddressSpace(AddressSpace
);
4522 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4526 ULONG_PTR ImageBase
;
4528 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4529 PMM_SECTION_SEGMENT SectionSegments
;
4531 ImageSectionObject
= Section
->ImageSection
;
4532 SectionSegments
= ImageSectionObject
->Segments
;
4533 NrSegments
= ImageSectionObject
->NrSegments
;
4535 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4538 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4542 for (i
= 0; i
< NrSegments
; i
++)
4544 ULONG_PTR MaxExtent
;
4545 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4546 SectionSegments
[i
].Length
.QuadPart
);
4547 ImageSize
= max(ImageSize
, MaxExtent
);
4550 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4552 /* Check for an illegal base address */
4553 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4554 ((ImageBase
+ ImageSize
) < ImageSize
))
4556 ASSERT(*BaseAddress
== NULL
);
4557 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4558 MM_VIRTMEM_GRANULARITY
);
4561 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4563 ASSERT(*BaseAddress
== NULL
);
4564 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4568 /* Check there is enough space to map the section at that point. */
4569 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4570 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4572 /* Fail if the user requested a fixed base address. */
4573 if ((*BaseAddress
) != NULL
)
4575 MmUnlockAddressSpace(AddressSpace
);
4576 return(STATUS_CONFLICTING_ADDRESSES
);
4578 /* Otherwise find a gap to map the image. */
4579 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4582 MmUnlockAddressSpace(AddressSpace
);
4583 return(STATUS_CONFLICTING_ADDRESSES
);
4585 /* Remember that we loaded image at a different base address */
4589 for (i
= 0; i
< NrSegments
; i
++)
4591 PVOID SBaseAddress
= (PVOID
)
4592 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4593 MmLockSectionSegment(&SectionSegments
[i
]);
4594 Status
= MmMapViewOfSegment(AddressSpace
,
4596 &SectionSegments
[i
],
4598 SectionSegments
[i
].Length
.LowPart
,
4599 SectionSegments
[i
].Protection
,
4602 MmUnlockSectionSegment(&SectionSegments
[i
]);
4603 if (!NT_SUCCESS(Status
))
4605 MmUnlockAddressSpace(AddressSpace
);
4610 *BaseAddress
= (PVOID
)ImageBase
;
4611 *ViewSize
= ImageSize
;
4615 /* check for write access */
4616 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4617 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4619 MmUnlockAddressSpace(AddressSpace
);
4620 return STATUS_SECTION_PROTECTION
;
4622 /* check for read access */
4623 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4624 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4626 MmUnlockAddressSpace(AddressSpace
);
4627 return STATUS_SECTION_PROTECTION
;
4629 /* check for execute access */
4630 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4631 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4633 MmUnlockAddressSpace(AddressSpace
);
4634 return STATUS_SECTION_PROTECTION
;
4637 if (SectionOffset
== NULL
)
4643 ViewOffset
= SectionOffset
->u
.LowPart
;
4646 if ((ViewOffset
% PAGE_SIZE
) != 0)
4648 MmUnlockAddressSpace(AddressSpace
);
4649 return(STATUS_MAPPED_ALIGNMENT
);
4652 if ((*ViewSize
) == 0)
4654 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4656 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4658 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4661 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4663 MmLockSectionSegment(Section
->Segment
);
4664 Status
= MmMapViewOfSegment(AddressSpace
,
4671 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4672 MmUnlockSectionSegment(Section
->Segment
);
4673 if (!NT_SUCCESS(Status
))
4675 MmUnlockAddressSpace(AddressSpace
);
4680 MmUnlockAddressSpace(AddressSpace
);
4681 ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4684 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4686 Status
= STATUS_SUCCESS
;
4695 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4696 IN PLARGE_INTEGER NewFileSize
)
4698 /* Check whether an ImageSectionObject exists */
4699 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4701 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4705 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4707 PMM_SECTION_SEGMENT Segment
;
4709 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4712 if (Segment
->ReferenceCount
!= 0)
4715 CC_FILE_SIZES FileSizes
;
4717 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4720 /* Check size of file */
4721 if (SectionObjectPointer
->SharedCacheMap
)
4723 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4728 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4737 /* Check size of file */
4738 if (SectionObjectPointer
->SharedCacheMap
)
4740 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4741 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4750 /* Something must gone wrong
4751 * how can we have a Section but no
4753 DPRINT("ERROR: DataSectionObject without reference!\n");
4757 DPRINT("FIXME: didn't check for outstanding write probes\n");
4769 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4770 IN MMFLUSH_TYPE FlushType
)
4772 BOOLEAN Result
= TRUE
;
4774 PMM_SECTION_SEGMENT Segment
;
4779 case MmFlushForDelete
:
4780 if (SectionObjectPointer
->ImageSectionObject
||
4781 SectionObjectPointer
->DataSectionObject
)
4786 CcRosRemoveIfClosed(SectionObjectPointer
);
4789 case MmFlushForWrite
:
4791 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4793 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4796 if (SectionObjectPointer
->ImageSectionObject
)
4798 DPRINT1("SectionObject has ImageSection\n");
4804 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4806 DPRINT("Result %d\n", Result
);
4818 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4819 OUT PVOID
* MappedBase
,
4820 IN OUT PSIZE_T ViewSize
)
4822 PROS_SECTION_OBJECT Section
;
4823 PMMSUPPORT AddressSpace
;
4827 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4829 return MiMapViewInSystemSpace(SectionObject
,
4835 DPRINT("MmMapViewInSystemSpace() called\n");
4837 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4838 AddressSpace
= MmGetKernelAddressSpace();
4840 MmLockAddressSpace(AddressSpace
);
4843 if ((*ViewSize
) == 0)
4845 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4847 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4849 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4852 MmLockSectionSegment(Section
->Segment
);
4855 Status
= MmMapViewOfSegment(AddressSpace
,
4864 MmUnlockSectionSegment(Section
->Segment
);
4865 MmUnlockAddressSpace(AddressSpace
);
4872 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4874 PMMSUPPORT AddressSpace
;
4877 DPRINT("MmUnmapViewInSystemSpace() called\n");
4879 AddressSpace
= MmGetKernelAddressSpace();
4881 MmLockAddressSpace(AddressSpace
);
4883 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4885 MmUnlockAddressSpace(AddressSpace
);
4890 /**********************************************************************
4895 * Creates a section object.
4898 * SectionObject (OUT)
4899 * Caller supplied storage for the resulting pointer
4900 * to a SECTION_OBJECT instance;
4903 * Specifies the desired access to the section can be a
4905 * STANDARD_RIGHTS_REQUIRED |
4907 * SECTION_MAP_WRITE |
4908 * SECTION_MAP_READ |
4909 * SECTION_MAP_EXECUTE
4911 * ObjectAttributes [OPTIONAL]
4912 * Initialized attributes for the object can be used
4913 * to create a named section;
4916 * Maximizes the size of the memory section. Must be
4917 * non-NULL for a page-file backed section.
4918 * If value specified for a mapped file and the file is
4919 * not large enough, file will be extended.
4921 * SectionPageProtection
4922 * Can be a combination of:
4928 * AllocationAttributes
4929 * Can be a combination of:
4934 * Handle to a file to create a section mapped to a file
4935 * instead of a memory backed section;
4946 MmCreateSection (OUT PVOID
* Section
,
4947 IN ACCESS_MASK DesiredAccess
,
4948 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4949 IN PLARGE_INTEGER MaximumSize
,
4950 IN ULONG SectionPageProtection
,
4951 IN ULONG AllocationAttributes
,
4952 IN HANDLE FileHandle OPTIONAL
,
4953 IN PFILE_OBJECT FileObject OPTIONAL
)
4957 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4959 /* Check if an ARM3 section is being created instead */
4960 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4962 if (!(FileObject
) && !(FileHandle
))
4964 return MmCreateArm3Section(Section
,
4968 SectionPageProtection
,
4969 AllocationAttributes
&~ 1,
4975 /* Convert section flag to page flag */
4976 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4978 /* Check to make sure the protection is correct. Nt* does this already */
4979 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4980 if (Protection
== MM_INVALID_PROTECTION
)
4982 DPRINT1("Page protection is invalid\n");
4983 return STATUS_INVALID_PAGE_PROTECTION
;
4986 /* Check if this is going to be a data or image backed file section */
4987 if ((FileHandle
) || (FileObject
))
4989 /* These cannot be mapped with large pages */
4990 if (AllocationAttributes
& SEC_LARGE_PAGES
)
4992 DPRINT1("Large pages cannot be used with an image mapping\n");
4993 return STATUS_INVALID_PARAMETER_6
;
4996 /* Did the caller pass an object? */
4999 /* Reference the object directly */
5000 ObReferenceObject(FileObject
);
5004 /* Reference the file handle to get the object */
5005 Status
= ObReferenceObjectByHandle(FileHandle
,
5006 MmMakeFileAccess
[Protection
],
5008 ExGetPreviousMode(),
5009 (PVOID
*)&FileObject
,
5011 if (!NT_SUCCESS(Status
))
5013 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
5020 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
5021 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
5024 #ifndef NEWCC // A hack for initializing caching.
5025 // This is needed only in the old case.
5028 IO_STATUS_BLOCK Iosb
;
5031 LARGE_INTEGER ByteOffset
;
5032 ByteOffset
.QuadPart
= 0;
5033 Status
= ZwReadFile(FileHandle
,
5042 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5044 DPRINT1("CC failure: %lx\n", Status
);
5046 ObDereferenceObject(FileObject
);
5049 // Caching is initialized...
5051 // Hack of the hack: actually, it might not be initialized if FSD init on effective right and if file is null-size
5052 // In such case, force cache by initiating a write IRP
5053 if (Status
== STATUS_END_OF_FILE
&& !(AllocationAttributes
& SEC_IMAGE
) && FileObject
!= NULL
&&
5054 (FileObject
->SectionObjectPointer
== NULL
|| FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
))
5057 Status
= ZwWriteFile(FileHandle
,
5066 if (NT_SUCCESS(Status
))
5069 Zero
.QuadPart
= 0LL;
5071 Status
= IoSetInformation(FileObject
,
5072 FileEndOfFileInformation
,
5073 sizeof(LARGE_INTEGER
),
5075 ASSERT(NT_SUCCESS(Status
));
5081 if (AllocationAttributes
& SEC_IMAGE
)
5083 Status
= MmCreateImageSection(SectionObject
,
5087 SectionPageProtection
,
5088 AllocationAttributes
,
5092 else if (FileHandle
!= NULL
)
5094 Status
= MmCreateDataFileSection(SectionObject
,
5098 SectionPageProtection
,
5099 AllocationAttributes
,
5103 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5105 Status
= MmCreateCacheSection(SectionObject
,
5109 SectionPageProtection
,
5110 AllocationAttributes
,
5116 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5118 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5120 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5121 Status
= MmCreatePageFileSection(SectionObject
,
5125 SectionPageProtection
,
5126 AllocationAttributes
);
5128 ObDereferenceObject(FileObject
);