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
);
1414 /* Check for a NOACCESS mapping */
1415 if (Region
->Protect
& PAGE_NOACCESS
)
1417 return STATUS_ACCESS_VIOLATION
;
1420 if (Region
->Protect
& PAGE_GUARD
)
1423 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
1424 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1425 Address
, PAGE_SIZE
, Region
->Type
, Region
->Protect
& ~PAGE_GUARD
,
1426 MmAlterViewAttributes
);
1428 if (!NT_SUCCESS(Status
))
1430 DPRINT1("Removing PAGE_GUARD protection failed : 0x%08x.\n", Status
);
1433 return STATUS_GUARD_PAGE_VIOLATION
;
1439 MmLockSectionSegment(Segment
);
1440 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1442 * Check if this page needs to be mapped COW
1444 if ((Segment
->WriteCopy
) &&
1445 (Region
->Protect
== PAGE_READWRITE
||
1446 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1448 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1452 Attributes
= Region
->Protect
;
1456 * Check if someone else is already handling this fault, if so wait
1459 if (Entry
&& MM_IS_WAIT_PTE(Entry
))
1461 MmUnlockSectionSegment(Segment
);
1462 MmUnlockAddressSpace(AddressSpace
);
1463 MiWaitForPageEvent(NULL
, NULL
);
1464 MmLockAddressSpace(AddressSpace
);
1465 DPRINT("Address 0x%p\n", Address
);
1466 return(STATUS_MM_RESTART_OPERATION
);
1469 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1471 /* See if we should use a private page */
1474 SWAPENTRY DummyEntry
;
1477 * Is it a wait entry?
1481 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1483 if (SwapEntry
== MM_WAIT_ENTRY
)
1485 MmUnlockSectionSegment(Segment
);
1486 MmUnlockAddressSpace(AddressSpace
);
1487 MiWaitForPageEvent(NULL
, NULL
);
1488 MmLockAddressSpace(AddressSpace
);
1489 return STATUS_MM_RESTART_OPERATION
;
1493 * Must be private page we have swapped out.
1499 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1501 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1502 KeBugCheck(MEMORY_MANAGEMENT
);
1504 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1507 MmUnlockSectionSegment(Segment
);
1509 /* Tell everyone else we are serving the fault. */
1510 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1512 MmUnlockAddressSpace(AddressSpace
);
1513 MI_SET_USAGE(MI_USAGE_SECTION
);
1514 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1515 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1516 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1517 if (!NT_SUCCESS(Status
))
1519 KeBugCheck(MEMORY_MANAGEMENT
);
1524 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1525 if (!NT_SUCCESS(Status
))
1527 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1528 KeBugCheck(MEMORY_MANAGEMENT
);
1532 MmLockAddressSpace(AddressSpace
);
1533 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1534 Status
= MmCreateVirtualMapping(Process
,
1539 if (!NT_SUCCESS(Status
))
1541 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1542 KeBugCheck(MEMORY_MANAGEMENT
);
1547 * Store the swap entry for later use.
1550 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1553 * Add the page to the process's working set
1555 MmInsertRmap(Page
, Process
, Address
);
1557 * Finish the operation
1559 MiSetPageEvent(Process
, Address
);
1560 DPRINT("Address 0x%p\n", Address
);
1561 return(STATUS_SUCCESS
);
1565 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1567 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1569 MmUnlockSectionSegment(Segment
);
1571 * Just map the desired physical page
1573 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1574 Status
= MmCreateVirtualMappingUnsafe(Process
,
1579 if (!NT_SUCCESS(Status
))
1581 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1582 KeBugCheck(MEMORY_MANAGEMENT
);
1587 * Cleanup and release locks
1589 MiSetPageEvent(Process
, Address
);
1590 DPRINT("Address 0x%p\n", Address
);
1591 return(STATUS_SUCCESS
);
1595 * Get the entry corresponding to the offset within the section
1597 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1601 SWAPENTRY FakeSwapEntry
;
1604 * If the entry is zero (and it can't change because we have
1605 * locked the segment) then we need to load the page.
1609 * Release all our locks and read in the page from disk
1611 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1612 MmUnlockSectionSegment(Segment
);
1613 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1614 MmUnlockAddressSpace(AddressSpace
);
1616 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1617 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1618 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1620 MI_SET_USAGE(MI_USAGE_SECTION
);
1621 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1622 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1623 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1624 if (!NT_SUCCESS(Status
))
1626 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1632 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1633 if (!NT_SUCCESS(Status
))
1635 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1638 if (!NT_SUCCESS(Status
))
1641 * FIXME: What do we know in this case?
1644 * Cleanup and release locks
1646 MmLockAddressSpace(AddressSpace
);
1647 MiSetPageEvent(Process
, Address
);
1648 DPRINT("Address 0x%p\n", Address
);
1652 /* Lock both segment and process address space while we proceed. */
1653 MmLockAddressSpace(AddressSpace
);
1654 MmLockSectionSegment(Segment
);
1656 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1657 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1658 Page
, Process
, PAddress
, Attributes
);
1659 Status
= MmCreateVirtualMapping(Process
,
1664 if (!NT_SUCCESS(Status
))
1666 DPRINT1("Unable to create virtual mapping\n");
1667 KeBugCheck(MEMORY_MANAGEMENT
);
1669 ASSERT(MmIsPagePresent(Process
, PAddress
));
1670 MmInsertRmap(Page
, Process
, Address
);
1672 /* Set this section offset has being backed by our new page. */
1673 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1674 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1675 MmUnlockSectionSegment(Segment
);
1677 MiSetPageEvent(Process
, Address
);
1678 DPRINT("Address 0x%p\n", Address
);
1679 return(STATUS_SUCCESS
);
1681 else if (IS_SWAP_FROM_SSE(Entry
))
1683 SWAPENTRY SwapEntry
;
1685 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1687 /* See if a page op is running on this segment. */
1688 if (SwapEntry
== MM_WAIT_ENTRY
)
1690 MmUnlockSectionSegment(Segment
);
1691 MmUnlockAddressSpace(AddressSpace
);
1692 MiWaitForPageEvent(NULL
, NULL
);
1693 MmLockAddressSpace(AddressSpace
);
1694 return STATUS_MM_RESTART_OPERATION
;
1698 * Release all our locks and read in the page from disk
1700 MmUnlockSectionSegment(Segment
);
1702 MmUnlockAddressSpace(AddressSpace
);
1703 MI_SET_USAGE(MI_USAGE_SECTION
);
1704 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1705 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1706 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1707 if (!NT_SUCCESS(Status
))
1709 KeBugCheck(MEMORY_MANAGEMENT
);
1712 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1713 if (!NT_SUCCESS(Status
))
1715 KeBugCheck(MEMORY_MANAGEMENT
);
1719 * Relock the address space and segment
1721 MmLockAddressSpace(AddressSpace
);
1722 MmLockSectionSegment(Segment
);
1725 * Check the entry. No one should change the status of a page
1726 * that has a pending page-in.
1728 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1729 if (Entry
!= Entry1
)
1731 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1732 KeBugCheck(MEMORY_MANAGEMENT
);
1736 * Save the swap entry.
1738 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1740 /* Map the page into the process address space */
1741 Status
= MmCreateVirtualMapping(Process
,
1746 if (!NT_SUCCESS(Status
))
1748 DPRINT1("Unable to create virtual mapping\n");
1749 KeBugCheck(MEMORY_MANAGEMENT
);
1751 MmInsertRmap(Page
, Process
, Address
);
1754 * Mark the offset within the section as having valid, in-memory
1757 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1758 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1759 MmUnlockSectionSegment(Segment
);
1761 MiSetPageEvent(Process
, Address
);
1762 DPRINT("Address 0x%p\n", Address
);
1763 return(STATUS_SUCCESS
);
1767 /* We already have a page on this section offset. Map it into the process address space. */
1768 Page
= PFN_FROM_SSE(Entry
);
1770 Status
= MmCreateVirtualMapping(Process
,
1775 if (!NT_SUCCESS(Status
))
1777 DPRINT1("Unable to create virtual mapping\n");
1778 KeBugCheck(MEMORY_MANAGEMENT
);
1780 MmInsertRmap(Page
, Process
, Address
);
1782 /* Take a reference on it */
1783 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1784 MmUnlockSectionSegment(Segment
);
1786 MiSetPageEvent(Process
, Address
);
1787 DPRINT("Address 0x%p\n", Address
);
1788 return(STATUS_SUCCESS
);
1794 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1795 MEMORY_AREA
* MemoryArea
,
1798 PMM_SECTION_SEGMENT Segment
;
1799 PROS_SECTION_OBJECT Section
;
1804 LARGE_INTEGER Offset
;
1807 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1809 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1811 /* Make sure we have a page mapping for this address. */
1812 Status
= MmNotPresentFaultSectionView(AddressSpace
, MemoryArea
, Address
, TRUE
);
1813 if (!NT_SUCCESS(Status
))
1815 /* This is invalid access ! */
1820 * Check if the page has already been set readwrite
1822 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1824 DPRINT("Address 0x%p\n", Address
);
1825 return(STATUS_SUCCESS
);
1829 * Find the offset of the page
1831 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1832 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1833 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1835 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1836 Section
= MemoryArea
->Data
.SectionData
.Section
;
1837 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1838 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1840 ASSERT(Region
!= NULL
);
1843 * Check if we are doing COW
1845 if (!((Segment
->WriteCopy
) &&
1846 (Region
->Protect
== PAGE_READWRITE
||
1847 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1849 DPRINT("Address 0x%p\n", Address
);
1850 return(STATUS_ACCESS_VIOLATION
);
1853 /* Get the page mapping this section offset. */
1854 MmLockSectionSegment(Segment
);
1855 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1857 /* Get the current page mapping for the process */
1858 ASSERT(MmIsPagePresent(Process
, PAddress
));
1859 OldPage
= MmGetPfnForProcess(Process
, PAddress
);
1860 ASSERT(OldPage
!= 0);
1862 if (IS_SWAP_FROM_SSE(Entry
) ||
1863 PFN_FROM_SSE(Entry
) != OldPage
)
1865 MmUnlockSectionSegment(Segment
);
1866 /* This is a private page. We must only change the page protection. */
1867 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1868 return(STATUS_SUCCESS
);
1874 MI_SET_USAGE(MI_USAGE_SECTION
);
1875 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1876 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1877 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1878 if (!NT_SUCCESS(Status
))
1880 KeBugCheck(MEMORY_MANAGEMENT
);
1886 NT_VERIFY(NT_SUCCESS(MiCopyFromUserPage(NewPage
, PAddress
)));
1889 * Unshare the old page.
1891 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1892 MmDeleteVirtualMapping(Process
, PAddress
, NULL
, NULL
);
1893 MmDeleteRmap(OldPage
, Process
, PAddress
);
1894 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1895 MmUnlockSectionSegment(Segment
);
1898 * Set the PTE to point to the new page
1900 Status
= MmCreateVirtualMapping(Process
,
1905 if (!NT_SUCCESS(Status
))
1907 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1908 KeBugCheck(MEMORY_MANAGEMENT
);
1911 MmInsertRmap(NewPage
, Process
, PAddress
);
1913 MiSetPageEvent(Process
, Address
);
1914 DPRINT("Address 0x%p\n", Address
);
1915 return(STATUS_SUCCESS
);
1919 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1921 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1923 PFN_NUMBER Page
= 0;
1925 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1928 MmLockAddressSpace(&Process
->Vm
);
1931 MmDeleteVirtualMapping(Process
,
1937 PageOutContext
->WasDirty
= TRUE
;
1939 if (!PageOutContext
->Private
)
1941 MmLockSectionSegment(PageOutContext
->Segment
);
1942 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1943 PageOutContext
->Segment
,
1944 &PageOutContext
->Offset
,
1945 PageOutContext
->WasDirty
,
1947 &PageOutContext
->SectionEntry
);
1948 MmUnlockSectionSegment(PageOutContext
->Segment
);
1952 MmUnlockAddressSpace(&Process
->Vm
);
1955 if (PageOutContext
->Private
)
1957 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1963 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1964 MEMORY_AREA
* MemoryArea
,
1965 PVOID Address
, ULONG_PTR Entry
)
1968 MM_SECTION_PAGEOUT_CONTEXT Context
;
1969 SWAPENTRY SwapEntry
;
1972 ULONGLONG FileOffset
;
1973 PFILE_OBJECT FileObject
;
1974 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1975 BOOLEAN IsImageSection
;
1977 BOOLEAN DirectMapped
;
1978 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1981 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1984 * Get the segment and section.
1986 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1987 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1988 Context
.SectionEntry
= Entry
;
1989 Context
.CallingProcess
= Process
;
1991 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
1992 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1994 DirectMapped
= FALSE
;
1996 MmLockSectionSegment(Context
.Segment
);
1999 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
2000 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2001 FileObject
= Context
.Section
->FileObject
;
2003 if (FileObject
!= NULL
&&
2004 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2006 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2009 * If the file system is letting us go directly to the cache and the
2010 * memory area was mapped at an offset in the file which is page aligned
2011 * then note this is a direct mapped page.
2013 if ((FileOffset
% PAGE_SIZE
) == 0 &&
2014 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2016 DirectMapped
= TRUE
;
2023 * This should never happen since mappings of physical memory are never
2024 * placed in the rmap lists.
2026 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2028 DPRINT1("Trying to page out from physical memory section address 0x%p "
2029 "process %p\n", Address
,
2030 Process
? Process
->UniqueProcessId
: 0);
2031 KeBugCheck(MEMORY_MANAGEMENT
);
2035 * Get the section segment entry and the physical address.
2037 if (!MmIsPagePresent(Process
, Address
))
2039 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2040 Process
? Process
->UniqueProcessId
: 0, Address
);
2041 KeBugCheck(MEMORY_MANAGEMENT
);
2043 Page
= MmGetPfnForProcess(Process
, Address
);
2044 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2047 * Check the reference count to ensure this page can be paged out
2049 if (MmGetReferenceCountPage(Page
) != 1)
2051 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
2052 Page
, MmGetReferenceCountPage(Page
));
2053 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2054 MmUnlockSectionSegment(Context
.Segment
);
2055 return STATUS_UNSUCCESSFUL
;
2059 * Prepare the context structure for the rmap delete call.
2061 MmUnlockSectionSegment(Context
.Segment
);
2062 Context
.WasDirty
= FALSE
;
2063 if (IS_SWAP_FROM_SSE(Entry
) || PFN_FROM_SSE(Entry
) != Page
)
2065 Context
.Private
= TRUE
;
2069 Context
.Private
= FALSE
;
2073 * Take an additional reference to the page or the VACB.
2075 if (DirectMapped
&& !Context
.Private
)
2077 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
2079 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2080 KeBugCheck(MEMORY_MANAGEMENT
);
2085 OldIrql
= MiAcquirePfnLock();
2086 MmReferencePage(Page
);
2087 MiReleasePfnLock(OldIrql
);
2090 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2092 /* Since we passed in a surrogate, we'll get back the page entry
2093 * state in our context. This is intended to make intermediate
2094 * decrements of share count not release the wait entry.
2096 Entry
= Context
.SectionEntry
;
2099 * If this wasn't a private page then we should have reduced the entry to
2100 * zero by deleting all the rmaps.
2102 if (!Context
.Private
&& Entry
!= 0)
2104 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2105 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2107 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2112 * If the page wasn't dirty then we can just free it as for a readonly page.
2113 * Since we unmapped all the mappings above we know it will not suddenly
2115 * If the page is from a pagefile section and has no swap entry,
2116 * we can't free the page at this point.
2118 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2119 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2121 if (Context
.Private
)
2123 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2124 Context
.WasDirty
? "dirty" : "clean", Address
);
2125 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2127 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2129 MmSetSavedSwapEntryPage(Page
, 0);
2130 MmLockSectionSegment(Context
.Segment
);
2131 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2132 MmUnlockSectionSegment(Context
.Segment
);
2133 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2134 MiSetPageEvent(NULL
, NULL
);
2135 return(STATUS_SUCCESS
);
2138 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2140 if (Context
.Private
)
2142 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2143 Context
.WasDirty
? "dirty" : "clean", Address
);
2144 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2146 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2148 MmSetSavedSwapEntryPage(Page
, 0);
2151 MmLockSectionSegment(Context
.Segment
);
2152 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2153 MmUnlockSectionSegment(Context
.Segment
);
2155 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2156 MiSetPageEvent(NULL
, NULL
);
2157 return(STATUS_SUCCESS
);
2160 else if (!Context
.Private
&& DirectMapped
)
2164 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2166 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2169 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
, FALSE
);
2171 Status
= STATUS_SUCCESS
;
2174 if (!NT_SUCCESS(Status
))
2176 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2177 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2180 MiSetPageEvent(NULL
, NULL
);
2181 return(STATUS_SUCCESS
);
2183 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2187 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2189 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2191 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2192 MiSetPageEvent(NULL
, NULL
);
2193 return(STATUS_SUCCESS
);
2195 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2197 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2198 MmSetSavedSwapEntryPage(Page
, 0);
2199 MmLockAddressSpace(AddressSpace
);
2200 Status
= MmCreatePageFileMapping(Process
,
2203 MmUnlockAddressSpace(AddressSpace
);
2204 if (!NT_SUCCESS(Status
))
2206 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2207 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2209 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2210 MiSetPageEvent(NULL
, NULL
);
2211 return(STATUS_SUCCESS
);
2215 * If necessary, allocate an entry in the paging file for this page
2219 SwapEntry
= MmAllocSwapPage();
2222 MmShowOutOfSpaceMessagePagingFile();
2223 MmLockAddressSpace(AddressSpace
);
2225 * For private pages restore the old mappings.
2227 if (Context
.Private
)
2229 Status
= MmCreateVirtualMapping(Process
,
2231 MemoryArea
->Protect
,
2234 MmSetDirtyPage(Process
, Address
);
2243 MmLockSectionSegment(Context
.Segment
);
2246 * For non-private pages if the page wasn't direct mapped then
2247 * set it back into the section segment entry so we don't loose
2248 * our copy. Otherwise it will be handled by the cache manager.
2250 Status
= MmCreateVirtualMapping(Process
,
2252 MemoryArea
->Protect
,
2255 MmSetDirtyPage(Process
, Address
);
2259 // If we got here, the previous entry should have been a wait
2260 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2261 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2262 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2263 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2264 MmUnlockSectionSegment(Context
.Segment
);
2266 MmUnlockAddressSpace(AddressSpace
);
2267 MiSetPageEvent(NULL
, NULL
);
2268 return(STATUS_PAGEFILE_QUOTA
);
2273 * Write the page to the pagefile
2275 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2276 if (!NT_SUCCESS(Status
))
2278 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2281 * As above: undo our actions.
2282 * FIXME: Also free the swap page.
2284 MmLockAddressSpace(AddressSpace
);
2285 if (Context
.Private
)
2287 Status
= MmCreateVirtualMapping(Process
,
2289 MemoryArea
->Protect
,
2292 MmSetDirtyPage(Process
, Address
);
2299 MmLockSectionSegment(Context
.Segment
);
2300 Status
= MmCreateVirtualMapping(Process
,
2302 MemoryArea
->Protect
,
2305 MmSetDirtyPage(Process
, Address
);
2309 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2310 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2311 MmUnlockSectionSegment(Context
.Segment
);
2313 MmUnlockAddressSpace(AddressSpace
);
2314 MiSetPageEvent(NULL
, NULL
);
2315 return(STATUS_UNSUCCESSFUL
);
2319 * Otherwise we have succeeded.
2321 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2322 MmSetSavedSwapEntryPage(Page
, 0);
2323 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2324 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2326 MmLockSectionSegment(Context
.Segment
);
2327 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2328 MmUnlockSectionSegment(Context
.Segment
);
2332 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2335 if (Context
.Private
)
2337 MmLockAddressSpace(AddressSpace
);
2338 MmLockSectionSegment(Context
.Segment
);
2339 Status
= MmCreatePageFileMapping(Process
,
2342 /* We had placed a wait entry upon entry ... replace it before leaving */
2343 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2344 MmUnlockSectionSegment(Context
.Segment
);
2345 MmUnlockAddressSpace(AddressSpace
);
2346 if (!NT_SUCCESS(Status
))
2348 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2349 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2354 MmLockAddressSpace(AddressSpace
);
2355 MmLockSectionSegment(Context
.Segment
);
2356 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2357 /* We had placed a wait entry upon entry ... replace it before leaving */
2358 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2359 MmUnlockSectionSegment(Context
.Segment
);
2360 MmUnlockAddressSpace(AddressSpace
);
2363 MiSetPageEvent(NULL
, NULL
);
2364 return(STATUS_SUCCESS
);
2369 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2370 PMEMORY_AREA MemoryArea
,
2374 LARGE_INTEGER Offset
;
2375 PROS_SECTION_OBJECT Section
;
2376 PMM_SECTION_SEGMENT Segment
;
2378 SWAPENTRY SwapEntry
;
2382 PFILE_OBJECT FileObject
;
2384 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2386 BOOLEAN DirectMapped
;
2387 BOOLEAN IsImageSection
;
2388 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2390 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2392 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2393 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2396 * Get the segment and section.
2398 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2399 Section
= MemoryArea
->Data
.SectionData
.Section
;
2400 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2402 FileObject
= Section
->FileObject
;
2403 DirectMapped
= FALSE
;
2404 if (FileObject
!= NULL
&&
2405 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2408 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2412 * If the file system is letting us go directly to the cache and the
2413 * memory area was mapped at an offset in the file which is page aligned
2414 * then note this is a direct mapped page.
2416 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2417 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2419 DirectMapped
= TRUE
;
2424 * This should never happen since mappings of physical memory are never
2425 * placed in the rmap lists.
2427 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2429 DPRINT1("Trying to write back page from physical memory mapped at %p "
2430 "process %p\n", Address
,
2431 Process
? Process
->UniqueProcessId
: 0);
2432 KeBugCheck(MEMORY_MANAGEMENT
);
2436 * Get the section segment entry and the physical address.
2438 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2439 if (!MmIsPagePresent(Process
, Address
))
2441 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2442 Process
? Process
->UniqueProcessId
: 0, Address
);
2443 KeBugCheck(MEMORY_MANAGEMENT
);
2445 Page
= MmGetPfnForProcess(Process
, Address
);
2446 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2449 * Check for a private (COWed) page.
2451 if (IS_SWAP_FROM_SSE(Entry
) || PFN_FROM_SSE(Entry
) != Page
)
2461 * Speculatively set all mappings of the page to clean.
2463 MmSetCleanAllRmaps(Page
);
2466 * If this page was direct mapped from the cache then the cache manager
2467 * will take care of writing it back to disk.
2469 if (DirectMapped
&& !Private
)
2471 //LARGE_INTEGER SOffset;
2472 ASSERT(SwapEntry
== 0);
2473 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2475 CcRosMarkDirtyFile(SharedCacheMap
, Offset
.QuadPart
);
2477 MmLockSectionSegment(Segment
);
2478 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2479 MmUnlockSectionSegment(Segment
);
2480 MiSetPageEvent(NULL
, NULL
);
2481 return(STATUS_SUCCESS
);
2485 * If necessary, allocate an entry in the paging file for this page
2489 SwapEntry
= MmAllocSwapPage();
2492 MmSetDirtyAllRmaps(Page
);
2493 MiSetPageEvent(NULL
, NULL
);
2494 return(STATUS_PAGEFILE_QUOTA
);
2496 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2500 * Write the page to the pagefile
2502 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2503 if (!NT_SUCCESS(Status
))
2505 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2507 MmSetDirtyAllRmaps(Page
);
2508 MiSetPageEvent(NULL
, NULL
);
2509 return(STATUS_UNSUCCESSFUL
);
2513 * Otherwise we have succeeded.
2515 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2516 MiSetPageEvent(NULL
, NULL
);
2517 return(STATUS_SUCCESS
);
2522 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2523 PMEMORY_AREA MemoryArea
,
2531 ULONG_PTR MaxLength
;
2533 MaxLength
= MA_GetEndingAddress(MemoryArea
) - (ULONG_PTR
)BaseAddress
;
2534 if (Length
> MaxLength
)
2535 Length
= (ULONG
)MaxLength
;
2537 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2538 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2540 ASSERT(Region
!= NULL
);
2542 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2543 Region
->Protect
!= Protect
)
2545 return STATUS_INVALID_PAGE_PROTECTION
;
2548 *OldProtect
= Region
->Protect
;
2549 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
2550 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2551 BaseAddress
, Length
, Region
->Type
, Protect
,
2552 MmAlterViewAttributes
);
2558 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2560 PMEMORY_BASIC_INFORMATION Info
,
2561 PSIZE_T ResultLength
)
2564 PVOID RegionBaseAddress
;
2565 PROS_SECTION_OBJECT Section
;
2566 PMM_SECTION_SEGMENT Segment
;
2568 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2569 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2570 Address
, &RegionBaseAddress
);
2573 return STATUS_UNSUCCESSFUL
;
2576 Section
= MemoryArea
->Data
.SectionData
.Section
;
2577 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2579 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2580 Info
->AllocationBase
= (PUCHAR
)MA_GetStartingAddress(MemoryArea
) - Segment
->Image
.VirtualAddress
;
2581 Info
->Type
= MEM_IMAGE
;
2585 Info
->AllocationBase
= (PVOID
)MA_GetStartingAddress(MemoryArea
);
2586 Info
->Type
= MEM_MAPPED
;
2588 Info
->BaseAddress
= RegionBaseAddress
;
2589 Info
->AllocationProtect
= MemoryArea
->Protect
;
2590 Info
->RegionSize
= Region
->Length
;
2591 Info
->State
= MEM_COMMIT
;
2592 Info
->Protect
= Region
->Protect
;
2594 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2595 return(STATUS_SUCCESS
);
2600 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2603 LARGE_INTEGER Offset
;
2605 SWAPENTRY SavedSwapEntry
;
2610 MmLockSectionSegment(Segment
);
2612 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2613 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2615 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2618 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2619 if (IS_SWAP_FROM_SSE(Entry
))
2621 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2625 Page
= PFN_FROM_SSE(Entry
);
2626 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2627 if (SavedSwapEntry
!= 0)
2629 MmSetSavedSwapEntryPage(Page
, 0);
2630 MmFreeSwapPage(SavedSwapEntry
);
2632 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2637 MmUnlockSectionSegment(Segment
);
2641 MmpDeleteSection(PVOID ObjectBody
)
2643 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2645 /* Check if it's an ARM3, or ReactOS section */
2646 if (!MiIsRosSectionObject(Section
))
2648 MiDeleteARM3Section(ObjectBody
);
2652 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2653 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2658 PMM_SECTION_SEGMENT SectionSegments
;
2661 * NOTE: Section->ImageSection can be NULL for short time
2662 * during the section creating. If we fail for some reason
2663 * until the image section is properly initialized we shouldn't
2664 * process further here.
2666 if (Section
->ImageSection
== NULL
)
2669 SectionSegments
= Section
->ImageSection
->Segments
;
2670 NrSegments
= Section
->ImageSection
->NrSegments
;
2672 for (i
= 0; i
< NrSegments
; i
++)
2674 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2676 MmLockSectionSegment(&SectionSegments
[i
]);
2678 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2679 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2681 MmUnlockSectionSegment(&SectionSegments
[i
]);
2684 MmpFreePageFileSegment(&SectionSegments
[i
]);
2690 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2693 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2696 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2698 DPRINT("Freeing section segment\n");
2699 Section
->Segment
= NULL
;
2700 MmFinalizeSegment(Segment
);
2704 DPRINT("RefCount %d\n", RefCount
);
2711 * NOTE: Section->Segment can be NULL for short time
2712 * during the section creating.
2714 if (Section
->Segment
== NULL
)
2717 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2719 MmpFreePageFileSegment(Section
->Segment
);
2720 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2721 ExFreePool(Section
->Segment
);
2722 Section
->Segment
= NULL
;
2726 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2729 if (Section
->FileObject
!= NULL
)
2732 CcRosDereferenceCache(Section
->FileObject
);
2734 ObDereferenceObject(Section
->FileObject
);
2735 Section
->FileObject
= NULL
;
2740 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2742 IN ACCESS_MASK GrantedAccess
,
2743 IN ULONG ProcessHandleCount
,
2744 IN ULONG SystemHandleCount
)
2746 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2752 MmCreatePhysicalMemorySection(VOID
)
2754 PROS_SECTION_OBJECT PhysSection
;
2756 OBJECT_ATTRIBUTES Obj
;
2757 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2758 LARGE_INTEGER SectionSize
;
2762 * Create the section mapping physical memory
2764 SectionSize
.QuadPart
= 0xFFFFFFFF;
2765 InitializeObjectAttributes(&Obj
,
2767 OBJ_PERMANENT
| OBJ_KERNEL_EXCLUSIVE
,
2770 Status
= MmCreateSection((PVOID
)&PhysSection
,
2774 PAGE_EXECUTE_READWRITE
,
2778 if (!NT_SUCCESS(Status
))
2780 DPRINT1("Failed to create PhysicalMemory section\n");
2781 KeBugCheck(MEMORY_MANAGEMENT
);
2783 Status
= ObInsertObject(PhysSection
,
2789 if (!NT_SUCCESS(Status
))
2791 ObDereferenceObject(PhysSection
);
2793 ObCloseHandle(Handle
, KernelMode
);
2794 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2795 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2797 return(STATUS_SUCCESS
);
2803 MmInitSectionImplementation(VOID
)
2805 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2806 UNICODE_STRING Name
;
2808 DPRINT("Creating Section Object Type\n");
2810 /* Initialize the section based root */
2811 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2812 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2814 /* Initialize the Section object type */
2815 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2816 RtlInitUnicodeString(&Name
, L
"Section");
2817 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2818 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2819 ObjectTypeInitializer
.PoolType
= PagedPool
;
2820 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2821 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2822 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2823 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2824 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2825 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2826 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2828 MmCreatePhysicalMemorySection();
2830 return(STATUS_SUCCESS
);
2835 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2836 ACCESS_MASK DesiredAccess
,
2837 POBJECT_ATTRIBUTES ObjectAttributes
,
2838 PLARGE_INTEGER UMaximumSize
,
2839 ULONG SectionPageProtection
,
2840 ULONG AllocationAttributes
)
2842 * Create a section which is backed by the pagefile
2845 LARGE_INTEGER MaximumSize
;
2846 PROS_SECTION_OBJECT Section
;
2847 PMM_SECTION_SEGMENT Segment
;
2850 if (UMaximumSize
== NULL
)
2852 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2853 return(STATUS_INVALID_PARAMETER
);
2855 MaximumSize
= *UMaximumSize
;
2858 * Create the section
2860 Status
= ObCreateObject(ExGetPreviousMode(),
2861 MmSectionObjectType
,
2863 ExGetPreviousMode(),
2865 sizeof(ROS_SECTION_OBJECT
),
2868 (PVOID
*)(PVOID
)&Section
);
2869 if (!NT_SUCCESS(Status
))
2871 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2878 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2879 Section
->Type
= 'SC';
2880 Section
->Size
= 'TN';
2881 Section
->SectionPageProtection
= SectionPageProtection
;
2882 Section
->AllocationAttributes
= AllocationAttributes
;
2883 Section
->MaximumSize
= MaximumSize
;
2884 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2885 TAG_MM_SECTION_SEGMENT
);
2886 if (Segment
== NULL
)
2888 ObDereferenceObject(Section
);
2889 return(STATUS_NO_MEMORY
);
2891 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2892 Section
->Segment
= Segment
;
2893 Segment
->ReferenceCount
= 1;
2894 ExInitializeFastMutex(&Segment
->Lock
);
2895 Segment
->Image
.FileOffset
= 0;
2896 Segment
->Protection
= SectionPageProtection
;
2897 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2898 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2899 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2900 Segment
->WriteCopy
= FALSE
;
2901 Segment
->Image
.VirtualAddress
= 0;
2902 Segment
->Image
.Characteristics
= 0;
2903 *SectionObject
= Section
;
2904 MiInitializeSectionPageTable(Segment
);
2905 return(STATUS_SUCCESS
);
2910 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2911 ACCESS_MASK DesiredAccess
,
2912 POBJECT_ATTRIBUTES ObjectAttributes
,
2913 PLARGE_INTEGER UMaximumSize
,
2914 ULONG SectionPageProtection
,
2915 ULONG AllocationAttributes
,
2916 PFILE_OBJECT FileObject
)
2918 * Create a section backed by a data file
2921 PROS_SECTION_OBJECT Section
;
2923 LARGE_INTEGER MaximumSize
;
2924 PMM_SECTION_SEGMENT Segment
;
2925 FILE_STANDARD_INFORMATION FileInfo
;
2929 * Create the section
2931 Status
= ObCreateObject(ExGetPreviousMode(),
2932 MmSectionObjectType
,
2934 ExGetPreviousMode(),
2936 sizeof(ROS_SECTION_OBJECT
),
2940 if (!NT_SUCCESS(Status
))
2942 ObDereferenceObject(FileObject
);
2948 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2949 Section
->Type
= 'SC';
2950 Section
->Size
= 'TN';
2951 Section
->SectionPageProtection
= SectionPageProtection
;
2952 Section
->AllocationAttributes
= AllocationAttributes
;
2955 * FIXME: This is propably not entirely correct. We can't look into
2956 * the standard FCB header because it might not be initialized yet
2957 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2958 * standard file information is filled on first request).
2960 Status
= IoQueryFileInformation(FileObject
,
2961 FileStandardInformation
,
2962 sizeof(FILE_STANDARD_INFORMATION
),
2965 if (!NT_SUCCESS(Status
))
2967 ObDereferenceObject(Section
);
2968 ObDereferenceObject(FileObject
);
2973 * FIXME: Revise this once a locking order for file size changes is
2976 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2978 MaximumSize
= *UMaximumSize
;
2982 MaximumSize
= FileInfo
.EndOfFile
;
2983 /* Mapping zero-sized files isn't allowed. */
2984 if (MaximumSize
.QuadPart
== 0)
2986 ObDereferenceObject(Section
);
2987 ObDereferenceObject(FileObject
);
2988 return STATUS_MAPPED_FILE_SIZE_ZERO
;
2992 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2994 Status
= IoSetInformation(FileObject
,
2995 FileEndOfFileInformation
,
2996 sizeof(LARGE_INTEGER
),
2998 if (!NT_SUCCESS(Status
))
3000 ObDereferenceObject(Section
);
3001 ObDereferenceObject(FileObject
);
3002 return(STATUS_SECTION_NOT_EXTENDED
);
3006 if (FileObject
->SectionObjectPointer
== NULL
||
3007 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3009 ObDereferenceObject(Section
);
3010 ObDereferenceObject(FileObject
);
3011 return STATUS_INVALID_FILE_FOR_SECTION
;
3017 Status
= MmspWaitForFileLock(FileObject
);
3018 if (Status
!= STATUS_SUCCESS
)
3020 ObDereferenceObject(Section
);
3021 ObDereferenceObject(FileObject
);
3026 * If this file hasn't been mapped as a data file before then allocate a
3027 * section segment to describe the data file mapping
3029 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3031 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3032 TAG_MM_SECTION_SEGMENT
);
3033 if (Segment
== NULL
)
3035 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3036 ObDereferenceObject(Section
);
3037 ObDereferenceObject(FileObject
);
3038 return(STATUS_NO_MEMORY
);
3040 Section
->Segment
= Segment
;
3041 Segment
->ReferenceCount
= 1;
3042 ExInitializeFastMutex(&Segment
->Lock
);
3044 * Set the lock before assigning the segment to the file object
3046 ExAcquireFastMutex(&Segment
->Lock
);
3047 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3049 Segment
->Image
.FileOffset
= 0;
3050 Segment
->Protection
= SectionPageProtection
;
3051 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3052 Segment
->Image
.Characteristics
= 0;
3053 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3054 if (AllocationAttributes
& SEC_RESERVE
)
3056 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3060 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3061 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3063 Segment
->Image
.VirtualAddress
= 0;
3064 Segment
->Locked
= TRUE
;
3065 MiInitializeSectionPageTable(Segment
);
3070 * If the file is already mapped as a data file then we may need
3074 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3076 Section
->Segment
= Segment
;
3077 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3078 MmLockSectionSegment(Segment
);
3080 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3081 !(AllocationAttributes
& SEC_RESERVE
))
3083 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3084 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3087 MmUnlockSectionSegment(Segment
);
3088 Section
->FileObject
= FileObject
;
3089 Section
->MaximumSize
= MaximumSize
;
3091 CcRosReferenceCache(FileObject
);
3093 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3094 *SectionObject
= Section
;
3095 return(STATUS_SUCCESS
);
3099 TODO: not that great (declaring loaders statically, having to declare all of
3100 them, having to keep them extern, etc.), will fix in the future
3102 extern NTSTATUS NTAPI PeFmtCreateSection
3104 IN CONST VOID
* FileHeader
,
3105 IN SIZE_T FileHeaderSize
,
3107 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3109 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3110 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3113 extern NTSTATUS NTAPI ElfFmtCreateSection
3115 IN CONST VOID
* FileHeader
,
3116 IN SIZE_T FileHeaderSize
,
3118 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3120 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3121 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3124 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3135 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3137 SIZE_T SizeOfSegments
;
3138 PMM_SECTION_SEGMENT Segments
;
3140 /* TODO: check for integer overflow */
3141 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3143 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3145 TAG_MM_SECTION_SEGMENT
);
3148 RtlZeroMemory(Segments
, SizeOfSegments
);
3156 ExeFmtpReadFile(IN PVOID File
,
3157 IN PLARGE_INTEGER Offset
,
3160 OUT PVOID
* AllocBase
,
3161 OUT PULONG ReadSize
)
3164 LARGE_INTEGER FileOffset
;
3166 ULONG OffsetAdjustment
;
3170 PFILE_OBJECT FileObject
= File
;
3171 IO_STATUS_BLOCK Iosb
;
3173 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3177 KeBugCheck(MEMORY_MANAGEMENT
);
3180 FileOffset
= *Offset
;
3182 /* Negative/special offset: it cannot be used in this context */
3183 if(FileOffset
.u
.HighPart
< 0)
3185 KeBugCheck(MEMORY_MANAGEMENT
);
3188 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3189 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3190 FileOffset
.u
.LowPart
= AdjustOffset
;
3192 BufferSize
= Length
+ OffsetAdjustment
;
3193 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3195 /* Flush data since we're about to perform a non-cached read */
3196 CcFlushCache(FileObject
->SectionObjectPointer
,
3202 * It's ok to use paged pool, because this is a temporary buffer only used in
3203 * the loading of executables. The assumption is that MmCreateSection is
3204 * always called at low IRQLs and that these buffers don't survive a brief
3205 * initialization phase
3207 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3212 return STATUS_INSUFFICIENT_RESOURCES
;
3217 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3219 UsedSize
= (ULONG
)Iosb
.Information
;
3221 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3223 Status
= STATUS_IN_PAGE_ERROR
;
3224 ASSERT(!NT_SUCCESS(Status
));
3227 if(NT_SUCCESS(Status
))
3229 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3230 *AllocBase
= Buffer
;
3231 *ReadSize
= UsedSize
- OffsetAdjustment
;
3235 ExFreePoolWithTag(Buffer
, 'rXmM');
3242 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3243 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3244 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3249 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3253 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3255 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3256 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3263 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3267 MmspAssertSegmentsSorted(ImageSectionObject
);
3269 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3271 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3275 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3276 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3277 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3285 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3289 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3291 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3292 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3300 MmspCompareSegments(const void * x
,
3303 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3304 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3307 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3308 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3312 * Ensures an image section's segments are sorted in memory
3317 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3320 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3322 MmspAssertSegmentsSorted(ImageSectionObject
);
3326 qsort(ImageSectionObject
->Segments
,
3327 ImageSectionObject
->NrSegments
,
3328 sizeof(ImageSectionObject
->Segments
[0]),
3329 MmspCompareSegments
);
3335 * Ensures an image section's segments don't overlap in memory and don't have
3336 * gaps and don't have a null size. We let them map to overlapping file regions,
3337 * though - that's not necessarily an error
3342 MmspCheckSegmentBounds
3344 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3350 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3352 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3356 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3358 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3360 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3368 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3369 * page could be OK (Windows seems to be OK with them), and larger gaps
3370 * could lead to image sections spanning several discontiguous regions
3371 * (NtMapViewOfSection could then refuse to map them, and they could
3372 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3374 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3375 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3376 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3387 * Merges and pads an image section's segments until they all are page-aligned
3388 * and have a size that is a multiple of the page size
3393 MmspPageAlignSegments
3395 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3401 PMM_SECTION_SEGMENT EffectiveSegment
;
3403 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3405 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3410 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3412 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3415 * The first segment requires special handling
3419 ULONG_PTR VirtualAddress
;
3420 ULONG_PTR VirtualOffset
;
3422 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3424 /* Round down the virtual address to the nearest page */
3425 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3427 /* Round up the virtual size to the nearest page */
3428 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3429 EffectiveSegment
->Image
.VirtualAddress
;
3431 /* Adjust the raw address and size */
3432 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3434 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3440 * Garbage in, garbage out: unaligned base addresses make the file
3441 * offset point in curious and odd places, but that's what we were
3444 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3445 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3449 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3450 ULONG_PTR EndOfEffectiveSegment
;
3452 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3453 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3456 * The current segment begins exactly where the current effective
3457 * segment ended, therefore beginning a new effective segment
3459 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3462 ASSERT(LastSegment
<= i
);
3463 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3465 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3467 if (LastSegment
!= i
)
3470 * Copy the current segment. If necessary, the effective segment
3471 * will be expanded later
3473 *EffectiveSegment
= *Segment
;
3477 * Page-align the virtual size. We know for sure the virtual address
3480 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3481 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3484 * The current segment is still part of the current effective segment:
3485 * extend the effective segment to reflect this
3487 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3489 static const ULONG FlagsToProtection
[16] =
3497 PAGE_EXECUTE_READWRITE
,
3498 PAGE_EXECUTE_READWRITE
,
3503 PAGE_EXECUTE_WRITECOPY
,
3504 PAGE_EXECUTE_WRITECOPY
,
3505 PAGE_EXECUTE_WRITECOPY
,
3506 PAGE_EXECUTE_WRITECOPY
3509 unsigned ProtectionFlags
;
3512 * Extend the file size
3515 /* Unaligned segments must be contiguous within the file */
3516 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3517 EffectiveSegment
->RawLength
.QuadPart
))
3522 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3525 * Extend the virtual size
3527 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3529 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3530 EffectiveSegment
->Image
.VirtualAddress
;
3533 * Merge the protection
3535 EffectiveSegment
->Protection
|= Segment
->Protection
;
3537 /* Clean up redundance */
3538 ProtectionFlags
= 0;
3540 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3541 ProtectionFlags
|= 1 << 0;
3543 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3544 ProtectionFlags
|= 1 << 1;
3546 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3547 ProtectionFlags
|= 1 << 2;
3549 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3550 ProtectionFlags
|= 1 << 3;
3552 ASSERT(ProtectionFlags
< 16);
3553 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3555 /* If a segment was required to be shared and cannot, fail */
3556 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3557 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3563 * We assume no holes between segments at this point
3567 KeBugCheck(MEMORY_MANAGEMENT
);
3571 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3577 ExeFmtpCreateImageSection(PFILE_OBJECT FileObject
,
3578 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3580 LARGE_INTEGER Offset
;
3582 PVOID FileHeaderBuffer
;
3583 ULONG FileHeaderSize
;
3585 ULONG OldNrSegments
;
3590 * Read the beginning of the file (2 pages). Should be enough to contain
3591 * all (or most) of the headers
3593 Offset
.QuadPart
= 0;
3595 Status
= ExeFmtpReadFile (FileObject
,
3602 if (!NT_SUCCESS(Status
))
3605 if (FileHeaderSize
== 0)
3607 ExFreePool(FileHeaderBuffer
);
3608 return STATUS_UNSUCCESSFUL
;
3612 * Look for a loader that can handle this executable
3614 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3616 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3619 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3625 ExeFmtpAllocateSegments
);
3627 if (!NT_SUCCESS(Status
))
3629 if (ImageSectionObject
->Segments
)
3631 ExFreePool(ImageSectionObject
->Segments
);
3632 ImageSectionObject
->Segments
= NULL
;
3636 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3640 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3643 * No loader handled the format
3645 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3647 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3648 ASSERT(!NT_SUCCESS(Status
));
3651 if (!NT_SUCCESS(Status
))
3654 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3659 /* FIXME? are these values platform-dependent? */
3660 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3661 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3663 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3664 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3666 if(ImageSectionObject
->BasedAddress
== NULL
)
3668 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3669 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3671 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3675 * And now the fun part: fixing the segments
3678 /* Sort them by virtual address */
3679 MmspSortSegments(ImageSectionObject
, Flags
);
3681 /* Ensure they don't overlap in memory */
3682 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3683 return STATUS_INVALID_IMAGE_FORMAT
;
3685 /* Ensure they are aligned */
3686 OldNrSegments
= ImageSectionObject
->NrSegments
;
3688 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3689 return STATUS_INVALID_IMAGE_FORMAT
;
3691 /* Trim them if the alignment phase merged some of them */
3692 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3694 PMM_SECTION_SEGMENT Segments
;
3695 SIZE_T SizeOfSegments
;
3697 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3699 Segments
= ExAllocatePoolWithTag(PagedPool
,
3701 TAG_MM_SECTION_SEGMENT
);
3703 if (Segments
== NULL
)
3704 return STATUS_INSUFFICIENT_RESOURCES
;
3706 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3707 ExFreePool(ImageSectionObject
->Segments
);
3708 ImageSectionObject
->Segments
= Segments
;
3711 /* And finish their initialization */
3712 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3714 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3715 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3716 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3719 ASSERT(NT_SUCCESS(Status
));
3724 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3725 ACCESS_MASK DesiredAccess
,
3726 POBJECT_ATTRIBUTES ObjectAttributes
,
3727 PLARGE_INTEGER UMaximumSize
,
3728 ULONG SectionPageProtection
,
3729 ULONG AllocationAttributes
,
3730 PFILE_OBJECT FileObject
)
3732 PROS_SECTION_OBJECT Section
;
3734 PMM_SECTION_SEGMENT SectionSegments
;
3735 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3738 if (FileObject
== NULL
)
3739 return STATUS_INVALID_FILE_FOR_SECTION
;
3742 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3744 DPRINT1("Denying section creation due to missing cache initialization\n");
3745 return STATUS_INVALID_FILE_FOR_SECTION
;
3750 * Create the section
3752 Status
= ObCreateObject (ExGetPreviousMode(),
3753 MmSectionObjectType
,
3755 ExGetPreviousMode(),
3757 sizeof(ROS_SECTION_OBJECT
),
3760 (PVOID
*)(PVOID
)&Section
);
3761 if (!NT_SUCCESS(Status
))
3763 ObDereferenceObject(FileObject
);
3770 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3771 Section
->Type
= 'SC';
3772 Section
->Size
= 'TN';
3773 Section
->SectionPageProtection
= SectionPageProtection
;
3774 Section
->AllocationAttributes
= AllocationAttributes
;
3776 if (FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3778 NTSTATUS StatusExeFmt
;
3780 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3781 if (ImageSectionObject
== NULL
)
3783 ObDereferenceObject(FileObject
);
3784 ObDereferenceObject(Section
);
3785 return(STATUS_NO_MEMORY
);
3788 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3790 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3792 if (!NT_SUCCESS(StatusExeFmt
))
3794 if(ImageSectionObject
->Segments
!= NULL
)
3795 ExFreePool(ImageSectionObject
->Segments
);
3798 * If image file is empty, then return that the file is invalid for section
3800 Status
= StatusExeFmt
;
3801 if (StatusExeFmt
== STATUS_END_OF_FILE
)
3803 Status
= STATUS_INVALID_FILE_FOR_SECTION
;
3806 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3807 ObDereferenceObject(Section
);
3808 ObDereferenceObject(FileObject
);
3812 Section
->ImageSection
= ImageSectionObject
;
3813 ASSERT(ImageSectionObject
->Segments
);
3818 Status
= MmspWaitForFileLock(FileObject
);
3819 if (!NT_SUCCESS(Status
))
3821 ExFreePool(ImageSectionObject
->Segments
);
3822 ExFreePool(ImageSectionObject
);
3823 ObDereferenceObject(Section
);
3824 ObDereferenceObject(FileObject
);
3828 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3829 ImageSectionObject
, NULL
))
3832 * An other thread has initialized the same image in the background
3834 ExFreePool(ImageSectionObject
->Segments
);
3835 ExFreePool(ImageSectionObject
);
3836 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3837 Section
->ImageSection
= ImageSectionObject
;
3838 SectionSegments
= ImageSectionObject
->Segments
;
3840 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3842 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3846 Status
= StatusExeFmt
;
3853 Status
= MmspWaitForFileLock(FileObject
);
3854 if (Status
!= STATUS_SUCCESS
)
3856 ObDereferenceObject(Section
);
3857 ObDereferenceObject(FileObject
);
3861 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3862 Section
->ImageSection
= ImageSectionObject
;
3863 SectionSegments
= ImageSectionObject
->Segments
;
3866 * Otherwise just reference all the section segments
3868 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3870 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3873 Status
= STATUS_SUCCESS
;
3875 Section
->FileObject
= FileObject
;
3877 CcRosReferenceCache(FileObject
);
3879 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3880 *SectionObject
= Section
;
3887 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3888 PROS_SECTION_OBJECT Section
,
3889 PMM_SECTION_SEGMENT Segment
,
3894 ULONG AllocationType
)
3900 if (Segment
->WriteCopy
)
3902 /* We have to do this because the not present fault
3903 * and access fault handlers depend on the protection
3904 * that should be granted AFTER the COW fault takes
3905 * place to be in Region->Protect. The not present fault
3906 * handler changes this to the correct protection for COW when
3907 * mapping the pages into the process's address space. If a COW
3908 * fault takes place, the access fault handler sets the page protection
3909 * to these values for the newly copied pages
3911 if (Protect
== PAGE_WRITECOPY
)
3912 Protect
= PAGE_READWRITE
;
3913 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3914 Protect
= PAGE_EXECUTE_READWRITE
;
3917 if (*BaseAddress
== NULL
)
3918 Granularity
= MM_ALLOCATION_GRANULARITY
;
3920 Granularity
= PAGE_SIZE
;
3923 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3925 LARGE_INTEGER FileOffset
;
3926 FileOffset
.QuadPart
= ViewOffset
;
3927 ObReferenceObject(Section
);
3928 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3931 Status
= MmCreateMemoryArea(AddressSpace
,
3932 MEMORY_AREA_SECTION_VIEW
,
3939 if (!NT_SUCCESS(Status
))
3941 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3942 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3946 ObReferenceObject((PVOID
)Section
);
3948 MArea
->Data
.SectionData
.Segment
= Segment
;
3949 MArea
->Data
.SectionData
.Section
= Section
;
3950 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3951 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3953 MArea
->VadNode
.u
.VadFlags
.VadType
= VadImageMap
;
3956 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3957 ViewSize
, 0, Protect
);
3959 return(STATUS_SUCCESS
);
3964 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3965 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3969 PFILE_OBJECT FileObject
;
3970 PROS_SHARED_CACHE_MAP SharedCacheMap
;
3972 LARGE_INTEGER Offset
;
3973 SWAPENTRY SavedSwapEntry
;
3974 PROS_SECTION_OBJECT Section
;
3975 PMM_SECTION_SEGMENT Segment
;
3976 PMMSUPPORT AddressSpace
;
3979 AddressSpace
= (PMMSUPPORT
)Context
;
3980 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3982 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3984 Offset
.QuadPart
= ((ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)) +
3985 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3987 Section
= MemoryArea
->Data
.SectionData
.Section
;
3988 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3990 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3991 while (Entry
&& MM_IS_WAIT_PTE(Entry
))
3993 MmUnlockSectionSegment(Segment
);
3994 MmUnlockAddressSpace(AddressSpace
);
3996 MiWaitForPageEvent(NULL
, NULL
);
3998 MmLockAddressSpace(AddressSpace
);
3999 MmLockSectionSegment(Segment
);
4000 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4004 * For a dirty, datafile, non-private page mark it as dirty in the
4007 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4009 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4012 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4013 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4014 CcRosMarkDirtyFile(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4016 ASSERT(SwapEntry
== 0);
4025 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4027 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4028 KeBugCheck(MEMORY_MANAGEMENT
);
4030 MmFreeSwapPage(SwapEntry
);
4034 if (IS_SWAP_FROM_SSE(Entry
) ||
4035 Page
!= PFN_FROM_SSE(Entry
))
4040 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4042 DPRINT1("Found a private page in a pagefile section.\n");
4043 KeBugCheck(MEMORY_MANAGEMENT
);
4046 * Just dereference private pages
4048 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4049 if (SavedSwapEntry
!= 0)
4051 MmFreeSwapPage(SavedSwapEntry
);
4052 MmSetSavedSwapEntryPage(Page
, 0);
4054 MmDeleteRmap(Page
, Process
, Address
);
4055 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4059 MmDeleteRmap(Page
, Process
, Address
);
4060 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4066 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4070 PMEMORY_AREA MemoryArea
;
4071 PROS_SECTION_OBJECT Section
;
4072 PMM_SECTION_SEGMENT Segment
;
4073 PLIST_ENTRY CurrentEntry
;
4074 PMM_REGION CurrentRegion
;
4075 PLIST_ENTRY RegionListHead
;
4077 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4079 if (MemoryArea
== NULL
)
4081 return(STATUS_UNSUCCESSFUL
);
4084 Section
= MemoryArea
->Data
.SectionData
.Section
;
4085 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4088 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4090 MmUnlockAddressSpace(AddressSpace
);
4091 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4092 MmLockAddressSpace(AddressSpace
);
4098 MemoryArea
->DeleteInProgress
= TRUE
;
4100 MmLockSectionSegment(Segment
);
4102 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4103 while (!IsListEmpty(RegionListHead
))
4105 CurrentEntry
= RemoveHeadList(RegionListHead
);
4106 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4107 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4110 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4112 Status
= MmFreeMemoryArea(AddressSpace
,
4119 Status
= MmFreeMemoryArea(AddressSpace
,
4124 MmUnlockSectionSegment(Segment
);
4125 ObDereferenceObject(Section
);
4131 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4132 IN PVOID BaseAddress
,
4133 IN BOOLEAN SkipDebuggerNotify
)
4136 PMEMORY_AREA MemoryArea
;
4137 PMMSUPPORT AddressSpace
;
4138 PROS_SECTION_OBJECT Section
;
4139 PVOID ImageBaseAddress
= 0;
4141 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4142 Process
, BaseAddress
);
4146 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4148 MmLockAddressSpace(AddressSpace
);
4149 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4151 if (MemoryArea
== NULL
||
4152 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4153 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4154 MemoryArea
->DeleteInProgress
)
4156 if (MemoryArea
) ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4157 MmUnlockAddressSpace(AddressSpace
);
4158 return STATUS_NOT_MAPPED_VIEW
;
4161 Section
= MemoryArea
->Data
.SectionData
.Section
;
4163 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4167 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4168 PMM_SECTION_SEGMENT SectionSegments
;
4169 PMM_SECTION_SEGMENT Segment
;
4171 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4172 ImageSectionObject
= Section
->ImageSection
;
4173 SectionSegments
= ImageSectionObject
->Segments
;
4174 NrSegments
= ImageSectionObject
->NrSegments
;
4176 MemoryArea
->DeleteInProgress
= TRUE
;
4178 /* Search for the current segment within the section segments
4179 * and calculate the image base address */
4180 for (i
= 0; i
< NrSegments
; i
++)
4182 if (Segment
== &SectionSegments
[i
])
4184 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4188 if (i
>= NrSegments
)
4190 KeBugCheck(MEMORY_MANAGEMENT
);
4193 for (i
= 0; i
< NrSegments
; i
++)
4195 PVOID SBaseAddress
= (PVOID
)
4196 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4198 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4199 if (!NT_SUCCESS(Status
))
4201 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4202 SBaseAddress
, Process
, Status
);
4203 ASSERT(NT_SUCCESS(Status
));
4209 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4210 if (!NT_SUCCESS(Status
))
4212 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4213 BaseAddress
, Process
, Status
);
4214 ASSERT(NT_SUCCESS(Status
));
4218 MmUnlockAddressSpace(AddressSpace
);
4220 /* Notify debugger */
4221 if (ImageBaseAddress
&& !SkipDebuggerNotify
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4223 return(STATUS_SUCCESS
);
4230 * Queries the information of a section object.
4232 * @param SectionHandle
4233 * Handle to the section object. It must be opened with SECTION_QUERY
4235 * @param SectionInformationClass
4236 * Index to a certain information structure. Can be either
4237 * SectionBasicInformation or SectionImageInformation. The latter
4238 * is valid only for sections that were created with the SEC_IMAGE
4240 * @param SectionInformation
4241 * Caller supplies storage for resulting information.
4243 * Size of the supplied storage.
4244 * @param ResultLength
4254 _In_ HANDLE SectionHandle
,
4255 _In_ SECTION_INFORMATION_CLASS SectionInformationClass
,
4256 _Out_ PVOID SectionInformation
,
4257 _In_ SIZE_T SectionInformationLength
,
4258 _Out_opt_ PSIZE_T ResultLength
)
4261 KPROCESSOR_MODE PreviousMode
;
4265 PreviousMode
= ExGetPreviousMode();
4266 if (PreviousMode
!= KernelMode
)
4270 ProbeForWrite(SectionInformation
,
4271 SectionInformationLength
,
4273 if (ResultLength
!= NULL
)
4275 ProbeForWrite(ResultLength
,
4276 sizeof(*ResultLength
),
4280 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4282 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4287 if (SectionInformationClass
== SectionBasicInformation
)
4289 if (SectionInformationLength
< sizeof(SECTION_BASIC_INFORMATION
))
4291 return STATUS_INFO_LENGTH_MISMATCH
;
4294 else if (SectionInformationClass
== SectionImageInformation
)
4296 if (SectionInformationLength
< sizeof(SECTION_IMAGE_INFORMATION
))
4298 return STATUS_INFO_LENGTH_MISMATCH
;
4303 return STATUS_INVALID_INFO_CLASS
;
4306 Status
= ObReferenceObjectByHandle(SectionHandle
,
4308 MmSectionObjectType
,
4310 (PVOID
*)(PVOID
)&Section
,
4312 if (!NT_SUCCESS(Status
))
4314 DPRINT1("Failed to reference section: 0x%lx\n", Status
);
4318 if (MiIsRosSectionObject(Section
))
4320 PROS_SECTION_OBJECT RosSection
= (PROS_SECTION_OBJECT
)Section
;
4322 switch (SectionInformationClass
)
4324 case SectionBasicInformation
:
4326 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4330 Sbi
->Attributes
= RosSection
->AllocationAttributes
;
4331 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4333 Sbi
->BaseAddress
= 0;
4334 Sbi
->Size
.QuadPart
= 0;
4338 Sbi
->BaseAddress
= (PVOID
)RosSection
->Segment
->Image
.VirtualAddress
;
4339 Sbi
->Size
.QuadPart
= RosSection
->Segment
->Length
.QuadPart
;
4342 if (ResultLength
!= NULL
)
4344 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4346 Status
= STATUS_SUCCESS
;
4348 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4350 Status
= _SEH2_GetExceptionCode();
4357 case SectionImageInformation
:
4359 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4363 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4365 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4366 ImageSectionObject
= RosSection
->ImageSection
;
4368 *Sii
= ImageSectionObject
->ImageInformation
;
4371 if (ResultLength
!= NULL
)
4373 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4375 Status
= STATUS_SUCCESS
;
4377 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4379 Status
= _SEH2_GetExceptionCode();
4389 switch(SectionInformationClass
)
4391 case SectionBasicInformation
:
4393 SECTION_BASIC_INFORMATION Sbi
;
4395 Sbi
.Size
= Section
->SizeOfSection
;
4396 Sbi
.BaseAddress
= (PVOID
)Section
->Address
.StartingVpn
;
4399 if (Section
->u
.Flags
.Image
)
4400 Sbi
.Attributes
|= SEC_IMAGE
;
4401 if (Section
->u
.Flags
.Commit
)
4402 Sbi
.Attributes
|= SEC_COMMIT
;
4403 if (Section
->u
.Flags
.Reserve
)
4404 Sbi
.Attributes
|= SEC_RESERVE
;
4405 if (Section
->u
.Flags
.File
)
4406 Sbi
.Attributes
|= SEC_FILE
;
4407 if (Section
->u
.Flags
.Image
)
4408 Sbi
.Attributes
|= SEC_IMAGE
;
4410 /* FIXME : Complete/test the list of flags passed back from NtCreateSection */
4414 *((SECTION_BASIC_INFORMATION
*)SectionInformation
) = Sbi
;
4416 *ResultLength
= sizeof(Sbi
);
4418 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4420 Status
= _SEH2_GetExceptionCode();
4425 case SectionImageInformation
:
4427 if (!Section
->u
.Flags
.Image
)
4429 Status
= STATUS_SECTION_NOT_IMAGE
;
4433 /* Currently not supported */
4441 ObDereferenceObject(Section
);
4446 /**********************************************************************
4448 * MmMapViewOfSection
4451 * Maps a view of a section into the virtual address space of a
4456 * Pointer to the section object.
4459 * Pointer to the process.
4462 * Desired base address (or NULL) on entry;
4463 * Actual base address of the view on exit.
4466 * Number of high order address bits that must be zero.
4469 * Size in bytes of the initially committed section of
4473 * Offset in bytes from the beginning of the section
4474 * to the beginning of the view.
4477 * Desired length of map (or zero to map all) on entry
4478 * Actual length mapped on exit.
4480 * InheritDisposition
4481 * Specified how the view is to be shared with
4485 * Type of allocation for the pages.
4488 * Protection for the committed region of the view.
4496 MmMapViewOfSection(IN PVOID SectionObject
,
4497 IN PEPROCESS Process
,
4498 IN OUT PVOID
*BaseAddress
,
4499 IN ULONG_PTR ZeroBits
,
4500 IN SIZE_T CommitSize
,
4501 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4502 IN OUT PSIZE_T ViewSize
,
4503 IN SECTION_INHERIT InheritDisposition
,
4504 IN ULONG AllocationType
,
4507 PROS_SECTION_OBJECT Section
;
4508 PMMSUPPORT AddressSpace
;
4510 NTSTATUS Status
= STATUS_SUCCESS
;
4511 BOOLEAN NotAtBase
= FALSE
;
4513 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4515 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4516 return MmMapViewOfArm3Section(SectionObject
,
4530 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4532 return STATUS_INVALID_PAGE_PROTECTION
;
4535 /* FIXME: We should keep this, but it would break code checking equality */
4536 Protect
&= ~PAGE_NOCACHE
;
4538 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4539 AddressSpace
= &Process
->Vm
;
4541 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4543 MmLockAddressSpace(AddressSpace
);
4545 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4549 ULONG_PTR ImageBase
;
4551 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4552 PMM_SECTION_SEGMENT SectionSegments
;
4554 ImageSectionObject
= Section
->ImageSection
;
4555 SectionSegments
= ImageSectionObject
->Segments
;
4556 NrSegments
= ImageSectionObject
->NrSegments
;
4558 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4561 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4565 for (i
= 0; i
< NrSegments
; i
++)
4567 ULONG_PTR MaxExtent
;
4568 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4569 SectionSegments
[i
].Length
.QuadPart
);
4570 ImageSize
= max(ImageSize
, MaxExtent
);
4573 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4575 /* Check for an illegal base address */
4576 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4577 ((ImageBase
+ ImageSize
) < ImageSize
))
4579 ASSERT(*BaseAddress
== NULL
);
4580 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4581 MM_VIRTMEM_GRANULARITY
);
4584 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4586 ASSERT(*BaseAddress
== NULL
);
4587 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4591 /* Check there is enough space to map the section at that point. */
4592 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4593 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4595 /* Fail if the user requested a fixed base address. */
4596 if ((*BaseAddress
) != NULL
)
4598 MmUnlockAddressSpace(AddressSpace
);
4599 return(STATUS_CONFLICTING_ADDRESSES
);
4601 /* Otherwise find a gap to map the image. */
4602 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4605 MmUnlockAddressSpace(AddressSpace
);
4606 return(STATUS_CONFLICTING_ADDRESSES
);
4608 /* Remember that we loaded image at a different base address */
4612 for (i
= 0; i
< NrSegments
; i
++)
4614 PVOID SBaseAddress
= (PVOID
)
4615 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4616 MmLockSectionSegment(&SectionSegments
[i
]);
4617 Status
= MmMapViewOfSegment(AddressSpace
,
4619 &SectionSegments
[i
],
4621 SectionSegments
[i
].Length
.LowPart
,
4622 SectionSegments
[i
].Protection
,
4625 MmUnlockSectionSegment(&SectionSegments
[i
]);
4626 if (!NT_SUCCESS(Status
))
4628 MmUnlockAddressSpace(AddressSpace
);
4633 *BaseAddress
= (PVOID
)ImageBase
;
4634 *ViewSize
= ImageSize
;
4638 /* check for write access */
4639 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4640 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4642 MmUnlockAddressSpace(AddressSpace
);
4643 return STATUS_SECTION_PROTECTION
;
4645 /* check for read access */
4646 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4647 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4649 MmUnlockAddressSpace(AddressSpace
);
4650 return STATUS_SECTION_PROTECTION
;
4652 /* check for execute access */
4653 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4654 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4656 MmUnlockAddressSpace(AddressSpace
);
4657 return STATUS_SECTION_PROTECTION
;
4660 if (SectionOffset
== NULL
)
4666 ViewOffset
= SectionOffset
->u
.LowPart
;
4669 if ((ViewOffset
% PAGE_SIZE
) != 0)
4671 MmUnlockAddressSpace(AddressSpace
);
4672 return(STATUS_MAPPED_ALIGNMENT
);
4675 if ((*ViewSize
) == 0)
4677 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4679 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4681 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4684 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4686 MmLockSectionSegment(Section
->Segment
);
4687 Status
= MmMapViewOfSegment(AddressSpace
,
4694 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4695 MmUnlockSectionSegment(Section
->Segment
);
4696 if (!NT_SUCCESS(Status
))
4698 MmUnlockAddressSpace(AddressSpace
);
4703 MmUnlockAddressSpace(AddressSpace
);
4704 ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4707 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4709 Status
= STATUS_SUCCESS
;
4718 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4719 IN PLARGE_INTEGER NewFileSize
)
4721 /* Check whether an ImageSectionObject exists */
4722 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4724 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4728 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4730 PMM_SECTION_SEGMENT Segment
;
4732 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4735 if (Segment
->ReferenceCount
!= 0)
4738 CC_FILE_SIZES FileSizes
;
4740 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4743 /* Check size of file */
4744 if (SectionObjectPointer
->SharedCacheMap
)
4746 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4751 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4760 /* Check size of file */
4761 if (SectionObjectPointer
->SharedCacheMap
)
4763 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4764 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4773 /* Something must gone wrong
4774 * how can we have a Section but no
4776 DPRINT("ERROR: DataSectionObject without reference!\n");
4780 DPRINT("FIXME: didn't check for outstanding write probes\n");
4792 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4793 IN MMFLUSH_TYPE FlushType
)
4795 BOOLEAN Result
= TRUE
;
4797 PMM_SECTION_SEGMENT Segment
;
4802 case MmFlushForDelete
:
4803 if (SectionObjectPointer
->ImageSectionObject
||
4804 SectionObjectPointer
->DataSectionObject
)
4809 CcRosRemoveIfClosed(SectionObjectPointer
);
4812 case MmFlushForWrite
:
4814 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4816 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4819 if (SectionObjectPointer
->ImageSectionObject
)
4821 DPRINT1("SectionObject has ImageSection\n");
4827 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4829 DPRINT("Result %d\n", Result
);
4841 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4842 OUT PVOID
* MappedBase
,
4843 IN OUT PSIZE_T ViewSize
)
4845 PROS_SECTION_OBJECT Section
;
4846 PMMSUPPORT AddressSpace
;
4850 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4852 return MiMapViewInSystemSpace(SectionObject
,
4858 DPRINT("MmMapViewInSystemSpace() called\n");
4860 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4861 AddressSpace
= MmGetKernelAddressSpace();
4863 MmLockAddressSpace(AddressSpace
);
4866 if ((*ViewSize
) == 0)
4868 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4870 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4872 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4875 MmLockSectionSegment(Section
->Segment
);
4878 Status
= MmMapViewOfSegment(AddressSpace
,
4887 MmUnlockSectionSegment(Section
->Segment
);
4888 MmUnlockAddressSpace(AddressSpace
);
4895 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4897 PMMSUPPORT AddressSpace
;
4900 DPRINT("MmUnmapViewInSystemSpace() called\n");
4902 AddressSpace
= MmGetKernelAddressSpace();
4904 MmLockAddressSpace(AddressSpace
);
4906 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4908 MmUnlockAddressSpace(AddressSpace
);
4913 /**********************************************************************
4918 * Creates a section object.
4921 * SectionObject (OUT)
4922 * Caller supplied storage for the resulting pointer
4923 * to a SECTION_OBJECT instance;
4926 * Specifies the desired access to the section can be a
4928 * STANDARD_RIGHTS_REQUIRED |
4930 * SECTION_MAP_WRITE |
4931 * SECTION_MAP_READ |
4932 * SECTION_MAP_EXECUTE
4934 * ObjectAttributes [OPTIONAL]
4935 * Initialized attributes for the object can be used
4936 * to create a named section;
4939 * Maximizes the size of the memory section. Must be
4940 * non-NULL for a page-file backed section.
4941 * If value specified for a mapped file and the file is
4942 * not large enough, file will be extended.
4944 * SectionPageProtection
4945 * Can be a combination of:
4951 * AllocationAttributes
4952 * Can be a combination of:
4957 * Handle to a file to create a section mapped to a file
4958 * instead of a memory backed section;
4969 MmCreateSection (OUT PVOID
* Section
,
4970 IN ACCESS_MASK DesiredAccess
,
4971 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4972 IN PLARGE_INTEGER MaximumSize
,
4973 IN ULONG SectionPageProtection
,
4974 IN ULONG AllocationAttributes
,
4975 IN HANDLE FileHandle OPTIONAL
,
4976 IN PFILE_OBJECT FileObject OPTIONAL
)
4980 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4982 /* Check if an ARM3 section is being created instead */
4983 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4985 if (!(FileObject
) && !(FileHandle
))
4987 return MmCreateArm3Section(Section
,
4991 SectionPageProtection
,
4992 AllocationAttributes
&~ 1,
4998 /* Convert section flag to page flag */
4999 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
5001 /* Check to make sure the protection is correct. Nt* does this already */
5002 Protection
= MiMakeProtectionMask(SectionPageProtection
);
5003 if (Protection
== MM_INVALID_PROTECTION
)
5005 DPRINT1("Page protection is invalid\n");
5006 return STATUS_INVALID_PAGE_PROTECTION
;
5009 /* Check if this is going to be a data or image backed file section */
5010 if ((FileHandle
) || (FileObject
))
5012 /* These cannot be mapped with large pages */
5013 if (AllocationAttributes
& SEC_LARGE_PAGES
)
5015 DPRINT1("Large pages cannot be used with an image mapping\n");
5016 return STATUS_INVALID_PARAMETER_6
;
5019 /* Did the caller pass an object? */
5022 /* Reference the object directly */
5023 ObReferenceObject(FileObject
);
5027 /* Reference the file handle to get the object */
5028 Status
= ObReferenceObjectByHandle(FileHandle
,
5029 MmMakeFileAccess
[Protection
],
5031 ExGetPreviousMode(),
5032 (PVOID
*)&FileObject
,
5034 if (!NT_SUCCESS(Status
))
5036 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
5043 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
5044 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
5047 #ifndef NEWCC // A hack for initializing caching.
5048 // This is needed only in the old case.
5051 IO_STATUS_BLOCK Iosb
;
5054 LARGE_INTEGER ByteOffset
;
5055 ByteOffset
.QuadPart
= 0;
5056 Status
= ZwReadFile(FileHandle
,
5065 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5067 DPRINT1("CC failure: %lx\n", Status
);
5069 ObDereferenceObject(FileObject
);
5072 // Caching is initialized...
5074 // Hack of the hack: actually, it might not be initialized if FSD init on effective right and if file is null-size
5075 // In such case, force cache by initiating a write IRP
5076 if (Status
== STATUS_END_OF_FILE
&& !(AllocationAttributes
& SEC_IMAGE
) && FileObject
!= NULL
&&
5077 (FileObject
->SectionObjectPointer
== NULL
|| FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
))
5080 Status
= ZwWriteFile(FileHandle
,
5089 if (NT_SUCCESS(Status
))
5092 Zero
.QuadPart
= 0LL;
5094 Status
= IoSetInformation(FileObject
,
5095 FileEndOfFileInformation
,
5096 sizeof(LARGE_INTEGER
),
5098 ASSERT(NT_SUCCESS(Status
));
5104 if (AllocationAttributes
& SEC_IMAGE
)
5106 Status
= MmCreateImageSection(SectionObject
,
5110 SectionPageProtection
,
5111 AllocationAttributes
,
5115 else if (FileHandle
!= NULL
)
5117 Status
= MmCreateDataFileSection(SectionObject
,
5121 SectionPageProtection
,
5122 AllocationAttributes
,
5126 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5128 Status
= MmCreateCacheSection(SectionObject
,
5132 SectionPageProtection
,
5133 AllocationAttributes
,
5139 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5141 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5143 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5144 Status
= MmCreatePageFileSection(SectionObject
,
5148 SectionPageProtection
,
5149 AllocationAttributes
);
5151 ObDereferenceObject(FileObject
);