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
,
2901 PFILE_OBJECT FileObject
)
2903 * Create a section backed by a data file
2906 PROS_SECTION_OBJECT Section
;
2908 LARGE_INTEGER MaximumSize
;
2909 PMM_SECTION_SEGMENT Segment
;
2910 FILE_STANDARD_INFORMATION FileInfo
;
2914 * Create the section
2916 Status
= ObCreateObject(ExGetPreviousMode(),
2917 MmSectionObjectType
,
2919 ExGetPreviousMode(),
2921 sizeof(ROS_SECTION_OBJECT
),
2925 if (!NT_SUCCESS(Status
))
2927 ObDereferenceObject(FileObject
);
2933 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2934 Section
->Type
= 'SC';
2935 Section
->Size
= 'TN';
2936 Section
->SectionPageProtection
= SectionPageProtection
;
2937 Section
->AllocationAttributes
= AllocationAttributes
;
2940 * FIXME: This is propably not entirely correct. We can't look into
2941 * the standard FCB header because it might not be initialized yet
2942 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2943 * standard file information is filled on first request).
2945 Status
= IoQueryFileInformation(FileObject
,
2946 FileStandardInformation
,
2947 sizeof(FILE_STANDARD_INFORMATION
),
2950 if (!NT_SUCCESS(Status
))
2952 ObDereferenceObject(Section
);
2953 ObDereferenceObject(FileObject
);
2958 * FIXME: Revise this once a locking order for file size changes is
2961 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2963 MaximumSize
= *UMaximumSize
;
2967 MaximumSize
= FileInfo
.EndOfFile
;
2968 /* Mapping zero-sized files isn't allowed. */
2969 if (MaximumSize
.QuadPart
== 0)
2971 ObDereferenceObject(Section
);
2972 ObDereferenceObject(FileObject
);
2973 return STATUS_MAPPED_FILE_SIZE_ZERO
;
2977 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2979 Status
= IoSetInformation(FileObject
,
2980 FileEndOfFileInformation
,
2981 sizeof(LARGE_INTEGER
),
2983 if (!NT_SUCCESS(Status
))
2985 ObDereferenceObject(Section
);
2986 ObDereferenceObject(FileObject
);
2987 return(STATUS_SECTION_NOT_EXTENDED
);
2991 if (FileObject
->SectionObjectPointer
== NULL
||
2992 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2994 ObDereferenceObject(Section
);
2995 ObDereferenceObject(FileObject
);
2996 return STATUS_INVALID_FILE_FOR_SECTION
;
3002 Status
= MmspWaitForFileLock(FileObject
);
3003 if (Status
!= STATUS_SUCCESS
)
3005 ObDereferenceObject(Section
);
3006 ObDereferenceObject(FileObject
);
3011 * If this file hasn't been mapped as a data file before then allocate a
3012 * section segment to describe the data file mapping
3014 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3016 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3017 TAG_MM_SECTION_SEGMENT
);
3018 if (Segment
== NULL
)
3020 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3021 ObDereferenceObject(Section
);
3022 ObDereferenceObject(FileObject
);
3023 return(STATUS_NO_MEMORY
);
3025 Section
->Segment
= Segment
;
3026 Segment
->ReferenceCount
= 1;
3027 ExInitializeFastMutex(&Segment
->Lock
);
3029 * Set the lock before assigning the segment to the file object
3031 ExAcquireFastMutex(&Segment
->Lock
);
3032 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3034 Segment
->Image
.FileOffset
= 0;
3035 Segment
->Protection
= SectionPageProtection
;
3036 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3037 Segment
->Image
.Characteristics
= 0;
3038 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3039 if (AllocationAttributes
& SEC_RESERVE
)
3041 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3045 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3046 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3048 Segment
->Image
.VirtualAddress
= 0;
3049 Segment
->Locked
= TRUE
;
3050 MiInitializeSectionPageTable(Segment
);
3055 * If the file is already mapped as a data file then we may need
3059 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3061 Section
->Segment
= Segment
;
3062 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3063 MmLockSectionSegment(Segment
);
3065 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3066 !(AllocationAttributes
& SEC_RESERVE
))
3068 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3069 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3072 MmUnlockSectionSegment(Segment
);
3073 Section
->FileObject
= FileObject
;
3074 Section
->MaximumSize
= MaximumSize
;
3076 CcRosReferenceCache(FileObject
);
3078 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3079 *SectionObject
= Section
;
3080 return(STATUS_SUCCESS
);
3084 TODO: not that great (declaring loaders statically, having to declare all of
3085 them, having to keep them extern, etc.), will fix in the future
3087 extern NTSTATUS NTAPI PeFmtCreateSection
3089 IN CONST VOID
* FileHeader
,
3090 IN SIZE_T FileHeaderSize
,
3092 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3094 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3095 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3098 extern NTSTATUS NTAPI ElfFmtCreateSection
3100 IN CONST VOID
* FileHeader
,
3101 IN SIZE_T FileHeaderSize
,
3103 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3105 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3106 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3109 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3120 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3122 SIZE_T SizeOfSegments
;
3123 PMM_SECTION_SEGMENT Segments
;
3125 /* TODO: check for integer overflow */
3126 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3128 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3130 TAG_MM_SECTION_SEGMENT
);
3133 RtlZeroMemory(Segments
, SizeOfSegments
);
3141 ExeFmtpReadFile(IN PVOID File
,
3142 IN PLARGE_INTEGER Offset
,
3145 OUT PVOID
* AllocBase
,
3146 OUT PULONG ReadSize
)
3149 LARGE_INTEGER FileOffset
;
3151 ULONG OffsetAdjustment
;
3155 PFILE_OBJECT FileObject
= File
;
3156 IO_STATUS_BLOCK Iosb
;
3158 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3162 KeBugCheck(MEMORY_MANAGEMENT
);
3165 FileOffset
= *Offset
;
3167 /* Negative/special offset: it cannot be used in this context */
3168 if(FileOffset
.u
.HighPart
< 0)
3170 KeBugCheck(MEMORY_MANAGEMENT
);
3173 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3174 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3175 FileOffset
.u
.LowPart
= AdjustOffset
;
3177 BufferSize
= Length
+ OffsetAdjustment
;
3178 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3180 /* Flush data since we're about to perform a non-cached read */
3181 CcFlushCache(FileObject
->SectionObjectPointer
,
3187 * It's ok to use paged pool, because this is a temporary buffer only used in
3188 * the loading of executables. The assumption is that MmCreateSection is
3189 * always called at low IRQLs and that these buffers don't survive a brief
3190 * initialization phase
3192 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3197 return STATUS_INSUFFICIENT_RESOURCES
;
3202 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3204 UsedSize
= (ULONG
)Iosb
.Information
;
3206 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3208 Status
= STATUS_IN_PAGE_ERROR
;
3209 ASSERT(!NT_SUCCESS(Status
));
3212 if(NT_SUCCESS(Status
))
3214 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3215 *AllocBase
= Buffer
;
3216 *ReadSize
= UsedSize
- OffsetAdjustment
;
3220 ExFreePoolWithTag(Buffer
, 'rXmM');
3227 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3228 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3229 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3234 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3238 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3240 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3241 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3248 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3252 MmspAssertSegmentsSorted(ImageSectionObject
);
3254 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3256 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3260 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3261 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3262 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3270 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3274 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3276 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3277 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3285 MmspCompareSegments(const void * x
,
3288 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3289 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3292 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3293 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3297 * Ensures an image section's segments are sorted in memory
3302 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3305 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3307 MmspAssertSegmentsSorted(ImageSectionObject
);
3311 qsort(ImageSectionObject
->Segments
,
3312 ImageSectionObject
->NrSegments
,
3313 sizeof(ImageSectionObject
->Segments
[0]),
3314 MmspCompareSegments
);
3320 * Ensures an image section's segments don't overlap in memory and don't have
3321 * gaps and don't have a null size. We let them map to overlapping file regions,
3322 * though - that's not necessarily an error
3327 MmspCheckSegmentBounds
3329 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3335 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3337 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3341 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3343 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3345 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3353 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3354 * page could be OK (Windows seems to be OK with them), and larger gaps
3355 * could lead to image sections spanning several discontiguous regions
3356 * (NtMapViewOfSection could then refuse to map them, and they could
3357 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3359 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3360 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3361 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3372 * Merges and pads an image section's segments until they all are page-aligned
3373 * and have a size that is a multiple of the page size
3378 MmspPageAlignSegments
3380 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3386 PMM_SECTION_SEGMENT EffectiveSegment
;
3388 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3390 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3395 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3397 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3400 * The first segment requires special handling
3404 ULONG_PTR VirtualAddress
;
3405 ULONG_PTR VirtualOffset
;
3407 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3409 /* Round down the virtual address to the nearest page */
3410 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3412 /* Round up the virtual size to the nearest page */
3413 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3414 EffectiveSegment
->Image
.VirtualAddress
;
3416 /* Adjust the raw address and size */
3417 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3419 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3425 * Garbage in, garbage out: unaligned base addresses make the file
3426 * offset point in curious and odd places, but that's what we were
3429 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3430 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3434 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3435 ULONG_PTR EndOfEffectiveSegment
;
3437 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3438 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3441 * The current segment begins exactly where the current effective
3442 * segment ended, therefore beginning a new effective segment
3444 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3447 ASSERT(LastSegment
<= i
);
3448 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3450 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3452 if (LastSegment
!= i
)
3455 * Copy the current segment. If necessary, the effective segment
3456 * will be expanded later
3458 *EffectiveSegment
= *Segment
;
3462 * Page-align the virtual size. We know for sure the virtual address
3465 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3466 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3469 * The current segment is still part of the current effective segment:
3470 * extend the effective segment to reflect this
3472 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3474 static const ULONG FlagsToProtection
[16] =
3482 PAGE_EXECUTE_READWRITE
,
3483 PAGE_EXECUTE_READWRITE
,
3488 PAGE_EXECUTE_WRITECOPY
,
3489 PAGE_EXECUTE_WRITECOPY
,
3490 PAGE_EXECUTE_WRITECOPY
,
3491 PAGE_EXECUTE_WRITECOPY
3494 unsigned ProtectionFlags
;
3497 * Extend the file size
3500 /* Unaligned segments must be contiguous within the file */
3501 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3502 EffectiveSegment
->RawLength
.QuadPart
))
3507 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3510 * Extend the virtual size
3512 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3514 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3515 EffectiveSegment
->Image
.VirtualAddress
;
3518 * Merge the protection
3520 EffectiveSegment
->Protection
|= Segment
->Protection
;
3522 /* Clean up redundance */
3523 ProtectionFlags
= 0;
3525 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3526 ProtectionFlags
|= 1 << 0;
3528 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3529 ProtectionFlags
|= 1 << 1;
3531 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3532 ProtectionFlags
|= 1 << 2;
3534 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3535 ProtectionFlags
|= 1 << 3;
3537 ASSERT(ProtectionFlags
< 16);
3538 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3540 /* If a segment was required to be shared and cannot, fail */
3541 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3542 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3548 * We assume no holes between segments at this point
3552 KeBugCheck(MEMORY_MANAGEMENT
);
3556 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3562 ExeFmtpCreateImageSection(PFILE_OBJECT FileObject
,
3563 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3565 LARGE_INTEGER Offset
;
3567 PVOID FileHeaderBuffer
;
3568 ULONG FileHeaderSize
;
3570 ULONG OldNrSegments
;
3575 * Read the beginning of the file (2 pages). Should be enough to contain
3576 * all (or most) of the headers
3578 Offset
.QuadPart
= 0;
3580 Status
= ExeFmtpReadFile (FileObject
,
3587 if (!NT_SUCCESS(Status
))
3590 if (FileHeaderSize
== 0)
3592 ExFreePool(FileHeaderBuffer
);
3593 return STATUS_UNSUCCESSFUL
;
3597 * Look for a loader that can handle this executable
3599 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3601 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3604 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3610 ExeFmtpAllocateSegments
);
3612 if (!NT_SUCCESS(Status
))
3614 if (ImageSectionObject
->Segments
)
3616 ExFreePool(ImageSectionObject
->Segments
);
3617 ImageSectionObject
->Segments
= NULL
;
3621 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3625 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3628 * No loader handled the format
3630 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3632 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3633 ASSERT(!NT_SUCCESS(Status
));
3636 if (!NT_SUCCESS(Status
))
3639 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3644 /* FIXME? are these values platform-dependent? */
3645 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3646 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3648 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3649 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3651 if(ImageSectionObject
->BasedAddress
== NULL
)
3653 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3654 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3656 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3660 * And now the fun part: fixing the segments
3663 /* Sort them by virtual address */
3664 MmspSortSegments(ImageSectionObject
, Flags
);
3666 /* Ensure they don't overlap in memory */
3667 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3668 return STATUS_INVALID_IMAGE_FORMAT
;
3670 /* Ensure they are aligned */
3671 OldNrSegments
= ImageSectionObject
->NrSegments
;
3673 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3674 return STATUS_INVALID_IMAGE_FORMAT
;
3676 /* Trim them if the alignment phase merged some of them */
3677 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3679 PMM_SECTION_SEGMENT Segments
;
3680 SIZE_T SizeOfSegments
;
3682 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3684 Segments
= ExAllocatePoolWithTag(PagedPool
,
3686 TAG_MM_SECTION_SEGMENT
);
3688 if (Segments
== NULL
)
3689 return STATUS_INSUFFICIENT_RESOURCES
;
3691 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3692 ExFreePool(ImageSectionObject
->Segments
);
3693 ImageSectionObject
->Segments
= Segments
;
3696 /* And finish their initialization */
3697 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3699 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3700 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3701 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3704 ASSERT(NT_SUCCESS(Status
));
3709 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3710 ACCESS_MASK DesiredAccess
,
3711 POBJECT_ATTRIBUTES ObjectAttributes
,
3712 PLARGE_INTEGER UMaximumSize
,
3713 ULONG SectionPageProtection
,
3714 ULONG AllocationAttributes
,
3715 PFILE_OBJECT FileObject
)
3717 PROS_SECTION_OBJECT Section
;
3719 PMM_SECTION_SEGMENT SectionSegments
;
3720 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3723 if (FileObject
== NULL
)
3724 return STATUS_INVALID_FILE_FOR_SECTION
;
3727 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3729 DPRINT1("Denying section creation due to missing cache initialization\n");
3730 return STATUS_INVALID_FILE_FOR_SECTION
;
3735 * Create the section
3737 Status
= ObCreateObject (ExGetPreviousMode(),
3738 MmSectionObjectType
,
3740 ExGetPreviousMode(),
3742 sizeof(ROS_SECTION_OBJECT
),
3745 (PVOID
*)(PVOID
)&Section
);
3746 if (!NT_SUCCESS(Status
))
3748 ObDereferenceObject(FileObject
);
3755 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3756 Section
->Type
= 'SC';
3757 Section
->Size
= 'TN';
3758 Section
->SectionPageProtection
= SectionPageProtection
;
3759 Section
->AllocationAttributes
= AllocationAttributes
;
3763 * Initialized caching for this file object if previously caching
3764 * was initialized for the same on disk file
3766 Status
= CcTryToInitializeFileCache(FileObject
);
3768 Status
= STATUS_SUCCESS
;
3771 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3773 NTSTATUS StatusExeFmt
;
3775 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3776 if (ImageSectionObject
== NULL
)
3778 ObDereferenceObject(FileObject
);
3779 ObDereferenceObject(Section
);
3780 return(STATUS_NO_MEMORY
);
3783 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3785 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3787 if (!NT_SUCCESS(StatusExeFmt
))
3789 if(ImageSectionObject
->Segments
!= NULL
)
3790 ExFreePool(ImageSectionObject
->Segments
);
3793 * If image file is empty, then return that the file is invalid for section
3795 Status
= StatusExeFmt
;
3796 if (StatusExeFmt
== STATUS_END_OF_FILE
)
3798 Status
= STATUS_INVALID_FILE_FOR_SECTION
;
3801 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3802 ObDereferenceObject(Section
);
3803 ObDereferenceObject(FileObject
);
3807 Section
->ImageSection
= ImageSectionObject
;
3808 ASSERT(ImageSectionObject
->Segments
);
3813 Status
= MmspWaitForFileLock(FileObject
);
3814 if (!NT_SUCCESS(Status
))
3816 ExFreePool(ImageSectionObject
->Segments
);
3817 ExFreePool(ImageSectionObject
);
3818 ObDereferenceObject(Section
);
3819 ObDereferenceObject(FileObject
);
3823 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3824 ImageSectionObject
, NULL
))
3827 * An other thread has initialized the same image in the background
3829 ExFreePool(ImageSectionObject
->Segments
);
3830 ExFreePool(ImageSectionObject
);
3831 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3832 Section
->ImageSection
= ImageSectionObject
;
3833 SectionSegments
= ImageSectionObject
->Segments
;
3835 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3837 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3841 Status
= StatusExeFmt
;
3848 Status
= MmspWaitForFileLock(FileObject
);
3849 if (Status
!= STATUS_SUCCESS
)
3851 ObDereferenceObject(Section
);
3852 ObDereferenceObject(FileObject
);
3856 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3857 Section
->ImageSection
= ImageSectionObject
;
3858 SectionSegments
= ImageSectionObject
->Segments
;
3861 * Otherwise just reference all the section segments
3863 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3865 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3868 Status
= STATUS_SUCCESS
;
3870 Section
->FileObject
= FileObject
;
3872 CcRosReferenceCache(FileObject
);
3874 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3875 *SectionObject
= Section
;
3882 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3883 PROS_SECTION_OBJECT Section
,
3884 PMM_SECTION_SEGMENT Segment
,
3889 ULONG AllocationType
)
3895 if (Segment
->WriteCopy
)
3897 /* We have to do this because the not present fault
3898 * and access fault handlers depend on the protection
3899 * that should be granted AFTER the COW fault takes
3900 * place to be in Region->Protect. The not present fault
3901 * handler changes this to the correct protection for COW when
3902 * mapping the pages into the process's address space. If a COW
3903 * fault takes place, the access fault handler sets the page protection
3904 * to these values for the newly copied pages
3906 if (Protect
== PAGE_WRITECOPY
)
3907 Protect
= PAGE_READWRITE
;
3908 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3909 Protect
= PAGE_EXECUTE_READWRITE
;
3912 if (*BaseAddress
== NULL
)
3913 Granularity
= MM_ALLOCATION_GRANULARITY
;
3915 Granularity
= PAGE_SIZE
;
3918 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3920 LARGE_INTEGER FileOffset
;
3921 FileOffset
.QuadPart
= ViewOffset
;
3922 ObReferenceObject(Section
);
3923 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3926 Status
= MmCreateMemoryArea(AddressSpace
,
3927 MEMORY_AREA_SECTION_VIEW
,
3934 if (!NT_SUCCESS(Status
))
3936 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3937 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3941 ObReferenceObject((PVOID
)Section
);
3943 MArea
->Data
.SectionData
.Segment
= Segment
;
3944 MArea
->Data
.SectionData
.Section
= Section
;
3945 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3946 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3948 MArea
->VadNode
.u
.VadFlags
.VadType
= VadImageMap
;
3951 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3952 ViewSize
, 0, Protect
);
3954 return(STATUS_SUCCESS
);
3959 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3960 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3964 PFILE_OBJECT FileObject
;
3965 PROS_SHARED_CACHE_MAP SharedCacheMap
;
3967 LARGE_INTEGER Offset
;
3968 SWAPENTRY SavedSwapEntry
;
3969 PROS_SECTION_OBJECT Section
;
3970 PMM_SECTION_SEGMENT Segment
;
3971 PMMSUPPORT AddressSpace
;
3974 AddressSpace
= (PMMSUPPORT
)Context
;
3975 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3977 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3979 Offset
.QuadPart
= ((ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)) +
3980 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3982 Section
= MemoryArea
->Data
.SectionData
.Section
;
3983 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3985 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3986 while (Entry
&& MM_IS_WAIT_PTE(Entry
))
3988 MmUnlockSectionSegment(Segment
);
3989 MmUnlockAddressSpace(AddressSpace
);
3991 MiWaitForPageEvent(NULL
, NULL
);
3993 MmLockAddressSpace(AddressSpace
);
3994 MmLockSectionSegment(Segment
);
3995 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3999 * For a dirty, datafile, non-private page mark it as dirty in the
4002 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4004 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4007 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4008 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4009 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4011 ASSERT(SwapEntry
== 0);
4020 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4022 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4023 KeBugCheck(MEMORY_MANAGEMENT
);
4025 MmFreeSwapPage(SwapEntry
);
4029 if (IS_SWAP_FROM_SSE(Entry
) ||
4030 Page
!= PFN_FROM_SSE(Entry
))
4035 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4037 DPRINT1("Found a private page in a pagefile section.\n");
4038 KeBugCheck(MEMORY_MANAGEMENT
);
4041 * Just dereference private pages
4043 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4044 if (SavedSwapEntry
!= 0)
4046 MmFreeSwapPage(SavedSwapEntry
);
4047 MmSetSavedSwapEntryPage(Page
, 0);
4049 MmDeleteRmap(Page
, Process
, Address
);
4050 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4054 MmDeleteRmap(Page
, Process
, Address
);
4055 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4061 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4065 PMEMORY_AREA MemoryArea
;
4066 PROS_SECTION_OBJECT Section
;
4067 PMM_SECTION_SEGMENT Segment
;
4068 PLIST_ENTRY CurrentEntry
;
4069 PMM_REGION CurrentRegion
;
4070 PLIST_ENTRY RegionListHead
;
4072 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4074 if (MemoryArea
== NULL
)
4076 return(STATUS_UNSUCCESSFUL
);
4079 Section
= MemoryArea
->Data
.SectionData
.Section
;
4080 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4083 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4085 MmUnlockAddressSpace(AddressSpace
);
4086 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4087 MmLockAddressSpace(AddressSpace
);
4093 MemoryArea
->DeleteInProgress
= TRUE
;
4095 MmLockSectionSegment(Segment
);
4097 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4098 while (!IsListEmpty(RegionListHead
))
4100 CurrentEntry
= RemoveHeadList(RegionListHead
);
4101 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4102 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4105 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4107 Status
= MmFreeMemoryArea(AddressSpace
,
4114 Status
= MmFreeMemoryArea(AddressSpace
,
4119 MmUnlockSectionSegment(Segment
);
4120 ObDereferenceObject(Section
);
4126 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4127 IN PVOID BaseAddress
,
4128 IN BOOLEAN SkipDebuggerNotify
)
4131 PMEMORY_AREA MemoryArea
;
4132 PMMSUPPORT AddressSpace
;
4133 PROS_SECTION_OBJECT Section
;
4134 PVOID ImageBaseAddress
= 0;
4136 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4137 Process
, BaseAddress
);
4141 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4143 MmLockAddressSpace(AddressSpace
);
4144 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4146 if (MemoryArea
== NULL
||
4147 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4148 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4149 MemoryArea
->DeleteInProgress
)
4151 if (MemoryArea
) ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4152 MmUnlockAddressSpace(AddressSpace
);
4153 return STATUS_NOT_MAPPED_VIEW
;
4156 Section
= MemoryArea
->Data
.SectionData
.Section
;
4158 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4162 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4163 PMM_SECTION_SEGMENT SectionSegments
;
4164 PMM_SECTION_SEGMENT Segment
;
4166 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4167 ImageSectionObject
= Section
->ImageSection
;
4168 SectionSegments
= ImageSectionObject
->Segments
;
4169 NrSegments
= ImageSectionObject
->NrSegments
;
4171 MemoryArea
->DeleteInProgress
= TRUE
;
4173 /* Search for the current segment within the section segments
4174 * and calculate the image base address */
4175 for (i
= 0; i
< NrSegments
; i
++)
4177 if (Segment
== &SectionSegments
[i
])
4179 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4183 if (i
>= NrSegments
)
4185 KeBugCheck(MEMORY_MANAGEMENT
);
4188 for (i
= 0; i
< NrSegments
; i
++)
4190 PVOID SBaseAddress
= (PVOID
)
4191 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4193 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4194 if (!NT_SUCCESS(Status
))
4196 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4197 SBaseAddress
, Process
, Status
);
4198 ASSERT(NT_SUCCESS(Status
));
4204 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4205 if (!NT_SUCCESS(Status
))
4207 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4208 BaseAddress
, Process
, Status
);
4209 ASSERT(NT_SUCCESS(Status
));
4213 MmUnlockAddressSpace(AddressSpace
);
4215 /* Notify debugger */
4216 if (ImageBaseAddress
&& !SkipDebuggerNotify
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4218 return(STATUS_SUCCESS
);
4225 * Queries the information of a section object.
4227 * @param SectionHandle
4228 * Handle to the section object. It must be opened with SECTION_QUERY
4230 * @param SectionInformationClass
4231 * Index to a certain information structure. Can be either
4232 * SectionBasicInformation or SectionImageInformation. The latter
4233 * is valid only for sections that were created with the SEC_IMAGE
4235 * @param SectionInformation
4236 * Caller supplies storage for resulting information.
4238 * Size of the supplied storage.
4239 * @param ResultLength
4249 _In_ HANDLE SectionHandle
,
4250 _In_ SECTION_INFORMATION_CLASS SectionInformationClass
,
4251 _Out_ PVOID SectionInformation
,
4252 _In_ SIZE_T SectionInformationLength
,
4253 _Out_opt_ PSIZE_T ResultLength
)
4256 KPROCESSOR_MODE PreviousMode
;
4260 PreviousMode
= ExGetPreviousMode();
4261 if (PreviousMode
!= KernelMode
)
4265 ProbeForWrite(SectionInformation
,
4266 SectionInformationLength
,
4268 if (ResultLength
!= NULL
)
4270 ProbeForWrite(ResultLength
,
4271 sizeof(*ResultLength
),
4275 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4277 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4282 if (SectionInformationClass
== SectionBasicInformation
)
4284 if (SectionInformationLength
< sizeof(SECTION_BASIC_INFORMATION
))
4286 return STATUS_INFO_LENGTH_MISMATCH
;
4289 else if (SectionInformationClass
== SectionImageInformation
)
4291 if (SectionInformationLength
< sizeof(SECTION_IMAGE_INFORMATION
))
4293 return STATUS_INFO_LENGTH_MISMATCH
;
4298 return STATUS_INVALID_INFO_CLASS
;
4301 Status
= ObReferenceObjectByHandle(SectionHandle
,
4303 MmSectionObjectType
,
4305 (PVOID
*)(PVOID
)&Section
,
4307 if (!NT_SUCCESS(Status
))
4309 DPRINT1("Failed to reference section: 0x%lx\n", Status
);
4313 if (MiIsRosSectionObject(Section
))
4315 PROS_SECTION_OBJECT RosSection
= (PROS_SECTION_OBJECT
)Section
;
4317 switch (SectionInformationClass
)
4319 case SectionBasicInformation
:
4321 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4325 Sbi
->Attributes
= RosSection
->AllocationAttributes
;
4326 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4328 Sbi
->BaseAddress
= 0;
4329 Sbi
->Size
.QuadPart
= 0;
4333 Sbi
->BaseAddress
= (PVOID
)RosSection
->Segment
->Image
.VirtualAddress
;
4334 Sbi
->Size
.QuadPart
= RosSection
->Segment
->Length
.QuadPart
;
4337 if (ResultLength
!= NULL
)
4339 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4341 Status
= STATUS_SUCCESS
;
4343 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4345 Status
= _SEH2_GetExceptionCode();
4352 case SectionImageInformation
:
4354 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4358 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4360 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4361 ImageSectionObject
= RosSection
->ImageSection
;
4363 *Sii
= ImageSectionObject
->ImageInformation
;
4366 if (ResultLength
!= NULL
)
4368 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4370 Status
= STATUS_SUCCESS
;
4372 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4374 Status
= _SEH2_GetExceptionCode();
4384 switch(SectionInformationClass
)
4386 case SectionBasicInformation
:
4388 SECTION_BASIC_INFORMATION Sbi
;
4390 Sbi
.Size
= Section
->SizeOfSection
;
4391 Sbi
.BaseAddress
= (PVOID
)Section
->Address
.StartingVpn
;
4394 if (Section
->u
.Flags
.Image
)
4395 Sbi
.Attributes
|= SEC_IMAGE
;
4396 if (Section
->u
.Flags
.Commit
)
4397 Sbi
.Attributes
|= SEC_COMMIT
;
4398 if (Section
->u
.Flags
.Reserve
)
4399 Sbi
.Attributes
|= SEC_RESERVE
;
4400 if (Section
->u
.Flags
.File
)
4401 Sbi
.Attributes
|= SEC_FILE
;
4402 if (Section
->u
.Flags
.Image
)
4403 Sbi
.Attributes
|= SEC_IMAGE
;
4405 /* FIXME : Complete/test the list of flags passed back from NtCreateSection */
4409 *((SECTION_BASIC_INFORMATION
*)SectionInformation
) = Sbi
;
4411 *ResultLength
= sizeof(Sbi
);
4413 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4415 Status
= _SEH2_GetExceptionCode();
4420 case SectionImageInformation
:
4422 if (!Section
->u
.Flags
.Image
)
4424 Status
= STATUS_SECTION_NOT_IMAGE
;
4428 /* Currently not supported */
4436 ObDereferenceObject(Section
);
4441 /**********************************************************************
4443 * MmMapViewOfSection
4446 * Maps a view of a section into the virtual address space of a
4451 * Pointer to the section object.
4454 * Pointer to the process.
4457 * Desired base address (or NULL) on entry;
4458 * Actual base address of the view on exit.
4461 * Number of high order address bits that must be zero.
4464 * Size in bytes of the initially committed section of
4468 * Offset in bytes from the beginning of the section
4469 * to the beginning of the view.
4472 * Desired length of map (or zero to map all) on entry
4473 * Actual length mapped on exit.
4475 * InheritDisposition
4476 * Specified how the view is to be shared with
4480 * Type of allocation for the pages.
4483 * Protection for the committed region of the view.
4491 MmMapViewOfSection(IN PVOID SectionObject
,
4492 IN PEPROCESS Process
,
4493 IN OUT PVOID
*BaseAddress
,
4494 IN ULONG_PTR ZeroBits
,
4495 IN SIZE_T CommitSize
,
4496 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4497 IN OUT PSIZE_T ViewSize
,
4498 IN SECTION_INHERIT InheritDisposition
,
4499 IN ULONG AllocationType
,
4502 PROS_SECTION_OBJECT Section
;
4503 PMMSUPPORT AddressSpace
;
4505 NTSTATUS Status
= STATUS_SUCCESS
;
4506 BOOLEAN NotAtBase
= FALSE
;
4508 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4510 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4511 return MmMapViewOfArm3Section(SectionObject
,
4525 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4527 return STATUS_INVALID_PAGE_PROTECTION
;
4530 /* FIXME: We should keep this, but it would break code checking equality */
4531 Protect
&= ~PAGE_NOCACHE
;
4533 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4534 AddressSpace
= &Process
->Vm
;
4536 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4538 MmLockAddressSpace(AddressSpace
);
4540 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4544 ULONG_PTR ImageBase
;
4546 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4547 PMM_SECTION_SEGMENT SectionSegments
;
4549 ImageSectionObject
= Section
->ImageSection
;
4550 SectionSegments
= ImageSectionObject
->Segments
;
4551 NrSegments
= ImageSectionObject
->NrSegments
;
4553 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4556 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4560 for (i
= 0; i
< NrSegments
; i
++)
4562 ULONG_PTR MaxExtent
;
4563 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4564 SectionSegments
[i
].Length
.QuadPart
);
4565 ImageSize
= max(ImageSize
, MaxExtent
);
4568 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4570 /* Check for an illegal base address */
4571 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4572 ((ImageBase
+ ImageSize
) < ImageSize
))
4574 ASSERT(*BaseAddress
== NULL
);
4575 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4576 MM_VIRTMEM_GRANULARITY
);
4579 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4581 ASSERT(*BaseAddress
== NULL
);
4582 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4586 /* Check there is enough space to map the section at that point. */
4587 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4588 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4590 /* Fail if the user requested a fixed base address. */
4591 if ((*BaseAddress
) != NULL
)
4593 MmUnlockAddressSpace(AddressSpace
);
4594 return(STATUS_CONFLICTING_ADDRESSES
);
4596 /* Otherwise find a gap to map the image. */
4597 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4600 MmUnlockAddressSpace(AddressSpace
);
4601 return(STATUS_CONFLICTING_ADDRESSES
);
4603 /* Remember that we loaded image at a different base address */
4607 for (i
= 0; i
< NrSegments
; i
++)
4609 PVOID SBaseAddress
= (PVOID
)
4610 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4611 MmLockSectionSegment(&SectionSegments
[i
]);
4612 Status
= MmMapViewOfSegment(AddressSpace
,
4614 &SectionSegments
[i
],
4616 SectionSegments
[i
].Length
.LowPart
,
4617 SectionSegments
[i
].Protection
,
4620 MmUnlockSectionSegment(&SectionSegments
[i
]);
4621 if (!NT_SUCCESS(Status
))
4623 MmUnlockAddressSpace(AddressSpace
);
4628 *BaseAddress
= (PVOID
)ImageBase
;
4629 *ViewSize
= ImageSize
;
4633 /* check for write access */
4634 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4635 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4637 MmUnlockAddressSpace(AddressSpace
);
4638 return STATUS_SECTION_PROTECTION
;
4640 /* check for read access */
4641 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4642 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4644 MmUnlockAddressSpace(AddressSpace
);
4645 return STATUS_SECTION_PROTECTION
;
4647 /* check for execute access */
4648 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4649 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4651 MmUnlockAddressSpace(AddressSpace
);
4652 return STATUS_SECTION_PROTECTION
;
4655 if (SectionOffset
== NULL
)
4661 ViewOffset
= SectionOffset
->u
.LowPart
;
4664 if ((ViewOffset
% PAGE_SIZE
) != 0)
4666 MmUnlockAddressSpace(AddressSpace
);
4667 return(STATUS_MAPPED_ALIGNMENT
);
4670 if ((*ViewSize
) == 0)
4672 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4674 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4676 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4679 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4681 MmLockSectionSegment(Section
->Segment
);
4682 Status
= MmMapViewOfSegment(AddressSpace
,
4689 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4690 MmUnlockSectionSegment(Section
->Segment
);
4691 if (!NT_SUCCESS(Status
))
4693 MmUnlockAddressSpace(AddressSpace
);
4698 MmUnlockAddressSpace(AddressSpace
);
4699 ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4702 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4704 Status
= STATUS_SUCCESS
;
4713 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4714 IN PLARGE_INTEGER NewFileSize
)
4716 /* Check whether an ImageSectionObject exists */
4717 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4719 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4723 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4725 PMM_SECTION_SEGMENT Segment
;
4727 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4730 if (Segment
->ReferenceCount
!= 0)
4733 CC_FILE_SIZES FileSizes
;
4735 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4738 /* Check size of file */
4739 if (SectionObjectPointer
->SharedCacheMap
)
4741 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4746 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4755 /* Check size of file */
4756 if (SectionObjectPointer
->SharedCacheMap
)
4758 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4759 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4768 /* Something must gone wrong
4769 * how can we have a Section but no
4771 DPRINT("ERROR: DataSectionObject without reference!\n");
4775 DPRINT("FIXME: didn't check for outstanding write probes\n");
4787 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4788 IN MMFLUSH_TYPE FlushType
)
4790 BOOLEAN Result
= TRUE
;
4792 PMM_SECTION_SEGMENT Segment
;
4797 case MmFlushForDelete
:
4798 if (SectionObjectPointer
->ImageSectionObject
||
4799 SectionObjectPointer
->DataSectionObject
)
4804 CcRosRemoveIfClosed(SectionObjectPointer
);
4807 case MmFlushForWrite
:
4809 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4811 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4814 if (SectionObjectPointer
->ImageSectionObject
)
4816 DPRINT1("SectionObject has ImageSection\n");
4822 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4824 DPRINT("Result %d\n", Result
);
4836 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4837 OUT PVOID
* MappedBase
,
4838 IN OUT PSIZE_T ViewSize
)
4840 PROS_SECTION_OBJECT Section
;
4841 PMMSUPPORT AddressSpace
;
4845 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4847 return MiMapViewInSystemSpace(SectionObject
,
4853 DPRINT("MmMapViewInSystemSpace() called\n");
4855 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4856 AddressSpace
= MmGetKernelAddressSpace();
4858 MmLockAddressSpace(AddressSpace
);
4861 if ((*ViewSize
) == 0)
4863 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4865 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4867 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4870 MmLockSectionSegment(Section
->Segment
);
4873 Status
= MmMapViewOfSegment(AddressSpace
,
4882 MmUnlockSectionSegment(Section
->Segment
);
4883 MmUnlockAddressSpace(AddressSpace
);
4890 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4892 PMMSUPPORT AddressSpace
;
4895 DPRINT("MmUnmapViewInSystemSpace() called\n");
4897 AddressSpace
= MmGetKernelAddressSpace();
4899 MmLockAddressSpace(AddressSpace
);
4901 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4903 MmUnlockAddressSpace(AddressSpace
);
4908 /**********************************************************************
4913 * Creates a section object.
4916 * SectionObject (OUT)
4917 * Caller supplied storage for the resulting pointer
4918 * to a SECTION_OBJECT instance;
4921 * Specifies the desired access to the section can be a
4923 * STANDARD_RIGHTS_REQUIRED |
4925 * SECTION_MAP_WRITE |
4926 * SECTION_MAP_READ |
4927 * SECTION_MAP_EXECUTE
4929 * ObjectAttributes [OPTIONAL]
4930 * Initialized attributes for the object can be used
4931 * to create a named section;
4934 * Maximizes the size of the memory section. Must be
4935 * non-NULL for a page-file backed section.
4936 * If value specified for a mapped file and the file is
4937 * not large enough, file will be extended.
4939 * SectionPageProtection
4940 * Can be a combination of:
4946 * AllocationAttributes
4947 * Can be a combination of:
4952 * Handle to a file to create a section mapped to a file
4953 * instead of a memory backed section;
4964 MmCreateSection (OUT PVOID
* Section
,
4965 IN ACCESS_MASK DesiredAccess
,
4966 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4967 IN PLARGE_INTEGER MaximumSize
,
4968 IN ULONG SectionPageProtection
,
4969 IN ULONG AllocationAttributes
,
4970 IN HANDLE FileHandle OPTIONAL
,
4971 IN PFILE_OBJECT FileObject OPTIONAL
)
4975 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4977 /* Check if an ARM3 section is being created instead */
4978 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4980 if (!(FileObject
) && !(FileHandle
))
4982 return MmCreateArm3Section(Section
,
4986 SectionPageProtection
,
4987 AllocationAttributes
&~ 1,
4993 /* Convert section flag to page flag */
4994 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4996 /* Check to make sure the protection is correct. Nt* does this already */
4997 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4998 if (Protection
== MM_INVALID_PROTECTION
)
5000 DPRINT1("Page protection is invalid\n");
5001 return STATUS_INVALID_PAGE_PROTECTION
;
5004 /* Check if this is going to be a data or image backed file section */
5005 if ((FileHandle
) || (FileObject
))
5007 /* These cannot be mapped with large pages */
5008 if (AllocationAttributes
& SEC_LARGE_PAGES
)
5010 DPRINT1("Large pages cannot be used with an image mapping\n");
5011 return STATUS_INVALID_PARAMETER_6
;
5014 /* Did the caller pass an object? */
5017 /* Reference the object directly */
5018 ObReferenceObject(FileObject
);
5022 /* Reference the file handle to get the object */
5023 Status
= ObReferenceObjectByHandle(FileHandle
,
5024 MmMakeFileAccess
[Protection
],
5026 ExGetPreviousMode(),
5027 (PVOID
*)&FileObject
,
5029 if (!NT_SUCCESS(Status
))
5031 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
5038 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
5039 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
5042 #ifndef NEWCC // A hack for initializing caching.
5043 // This is needed only in the old case.
5046 IO_STATUS_BLOCK Iosb
;
5049 LARGE_INTEGER ByteOffset
;
5050 ByteOffset
.QuadPart
= 0;
5051 Status
= ZwReadFile(FileHandle
,
5060 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5062 DPRINT1("CC failure: %lx\n", Status
);
5064 ObDereferenceObject(FileObject
);
5067 // Caching is initialized...
5069 // Hack of the hack: actually, it might not be initialized if FSD init on effective right and if file is null-size
5070 // In such case, force cache by initiating a write IRP
5071 if (Status
== STATUS_END_OF_FILE
&& !(AllocationAttributes
& SEC_IMAGE
) && FileObject
!= NULL
&&
5072 (FileObject
->SectionObjectPointer
== NULL
|| FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
))
5075 Status
= ZwWriteFile(FileHandle
,
5084 if (NT_SUCCESS(Status
))
5087 Zero
.QuadPart
= 0LL;
5089 Status
= IoSetInformation(FileObject
,
5090 FileEndOfFileInformation
,
5091 sizeof(LARGE_INTEGER
),
5093 ASSERT(NT_SUCCESS(Status
));
5099 if (AllocationAttributes
& SEC_IMAGE
)
5101 Status
= MmCreateImageSection(SectionObject
,
5105 SectionPageProtection
,
5106 AllocationAttributes
,
5110 else if (FileHandle
!= NULL
)
5112 Status
= MmCreateDataFileSection(SectionObject
,
5116 SectionPageProtection
,
5117 AllocationAttributes
,
5121 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5123 Status
= MmCreateCacheSection(SectionObject
,
5127 SectionPageProtection
,
5128 AllocationAttributes
,
5134 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5136 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5138 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5139 Status
= MmCreatePageFileSection(SectionObject
,
5143 SectionPageProtection
,
5144 AllocationAttributes
);
5146 ObDereferenceObject(FileObject
);