2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
48 #include <cache/newcc.h>
49 #include <cache/section/newmm.h>
52 #include <reactos/exeformat.h>
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 #include "ARM3/miarm.h"
61 #undef MmSetPageEntrySectionSegment
62 #define MmSetPageEntrySectionSegment(S,O,E) do { \
63 DPRINT("SetPageEntrySectionSegment(old,%p,%x,%x)\n",(S),(O)->LowPart,E); \
64 _MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__); \
67 extern MMSESSION MmSession
;
71 MiMapViewInSystemSpace(IN PVOID Section
,
73 OUT PVOID
*MappedBase
,
74 IN OUT PSIZE_T ViewSize
);
78 MmCreateArm3Section(OUT PVOID
*SectionObject
,
79 IN ACCESS_MASK DesiredAccess
,
80 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
81 IN PLARGE_INTEGER InputMaximumSize
,
82 IN ULONG SectionPageProtection
,
83 IN ULONG AllocationAttributes
,
84 IN HANDLE FileHandle OPTIONAL
,
85 IN PFILE_OBJECT FileObject OPTIONAL
);
89 MmMapViewOfArm3Section(IN PVOID SectionObject
,
91 IN OUT PVOID
*BaseAddress
,
92 IN ULONG_PTR ZeroBits
,
94 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
95 IN OUT PSIZE_T ViewSize
,
96 IN SECTION_INHERIT InheritDisposition
,
97 IN ULONG AllocationType
,
101 // PeFmtCreateSection depends on the following:
103 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
104 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
106 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
107 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
108 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
110 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
111 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
112 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
113 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
114 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
115 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
116 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
117 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
118 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
120 /* TYPES *********************************************************************/
124 PROS_SECTION_OBJECT Section
;
125 PMM_SECTION_SEGMENT Segment
;
126 LARGE_INTEGER Offset
;
129 PEPROCESS CallingProcess
;
130 ULONG_PTR SectionEntry
;
132 MM_SECTION_PAGEOUT_CONTEXT
;
134 /* GLOBALS *******************************************************************/
136 POBJECT_TYPE MmSectionObjectType
= NULL
;
138 ULONG_PTR MmSubsectionBase
;
140 static ULONG SectionCharacteristicsToProtect
[16] =
142 PAGE_NOACCESS
, /* 0 = NONE */
143 PAGE_NOACCESS
, /* 1 = SHARED */
144 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
145 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
146 PAGE_READONLY
, /* 4 = READABLE */
147 PAGE_READONLY
, /* 5 = READABLE, SHARED */
148 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
149 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
151 * FIXME? do we really need the WriteCopy field in segments? can't we use
152 * PAGE_WRITECOPY here?
154 PAGE_READWRITE
, /* 8 = WRITABLE */
155 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
156 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
157 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
158 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
159 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
160 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
161 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
164 extern ULONG MmMakeFileAccess
[];
165 ACCESS_MASK NTAPI
MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection
);
166 static GENERIC_MAPPING MmpSectionMapping
=
168 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
169 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
170 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
175 /* FUNCTIONS *****************************************************************/
180 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
181 File Format Specification", revision 6.0 (February 1999)
183 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
184 IN SIZE_T FileHeaderSize
,
186 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
188 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
189 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
192 ULONG cbFileHeaderOffsetSize
= 0;
193 ULONG cbSectionHeadersOffset
= 0;
194 ULONG cbSectionHeadersSize
;
195 ULONG cbSectionHeadersOffsetSize
= 0;
196 ULONG cbOptHeaderSize
;
197 ULONG cbHeadersSize
= 0;
198 ULONG nSectionAlignment
;
199 ULONG nFileAlignment
;
201 const IMAGE_DOS_HEADER
* pidhDosHeader
;
202 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
203 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
204 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
205 PMM_SECTION_SEGMENT pssSegments
;
206 LARGE_INTEGER lnOffset
;
208 SIZE_T nPrevVirtualEndOfSegment
= 0;
209 ULONG nFileSizeOfHeaders
= 0;
214 ASSERT(FileHeaderSize
> 0);
216 ASSERT(ImageSectionObject
);
218 ASSERT(AllocateSegmentsCb
);
220 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
222 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
224 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
227 pidhDosHeader
= FileHeader
;
230 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
232 /* image too small to be an MZ executable */
233 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
234 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
236 /* no MZ signature */
237 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
238 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
241 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
243 /* not a Windows executable */
244 if(pidhDosHeader
->e_lfanew
<= 0)
245 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
247 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
248 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
250 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
255 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
256 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
258 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
259 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
263 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
264 * need to read the header from the file
266 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
267 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
269 ULONG cbNtHeaderSize
;
273 l_ReadHeaderFromFile
:
275 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
277 /* read the header from the file */
278 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
280 if(!NT_SUCCESS(nStatus
))
282 NTSTATUS ReturnedStatus
= nStatus
;
284 /* If it attempted to read past the end of the file, it means e_lfanew is invalid */
285 if (ReturnedStatus
== STATUS_END_OF_FILE
) nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
287 DIE(("ReadFile failed, status %08X\n", ReturnedStatus
));
292 ASSERT(cbReadSize
> 0);
294 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
296 /* the buffer doesn't contain the file header */
297 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
298 DIE(("The file doesn't contain the PE file header\n"));
300 pinhNtHeader
= pData
;
302 /* object still not aligned: copy it to the beginning of the buffer */
303 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
305 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
306 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
307 pinhNtHeader
= pBuffer
;
310 /* invalid NT header */
311 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
313 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
314 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
316 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
318 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
319 DIE(("The full NT header is too large\n"));
321 /* the buffer doesn't contain the whole NT header */
322 if(cbReadSize
< cbNtHeaderSize
)
323 DIE(("The file doesn't contain the full NT header\n"));
327 ULONG cbOptHeaderOffsetSize
= 0;
329 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
331 /* don't trust an invalid NT header */
332 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
333 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
335 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
336 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
338 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
340 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
341 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
343 /* the buffer doesn't contain the whole NT header: read it from the file */
344 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
345 goto l_ReadHeaderFromFile
;
348 /* read information from the NT header */
349 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
350 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
352 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
354 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
355 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
357 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
359 switch(piohOptHeader
->Magic
)
361 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
363 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
368 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
371 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
372 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
374 /* See [1], section 3.4.2 */
375 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
377 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
378 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
380 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
381 DIE(("The section alignment is smaller than the file alignment\n"));
383 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
384 nFileAlignment
= piohOptHeader
->FileAlignment
;
386 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
387 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
391 nSectionAlignment
= PAGE_SIZE
;
392 nFileAlignment
= PAGE_SIZE
;
395 ASSERT(IsPowerOf2(nSectionAlignment
));
396 ASSERT(IsPowerOf2(nFileAlignment
));
398 switch(piohOptHeader
->Magic
)
401 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
403 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
404 ImageBase
= piohOptHeader
->ImageBase
;
406 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
407 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
409 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
410 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
412 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
413 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
415 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
417 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
419 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
420 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
422 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
423 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
427 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
429 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
430 piohOptHeader
->AddressOfEntryPoint
);
433 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
434 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
436 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
438 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
440 if (piohOptHeader
->AddressOfEntryPoint
== 0)
442 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
446 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
447 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
449 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
451 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
454 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
455 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
456 * magic to any binary.
458 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
459 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
460 * the SxS support -- at which point, duh, this should be removed.
462 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
464 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
471 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
473 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
475 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
477 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
479 ImageBase
= pioh64OptHeader
->ImageBase
;
480 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
481 DIE(("ImageBase exceeds the address space\n"));
484 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
486 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
487 DIE(("SizeOfImage exceeds the address space\n"));
489 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
492 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
494 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
495 DIE(("SizeOfStackReserve exceeds the address space\n"));
497 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
500 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
502 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
503 DIE(("SizeOfStackCommit exceeds the address space\n"));
505 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
508 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
510 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
512 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
513 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
515 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
516 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
520 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
522 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
523 pioh64OptHeader
->AddressOfEntryPoint
);
526 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
527 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
529 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
531 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
533 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
535 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
539 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
540 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
542 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
543 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
550 /* [1], section 3.4.2 */
551 if((ULONG_PTR
)ImageBase
% 0x10000)
552 DIE(("ImageBase is not aligned on a 64KB boundary"));
554 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
555 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
556 ImageSectionObject
->ImageInformation
.GpValue
= 0;
557 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
558 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
560 /* SECTION HEADERS */
561 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
563 /* see [1], section 3.3 */
564 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
565 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
568 * the additional segment is for the file's headers. They need to be present for
569 * the benefit of the dynamic loader (to locate exports, defaults for thread
570 * parameters, resources, etc.)
572 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
574 /* file offset for the section headers */
575 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
576 DIE(("Offset overflow\n"));
578 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
579 DIE(("Offset overflow\n"));
581 /* size of the section headers */
582 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
583 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
585 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
586 DIE(("Section headers too large\n"));
588 /* size of the executable's headers */
589 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
591 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
592 // DIE(("SizeOfHeaders is not aligned\n"));
594 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
595 DIE(("The section headers overflow SizeOfHeaders\n"));
597 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
599 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
600 DIE(("Overflow aligning the size of headers\n"));
607 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
608 /* WARNING: piohOptHeader IS NO LONGER USABLE */
609 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
611 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
612 pishSectionHeaders
= NULL
;
616 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
617 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
619 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
620 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
624 * the buffer doesn't contain the section headers, or the alignment is wrong:
625 * read the headers from the file
627 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
628 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
633 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
635 /* read the header from the file */
636 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
638 if(!NT_SUCCESS(nStatus
))
639 DIE(("ReadFile failed with status %08X\n", nStatus
));
643 ASSERT(cbReadSize
> 0);
645 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
647 /* the buffer doesn't contain all the section headers */
648 if(cbReadSize
< cbSectionHeadersSize
)
649 DIE(("The file doesn't contain all of the section headers\n"));
651 pishSectionHeaders
= pData
;
653 /* object still not aligned: copy it to the beginning of the buffer */
654 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
656 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
657 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
658 pishSectionHeaders
= pBuffer
;
663 /* allocate the segments */
664 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
665 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
667 if(ImageSectionObject
->Segments
== NULL
)
668 DIE(("AllocateSegments failed\n"));
670 /* initialize the headers segment */
671 pssSegments
= ImageSectionObject
->Segments
;
673 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
675 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
676 DIE(("Cannot align the size of the section headers\n"));
678 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
679 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
680 DIE(("Cannot align the size of the section headers\n"));
682 pssSegments
[0].Image
.FileOffset
= 0;
683 pssSegments
[0].Protection
= PAGE_READONLY
;
684 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
685 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
686 pssSegments
[0].Image
.VirtualAddress
= 0;
687 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
688 pssSegments
[0].WriteCopy
= TRUE
;
690 /* skip the headers segment */
693 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
695 /* convert the executable sections into segments. See also [1], section 4 */
696 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
698 ULONG nCharacteristics
;
700 /* validate the alignment */
701 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
702 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
704 /* sections must be contiguous, ordered by base address and non-overlapping */
705 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
706 DIE(("Memory gap between section %u and the previous\n", i
));
708 /* ignore explicit BSS sections */
709 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
711 /* validate the alignment */
713 /* Yes, this should be a multiple of FileAlignment, but there's
714 * stuff out there that isn't. We can cope with that
716 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
717 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
720 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
721 // DIE(("PointerToRawData[%u] is not aligned\n", i));
724 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
725 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
729 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
730 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
733 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
735 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
737 /* no explicit protection */
738 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
740 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
741 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
743 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
744 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
746 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
747 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
750 /* see table above */
751 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
752 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
754 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
755 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
757 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
759 AlignedLength
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
760 if(AlignedLength
< pssSegments
[i
].Length
.LowPart
)
761 DIE(("Cannot align the virtual size of section %u\n", i
));
763 pssSegments
[i
].Length
.LowPart
= AlignedLength
;
765 if(pssSegments
[i
].Length
.QuadPart
== 0)
766 DIE(("Virtual size of section %u is null\n", i
));
768 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
769 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
771 /* ensure the memory image is no larger than 4GB */
772 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
773 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
774 DIE(("The image is too large\n"));
777 if(nSectionAlignment
>= PAGE_SIZE
)
778 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
781 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
791 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
792 * ARGUMENTS: PFILE_OBJECT to wait for.
793 * RETURNS: Status of the wait.
796 MmspWaitForFileLock(PFILE_OBJECT File
)
798 return STATUS_SUCCESS
;
799 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
804 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
806 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
808 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
809 PMM_SECTION_SEGMENT SectionSegments
;
813 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
814 NrSegments
= ImageSectionObject
->NrSegments
;
815 SectionSegments
= ImageSectionObject
->Segments
;
816 for (i
= 0; i
< NrSegments
; i
++)
818 if (SectionSegments
[i
].ReferenceCount
!= 0)
820 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
821 SectionSegments
[i
].ReferenceCount
);
822 KeBugCheck(MEMORY_MANAGEMENT
);
824 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
826 ExFreePool(ImageSectionObject
->Segments
);
827 ExFreePool(ImageSectionObject
);
828 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
830 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
832 PMM_SECTION_SEGMENT Segment
;
834 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
837 if (Segment
->ReferenceCount
!= 0)
839 DPRINT1("Data segment still referenced\n");
840 KeBugCheck(MEMORY_MANAGEMENT
);
842 MmFreePageTablesSectionSegment(Segment
, NULL
);
844 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
850 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
851 PLARGE_INTEGER Offset
)
855 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
858 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
859 KeBugCheck(MEMORY_MANAGEMENT
);
861 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
863 DPRINT1("Maximum share count reached\n");
864 KeBugCheck(MEMORY_MANAGEMENT
);
866 if (IS_SWAP_FROM_SSE(Entry
))
868 KeBugCheck(MEMORY_MANAGEMENT
);
870 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
871 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
876 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
877 PMM_SECTION_SEGMENT Segment
,
878 PLARGE_INTEGER Offset
,
883 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
884 BOOLEAN IsDirectMapped
= FALSE
;
888 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
889 KeBugCheck(MEMORY_MANAGEMENT
);
891 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
893 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
894 KeBugCheck(MEMORY_MANAGEMENT
);
896 if (IS_SWAP_FROM_SSE(Entry
))
898 KeBugCheck(MEMORY_MANAGEMENT
);
900 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
902 * If we reducing the share count of this entry to zero then set the entry
903 * to zero and tell the cache the page is no longer mapped.
905 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
907 PFILE_OBJECT FileObject
;
908 SWAPENTRY SavedSwapEntry
;
911 PROS_SHARED_CACHE_MAP SharedCacheMap
;
912 BOOLEAN IsImageSection
;
913 LARGE_INTEGER FileOffset
;
915 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
916 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
919 Page
= PFN_FROM_SSE(Entry
);
920 FileObject
= Section
->FileObject
;
921 if (FileObject
!= NULL
&&
922 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
926 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
927 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
930 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
931 IsDirectMapped
= TRUE
;
933 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
.QuadPart
, Dirty
);
935 Status
= STATUS_SUCCESS
;
937 if (!NT_SUCCESS(Status
))
939 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
940 KeBugCheck(MEMORY_MANAGEMENT
);
946 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
947 if (SavedSwapEntry
== 0)
950 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
951 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
955 * Try to page out this page and set the swap entry
956 * within the section segment. There exist no rmap entry
957 * for this page. The pager thread can't page out a
958 * page without a rmap entry.
960 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
961 if (InEntry
) *InEntry
= Entry
;
962 MiSetPageEvent(NULL
, NULL
);
966 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
967 if (InEntry
) *InEntry
= 0;
968 MiSetPageEvent(NULL
, NULL
);
971 MmReleasePageMemoryConsumer(MC_USER
, Page
);
977 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
978 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
986 * We hold all locks. Nobody can do something with the current
987 * process and the current segment (also not within an other process).
990 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
991 if (!NT_SUCCESS(Status
))
993 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
994 KeBugCheck(MEMORY_MANAGEMENT
);
997 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
998 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
999 MmSetSavedSwapEntryPage(Page
, 0);
1000 MiSetPageEvent(NULL
, NULL
);
1002 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1006 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1007 KeBugCheck(MEMORY_MANAGEMENT
);
1016 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1018 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1021 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1025 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1027 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1029 SharedCacheMap
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1030 Vacb
= CcRosLookupVacb(SharedCacheMap
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
);
1033 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, FALSE
, TRUE
);
1043 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1047 PVOID DestAddress
, SrcAddress
;
1049 Process
= PsGetCurrentProcess();
1050 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1051 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1052 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1054 return(STATUS_NO_MEMORY
);
1056 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1057 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1058 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1059 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1060 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1061 return(STATUS_SUCCESS
);
1067 MiReadPage(PMEMORY_AREA MemoryArea
,
1071 * FUNCTION: Read a page for a section backed memory area.
1073 * MemoryArea - Memory area to read the page for.
1074 * Offset - Offset of the page to read.
1075 * Page - Variable that receives a page contains the read data.
1078 LONGLONG BaseOffset
;
1079 LONGLONG FileOffset
;
1083 PFILE_OBJECT FileObject
;
1086 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1087 BOOLEAN IsImageSection
;
1090 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1091 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1092 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
;
1093 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1094 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1096 ASSERT(SharedCacheMap
);
1098 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1101 * If the file system is letting us go directly to the cache and the
1102 * memory area was mapped at an offset in the file which is page aligned
1103 * then get the related VACB.
1105 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1106 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1107 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1111 * Get the related VACB; we use a lower level interface than
1112 * filesystems do because it is safe for us to use an offset with an
1113 * alignment less than the file system block size.
1115 Status
= CcRosGetVacb(SharedCacheMap
,
1121 if (!NT_SUCCESS(Status
))
1128 * If the VACB isn't up to date then call the file
1129 * system to read in the data.
1131 Status
= CcReadVirtualAddress(Vacb
);
1132 if (!NT_SUCCESS(Status
))
1134 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1139 /* Probe the page, since it's PDE might not be synced */
1140 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1143 * Retrieve the page from the view that we actually want.
1145 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1146 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1148 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, TRUE
);
1155 LONGLONG VacbOffset
;
1158 * Allocate a page, this is rather complicated by the possibility
1159 * we might have to move other things out of memory
1161 MI_SET_USAGE(MI_USAGE_SECTION
);
1162 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1163 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1164 if (!NT_SUCCESS(Status
))
1168 Status
= CcRosGetVacb(SharedCacheMap
,
1174 if (!NT_SUCCESS(Status
))
1181 * If the VACB isn't up to date then call the file
1182 * system to read in the data.
1184 Status
= CcReadVirtualAddress(Vacb
);
1185 if (!NT_SUCCESS(Status
))
1187 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1192 Process
= PsGetCurrentProcess();
1193 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1194 VacbOffset
= BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
;
1195 Length
= RawLength
- SegOffset
;
1196 if (Length
<= VacbOffset
&& Length
<= PAGE_SIZE
)
1198 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1200 else if (VacbOffset
>= PAGE_SIZE
)
1202 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1206 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, VacbOffset
);
1207 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1208 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1209 Status
= CcRosGetVacb(SharedCacheMap
,
1210 FileOffset
+ VacbOffset
,
1215 if (!NT_SUCCESS(Status
))
1222 * If the VACB isn't up to date then call the file
1223 * system to read in the data.
1225 Status
= CcReadVirtualAddress(Vacb
);
1226 if (!NT_SUCCESS(Status
))
1228 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1232 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1233 if (Length
< PAGE_SIZE
)
1235 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, Length
- VacbOffset
);
1239 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, PAGE_SIZE
- VacbOffset
);
1242 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1243 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1245 return(STATUS_SUCCESS
);
1250 MiReadPage(PMEMORY_AREA MemoryArea
,
1254 * FUNCTION: Read a page for a section backed memory area.
1256 * MemoryArea - Memory area to read the page for.
1257 * Offset - Offset of the page to read.
1258 * Page - Variable that receives a page contains the read data.
1261 MM_REQUIRED_RESOURCES Resources
;
1264 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1266 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1267 Resources
.FileOffset
.QuadPart
= SegOffset
+
1268 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1269 Resources
.Consumer
= MC_USER
;
1270 Resources
.Amount
= PAGE_SIZE
;
1272 DPRINT("%S, offset 0x%x, len 0x%x, page 0x%x\n", ((PFILE_OBJECT
)Resources
.Context
)->FileName
.Buffer
, Resources
.FileOffset
.LowPart
, Resources
.Amount
, Resources
.Page
[0]);
1274 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1275 *Page
= Resources
.Page
[0];
1282 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1283 MEMORY_AREA
* MemoryArea
,
1287 LARGE_INTEGER Offset
;
1290 PROS_SECTION_OBJECT Section
;
1291 PMM_SECTION_SEGMENT Segment
;
1296 BOOLEAN HasSwapEntry
;
1298 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1299 SWAPENTRY SwapEntry
;
1302 * There is a window between taking the page fault and locking the
1303 * address space when another thread could load the page so we check
1306 if (MmIsPagePresent(Process
, Address
))
1308 return(STATUS_SUCCESS
);
1311 if (MmIsDisabledPage(Process
, Address
))
1313 return(STATUS_ACCESS_VIOLATION
);
1317 * Check for the virtual memory area being deleted.
1319 if (MemoryArea
->DeleteInProgress
)
1321 return(STATUS_UNSUCCESSFUL
);
1324 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1325 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1326 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1328 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1329 Section
= MemoryArea
->Data
.SectionData
.Section
;
1330 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1331 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1333 ASSERT(Region
!= NULL
);
1337 MmLockSectionSegment(Segment
);
1338 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1340 * Check if this page needs to be mapped COW
1342 if ((Segment
->WriteCopy
) &&
1343 (Region
->Protect
== PAGE_READWRITE
||
1344 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1346 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1350 Attributes
= Region
->Protect
;
1354 * Check if someone else is already handling this fault, if so wait
1357 if (Entry
&& MM_IS_WAIT_PTE(Entry
))
1359 MmUnlockSectionSegment(Segment
);
1360 MmUnlockAddressSpace(AddressSpace
);
1361 MiWaitForPageEvent(NULL
, NULL
);
1362 MmLockAddressSpace(AddressSpace
);
1363 DPRINT("Address 0x%p\n", Address
);
1364 return(STATUS_MM_RESTART_OPERATION
);
1367 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1369 /* See if we should use a private page */
1370 if ((HasSwapEntry
) || (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
))
1372 SWAPENTRY DummyEntry
;
1375 * Is it a wait entry?
1379 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1381 if (SwapEntry
== MM_WAIT_ENTRY
)
1383 MmUnlockSectionSegment(Segment
);
1384 MmUnlockAddressSpace(AddressSpace
);
1385 MiWaitForPageEvent(NULL
, NULL
);
1386 MmLockAddressSpace(AddressSpace
);
1387 return STATUS_MM_RESTART_OPERATION
;
1391 * Must be private page we have swapped out.
1397 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1399 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1400 KeBugCheck(MEMORY_MANAGEMENT
);
1402 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1405 MmUnlockSectionSegment(Segment
);
1407 /* Tell everyone else we are serving the fault. */
1408 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1410 MmUnlockAddressSpace(AddressSpace
);
1411 MI_SET_USAGE(MI_USAGE_SECTION
);
1412 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1413 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1414 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1415 if (!NT_SUCCESS(Status
))
1417 KeBugCheck(MEMORY_MANAGEMENT
);
1422 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1423 if (!NT_SUCCESS(Status
))
1425 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1426 KeBugCheck(MEMORY_MANAGEMENT
);
1430 MmLockAddressSpace(AddressSpace
);
1431 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1432 Status
= MmCreateVirtualMapping(Process
,
1437 if (!NT_SUCCESS(Status
))
1439 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1440 KeBugCheck(MEMORY_MANAGEMENT
);
1445 * Store the swap entry for later use.
1448 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1451 * Add the page to the process's working set
1453 MmInsertRmap(Page
, Process
, Address
);
1455 * Finish the operation
1457 MiSetPageEvent(Process
, Address
);
1458 DPRINT("Address 0x%p\n", Address
);
1459 return(STATUS_SUCCESS
);
1463 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1465 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1467 MmUnlockSectionSegment(Segment
);
1469 * Just map the desired physical page
1471 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1472 Status
= MmCreateVirtualMappingUnsafe(Process
,
1477 if (!NT_SUCCESS(Status
))
1479 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1480 KeBugCheck(MEMORY_MANAGEMENT
);
1485 * Cleanup and release locks
1487 MiSetPageEvent(Process
, Address
);
1488 DPRINT("Address 0x%p\n", Address
);
1489 return(STATUS_SUCCESS
);
1493 * Get the entry corresponding to the offset within the section
1495 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1499 SWAPENTRY FakeSwapEntry
;
1502 * If the entry is zero (and it can't change because we have
1503 * locked the segment) then we need to load the page.
1507 * Release all our locks and read in the page from disk
1509 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1510 MmUnlockSectionSegment(Segment
);
1511 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1512 MmUnlockAddressSpace(AddressSpace
);
1514 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1515 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1516 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1518 MI_SET_USAGE(MI_USAGE_SECTION
);
1519 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1520 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1521 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1522 if (!NT_SUCCESS(Status
))
1524 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1530 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1531 if (!NT_SUCCESS(Status
))
1533 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1536 if (!NT_SUCCESS(Status
))
1539 * FIXME: What do we know in this case?
1542 * Cleanup and release locks
1544 MmLockAddressSpace(AddressSpace
);
1545 MiSetPageEvent(Process
, Address
);
1546 DPRINT("Address 0x%p\n", Address
);
1550 /* Lock both segment and process address space while we proceed. */
1551 MmLockAddressSpace(AddressSpace
);
1552 MmLockSectionSegment(Segment
);
1554 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1555 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1556 Page
, Process
, PAddress
, Attributes
);
1557 Status
= MmCreateVirtualMapping(Process
,
1562 if (!NT_SUCCESS(Status
))
1564 DPRINT1("Unable to create virtual mapping\n");
1565 KeBugCheck(MEMORY_MANAGEMENT
);
1567 ASSERT(MmIsPagePresent(Process
, PAddress
));
1568 MmInsertRmap(Page
, Process
, Address
);
1570 /* Set this section offset has being backed by our new page. */
1571 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1572 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1573 MmUnlockSectionSegment(Segment
);
1575 MiSetPageEvent(Process
, Address
);
1576 DPRINT("Address 0x%p\n", Address
);
1577 return(STATUS_SUCCESS
);
1579 else if (IS_SWAP_FROM_SSE(Entry
))
1581 SWAPENTRY SwapEntry
;
1583 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1585 /* See if a page op is running on this segment. */
1586 if (SwapEntry
== MM_WAIT_ENTRY
)
1588 MmUnlockSectionSegment(Segment
);
1589 MmUnlockAddressSpace(AddressSpace
);
1590 MiWaitForPageEvent(NULL
, NULL
);
1591 MmLockAddressSpace(AddressSpace
);
1592 return STATUS_MM_RESTART_OPERATION
;
1596 * Release all our locks and read in the page from disk
1598 MmUnlockSectionSegment(Segment
);
1600 MmUnlockAddressSpace(AddressSpace
);
1601 MI_SET_USAGE(MI_USAGE_SECTION
);
1602 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1603 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1604 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1605 if (!NT_SUCCESS(Status
))
1607 KeBugCheck(MEMORY_MANAGEMENT
);
1610 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1611 if (!NT_SUCCESS(Status
))
1613 KeBugCheck(MEMORY_MANAGEMENT
);
1617 * Relock the address space and segment
1619 MmLockAddressSpace(AddressSpace
);
1620 MmLockSectionSegment(Segment
);
1623 * Check the entry. No one should change the status of a page
1624 * that has a pending page-in.
1626 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1627 if (Entry
!= Entry1
)
1629 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1630 KeBugCheck(MEMORY_MANAGEMENT
);
1634 * Save the swap entry.
1636 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1638 /* Map the page into the process address space */
1639 Status
= MmCreateVirtualMapping(Process
,
1644 if (!NT_SUCCESS(Status
))
1646 DPRINT1("Unable to create virtual mapping\n");
1647 KeBugCheck(MEMORY_MANAGEMENT
);
1649 MmInsertRmap(Page
, Process
, Address
);
1652 * Mark the offset within the section as having valid, in-memory
1655 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1656 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1657 MmUnlockSectionSegment(Segment
);
1659 MiSetPageEvent(Process
, Address
);
1660 DPRINT("Address 0x%p\n", Address
);
1661 return(STATUS_SUCCESS
);
1665 /* We already have a page on this section offset. Map it into the process address space. */
1666 Page
= PFN_FROM_SSE(Entry
);
1668 Status
= MmCreateVirtualMapping(Process
,
1673 if (!NT_SUCCESS(Status
))
1675 DPRINT1("Unable to create virtual mapping\n");
1676 KeBugCheck(MEMORY_MANAGEMENT
);
1678 MmInsertRmap(Page
, Process
, Address
);
1680 /* Take a reference on it */
1681 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1682 MmUnlockSectionSegment(Segment
);
1684 MiSetPageEvent(Process
, Address
);
1685 DPRINT("Address 0x%p\n", Address
);
1686 return(STATUS_SUCCESS
);
1692 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1693 MEMORY_AREA
* MemoryArea
,
1696 PMM_SECTION_SEGMENT Segment
;
1697 PROS_SECTION_OBJECT Section
;
1702 LARGE_INTEGER Offset
;
1705 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1707 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1709 /* Make sure we have a page mapping for this address. */
1710 Status
= MmNotPresentFaultSectionView(AddressSpace
, MemoryArea
, Address
, TRUE
);
1711 if (!NT_SUCCESS(Status
))
1713 /* This is invalid access ! */
1718 * Check if the page has already been set readwrite
1720 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1722 DPRINT("Address 0x%p\n", Address
);
1723 return(STATUS_SUCCESS
);
1727 * Find the offset of the page
1729 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1730 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1731 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1733 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1734 Section
= MemoryArea
->Data
.SectionData
.Section
;
1735 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1736 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1738 ASSERT(Region
!= NULL
);
1741 * Check if we are doing COW
1743 if (!((Segment
->WriteCopy
) &&
1744 (Region
->Protect
== PAGE_READWRITE
||
1745 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1747 DPRINT("Address 0x%p\n", Address
);
1748 return(STATUS_ACCESS_VIOLATION
);
1751 /* Get the page mapping this section offset. */
1752 MmLockSectionSegment(Segment
);
1753 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1755 /* Get the current page mapping for the process */
1756 ASSERT(MmIsPagePresent(Process
, PAddress
));
1757 OldPage
= MmGetPfnForProcess(Process
, PAddress
);
1758 ASSERT(OldPage
!= 0);
1760 if (IS_SWAP_FROM_SSE(Entry
) ||
1761 PFN_FROM_SSE(Entry
) != OldPage
)
1763 MmUnlockSectionSegment(Segment
);
1764 /* This is a private page. We must only change the page protection. */
1765 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1766 return(STATUS_SUCCESS
);
1772 MI_SET_USAGE(MI_USAGE_SECTION
);
1773 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1774 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1775 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1776 if (!NT_SUCCESS(Status
))
1778 KeBugCheck(MEMORY_MANAGEMENT
);
1784 MiCopyFromUserPage(NewPage
, OldPage
);
1787 * Unshare the old page.
1789 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1790 MmDeleteVirtualMapping(Process
, PAddress
, NULL
, NULL
);
1791 MmDeleteRmap(OldPage
, Process
, PAddress
);
1792 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1793 MmUnlockSectionSegment(Segment
);
1796 * Set the PTE to point to the new page
1798 Status
= MmCreateVirtualMapping(Process
,
1803 if (!NT_SUCCESS(Status
))
1805 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1806 KeBugCheck(MEMORY_MANAGEMENT
);
1809 MmInsertRmap(NewPage
, Process
, PAddress
);
1811 MiSetPageEvent(Process
, Address
);
1812 DPRINT("Address 0x%p\n", Address
);
1813 return(STATUS_SUCCESS
);
1817 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1819 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1821 PFN_NUMBER Page
= 0;
1823 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1826 MmLockAddressSpace(&Process
->Vm
);
1829 MmDeleteVirtualMapping(Process
,
1835 PageOutContext
->WasDirty
= TRUE
;
1837 if (!PageOutContext
->Private
)
1839 MmLockSectionSegment(PageOutContext
->Segment
);
1840 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1841 PageOutContext
->Segment
,
1842 &PageOutContext
->Offset
,
1843 PageOutContext
->WasDirty
,
1845 &PageOutContext
->SectionEntry
);
1846 MmUnlockSectionSegment(PageOutContext
->Segment
);
1850 MmUnlockAddressSpace(&Process
->Vm
);
1853 if (PageOutContext
->Private
)
1855 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1861 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1862 MEMORY_AREA
* MemoryArea
,
1863 PVOID Address
, ULONG_PTR Entry
)
1866 MM_SECTION_PAGEOUT_CONTEXT Context
;
1867 SWAPENTRY SwapEntry
;
1870 ULONGLONG FileOffset
;
1871 PFILE_OBJECT FileObject
;
1872 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1873 BOOLEAN IsImageSection
;
1875 BOOLEAN DirectMapped
;
1876 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1879 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1882 * Get the segment and section.
1884 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1885 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1886 Context
.SectionEntry
= Entry
;
1887 Context
.CallingProcess
= Process
;
1889 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
1890 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1892 DirectMapped
= FALSE
;
1894 MmLockSectionSegment(Context
.Segment
);
1897 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1898 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1899 FileObject
= Context
.Section
->FileObject
;
1901 if (FileObject
!= NULL
&&
1902 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1904 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1907 * If the file system is letting us go directly to the cache and the
1908 * memory area was mapped at an offset in the file which is page aligned
1909 * then note this is a direct mapped page.
1911 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1912 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1914 DirectMapped
= TRUE
;
1921 * This should never happen since mappings of physical memory are never
1922 * placed in the rmap lists.
1924 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1926 DPRINT1("Trying to page out from physical memory section address 0x%p "
1927 "process %p\n", Address
,
1928 Process
? Process
->UniqueProcessId
: 0);
1929 KeBugCheck(MEMORY_MANAGEMENT
);
1933 * Get the section segment entry and the physical address.
1935 if (!MmIsPagePresent(Process
, Address
))
1937 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1938 Process
? Process
->UniqueProcessId
: 0, Address
);
1939 KeBugCheck(MEMORY_MANAGEMENT
);
1941 Page
= MmGetPfnForProcess(Process
, Address
);
1942 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1945 * Check the reference count to ensure this page can be paged out
1947 if (MmGetReferenceCountPage(Page
) != 1)
1949 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1950 Page
, MmGetReferenceCountPage(Page
));
1951 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1952 MmUnlockSectionSegment(Context
.Segment
);
1953 return STATUS_UNSUCCESSFUL
;
1957 * Prepare the context structure for the rmap delete call.
1959 MmUnlockSectionSegment(Context
.Segment
);
1960 Context
.WasDirty
= FALSE
;
1961 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1962 IS_SWAP_FROM_SSE(Entry
) ||
1963 PFN_FROM_SSE(Entry
) != Page
)
1965 Context
.Private
= TRUE
;
1969 Context
.Private
= FALSE
;
1973 * Take an additional reference to the page or the VACB.
1975 if (DirectMapped
&& !Context
.Private
)
1977 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
1979 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1980 KeBugCheck(MEMORY_MANAGEMENT
);
1985 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1986 MmReferencePage(Page
);
1987 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1990 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1992 /* Since we passed in a surrogate, we'll get back the page entry
1993 * state in our context. This is intended to make intermediate
1994 * decrements of share count not release the wait entry.
1996 Entry
= Context
.SectionEntry
;
1999 * If this wasn't a private page then we should have reduced the entry to
2000 * zero by deleting all the rmaps.
2002 if (!Context
.Private
&& Entry
!= 0)
2004 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2005 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2007 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2012 * If the page wasn't dirty then we can just free it as for a readonly page.
2013 * Since we unmapped all the mappings above we know it will not suddenly
2015 * If the page is from a pagefile section and has no swap entry,
2016 * we can't free the page at this point.
2018 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2019 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2021 if (Context
.Private
)
2023 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2024 Context
.WasDirty
? "dirty" : "clean", Address
);
2025 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2027 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2029 MmSetSavedSwapEntryPage(Page
, 0);
2030 MmLockSectionSegment(Context
.Segment
);
2031 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2032 MmUnlockSectionSegment(Context
.Segment
);
2033 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2034 MiSetPageEvent(NULL
, NULL
);
2035 return(STATUS_SUCCESS
);
2038 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2040 if (Context
.Private
)
2042 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2043 Context
.WasDirty
? "dirty" : "clean", Address
);
2044 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2046 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2048 MmSetSavedSwapEntryPage(Page
, 0);
2051 MmLockSectionSegment(Context
.Segment
);
2052 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2053 MmUnlockSectionSegment(Context
.Segment
);
2055 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2056 MiSetPageEvent(NULL
, NULL
);
2057 return(STATUS_SUCCESS
);
2060 else if (!Context
.Private
&& DirectMapped
)
2064 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2066 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2069 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
, FALSE
);
2071 Status
= STATUS_SUCCESS
;
2074 if (!NT_SUCCESS(Status
))
2076 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2077 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2080 MiSetPageEvent(NULL
, NULL
);
2081 return(STATUS_SUCCESS
);
2083 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2087 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2089 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2091 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2092 MiSetPageEvent(NULL
, NULL
);
2093 return(STATUS_SUCCESS
);
2095 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2097 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2098 MmSetSavedSwapEntryPage(Page
, 0);
2099 MmLockAddressSpace(AddressSpace
);
2100 Status
= MmCreatePageFileMapping(Process
,
2103 MmUnlockAddressSpace(AddressSpace
);
2104 if (!NT_SUCCESS(Status
))
2106 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2107 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2109 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2110 MiSetPageEvent(NULL
, NULL
);
2111 return(STATUS_SUCCESS
);
2115 * If necessary, allocate an entry in the paging file for this page
2119 SwapEntry
= MmAllocSwapPage();
2122 MmShowOutOfSpaceMessagePagingFile();
2123 MmLockAddressSpace(AddressSpace
);
2125 * For private pages restore the old mappings.
2127 if (Context
.Private
)
2129 Status
= MmCreateVirtualMapping(Process
,
2131 MemoryArea
->Protect
,
2134 MmSetDirtyPage(Process
, Address
);
2143 MmLockSectionSegment(Context
.Segment
);
2146 * For non-private pages if the page wasn't direct mapped then
2147 * set it back into the section segment entry so we don't loose
2148 * our copy. Otherwise it will be handled by the cache manager.
2150 Status
= MmCreateVirtualMapping(Process
,
2152 MemoryArea
->Protect
,
2155 MmSetDirtyPage(Process
, Address
);
2159 // If we got here, the previous entry should have been a wait
2160 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2161 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2162 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2163 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2164 MmUnlockSectionSegment(Context
.Segment
);
2166 MmUnlockAddressSpace(AddressSpace
);
2167 MiSetPageEvent(NULL
, NULL
);
2168 return(STATUS_PAGEFILE_QUOTA
);
2173 * Write the page to the pagefile
2175 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2176 if (!NT_SUCCESS(Status
))
2178 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2181 * As above: undo our actions.
2182 * FIXME: Also free the swap page.
2184 MmLockAddressSpace(AddressSpace
);
2185 if (Context
.Private
)
2187 Status
= MmCreateVirtualMapping(Process
,
2189 MemoryArea
->Protect
,
2192 MmSetDirtyPage(Process
, Address
);
2199 MmLockSectionSegment(Context
.Segment
);
2200 Status
= MmCreateVirtualMapping(Process
,
2202 MemoryArea
->Protect
,
2205 MmSetDirtyPage(Process
, Address
);
2209 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2210 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2211 MmUnlockSectionSegment(Context
.Segment
);
2213 MmUnlockAddressSpace(AddressSpace
);
2214 MiSetPageEvent(NULL
, NULL
);
2215 return(STATUS_UNSUCCESSFUL
);
2219 * Otherwise we have succeeded.
2221 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2222 MmSetSavedSwapEntryPage(Page
, 0);
2223 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2224 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2226 MmLockSectionSegment(Context
.Segment
);
2227 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2228 MmUnlockSectionSegment(Context
.Segment
);
2232 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2235 if (Context
.Private
)
2237 MmLockAddressSpace(AddressSpace
);
2238 MmLockSectionSegment(Context
.Segment
);
2239 Status
= MmCreatePageFileMapping(Process
,
2242 /* We had placed a wait entry upon entry ... replace it before leaving */
2243 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2244 MmUnlockSectionSegment(Context
.Segment
);
2245 MmUnlockAddressSpace(AddressSpace
);
2246 if (!NT_SUCCESS(Status
))
2248 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2249 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2254 MmLockAddressSpace(AddressSpace
);
2255 MmLockSectionSegment(Context
.Segment
);
2256 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2257 /* We had placed a wait entry upon entry ... replace it before leaving */
2258 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2259 MmUnlockSectionSegment(Context
.Segment
);
2260 MmUnlockAddressSpace(AddressSpace
);
2263 MiSetPageEvent(NULL
, NULL
);
2264 return(STATUS_SUCCESS
);
2269 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2270 PMEMORY_AREA MemoryArea
,
2274 LARGE_INTEGER Offset
;
2275 PROS_SECTION_OBJECT Section
;
2276 PMM_SECTION_SEGMENT Segment
;
2278 SWAPENTRY SwapEntry
;
2282 PFILE_OBJECT FileObject
;
2284 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2286 BOOLEAN DirectMapped
;
2287 BOOLEAN IsImageSection
;
2288 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2290 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2292 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2293 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2296 * Get the segment and section.
2298 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2299 Section
= MemoryArea
->Data
.SectionData
.Section
;
2300 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2302 FileObject
= Section
->FileObject
;
2303 DirectMapped
= FALSE
;
2304 if (FileObject
!= NULL
&&
2305 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2308 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2312 * If the file system is letting us go directly to the cache and the
2313 * memory area was mapped at an offset in the file which is page aligned
2314 * then note this is a direct mapped page.
2316 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2317 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2319 DirectMapped
= TRUE
;
2324 * This should never happen since mappings of physical memory are never
2325 * placed in the rmap lists.
2327 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2329 DPRINT1("Trying to write back page from physical memory mapped at %p "
2330 "process %p\n", Address
,
2331 Process
? Process
->UniqueProcessId
: 0);
2332 KeBugCheck(MEMORY_MANAGEMENT
);
2336 * Get the section segment entry and the physical address.
2338 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2339 if (!MmIsPagePresent(Process
, Address
))
2341 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2342 Process
? Process
->UniqueProcessId
: 0, Address
);
2343 KeBugCheck(MEMORY_MANAGEMENT
);
2345 Page
= MmGetPfnForProcess(Process
, Address
);
2346 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2349 * Check for a private (COWed) page.
2351 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2352 IS_SWAP_FROM_SSE(Entry
) ||
2353 PFN_FROM_SSE(Entry
) != Page
)
2363 * Speculatively set all mappings of the page to clean.
2365 MmSetCleanAllRmaps(Page
);
2368 * If this page was direct mapped from the cache then the cache manager
2369 * will take care of writing it back to disk.
2371 if (DirectMapped
&& !Private
)
2373 //LARGE_INTEGER SOffset;
2374 ASSERT(SwapEntry
== 0);
2375 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2377 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
);
2379 MmLockSectionSegment(Segment
);
2380 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2381 MmUnlockSectionSegment(Segment
);
2382 MiSetPageEvent(NULL
, NULL
);
2383 return(STATUS_SUCCESS
);
2387 * If necessary, allocate an entry in the paging file for this page
2391 SwapEntry
= MmAllocSwapPage();
2394 MmSetDirtyAllRmaps(Page
);
2395 MiSetPageEvent(NULL
, NULL
);
2396 return(STATUS_PAGEFILE_QUOTA
);
2398 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2402 * Write the page to the pagefile
2404 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2405 if (!NT_SUCCESS(Status
))
2407 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2409 MmSetDirtyAllRmaps(Page
);
2410 MiSetPageEvent(NULL
, NULL
);
2411 return(STATUS_UNSUCCESSFUL
);
2415 * Otherwise we have succeeded.
2417 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2418 MiSetPageEvent(NULL
, NULL
);
2419 return(STATUS_SUCCESS
);
2423 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2431 PMEMORY_AREA MemoryArea
;
2432 PMM_SECTION_SEGMENT Segment
;
2433 BOOLEAN DoCOW
= FALSE
;
2435 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2437 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2438 ASSERT(MemoryArea
!= NULL
);
2439 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2440 MmLockSectionSegment(Segment
);
2442 if ((Segment
->WriteCopy
) &&
2443 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2448 if (OldProtect
!= NewProtect
)
2450 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2452 SWAPENTRY SwapEntry
;
2453 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2454 ULONG Protect
= NewProtect
;
2456 /* Wait for a wait entry to disappear */
2459 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2460 if (SwapEntry
!= MM_WAIT_ENTRY
)
2462 MiWaitForPageEvent(Process
, Address
);
2467 * If we doing COW for this segment then check if the page is
2470 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2472 LARGE_INTEGER Offset
;
2476 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2477 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2478 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2480 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2481 * IS_SWAP_FROM_SSE and we'll do the right thing.
2483 Page
= MmGetPfnForProcess(Process
, Address
);
2485 Protect
= PAGE_READONLY
;
2486 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2487 IS_SWAP_FROM_SSE(Entry
) ||
2488 PFN_FROM_SSE(Entry
) != Page
)
2490 Protect
= NewProtect
;
2494 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2496 MmSetPageProtect(Process
, Address
,
2502 MmUnlockSectionSegment(Segment
);
2507 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2508 PMEMORY_AREA MemoryArea
,
2516 ULONG_PTR MaxLength
;
2518 MaxLength
= MA_GetEndingAddress(MemoryArea
) - (ULONG_PTR
)BaseAddress
;
2519 if (Length
> MaxLength
)
2520 Length
= (ULONG
)MaxLength
;
2522 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2523 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2525 ASSERT(Region
!= NULL
);
2527 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2528 Region
->Protect
!= Protect
)
2530 return STATUS_INVALID_PAGE_PROTECTION
;
2533 *OldProtect
= Region
->Protect
;
2534 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
2535 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2536 BaseAddress
, Length
, Region
->Type
, Protect
,
2537 MmAlterViewAttributes
);
2543 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2545 PMEMORY_BASIC_INFORMATION Info
,
2546 PSIZE_T ResultLength
)
2549 PVOID RegionBaseAddress
;
2550 PROS_SECTION_OBJECT Section
;
2551 PMM_SECTION_SEGMENT Segment
;
2553 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2554 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2555 Address
, &RegionBaseAddress
);
2558 return STATUS_UNSUCCESSFUL
;
2561 Section
= MemoryArea
->Data
.SectionData
.Section
;
2562 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2564 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2565 Info
->AllocationBase
= (PUCHAR
)MA_GetStartingAddress(MemoryArea
) - Segment
->Image
.VirtualAddress
;
2566 Info
->Type
= MEM_IMAGE
;
2570 Info
->AllocationBase
= (PVOID
)MA_GetStartingAddress(MemoryArea
);
2571 Info
->Type
= MEM_MAPPED
;
2573 Info
->BaseAddress
= RegionBaseAddress
;
2574 Info
->AllocationProtect
= MemoryArea
->Protect
;
2575 Info
->RegionSize
= Region
->Length
;
2576 Info
->State
= MEM_COMMIT
;
2577 Info
->Protect
= Region
->Protect
;
2579 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2580 return(STATUS_SUCCESS
);
2585 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2588 LARGE_INTEGER Offset
;
2590 SWAPENTRY SavedSwapEntry
;
2595 MmLockSectionSegment(Segment
);
2597 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2598 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2600 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2603 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2604 if (IS_SWAP_FROM_SSE(Entry
))
2606 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2610 Page
= PFN_FROM_SSE(Entry
);
2611 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2612 if (SavedSwapEntry
!= 0)
2614 MmSetSavedSwapEntryPage(Page
, 0);
2615 MmFreeSwapPage(SavedSwapEntry
);
2617 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2622 MmUnlockSectionSegment(Segment
);
2626 MmpDeleteSection(PVOID ObjectBody
)
2628 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2630 /* Check if it's an ARM3, or ReactOS section */
2631 if (!MiIsRosSectionObject(Section
))
2633 MiDeleteARM3Section(ObjectBody
);
2637 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2638 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2643 PMM_SECTION_SEGMENT SectionSegments
;
2646 * NOTE: Section->ImageSection can be NULL for short time
2647 * during the section creating. If we fail for some reason
2648 * until the image section is properly initialized we shouldn't
2649 * process further here.
2651 if (Section
->ImageSection
== NULL
)
2654 SectionSegments
= Section
->ImageSection
->Segments
;
2655 NrSegments
= Section
->ImageSection
->NrSegments
;
2657 for (i
= 0; i
< NrSegments
; i
++)
2659 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2661 MmLockSectionSegment(&SectionSegments
[i
]);
2663 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2664 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2666 MmUnlockSectionSegment(&SectionSegments
[i
]);
2669 MmpFreePageFileSegment(&SectionSegments
[i
]);
2675 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2678 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2681 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2683 DPRINT("Freeing section segment\n");
2684 Section
->Segment
= NULL
;
2685 MmFinalizeSegment(Segment
);
2689 DPRINT("RefCount %d\n", RefCount
);
2696 * NOTE: Section->Segment can be NULL for short time
2697 * during the section creating.
2699 if (Section
->Segment
== NULL
)
2702 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2704 MmpFreePageFileSegment(Section
->Segment
);
2705 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2706 ExFreePool(Section
->Segment
);
2707 Section
->Segment
= NULL
;
2711 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2714 if (Section
->FileObject
!= NULL
)
2717 CcRosDereferenceCache(Section
->FileObject
);
2719 ObDereferenceObject(Section
->FileObject
);
2720 Section
->FileObject
= NULL
;
2725 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2727 IN ACCESS_MASK GrantedAccess
,
2728 IN ULONG ProcessHandleCount
,
2729 IN ULONG SystemHandleCount
)
2731 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2737 MmCreatePhysicalMemorySection(VOID
)
2739 PROS_SECTION_OBJECT PhysSection
;
2741 OBJECT_ATTRIBUTES Obj
;
2742 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2743 LARGE_INTEGER SectionSize
;
2747 * Create the section mapping physical memory
2749 SectionSize
.QuadPart
= 0xFFFFFFFF;
2750 InitializeObjectAttributes(&Obj
,
2752 OBJ_PERMANENT
| OBJ_KERNEL_EXCLUSIVE
,
2755 Status
= MmCreateSection((PVOID
)&PhysSection
,
2759 PAGE_EXECUTE_READWRITE
,
2763 if (!NT_SUCCESS(Status
))
2765 DPRINT1("Failed to create PhysicalMemory section\n");
2766 KeBugCheck(MEMORY_MANAGEMENT
);
2768 Status
= ObInsertObject(PhysSection
,
2774 if (!NT_SUCCESS(Status
))
2776 ObDereferenceObject(PhysSection
);
2778 ObCloseHandle(Handle
, KernelMode
);
2779 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2780 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2782 return(STATUS_SUCCESS
);
2788 MmInitSectionImplementation(VOID
)
2790 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2791 UNICODE_STRING Name
;
2793 DPRINT("Creating Section Object Type\n");
2795 /* Initialize the section based root */
2796 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2797 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2799 /* Initialize the Section object type */
2800 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2801 RtlInitUnicodeString(&Name
, L
"Section");
2802 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2803 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2804 ObjectTypeInitializer
.PoolType
= PagedPool
;
2805 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2806 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2807 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2808 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2809 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2810 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2811 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2813 MmCreatePhysicalMemorySection();
2815 return(STATUS_SUCCESS
);
2820 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2821 ACCESS_MASK DesiredAccess
,
2822 POBJECT_ATTRIBUTES ObjectAttributes
,
2823 PLARGE_INTEGER UMaximumSize
,
2824 ULONG SectionPageProtection
,
2825 ULONG AllocationAttributes
)
2827 * Create a section which is backed by the pagefile
2830 LARGE_INTEGER MaximumSize
;
2831 PROS_SECTION_OBJECT Section
;
2832 PMM_SECTION_SEGMENT Segment
;
2835 if (UMaximumSize
== NULL
)
2837 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2838 return(STATUS_INVALID_PARAMETER
);
2840 MaximumSize
= *UMaximumSize
;
2843 * Create the section
2845 Status
= ObCreateObject(ExGetPreviousMode(),
2846 MmSectionObjectType
,
2848 ExGetPreviousMode(),
2850 sizeof(ROS_SECTION_OBJECT
),
2853 (PVOID
*)(PVOID
)&Section
);
2854 if (!NT_SUCCESS(Status
))
2856 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2863 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2864 Section
->Type
= 'SC';
2865 Section
->Size
= 'TN';
2866 Section
->SectionPageProtection
= SectionPageProtection
;
2867 Section
->AllocationAttributes
= AllocationAttributes
;
2868 Section
->MaximumSize
= MaximumSize
;
2869 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2870 TAG_MM_SECTION_SEGMENT
);
2871 if (Segment
== NULL
)
2873 ObDereferenceObject(Section
);
2874 return(STATUS_NO_MEMORY
);
2876 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2877 Section
->Segment
= Segment
;
2878 Segment
->ReferenceCount
= 1;
2879 ExInitializeFastMutex(&Segment
->Lock
);
2880 Segment
->Image
.FileOffset
= 0;
2881 Segment
->Protection
= SectionPageProtection
;
2882 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2883 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2884 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2885 Segment
->WriteCopy
= FALSE
;
2886 Segment
->Image
.VirtualAddress
= 0;
2887 Segment
->Image
.Characteristics
= 0;
2888 *SectionObject
= Section
;
2889 MiInitializeSectionPageTable(Segment
);
2890 return(STATUS_SUCCESS
);
2895 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2896 ACCESS_MASK DesiredAccess
,
2897 POBJECT_ATTRIBUTES ObjectAttributes
,
2898 PLARGE_INTEGER UMaximumSize
,
2899 ULONG SectionPageProtection
,
2900 ULONG AllocationAttributes
,
2903 * Create a section backed by a data file
2906 PROS_SECTION_OBJECT Section
;
2908 LARGE_INTEGER MaximumSize
;
2909 PFILE_OBJECT FileObject
;
2910 PMM_SECTION_SEGMENT Segment
;
2912 FILE_STANDARD_INFORMATION FileInfo
;
2916 * Create the section
2918 Status
= ObCreateObject(ExGetPreviousMode(),
2919 MmSectionObjectType
,
2921 ExGetPreviousMode(),
2923 sizeof(ROS_SECTION_OBJECT
),
2927 if (!NT_SUCCESS(Status
))
2934 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2935 Section
->Type
= 'SC';
2936 Section
->Size
= 'TN';
2937 Section
->SectionPageProtection
= SectionPageProtection
;
2938 Section
->AllocationAttributes
= AllocationAttributes
;
2941 * Reference the file handle
2943 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2944 Status
= ObReferenceObjectByHandle(FileHandle
,
2947 ExGetPreviousMode(),
2948 (PVOID
*)(PVOID
)&FileObject
,
2950 if (!NT_SUCCESS(Status
))
2952 ObDereferenceObject(Section
);
2957 * FIXME: This is propably not entirely correct. We can't look into
2958 * the standard FCB header because it might not be initialized yet
2959 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2960 * standard file information is filled on first request).
2962 Status
= IoQueryFileInformation(FileObject
,
2963 FileStandardInformation
,
2964 sizeof(FILE_STANDARD_INFORMATION
),
2967 if (!NT_SUCCESS(Status
))
2969 ObDereferenceObject(Section
);
2970 ObDereferenceObject(FileObject
);
2975 * FIXME: Revise this once a locking order for file size changes is
2978 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2980 MaximumSize
= *UMaximumSize
;
2984 MaximumSize
= FileInfo
.EndOfFile
;
2985 /* Mapping zero-sized files isn't allowed. */
2986 if (MaximumSize
.QuadPart
== 0)
2988 ObDereferenceObject(Section
);
2989 ObDereferenceObject(FileObject
);
2990 return STATUS_MAPPED_FILE_SIZE_ZERO
;
2994 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2996 Status
= IoSetInformation(FileObject
,
2997 FileEndOfFileInformation
,
2998 sizeof(LARGE_INTEGER
),
3000 if (!NT_SUCCESS(Status
))
3002 ObDereferenceObject(Section
);
3003 ObDereferenceObject(FileObject
);
3004 return(STATUS_SECTION_NOT_EXTENDED
);
3008 if (FileObject
->SectionObjectPointer
== NULL
||
3009 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3011 ObDereferenceObject(Section
);
3012 ObDereferenceObject(FileObject
);
3013 return STATUS_INVALID_FILE_FOR_SECTION
;
3019 Status
= MmspWaitForFileLock(FileObject
);
3020 if (Status
!= STATUS_SUCCESS
)
3022 ObDereferenceObject(Section
);
3023 ObDereferenceObject(FileObject
);
3028 * If this file hasn't been mapped as a data file before then allocate a
3029 * section segment to describe the data file mapping
3031 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3033 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3034 TAG_MM_SECTION_SEGMENT
);
3035 if (Segment
== NULL
)
3037 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3038 ObDereferenceObject(Section
);
3039 ObDereferenceObject(FileObject
);
3040 return(STATUS_NO_MEMORY
);
3042 Section
->Segment
= Segment
;
3043 Segment
->ReferenceCount
= 1;
3044 ExInitializeFastMutex(&Segment
->Lock
);
3046 * Set the lock before assigning the segment to the file object
3048 ExAcquireFastMutex(&Segment
->Lock
);
3049 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3051 Segment
->Image
.FileOffset
= 0;
3052 Segment
->Protection
= SectionPageProtection
;
3053 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3054 Segment
->Image
.Characteristics
= 0;
3055 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3056 if (AllocationAttributes
& SEC_RESERVE
)
3058 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3062 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3063 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3065 Segment
->Image
.VirtualAddress
= 0;
3066 Segment
->Locked
= TRUE
;
3067 MiInitializeSectionPageTable(Segment
);
3072 * If the file is already mapped as a data file then we may need
3076 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3078 Section
->Segment
= Segment
;
3079 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3080 MmLockSectionSegment(Segment
);
3082 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3083 !(AllocationAttributes
& SEC_RESERVE
))
3085 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3086 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3089 MmUnlockSectionSegment(Segment
);
3090 Section
->FileObject
= FileObject
;
3091 Section
->MaximumSize
= MaximumSize
;
3093 CcRosReferenceCache(FileObject
);
3095 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3096 *SectionObject
= Section
;
3097 return(STATUS_SUCCESS
);
3101 TODO: not that great (declaring loaders statically, having to declare all of
3102 them, having to keep them extern, etc.), will fix in the future
3104 extern NTSTATUS NTAPI PeFmtCreateSection
3106 IN CONST VOID
* FileHeader
,
3107 IN SIZE_T FileHeaderSize
,
3109 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3111 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3112 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3115 extern NTSTATUS NTAPI ElfFmtCreateSection
3117 IN CONST VOID
* FileHeader
,
3118 IN SIZE_T FileHeaderSize
,
3120 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3122 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3123 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3126 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3137 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3139 SIZE_T SizeOfSegments
;
3140 PMM_SECTION_SEGMENT Segments
;
3142 /* TODO: check for integer overflow */
3143 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3145 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3147 TAG_MM_SECTION_SEGMENT
);
3150 RtlZeroMemory(Segments
, SizeOfSegments
);
3158 ExeFmtpReadFile(IN PVOID File
,
3159 IN PLARGE_INTEGER Offset
,
3162 OUT PVOID
* AllocBase
,
3163 OUT PULONG ReadSize
)
3166 LARGE_INTEGER FileOffset
;
3168 ULONG OffsetAdjustment
;
3172 PFILE_OBJECT FileObject
= File
;
3173 IO_STATUS_BLOCK Iosb
;
3175 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3179 KeBugCheck(MEMORY_MANAGEMENT
);
3182 FileOffset
= *Offset
;
3184 /* Negative/special offset: it cannot be used in this context */
3185 if(FileOffset
.u
.HighPart
< 0)
3187 KeBugCheck(MEMORY_MANAGEMENT
);
3190 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3191 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3192 FileOffset
.u
.LowPart
= AdjustOffset
;
3194 BufferSize
= Length
+ OffsetAdjustment
;
3195 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3197 /* Flush data since we're about to perform a non-cached read */
3198 CcFlushCache(FileObject
->SectionObjectPointer
,
3204 * It's ok to use paged pool, because this is a temporary buffer only used in
3205 * the loading of executables. The assumption is that MmCreateSection is
3206 * always called at low IRQLs and that these buffers don't survive a brief
3207 * initialization phase
3209 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3214 return STATUS_INSUFFICIENT_RESOURCES
;
3219 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3221 UsedSize
= (ULONG
)Iosb
.Information
;
3223 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3225 Status
= STATUS_IN_PAGE_ERROR
;
3226 ASSERT(!NT_SUCCESS(Status
));
3229 if(NT_SUCCESS(Status
))
3231 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3232 *AllocBase
= Buffer
;
3233 *ReadSize
= UsedSize
- OffsetAdjustment
;
3237 ExFreePoolWithTag(Buffer
, 'rXmM');
3244 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3245 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3246 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3251 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3255 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3257 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3258 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3265 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3269 MmspAssertSegmentsSorted(ImageSectionObject
);
3271 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3273 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3277 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3278 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3279 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3287 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3291 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3293 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3294 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3302 MmspCompareSegments(const void * x
,
3305 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3306 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3309 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3310 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3314 * Ensures an image section's segments are sorted in memory
3319 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3322 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3324 MmspAssertSegmentsSorted(ImageSectionObject
);
3328 qsort(ImageSectionObject
->Segments
,
3329 ImageSectionObject
->NrSegments
,
3330 sizeof(ImageSectionObject
->Segments
[0]),
3331 MmspCompareSegments
);
3337 * Ensures an image section's segments don't overlap in memory and don't have
3338 * gaps and don't have a null size. We let them map to overlapping file regions,
3339 * though - that's not necessarily an error
3344 MmspCheckSegmentBounds
3346 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3352 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3354 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3358 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3360 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3362 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3370 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3371 * page could be OK (Windows seems to be OK with them), and larger gaps
3372 * could lead to image sections spanning several discontiguous regions
3373 * (NtMapViewOfSection could then refuse to map them, and they could
3374 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3376 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3377 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3378 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3389 * Merges and pads an image section's segments until they all are page-aligned
3390 * and have a size that is a multiple of the page size
3395 MmspPageAlignSegments
3397 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3403 PMM_SECTION_SEGMENT EffectiveSegment
;
3405 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3407 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3412 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3414 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3417 * The first segment requires special handling
3421 ULONG_PTR VirtualAddress
;
3422 ULONG_PTR VirtualOffset
;
3424 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3426 /* Round down the virtual address to the nearest page */
3427 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3429 /* Round up the virtual size to the nearest page */
3430 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3431 EffectiveSegment
->Image
.VirtualAddress
;
3433 /* Adjust the raw address and size */
3434 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3436 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3442 * Garbage in, garbage out: unaligned base addresses make the file
3443 * offset point in curious and odd places, but that's what we were
3446 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3447 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3451 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3452 ULONG_PTR EndOfEffectiveSegment
;
3454 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3455 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3458 * The current segment begins exactly where the current effective
3459 * segment ended, therefore beginning a new effective segment
3461 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3464 ASSERT(LastSegment
<= i
);
3465 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3467 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3469 if (LastSegment
!= i
)
3472 * Copy the current segment. If necessary, the effective segment
3473 * will be expanded later
3475 *EffectiveSegment
= *Segment
;
3479 * Page-align the virtual size. We know for sure the virtual address
3482 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3483 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3486 * The current segment is still part of the current effective segment:
3487 * extend the effective segment to reflect this
3489 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3491 static const ULONG FlagsToProtection
[16] =
3499 PAGE_EXECUTE_READWRITE
,
3500 PAGE_EXECUTE_READWRITE
,
3505 PAGE_EXECUTE_WRITECOPY
,
3506 PAGE_EXECUTE_WRITECOPY
,
3507 PAGE_EXECUTE_WRITECOPY
,
3508 PAGE_EXECUTE_WRITECOPY
3511 unsigned ProtectionFlags
;
3514 * Extend the file size
3517 /* Unaligned segments must be contiguous within the file */
3518 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3519 EffectiveSegment
->RawLength
.QuadPart
))
3524 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3527 * Extend the virtual size
3529 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3531 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3532 EffectiveSegment
->Image
.VirtualAddress
;
3535 * Merge the protection
3537 EffectiveSegment
->Protection
|= Segment
->Protection
;
3539 /* Clean up redundance */
3540 ProtectionFlags
= 0;
3542 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3543 ProtectionFlags
|= 1 << 0;
3545 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3546 ProtectionFlags
|= 1 << 1;
3548 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3549 ProtectionFlags
|= 1 << 2;
3551 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3552 ProtectionFlags
|= 1 << 3;
3554 ASSERT(ProtectionFlags
< 16);
3555 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3557 /* If a segment was required to be shared and cannot, fail */
3558 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3559 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3565 * We assume no holes between segments at this point
3569 KeBugCheck(MEMORY_MANAGEMENT
);
3573 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3579 ExeFmtpCreateImageSection(PFILE_OBJECT FileObject
,
3580 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3582 LARGE_INTEGER Offset
;
3584 PVOID FileHeaderBuffer
;
3585 ULONG FileHeaderSize
;
3587 ULONG OldNrSegments
;
3592 * Read the beginning of the file (2 pages). Should be enough to contain
3593 * all (or most) of the headers
3595 Offset
.QuadPart
= 0;
3597 Status
= ExeFmtpReadFile (FileObject
,
3604 if (!NT_SUCCESS(Status
))
3607 if (FileHeaderSize
== 0)
3609 ExFreePool(FileHeaderBuffer
);
3610 return STATUS_UNSUCCESSFUL
;
3614 * Look for a loader that can handle this executable
3616 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3618 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3621 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3627 ExeFmtpAllocateSegments
);
3629 if (!NT_SUCCESS(Status
))
3631 if (ImageSectionObject
->Segments
)
3633 ExFreePool(ImageSectionObject
->Segments
);
3634 ImageSectionObject
->Segments
= NULL
;
3638 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3642 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3645 * No loader handled the format
3647 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3649 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3650 ASSERT(!NT_SUCCESS(Status
));
3653 if (!NT_SUCCESS(Status
))
3656 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3661 /* FIXME? are these values platform-dependent? */
3662 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3663 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3665 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3666 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3668 if(ImageSectionObject
->BasedAddress
== NULL
)
3670 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3671 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3673 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3677 * And now the fun part: fixing the segments
3680 /* Sort them by virtual address */
3681 MmspSortSegments(ImageSectionObject
, Flags
);
3683 /* Ensure they don't overlap in memory */
3684 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3685 return STATUS_INVALID_IMAGE_FORMAT
;
3687 /* Ensure they are aligned */
3688 OldNrSegments
= ImageSectionObject
->NrSegments
;
3690 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3691 return STATUS_INVALID_IMAGE_FORMAT
;
3693 /* Trim them if the alignment phase merged some of them */
3694 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3696 PMM_SECTION_SEGMENT Segments
;
3697 SIZE_T SizeOfSegments
;
3699 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3701 Segments
= ExAllocatePoolWithTag(PagedPool
,
3703 TAG_MM_SECTION_SEGMENT
);
3705 if (Segments
== NULL
)
3706 return STATUS_INSUFFICIENT_RESOURCES
;
3708 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3709 ExFreePool(ImageSectionObject
->Segments
);
3710 ImageSectionObject
->Segments
= Segments
;
3713 /* And finish their initialization */
3714 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3716 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3717 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3718 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3721 ASSERT(NT_SUCCESS(Status
));
3726 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3727 ACCESS_MASK DesiredAccess
,
3728 POBJECT_ATTRIBUTES ObjectAttributes
,
3729 PLARGE_INTEGER UMaximumSize
,
3730 ULONG SectionPageProtection
,
3731 ULONG AllocationAttributes
,
3732 PFILE_OBJECT FileObject
)
3734 PROS_SECTION_OBJECT Section
;
3736 PMM_SECTION_SEGMENT SectionSegments
;
3737 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3740 if (FileObject
== NULL
)
3741 return STATUS_INVALID_FILE_FOR_SECTION
;
3744 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3746 DPRINT1("Denying section creation due to missing cache initialization\n");
3747 return STATUS_INVALID_FILE_FOR_SECTION
;
3752 * Create the section
3754 Status
= ObCreateObject (ExGetPreviousMode(),
3755 MmSectionObjectType
,
3757 ExGetPreviousMode(),
3759 sizeof(ROS_SECTION_OBJECT
),
3762 (PVOID
*)(PVOID
)&Section
);
3763 if (!NT_SUCCESS(Status
))
3765 ObDereferenceObject(FileObject
);
3772 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3773 Section
->Type
= 'SC';
3774 Section
->Size
= 'TN';
3775 Section
->SectionPageProtection
= SectionPageProtection
;
3776 Section
->AllocationAttributes
= AllocationAttributes
;
3780 * Initialized caching for this file object if previously caching
3781 * was initialized for the same on disk file
3783 Status
= CcTryToInitializeFileCache(FileObject
);
3785 Status
= STATUS_SUCCESS
;
3788 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3790 NTSTATUS StatusExeFmt
;
3792 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3793 if (ImageSectionObject
== NULL
)
3795 ObDereferenceObject(FileObject
);
3796 ObDereferenceObject(Section
);
3797 return(STATUS_NO_MEMORY
);
3800 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3802 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3804 if (!NT_SUCCESS(StatusExeFmt
))
3806 if(ImageSectionObject
->Segments
!= NULL
)
3807 ExFreePool(ImageSectionObject
->Segments
);
3810 * If image file is empty, then return that the file is invalid for section
3812 Status
= StatusExeFmt
;
3813 if (StatusExeFmt
== STATUS_END_OF_FILE
)
3815 Status
= STATUS_INVALID_FILE_FOR_SECTION
;
3818 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3819 ObDereferenceObject(Section
);
3820 ObDereferenceObject(FileObject
);
3824 Section
->ImageSection
= ImageSectionObject
;
3825 ASSERT(ImageSectionObject
->Segments
);
3830 Status
= MmspWaitForFileLock(FileObject
);
3831 if (!NT_SUCCESS(Status
))
3833 ExFreePool(ImageSectionObject
->Segments
);
3834 ExFreePool(ImageSectionObject
);
3835 ObDereferenceObject(Section
);
3836 ObDereferenceObject(FileObject
);
3840 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3841 ImageSectionObject
, NULL
))
3844 * An other thread has initialized the same image in the background
3846 ExFreePool(ImageSectionObject
->Segments
);
3847 ExFreePool(ImageSectionObject
);
3848 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3849 Section
->ImageSection
= ImageSectionObject
;
3850 SectionSegments
= ImageSectionObject
->Segments
;
3852 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3854 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3858 Status
= StatusExeFmt
;
3865 Status
= MmspWaitForFileLock(FileObject
);
3866 if (Status
!= STATUS_SUCCESS
)
3868 ObDereferenceObject(Section
);
3869 ObDereferenceObject(FileObject
);
3873 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3874 Section
->ImageSection
= ImageSectionObject
;
3875 SectionSegments
= ImageSectionObject
->Segments
;
3878 * Otherwise just reference all the section segments
3880 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3882 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3885 Status
= STATUS_SUCCESS
;
3887 Section
->FileObject
= FileObject
;
3889 CcRosReferenceCache(FileObject
);
3891 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3892 *SectionObject
= Section
;
3899 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3900 PROS_SECTION_OBJECT Section
,
3901 PMM_SECTION_SEGMENT Segment
,
3906 ULONG AllocationType
)
3912 if (Segment
->WriteCopy
)
3914 /* We have to do this because the not present fault
3915 * and access fault handlers depend on the protection
3916 * that should be granted AFTER the COW fault takes
3917 * place to be in Region->Protect. The not present fault
3918 * handler changes this to the correct protection for COW when
3919 * mapping the pages into the process's address space. If a COW
3920 * fault takes place, the access fault handler sets the page protection
3921 * to these values for the newly copied pages
3923 if (Protect
== PAGE_WRITECOPY
)
3924 Protect
= PAGE_READWRITE
;
3925 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3926 Protect
= PAGE_EXECUTE_READWRITE
;
3929 if (*BaseAddress
== NULL
)
3930 Granularity
= MM_ALLOCATION_GRANULARITY
;
3932 Granularity
= PAGE_SIZE
;
3935 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3937 LARGE_INTEGER FileOffset
;
3938 FileOffset
.QuadPart
= ViewOffset
;
3939 ObReferenceObject(Section
);
3940 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3943 Status
= MmCreateMemoryArea(AddressSpace
,
3944 MEMORY_AREA_SECTION_VIEW
,
3951 if (!NT_SUCCESS(Status
))
3953 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3954 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3958 ObReferenceObject((PVOID
)Section
);
3960 MArea
->Data
.SectionData
.Segment
= Segment
;
3961 MArea
->Data
.SectionData
.Section
= Section
;
3962 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3963 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3965 MArea
->VadNode
.u
.VadFlags
.VadType
= VadImageMap
;
3968 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3969 ViewSize
, 0, Protect
);
3971 return(STATUS_SUCCESS
);
3976 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3977 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3981 PFILE_OBJECT FileObject
;
3982 PROS_SHARED_CACHE_MAP SharedCacheMap
;
3984 LARGE_INTEGER Offset
;
3985 SWAPENTRY SavedSwapEntry
;
3986 PROS_SECTION_OBJECT Section
;
3987 PMM_SECTION_SEGMENT Segment
;
3988 PMMSUPPORT AddressSpace
;
3991 AddressSpace
= (PMMSUPPORT
)Context
;
3992 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3994 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3996 Offset
.QuadPart
= ((ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)) +
3997 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3999 Section
= MemoryArea
->Data
.SectionData
.Section
;
4000 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4002 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4003 while (Entry
&& MM_IS_WAIT_PTE(Entry
))
4005 MmUnlockSectionSegment(Segment
);
4006 MmUnlockAddressSpace(AddressSpace
);
4008 MiWaitForPageEvent(NULL
, NULL
);
4010 MmLockAddressSpace(AddressSpace
);
4011 MmLockSectionSegment(Segment
);
4012 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4016 * For a dirty, datafile, non-private page mark it as dirty in the
4019 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4021 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4024 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4025 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4026 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4028 ASSERT(SwapEntry
== 0);
4037 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4039 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4040 KeBugCheck(MEMORY_MANAGEMENT
);
4042 MmFreeSwapPage(SwapEntry
);
4046 if (IS_SWAP_FROM_SSE(Entry
) ||
4047 Page
!= PFN_FROM_SSE(Entry
))
4052 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4054 DPRINT1("Found a private page in a pagefile section.\n");
4055 KeBugCheck(MEMORY_MANAGEMENT
);
4058 * Just dereference private pages
4060 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4061 if (SavedSwapEntry
!= 0)
4063 MmFreeSwapPage(SavedSwapEntry
);
4064 MmSetSavedSwapEntryPage(Page
, 0);
4066 MmDeleteRmap(Page
, Process
, Address
);
4067 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4071 MmDeleteRmap(Page
, Process
, Address
);
4072 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4078 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4082 PMEMORY_AREA MemoryArea
;
4083 PROS_SECTION_OBJECT Section
;
4084 PMM_SECTION_SEGMENT Segment
;
4085 PLIST_ENTRY CurrentEntry
;
4086 PMM_REGION CurrentRegion
;
4087 PLIST_ENTRY RegionListHead
;
4089 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4091 if (MemoryArea
== NULL
)
4093 return(STATUS_UNSUCCESSFUL
);
4096 Section
= MemoryArea
->Data
.SectionData
.Section
;
4097 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4100 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4102 MmUnlockAddressSpace(AddressSpace
);
4103 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4104 MmLockAddressSpace(AddressSpace
);
4110 MemoryArea
->DeleteInProgress
= TRUE
;
4112 MmLockSectionSegment(Segment
);
4114 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4115 while (!IsListEmpty(RegionListHead
))
4117 CurrentEntry
= RemoveHeadList(RegionListHead
);
4118 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4119 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4122 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4124 Status
= MmFreeMemoryArea(AddressSpace
,
4131 Status
= MmFreeMemoryArea(AddressSpace
,
4136 MmUnlockSectionSegment(Segment
);
4137 ObDereferenceObject(Section
);
4143 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4144 IN PVOID BaseAddress
,
4148 PMEMORY_AREA MemoryArea
;
4149 PMMSUPPORT AddressSpace
;
4150 PROS_SECTION_OBJECT Section
;
4151 PVOID ImageBaseAddress
= 0;
4153 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4154 Process
, BaseAddress
);
4158 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4160 MmLockAddressSpace(AddressSpace
);
4161 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4163 if (MemoryArea
== NULL
||
4164 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4165 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4166 MemoryArea
->DeleteInProgress
)
4168 if (MemoryArea
) ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4169 MmUnlockAddressSpace(AddressSpace
);
4170 return STATUS_NOT_MAPPED_VIEW
;
4173 Section
= MemoryArea
->Data
.SectionData
.Section
;
4175 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4179 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4180 PMM_SECTION_SEGMENT SectionSegments
;
4181 PMM_SECTION_SEGMENT Segment
;
4183 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4184 ImageSectionObject
= Section
->ImageSection
;
4185 SectionSegments
= ImageSectionObject
->Segments
;
4186 NrSegments
= ImageSectionObject
->NrSegments
;
4188 MemoryArea
->DeleteInProgress
= TRUE
;
4190 /* Search for the current segment within the section segments
4191 * and calculate the image base address */
4192 for (i
= 0; i
< NrSegments
; i
++)
4194 if (Segment
== &SectionSegments
[i
])
4196 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4200 if (i
>= NrSegments
)
4202 KeBugCheck(MEMORY_MANAGEMENT
);
4205 for (i
= 0; i
< NrSegments
; i
++)
4207 PVOID SBaseAddress
= (PVOID
)
4208 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4210 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4211 if (!NT_SUCCESS(Status
))
4213 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4214 SBaseAddress
, Process
, Status
);
4215 ASSERT(NT_SUCCESS(Status
));
4221 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4222 if (!NT_SUCCESS(Status
))
4224 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4225 BaseAddress
, Process
, Status
);
4226 ASSERT(NT_SUCCESS(Status
));
4230 MmUnlockAddressSpace(AddressSpace
);
4232 /* Notify debugger */
4233 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4235 return(STATUS_SUCCESS
);
4242 * Queries the information of a section object.
4244 * @param SectionHandle
4245 * Handle to the section object. It must be opened with SECTION_QUERY
4247 * @param SectionInformationClass
4248 * Index to a certain information structure. Can be either
4249 * SectionBasicInformation or SectionImageInformation. The latter
4250 * is valid only for sections that were created with the SEC_IMAGE
4252 * @param SectionInformation
4253 * Caller supplies storage for resulting information.
4255 * Size of the supplied storage.
4256 * @param ResultLength
4266 _In_ HANDLE SectionHandle
,
4267 _In_ SECTION_INFORMATION_CLASS SectionInformationClass
,
4268 _Out_ PVOID SectionInformation
,
4269 _In_ SIZE_T SectionInformationLength
,
4270 _Out_opt_ PSIZE_T ResultLength
)
4273 KPROCESSOR_MODE PreviousMode
;
4277 PreviousMode
= ExGetPreviousMode();
4278 if (PreviousMode
!= KernelMode
)
4282 ProbeForWrite(SectionInformation
,
4283 SectionInformationLength
,
4285 if (ResultLength
!= NULL
)
4287 ProbeForWrite(ResultLength
,
4288 sizeof(*ResultLength
),
4292 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4294 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4299 if (SectionInformationClass
== SectionBasicInformation
)
4301 if (SectionInformationLength
< sizeof(SECTION_BASIC_INFORMATION
))
4303 return STATUS_INFO_LENGTH_MISMATCH
;
4306 else if (SectionInformationClass
== SectionImageInformation
)
4308 if (SectionInformationLength
< sizeof(SECTION_IMAGE_INFORMATION
))
4310 return STATUS_INFO_LENGTH_MISMATCH
;
4315 return STATUS_INVALID_INFO_CLASS
;
4318 Status
= ObReferenceObjectByHandle(SectionHandle
,
4320 MmSectionObjectType
,
4322 (PVOID
*)(PVOID
)&Section
,
4324 if (!NT_SUCCESS(Status
))
4326 DPRINT1("Failed to reference section: 0x%lx\n", Status
);
4330 if (MiIsRosSectionObject(Section
))
4332 PROS_SECTION_OBJECT RosSection
= (PROS_SECTION_OBJECT
)Section
;
4334 switch (SectionInformationClass
)
4336 case SectionBasicInformation
:
4338 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4342 Sbi
->Attributes
= RosSection
->AllocationAttributes
;
4343 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4345 Sbi
->BaseAddress
= 0;
4346 Sbi
->Size
.QuadPart
= 0;
4350 Sbi
->BaseAddress
= (PVOID
)RosSection
->Segment
->Image
.VirtualAddress
;
4351 Sbi
->Size
.QuadPart
= RosSection
->Segment
->Length
.QuadPart
;
4354 if (ResultLength
!= NULL
)
4356 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4358 Status
= STATUS_SUCCESS
;
4360 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4362 Status
= _SEH2_GetExceptionCode();
4369 case SectionImageInformation
:
4371 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4375 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4377 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4378 ImageSectionObject
= RosSection
->ImageSection
;
4380 *Sii
= ImageSectionObject
->ImageInformation
;
4383 if (ResultLength
!= NULL
)
4385 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4387 Status
= STATUS_SUCCESS
;
4389 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4391 Status
= _SEH2_GetExceptionCode();
4401 switch(SectionInformationClass
)
4403 case SectionBasicInformation
:
4405 SECTION_BASIC_INFORMATION Sbi
;
4407 Sbi
.Size
= Section
->SizeOfSection
;
4408 Sbi
.BaseAddress
= (PVOID
)Section
->Address
.StartingVpn
;
4411 if (Section
->u
.Flags
.Image
)
4412 Sbi
.Attributes
|= SEC_IMAGE
;
4413 if (Section
->u
.Flags
.Commit
)
4414 Sbi
.Attributes
|= SEC_COMMIT
;
4415 if (Section
->u
.Flags
.Reserve
)
4416 Sbi
.Attributes
|= SEC_RESERVE
;
4417 if (Section
->u
.Flags
.File
)
4418 Sbi
.Attributes
|= SEC_FILE
;
4419 if (Section
->u
.Flags
.Image
)
4420 Sbi
.Attributes
|= SEC_IMAGE
;
4422 /* FIXME : Complete/test the list of flags passed back from NtCreateSection */
4426 *((SECTION_BASIC_INFORMATION
*)SectionInformation
) = Sbi
;
4428 *ResultLength
= sizeof(Sbi
);
4430 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4432 Status
= _SEH2_GetExceptionCode();
4437 case SectionImageInformation
:
4439 if (!Section
->u
.Flags
.Image
)
4441 Status
= STATUS_SECTION_NOT_IMAGE
;
4445 /* Currently not supported */
4453 ObDereferenceObject(Section
);
4458 /**********************************************************************
4460 * MmMapViewOfSection
4463 * Maps a view of a section into the virtual address space of a
4468 * Pointer to the section object.
4471 * Pointer to the process.
4474 * Desired base address (or NULL) on entry;
4475 * Actual base address of the view on exit.
4478 * Number of high order address bits that must be zero.
4481 * Size in bytes of the initially committed section of
4485 * Offset in bytes from the beginning of the section
4486 * to the beginning of the view.
4489 * Desired length of map (or zero to map all) on entry
4490 * Actual length mapped on exit.
4492 * InheritDisposition
4493 * Specified how the view is to be shared with
4497 * Type of allocation for the pages.
4500 * Protection for the committed region of the view.
4508 MmMapViewOfSection(IN PVOID SectionObject
,
4509 IN PEPROCESS Process
,
4510 IN OUT PVOID
*BaseAddress
,
4511 IN ULONG_PTR ZeroBits
,
4512 IN SIZE_T CommitSize
,
4513 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4514 IN OUT PSIZE_T ViewSize
,
4515 IN SECTION_INHERIT InheritDisposition
,
4516 IN ULONG AllocationType
,
4519 PROS_SECTION_OBJECT Section
;
4520 PMMSUPPORT AddressSpace
;
4522 NTSTATUS Status
= STATUS_SUCCESS
;
4523 BOOLEAN NotAtBase
= FALSE
;
4525 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4527 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4528 return MmMapViewOfArm3Section(SectionObject
,
4542 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4544 return STATUS_INVALID_PAGE_PROTECTION
;
4547 /* FIXME: We should keep this, but it would break code checking equality */
4548 Protect
&= ~PAGE_NOCACHE
;
4550 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4551 AddressSpace
= &Process
->Vm
;
4553 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4555 MmLockAddressSpace(AddressSpace
);
4557 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4561 ULONG_PTR ImageBase
;
4563 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4564 PMM_SECTION_SEGMENT SectionSegments
;
4566 ImageSectionObject
= Section
->ImageSection
;
4567 SectionSegments
= ImageSectionObject
->Segments
;
4568 NrSegments
= ImageSectionObject
->NrSegments
;
4570 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4573 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4577 for (i
= 0; i
< NrSegments
; i
++)
4579 ULONG_PTR MaxExtent
;
4580 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4581 SectionSegments
[i
].Length
.QuadPart
);
4582 ImageSize
= max(ImageSize
, MaxExtent
);
4585 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4587 /* Check for an illegal base address */
4588 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4589 ((ImageBase
+ ImageSize
) < ImageSize
))
4591 ASSERT(*BaseAddress
== NULL
);
4592 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4593 MM_VIRTMEM_GRANULARITY
);
4596 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4598 ASSERT(*BaseAddress
== NULL
);
4599 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4603 /* Check there is enough space to map the section at that point. */
4604 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4605 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4607 /* Fail if the user requested a fixed base address. */
4608 if ((*BaseAddress
) != NULL
)
4610 MmUnlockAddressSpace(AddressSpace
);
4611 return(STATUS_CONFLICTING_ADDRESSES
);
4613 /* Otherwise find a gap to map the image. */
4614 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4617 MmUnlockAddressSpace(AddressSpace
);
4618 return(STATUS_CONFLICTING_ADDRESSES
);
4620 /* Remember that we loaded image at a different base address */
4624 for (i
= 0; i
< NrSegments
; i
++)
4626 PVOID SBaseAddress
= (PVOID
)
4627 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4628 MmLockSectionSegment(&SectionSegments
[i
]);
4629 Status
= MmMapViewOfSegment(AddressSpace
,
4631 &SectionSegments
[i
],
4633 SectionSegments
[i
].Length
.LowPart
,
4634 SectionSegments
[i
].Protection
,
4637 MmUnlockSectionSegment(&SectionSegments
[i
]);
4638 if (!NT_SUCCESS(Status
))
4640 MmUnlockAddressSpace(AddressSpace
);
4645 *BaseAddress
= (PVOID
)ImageBase
;
4646 *ViewSize
= ImageSize
;
4650 /* check for write access */
4651 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4652 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4654 MmUnlockAddressSpace(AddressSpace
);
4655 return STATUS_SECTION_PROTECTION
;
4657 /* check for read access */
4658 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4659 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4661 MmUnlockAddressSpace(AddressSpace
);
4662 return STATUS_SECTION_PROTECTION
;
4664 /* check for execute access */
4665 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4666 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4668 MmUnlockAddressSpace(AddressSpace
);
4669 return STATUS_SECTION_PROTECTION
;
4672 if (SectionOffset
== NULL
)
4678 ViewOffset
= SectionOffset
->u
.LowPart
;
4681 if ((ViewOffset
% PAGE_SIZE
) != 0)
4683 MmUnlockAddressSpace(AddressSpace
);
4684 return(STATUS_MAPPED_ALIGNMENT
);
4687 if ((*ViewSize
) == 0)
4689 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4691 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4693 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4696 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4698 MmLockSectionSegment(Section
->Segment
);
4699 Status
= MmMapViewOfSegment(AddressSpace
,
4706 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4707 MmUnlockSectionSegment(Section
->Segment
);
4708 if (!NT_SUCCESS(Status
))
4710 MmUnlockAddressSpace(AddressSpace
);
4715 MmUnlockAddressSpace(AddressSpace
);
4716 ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4719 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4721 Status
= STATUS_SUCCESS
;
4730 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4731 IN PLARGE_INTEGER NewFileSize
)
4733 /* Check whether an ImageSectionObject exists */
4734 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4736 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4740 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4742 PMM_SECTION_SEGMENT Segment
;
4744 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4747 if (Segment
->ReferenceCount
!= 0)
4750 CC_FILE_SIZES FileSizes
;
4752 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4755 /* Check size of file */
4756 if (SectionObjectPointer
->SharedCacheMap
)
4758 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4763 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4772 /* Check size of file */
4773 if (SectionObjectPointer
->SharedCacheMap
)
4775 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4776 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4785 /* Something must gone wrong
4786 * how can we have a Section but no
4788 DPRINT("ERROR: DataSectionObject without reference!\n");
4792 DPRINT("FIXME: didn't check for outstanding write probes\n");
4804 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4805 IN MMFLUSH_TYPE FlushType
)
4807 BOOLEAN Result
= TRUE
;
4809 PMM_SECTION_SEGMENT Segment
;
4814 case MmFlushForDelete
:
4815 if (SectionObjectPointer
->ImageSectionObject
||
4816 SectionObjectPointer
->DataSectionObject
)
4821 CcRosRemoveIfClosed(SectionObjectPointer
);
4824 case MmFlushForWrite
:
4826 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4828 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4831 if (SectionObjectPointer
->ImageSectionObject
)
4833 DPRINT1("SectionObject has ImageSection\n");
4839 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4841 DPRINT("Result %d\n", Result
);
4853 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4854 OUT PVOID
* MappedBase
,
4855 IN OUT PSIZE_T ViewSize
)
4857 PROS_SECTION_OBJECT Section
;
4858 PMMSUPPORT AddressSpace
;
4862 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4864 return MiMapViewInSystemSpace(SectionObject
,
4870 DPRINT("MmMapViewInSystemSpace() called\n");
4872 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4873 AddressSpace
= MmGetKernelAddressSpace();
4875 MmLockAddressSpace(AddressSpace
);
4878 if ((*ViewSize
) == 0)
4880 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4882 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4884 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4887 MmLockSectionSegment(Section
->Segment
);
4890 Status
= MmMapViewOfSegment(AddressSpace
,
4899 MmUnlockSectionSegment(Section
->Segment
);
4900 MmUnlockAddressSpace(AddressSpace
);
4907 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4909 PMMSUPPORT AddressSpace
;
4912 DPRINT("MmUnmapViewInSystemSpace() called\n");
4914 AddressSpace
= MmGetKernelAddressSpace();
4916 MmLockAddressSpace(AddressSpace
);
4918 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4920 MmUnlockAddressSpace(AddressSpace
);
4925 /**********************************************************************
4930 * Creates a section object.
4933 * SectionObject (OUT)
4934 * Caller supplied storage for the resulting pointer
4935 * to a SECTION_OBJECT instance;
4938 * Specifies the desired access to the section can be a
4940 * STANDARD_RIGHTS_REQUIRED |
4942 * SECTION_MAP_WRITE |
4943 * SECTION_MAP_READ |
4944 * SECTION_MAP_EXECUTE
4946 * ObjectAttributes [OPTIONAL]
4947 * Initialized attributes for the object can be used
4948 * to create a named section;
4951 * Maximizes the size of the memory section. Must be
4952 * non-NULL for a page-file backed section.
4953 * If value specified for a mapped file and the file is
4954 * not large enough, file will be extended.
4956 * SectionPageProtection
4957 * Can be a combination of:
4963 * AllocationAttributes
4964 * Can be a combination of:
4969 * Handle to a file to create a section mapped to a file
4970 * instead of a memory backed section;
4981 MmCreateSection (OUT PVOID
* Section
,
4982 IN ACCESS_MASK DesiredAccess
,
4983 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4984 IN PLARGE_INTEGER MaximumSize
,
4985 IN ULONG SectionPageProtection
,
4986 IN ULONG AllocationAttributes
,
4987 IN HANDLE FileHandle OPTIONAL
,
4988 IN PFILE_OBJECT FileObject OPTIONAL
)
4992 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4994 /* Check if an ARM3 section is being created instead */
4995 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4997 if (!(FileObject
) && !(FileHandle
))
4999 return MmCreateArm3Section(Section
,
5003 SectionPageProtection
,
5004 AllocationAttributes
&~ 1,
5010 /* Convert section flag to page flag */
5011 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
5013 /* Check to make sure the protection is correct. Nt* does this already */
5014 Protection
= MiMakeProtectionMask(SectionPageProtection
);
5015 if (Protection
== MM_INVALID_PROTECTION
)
5017 DPRINT1("Page protection is invalid\n");
5018 return STATUS_INVALID_PAGE_PROTECTION
;
5021 /* Check if this is going to be a data or image backed file section */
5022 if ((FileHandle
) || (FileObject
))
5024 /* These cannot be mapped with large pages */
5025 if (AllocationAttributes
& SEC_LARGE_PAGES
)
5027 DPRINT1("Large pages cannot be used with an image mapping\n");
5028 return STATUS_INVALID_PARAMETER_6
;
5031 /* Did the caller pass an object? */
5034 /* Reference the object directly */
5035 ObReferenceObject(FileObject
);
5039 /* Reference the file handle to get the object */
5040 Status
= ObReferenceObjectByHandle(FileHandle
,
5041 MmMakeFileAccess
[Protection
],
5043 ExGetPreviousMode(),
5044 (PVOID
*)&FileObject
,
5046 if (!NT_SUCCESS(Status
))
5048 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
5055 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
5056 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
5059 #ifndef NEWCC // A hack for initializing caching.
5060 // This is needed only in the old case.
5063 IO_STATUS_BLOCK Iosb
;
5066 LARGE_INTEGER ByteOffset
;
5067 ByteOffset
.QuadPart
= 0;
5068 Status
= ZwReadFile(FileHandle
,
5077 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5079 DPRINT1("CC failure: %lx\n", Status
);
5081 ObDereferenceObject(FileObject
);
5084 // Caching is initialized...
5086 // Hack of the hack: actually, it might not be initialized if FSD init on effective right and if file is null-size
5087 // In such case, force cache by initiating a write IRP
5088 if (Status
== STATUS_END_OF_FILE
&& !(AllocationAttributes
& SEC_IMAGE
) && FileObject
!= NULL
&&
5089 (FileObject
->SectionObjectPointer
== NULL
|| FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
))
5092 Status
= ZwWriteFile(FileHandle
,
5101 if (NT_SUCCESS(Status
))
5104 Zero
.QuadPart
= 0LL;
5106 Status
= IoSetInformation(FileObject
,
5107 FileEndOfFileInformation
,
5108 sizeof(LARGE_INTEGER
),
5110 ASSERT(NT_SUCCESS(Status
));
5116 if (AllocationAttributes
& SEC_IMAGE
)
5118 Status
= MmCreateImageSection(SectionObject
,
5122 SectionPageProtection
,
5123 AllocationAttributes
,
5127 else if (FileHandle
!= NULL
)
5129 Status
= MmCreateDataFileSection(SectionObject
,
5133 SectionPageProtection
,
5134 AllocationAttributes
,
5137 ObDereferenceObject(FileObject
);
5140 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5142 Status
= MmCreateCacheSection(SectionObject
,
5146 SectionPageProtection
,
5147 AllocationAttributes
,
5153 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5155 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5157 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5158 Status
= MmCreatePageFileSection(SectionObject
,
5162 SectionPageProtection
,
5163 AllocationAttributes
);