2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
48 #include <cache/newcc.h>
49 #include <cache/section/newmm.h>
52 #include <reactos/exeformat.h>
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 #include "ARM3/miarm.h"
61 #undef MmSetPageEntrySectionSegment
62 #define MmSetPageEntrySectionSegment(S,O,E) do { \
63 DPRINT("SetPageEntrySectionSegment(old,%p,%x,%x)\n",(S),(O)->LowPart,E); \
64 _MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__); \
67 extern MMSESSION MmSession
;
71 MiMapViewInSystemSpace(IN PVOID Section
,
73 OUT PVOID
*MappedBase
,
74 IN OUT PSIZE_T ViewSize
);
78 MmCreateArm3Section(OUT PVOID
*SectionObject
,
79 IN ACCESS_MASK DesiredAccess
,
80 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
81 IN PLARGE_INTEGER InputMaximumSize
,
82 IN ULONG SectionPageProtection
,
83 IN ULONG AllocationAttributes
,
84 IN HANDLE FileHandle OPTIONAL
,
85 IN PFILE_OBJECT FileObject OPTIONAL
);
89 MmMapViewOfArm3Section(IN PVOID SectionObject
,
91 IN OUT PVOID
*BaseAddress
,
92 IN ULONG_PTR ZeroBits
,
94 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
95 IN OUT PSIZE_T ViewSize
,
96 IN SECTION_INHERIT InheritDisposition
,
97 IN ULONG AllocationType
,
101 // PeFmtCreateSection depends on the following:
103 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
104 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
106 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
107 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
108 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
110 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
111 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
112 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
113 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
114 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
115 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
116 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
117 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
118 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
120 /* TYPES *********************************************************************/
124 PROS_SECTION_OBJECT Section
;
125 PMM_SECTION_SEGMENT Segment
;
126 LARGE_INTEGER Offset
;
129 PEPROCESS CallingProcess
;
130 ULONG_PTR SectionEntry
;
132 MM_SECTION_PAGEOUT_CONTEXT
;
134 /* GLOBALS *******************************************************************/
136 POBJECT_TYPE MmSectionObjectType
= NULL
;
138 ULONG_PTR MmSubsectionBase
;
140 static ULONG SectionCharacteristicsToProtect
[16] =
142 PAGE_NOACCESS
, /* 0 = NONE */
143 PAGE_NOACCESS
, /* 1 = SHARED */
144 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
145 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
146 PAGE_READONLY
, /* 4 = READABLE */
147 PAGE_READONLY
, /* 5 = READABLE, SHARED */
148 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
149 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
151 * FIXME? do we really need the WriteCopy field in segments? can't we use
152 * PAGE_WRITECOPY here?
154 PAGE_READWRITE
, /* 8 = WRITABLE */
155 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
156 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
157 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
158 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
159 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
160 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
161 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
164 extern ULONG MmMakeFileAccess
[];
165 ACCESS_MASK NTAPI
MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection
);
166 static GENERIC_MAPPING MmpSectionMapping
=
168 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
169 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
170 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
175 /* FUNCTIONS *****************************************************************/
180 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
181 File Format Specification", revision 6.0 (February 1999)
183 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
184 IN SIZE_T FileHeaderSize
,
186 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
188 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
189 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
192 ULONG cbFileHeaderOffsetSize
= 0;
193 ULONG cbSectionHeadersOffset
= 0;
194 ULONG cbSectionHeadersSize
;
195 ULONG cbSectionHeadersOffsetSize
= 0;
196 ULONG cbOptHeaderSize
;
197 ULONG cbHeadersSize
= 0;
198 ULONG nSectionAlignment
;
199 ULONG nFileAlignment
;
201 const IMAGE_DOS_HEADER
* pidhDosHeader
;
202 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
203 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
204 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
205 PMM_SECTION_SEGMENT pssSegments
;
206 LARGE_INTEGER lnOffset
;
208 SIZE_T nPrevVirtualEndOfSegment
= 0;
209 ULONG nFileSizeOfHeaders
= 0;
214 ASSERT(FileHeaderSize
> 0);
216 ASSERT(ImageSectionObject
);
218 ASSERT(AllocateSegmentsCb
);
220 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
222 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
224 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
227 pidhDosHeader
= FileHeader
;
230 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
232 /* image too small to be an MZ executable */
233 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
234 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
236 /* no MZ signature */
237 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
238 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
241 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
243 /* not a Windows executable */
244 if(pidhDosHeader
->e_lfanew
<= 0)
245 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
247 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
248 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
250 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
255 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
256 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
258 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
259 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
263 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
264 * need to read the header from the file
266 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
267 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
269 ULONG cbNtHeaderSize
;
273 l_ReadHeaderFromFile
:
275 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
277 /* read the header from the file */
278 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
280 if(!NT_SUCCESS(nStatus
))
282 NTSTATUS ReturnedStatus
= nStatus
;
284 /* If it attempted to read past the end of the file, it means e_lfanew is invalid */
285 if (ReturnedStatus
== STATUS_END_OF_FILE
) nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
287 DIE(("ReadFile failed, status %08X\n", ReturnedStatus
));
292 ASSERT(cbReadSize
> 0);
294 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
296 /* the buffer doesn't contain the file header */
297 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
298 DIE(("The file doesn't contain the PE file header\n"));
300 pinhNtHeader
= pData
;
302 /* object still not aligned: copy it to the beginning of the buffer */
303 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
305 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
306 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
307 pinhNtHeader
= pBuffer
;
310 /* invalid NT header */
311 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
313 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
314 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
316 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
318 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
319 DIE(("The full NT header is too large\n"));
321 /* the buffer doesn't contain the whole NT header */
322 if(cbReadSize
< cbNtHeaderSize
)
323 DIE(("The file doesn't contain the full NT header\n"));
327 ULONG cbOptHeaderOffsetSize
= 0;
329 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
331 /* don't trust an invalid NT header */
332 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
333 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
335 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
336 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
338 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
340 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
341 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
343 /* the buffer doesn't contain the whole NT header: read it from the file */
344 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
345 goto l_ReadHeaderFromFile
;
348 /* read information from the NT header */
349 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
350 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
352 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
354 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
355 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
357 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
359 switch(piohOptHeader
->Magic
)
361 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
363 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
368 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
371 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
372 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
374 /* See [1], section 3.4.2 */
375 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
377 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
378 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
380 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
381 DIE(("The section alignment is smaller than the file alignment\n"));
383 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
384 nFileAlignment
= piohOptHeader
->FileAlignment
;
386 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
387 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
391 nSectionAlignment
= PAGE_SIZE
;
392 nFileAlignment
= PAGE_SIZE
;
395 ASSERT(IsPowerOf2(nSectionAlignment
));
396 ASSERT(IsPowerOf2(nFileAlignment
));
398 switch(piohOptHeader
->Magic
)
401 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
403 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
404 ImageBase
= piohOptHeader
->ImageBase
;
406 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
407 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
409 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
410 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
412 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
413 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
415 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
417 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
419 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
420 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
422 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
423 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
427 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
429 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
430 piohOptHeader
->AddressOfEntryPoint
);
433 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
434 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
436 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
438 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
440 if (piohOptHeader
->AddressOfEntryPoint
== 0)
442 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
446 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
447 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
449 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
451 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
454 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
455 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
456 * magic to any binary.
458 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
459 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
460 * the SxS support -- at which point, duh, this should be removed.
462 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
464 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
471 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
473 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
475 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
477 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
479 ImageBase
= pioh64OptHeader
->ImageBase
;
480 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
481 DIE(("ImageBase exceeds the address space\n"));
484 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
486 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
487 DIE(("SizeOfImage exceeds the address space\n"));
489 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
492 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
494 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
495 DIE(("SizeOfStackReserve exceeds the address space\n"));
497 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
500 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
502 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
503 DIE(("SizeOfStackCommit exceeds the address space\n"));
505 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
508 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
510 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
512 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
513 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
515 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
516 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
520 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
522 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
523 pioh64OptHeader
->AddressOfEntryPoint
);
526 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
527 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
529 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
531 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
533 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
535 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
539 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
540 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
542 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
543 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
550 /* [1], section 3.4.2 */
551 if((ULONG_PTR
)ImageBase
% 0x10000)
552 DIE(("ImageBase is not aligned on a 64KB boundary"));
554 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
555 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
556 ImageSectionObject
->ImageInformation
.GpValue
= 0;
557 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
558 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
560 /* SECTION HEADERS */
561 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
563 /* see [1], section 3.3 */
564 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
565 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
568 * the additional segment is for the file's headers. They need to be present for
569 * the benefit of the dynamic loader (to locate exports, defaults for thread
570 * parameters, resources, etc.)
572 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
574 /* file offset for the section headers */
575 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
576 DIE(("Offset overflow\n"));
578 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
579 DIE(("Offset overflow\n"));
581 /* size of the section headers */
582 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
583 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
585 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
586 DIE(("Section headers too large\n"));
588 /* size of the executable's headers */
589 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
591 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
592 // DIE(("SizeOfHeaders is not aligned\n"));
594 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
595 DIE(("The section headers overflow SizeOfHeaders\n"));
597 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
599 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
600 DIE(("Overflow aligning the size of headers\n"));
607 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
608 /* WARNING: piohOptHeader IS NO LONGER USABLE */
609 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
611 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
612 pishSectionHeaders
= NULL
;
616 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
617 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
619 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
620 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
624 * the buffer doesn't contain the section headers, or the alignment is wrong:
625 * read the headers from the file
627 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
628 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
633 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
635 /* read the header from the file */
636 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
638 if(!NT_SUCCESS(nStatus
))
639 DIE(("ReadFile failed with status %08X\n", nStatus
));
643 ASSERT(cbReadSize
> 0);
645 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
647 /* the buffer doesn't contain all the section headers */
648 if(cbReadSize
< cbSectionHeadersSize
)
649 DIE(("The file doesn't contain all of the section headers\n"));
651 pishSectionHeaders
= pData
;
653 /* object still not aligned: copy it to the beginning of the buffer */
654 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
656 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
657 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
658 pishSectionHeaders
= pBuffer
;
663 /* allocate the segments */
664 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
665 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
667 if(ImageSectionObject
->Segments
== NULL
)
668 DIE(("AllocateSegments failed\n"));
670 /* initialize the headers segment */
671 pssSegments
= ImageSectionObject
->Segments
;
673 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
675 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
676 DIE(("Cannot align the size of the section headers\n"));
678 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
679 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
680 DIE(("Cannot align the size of the section headers\n"));
682 pssSegments
[0].Image
.FileOffset
= 0;
683 pssSegments
[0].Protection
= PAGE_READONLY
;
684 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
685 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
686 pssSegments
[0].Image
.VirtualAddress
= 0;
687 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
688 pssSegments
[0].WriteCopy
= TRUE
;
690 /* skip the headers segment */
693 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
695 /* convert the executable sections into segments. See also [1], section 4 */
696 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
698 ULONG nCharacteristics
;
700 /* validate the alignment */
701 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
702 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
704 /* sections must be contiguous, ordered by base address and non-overlapping */
705 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
706 DIE(("Memory gap between section %u and the previous\n", i
));
708 /* ignore explicit BSS sections */
709 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
711 /* validate the alignment */
713 /* Yes, this should be a multiple of FileAlignment, but there's
714 * stuff out there that isn't. We can cope with that
716 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
717 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
720 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
721 // DIE(("PointerToRawData[%u] is not aligned\n", i));
724 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
725 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
729 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
730 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
733 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
735 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
737 /* no explicit protection */
738 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
740 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
741 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
743 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
744 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
746 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
747 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
750 /* see table above */
751 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
752 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
754 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
755 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
757 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
759 AlignedLength
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
760 if(AlignedLength
< pssSegments
[i
].Length
.LowPart
)
761 DIE(("Cannot align the virtual size of section %u\n", i
));
763 pssSegments
[i
].Length
.LowPart
= AlignedLength
;
765 if(pssSegments
[i
].Length
.QuadPart
== 0)
766 DIE(("Virtual size of section %u is null\n", i
));
768 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
769 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
771 /* ensure the memory image is no larger than 4GB */
772 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
773 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
774 DIE(("The image is too large\n"));
777 if(nSectionAlignment
>= PAGE_SIZE
)
778 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
781 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
791 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
792 * ARGUMENTS: PFILE_OBJECT to wait for.
793 * RETURNS: Status of the wait.
796 MmspWaitForFileLock(PFILE_OBJECT File
)
798 return STATUS_SUCCESS
;
799 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
804 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
806 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
808 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
809 PMM_SECTION_SEGMENT SectionSegments
;
813 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
814 NrSegments
= ImageSectionObject
->NrSegments
;
815 SectionSegments
= ImageSectionObject
->Segments
;
816 for (i
= 0; i
< NrSegments
; i
++)
818 if (SectionSegments
[i
].ReferenceCount
!= 0)
820 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
821 SectionSegments
[i
].ReferenceCount
);
822 KeBugCheck(MEMORY_MANAGEMENT
);
824 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
826 ExFreePool(ImageSectionObject
->Segments
);
827 ExFreePool(ImageSectionObject
);
828 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
830 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
832 PMM_SECTION_SEGMENT Segment
;
834 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
837 if (Segment
->ReferenceCount
!= 0)
839 DPRINT1("Data segment still referenced\n");
840 KeBugCheck(MEMORY_MANAGEMENT
);
842 MmFreePageTablesSectionSegment(Segment
, NULL
);
844 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
850 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
851 PLARGE_INTEGER Offset
)
855 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
858 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
859 KeBugCheck(MEMORY_MANAGEMENT
);
861 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
863 DPRINT1("Maximum share count reached\n");
864 KeBugCheck(MEMORY_MANAGEMENT
);
866 if (IS_SWAP_FROM_SSE(Entry
))
868 KeBugCheck(MEMORY_MANAGEMENT
);
870 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
871 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
876 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
877 PMM_SECTION_SEGMENT Segment
,
878 PLARGE_INTEGER Offset
,
883 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
884 BOOLEAN IsDirectMapped
= FALSE
;
888 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
889 KeBugCheck(MEMORY_MANAGEMENT
);
891 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
893 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
894 KeBugCheck(MEMORY_MANAGEMENT
);
896 if (IS_SWAP_FROM_SSE(Entry
))
898 KeBugCheck(MEMORY_MANAGEMENT
);
900 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
902 * If we reducing the share count of this entry to zero then set the entry
903 * to zero and tell the cache the page is no longer mapped.
905 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
907 PFILE_OBJECT FileObject
;
908 SWAPENTRY SavedSwapEntry
;
911 PROS_SHARED_CACHE_MAP SharedCacheMap
;
912 BOOLEAN IsImageSection
;
913 LARGE_INTEGER FileOffset
;
915 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
916 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
919 Page
= PFN_FROM_SSE(Entry
);
920 FileObject
= Section
->FileObject
;
921 if (FileObject
!= NULL
&&
922 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
926 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
927 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
930 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
931 IsDirectMapped
= TRUE
;
933 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
.QuadPart
, Dirty
);
935 Status
= STATUS_SUCCESS
;
937 if (!NT_SUCCESS(Status
))
939 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
940 KeBugCheck(MEMORY_MANAGEMENT
);
946 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
947 if (SavedSwapEntry
== 0)
950 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
951 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
955 * Try to page out this page and set the swap entry
956 * within the section segment. There exist no rmap entry
957 * for this page. The pager thread can't page out a
958 * page without a rmap entry.
960 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
961 if (InEntry
) *InEntry
= Entry
;
962 MiSetPageEvent(NULL
, NULL
);
966 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
967 if (InEntry
) *InEntry
= 0;
968 MiSetPageEvent(NULL
, NULL
);
971 MmReleasePageMemoryConsumer(MC_USER
, Page
);
977 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
978 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
986 * We hold all locks. Nobody can do something with the current
987 * process and the current segment (also not within an other process).
990 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
991 if (!NT_SUCCESS(Status
))
993 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
994 KeBugCheck(MEMORY_MANAGEMENT
);
997 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
998 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
999 MmSetSavedSwapEntryPage(Page
, 0);
1000 MiSetPageEvent(NULL
, NULL
);
1002 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1006 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1007 KeBugCheck(MEMORY_MANAGEMENT
);
1016 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1018 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1021 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1025 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1027 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1029 SharedCacheMap
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1030 Vacb
= CcRosLookupVacb(SharedCacheMap
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
);
1033 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, FALSE
, TRUE
);
1043 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1047 PVOID DestAddress
, SrcAddress
;
1049 Process
= PsGetCurrentProcess();
1050 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1051 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1052 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1054 return(STATUS_NO_MEMORY
);
1056 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1057 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1058 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1059 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1060 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1061 return(STATUS_SUCCESS
);
1067 MiReadPage(PMEMORY_AREA MemoryArea
,
1071 * FUNCTION: Read a page for a section backed memory area.
1073 * MemoryArea - Memory area to read the page for.
1074 * Offset - Offset of the page to read.
1075 * Page - Variable that receives a page contains the read data.
1078 LONGLONG BaseOffset
;
1079 LONGLONG FileOffset
;
1083 PFILE_OBJECT FileObject
;
1086 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1087 BOOLEAN IsImageSection
;
1090 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1091 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1092 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
;
1093 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1094 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1096 ASSERT(SharedCacheMap
);
1098 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1101 * If the file system is letting us go directly to the cache and the
1102 * memory area was mapped at an offset in the file which is page aligned
1103 * then get the related VACB.
1105 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1106 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1107 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1111 * Get the related VACB; we use a lower level interface than
1112 * filesystems do because it is safe for us to use an offset with an
1113 * alignment less than the file system block size.
1115 Status
= CcRosGetVacb(SharedCacheMap
,
1121 if (!NT_SUCCESS(Status
))
1128 * If the VACB isn't up to date then call the file
1129 * system to read in the data.
1131 Status
= CcReadVirtualAddress(Vacb
);
1132 if (!NT_SUCCESS(Status
))
1134 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1139 /* Probe the page, since it's PDE might not be synced */
1140 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1143 * Retrieve the page from the view that we actually want.
1145 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1146 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1148 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, TRUE
);
1155 LONGLONG VacbOffset
;
1158 * Allocate a page, this is rather complicated by the possibility
1159 * we might have to move other things out of memory
1161 MI_SET_USAGE(MI_USAGE_SECTION
);
1162 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1163 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1164 if (!NT_SUCCESS(Status
))
1168 Status
= CcRosGetVacb(SharedCacheMap
,
1174 if (!NT_SUCCESS(Status
))
1181 * If the VACB isn't up to date then call the file
1182 * system to read in the data.
1184 Status
= CcReadVirtualAddress(Vacb
);
1185 if (!NT_SUCCESS(Status
))
1187 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1192 Process
= PsGetCurrentProcess();
1193 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1194 VacbOffset
= BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
;
1195 Length
= RawLength
- SegOffset
;
1196 if (Length
<= VacbOffset
&& Length
<= PAGE_SIZE
)
1198 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1200 else if (VacbOffset
>= PAGE_SIZE
)
1202 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1206 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, VacbOffset
);
1207 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1208 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1209 Status
= CcRosGetVacb(SharedCacheMap
,
1210 FileOffset
+ VacbOffset
,
1215 if (!NT_SUCCESS(Status
))
1222 * If the VACB isn't up to date then call the file
1223 * system to read in the data.
1225 Status
= CcReadVirtualAddress(Vacb
);
1226 if (!NT_SUCCESS(Status
))
1228 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1232 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1233 if (Length
< PAGE_SIZE
)
1235 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, Length
- VacbOffset
);
1239 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, PAGE_SIZE
- VacbOffset
);
1242 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1243 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1245 return(STATUS_SUCCESS
);
1250 MiReadPage(PMEMORY_AREA MemoryArea
,
1254 * FUNCTION: Read a page for a section backed memory area.
1256 * MemoryArea - Memory area to read the page for.
1257 * Offset - Offset of the page to read.
1258 * Page - Variable that receives a page contains the read data.
1261 MM_REQUIRED_RESOURCES Resources
;
1264 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1266 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1267 Resources
.FileOffset
.QuadPart
= SegOffset
+
1268 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1269 Resources
.Consumer
= MC_USER
;
1270 Resources
.Amount
= PAGE_SIZE
;
1272 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]);
1274 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1275 *Page
= Resources
.Page
[0];
1282 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1283 MEMORY_AREA
* MemoryArea
,
1287 LARGE_INTEGER Offset
;
1290 PROS_SECTION_OBJECT Section
;
1291 PMM_SECTION_SEGMENT Segment
;
1296 BOOLEAN HasSwapEntry
;
1298 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1299 SWAPENTRY SwapEntry
;
1302 * There is a window between taking the page fault and locking the
1303 * address space when another thread could load the page so we check
1306 if (MmIsPagePresent(Process
, Address
))
1308 return(STATUS_SUCCESS
);
1311 if (MmIsDisabledPage(Process
, Address
))
1313 return(STATUS_ACCESS_VIOLATION
);
1317 * Check for the virtual memory area being deleted.
1319 if (MemoryArea
->DeleteInProgress
)
1321 return(STATUS_UNSUCCESSFUL
);
1324 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1325 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1326 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1328 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1329 Section
= MemoryArea
->Data
.SectionData
.Section
;
1330 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1331 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1333 ASSERT(Region
!= NULL
);
1337 MmLockSectionSegment(Segment
);
1338 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1340 * Check if this page needs to be mapped COW
1342 if ((Segment
->WriteCopy
) &&
1343 (Region
->Protect
== PAGE_READWRITE
||
1344 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1346 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1350 Attributes
= Region
->Protect
;
1354 * Check if someone else is already handling this fault, if so wait
1357 if (Entry
&& MM_IS_WAIT_PTE(Entry
))
1359 MmUnlockSectionSegment(Segment
);
1360 MmUnlockAddressSpace(AddressSpace
);
1361 MiWaitForPageEvent(NULL
, NULL
);
1362 MmLockAddressSpace(AddressSpace
);
1363 DPRINT("Address 0x%p\n", Address
);
1364 return(STATUS_MM_RESTART_OPERATION
);
1367 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1369 /* See if we should use a private page */
1370 if ((HasSwapEntry
) || (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
))
1372 SWAPENTRY DummyEntry
;
1375 * Is it a wait entry?
1379 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1381 if (SwapEntry
== MM_WAIT_ENTRY
)
1383 MmUnlockSectionSegment(Segment
);
1384 MmUnlockAddressSpace(AddressSpace
);
1385 MiWaitForPageEvent(NULL
, NULL
);
1386 MmLockAddressSpace(AddressSpace
);
1387 return STATUS_MM_RESTART_OPERATION
;
1391 * Must be private page we have swapped out.
1397 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1399 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1400 KeBugCheck(MEMORY_MANAGEMENT
);
1402 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1405 MmUnlockSectionSegment(Segment
);
1407 /* Tell everyone else we are serving the fault. */
1408 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1410 MmUnlockAddressSpace(AddressSpace
);
1411 MI_SET_USAGE(MI_USAGE_SECTION
);
1412 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1413 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1414 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1415 if (!NT_SUCCESS(Status
))
1417 KeBugCheck(MEMORY_MANAGEMENT
);
1422 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1423 if (!NT_SUCCESS(Status
))
1425 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1426 KeBugCheck(MEMORY_MANAGEMENT
);
1430 MmLockAddressSpace(AddressSpace
);
1431 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1432 Status
= MmCreateVirtualMapping(Process
,
1437 if (!NT_SUCCESS(Status
))
1439 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1440 KeBugCheck(MEMORY_MANAGEMENT
);
1445 * Store the swap entry for later use.
1448 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1451 * Add the page to the process's working set
1453 MmInsertRmap(Page
, Process
, Address
);
1455 * Finish the operation
1457 MiSetPageEvent(Process
, Address
);
1458 DPRINT("Address 0x%p\n", Address
);
1459 return(STATUS_SUCCESS
);
1463 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1465 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1467 MmUnlockSectionSegment(Segment
);
1469 * Just map the desired physical page
1471 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1472 Status
= MmCreateVirtualMappingUnsafe(Process
,
1477 if (!NT_SUCCESS(Status
))
1479 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1480 KeBugCheck(MEMORY_MANAGEMENT
);
1485 * Cleanup and release locks
1487 MiSetPageEvent(Process
, Address
);
1488 DPRINT("Address 0x%p\n", Address
);
1489 return(STATUS_SUCCESS
);
1493 * Get the entry corresponding to the offset within the section
1495 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1499 SWAPENTRY FakeSwapEntry
;
1502 * If the entry is zero (and it can't change because we have
1503 * locked the segment) then we need to load the page.
1507 * Release all our locks and read in the page from disk
1509 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1510 MmUnlockSectionSegment(Segment
);
1511 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1512 MmUnlockAddressSpace(AddressSpace
);
1514 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1515 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1516 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1518 MI_SET_USAGE(MI_USAGE_SECTION
);
1519 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1520 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1521 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1522 if (!NT_SUCCESS(Status
))
1524 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1530 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1531 if (!NT_SUCCESS(Status
))
1533 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1536 if (!NT_SUCCESS(Status
))
1539 * FIXME: What do we know in this case?
1542 * Cleanup and release locks
1544 MmLockAddressSpace(AddressSpace
);
1545 MiSetPageEvent(Process
, Address
);
1546 DPRINT("Address 0x%p\n", Address
);
1550 /* Lock both segment and process address space while we proceed. */
1551 MmLockAddressSpace(AddressSpace
);
1552 MmLockSectionSegment(Segment
);
1554 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1555 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1556 Page
, Process
, PAddress
, Attributes
);
1557 Status
= MmCreateVirtualMapping(Process
,
1562 if (!NT_SUCCESS(Status
))
1564 DPRINT1("Unable to create virtual mapping\n");
1565 KeBugCheck(MEMORY_MANAGEMENT
);
1567 ASSERT(MmIsPagePresent(Process
, PAddress
));
1568 MmInsertRmap(Page
, Process
, Address
);
1570 /* Set this section offset has being backed by our new page. */
1571 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1572 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1573 MmUnlockSectionSegment(Segment
);
1575 MiSetPageEvent(Process
, Address
);
1576 DPRINT("Address 0x%p\n", Address
);
1577 return(STATUS_SUCCESS
);
1579 else if (IS_SWAP_FROM_SSE(Entry
))
1581 SWAPENTRY SwapEntry
;
1583 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1585 /* See if a page op is running on this segment. */
1586 if (SwapEntry
== MM_WAIT_ENTRY
)
1588 MmUnlockSectionSegment(Segment
);
1589 MmUnlockAddressSpace(AddressSpace
);
1590 MiWaitForPageEvent(NULL
, NULL
);
1591 MmLockAddressSpace(AddressSpace
);
1592 return STATUS_MM_RESTART_OPERATION
;
1596 * Release all our locks and read in the page from disk
1598 MmUnlockSectionSegment(Segment
);
1600 MmUnlockAddressSpace(AddressSpace
);
1601 MI_SET_USAGE(MI_USAGE_SECTION
);
1602 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1603 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1604 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1605 if (!NT_SUCCESS(Status
))
1607 KeBugCheck(MEMORY_MANAGEMENT
);
1610 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1611 if (!NT_SUCCESS(Status
))
1613 KeBugCheck(MEMORY_MANAGEMENT
);
1617 * Relock the address space and segment
1619 MmLockAddressSpace(AddressSpace
);
1620 MmLockSectionSegment(Segment
);
1623 * Check the entry. No one should change the status of a page
1624 * that has a pending page-in.
1626 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1627 if (Entry
!= Entry1
)
1629 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1630 KeBugCheck(MEMORY_MANAGEMENT
);
1634 * Save the swap entry.
1636 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1638 /* Map the page into the process address space */
1639 Status
= MmCreateVirtualMapping(Process
,
1644 if (!NT_SUCCESS(Status
))
1646 DPRINT1("Unable to create virtual mapping\n");
1647 KeBugCheck(MEMORY_MANAGEMENT
);
1649 MmInsertRmap(Page
, Process
, Address
);
1652 * Mark the offset within the section as having valid, in-memory
1655 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1656 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1657 MmUnlockSectionSegment(Segment
);
1659 MiSetPageEvent(Process
, Address
);
1660 DPRINT("Address 0x%p\n", Address
);
1661 return(STATUS_SUCCESS
);
1665 /* We already have a page on this section offset. Map it into the process address space. */
1666 Page
= PFN_FROM_SSE(Entry
);
1668 Status
= MmCreateVirtualMapping(Process
,
1673 if (!NT_SUCCESS(Status
))
1675 DPRINT1("Unable to create virtual mapping\n");
1676 KeBugCheck(MEMORY_MANAGEMENT
);
1678 MmInsertRmap(Page
, Process
, Address
);
1680 /* Take a reference on it */
1681 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1682 MmUnlockSectionSegment(Segment
);
1684 MiSetPageEvent(Process
, Address
);
1685 DPRINT("Address 0x%p\n", Address
);
1686 return(STATUS_SUCCESS
);
1692 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1693 MEMORY_AREA
* MemoryArea
,
1696 PMM_SECTION_SEGMENT Segment
;
1697 PROS_SECTION_OBJECT Section
;
1702 LARGE_INTEGER Offset
;
1705 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1707 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1709 /* Make sure we have a page mapping for this address. */
1710 Status
= MmNotPresentFaultSectionView(AddressSpace
, MemoryArea
, Address
, TRUE
);
1711 if (!NT_SUCCESS(Status
))
1713 /* This is invalid access ! */
1718 * Check if the page has already been set readwrite
1720 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1722 DPRINT("Address 0x%p\n", Address
);
1723 return(STATUS_SUCCESS
);
1727 * Find the offset of the page
1729 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1730 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1731 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1733 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1734 Section
= MemoryArea
->Data
.SectionData
.Section
;
1735 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1736 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1738 ASSERT(Region
!= NULL
);
1741 * Check if we are doing COW
1743 if (!((Segment
->WriteCopy
) &&
1744 (Region
->Protect
== PAGE_READWRITE
||
1745 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1747 DPRINT("Address 0x%p\n", Address
);
1748 return(STATUS_ACCESS_VIOLATION
);
1751 /* Get the page mapping this section offset. */
1752 MmLockSectionSegment(Segment
);
1753 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1755 /* Get the current page mapping for the process */
1756 ASSERT(MmIsPagePresent(Process
, PAddress
));
1757 OldPage
= MmGetPfnForProcess(Process
, PAddress
);
1758 ASSERT(OldPage
!= 0);
1760 if (IS_SWAP_FROM_SSE(Entry
) ||
1761 PFN_FROM_SSE(Entry
) != OldPage
)
1763 MmUnlockSectionSegment(Segment
);
1764 /* This is a private page. We must only change the page protection. */
1765 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1766 return(STATUS_SUCCESS
);
1772 MI_SET_USAGE(MI_USAGE_SECTION
);
1773 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1774 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1775 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1776 if (!NT_SUCCESS(Status
))
1778 KeBugCheck(MEMORY_MANAGEMENT
);
1784 MiCopyFromUserPage(NewPage
, OldPage
);
1787 * Unshare the old page.
1789 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1790 MmDeleteVirtualMapping(Process
, PAddress
, NULL
, NULL
);
1791 MmDeleteRmap(OldPage
, Process
, PAddress
);
1792 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1793 MmUnlockSectionSegment(Segment
);
1796 * Set the PTE to point to the new page
1798 Status
= MmCreateVirtualMapping(Process
,
1803 if (!NT_SUCCESS(Status
))
1805 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1806 KeBugCheck(MEMORY_MANAGEMENT
);
1809 MmInsertRmap(NewPage
, Process
, PAddress
);
1811 MiSetPageEvent(Process
, Address
);
1812 DPRINT("Address 0x%p\n", Address
);
1813 return(STATUS_SUCCESS
);
1817 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1819 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1821 PFN_NUMBER Page
= 0;
1823 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1826 MmLockAddressSpace(&Process
->Vm
);
1829 MmDeleteVirtualMapping(Process
,
1835 PageOutContext
->WasDirty
= TRUE
;
1837 if (!PageOutContext
->Private
)
1839 MmLockSectionSegment(PageOutContext
->Segment
);
1840 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1841 PageOutContext
->Segment
,
1842 &PageOutContext
->Offset
,
1843 PageOutContext
->WasDirty
,
1845 &PageOutContext
->SectionEntry
);
1846 MmUnlockSectionSegment(PageOutContext
->Segment
);
1850 MmUnlockAddressSpace(&Process
->Vm
);
1853 if (PageOutContext
->Private
)
1855 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1861 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1862 MEMORY_AREA
* MemoryArea
,
1863 PVOID Address
, ULONG_PTR Entry
)
1866 MM_SECTION_PAGEOUT_CONTEXT Context
;
1867 SWAPENTRY SwapEntry
;
1870 ULONGLONG FileOffset
;
1871 PFILE_OBJECT FileObject
;
1872 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1873 BOOLEAN IsImageSection
;
1875 BOOLEAN DirectMapped
;
1876 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1879 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1882 * Get the segment and section.
1884 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1885 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1886 Context
.SectionEntry
= Entry
;
1887 Context
.CallingProcess
= Process
;
1889 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
1890 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1892 DirectMapped
= FALSE
;
1894 MmLockSectionSegment(Context
.Segment
);
1897 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1898 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1899 FileObject
= Context
.Section
->FileObject
;
1901 if (FileObject
!= NULL
&&
1902 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1904 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1907 * If the file system is letting us go directly to the cache and the
1908 * memory area was mapped at an offset in the file which is page aligned
1909 * then note this is a direct mapped page.
1911 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1912 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1914 DirectMapped
= TRUE
;
1921 * This should never happen since mappings of physical memory are never
1922 * placed in the rmap lists.
1924 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1926 DPRINT1("Trying to page out from physical memory section address 0x%p "
1927 "process %p\n", Address
,
1928 Process
? Process
->UniqueProcessId
: 0);
1929 KeBugCheck(MEMORY_MANAGEMENT
);
1933 * Get the section segment entry and the physical address.
1935 if (!MmIsPagePresent(Process
, Address
))
1937 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1938 Process
? Process
->UniqueProcessId
: 0, Address
);
1939 KeBugCheck(MEMORY_MANAGEMENT
);
1941 Page
= MmGetPfnForProcess(Process
, Address
);
1942 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1945 * Check the reference count to ensure this page can be paged out
1947 if (MmGetReferenceCountPage(Page
) != 1)
1949 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1950 Page
, MmGetReferenceCountPage(Page
));
1951 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1952 MmUnlockSectionSegment(Context
.Segment
);
1953 return STATUS_UNSUCCESSFUL
;
1957 * Prepare the context structure for the rmap delete call.
1959 MmUnlockSectionSegment(Context
.Segment
);
1960 Context
.WasDirty
= FALSE
;
1961 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1962 IS_SWAP_FROM_SSE(Entry
) ||
1963 PFN_FROM_SSE(Entry
) != Page
)
1965 Context
.Private
= TRUE
;
1969 Context
.Private
= FALSE
;
1973 * Take an additional reference to the page or the VACB.
1975 if (DirectMapped
&& !Context
.Private
)
1977 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
1979 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1980 KeBugCheck(MEMORY_MANAGEMENT
);
1985 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1986 MmReferencePage(Page
);
1987 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1990 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1992 /* Since we passed in a surrogate, we'll get back the page entry
1993 * state in our context. This is intended to make intermediate
1994 * decrements of share count not release the wait entry.
1996 Entry
= Context
.SectionEntry
;
1999 * If this wasn't a private page then we should have reduced the entry to
2000 * zero by deleting all the rmaps.
2002 if (!Context
.Private
&& Entry
!= 0)
2004 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2005 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2007 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2012 * If the page wasn't dirty then we can just free it as for a readonly page.
2013 * Since we unmapped all the mappings above we know it will not suddenly
2015 * If the page is from a pagefile section and has no swap entry,
2016 * we can't free the page at this point.
2018 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2019 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2021 if (Context
.Private
)
2023 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2024 Context
.WasDirty
? "dirty" : "clean", Address
);
2025 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2027 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2029 MmSetSavedSwapEntryPage(Page
, 0);
2030 MmLockSectionSegment(Context
.Segment
);
2031 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2032 MmUnlockSectionSegment(Context
.Segment
);
2033 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2034 MiSetPageEvent(NULL
, NULL
);
2035 return(STATUS_SUCCESS
);
2038 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2040 if (Context
.Private
)
2042 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2043 Context
.WasDirty
? "dirty" : "clean", Address
);
2044 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2046 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2048 MmSetSavedSwapEntryPage(Page
, 0);
2051 MmLockSectionSegment(Context
.Segment
);
2052 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2053 MmUnlockSectionSegment(Context
.Segment
);
2055 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2056 MiSetPageEvent(NULL
, NULL
);
2057 return(STATUS_SUCCESS
);
2060 else if (!Context
.Private
&& DirectMapped
)
2064 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2066 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2069 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
, FALSE
);
2071 Status
= STATUS_SUCCESS
;
2074 if (!NT_SUCCESS(Status
))
2076 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2077 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2080 MiSetPageEvent(NULL
, NULL
);
2081 return(STATUS_SUCCESS
);
2083 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2087 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2089 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2091 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2092 MiSetPageEvent(NULL
, NULL
);
2093 return(STATUS_SUCCESS
);
2095 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2097 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2098 MmSetSavedSwapEntryPage(Page
, 0);
2099 MmLockAddressSpace(AddressSpace
);
2100 Status
= MmCreatePageFileMapping(Process
,
2103 MmUnlockAddressSpace(AddressSpace
);
2104 if (!NT_SUCCESS(Status
))
2106 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2107 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2109 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2110 MiSetPageEvent(NULL
, NULL
);
2111 return(STATUS_SUCCESS
);
2115 * If necessary, allocate an entry in the paging file for this page
2119 SwapEntry
= MmAllocSwapPage();
2122 MmShowOutOfSpaceMessagePagingFile();
2123 MmLockAddressSpace(AddressSpace
);
2125 * For private pages restore the old mappings.
2127 if (Context
.Private
)
2129 Status
= MmCreateVirtualMapping(Process
,
2131 MemoryArea
->Protect
,
2134 MmSetDirtyPage(Process
, Address
);
2143 MmLockSectionSegment(Context
.Segment
);
2146 * For non-private pages if the page wasn't direct mapped then
2147 * set it back into the section segment entry so we don't loose
2148 * our copy. Otherwise it will be handled by the cache manager.
2150 Status
= MmCreateVirtualMapping(Process
,
2152 MemoryArea
->Protect
,
2155 MmSetDirtyPage(Process
, Address
);
2159 // If we got here, the previous entry should have been a wait
2160 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2161 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2162 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2163 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2164 MmUnlockSectionSegment(Context
.Segment
);
2166 MmUnlockAddressSpace(AddressSpace
);
2167 MiSetPageEvent(NULL
, NULL
);
2168 return(STATUS_PAGEFILE_QUOTA
);
2173 * Write the page to the pagefile
2175 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2176 if (!NT_SUCCESS(Status
))
2178 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2181 * As above: undo our actions.
2182 * FIXME: Also free the swap page.
2184 MmLockAddressSpace(AddressSpace
);
2185 if (Context
.Private
)
2187 Status
= MmCreateVirtualMapping(Process
,
2189 MemoryArea
->Protect
,
2192 MmSetDirtyPage(Process
, Address
);
2199 MmLockSectionSegment(Context
.Segment
);
2200 Status
= MmCreateVirtualMapping(Process
,
2202 MemoryArea
->Protect
,
2205 MmSetDirtyPage(Process
, Address
);
2209 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2210 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2211 MmUnlockSectionSegment(Context
.Segment
);
2213 MmUnlockAddressSpace(AddressSpace
);
2214 MiSetPageEvent(NULL
, NULL
);
2215 return(STATUS_UNSUCCESSFUL
);
2219 * Otherwise we have succeeded.
2221 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2222 MmSetSavedSwapEntryPage(Page
, 0);
2223 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2224 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2226 MmLockSectionSegment(Context
.Segment
);
2227 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2228 MmUnlockSectionSegment(Context
.Segment
);
2232 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2235 if (Context
.Private
)
2237 MmLockAddressSpace(AddressSpace
);
2238 MmLockSectionSegment(Context
.Segment
);
2239 Status
= MmCreatePageFileMapping(Process
,
2242 /* We had placed a wait entry upon entry ... replace it before leaving */
2243 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2244 MmUnlockSectionSegment(Context
.Segment
);
2245 MmUnlockAddressSpace(AddressSpace
);
2246 if (!NT_SUCCESS(Status
))
2248 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2249 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2254 MmLockAddressSpace(AddressSpace
);
2255 MmLockSectionSegment(Context
.Segment
);
2256 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2257 /* We had placed a wait entry upon entry ... replace it before leaving */
2258 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2259 MmUnlockSectionSegment(Context
.Segment
);
2260 MmUnlockAddressSpace(AddressSpace
);
2263 MiSetPageEvent(NULL
, NULL
);
2264 return(STATUS_SUCCESS
);
2269 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2270 PMEMORY_AREA MemoryArea
,
2274 LARGE_INTEGER Offset
;
2275 PROS_SECTION_OBJECT Section
;
2276 PMM_SECTION_SEGMENT Segment
;
2278 SWAPENTRY SwapEntry
;
2282 PFILE_OBJECT FileObject
;
2284 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2286 BOOLEAN DirectMapped
;
2287 BOOLEAN IsImageSection
;
2288 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2290 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2292 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2293 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2296 * Get the segment and section.
2298 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2299 Section
= MemoryArea
->Data
.SectionData
.Section
;
2300 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2302 FileObject
= Section
->FileObject
;
2303 DirectMapped
= FALSE
;
2304 if (FileObject
!= NULL
&&
2305 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2308 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2312 * If the file system is letting us go directly to the cache and the
2313 * memory area was mapped at an offset in the file which is page aligned
2314 * then note this is a direct mapped page.
2316 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2317 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2319 DirectMapped
= TRUE
;
2324 * This should never happen since mappings of physical memory are never
2325 * placed in the rmap lists.
2327 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2329 DPRINT1("Trying to write back page from physical memory mapped at %p "
2330 "process %p\n", Address
,
2331 Process
? Process
->UniqueProcessId
: 0);
2332 KeBugCheck(MEMORY_MANAGEMENT
);
2336 * Get the section segment entry and the physical address.
2338 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2339 if (!MmIsPagePresent(Process
, Address
))
2341 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2342 Process
? Process
->UniqueProcessId
: 0, Address
);
2343 KeBugCheck(MEMORY_MANAGEMENT
);
2345 Page
= MmGetPfnForProcess(Process
, Address
);
2346 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2349 * Check for a private (COWed) page.
2351 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2352 IS_SWAP_FROM_SSE(Entry
) ||
2353 PFN_FROM_SSE(Entry
) != Page
)
2363 * Speculatively set all mappings of the page to clean.
2365 MmSetCleanAllRmaps(Page
);
2368 * If this page was direct mapped from the cache then the cache manager
2369 * will take care of writing it back to disk.
2371 if (DirectMapped
&& !Private
)
2373 //LARGE_INTEGER SOffset;
2374 ASSERT(SwapEntry
== 0);
2375 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2377 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
);
2379 MmLockSectionSegment(Segment
);
2380 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2381 MmUnlockSectionSegment(Segment
);
2382 MiSetPageEvent(NULL
, NULL
);
2383 return(STATUS_SUCCESS
);
2387 * If necessary, allocate an entry in the paging file for this page
2391 SwapEntry
= MmAllocSwapPage();
2394 MmSetDirtyAllRmaps(Page
);
2395 MiSetPageEvent(NULL
, NULL
);
2396 return(STATUS_PAGEFILE_QUOTA
);
2398 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2402 * Write the page to the pagefile
2404 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2405 if (!NT_SUCCESS(Status
))
2407 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2409 MmSetDirtyAllRmaps(Page
);
2410 MiSetPageEvent(NULL
, NULL
);
2411 return(STATUS_UNSUCCESSFUL
);
2415 * Otherwise we have succeeded.
2417 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2418 MiSetPageEvent(NULL
, NULL
);
2419 return(STATUS_SUCCESS
);
2423 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2431 PMEMORY_AREA MemoryArea
;
2432 PMM_SECTION_SEGMENT Segment
;
2433 BOOLEAN DoCOW
= FALSE
;
2435 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2437 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2438 ASSERT(MemoryArea
!= NULL
);
2439 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2440 MmLockSectionSegment(Segment
);
2442 if ((Segment
->WriteCopy
) &&
2443 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2448 if (OldProtect
!= NewProtect
)
2450 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2452 SWAPENTRY SwapEntry
;
2453 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2454 ULONG Protect
= NewProtect
;
2456 /* Wait for a wait entry to disappear */
2459 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2460 if (SwapEntry
!= MM_WAIT_ENTRY
)
2462 MiWaitForPageEvent(Process
, Address
);
2467 * If we doing COW for this segment then check if the page is
2470 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2472 LARGE_INTEGER Offset
;
2476 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2477 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2478 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2480 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2481 * IS_SWAP_FROM_SSE and we'll do the right thing.
2483 Page
= MmGetPfnForProcess(Process
, Address
);
2485 Protect
= PAGE_READONLY
;
2486 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2487 IS_SWAP_FROM_SSE(Entry
) ||
2488 PFN_FROM_SSE(Entry
) != Page
)
2490 Protect
= NewProtect
;
2494 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2496 MmSetPageProtect(Process
, Address
,
2502 MmUnlockSectionSegment(Segment
);
2507 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2508 PMEMORY_AREA MemoryArea
,
2516 ULONG_PTR MaxLength
;
2518 MaxLength
= MA_GetEndingAddress(MemoryArea
) - (ULONG_PTR
)BaseAddress
;
2519 if (Length
> MaxLength
)
2520 Length
= (ULONG
)MaxLength
;
2522 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2523 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2525 ASSERT(Region
!= NULL
);
2527 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2528 Region
->Protect
!= Protect
)
2530 return STATUS_INVALID_PAGE_PROTECTION
;
2533 *OldProtect
= Region
->Protect
;
2534 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
2535 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2536 BaseAddress
, Length
, Region
->Type
, Protect
,
2537 MmAlterViewAttributes
);
2543 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2545 PMEMORY_BASIC_INFORMATION Info
,
2546 PSIZE_T ResultLength
)
2549 PVOID RegionBaseAddress
;
2550 PROS_SECTION_OBJECT Section
;
2551 PMM_SECTION_SEGMENT Segment
;
2553 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2554 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2555 Address
, &RegionBaseAddress
);
2558 return STATUS_UNSUCCESSFUL
;
2561 Section
= MemoryArea
->Data
.SectionData
.Section
;
2562 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2564 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2565 Info
->AllocationBase
= (PUCHAR
)MA_GetStartingAddress(MemoryArea
) - Segment
->Image
.VirtualAddress
;
2566 Info
->Type
= MEM_IMAGE
;
2570 Info
->AllocationBase
= (PVOID
)MA_GetStartingAddress(MemoryArea
);
2571 Info
->Type
= MEM_MAPPED
;
2573 Info
->BaseAddress
= RegionBaseAddress
;
2574 Info
->AllocationProtect
= MemoryArea
->Protect
;
2575 Info
->RegionSize
= Region
->Length
;
2576 Info
->State
= MEM_COMMIT
;
2577 Info
->Protect
= Region
->Protect
;
2579 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2580 return(STATUS_SUCCESS
);
2585 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2588 LARGE_INTEGER Offset
;
2590 SWAPENTRY SavedSwapEntry
;
2595 MmLockSectionSegment(Segment
);
2597 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2598 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2600 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2603 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2604 if (IS_SWAP_FROM_SSE(Entry
))
2606 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2610 Page
= PFN_FROM_SSE(Entry
);
2611 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2612 if (SavedSwapEntry
!= 0)
2614 MmSetSavedSwapEntryPage(Page
, 0);
2615 MmFreeSwapPage(SavedSwapEntry
);
2617 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2622 MmUnlockSectionSegment(Segment
);
2626 MmpDeleteSection(PVOID ObjectBody
)
2628 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2630 /* Check if it's an ARM3, or ReactOS section */
2631 if (!MiIsRosSectionObject(Section
))
2633 MiDeleteARM3Section(ObjectBody
);
2637 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2638 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2643 PMM_SECTION_SEGMENT SectionSegments
;
2646 * NOTE: Section->ImageSection can be NULL for short time
2647 * during the section creating. If we fail for some reason
2648 * until the image section is properly initialized we shouldn't
2649 * process further here.
2651 if (Section
->ImageSection
== NULL
)
2654 SectionSegments
= Section
->ImageSection
->Segments
;
2655 NrSegments
= Section
->ImageSection
->NrSegments
;
2657 for (i
= 0; i
< NrSegments
; i
++)
2659 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2661 MmLockSectionSegment(&SectionSegments
[i
]);
2663 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2664 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2666 MmUnlockSectionSegment(&SectionSegments
[i
]);
2669 MmpFreePageFileSegment(&SectionSegments
[i
]);
2675 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2678 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2681 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2683 DPRINT("Freeing section segment\n");
2684 Section
->Segment
= NULL
;
2685 MmFinalizeSegment(Segment
);
2689 DPRINT("RefCount %d\n", RefCount
);
2696 * NOTE: Section->Segment can be NULL for short time
2697 * during the section creating.
2699 if (Section
->Segment
== NULL
)
2702 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2704 MmpFreePageFileSegment(Section
->Segment
);
2705 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2706 ExFreePool(Section
->Segment
);
2707 Section
->Segment
= NULL
;
2711 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2714 if (Section
->FileObject
!= NULL
)
2717 CcRosDereferenceCache(Section
->FileObject
);
2719 ObDereferenceObject(Section
->FileObject
);
2720 Section
->FileObject
= NULL
;
2725 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2727 IN ACCESS_MASK GrantedAccess
,
2728 IN ULONG ProcessHandleCount
,
2729 IN ULONG SystemHandleCount
)
2731 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2737 MmCreatePhysicalMemorySection(VOID
)
2739 PROS_SECTION_OBJECT PhysSection
;
2741 OBJECT_ATTRIBUTES Obj
;
2742 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2743 LARGE_INTEGER SectionSize
;
2747 * Create the section mapping physical memory
2749 SectionSize
.QuadPart
= 0xFFFFFFFF;
2750 InitializeObjectAttributes(&Obj
,
2752 OBJ_PERMANENT
| OBJ_KERNEL_EXCLUSIVE
,
2755 Status
= MmCreateSection((PVOID
)&PhysSection
,
2759 PAGE_EXECUTE_READWRITE
,
2763 if (!NT_SUCCESS(Status
))
2765 DPRINT1("Failed to create PhysicalMemory section\n");
2766 KeBugCheck(MEMORY_MANAGEMENT
);
2768 Status
= ObInsertObject(PhysSection
,
2774 if (!NT_SUCCESS(Status
))
2776 ObDereferenceObject(PhysSection
);
2778 ObCloseHandle(Handle
, KernelMode
);
2779 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2780 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2782 return(STATUS_SUCCESS
);
2788 MmInitSectionImplementation(VOID
)
2790 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2791 UNICODE_STRING Name
;
2793 DPRINT("Creating Section Object Type\n");
2795 /* Initialize the section based root */
2796 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2797 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2799 /* Initialize the Section object type */
2800 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2801 RtlInitUnicodeString(&Name
, L
"Section");
2802 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2803 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2804 ObjectTypeInitializer
.PoolType
= PagedPool
;
2805 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2806 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2807 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2808 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2809 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2810 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2811 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2813 MmCreatePhysicalMemorySection();
2815 return(STATUS_SUCCESS
);
2820 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2821 ACCESS_MASK DesiredAccess
,
2822 POBJECT_ATTRIBUTES ObjectAttributes
,
2823 PLARGE_INTEGER UMaximumSize
,
2824 ULONG SectionPageProtection
,
2825 ULONG AllocationAttributes
)
2827 * Create a section which is backed by the pagefile
2830 LARGE_INTEGER MaximumSize
;
2831 PROS_SECTION_OBJECT Section
;
2832 PMM_SECTION_SEGMENT Segment
;
2835 if (UMaximumSize
== NULL
)
2837 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2838 return(STATUS_INVALID_PARAMETER
);
2840 MaximumSize
= *UMaximumSize
;
2843 * Create the section
2845 Status
= ObCreateObject(ExGetPreviousMode(),
2846 MmSectionObjectType
,
2848 ExGetPreviousMode(),
2850 sizeof(ROS_SECTION_OBJECT
),
2853 (PVOID
*)(PVOID
)&Section
);
2854 if (!NT_SUCCESS(Status
))
2856 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2863 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2864 Section
->Type
= 'SC';
2865 Section
->Size
= 'TN';
2866 Section
->SectionPageProtection
= SectionPageProtection
;
2867 Section
->AllocationAttributes
= AllocationAttributes
;
2868 Section
->MaximumSize
= MaximumSize
;
2869 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2870 TAG_MM_SECTION_SEGMENT
);
2871 if (Segment
== NULL
)
2873 ObDereferenceObject(Section
);
2874 return(STATUS_NO_MEMORY
);
2876 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2877 Section
->Segment
= Segment
;
2878 Segment
->ReferenceCount
= 1;
2879 ExInitializeFastMutex(&Segment
->Lock
);
2880 Segment
->Image
.FileOffset
= 0;
2881 Segment
->Protection
= SectionPageProtection
;
2882 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2883 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2884 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2885 Segment
->WriteCopy
= FALSE
;
2886 Segment
->Image
.VirtualAddress
= 0;
2887 Segment
->Image
.Characteristics
= 0;
2888 *SectionObject
= Section
;
2889 MiInitializeSectionPageTable(Segment
);
2890 return(STATUS_SUCCESS
);
2895 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2896 ACCESS_MASK DesiredAccess
,
2897 POBJECT_ATTRIBUTES ObjectAttributes
,
2898 PLARGE_INTEGER UMaximumSize
,
2899 ULONG SectionPageProtection
,
2900 ULONG AllocationAttributes
,
2903 * Create a section backed by a data file
2906 PROS_SECTION_OBJECT Section
;
2908 LARGE_INTEGER MaximumSize
;
2909 PFILE_OBJECT FileObject
;
2910 PMM_SECTION_SEGMENT Segment
;
2912 IO_STATUS_BLOCK Iosb
;
2913 LARGE_INTEGER Offset
;
2915 FILE_STANDARD_INFORMATION FileInfo
;
2919 * Create the section
2921 Status
= ObCreateObject(ExGetPreviousMode(),
2922 MmSectionObjectType
,
2924 ExGetPreviousMode(),
2926 sizeof(ROS_SECTION_OBJECT
),
2930 if (!NT_SUCCESS(Status
))
2937 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2938 Section
->Type
= 'SC';
2939 Section
->Size
= 'TN';
2940 Section
->SectionPageProtection
= SectionPageProtection
;
2941 Section
->AllocationAttributes
= AllocationAttributes
;
2944 * Reference the file handle
2946 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2947 Status
= ObReferenceObjectByHandle(FileHandle
,
2950 ExGetPreviousMode(),
2951 (PVOID
*)(PVOID
)&FileObject
,
2953 if (!NT_SUCCESS(Status
))
2955 ObDereferenceObject(Section
);
2960 * FIXME: This is propably not entirely correct. We can't look into
2961 * the standard FCB header because it might not be initialized yet
2962 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2963 * standard file information is filled on first request).
2965 Status
= IoQueryFileInformation(FileObject
,
2966 FileStandardInformation
,
2967 sizeof(FILE_STANDARD_INFORMATION
),
2970 Iosb
.Information
= Length
;
2971 if (!NT_SUCCESS(Status
))
2973 ObDereferenceObject(Section
);
2974 ObDereferenceObject(FileObject
);
2979 * FIXME: Revise this once a locking order for file size changes is
2982 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2984 MaximumSize
= *UMaximumSize
;
2988 MaximumSize
= FileInfo
.EndOfFile
;
2989 /* Mapping zero-sized files isn't allowed. */
2990 if (MaximumSize
.QuadPart
== 0)
2992 ObDereferenceObject(Section
);
2993 ObDereferenceObject(FileObject
);
2994 return STATUS_MAPPED_FILE_SIZE_ZERO
;
2998 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3000 Status
= IoSetInformation(FileObject
,
3001 FileEndOfFileInformation
,
3002 sizeof(LARGE_INTEGER
),
3004 if (!NT_SUCCESS(Status
))
3006 ObDereferenceObject(Section
);
3007 ObDereferenceObject(FileObject
);
3008 return(STATUS_SECTION_NOT_EXTENDED
);
3012 if (FileObject
->SectionObjectPointer
== NULL
||
3013 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3016 * Read a bit so caching is initiated for the file object.
3017 * This is only needed because MiReadPage currently cannot
3018 * handle non-cached streams.
3020 Offset
.QuadPart
= 0;
3021 Status
= ZwReadFile(FileHandle
,
3030 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3032 ObDereferenceObject(Section
);
3033 ObDereferenceObject(FileObject
);
3036 if (FileObject
->SectionObjectPointer
== NULL
||
3037 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3039 /* FIXME: handle this situation */
3040 ObDereferenceObject(Section
);
3041 ObDereferenceObject(FileObject
);
3042 return STATUS_INVALID_PARAMETER
;
3049 Status
= MmspWaitForFileLock(FileObject
);
3050 if (Status
!= STATUS_SUCCESS
)
3052 ObDereferenceObject(Section
);
3053 ObDereferenceObject(FileObject
);
3058 * If this file hasn't been mapped as a data file before then allocate a
3059 * section segment to describe the data file mapping
3061 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3063 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3064 TAG_MM_SECTION_SEGMENT
);
3065 if (Segment
== NULL
)
3067 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3068 ObDereferenceObject(Section
);
3069 ObDereferenceObject(FileObject
);
3070 return(STATUS_NO_MEMORY
);
3072 Section
->Segment
= Segment
;
3073 Segment
->ReferenceCount
= 1;
3074 ExInitializeFastMutex(&Segment
->Lock
);
3076 * Set the lock before assigning the segment to the file object
3078 ExAcquireFastMutex(&Segment
->Lock
);
3079 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3081 Segment
->Image
.FileOffset
= 0;
3082 Segment
->Protection
= SectionPageProtection
;
3083 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3084 Segment
->Image
.Characteristics
= 0;
3085 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3086 if (AllocationAttributes
& SEC_RESERVE
)
3088 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3092 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3093 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3095 Segment
->Image
.VirtualAddress
= 0;
3096 Segment
->Locked
= TRUE
;
3097 MiInitializeSectionPageTable(Segment
);
3102 * If the file is already mapped as a data file then we may need
3106 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3108 Section
->Segment
= Segment
;
3109 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3110 MmLockSectionSegment(Segment
);
3112 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3113 !(AllocationAttributes
& SEC_RESERVE
))
3115 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3116 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3119 MmUnlockSectionSegment(Segment
);
3120 Section
->FileObject
= FileObject
;
3121 Section
->MaximumSize
= MaximumSize
;
3123 CcRosReferenceCache(FileObject
);
3125 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3126 *SectionObject
= Section
;
3127 return(STATUS_SUCCESS
);
3131 TODO: not that great (declaring loaders statically, having to declare all of
3132 them, having to keep them extern, etc.), will fix in the future
3134 extern NTSTATUS NTAPI PeFmtCreateSection
3136 IN CONST VOID
* FileHeader
,
3137 IN SIZE_T FileHeaderSize
,
3139 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3141 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3142 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3145 extern NTSTATUS NTAPI ElfFmtCreateSection
3147 IN CONST VOID
* FileHeader
,
3148 IN SIZE_T FileHeaderSize
,
3150 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3152 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3153 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3156 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3167 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3169 SIZE_T SizeOfSegments
;
3170 PMM_SECTION_SEGMENT Segments
;
3172 /* TODO: check for integer overflow */
3173 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3175 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3177 TAG_MM_SECTION_SEGMENT
);
3180 RtlZeroMemory(Segments
, SizeOfSegments
);
3188 ExeFmtpReadFile(IN PVOID File
,
3189 IN PLARGE_INTEGER Offset
,
3192 OUT PVOID
* AllocBase
,
3193 OUT PULONG ReadSize
)
3196 LARGE_INTEGER FileOffset
;
3198 ULONG OffsetAdjustment
;
3202 PFILE_OBJECT FileObject
= File
;
3203 IO_STATUS_BLOCK Iosb
;
3205 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3209 KeBugCheck(MEMORY_MANAGEMENT
);
3212 FileOffset
= *Offset
;
3214 /* Negative/special offset: it cannot be used in this context */
3215 if(FileOffset
.u
.HighPart
< 0)
3217 KeBugCheck(MEMORY_MANAGEMENT
);
3220 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3221 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3222 FileOffset
.u
.LowPart
= AdjustOffset
;
3224 BufferSize
= Length
+ OffsetAdjustment
;
3225 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3227 /* Flush data since we're about to perform a non-cached read */
3228 CcFlushCache(FileObject
->SectionObjectPointer
,
3234 * It's ok to use paged pool, because this is a temporary buffer only used in
3235 * the loading of executables. The assumption is that MmCreateSection is
3236 * always called at low IRQLs and that these buffers don't survive a brief
3237 * initialization phase
3239 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3244 return STATUS_INSUFFICIENT_RESOURCES
;
3249 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3251 UsedSize
= (ULONG
)Iosb
.Information
;
3253 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3255 Status
= STATUS_IN_PAGE_ERROR
;
3256 ASSERT(!NT_SUCCESS(Status
));
3259 if(NT_SUCCESS(Status
))
3261 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3262 *AllocBase
= Buffer
;
3263 *ReadSize
= UsedSize
- OffsetAdjustment
;
3267 ExFreePoolWithTag(Buffer
, 'rXmM');
3274 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3275 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3276 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3281 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3285 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3287 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3288 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3295 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3299 MmspAssertSegmentsSorted(ImageSectionObject
);
3301 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3303 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3307 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3308 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3309 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3317 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3321 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3323 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3324 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3332 MmspCompareSegments(const void * x
,
3335 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3336 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3339 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3340 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3344 * Ensures an image section's segments are sorted in memory
3349 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3352 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3354 MmspAssertSegmentsSorted(ImageSectionObject
);
3358 qsort(ImageSectionObject
->Segments
,
3359 ImageSectionObject
->NrSegments
,
3360 sizeof(ImageSectionObject
->Segments
[0]),
3361 MmspCompareSegments
);
3367 * Ensures an image section's segments don't overlap in memory and don't have
3368 * gaps and don't have a null size. We let them map to overlapping file regions,
3369 * though - that's not necessarily an error
3374 MmspCheckSegmentBounds
3376 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3382 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3384 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3388 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3390 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3392 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3400 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3401 * page could be OK (Windows seems to be OK with them), and larger gaps
3402 * could lead to image sections spanning several discontiguous regions
3403 * (NtMapViewOfSection could then refuse to map them, and they could
3404 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3406 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3407 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3408 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3419 * Merges and pads an image section's segments until they all are page-aligned
3420 * and have a size that is a multiple of the page size
3425 MmspPageAlignSegments
3427 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3433 PMM_SECTION_SEGMENT EffectiveSegment
;
3435 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3437 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3442 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3444 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3447 * The first segment requires special handling
3451 ULONG_PTR VirtualAddress
;
3452 ULONG_PTR VirtualOffset
;
3454 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3456 /* Round down the virtual address to the nearest page */
3457 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3459 /* Round up the virtual size to the nearest page */
3460 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3461 EffectiveSegment
->Image
.VirtualAddress
;
3463 /* Adjust the raw address and size */
3464 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3466 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3472 * Garbage in, garbage out: unaligned base addresses make the file
3473 * offset point in curious and odd places, but that's what we were
3476 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3477 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3481 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3482 ULONG_PTR EndOfEffectiveSegment
;
3484 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3485 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3488 * The current segment begins exactly where the current effective
3489 * segment ended, therefore beginning a new effective segment
3491 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3494 ASSERT(LastSegment
<= i
);
3495 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3497 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3499 if (LastSegment
!= i
)
3502 * Copy the current segment. If necessary, the effective segment
3503 * will be expanded later
3505 *EffectiveSegment
= *Segment
;
3509 * Page-align the virtual size. We know for sure the virtual address
3512 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3513 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3516 * The current segment is still part of the current effective segment:
3517 * extend the effective segment to reflect this
3519 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3521 static const ULONG FlagsToProtection
[16] =
3529 PAGE_EXECUTE_READWRITE
,
3530 PAGE_EXECUTE_READWRITE
,
3535 PAGE_EXECUTE_WRITECOPY
,
3536 PAGE_EXECUTE_WRITECOPY
,
3537 PAGE_EXECUTE_WRITECOPY
,
3538 PAGE_EXECUTE_WRITECOPY
3541 unsigned ProtectionFlags
;
3544 * Extend the file size
3547 /* Unaligned segments must be contiguous within the file */
3548 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3549 EffectiveSegment
->RawLength
.QuadPart
))
3554 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3557 * Extend the virtual size
3559 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3561 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3562 EffectiveSegment
->Image
.VirtualAddress
;
3565 * Merge the protection
3567 EffectiveSegment
->Protection
|= Segment
->Protection
;
3569 /* Clean up redundance */
3570 ProtectionFlags
= 0;
3572 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3573 ProtectionFlags
|= 1 << 0;
3575 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3576 ProtectionFlags
|= 1 << 1;
3578 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3579 ProtectionFlags
|= 1 << 2;
3581 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3582 ProtectionFlags
|= 1 << 3;
3584 ASSERT(ProtectionFlags
< 16);
3585 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3587 /* If a segment was required to be shared and cannot, fail */
3588 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3589 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3595 * We assume no holes between segments at this point
3599 KeBugCheck(MEMORY_MANAGEMENT
);
3603 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3609 ExeFmtpCreateImageSection(PFILE_OBJECT FileObject
,
3610 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3612 LARGE_INTEGER Offset
;
3614 PVOID FileHeaderBuffer
;
3615 ULONG FileHeaderSize
;
3617 ULONG OldNrSegments
;
3622 * Read the beginning of the file (2 pages). Should be enough to contain
3623 * all (or most) of the headers
3625 Offset
.QuadPart
= 0;
3627 Status
= ExeFmtpReadFile (FileObject
,
3634 if (!NT_SUCCESS(Status
))
3637 if (FileHeaderSize
== 0)
3639 ExFreePool(FileHeaderBuffer
);
3640 return STATUS_UNSUCCESSFUL
;
3644 * Look for a loader that can handle this executable
3646 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3648 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3651 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3657 ExeFmtpAllocateSegments
);
3659 if (!NT_SUCCESS(Status
))
3661 if (ImageSectionObject
->Segments
)
3663 ExFreePool(ImageSectionObject
->Segments
);
3664 ImageSectionObject
->Segments
= NULL
;
3668 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3672 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3675 * No loader handled the format
3677 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3679 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3680 ASSERT(!NT_SUCCESS(Status
));
3683 if (!NT_SUCCESS(Status
))
3686 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3691 /* FIXME? are these values platform-dependent? */
3692 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3693 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3695 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3696 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3698 if(ImageSectionObject
->BasedAddress
== NULL
)
3700 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3701 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3703 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3707 * And now the fun part: fixing the segments
3710 /* Sort them by virtual address */
3711 MmspSortSegments(ImageSectionObject
, Flags
);
3713 /* Ensure they don't overlap in memory */
3714 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3715 return STATUS_INVALID_IMAGE_FORMAT
;
3717 /* Ensure they are aligned */
3718 OldNrSegments
= ImageSectionObject
->NrSegments
;
3720 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3721 return STATUS_INVALID_IMAGE_FORMAT
;
3723 /* Trim them if the alignment phase merged some of them */
3724 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3726 PMM_SECTION_SEGMENT Segments
;
3727 SIZE_T SizeOfSegments
;
3729 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3731 Segments
= ExAllocatePoolWithTag(PagedPool
,
3733 TAG_MM_SECTION_SEGMENT
);
3735 if (Segments
== NULL
)
3736 return STATUS_INSUFFICIENT_RESOURCES
;
3738 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3739 ExFreePool(ImageSectionObject
->Segments
);
3740 ImageSectionObject
->Segments
= Segments
;
3743 /* And finish their initialization */
3744 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3746 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3747 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3748 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3751 ASSERT(NT_SUCCESS(Status
));
3756 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3757 ACCESS_MASK DesiredAccess
,
3758 POBJECT_ATTRIBUTES ObjectAttributes
,
3759 PLARGE_INTEGER UMaximumSize
,
3760 ULONG SectionPageProtection
,
3761 ULONG AllocationAttributes
,
3762 PFILE_OBJECT FileObject
)
3764 PROS_SECTION_OBJECT Section
;
3766 PMM_SECTION_SEGMENT SectionSegments
;
3767 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3770 if (FileObject
== NULL
)
3771 return STATUS_INVALID_FILE_FOR_SECTION
;
3774 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3776 DPRINT1("Denying section creation due to missing cache initialization\n");
3777 return STATUS_INVALID_FILE_FOR_SECTION
;
3782 * Create the section
3784 Status
= ObCreateObject (ExGetPreviousMode(),
3785 MmSectionObjectType
,
3787 ExGetPreviousMode(),
3789 sizeof(ROS_SECTION_OBJECT
),
3792 (PVOID
*)(PVOID
)&Section
);
3793 if (!NT_SUCCESS(Status
))
3795 ObDereferenceObject(FileObject
);
3802 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3803 Section
->Type
= 'SC';
3804 Section
->Size
= 'TN';
3805 Section
->SectionPageProtection
= SectionPageProtection
;
3806 Section
->AllocationAttributes
= AllocationAttributes
;
3810 * Initialized caching for this file object if previously caching
3811 * was initialized for the same on disk file
3813 Status
= CcTryToInitializeFileCache(FileObject
);
3815 Status
= STATUS_SUCCESS
;
3818 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3820 NTSTATUS StatusExeFmt
;
3822 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3823 if (ImageSectionObject
== NULL
)
3825 ObDereferenceObject(FileObject
);
3826 ObDereferenceObject(Section
);
3827 return(STATUS_NO_MEMORY
);
3830 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3832 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3834 if (!NT_SUCCESS(StatusExeFmt
))
3836 if(ImageSectionObject
->Segments
!= NULL
)
3837 ExFreePool(ImageSectionObject
->Segments
);
3839 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3840 ObDereferenceObject(Section
);
3841 ObDereferenceObject(FileObject
);
3842 return(StatusExeFmt
);
3845 Section
->ImageSection
= ImageSectionObject
;
3846 ASSERT(ImageSectionObject
->Segments
);
3851 Status
= MmspWaitForFileLock(FileObject
);
3852 if (!NT_SUCCESS(Status
))
3854 ExFreePool(ImageSectionObject
->Segments
);
3855 ExFreePool(ImageSectionObject
);
3856 ObDereferenceObject(Section
);
3857 ObDereferenceObject(FileObject
);
3861 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3862 ImageSectionObject
, NULL
))
3865 * An other thread has initialized the same image in the background
3867 ExFreePool(ImageSectionObject
->Segments
);
3868 ExFreePool(ImageSectionObject
);
3869 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3870 Section
->ImageSection
= ImageSectionObject
;
3871 SectionSegments
= ImageSectionObject
->Segments
;
3873 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3875 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3879 Status
= StatusExeFmt
;
3886 Status
= MmspWaitForFileLock(FileObject
);
3887 if (Status
!= STATUS_SUCCESS
)
3889 ObDereferenceObject(Section
);
3890 ObDereferenceObject(FileObject
);
3894 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3895 Section
->ImageSection
= ImageSectionObject
;
3896 SectionSegments
= ImageSectionObject
->Segments
;
3899 * Otherwise just reference all the section segments
3901 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3903 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3906 Status
= STATUS_SUCCESS
;
3908 Section
->FileObject
= FileObject
;
3910 CcRosReferenceCache(FileObject
);
3912 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3913 *SectionObject
= Section
;
3920 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3921 PROS_SECTION_OBJECT Section
,
3922 PMM_SECTION_SEGMENT Segment
,
3927 ULONG AllocationType
)
3933 if (Segment
->WriteCopy
)
3935 /* We have to do this because the not present fault
3936 * and access fault handlers depend on the protection
3937 * that should be granted AFTER the COW fault takes
3938 * place to be in Region->Protect. The not present fault
3939 * handler changes this to the correct protection for COW when
3940 * mapping the pages into the process's address space. If a COW
3941 * fault takes place, the access fault handler sets the page protection
3942 * to these values for the newly copied pages
3944 if (Protect
== PAGE_WRITECOPY
)
3945 Protect
= PAGE_READWRITE
;
3946 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3947 Protect
= PAGE_EXECUTE_READWRITE
;
3950 if (*BaseAddress
== NULL
)
3951 Granularity
= MM_ALLOCATION_GRANULARITY
;
3953 Granularity
= PAGE_SIZE
;
3956 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3958 LARGE_INTEGER FileOffset
;
3959 FileOffset
.QuadPart
= ViewOffset
;
3960 ObReferenceObject(Section
);
3961 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3964 Status
= MmCreateMemoryArea(AddressSpace
,
3965 MEMORY_AREA_SECTION_VIEW
,
3972 if (!NT_SUCCESS(Status
))
3974 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3975 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3979 ObReferenceObject((PVOID
)Section
);
3981 MArea
->Data
.SectionData
.Segment
= Segment
;
3982 MArea
->Data
.SectionData
.Section
= Section
;
3983 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3984 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3986 MArea
->VadNode
.u
.VadFlags
.VadType
= VadImageMap
;
3989 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3990 ViewSize
, 0, Protect
);
3992 return(STATUS_SUCCESS
);
3997 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3998 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4002 PFILE_OBJECT FileObject
;
4003 PROS_SHARED_CACHE_MAP SharedCacheMap
;
4005 LARGE_INTEGER Offset
;
4006 SWAPENTRY SavedSwapEntry
;
4007 PROS_SECTION_OBJECT Section
;
4008 PMM_SECTION_SEGMENT Segment
;
4009 PMMSUPPORT AddressSpace
;
4012 AddressSpace
= (PMMSUPPORT
)Context
;
4013 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4015 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4017 Offset
.QuadPart
= ((ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)) +
4018 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
4020 Section
= MemoryArea
->Data
.SectionData
.Section
;
4021 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4023 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4024 while (Entry
&& MM_IS_WAIT_PTE(Entry
))
4026 MmUnlockSectionSegment(Segment
);
4027 MmUnlockAddressSpace(AddressSpace
);
4029 MiWaitForPageEvent(NULL
, NULL
);
4031 MmLockAddressSpace(AddressSpace
);
4032 MmLockSectionSegment(Segment
);
4033 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4037 * For a dirty, datafile, non-private page mark it as dirty in the
4040 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4042 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4045 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4046 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4047 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4049 ASSERT(SwapEntry
== 0);
4058 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4060 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4061 KeBugCheck(MEMORY_MANAGEMENT
);
4063 MmFreeSwapPage(SwapEntry
);
4067 if (IS_SWAP_FROM_SSE(Entry
) ||
4068 Page
!= PFN_FROM_SSE(Entry
))
4073 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4075 DPRINT1("Found a private page in a pagefile section.\n");
4076 KeBugCheck(MEMORY_MANAGEMENT
);
4079 * Just dereference private pages
4081 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4082 if (SavedSwapEntry
!= 0)
4084 MmFreeSwapPage(SavedSwapEntry
);
4085 MmSetSavedSwapEntryPage(Page
, 0);
4087 MmDeleteRmap(Page
, Process
, Address
);
4088 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4092 MmDeleteRmap(Page
, Process
, Address
);
4093 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4099 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4103 PMEMORY_AREA MemoryArea
;
4104 PROS_SECTION_OBJECT Section
;
4105 PMM_SECTION_SEGMENT Segment
;
4106 PLIST_ENTRY CurrentEntry
;
4107 PMM_REGION CurrentRegion
;
4108 PLIST_ENTRY RegionListHead
;
4110 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4112 if (MemoryArea
== NULL
)
4114 return(STATUS_UNSUCCESSFUL
);
4117 Section
= MemoryArea
->Data
.SectionData
.Section
;
4118 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4121 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4123 MmUnlockAddressSpace(AddressSpace
);
4124 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4125 MmLockAddressSpace(AddressSpace
);
4131 MemoryArea
->DeleteInProgress
= TRUE
;
4133 MmLockSectionSegment(Segment
);
4135 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4136 while (!IsListEmpty(RegionListHead
))
4138 CurrentEntry
= RemoveHeadList(RegionListHead
);
4139 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4140 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4143 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4145 Status
= MmFreeMemoryArea(AddressSpace
,
4152 Status
= MmFreeMemoryArea(AddressSpace
,
4157 MmUnlockSectionSegment(Segment
);
4158 ObDereferenceObject(Section
);
4164 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4165 IN PVOID BaseAddress
,
4169 PMEMORY_AREA MemoryArea
;
4170 PMMSUPPORT AddressSpace
;
4171 PROS_SECTION_OBJECT Section
;
4172 PVOID ImageBaseAddress
= 0;
4174 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4175 Process
, BaseAddress
);
4179 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4181 MmLockAddressSpace(AddressSpace
);
4182 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4184 if (MemoryArea
== NULL
||
4185 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4186 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4187 MemoryArea
->DeleteInProgress
)
4189 if (MemoryArea
) ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4190 MmUnlockAddressSpace(AddressSpace
);
4191 return STATUS_NOT_MAPPED_VIEW
;
4194 Section
= MemoryArea
->Data
.SectionData
.Section
;
4196 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4200 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4201 PMM_SECTION_SEGMENT SectionSegments
;
4202 PMM_SECTION_SEGMENT Segment
;
4204 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4205 ImageSectionObject
= Section
->ImageSection
;
4206 SectionSegments
= ImageSectionObject
->Segments
;
4207 NrSegments
= ImageSectionObject
->NrSegments
;
4209 MemoryArea
->DeleteInProgress
= TRUE
;
4211 /* Search for the current segment within the section segments
4212 * and calculate the image base address */
4213 for (i
= 0; i
< NrSegments
; i
++)
4215 if (Segment
== &SectionSegments
[i
])
4217 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4221 if (i
>= NrSegments
)
4223 KeBugCheck(MEMORY_MANAGEMENT
);
4226 for (i
= 0; i
< NrSegments
; i
++)
4228 PVOID SBaseAddress
= (PVOID
)
4229 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4231 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4232 if (!NT_SUCCESS(Status
))
4234 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4235 SBaseAddress
, Process
, Status
);
4236 ASSERT(NT_SUCCESS(Status
));
4242 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4243 if (!NT_SUCCESS(Status
))
4245 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4246 BaseAddress
, Process
, Status
);
4247 ASSERT(NT_SUCCESS(Status
));
4251 MmUnlockAddressSpace(AddressSpace
);
4253 /* Notify debugger */
4254 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4256 return(STATUS_SUCCESS
);
4263 * Queries the information of a section object.
4265 * @param SectionHandle
4266 * Handle to the section object. It must be opened with SECTION_QUERY
4268 * @param SectionInformationClass
4269 * Index to a certain information structure. Can be either
4270 * SectionBasicInformation or SectionImageInformation. The latter
4271 * is valid only for sections that were created with the SEC_IMAGE
4273 * @param SectionInformation
4274 * Caller supplies storage for resulting information.
4276 * Size of the supplied storage.
4277 * @param ResultLength
4287 _In_ HANDLE SectionHandle
,
4288 _In_ SECTION_INFORMATION_CLASS SectionInformationClass
,
4289 _Out_ PVOID SectionInformation
,
4290 _In_ SIZE_T SectionInformationLength
,
4291 _Out_opt_ PSIZE_T ResultLength
)
4294 KPROCESSOR_MODE PreviousMode
;
4298 PreviousMode
= ExGetPreviousMode();
4299 if (PreviousMode
!= KernelMode
)
4303 ProbeForWrite(SectionInformation
,
4304 SectionInformationLength
,
4306 if (ResultLength
!= NULL
)
4308 ProbeForWrite(ResultLength
,
4309 sizeof(*ResultLength
),
4313 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4315 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4320 if (SectionInformationClass
== SectionBasicInformation
)
4322 if (SectionInformationLength
< sizeof(SECTION_BASIC_INFORMATION
))
4324 return STATUS_INFO_LENGTH_MISMATCH
;
4327 else if (SectionInformationClass
== SectionImageInformation
)
4329 if (SectionInformationLength
< sizeof(SECTION_IMAGE_INFORMATION
))
4331 return STATUS_INFO_LENGTH_MISMATCH
;
4336 return STATUS_INVALID_INFO_CLASS
;
4339 Status
= ObReferenceObjectByHandle(SectionHandle
,
4341 MmSectionObjectType
,
4343 (PVOID
*)(PVOID
)&Section
,
4345 if (!NT_SUCCESS(Status
))
4347 DPRINT1("Failed to reference section: 0x%lx\n", Status
);
4351 if (MiIsRosSectionObject(Section
))
4353 PROS_SECTION_OBJECT RosSection
= (PROS_SECTION_OBJECT
)Section
;
4355 switch (SectionInformationClass
)
4357 case SectionBasicInformation
:
4359 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4363 Sbi
->Attributes
= RosSection
->AllocationAttributes
;
4364 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4366 Sbi
->BaseAddress
= 0;
4367 Sbi
->Size
.QuadPart
= 0;
4371 Sbi
->BaseAddress
= (PVOID
)RosSection
->Segment
->Image
.VirtualAddress
;
4372 Sbi
->Size
.QuadPart
= RosSection
->Segment
->Length
.QuadPart
;
4375 if (ResultLength
!= NULL
)
4377 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4379 Status
= STATUS_SUCCESS
;
4381 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4383 Status
= _SEH2_GetExceptionCode();
4390 case SectionImageInformation
:
4392 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4396 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4398 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4399 ImageSectionObject
= RosSection
->ImageSection
;
4401 *Sii
= ImageSectionObject
->ImageInformation
;
4404 if (ResultLength
!= NULL
)
4406 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4408 Status
= STATUS_SUCCESS
;
4410 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4412 Status
= _SEH2_GetExceptionCode();
4422 switch(SectionInformationClass
)
4424 case SectionBasicInformation
:
4426 SECTION_BASIC_INFORMATION Sbi
;
4428 Sbi
.Size
= Section
->SizeOfSection
;
4429 Sbi
.BaseAddress
= (PVOID
)Section
->Address
.StartingVpn
;
4432 if (Section
->u
.Flags
.Image
)
4433 Sbi
.Attributes
|= SEC_IMAGE
;
4434 if (Section
->u
.Flags
.Commit
)
4435 Sbi
.Attributes
|= SEC_COMMIT
;
4436 if (Section
->u
.Flags
.Reserve
)
4437 Sbi
.Attributes
|= SEC_RESERVE
;
4438 if (Section
->u
.Flags
.File
)
4439 Sbi
.Attributes
|= SEC_FILE
;
4440 if (Section
->u
.Flags
.Image
)
4441 Sbi
.Attributes
|= SEC_IMAGE
;
4443 /* FIXME : Complete/test the list of flags passed back from NtCreateSection */
4447 *((SECTION_BASIC_INFORMATION
*)SectionInformation
) = Sbi
;
4449 *ResultLength
= sizeof(Sbi
);
4451 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4453 Status
= _SEH2_GetExceptionCode();
4458 case SectionImageInformation
:
4460 if (!Section
->u
.Flags
.Image
)
4462 Status
= STATUS_SECTION_NOT_IMAGE
;
4466 /* Currently not supported */
4474 ObDereferenceObject(Section
);
4479 /**********************************************************************
4481 * MmMapViewOfSection
4484 * Maps a view of a section into the virtual address space of a
4489 * Pointer to the section object.
4492 * Pointer to the process.
4495 * Desired base address (or NULL) on entry;
4496 * Actual base address of the view on exit.
4499 * Number of high order address bits that must be zero.
4502 * Size in bytes of the initially committed section of
4506 * Offset in bytes from the beginning of the section
4507 * to the beginning of the view.
4510 * Desired length of map (or zero to map all) on entry
4511 * Actual length mapped on exit.
4513 * InheritDisposition
4514 * Specified how the view is to be shared with
4518 * Type of allocation for the pages.
4521 * Protection for the committed region of the view.
4529 MmMapViewOfSection(IN PVOID SectionObject
,
4530 IN PEPROCESS Process
,
4531 IN OUT PVOID
*BaseAddress
,
4532 IN ULONG_PTR ZeroBits
,
4533 IN SIZE_T CommitSize
,
4534 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4535 IN OUT PSIZE_T ViewSize
,
4536 IN SECTION_INHERIT InheritDisposition
,
4537 IN ULONG AllocationType
,
4540 PROS_SECTION_OBJECT Section
;
4541 PMMSUPPORT AddressSpace
;
4543 NTSTATUS Status
= STATUS_SUCCESS
;
4544 BOOLEAN NotAtBase
= FALSE
;
4546 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4548 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4549 return MmMapViewOfArm3Section(SectionObject
,
4563 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4565 return STATUS_INVALID_PAGE_PROTECTION
;
4568 /* FIXME: We should keep this, but it would break code checking equality */
4569 Protect
&= ~PAGE_NOCACHE
;
4571 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4572 AddressSpace
= &Process
->Vm
;
4574 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4576 MmLockAddressSpace(AddressSpace
);
4578 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4582 ULONG_PTR ImageBase
;
4584 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4585 PMM_SECTION_SEGMENT SectionSegments
;
4587 ImageSectionObject
= Section
->ImageSection
;
4588 SectionSegments
= ImageSectionObject
->Segments
;
4589 NrSegments
= ImageSectionObject
->NrSegments
;
4591 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4594 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4598 for (i
= 0; i
< NrSegments
; i
++)
4600 ULONG_PTR MaxExtent
;
4601 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4602 SectionSegments
[i
].Length
.QuadPart
);
4603 ImageSize
= max(ImageSize
, MaxExtent
);
4606 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4608 /* Check for an illegal base address */
4609 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4610 ((ImageBase
+ ImageSize
) < ImageSize
))
4612 ASSERT(*BaseAddress
== NULL
);
4613 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4614 MM_VIRTMEM_GRANULARITY
);
4617 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4619 ASSERT(*BaseAddress
== NULL
);
4620 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4624 /* Check there is enough space to map the section at that point. */
4625 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4626 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4628 /* Fail if the user requested a fixed base address. */
4629 if ((*BaseAddress
) != NULL
)
4631 MmUnlockAddressSpace(AddressSpace
);
4632 return(STATUS_CONFLICTING_ADDRESSES
);
4634 /* Otherwise find a gap to map the image. */
4635 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4638 MmUnlockAddressSpace(AddressSpace
);
4639 return(STATUS_CONFLICTING_ADDRESSES
);
4641 /* Remember that we loaded image at a different base address */
4645 for (i
= 0; i
< NrSegments
; i
++)
4647 PVOID SBaseAddress
= (PVOID
)
4648 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4649 MmLockSectionSegment(&SectionSegments
[i
]);
4650 Status
= MmMapViewOfSegment(AddressSpace
,
4652 &SectionSegments
[i
],
4654 SectionSegments
[i
].Length
.LowPart
,
4655 SectionSegments
[i
].Protection
,
4658 MmUnlockSectionSegment(&SectionSegments
[i
]);
4659 if (!NT_SUCCESS(Status
))
4661 MmUnlockAddressSpace(AddressSpace
);
4666 *BaseAddress
= (PVOID
)ImageBase
;
4667 *ViewSize
= ImageSize
;
4671 /* check for write access */
4672 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4673 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4675 MmUnlockAddressSpace(AddressSpace
);
4676 return STATUS_SECTION_PROTECTION
;
4678 /* check for read access */
4679 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4680 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4682 MmUnlockAddressSpace(AddressSpace
);
4683 return STATUS_SECTION_PROTECTION
;
4685 /* check for execute access */
4686 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4687 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4689 MmUnlockAddressSpace(AddressSpace
);
4690 return STATUS_SECTION_PROTECTION
;
4693 if (SectionOffset
== NULL
)
4699 ViewOffset
= SectionOffset
->u
.LowPart
;
4702 if ((ViewOffset
% PAGE_SIZE
) != 0)
4704 MmUnlockAddressSpace(AddressSpace
);
4705 return(STATUS_MAPPED_ALIGNMENT
);
4708 if ((*ViewSize
) == 0)
4710 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4712 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4714 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4717 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4719 MmLockSectionSegment(Section
->Segment
);
4720 Status
= MmMapViewOfSegment(AddressSpace
,
4727 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4728 MmUnlockSectionSegment(Section
->Segment
);
4729 if (!NT_SUCCESS(Status
))
4731 MmUnlockAddressSpace(AddressSpace
);
4736 MmUnlockAddressSpace(AddressSpace
);
4737 ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4740 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4742 Status
= STATUS_SUCCESS
;
4751 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4752 IN PLARGE_INTEGER NewFileSize
)
4754 /* Check whether an ImageSectionObject exists */
4755 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4757 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4761 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4763 PMM_SECTION_SEGMENT Segment
;
4765 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4768 if (Segment
->ReferenceCount
!= 0)
4771 CC_FILE_SIZES FileSizes
;
4773 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4776 /* Check size of file */
4777 if (SectionObjectPointer
->SharedCacheMap
)
4779 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4784 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4793 /* Check size of file */
4794 if (SectionObjectPointer
->SharedCacheMap
)
4796 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4797 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4806 /* Something must gone wrong
4807 * how can we have a Section but no
4809 DPRINT("ERROR: DataSectionObject without reference!\n");
4813 DPRINT("FIXME: didn't check for outstanding write probes\n");
4825 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4826 IN MMFLUSH_TYPE FlushType
)
4828 BOOLEAN Result
= TRUE
;
4830 PMM_SECTION_SEGMENT Segment
;
4835 case MmFlushForDelete
:
4836 if (SectionObjectPointer
->ImageSectionObject
||
4837 SectionObjectPointer
->DataSectionObject
)
4842 CcRosRemoveIfClosed(SectionObjectPointer
);
4845 case MmFlushForWrite
:
4847 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4849 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4852 if (SectionObjectPointer
->ImageSectionObject
)
4854 DPRINT1("SectionObject has ImageSection\n");
4860 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4862 DPRINT("Result %d\n", Result
);
4874 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4875 OUT PVOID
* MappedBase
,
4876 IN OUT PSIZE_T ViewSize
)
4878 PROS_SECTION_OBJECT Section
;
4879 PMMSUPPORT AddressSpace
;
4883 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4885 return MiMapViewInSystemSpace(SectionObject
,
4891 DPRINT("MmMapViewInSystemSpace() called\n");
4893 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4894 AddressSpace
= MmGetKernelAddressSpace();
4896 MmLockAddressSpace(AddressSpace
);
4899 if ((*ViewSize
) == 0)
4901 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4903 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4905 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4908 MmLockSectionSegment(Section
->Segment
);
4911 Status
= MmMapViewOfSegment(AddressSpace
,
4920 MmUnlockSectionSegment(Section
->Segment
);
4921 MmUnlockAddressSpace(AddressSpace
);
4928 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4930 PMMSUPPORT AddressSpace
;
4933 DPRINT("MmUnmapViewInSystemSpace() called\n");
4935 AddressSpace
= MmGetKernelAddressSpace();
4937 MmLockAddressSpace(AddressSpace
);
4939 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4941 MmUnlockAddressSpace(AddressSpace
);
4946 /**********************************************************************
4951 * Creates a section object.
4954 * SectionObject (OUT)
4955 * Caller supplied storage for the resulting pointer
4956 * to a SECTION_OBJECT instance;
4959 * Specifies the desired access to the section can be a
4961 * STANDARD_RIGHTS_REQUIRED |
4963 * SECTION_MAP_WRITE |
4964 * SECTION_MAP_READ |
4965 * SECTION_MAP_EXECUTE
4967 * ObjectAttributes [OPTIONAL]
4968 * Initialized attributes for the object can be used
4969 * to create a named section;
4972 * Maximizes the size of the memory section. Must be
4973 * non-NULL for a page-file backed section.
4974 * If value specified for a mapped file and the file is
4975 * not large enough, file will be extended.
4977 * SectionPageProtection
4978 * Can be a combination of:
4984 * AllocationAttributes
4985 * Can be a combination of:
4990 * Handle to a file to create a section mapped to a file
4991 * instead of a memory backed section;
5002 MmCreateSection (OUT PVOID
* Section
,
5003 IN ACCESS_MASK DesiredAccess
,
5004 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
5005 IN PLARGE_INTEGER MaximumSize
,
5006 IN ULONG SectionPageProtection
,
5007 IN ULONG AllocationAttributes
,
5008 IN HANDLE FileHandle OPTIONAL
,
5009 IN PFILE_OBJECT FileObject OPTIONAL
)
5013 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
5015 /* Check if an ARM3 section is being created instead */
5016 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
5018 if (!(FileObject
) && !(FileHandle
))
5020 return MmCreateArm3Section(Section
,
5024 SectionPageProtection
,
5025 AllocationAttributes
&~ 1,
5031 /* Convert section flag to page flag */
5032 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
5034 /* Check to make sure the protection is correct. Nt* does this already */
5035 Protection
= MiMakeProtectionMask(SectionPageProtection
);
5036 if (Protection
== MM_INVALID_PROTECTION
)
5038 DPRINT1("Page protection is invalid\n");
5039 return STATUS_INVALID_PAGE_PROTECTION
;
5042 /* Check if this is going to be a data or image backed file section */
5043 if ((FileHandle
) || (FileObject
))
5045 /* These cannot be mapped with large pages */
5046 if (AllocationAttributes
& SEC_LARGE_PAGES
)
5048 DPRINT1("Large pages cannot be used with an image mapping\n");
5049 return STATUS_INVALID_PARAMETER_6
;
5052 /* Did the caller pass an object? */
5055 /* Reference the object directly */
5056 ObReferenceObject(FileObject
);
5060 /* Reference the file handle to get the object */
5061 Status
= ObReferenceObjectByHandle(FileHandle
,
5062 MmMakeFileAccess
[Protection
],
5064 ExGetPreviousMode(),
5065 (PVOID
*)&FileObject
,
5067 if (!NT_SUCCESS(Status
))
5069 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
5076 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
5077 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
5080 #ifndef NEWCC // A hack for initializing caching.
5081 // This is needed only in the old case.
5084 IO_STATUS_BLOCK Iosb
;
5087 LARGE_INTEGER ByteOffset
;
5088 ByteOffset
.QuadPart
= 0;
5089 Status
= ZwReadFile(FileHandle
,
5098 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5100 DPRINT1("CC failure: %lx\n", Status
);
5103 // Caching is initialized...
5107 if (AllocationAttributes
& SEC_IMAGE
)
5109 Status
= MmCreateImageSection(SectionObject
,
5113 SectionPageProtection
,
5114 AllocationAttributes
,
5118 else if (FileHandle
!= NULL
)
5120 Status
= MmCreateDataFileSection(SectionObject
,
5124 SectionPageProtection
,
5125 AllocationAttributes
,
5128 ObDereferenceObject(FileObject
);
5131 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5133 Status
= MmCreateCacheSection(SectionObject
,
5137 SectionPageProtection
,
5138 AllocationAttributes
,
5144 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5146 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5148 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5149 Status
= MmCreatePageFileSection(SectionObject
,
5153 SectionPageProtection
,
5154 AllocationAttributes
);