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];
1279 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
1287 PMEMORY_AREA MemoryArea
;
1288 PMM_SECTION_SEGMENT Segment
;
1289 BOOLEAN DoCOW
= FALSE
;
1291 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1293 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1294 ASSERT(MemoryArea
!= NULL
);
1295 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1296 MmLockSectionSegment(Segment
);
1298 if ((Segment
->WriteCopy
) &&
1299 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1304 if (OldProtect
!= NewProtect
)
1306 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1308 SWAPENTRY SwapEntry
;
1309 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1310 ULONG Protect
= NewProtect
;
1312 /* Wait for a wait entry to disappear */
1315 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1316 if (SwapEntry
!= MM_WAIT_ENTRY
)
1318 MiWaitForPageEvent(Process
, Address
);
1323 * If we doing COW for this segment then check if the page is
1326 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
1328 LARGE_INTEGER Offset
;
1332 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
1333 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1334 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1336 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
1337 * IS_SWAP_FROM_SSE and we'll do the right thing.
1339 Page
= MmGetPfnForProcess(Process
, Address
);
1341 Protect
= PAGE_READONLY
;
1342 if (IS_SWAP_FROM_SSE(Entry
) || PFN_FROM_SSE(Entry
) != Page
)
1344 Protect
= NewProtect
;
1348 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
1350 MmSetPageProtect(Process
, Address
,
1356 MmUnlockSectionSegment(Segment
);
1361 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1362 MEMORY_AREA
* MemoryArea
,
1366 LARGE_INTEGER Offset
;
1369 PROS_SECTION_OBJECT Section
;
1370 PMM_SECTION_SEGMENT Segment
;
1375 BOOLEAN HasSwapEntry
;
1377 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1378 SWAPENTRY SwapEntry
;
1381 * There is a window between taking the page fault and locking the
1382 * address space when another thread could load the page so we check
1385 if (MmIsPagePresent(Process
, Address
))
1387 return(STATUS_SUCCESS
);
1390 if (MmIsDisabledPage(Process
, Address
))
1392 return(STATUS_ACCESS_VIOLATION
);
1396 * Check for the virtual memory area being deleted.
1398 if (MemoryArea
->DeleteInProgress
)
1400 return(STATUS_UNSUCCESSFUL
);
1403 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1404 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1405 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1407 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1408 Section
= MemoryArea
->Data
.SectionData
.Section
;
1409 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1410 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1412 ASSERT(Region
!= NULL
);
1416 MmLockSectionSegment(Segment
);
1417 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1419 * Check if this page needs to be mapped COW
1421 if ((Segment
->WriteCopy
) &&
1422 (Region
->Protect
== PAGE_READWRITE
||
1423 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1425 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1429 Attributes
= Region
->Protect
;
1433 * Check if someone else is already handling this fault, if so wait
1436 if (Entry
&& MM_IS_WAIT_PTE(Entry
))
1438 MmUnlockSectionSegment(Segment
);
1439 MmUnlockAddressSpace(AddressSpace
);
1440 MiWaitForPageEvent(NULL
, NULL
);
1441 MmLockAddressSpace(AddressSpace
);
1442 DPRINT("Address 0x%p\n", Address
);
1443 return(STATUS_MM_RESTART_OPERATION
);
1446 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1448 /* See if we should use a private page */
1451 SWAPENTRY DummyEntry
;
1454 * Is it a wait entry?
1458 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1460 if (SwapEntry
== MM_WAIT_ENTRY
)
1462 MmUnlockSectionSegment(Segment
);
1463 MmUnlockAddressSpace(AddressSpace
);
1464 MiWaitForPageEvent(NULL
, NULL
);
1465 MmLockAddressSpace(AddressSpace
);
1466 return STATUS_MM_RESTART_OPERATION
;
1470 * Must be private page we have swapped out.
1476 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1478 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1479 KeBugCheck(MEMORY_MANAGEMENT
);
1481 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1484 MmUnlockSectionSegment(Segment
);
1486 /* Tell everyone else we are serving the fault. */
1487 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1489 MmUnlockAddressSpace(AddressSpace
);
1490 MI_SET_USAGE(MI_USAGE_SECTION
);
1491 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1492 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1493 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1494 if (!NT_SUCCESS(Status
))
1496 KeBugCheck(MEMORY_MANAGEMENT
);
1501 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1502 if (!NT_SUCCESS(Status
))
1504 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1505 KeBugCheck(MEMORY_MANAGEMENT
);
1509 MmLockAddressSpace(AddressSpace
);
1510 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1511 Status
= MmCreateVirtualMapping(Process
,
1516 if (!NT_SUCCESS(Status
))
1518 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1519 KeBugCheck(MEMORY_MANAGEMENT
);
1524 * Store the swap entry for later use.
1527 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1530 * Add the page to the process's working set
1532 MmInsertRmap(Page
, Process
, Address
);
1534 * Finish the operation
1536 MiSetPageEvent(Process
, Address
);
1537 DPRINT("Address 0x%p\n", Address
);
1538 return(STATUS_SUCCESS
);
1542 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1544 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1546 MmUnlockSectionSegment(Segment
);
1548 * Just map the desired physical page
1550 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1551 Status
= MmCreateVirtualMappingUnsafe(Process
,
1556 if (!NT_SUCCESS(Status
))
1558 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1559 KeBugCheck(MEMORY_MANAGEMENT
);
1564 * Cleanup and release locks
1566 MiSetPageEvent(Process
, Address
);
1567 DPRINT("Address 0x%p\n", Address
);
1568 return(STATUS_SUCCESS
);
1572 * Get the entry corresponding to the offset within the section
1574 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1578 SWAPENTRY FakeSwapEntry
;
1581 * If the entry is zero (and it can't change because we have
1582 * locked the segment) then we need to load the page.
1586 * Release all our locks and read in the page from disk
1588 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1589 MmUnlockSectionSegment(Segment
);
1590 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1591 MmUnlockAddressSpace(AddressSpace
);
1593 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1594 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1595 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1597 MI_SET_USAGE(MI_USAGE_SECTION
);
1598 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1599 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1600 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1601 if (!NT_SUCCESS(Status
))
1603 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1609 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1610 if (!NT_SUCCESS(Status
))
1612 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1615 if (!NT_SUCCESS(Status
))
1618 * FIXME: What do we know in this case?
1621 * Cleanup and release locks
1623 MmLockAddressSpace(AddressSpace
);
1624 MiSetPageEvent(Process
, Address
);
1625 DPRINT("Address 0x%p\n", Address
);
1629 /* Lock both segment and process address space while we proceed. */
1630 MmLockAddressSpace(AddressSpace
);
1631 MmLockSectionSegment(Segment
);
1633 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1634 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1635 Page
, Process
, PAddress
, Attributes
);
1636 Status
= MmCreateVirtualMapping(Process
,
1641 if (!NT_SUCCESS(Status
))
1643 DPRINT1("Unable to create virtual mapping\n");
1644 KeBugCheck(MEMORY_MANAGEMENT
);
1646 ASSERT(MmIsPagePresent(Process
, PAddress
));
1647 MmInsertRmap(Page
, Process
, Address
);
1649 /* Set this section offset has being backed by our new page. */
1650 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1651 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1652 MmUnlockSectionSegment(Segment
);
1654 MiSetPageEvent(Process
, Address
);
1655 DPRINT("Address 0x%p\n", Address
);
1656 return(STATUS_SUCCESS
);
1658 else if (IS_SWAP_FROM_SSE(Entry
))
1660 SWAPENTRY SwapEntry
;
1662 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1664 /* See if a page op is running on this segment. */
1665 if (SwapEntry
== MM_WAIT_ENTRY
)
1667 MmUnlockSectionSegment(Segment
);
1668 MmUnlockAddressSpace(AddressSpace
);
1669 MiWaitForPageEvent(NULL
, NULL
);
1670 MmLockAddressSpace(AddressSpace
);
1671 return STATUS_MM_RESTART_OPERATION
;
1675 * Release all our locks and read in the page from disk
1677 MmUnlockSectionSegment(Segment
);
1679 MmUnlockAddressSpace(AddressSpace
);
1680 MI_SET_USAGE(MI_USAGE_SECTION
);
1681 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1682 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1683 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1684 if (!NT_SUCCESS(Status
))
1686 KeBugCheck(MEMORY_MANAGEMENT
);
1689 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1690 if (!NT_SUCCESS(Status
))
1692 KeBugCheck(MEMORY_MANAGEMENT
);
1696 * Relock the address space and segment
1698 MmLockAddressSpace(AddressSpace
);
1699 MmLockSectionSegment(Segment
);
1702 * Check the entry. No one should change the status of a page
1703 * that has a pending page-in.
1705 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1706 if (Entry
!= Entry1
)
1708 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1709 KeBugCheck(MEMORY_MANAGEMENT
);
1713 * Save the swap entry.
1715 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1717 /* Map the page into the process address space */
1718 Status
= MmCreateVirtualMapping(Process
,
1723 if (!NT_SUCCESS(Status
))
1725 DPRINT1("Unable to create virtual mapping\n");
1726 KeBugCheck(MEMORY_MANAGEMENT
);
1728 MmInsertRmap(Page
, Process
, Address
);
1731 * Mark the offset within the section as having valid, in-memory
1734 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1735 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1736 MmUnlockSectionSegment(Segment
);
1738 MiSetPageEvent(Process
, Address
);
1739 DPRINT("Address 0x%p\n", Address
);
1740 return(STATUS_SUCCESS
);
1744 /* We already have a page on this section offset. Map it into the process address space. */
1745 Page
= PFN_FROM_SSE(Entry
);
1747 Status
= MmCreateVirtualMapping(Process
,
1752 if (!NT_SUCCESS(Status
))
1754 DPRINT1("Unable to create virtual mapping\n");
1755 KeBugCheck(MEMORY_MANAGEMENT
);
1757 MmInsertRmap(Page
, Process
, Address
);
1759 /* Take a reference on it */
1760 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1761 MmUnlockSectionSegment(Segment
);
1763 MiSetPageEvent(Process
, Address
);
1764 DPRINT("Address 0x%p\n", Address
);
1765 return(STATUS_SUCCESS
);
1771 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1772 MEMORY_AREA
* MemoryArea
,
1775 PMM_SECTION_SEGMENT Segment
;
1776 PROS_SECTION_OBJECT Section
;
1781 LARGE_INTEGER Offset
;
1784 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1786 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1788 /* Make sure we have a page mapping for this address. */
1789 Status
= MmNotPresentFaultSectionView(AddressSpace
, MemoryArea
, Address
, TRUE
);
1790 if (!NT_SUCCESS(Status
))
1792 /* This is invalid access ! */
1797 * Check if the page has already been set readwrite
1799 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1801 DPRINT("Address 0x%p\n", Address
);
1802 return(STATUS_SUCCESS
);
1806 * Find the offset of the page
1808 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1809 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1810 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1812 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1813 Section
= MemoryArea
->Data
.SectionData
.Section
;
1814 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1815 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1817 ASSERT(Region
!= NULL
);
1820 * Check if we are doing COW
1822 if (!((Segment
->WriteCopy
) &&
1823 (Region
->Protect
== PAGE_READWRITE
||
1824 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1826 DPRINT("Address 0x%p\n", Address
);
1827 return(STATUS_ACCESS_VIOLATION
);
1830 /* Get the page mapping this section offset. */
1831 MmLockSectionSegment(Segment
);
1832 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1834 /* Get the current page mapping for the process */
1835 ASSERT(MmIsPagePresent(Process
, PAddress
));
1836 OldPage
= MmGetPfnForProcess(Process
, PAddress
);
1837 ASSERT(OldPage
!= 0);
1839 if (IS_SWAP_FROM_SSE(Entry
) ||
1840 PFN_FROM_SSE(Entry
) != OldPage
)
1842 MmUnlockSectionSegment(Segment
);
1843 /* This is a private page. We must only change the page protection. */
1844 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1845 return(STATUS_SUCCESS
);
1851 MI_SET_USAGE(MI_USAGE_SECTION
);
1852 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1853 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1854 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1855 if (!NT_SUCCESS(Status
))
1857 KeBugCheck(MEMORY_MANAGEMENT
);
1863 NT_VERIFY(NT_SUCCESS(MiCopyFromUserPage(NewPage
, PAddress
)));
1866 * Unshare the old page.
1868 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1869 MmDeleteVirtualMapping(Process
, PAddress
, NULL
, NULL
);
1870 MmDeleteRmap(OldPage
, Process
, PAddress
);
1871 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1872 MmUnlockSectionSegment(Segment
);
1875 * Set the PTE to point to the new page
1877 Status
= MmCreateVirtualMapping(Process
,
1882 if (!NT_SUCCESS(Status
))
1884 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1885 KeBugCheck(MEMORY_MANAGEMENT
);
1888 MmInsertRmap(NewPage
, Process
, PAddress
);
1890 MiSetPageEvent(Process
, Address
);
1891 DPRINT("Address 0x%p\n", Address
);
1892 return(STATUS_SUCCESS
);
1896 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1898 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1900 PFN_NUMBER Page
= 0;
1902 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1905 MmLockAddressSpace(&Process
->Vm
);
1908 MmDeleteVirtualMapping(Process
,
1914 PageOutContext
->WasDirty
= TRUE
;
1916 if (!PageOutContext
->Private
)
1918 MmLockSectionSegment(PageOutContext
->Segment
);
1919 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1920 PageOutContext
->Segment
,
1921 &PageOutContext
->Offset
,
1922 PageOutContext
->WasDirty
,
1924 &PageOutContext
->SectionEntry
);
1925 MmUnlockSectionSegment(PageOutContext
->Segment
);
1929 MmUnlockAddressSpace(&Process
->Vm
);
1932 if (PageOutContext
->Private
)
1934 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1940 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1941 MEMORY_AREA
* MemoryArea
,
1942 PVOID Address
, ULONG_PTR Entry
)
1945 MM_SECTION_PAGEOUT_CONTEXT Context
;
1946 SWAPENTRY SwapEntry
;
1949 ULONGLONG FileOffset
;
1950 PFILE_OBJECT FileObject
;
1951 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1952 BOOLEAN IsImageSection
;
1954 BOOLEAN DirectMapped
;
1955 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1958 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1961 * Get the segment and section.
1963 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1964 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1965 Context
.SectionEntry
= Entry
;
1966 Context
.CallingProcess
= Process
;
1968 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
1969 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1971 DirectMapped
= FALSE
;
1973 MmLockSectionSegment(Context
.Segment
);
1976 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1977 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1978 FileObject
= Context
.Section
->FileObject
;
1980 if (FileObject
!= NULL
&&
1981 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1983 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1986 * If the file system is letting us go directly to the cache and the
1987 * memory area was mapped at an offset in the file which is page aligned
1988 * then note this is a direct mapped page.
1990 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1991 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1993 DirectMapped
= TRUE
;
2000 * This should never happen since mappings of physical memory are never
2001 * placed in the rmap lists.
2003 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2005 DPRINT1("Trying to page out from physical memory section address 0x%p "
2006 "process %p\n", Address
,
2007 Process
? Process
->UniqueProcessId
: 0);
2008 KeBugCheck(MEMORY_MANAGEMENT
);
2012 * Get the section segment entry and the physical address.
2014 if (!MmIsPagePresent(Process
, Address
))
2016 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2017 Process
? Process
->UniqueProcessId
: 0, Address
);
2018 KeBugCheck(MEMORY_MANAGEMENT
);
2020 Page
= MmGetPfnForProcess(Process
, Address
);
2021 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2024 * Check the reference count to ensure this page can be paged out
2026 if (MmGetReferenceCountPage(Page
) != 1)
2028 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
2029 Page
, MmGetReferenceCountPage(Page
));
2030 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2031 MmUnlockSectionSegment(Context
.Segment
);
2032 return STATUS_UNSUCCESSFUL
;
2036 * Prepare the context structure for the rmap delete call.
2038 MmUnlockSectionSegment(Context
.Segment
);
2039 Context
.WasDirty
= FALSE
;
2040 if (IS_SWAP_FROM_SSE(Entry
) || PFN_FROM_SSE(Entry
) != Page
)
2042 Context
.Private
= TRUE
;
2046 Context
.Private
= FALSE
;
2050 * Take an additional reference to the page or the VACB.
2052 if (DirectMapped
&& !Context
.Private
)
2054 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
2056 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2057 KeBugCheck(MEMORY_MANAGEMENT
);
2062 OldIrql
= MiAcquirePfnLock();
2063 MmReferencePage(Page
);
2064 MiReleasePfnLock(OldIrql
);
2067 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2069 /* Since we passed in a surrogate, we'll get back the page entry
2070 * state in our context. This is intended to make intermediate
2071 * decrements of share count not release the wait entry.
2073 Entry
= Context
.SectionEntry
;
2076 * If this wasn't a private page then we should have reduced the entry to
2077 * zero by deleting all the rmaps.
2079 if (!Context
.Private
&& Entry
!= 0)
2081 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2082 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2084 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2089 * If the page wasn't dirty then we can just free it as for a readonly page.
2090 * Since we unmapped all the mappings above we know it will not suddenly
2092 * If the page is from a pagefile section and has no swap entry,
2093 * we can't free the page at this point.
2095 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2096 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2098 if (Context
.Private
)
2100 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2101 Context
.WasDirty
? "dirty" : "clean", Address
);
2102 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2104 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2106 MmSetSavedSwapEntryPage(Page
, 0);
2107 MmLockSectionSegment(Context
.Segment
);
2108 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2109 MmUnlockSectionSegment(Context
.Segment
);
2110 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2111 MiSetPageEvent(NULL
, NULL
);
2112 return(STATUS_SUCCESS
);
2115 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2117 if (Context
.Private
)
2119 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2120 Context
.WasDirty
? "dirty" : "clean", Address
);
2121 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2123 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2125 MmSetSavedSwapEntryPage(Page
, 0);
2128 MmLockSectionSegment(Context
.Segment
);
2129 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2130 MmUnlockSectionSegment(Context
.Segment
);
2132 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2133 MiSetPageEvent(NULL
, NULL
);
2134 return(STATUS_SUCCESS
);
2137 else if (!Context
.Private
&& DirectMapped
)
2141 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2143 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2146 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
, FALSE
);
2148 Status
= STATUS_SUCCESS
;
2151 if (!NT_SUCCESS(Status
))
2153 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2154 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2157 MiSetPageEvent(NULL
, NULL
);
2158 return(STATUS_SUCCESS
);
2160 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2164 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2166 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2168 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2169 MiSetPageEvent(NULL
, NULL
);
2170 return(STATUS_SUCCESS
);
2172 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2174 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2175 MmSetSavedSwapEntryPage(Page
, 0);
2176 MmLockAddressSpace(AddressSpace
);
2177 Status
= MmCreatePageFileMapping(Process
,
2180 MmUnlockAddressSpace(AddressSpace
);
2181 if (!NT_SUCCESS(Status
))
2183 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2184 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2186 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2187 MiSetPageEvent(NULL
, NULL
);
2188 return(STATUS_SUCCESS
);
2192 * If necessary, allocate an entry in the paging file for this page
2196 SwapEntry
= MmAllocSwapPage();
2199 MmShowOutOfSpaceMessagePagingFile();
2200 MmLockAddressSpace(AddressSpace
);
2202 * For private pages restore the old mappings.
2204 if (Context
.Private
)
2206 Status
= MmCreateVirtualMapping(Process
,
2208 MemoryArea
->Protect
,
2211 MmSetDirtyPage(Process
, Address
);
2220 MmLockSectionSegment(Context
.Segment
);
2223 * For non-private pages if the page wasn't direct mapped then
2224 * set it back into the section segment entry so we don't loose
2225 * our copy. Otherwise it will be handled by the cache manager.
2227 Status
= MmCreateVirtualMapping(Process
,
2229 MemoryArea
->Protect
,
2232 MmSetDirtyPage(Process
, Address
);
2236 // If we got here, the previous entry should have been a wait
2237 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2238 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2239 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2240 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2241 MmUnlockSectionSegment(Context
.Segment
);
2243 MmUnlockAddressSpace(AddressSpace
);
2244 MiSetPageEvent(NULL
, NULL
);
2245 return(STATUS_PAGEFILE_QUOTA
);
2250 * Write the page to the pagefile
2252 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2253 if (!NT_SUCCESS(Status
))
2255 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2258 * As above: undo our actions.
2259 * FIXME: Also free the swap page.
2261 MmLockAddressSpace(AddressSpace
);
2262 if (Context
.Private
)
2264 Status
= MmCreateVirtualMapping(Process
,
2266 MemoryArea
->Protect
,
2269 MmSetDirtyPage(Process
, Address
);
2276 MmLockSectionSegment(Context
.Segment
);
2277 Status
= MmCreateVirtualMapping(Process
,
2279 MemoryArea
->Protect
,
2282 MmSetDirtyPage(Process
, Address
);
2286 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2287 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2288 MmUnlockSectionSegment(Context
.Segment
);
2290 MmUnlockAddressSpace(AddressSpace
);
2291 MiSetPageEvent(NULL
, NULL
);
2292 return(STATUS_UNSUCCESSFUL
);
2296 * Otherwise we have succeeded.
2298 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2299 MmSetSavedSwapEntryPage(Page
, 0);
2300 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2301 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2303 MmLockSectionSegment(Context
.Segment
);
2304 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2305 MmUnlockSectionSegment(Context
.Segment
);
2309 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2312 if (Context
.Private
)
2314 MmLockAddressSpace(AddressSpace
);
2315 MmLockSectionSegment(Context
.Segment
);
2316 Status
= MmCreatePageFileMapping(Process
,
2319 /* We had placed a wait entry upon entry ... replace it before leaving */
2320 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2321 MmUnlockSectionSegment(Context
.Segment
);
2322 MmUnlockAddressSpace(AddressSpace
);
2323 if (!NT_SUCCESS(Status
))
2325 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2326 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2331 MmLockAddressSpace(AddressSpace
);
2332 MmLockSectionSegment(Context
.Segment
);
2333 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2334 /* We had placed a wait entry upon entry ... replace it before leaving */
2335 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2336 MmUnlockSectionSegment(Context
.Segment
);
2337 MmUnlockAddressSpace(AddressSpace
);
2340 MiSetPageEvent(NULL
, NULL
);
2341 return(STATUS_SUCCESS
);
2346 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2347 PMEMORY_AREA MemoryArea
,
2351 LARGE_INTEGER Offset
;
2352 PROS_SECTION_OBJECT Section
;
2353 PMM_SECTION_SEGMENT Segment
;
2355 SWAPENTRY SwapEntry
;
2359 PFILE_OBJECT FileObject
;
2361 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2363 BOOLEAN DirectMapped
;
2364 BOOLEAN IsImageSection
;
2365 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2367 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2369 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2370 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2373 * Get the segment and section.
2375 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2376 Section
= MemoryArea
->Data
.SectionData
.Section
;
2377 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2379 FileObject
= Section
->FileObject
;
2380 DirectMapped
= FALSE
;
2381 if (FileObject
!= NULL
&&
2382 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2385 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2389 * If the file system is letting us go directly to the cache and the
2390 * memory area was mapped at an offset in the file which is page aligned
2391 * then note this is a direct mapped page.
2393 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2394 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2396 DirectMapped
= TRUE
;
2401 * This should never happen since mappings of physical memory are never
2402 * placed in the rmap lists.
2404 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2406 DPRINT1("Trying to write back page from physical memory mapped at %p "
2407 "process %p\n", Address
,
2408 Process
? Process
->UniqueProcessId
: 0);
2409 KeBugCheck(MEMORY_MANAGEMENT
);
2413 * Get the section segment entry and the physical address.
2415 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2416 if (!MmIsPagePresent(Process
, Address
))
2418 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2419 Process
? Process
->UniqueProcessId
: 0, Address
);
2420 KeBugCheck(MEMORY_MANAGEMENT
);
2422 Page
= MmGetPfnForProcess(Process
, Address
);
2423 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2426 * Check for a private (COWed) page.
2428 if (IS_SWAP_FROM_SSE(Entry
) || PFN_FROM_SSE(Entry
) != Page
)
2438 * Speculatively set all mappings of the page to clean.
2440 MmSetCleanAllRmaps(Page
);
2443 * If this page was direct mapped from the cache then the cache manager
2444 * will take care of writing it back to disk.
2446 if (DirectMapped
&& !Private
)
2448 //LARGE_INTEGER SOffset;
2449 ASSERT(SwapEntry
== 0);
2450 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2452 CcRosMarkDirtyFile(SharedCacheMap
, Offset
.QuadPart
);
2454 MmLockSectionSegment(Segment
);
2455 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2456 MmUnlockSectionSegment(Segment
);
2457 MiSetPageEvent(NULL
, NULL
);
2458 return(STATUS_SUCCESS
);
2462 * If necessary, allocate an entry in the paging file for this page
2466 SwapEntry
= MmAllocSwapPage();
2469 MmSetDirtyAllRmaps(Page
);
2470 MiSetPageEvent(NULL
, NULL
);
2471 return(STATUS_PAGEFILE_QUOTA
);
2473 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2477 * Write the page to the pagefile
2479 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2480 if (!NT_SUCCESS(Status
))
2482 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2484 MmSetDirtyAllRmaps(Page
);
2485 MiSetPageEvent(NULL
, NULL
);
2486 return(STATUS_UNSUCCESSFUL
);
2490 * Otherwise we have succeeded.
2492 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2493 MiSetPageEvent(NULL
, NULL
);
2494 return(STATUS_SUCCESS
);
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
);