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
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1359 MmUnlockSectionSegment(Segment
);
1360 MmUnlockAddressSpace(AddressSpace
);
1361 MiWaitForPageEvent(NULL
, NULL
);
1362 MmLockAddressSpace(AddressSpace
);
1363 DPRINT("Address 0x%p\n", Address
);
1364 return(STATUS_MM_RESTART_OPERATION
);
1367 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1369 /* See if we should use a private page */
1370 if ((HasSwapEntry
) || (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
))
1372 SWAPENTRY DummyEntry
;
1375 * Is it a wait entry?
1379 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1381 if (SwapEntry
== MM_WAIT_ENTRY
)
1383 MmUnlockSectionSegment(Segment
);
1384 MmUnlockAddressSpace(AddressSpace
);
1385 MiWaitForPageEvent(NULL
, NULL
);
1386 MmLockAddressSpace(AddressSpace
);
1387 return STATUS_MM_RESTART_OPERATION
;
1391 * Must be private page we have swapped out.
1397 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1399 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1400 KeBugCheck(MEMORY_MANAGEMENT
);
1402 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1405 MmUnlockSectionSegment(Segment
);
1407 /* Tell everyone else we are serving the fault. */
1408 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1410 MmUnlockAddressSpace(AddressSpace
);
1411 MI_SET_USAGE(MI_USAGE_SECTION
);
1412 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1413 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1414 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1415 if (!NT_SUCCESS(Status
))
1417 KeBugCheck(MEMORY_MANAGEMENT
);
1422 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1423 if (!NT_SUCCESS(Status
))
1425 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1426 KeBugCheck(MEMORY_MANAGEMENT
);
1430 MmLockAddressSpace(AddressSpace
);
1431 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1432 Status
= MmCreateVirtualMapping(Process
,
1437 if (!NT_SUCCESS(Status
))
1439 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1440 KeBugCheck(MEMORY_MANAGEMENT
);
1445 * Store the swap entry for later use.
1448 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1451 * Add the page to the process's working set
1453 MmInsertRmap(Page
, Process
, Address
);
1455 * Finish the operation
1457 MiSetPageEvent(Process
, Address
);
1458 DPRINT("Address 0x%p\n", Address
);
1459 return(STATUS_SUCCESS
);
1463 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1465 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1467 MmUnlockSectionSegment(Segment
);
1469 * Just map the desired physical page
1471 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1472 Status
= MmCreateVirtualMappingUnsafe(Process
,
1477 if (!NT_SUCCESS(Status
))
1479 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1480 KeBugCheck(MEMORY_MANAGEMENT
);
1485 * Cleanup and release locks
1487 MiSetPageEvent(Process
, Address
);
1488 DPRINT("Address 0x%p\n", Address
);
1489 return(STATUS_SUCCESS
);
1493 * Get the entry corresponding to the offset within the section
1495 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1499 SWAPENTRY FakeSwapEntry
;
1502 * If the entry is zero (and it can't change because we have
1503 * locked the segment) then we need to load the page.
1507 * Release all our locks and read in the page from disk
1509 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1510 MmUnlockSectionSegment(Segment
);
1511 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1512 MmUnlockAddressSpace(AddressSpace
);
1514 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1515 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1516 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1518 MI_SET_USAGE(MI_USAGE_SECTION
);
1519 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1520 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1521 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1522 if (!NT_SUCCESS(Status
))
1524 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1530 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1531 if (!NT_SUCCESS(Status
))
1533 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1536 if (!NT_SUCCESS(Status
))
1539 * FIXME: What do we know in this case?
1542 * Cleanup and release locks
1544 MmLockAddressSpace(AddressSpace
);
1545 MiSetPageEvent(Process
, Address
);
1546 DPRINT("Address 0x%p\n", Address
);
1550 /* Lock both segment and process address space while we proceed. */
1551 MmLockAddressSpace(AddressSpace
);
1552 MmLockSectionSegment(Segment
);
1554 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1555 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1556 Page
, Process
, PAddress
, Attributes
);
1557 Status
= MmCreateVirtualMapping(Process
,
1562 if (!NT_SUCCESS(Status
))
1564 DPRINT1("Unable to create virtual mapping\n");
1565 KeBugCheck(MEMORY_MANAGEMENT
);
1567 ASSERT(MmIsPagePresent(Process
, PAddress
));
1568 MmInsertRmap(Page
, Process
, Address
);
1570 /* Set this section offset has being backed by our new page. */
1571 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1572 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1573 MmUnlockSectionSegment(Segment
);
1575 MiSetPageEvent(Process
, Address
);
1576 DPRINT("Address 0x%p\n", Address
);
1577 return(STATUS_SUCCESS
);
1579 else if (IS_SWAP_FROM_SSE(Entry
))
1581 SWAPENTRY SwapEntry
;
1583 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1585 /* See if a page op is running on this segment. */
1586 if (SwapEntry
== MM_WAIT_ENTRY
)
1588 MmUnlockSectionSegment(Segment
);
1589 MmUnlockAddressSpace(AddressSpace
);
1590 MiWaitForPageEvent(NULL
, NULL
);
1591 MmLockAddressSpace(AddressSpace
);
1592 return STATUS_MM_RESTART_OPERATION
;
1596 * Release all our locks and read in the page from disk
1598 MmUnlockSectionSegment(Segment
);
1600 MmUnlockAddressSpace(AddressSpace
);
1601 MI_SET_USAGE(MI_USAGE_SECTION
);
1602 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1603 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1604 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1605 if (!NT_SUCCESS(Status
))
1607 KeBugCheck(MEMORY_MANAGEMENT
);
1610 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1611 if (!NT_SUCCESS(Status
))
1613 KeBugCheck(MEMORY_MANAGEMENT
);
1617 * Relock the address space and segment
1619 MmLockAddressSpace(AddressSpace
);
1620 MmLockSectionSegment(Segment
);
1623 * Check the entry. No one should change the status of a page
1624 * that has a pending page-in.
1626 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1627 if (Entry
!= Entry1
)
1629 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1630 KeBugCheck(MEMORY_MANAGEMENT
);
1634 * Save the swap entry.
1636 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1638 /* Map the page into the process address space */
1639 Status
= MmCreateVirtualMapping(Process
,
1644 if (!NT_SUCCESS(Status
))
1646 DPRINT1("Unable to create virtual mapping\n");
1647 KeBugCheck(MEMORY_MANAGEMENT
);
1649 MmInsertRmap(Page
, Process
, Address
);
1652 * Mark the offset within the section as having valid, in-memory
1655 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1656 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1657 MmUnlockSectionSegment(Segment
);
1659 MiSetPageEvent(Process
, Address
);
1660 DPRINT("Address 0x%p\n", Address
);
1661 return(STATUS_SUCCESS
);
1665 /* We already have a page on this section offset. Map it into the process address space. */
1666 Page
= PFN_FROM_SSE(Entry
);
1668 Status
= MmCreateVirtualMapping(Process
,
1673 if (!NT_SUCCESS(Status
))
1675 DPRINT1("Unable to create virtual mapping\n");
1676 KeBugCheck(MEMORY_MANAGEMENT
);
1678 MmInsertRmap(Page
, Process
, Address
);
1680 /* Take a reference on it */
1681 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1682 MmUnlockSectionSegment(Segment
);
1684 MiSetPageEvent(Process
, Address
);
1685 DPRINT("Address 0x%p\n", Address
);
1686 return(STATUS_SUCCESS
);
1692 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1693 MEMORY_AREA
* MemoryArea
,
1696 PMM_SECTION_SEGMENT Segment
;
1697 PROS_SECTION_OBJECT Section
;
1702 LARGE_INTEGER Offset
;
1705 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1707 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1709 /* Make sure we have a page mapping for this address. */
1710 Status
= MmNotPresentFaultSectionView(AddressSpace
, MemoryArea
, Address
, TRUE
);
1711 if (!NT_SUCCESS(Status
))
1713 /* This is invalid access ! */
1718 * Check if the page has already been set readwrite
1720 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1722 DPRINT("Address 0x%p\n", Address
);
1723 return(STATUS_SUCCESS
);
1727 * Find the offset of the page
1729 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1730 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1731 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1733 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1734 Section
= MemoryArea
->Data
.SectionData
.Section
;
1735 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1736 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1738 ASSERT(Region
!= NULL
);
1741 * Check if we are doing COW
1743 if (!((Segment
->WriteCopy
) &&
1744 (Region
->Protect
== PAGE_READWRITE
||
1745 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1747 DPRINT("Address 0x%p\n", Address
);
1748 return(STATUS_ACCESS_VIOLATION
);
1751 /* Get the page mapping this section offset. */
1752 MmLockSectionSegment(Segment
);
1753 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1755 /* Get the current page mapping for the process */
1756 ASSERT(MmIsPagePresent(Process
, PAddress
));
1757 OldPage
= MmGetPfnForProcess(Process
, PAddress
);
1758 ASSERT(OldPage
!= 0);
1760 if (IS_SWAP_FROM_SSE(Entry
) ||
1761 PFN_FROM_SSE(Entry
) != OldPage
)
1763 MmUnlockSectionSegment(Segment
);
1764 /* This is a private page. We must only change the page protection. */
1765 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1766 return(STATUS_SUCCESS
);
1772 MI_SET_USAGE(MI_USAGE_SECTION
);
1773 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1774 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1775 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1776 if (!NT_SUCCESS(Status
))
1778 KeBugCheck(MEMORY_MANAGEMENT
);
1784 MiCopyFromUserPage(NewPage
, OldPage
);
1787 * Unshare the old page.
1789 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1790 MmDeleteVirtualMapping(Process
, PAddress
, NULL
, NULL
);
1791 MmDeleteRmap(OldPage
, Process
, PAddress
);
1792 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1793 MmUnlockSectionSegment(Segment
);
1796 * Set the PTE to point to the new page
1798 Status
= MmCreateVirtualMapping(Process
,
1803 if (!NT_SUCCESS(Status
))
1805 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1806 KeBugCheck(MEMORY_MANAGEMENT
);
1809 MmInsertRmap(NewPage
, Process
, PAddress
);
1811 MiSetPageEvent(Process
, Address
);
1812 DPRINT("Address 0x%p\n", Address
);
1813 return(STATUS_SUCCESS
);
1817 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1819 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1821 PFN_NUMBER Page
= 0;
1823 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1826 MmLockAddressSpace(&Process
->Vm
);
1829 MmDeleteVirtualMapping(Process
,
1835 PageOutContext
->WasDirty
= TRUE
;
1837 if (!PageOutContext
->Private
)
1839 MmLockSectionSegment(PageOutContext
->Segment
);
1840 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1841 PageOutContext
->Segment
,
1842 &PageOutContext
->Offset
,
1843 PageOutContext
->WasDirty
,
1845 &PageOutContext
->SectionEntry
);
1846 MmUnlockSectionSegment(PageOutContext
->Segment
);
1850 MmUnlockAddressSpace(&Process
->Vm
);
1853 if (PageOutContext
->Private
)
1855 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1861 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1862 MEMORY_AREA
* MemoryArea
,
1863 PVOID Address
, ULONG_PTR Entry
)
1866 MM_SECTION_PAGEOUT_CONTEXT Context
;
1867 SWAPENTRY SwapEntry
;
1870 ULONGLONG FileOffset
;
1871 PFILE_OBJECT FileObject
;
1872 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1873 BOOLEAN IsImageSection
;
1875 BOOLEAN DirectMapped
;
1876 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1879 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1882 * Get the segment and section.
1884 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1885 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1886 Context
.SectionEntry
= Entry
;
1887 Context
.CallingProcess
= Process
;
1889 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
1890 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1892 DirectMapped
= FALSE
;
1894 MmLockSectionSegment(Context
.Segment
);
1897 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1898 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1899 FileObject
= Context
.Section
->FileObject
;
1901 if (FileObject
!= NULL
&&
1902 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1904 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1907 * If the file system is letting us go directly to the cache and the
1908 * memory area was mapped at an offset in the file which is page aligned
1909 * then note this is a direct mapped page.
1911 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1912 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1914 DirectMapped
= TRUE
;
1921 * This should never happen since mappings of physical memory are never
1922 * placed in the rmap lists.
1924 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1926 DPRINT1("Trying to page out from physical memory section address 0x%p "
1927 "process %p\n", Address
,
1928 Process
? Process
->UniqueProcessId
: 0);
1929 KeBugCheck(MEMORY_MANAGEMENT
);
1933 * Get the section segment entry and the physical address.
1935 if (!MmIsPagePresent(Process
, Address
))
1937 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1938 Process
? Process
->UniqueProcessId
: 0, Address
);
1939 KeBugCheck(MEMORY_MANAGEMENT
);
1941 Page
= MmGetPfnForProcess(Process
, Address
);
1942 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1945 * Check the reference count to ensure this page can be paged out
1947 if (MmGetReferenceCountPage(Page
) != 1)
1949 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1950 Page
, MmGetReferenceCountPage(Page
));
1951 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1952 MmUnlockSectionSegment(Context
.Segment
);
1953 return STATUS_UNSUCCESSFUL
;
1957 * Prepare the context structure for the rmap delete call.
1959 MmUnlockSectionSegment(Context
.Segment
);
1960 Context
.WasDirty
= FALSE
;
1961 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1962 IS_SWAP_FROM_SSE(Entry
) ||
1963 PFN_FROM_SSE(Entry
) != Page
)
1965 Context
.Private
= TRUE
;
1969 Context
.Private
= FALSE
;
1973 * Take an additional reference to the page or the VACB.
1975 if (DirectMapped
&& !Context
.Private
)
1977 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
1979 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1980 KeBugCheck(MEMORY_MANAGEMENT
);
1985 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1986 MmReferencePage(Page
);
1987 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1990 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1992 /* Since we passed in a surrogate, we'll get back the page entry
1993 * state in our context. This is intended to make intermediate
1994 * decrements of share count not release the wait entry.
1996 Entry
= Context
.SectionEntry
;
1999 * If this wasn't a private page then we should have reduced the entry to
2000 * zero by deleting all the rmaps.
2002 if (!Context
.Private
&& Entry
!= 0)
2004 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2005 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2007 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2012 * If the page wasn't dirty then we can just free it as for a readonly page.
2013 * Since we unmapped all the mappings above we know it will not suddenly
2015 * If the page is from a pagefile section and has no swap entry,
2016 * we can't free the page at this point.
2018 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2019 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2021 if (Context
.Private
)
2023 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2024 Context
.WasDirty
? "dirty" : "clean", Address
);
2025 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2027 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2029 MmSetSavedSwapEntryPage(Page
, 0);
2030 MmLockSectionSegment(Context
.Segment
);
2031 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2032 MmUnlockSectionSegment(Context
.Segment
);
2033 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2034 MiSetPageEvent(NULL
, NULL
);
2035 return(STATUS_SUCCESS
);
2038 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2040 if (Context
.Private
)
2042 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2043 Context
.WasDirty
? "dirty" : "clean", Address
);
2044 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2046 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2048 MmSetSavedSwapEntryPage(Page
, 0);
2051 MmLockSectionSegment(Context
.Segment
);
2052 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2053 MmUnlockSectionSegment(Context
.Segment
);
2055 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2056 MiSetPageEvent(NULL
, NULL
);
2057 return(STATUS_SUCCESS
);
2060 else if (!Context
.Private
&& DirectMapped
)
2064 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2066 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2069 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
, FALSE
);
2071 Status
= STATUS_SUCCESS
;
2074 if (!NT_SUCCESS(Status
))
2076 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2077 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2080 MiSetPageEvent(NULL
, NULL
);
2081 return(STATUS_SUCCESS
);
2083 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2087 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2089 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2091 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2092 MiSetPageEvent(NULL
, NULL
);
2093 return(STATUS_SUCCESS
);
2095 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2097 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2098 MmSetSavedSwapEntryPage(Page
, 0);
2099 MmLockAddressSpace(AddressSpace
);
2100 Status
= MmCreatePageFileMapping(Process
,
2103 MmUnlockAddressSpace(AddressSpace
);
2104 if (!NT_SUCCESS(Status
))
2106 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2107 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2109 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2110 MiSetPageEvent(NULL
, NULL
);
2111 return(STATUS_SUCCESS
);
2115 * If necessary, allocate an entry in the paging file for this page
2119 SwapEntry
= MmAllocSwapPage();
2122 MmShowOutOfSpaceMessagePagingFile();
2123 MmLockAddressSpace(AddressSpace
);
2125 * For private pages restore the old mappings.
2127 if (Context
.Private
)
2129 Status
= MmCreateVirtualMapping(Process
,
2131 MemoryArea
->Protect
,
2134 MmSetDirtyPage(Process
, Address
);
2143 MmLockSectionSegment(Context
.Segment
);
2146 * For non-private pages if the page wasn't direct mapped then
2147 * set it back into the section segment entry so we don't loose
2148 * our copy. Otherwise it will be handled by the cache manager.
2150 Status
= MmCreateVirtualMapping(Process
,
2152 MemoryArea
->Protect
,
2155 MmSetDirtyPage(Process
, Address
);
2159 // If we got here, the previous entry should have been a wait
2160 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2161 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2162 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2163 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2164 MmUnlockSectionSegment(Context
.Segment
);
2166 MmUnlockAddressSpace(AddressSpace
);
2167 MiSetPageEvent(NULL
, NULL
);
2168 return(STATUS_PAGEFILE_QUOTA
);
2173 * Write the page to the pagefile
2175 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2176 if (!NT_SUCCESS(Status
))
2178 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2181 * As above: undo our actions.
2182 * FIXME: Also free the swap page.
2184 MmLockAddressSpace(AddressSpace
);
2185 if (Context
.Private
)
2187 Status
= MmCreateVirtualMapping(Process
,
2189 MemoryArea
->Protect
,
2192 MmSetDirtyPage(Process
, Address
);
2199 MmLockSectionSegment(Context
.Segment
);
2200 Status
= MmCreateVirtualMapping(Process
,
2202 MemoryArea
->Protect
,
2205 MmSetDirtyPage(Process
, Address
);
2209 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2210 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2211 MmUnlockSectionSegment(Context
.Segment
);
2213 MmUnlockAddressSpace(AddressSpace
);
2214 MiSetPageEvent(NULL
, NULL
);
2215 return(STATUS_UNSUCCESSFUL
);
2219 * Otherwise we have succeeded.
2221 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2222 MmSetSavedSwapEntryPage(Page
, 0);
2223 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2224 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2226 MmLockSectionSegment(Context
.Segment
);
2227 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2228 MmUnlockSectionSegment(Context
.Segment
);
2232 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2235 if (Context
.Private
)
2237 MmLockAddressSpace(AddressSpace
);
2238 MmLockSectionSegment(Context
.Segment
);
2239 Status
= MmCreatePageFileMapping(Process
,
2242 /* We had placed a wait entry upon entry ... replace it before leaving */
2243 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2244 MmUnlockSectionSegment(Context
.Segment
);
2245 MmUnlockAddressSpace(AddressSpace
);
2246 if (!NT_SUCCESS(Status
))
2248 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2249 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2254 MmLockAddressSpace(AddressSpace
);
2255 MmLockSectionSegment(Context
.Segment
);
2256 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2257 /* We had placed a wait entry upon entry ... replace it before leaving */
2258 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2259 MmUnlockSectionSegment(Context
.Segment
);
2260 MmUnlockAddressSpace(AddressSpace
);
2263 MiSetPageEvent(NULL
, NULL
);
2264 return(STATUS_SUCCESS
);
2269 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2270 PMEMORY_AREA MemoryArea
,
2274 LARGE_INTEGER Offset
;
2275 PROS_SECTION_OBJECT Section
;
2276 PMM_SECTION_SEGMENT Segment
;
2278 SWAPENTRY SwapEntry
;
2282 PFILE_OBJECT FileObject
;
2284 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2286 BOOLEAN DirectMapped
;
2287 BOOLEAN IsImageSection
;
2288 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2290 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2292 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2293 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2296 * Get the segment and section.
2298 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2299 Section
= MemoryArea
->Data
.SectionData
.Section
;
2300 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2302 FileObject
= Section
->FileObject
;
2303 DirectMapped
= FALSE
;
2304 if (FileObject
!= NULL
&&
2305 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2308 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2312 * If the file system is letting us go directly to the cache and the
2313 * memory area was mapped at an offset in the file which is page aligned
2314 * then note this is a direct mapped page.
2316 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2317 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2319 DirectMapped
= TRUE
;
2324 * This should never happen since mappings of physical memory are never
2325 * placed in the rmap lists.
2327 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2329 DPRINT1("Trying to write back page from physical memory mapped at %p "
2330 "process %p\n", Address
,
2331 Process
? Process
->UniqueProcessId
: 0);
2332 KeBugCheck(MEMORY_MANAGEMENT
);
2336 * Get the section segment entry and the physical address.
2338 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2339 if (!MmIsPagePresent(Process
, Address
))
2341 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2342 Process
? Process
->UniqueProcessId
: 0, Address
);
2343 KeBugCheck(MEMORY_MANAGEMENT
);
2345 Page
= MmGetPfnForProcess(Process
, Address
);
2346 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2349 * Check for a private (COWed) page.
2351 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2352 IS_SWAP_FROM_SSE(Entry
) ||
2353 PFN_FROM_SSE(Entry
) != Page
)
2363 * Speculatively set all mappings of the page to clean.
2365 MmSetCleanAllRmaps(Page
);
2368 * If this page was direct mapped from the cache then the cache manager
2369 * will take care of writing it back to disk.
2371 if (DirectMapped
&& !Private
)
2373 //LARGE_INTEGER SOffset;
2374 ASSERT(SwapEntry
== 0);
2375 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2377 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
);
2379 MmLockSectionSegment(Segment
);
2380 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2381 MmUnlockSectionSegment(Segment
);
2382 MiSetPageEvent(NULL
, NULL
);
2383 return(STATUS_SUCCESS
);
2387 * If necessary, allocate an entry in the paging file for this page
2391 SwapEntry
= MmAllocSwapPage();
2394 MmSetDirtyAllRmaps(Page
);
2395 MiSetPageEvent(NULL
, NULL
);
2396 return(STATUS_PAGEFILE_QUOTA
);
2398 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2402 * Write the page to the pagefile
2404 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2405 if (!NT_SUCCESS(Status
))
2407 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2409 MmSetDirtyAllRmaps(Page
);
2410 MiSetPageEvent(NULL
, NULL
);
2411 return(STATUS_UNSUCCESSFUL
);
2415 * Otherwise we have succeeded.
2417 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2418 MiSetPageEvent(NULL
, NULL
);
2419 return(STATUS_SUCCESS
);
2423 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2431 PMEMORY_AREA MemoryArea
;
2432 PMM_SECTION_SEGMENT Segment
;
2433 BOOLEAN DoCOW
= FALSE
;
2435 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2437 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2438 ASSERT(MemoryArea
!= NULL
);
2439 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2440 MmLockSectionSegment(Segment
);
2442 if ((Segment
->WriteCopy
) &&
2443 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2448 if (OldProtect
!= NewProtect
)
2450 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2452 SWAPENTRY SwapEntry
;
2453 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2454 ULONG Protect
= NewProtect
;
2456 /* Wait for a wait entry to disappear */
2459 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2460 if (SwapEntry
!= MM_WAIT_ENTRY
)
2462 MiWaitForPageEvent(Process
, Address
);
2467 * If we doing COW for this segment then check if the page is
2470 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2472 LARGE_INTEGER Offset
;
2476 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2477 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2478 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2480 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2481 * IS_SWAP_FROM_SSE and we'll do the right thing.
2483 Page
= MmGetPfnForProcess(Process
, Address
);
2485 Protect
= PAGE_READONLY
;
2486 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2487 IS_SWAP_FROM_SSE(Entry
) ||
2488 PFN_FROM_SSE(Entry
) != Page
)
2490 Protect
= NewProtect
;
2494 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2496 MmSetPageProtect(Process
, Address
,
2502 MmUnlockSectionSegment(Segment
);
2507 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2508 PMEMORY_AREA MemoryArea
,
2516 ULONG_PTR MaxLength
;
2518 MaxLength
= MA_GetEndingAddress(MemoryArea
) - (ULONG_PTR
)BaseAddress
;
2519 if (Length
> MaxLength
)
2520 Length
= (ULONG
)MaxLength
;
2522 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2523 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2525 ASSERT(Region
!= NULL
);
2527 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2528 Region
->Protect
!= Protect
)
2530 return STATUS_INVALID_PAGE_PROTECTION
;
2533 *OldProtect
= Region
->Protect
;
2534 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
2535 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2536 BaseAddress
, Length
, Region
->Type
, Protect
,
2537 MmAlterViewAttributes
);
2543 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2545 PMEMORY_BASIC_INFORMATION Info
,
2546 PSIZE_T ResultLength
)
2549 PVOID RegionBaseAddress
;
2550 PROS_SECTION_OBJECT Section
;
2551 PMM_SECTION_SEGMENT Segment
;
2553 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2554 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2555 Address
, &RegionBaseAddress
);
2558 return STATUS_UNSUCCESSFUL
;
2561 Section
= MemoryArea
->Data
.SectionData
.Section
;
2562 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2564 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2565 Info
->AllocationBase
= (PUCHAR
)MA_GetStartingAddress(MemoryArea
) - Segment
->Image
.VirtualAddress
;
2566 Info
->Type
= MEM_IMAGE
;
2570 Info
->AllocationBase
= (PVOID
)MA_GetStartingAddress(MemoryArea
);
2571 Info
->Type
= MEM_MAPPED
;
2573 Info
->BaseAddress
= RegionBaseAddress
;
2574 Info
->AllocationProtect
= MemoryArea
->Protect
;
2575 Info
->RegionSize
= Region
->Length
;
2576 Info
->State
= MEM_COMMIT
;
2577 Info
->Protect
= Region
->Protect
;
2579 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2580 return(STATUS_SUCCESS
);
2585 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2588 LARGE_INTEGER Offset
;
2590 SWAPENTRY SavedSwapEntry
;
2595 MmLockSectionSegment(Segment
);
2597 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2598 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2600 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2603 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2604 if (IS_SWAP_FROM_SSE(Entry
))
2606 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2610 Page
= PFN_FROM_SSE(Entry
);
2611 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2612 if (SavedSwapEntry
!= 0)
2614 MmSetSavedSwapEntryPage(Page
, 0);
2615 MmFreeSwapPage(SavedSwapEntry
);
2617 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2622 MmUnlockSectionSegment(Segment
);
2626 MmpDeleteSection(PVOID ObjectBody
)
2628 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2630 /* Check if it's an ARM3, or ReactOS section */
2631 if (!MiIsRosSectionObject(Section
))
2633 MiDeleteARM3Section(ObjectBody
);
2637 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2638 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2643 PMM_SECTION_SEGMENT SectionSegments
;
2646 * NOTE: Section->ImageSection can be NULL for short time
2647 * during the section creating. If we fail for some reason
2648 * until the image section is properly initialized we shouldn't
2649 * process further here.
2651 if (Section
->ImageSection
== NULL
)
2654 SectionSegments
= Section
->ImageSection
->Segments
;
2655 NrSegments
= Section
->ImageSection
->NrSegments
;
2657 for (i
= 0; i
< NrSegments
; i
++)
2659 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2661 MmLockSectionSegment(&SectionSegments
[i
]);
2663 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2664 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2666 MmUnlockSectionSegment(&SectionSegments
[i
]);
2669 MmpFreePageFileSegment(&SectionSegments
[i
]);
2675 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2678 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2681 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2683 DPRINT("Freeing section segment\n");
2684 Section
->Segment
= NULL
;
2685 MmFinalizeSegment(Segment
);
2689 DPRINT("RefCount %d\n", RefCount
);
2696 * NOTE: Section->Segment can be NULL for short time
2697 * during the section creating.
2699 if (Section
->Segment
== NULL
)
2702 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2704 MmpFreePageFileSegment(Section
->Segment
);
2705 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2706 ExFreePool(Section
->Segment
);
2707 Section
->Segment
= NULL
;
2711 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2714 if (Section
->FileObject
!= NULL
)
2717 CcRosDereferenceCache(Section
->FileObject
);
2719 ObDereferenceObject(Section
->FileObject
);
2720 Section
->FileObject
= NULL
;
2725 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2727 IN ACCESS_MASK GrantedAccess
,
2728 IN ULONG ProcessHandleCount
,
2729 IN ULONG SystemHandleCount
)
2731 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2737 MmCreatePhysicalMemorySection(VOID
)
2739 PROS_SECTION_OBJECT PhysSection
;
2741 OBJECT_ATTRIBUTES Obj
;
2742 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2743 LARGE_INTEGER SectionSize
;
2747 * Create the section mapping physical memory
2749 SectionSize
.QuadPart
= 0xFFFFFFFF;
2750 InitializeObjectAttributes(&Obj
,
2752 OBJ_PERMANENT
| OBJ_KERNEL_EXCLUSIVE
,
2755 Status
= MmCreateSection((PVOID
)&PhysSection
,
2759 PAGE_EXECUTE_READWRITE
,
2763 if (!NT_SUCCESS(Status
))
2765 DPRINT1("Failed to create PhysicalMemory section\n");
2766 KeBugCheck(MEMORY_MANAGEMENT
);
2768 Status
= ObInsertObject(PhysSection
,
2774 if (!NT_SUCCESS(Status
))
2776 ObDereferenceObject(PhysSection
);
2778 ObCloseHandle(Handle
, KernelMode
);
2779 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2780 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2782 return(STATUS_SUCCESS
);
2788 MmInitSectionImplementation(VOID
)
2790 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2791 UNICODE_STRING Name
;
2793 DPRINT("Creating Section Object Type\n");
2795 /* Initialize the section based root */
2796 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2797 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2799 /* Initialize the Section object type */
2800 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2801 RtlInitUnicodeString(&Name
, L
"Section");
2802 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2803 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2804 ObjectTypeInitializer
.PoolType
= PagedPool
;
2805 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2806 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2807 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2808 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2809 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2810 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2811 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2813 MmCreatePhysicalMemorySection();
2815 return(STATUS_SUCCESS
);
2820 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2821 ACCESS_MASK DesiredAccess
,
2822 POBJECT_ATTRIBUTES ObjectAttributes
,
2823 PLARGE_INTEGER UMaximumSize
,
2824 ULONG SectionPageProtection
,
2825 ULONG AllocationAttributes
)
2827 * Create a section which is backed by the pagefile
2830 LARGE_INTEGER MaximumSize
;
2831 PROS_SECTION_OBJECT Section
;
2832 PMM_SECTION_SEGMENT Segment
;
2835 if (UMaximumSize
== NULL
)
2837 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2838 return(STATUS_INVALID_PARAMETER
);
2840 MaximumSize
= *UMaximumSize
;
2843 * Create the section
2845 Status
= ObCreateObject(ExGetPreviousMode(),
2846 MmSectionObjectType
,
2848 ExGetPreviousMode(),
2850 sizeof(ROS_SECTION_OBJECT
),
2853 (PVOID
*)(PVOID
)&Section
);
2854 if (!NT_SUCCESS(Status
))
2856 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2863 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2864 Section
->Type
= 'SC';
2865 Section
->Size
= 'TN';
2866 Section
->SectionPageProtection
= SectionPageProtection
;
2867 Section
->AllocationAttributes
= AllocationAttributes
;
2868 Section
->MaximumSize
= MaximumSize
;
2869 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2870 TAG_MM_SECTION_SEGMENT
);
2871 if (Segment
== NULL
)
2873 ObDereferenceObject(Section
);
2874 return(STATUS_NO_MEMORY
);
2876 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2877 Section
->Segment
= Segment
;
2878 Segment
->ReferenceCount
= 1;
2879 ExInitializeFastMutex(&Segment
->Lock
);
2880 Segment
->Image
.FileOffset
= 0;
2881 Segment
->Protection
= SectionPageProtection
;
2882 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2883 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2884 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2885 Segment
->WriteCopy
= FALSE
;
2886 Segment
->Image
.VirtualAddress
= 0;
2887 Segment
->Image
.Characteristics
= 0;
2888 *SectionObject
= Section
;
2889 MiInitializeSectionPageTable(Segment
);
2890 return(STATUS_SUCCESS
);
2895 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2896 ACCESS_MASK DesiredAccess
,
2897 POBJECT_ATTRIBUTES ObjectAttributes
,
2898 PLARGE_INTEGER UMaximumSize
,
2899 ULONG SectionPageProtection
,
2900 ULONG AllocationAttributes
,
2903 * Create a section backed by a data file
2906 PROS_SECTION_OBJECT Section
;
2908 LARGE_INTEGER MaximumSize
;
2909 PFILE_OBJECT FileObject
;
2910 PMM_SECTION_SEGMENT Segment
;
2912 IO_STATUS_BLOCK Iosb
;
2913 LARGE_INTEGER Offset
;
2915 FILE_STANDARD_INFORMATION FileInfo
;
2919 * Create the section
2921 Status
= ObCreateObject(ExGetPreviousMode(),
2922 MmSectionObjectType
,
2924 ExGetPreviousMode(),
2926 sizeof(ROS_SECTION_OBJECT
),
2930 if (!NT_SUCCESS(Status
))
2937 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2938 Section
->Type
= 'SC';
2939 Section
->Size
= 'TN';
2940 Section
->SectionPageProtection
= SectionPageProtection
;
2941 Section
->AllocationAttributes
= AllocationAttributes
;
2944 * Reference the file handle
2946 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2947 Status
= ObReferenceObjectByHandle(FileHandle
,
2950 ExGetPreviousMode(),
2951 (PVOID
*)(PVOID
)&FileObject
,
2953 if (!NT_SUCCESS(Status
))
2955 ObDereferenceObject(Section
);
2960 * FIXME: This is propably not entirely correct. We can't look into
2961 * the standard FCB header because it might not be initialized yet
2962 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2963 * standard file information is filled on first request).
2965 Status
= IoQueryFileInformation(FileObject
,
2966 FileStandardInformation
,
2967 sizeof(FILE_STANDARD_INFORMATION
),
2970 Iosb
.Information
= Length
;
2971 if (!NT_SUCCESS(Status
))
2973 ObDereferenceObject(Section
);
2974 ObDereferenceObject(FileObject
);
2979 * FIXME: Revise this once a locking order for file size changes is
2982 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2984 MaximumSize
= *UMaximumSize
;
2988 MaximumSize
= FileInfo
.EndOfFile
;
2989 /* Mapping zero-sized files isn't allowed. */
2990 if (MaximumSize
.QuadPart
== 0)
2992 ObDereferenceObject(Section
);
2993 ObDereferenceObject(FileObject
);
2994 return STATUS_MAPPED_FILE_SIZE_ZERO
;
2998 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3000 Status
= IoSetInformation(FileObject
,
3001 FileAllocationInformation
,
3002 sizeof(LARGE_INTEGER
),
3004 if (!NT_SUCCESS(Status
))
3006 ObDereferenceObject(Section
);
3007 ObDereferenceObject(FileObject
);
3008 return(STATUS_SECTION_NOT_EXTENDED
);
3012 if (FileObject
->SectionObjectPointer
== NULL
||
3013 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3016 * Read a bit so caching is initiated for the file object.
3017 * This is only needed because MiReadPage currently cannot
3018 * handle non-cached streams.
3020 Offset
.QuadPart
= 0;
3021 Status
= ZwReadFile(FileHandle
,
3030 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3032 ObDereferenceObject(Section
);
3033 ObDereferenceObject(FileObject
);
3036 if (FileObject
->SectionObjectPointer
== NULL
||
3037 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3039 /* FIXME: handle this situation */
3040 ObDereferenceObject(Section
);
3041 ObDereferenceObject(FileObject
);
3042 return STATUS_INVALID_PARAMETER
;
3049 Status
= MmspWaitForFileLock(FileObject
);
3050 if (Status
!= STATUS_SUCCESS
)
3052 ObDereferenceObject(Section
);
3053 ObDereferenceObject(FileObject
);
3058 * If this file hasn't been mapped as a data file before then allocate a
3059 * section segment to describe the data file mapping
3061 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3063 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3064 TAG_MM_SECTION_SEGMENT
);
3065 if (Segment
== NULL
)
3067 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3068 ObDereferenceObject(Section
);
3069 ObDereferenceObject(FileObject
);
3070 return(STATUS_NO_MEMORY
);
3072 Section
->Segment
= Segment
;
3073 Segment
->ReferenceCount
= 1;
3074 ExInitializeFastMutex(&Segment
->Lock
);
3076 * Set the lock before assigning the segment to the file object
3078 ExAcquireFastMutex(&Segment
->Lock
);
3079 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3081 Segment
->Image
.FileOffset
= 0;
3082 Segment
->Protection
= SectionPageProtection
;
3083 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3084 Segment
->Image
.Characteristics
= 0;
3085 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3086 if (AllocationAttributes
& SEC_RESERVE
)
3088 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3092 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3093 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3095 Segment
->Image
.VirtualAddress
= 0;
3096 Segment
->Locked
= TRUE
;
3097 MiInitializeSectionPageTable(Segment
);
3102 * If the file is already mapped as a data file then we may need
3106 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3108 Section
->Segment
= Segment
;
3109 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3110 MmLockSectionSegment(Segment
);
3112 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3113 !(AllocationAttributes
& SEC_RESERVE
))
3115 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3116 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3119 MmUnlockSectionSegment(Segment
);
3120 Section
->FileObject
= FileObject
;
3121 Section
->MaximumSize
= MaximumSize
;
3123 CcRosReferenceCache(FileObject
);
3125 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3126 *SectionObject
= Section
;
3127 return(STATUS_SUCCESS
);
3131 TODO: not that great (declaring loaders statically, having to declare all of
3132 them, having to keep them extern, etc.), will fix in the future
3134 extern NTSTATUS NTAPI PeFmtCreateSection
3136 IN CONST VOID
* FileHeader
,
3137 IN SIZE_T FileHeaderSize
,
3139 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3141 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3142 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3145 extern NTSTATUS NTAPI ElfFmtCreateSection
3147 IN CONST VOID
* FileHeader
,
3148 IN SIZE_T FileHeaderSize
,
3150 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3152 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3153 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3156 /* TODO: this is a standard DDK/PSDK macro */
3157 #ifndef RTL_NUMBER_OF
3158 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3161 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3172 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3174 SIZE_T SizeOfSegments
;
3175 PMM_SECTION_SEGMENT Segments
;
3177 /* TODO: check for integer overflow */
3178 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3180 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3182 TAG_MM_SECTION_SEGMENT
);
3185 RtlZeroMemory(Segments
, SizeOfSegments
);
3193 ExeFmtpReadFile(IN PVOID File
,
3194 IN PLARGE_INTEGER Offset
,
3197 OUT PVOID
* AllocBase
,
3198 OUT PULONG ReadSize
)
3201 LARGE_INTEGER FileOffset
;
3203 ULONG OffsetAdjustment
;
3207 PFILE_OBJECT FileObject
= File
;
3208 IO_STATUS_BLOCK Iosb
;
3210 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3214 KeBugCheck(MEMORY_MANAGEMENT
);
3217 FileOffset
= *Offset
;
3219 /* Negative/special offset: it cannot be used in this context */
3220 if(FileOffset
.u
.HighPart
< 0)
3222 KeBugCheck(MEMORY_MANAGEMENT
);
3225 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3226 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3227 FileOffset
.u
.LowPart
= AdjustOffset
;
3229 BufferSize
= Length
+ OffsetAdjustment
;
3230 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3232 /* Flush data since we're about to perform a non-cached read */
3233 CcFlushCache(FileObject
->SectionObjectPointer
,
3239 * It's ok to use paged pool, because this is a temporary buffer only used in
3240 * the loading of executables. The assumption is that MmCreateSection is
3241 * always called at low IRQLs and that these buffers don't survive a brief
3242 * initialization phase
3244 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3249 return STATUS_INSUFFICIENT_RESOURCES
;
3254 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3256 UsedSize
= (ULONG
)Iosb
.Information
;
3258 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3260 Status
= STATUS_IN_PAGE_ERROR
;
3261 ASSERT(!NT_SUCCESS(Status
));
3264 if(NT_SUCCESS(Status
))
3266 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3267 *AllocBase
= Buffer
;
3268 *ReadSize
= UsedSize
- OffsetAdjustment
;
3272 ExFreePoolWithTag(Buffer
, 'rXmM');
3279 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3280 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3281 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3286 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3290 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3292 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3293 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3300 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3304 MmspAssertSegmentsSorted(ImageSectionObject
);
3306 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3308 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3312 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3313 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3314 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3322 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3326 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3328 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3329 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3337 MmspCompareSegments(const void * x
,
3340 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3341 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3344 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3345 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3349 * Ensures an image section's segments are sorted in memory
3354 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3357 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3359 MmspAssertSegmentsSorted(ImageSectionObject
);
3363 qsort(ImageSectionObject
->Segments
,
3364 ImageSectionObject
->NrSegments
,
3365 sizeof(ImageSectionObject
->Segments
[0]),
3366 MmspCompareSegments
);
3372 * Ensures an image section's segments don't overlap in memory and don't have
3373 * gaps and don't have a null size. We let them map to overlapping file regions,
3374 * though - that's not necessarily an error
3379 MmspCheckSegmentBounds
3381 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3387 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3389 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3393 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3395 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3397 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3405 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3406 * page could be OK (Windows seems to be OK with them), and larger gaps
3407 * could lead to image sections spanning several discontiguous regions
3408 * (NtMapViewOfSection could then refuse to map them, and they could
3409 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3411 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3412 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3413 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3424 * Merges and pads an image section's segments until they all are page-aligned
3425 * and have a size that is a multiple of the page size
3430 MmspPageAlignSegments
3432 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3438 PMM_SECTION_SEGMENT EffectiveSegment
;
3440 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3442 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3447 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3449 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3452 * The first segment requires special handling
3456 ULONG_PTR VirtualAddress
;
3457 ULONG_PTR VirtualOffset
;
3459 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3461 /* Round down the virtual address to the nearest page */
3462 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3464 /* Round up the virtual size to the nearest page */
3465 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3466 EffectiveSegment
->Image
.VirtualAddress
;
3468 /* Adjust the raw address and size */
3469 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3471 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3477 * Garbage in, garbage out: unaligned base addresses make the file
3478 * offset point in curious and odd places, but that's what we were
3481 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3482 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3486 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3487 ULONG_PTR EndOfEffectiveSegment
;
3489 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3490 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3493 * The current segment begins exactly where the current effective
3494 * segment ended, therefore beginning a new effective segment
3496 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3499 ASSERT(LastSegment
<= i
);
3500 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3502 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3504 if (LastSegment
!= i
)
3507 * Copy the current segment. If necessary, the effective segment
3508 * will be expanded later
3510 *EffectiveSegment
= *Segment
;
3514 * Page-align the virtual size. We know for sure the virtual address
3517 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3518 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3521 * The current segment is still part of the current effective segment:
3522 * extend the effective segment to reflect this
3524 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3526 static const ULONG FlagsToProtection
[16] =
3534 PAGE_EXECUTE_READWRITE
,
3535 PAGE_EXECUTE_READWRITE
,
3540 PAGE_EXECUTE_WRITECOPY
,
3541 PAGE_EXECUTE_WRITECOPY
,
3542 PAGE_EXECUTE_WRITECOPY
,
3543 PAGE_EXECUTE_WRITECOPY
3546 unsigned ProtectionFlags
;
3549 * Extend the file size
3552 /* Unaligned segments must be contiguous within the file */
3553 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3554 EffectiveSegment
->RawLength
.QuadPart
))
3559 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3562 * Extend the virtual size
3564 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3566 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3567 EffectiveSegment
->Image
.VirtualAddress
;
3570 * Merge the protection
3572 EffectiveSegment
->Protection
|= Segment
->Protection
;
3574 /* Clean up redundance */
3575 ProtectionFlags
= 0;
3577 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3578 ProtectionFlags
|= 1 << 0;
3580 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3581 ProtectionFlags
|= 1 << 1;
3583 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3584 ProtectionFlags
|= 1 << 2;
3586 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3587 ProtectionFlags
|= 1 << 3;
3589 ASSERT(ProtectionFlags
< 16);
3590 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3592 /* If a segment was required to be shared and cannot, fail */
3593 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3594 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3600 * We assume no holes between segments at this point
3604 KeBugCheck(MEMORY_MANAGEMENT
);
3608 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3614 ExeFmtpCreateImageSection(PFILE_OBJECT FileObject
,
3615 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3617 LARGE_INTEGER Offset
;
3619 PVOID FileHeaderBuffer
;
3620 ULONG FileHeaderSize
;
3622 ULONG OldNrSegments
;
3627 * Read the beginning of the file (2 pages). Should be enough to contain
3628 * all (or most) of the headers
3630 Offset
.QuadPart
= 0;
3632 Status
= ExeFmtpReadFile (FileObject
,
3639 if (!NT_SUCCESS(Status
))
3642 if (FileHeaderSize
== 0)
3644 ExFreePool(FileHeaderBuffer
);
3645 return STATUS_UNSUCCESSFUL
;
3649 * Look for a loader that can handle this executable
3651 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3653 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3656 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3662 ExeFmtpAllocateSegments
);
3664 if (!NT_SUCCESS(Status
))
3666 if (ImageSectionObject
->Segments
)
3668 ExFreePool(ImageSectionObject
->Segments
);
3669 ImageSectionObject
->Segments
= NULL
;
3673 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3677 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3680 * No loader handled the format
3682 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3684 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3685 ASSERT(!NT_SUCCESS(Status
));
3688 if (!NT_SUCCESS(Status
))
3691 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3696 /* FIXME? are these values platform-dependent? */
3697 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3698 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3700 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3701 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3703 if(ImageSectionObject
->BasedAddress
== NULL
)
3705 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3706 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3708 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3712 * And now the fun part: fixing the segments
3715 /* Sort them by virtual address */
3716 MmspSortSegments(ImageSectionObject
, Flags
);
3718 /* Ensure they don't overlap in memory */
3719 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3720 return STATUS_INVALID_IMAGE_FORMAT
;
3722 /* Ensure they are aligned */
3723 OldNrSegments
= ImageSectionObject
->NrSegments
;
3725 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3726 return STATUS_INVALID_IMAGE_FORMAT
;
3728 /* Trim them if the alignment phase merged some of them */
3729 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3731 PMM_SECTION_SEGMENT Segments
;
3732 SIZE_T SizeOfSegments
;
3734 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3736 Segments
= ExAllocatePoolWithTag(PagedPool
,
3738 TAG_MM_SECTION_SEGMENT
);
3740 if (Segments
== NULL
)
3741 return STATUS_INSUFFICIENT_RESOURCES
;
3743 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3744 ExFreePool(ImageSectionObject
->Segments
);
3745 ImageSectionObject
->Segments
= Segments
;
3748 /* And finish their initialization */
3749 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3751 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3752 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3753 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3756 ASSERT(NT_SUCCESS(Status
));
3761 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3762 ACCESS_MASK DesiredAccess
,
3763 POBJECT_ATTRIBUTES ObjectAttributes
,
3764 PLARGE_INTEGER UMaximumSize
,
3765 ULONG SectionPageProtection
,
3766 ULONG AllocationAttributes
,
3767 PFILE_OBJECT FileObject
)
3769 PROS_SECTION_OBJECT Section
;
3771 PMM_SECTION_SEGMENT SectionSegments
;
3772 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3775 if (FileObject
== NULL
)
3776 return STATUS_INVALID_FILE_FOR_SECTION
;
3779 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3781 DPRINT1("Denying section creation due to missing cache initialization\n");
3782 return STATUS_INVALID_FILE_FOR_SECTION
;
3787 * Create the section
3789 Status
= ObCreateObject (ExGetPreviousMode(),
3790 MmSectionObjectType
,
3792 ExGetPreviousMode(),
3794 sizeof(ROS_SECTION_OBJECT
),
3797 (PVOID
*)(PVOID
)&Section
);
3798 if (!NT_SUCCESS(Status
))
3800 ObDereferenceObject(FileObject
);
3807 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3808 Section
->Type
= 'SC';
3809 Section
->Size
= 'TN';
3810 Section
->SectionPageProtection
= SectionPageProtection
;
3811 Section
->AllocationAttributes
= AllocationAttributes
;
3815 * Initialized caching for this file object if previously caching
3816 * was initialized for the same on disk file
3818 Status
= CcTryToInitializeFileCache(FileObject
);
3820 Status
= STATUS_SUCCESS
;
3823 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3825 NTSTATUS StatusExeFmt
;
3827 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3828 if (ImageSectionObject
== NULL
)
3830 ObDereferenceObject(FileObject
);
3831 ObDereferenceObject(Section
);
3832 return(STATUS_NO_MEMORY
);
3835 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3837 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3839 if (!NT_SUCCESS(StatusExeFmt
))
3841 if(ImageSectionObject
->Segments
!= NULL
)
3842 ExFreePool(ImageSectionObject
->Segments
);
3844 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3845 ObDereferenceObject(Section
);
3846 ObDereferenceObject(FileObject
);
3847 return(StatusExeFmt
);
3850 Section
->ImageSection
= ImageSectionObject
;
3851 ASSERT(ImageSectionObject
->Segments
);
3856 Status
= MmspWaitForFileLock(FileObject
);
3857 if (!NT_SUCCESS(Status
))
3859 ExFreePool(ImageSectionObject
->Segments
);
3860 ExFreePool(ImageSectionObject
);
3861 ObDereferenceObject(Section
);
3862 ObDereferenceObject(FileObject
);
3866 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3867 ImageSectionObject
, NULL
))
3870 * An other thread has initialized the same image in the background
3872 ExFreePool(ImageSectionObject
->Segments
);
3873 ExFreePool(ImageSectionObject
);
3874 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3875 Section
->ImageSection
= ImageSectionObject
;
3876 SectionSegments
= ImageSectionObject
->Segments
;
3878 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3880 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3884 Status
= StatusExeFmt
;
3891 Status
= MmspWaitForFileLock(FileObject
);
3892 if (Status
!= STATUS_SUCCESS
)
3894 ObDereferenceObject(Section
);
3895 ObDereferenceObject(FileObject
);
3899 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3900 Section
->ImageSection
= ImageSectionObject
;
3901 SectionSegments
= ImageSectionObject
->Segments
;
3904 * Otherwise just reference all the section segments
3906 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3908 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3911 Status
= STATUS_SUCCESS
;
3913 Section
->FileObject
= FileObject
;
3915 CcRosReferenceCache(FileObject
);
3917 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3918 *SectionObject
= Section
;
3925 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3926 PROS_SECTION_OBJECT Section
,
3927 PMM_SECTION_SEGMENT Segment
,
3932 ULONG AllocationType
)
3938 if (Segment
->WriteCopy
)
3940 /* We have to do this because the not present fault
3941 * and access fault handlers depend on the protection
3942 * that should be granted AFTER the COW fault takes
3943 * place to be in Region->Protect. The not present fault
3944 * handler changes this to the correct protection for COW when
3945 * mapping the pages into the process's address space. If a COW
3946 * fault takes place, the access fault handler sets the page protection
3947 * to these values for the newly copied pages
3949 if (Protect
== PAGE_WRITECOPY
)
3950 Protect
= PAGE_READWRITE
;
3951 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3952 Protect
= PAGE_EXECUTE_READWRITE
;
3955 if (*BaseAddress
== NULL
)
3956 Granularity
= MM_ALLOCATION_GRANULARITY
;
3958 Granularity
= PAGE_SIZE
;
3961 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3963 LARGE_INTEGER FileOffset
;
3964 FileOffset
.QuadPart
= ViewOffset
;
3965 ObReferenceObject(Section
);
3966 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3969 Status
= MmCreateMemoryArea(AddressSpace
,
3970 MEMORY_AREA_SECTION_VIEW
,
3977 if (!NT_SUCCESS(Status
))
3979 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3980 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3984 ObReferenceObject((PVOID
)Section
);
3986 MArea
->Data
.SectionData
.Segment
= Segment
;
3987 MArea
->Data
.SectionData
.Section
= Section
;
3988 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3989 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3991 MArea
->VadNode
.u
.VadFlags
.VadType
= VadImageMap
;
3994 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3995 ViewSize
, 0, Protect
);
3997 return(STATUS_SUCCESS
);
4002 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
4003 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4007 PFILE_OBJECT FileObject
;
4008 PROS_SHARED_CACHE_MAP SharedCacheMap
;
4010 LARGE_INTEGER Offset
;
4011 SWAPENTRY SavedSwapEntry
;
4012 PROS_SECTION_OBJECT Section
;
4013 PMM_SECTION_SEGMENT Segment
;
4014 PMMSUPPORT AddressSpace
;
4017 AddressSpace
= (PMMSUPPORT
)Context
;
4018 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4020 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4022 Offset
.QuadPart
= ((ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)) +
4023 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
4025 Section
= MemoryArea
->Data
.SectionData
.Section
;
4026 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4028 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4029 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
4031 MmUnlockSectionSegment(Segment
);
4032 MmUnlockAddressSpace(AddressSpace
);
4034 MiWaitForPageEvent(NULL
, NULL
);
4036 MmLockAddressSpace(AddressSpace
);
4037 MmLockSectionSegment(Segment
);
4038 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4042 * For a dirty, datafile, non-private page mark it as dirty in the
4045 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4047 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4050 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4051 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4052 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4054 ASSERT(SwapEntry
== 0);
4063 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4065 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4066 KeBugCheck(MEMORY_MANAGEMENT
);
4068 MmFreeSwapPage(SwapEntry
);
4072 if (IS_SWAP_FROM_SSE(Entry
) ||
4073 Page
!= PFN_FROM_SSE(Entry
))
4078 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4080 DPRINT1("Found a private page in a pagefile section.\n");
4081 KeBugCheck(MEMORY_MANAGEMENT
);
4084 * Just dereference private pages
4086 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4087 if (SavedSwapEntry
!= 0)
4089 MmFreeSwapPage(SavedSwapEntry
);
4090 MmSetSavedSwapEntryPage(Page
, 0);
4092 MmDeleteRmap(Page
, Process
, Address
);
4093 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4097 MmDeleteRmap(Page
, Process
, Address
);
4098 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4104 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4108 PMEMORY_AREA MemoryArea
;
4109 PROS_SECTION_OBJECT Section
;
4110 PMM_SECTION_SEGMENT Segment
;
4111 PLIST_ENTRY CurrentEntry
;
4112 PMM_REGION CurrentRegion
;
4113 PLIST_ENTRY RegionListHead
;
4115 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4117 if (MemoryArea
== NULL
)
4119 return(STATUS_UNSUCCESSFUL
);
4122 Section
= MemoryArea
->Data
.SectionData
.Section
;
4123 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4126 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4128 MmUnlockAddressSpace(AddressSpace
);
4129 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4130 MmLockAddressSpace(AddressSpace
);
4136 MemoryArea
->DeleteInProgress
= TRUE
;
4138 MmLockSectionSegment(Segment
);
4140 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4141 while (!IsListEmpty(RegionListHead
))
4143 CurrentEntry
= RemoveHeadList(RegionListHead
);
4144 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4145 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4148 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4150 Status
= MmFreeMemoryArea(AddressSpace
,
4157 Status
= MmFreeMemoryArea(AddressSpace
,
4162 MmUnlockSectionSegment(Segment
);
4163 ObDereferenceObject(Section
);
4169 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4170 IN PVOID BaseAddress
,
4174 PMEMORY_AREA MemoryArea
;
4175 PMMSUPPORT AddressSpace
;
4176 PROS_SECTION_OBJECT Section
;
4177 PVOID ImageBaseAddress
= 0;
4179 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4180 Process
, BaseAddress
);
4184 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4186 MmLockAddressSpace(AddressSpace
);
4187 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4189 if (MemoryArea
== NULL
||
4190 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4191 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4192 MemoryArea
->DeleteInProgress
)
4194 if (MemoryArea
) ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4195 MmUnlockAddressSpace(AddressSpace
);
4196 return STATUS_NOT_MAPPED_VIEW
;
4199 Section
= MemoryArea
->Data
.SectionData
.Section
;
4201 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4205 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4206 PMM_SECTION_SEGMENT SectionSegments
;
4207 PMM_SECTION_SEGMENT Segment
;
4209 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4210 ImageSectionObject
= Section
->ImageSection
;
4211 SectionSegments
= ImageSectionObject
->Segments
;
4212 NrSegments
= ImageSectionObject
->NrSegments
;
4214 MemoryArea
->DeleteInProgress
= TRUE
;
4216 /* Search for the current segment within the section segments
4217 * and calculate the image base address */
4218 for (i
= 0; i
< NrSegments
; i
++)
4220 if (Segment
== &SectionSegments
[i
])
4222 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4226 if (i
>= NrSegments
)
4228 KeBugCheck(MEMORY_MANAGEMENT
);
4231 for (i
= 0; i
< NrSegments
; i
++)
4233 PVOID SBaseAddress
= (PVOID
)
4234 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4236 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4237 if (!NT_SUCCESS(Status
))
4239 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4240 SBaseAddress
, Process
, Status
);
4241 ASSERT(NT_SUCCESS(Status
));
4247 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4248 if (!NT_SUCCESS(Status
))
4250 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4251 BaseAddress
, Process
, Status
);
4252 ASSERT(NT_SUCCESS(Status
));
4256 MmUnlockAddressSpace(AddressSpace
);
4258 /* Notify debugger */
4259 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4261 return(STATUS_SUCCESS
);
4268 * Queries the information of a section object.
4270 * @param SectionHandle
4271 * Handle to the section object. It must be opened with SECTION_QUERY
4273 * @param SectionInformationClass
4274 * Index to a certain information structure. Can be either
4275 * SectionBasicInformation or SectionImageInformation. The latter
4276 * is valid only for sections that were created with the SEC_IMAGE
4278 * @param SectionInformation
4279 * Caller supplies storage for resulting information.
4281 * Size of the supplied storage.
4282 * @param ResultLength
4292 _In_ HANDLE SectionHandle
,
4293 _In_ SECTION_INFORMATION_CLASS SectionInformationClass
,
4294 _Out_ PVOID SectionInformation
,
4295 _In_ SIZE_T SectionInformationLength
,
4296 _Out_opt_ PSIZE_T ResultLength
)
4299 KPROCESSOR_MODE PreviousMode
;
4303 PreviousMode
= ExGetPreviousMode();
4304 if (PreviousMode
!= KernelMode
)
4308 ProbeForWrite(SectionInformation
,
4309 SectionInformationLength
,
4311 if (ResultLength
!= NULL
)
4313 ProbeForWrite(ResultLength
,
4314 sizeof(*ResultLength
),
4318 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4320 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4325 if (SectionInformationClass
== SectionBasicInformation
)
4327 if (SectionInformationLength
< sizeof(SECTION_BASIC_INFORMATION
))
4329 return STATUS_INFO_LENGTH_MISMATCH
;
4332 else if (SectionInformationClass
== SectionImageInformation
)
4334 if (SectionInformationLength
< sizeof(SECTION_IMAGE_INFORMATION
))
4336 return STATUS_INFO_LENGTH_MISMATCH
;
4341 return STATUS_INVALID_INFO_CLASS
;
4344 Status
= ObReferenceObjectByHandle(SectionHandle
,
4346 MmSectionObjectType
,
4348 (PVOID
*)(PVOID
)&Section
,
4350 if (!NT_SUCCESS(Status
))
4352 DPRINT1("Failed to reference section: 0x%lx\n", Status
);
4356 if (MiIsRosSectionObject(Section
))
4358 PROS_SECTION_OBJECT RosSection
= (PROS_SECTION_OBJECT
)Section
;
4360 switch (SectionInformationClass
)
4362 case SectionBasicInformation
:
4364 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4368 Sbi
->Attributes
= RosSection
->AllocationAttributes
;
4369 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4371 Sbi
->BaseAddress
= 0;
4372 Sbi
->Size
.QuadPart
= 0;
4376 Sbi
->BaseAddress
= (PVOID
)RosSection
->Segment
->Image
.VirtualAddress
;
4377 Sbi
->Size
.QuadPart
= RosSection
->Segment
->Length
.QuadPart
;
4380 if (ResultLength
!= NULL
)
4382 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4384 Status
= STATUS_SUCCESS
;
4386 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4388 Status
= _SEH2_GetExceptionCode();
4395 case SectionImageInformation
:
4397 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4401 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4403 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4404 ImageSectionObject
= RosSection
->ImageSection
;
4406 *Sii
= ImageSectionObject
->ImageInformation
;
4409 if (ResultLength
!= NULL
)
4411 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4413 Status
= STATUS_SUCCESS
;
4415 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4417 Status
= _SEH2_GetExceptionCode();
4427 switch(SectionInformationClass
)
4429 case SectionBasicInformation
:
4431 SECTION_BASIC_INFORMATION Sbi
;
4433 Sbi
.Size
= Section
->SizeOfSection
;
4434 Sbi
.BaseAddress
= (PVOID
)Section
->Address
.StartingVpn
;
4437 if (Section
->u
.Flags
.Image
)
4438 Sbi
.Attributes
|= SEC_IMAGE
;
4439 if (Section
->u
.Flags
.Commit
)
4440 Sbi
.Attributes
|= SEC_COMMIT
;
4441 if (Section
->u
.Flags
.Reserve
)
4442 Sbi
.Attributes
|= SEC_RESERVE
;
4443 if (Section
->u
.Flags
.File
)
4444 Sbi
.Attributes
|= SEC_FILE
;
4445 if (Section
->u
.Flags
.Image
)
4446 Sbi
.Attributes
|= SEC_IMAGE
;
4448 /* FIXME : Complete/test the list of flags passed back from NtCreateSection */
4452 *((SECTION_BASIC_INFORMATION
*)SectionInformation
) = Sbi
;
4454 *ResultLength
= sizeof(Sbi
);
4456 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4458 Status
= _SEH2_GetExceptionCode();
4463 case SectionImageInformation
:
4465 if (!Section
->u
.Flags
.Image
)
4467 Status
= STATUS_SECTION_NOT_IMAGE
;
4471 /* Currently not supported */
4479 ObDereferenceObject(Section
);
4484 /**********************************************************************
4486 * MmMapViewOfSection
4489 * Maps a view of a section into the virtual address space of a
4494 * Pointer to the section object.
4497 * Pointer to the process.
4500 * Desired base address (or NULL) on entry;
4501 * Actual base address of the view on exit.
4504 * Number of high order address bits that must be zero.
4507 * Size in bytes of the initially committed section of
4511 * Offset in bytes from the beginning of the section
4512 * to the beginning of the view.
4515 * Desired length of map (or zero to map all) on entry
4516 * Actual length mapped on exit.
4518 * InheritDisposition
4519 * Specified how the view is to be shared with
4523 * Type of allocation for the pages.
4526 * Protection for the committed region of the view.
4534 MmMapViewOfSection(IN PVOID SectionObject
,
4535 IN PEPROCESS Process
,
4536 IN OUT PVOID
*BaseAddress
,
4537 IN ULONG_PTR ZeroBits
,
4538 IN SIZE_T CommitSize
,
4539 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4540 IN OUT PSIZE_T ViewSize
,
4541 IN SECTION_INHERIT InheritDisposition
,
4542 IN ULONG AllocationType
,
4545 PROS_SECTION_OBJECT Section
;
4546 PMMSUPPORT AddressSpace
;
4548 NTSTATUS Status
= STATUS_SUCCESS
;
4549 BOOLEAN NotAtBase
= FALSE
;
4551 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4553 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4554 return MmMapViewOfArm3Section(SectionObject
,
4568 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4570 return STATUS_INVALID_PAGE_PROTECTION
;
4573 /* FIXME: We should keep this, but it would break code checking equality */
4574 Protect
&= ~PAGE_NOCACHE
;
4576 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4577 AddressSpace
= &Process
->Vm
;
4579 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4581 MmLockAddressSpace(AddressSpace
);
4583 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4587 ULONG_PTR ImageBase
;
4589 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4590 PMM_SECTION_SEGMENT SectionSegments
;
4592 ImageSectionObject
= Section
->ImageSection
;
4593 SectionSegments
= ImageSectionObject
->Segments
;
4594 NrSegments
= ImageSectionObject
->NrSegments
;
4596 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4599 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4603 for (i
= 0; i
< NrSegments
; i
++)
4605 ULONG_PTR MaxExtent
;
4606 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4607 SectionSegments
[i
].Length
.QuadPart
);
4608 ImageSize
= max(ImageSize
, MaxExtent
);
4611 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4613 /* Check for an illegal base address */
4614 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4615 ((ImageBase
+ ImageSize
) < ImageSize
))
4617 ASSERT(*BaseAddress
== NULL
);
4618 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4619 MM_VIRTMEM_GRANULARITY
);
4622 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4624 ASSERT(*BaseAddress
== NULL
);
4625 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4629 /* Check there is enough space to map the section at that point. */
4630 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4631 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4633 /* Fail if the user requested a fixed base address. */
4634 if ((*BaseAddress
) != NULL
)
4636 MmUnlockAddressSpace(AddressSpace
);
4637 return(STATUS_CONFLICTING_ADDRESSES
);
4639 /* Otherwise find a gap to map the image. */
4640 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4643 MmUnlockAddressSpace(AddressSpace
);
4644 return(STATUS_CONFLICTING_ADDRESSES
);
4646 /* Remember that we loaded image at a different base address */
4650 for (i
= 0; i
< NrSegments
; i
++)
4652 PVOID SBaseAddress
= (PVOID
)
4653 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4654 MmLockSectionSegment(&SectionSegments
[i
]);
4655 Status
= MmMapViewOfSegment(AddressSpace
,
4657 &SectionSegments
[i
],
4659 SectionSegments
[i
].Length
.LowPart
,
4660 SectionSegments
[i
].Protection
,
4663 MmUnlockSectionSegment(&SectionSegments
[i
]);
4664 if (!NT_SUCCESS(Status
))
4666 MmUnlockAddressSpace(AddressSpace
);
4671 *BaseAddress
= (PVOID
)ImageBase
;
4672 *ViewSize
= ImageSize
;
4676 /* check for write access */
4677 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4678 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4680 MmUnlockAddressSpace(AddressSpace
);
4681 return STATUS_SECTION_PROTECTION
;
4683 /* check for read access */
4684 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4685 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4687 MmUnlockAddressSpace(AddressSpace
);
4688 return STATUS_SECTION_PROTECTION
;
4690 /* check for execute access */
4691 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4692 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4694 MmUnlockAddressSpace(AddressSpace
);
4695 return STATUS_SECTION_PROTECTION
;
4698 if (SectionOffset
== NULL
)
4704 ViewOffset
= SectionOffset
->u
.LowPart
;
4707 if ((ViewOffset
% PAGE_SIZE
) != 0)
4709 MmUnlockAddressSpace(AddressSpace
);
4710 return(STATUS_MAPPED_ALIGNMENT
);
4713 if ((*ViewSize
) == 0)
4715 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4717 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4719 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4722 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4724 MmLockSectionSegment(Section
->Segment
);
4725 Status
= MmMapViewOfSegment(AddressSpace
,
4732 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4733 MmUnlockSectionSegment(Section
->Segment
);
4734 if (!NT_SUCCESS(Status
))
4736 MmUnlockAddressSpace(AddressSpace
);
4741 MmUnlockAddressSpace(AddressSpace
);
4742 ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4745 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4747 Status
= STATUS_SUCCESS
;
4756 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4757 IN PLARGE_INTEGER NewFileSize
)
4759 /* Check whether an ImageSectionObject exists */
4760 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4762 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4766 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4768 PMM_SECTION_SEGMENT Segment
;
4770 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4773 if (Segment
->ReferenceCount
!= 0)
4776 CC_FILE_SIZES FileSizes
;
4778 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4781 /* Check size of file */
4782 if (SectionObjectPointer
->SharedCacheMap
)
4784 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4789 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4798 /* Check size of file */
4799 if (SectionObjectPointer
->SharedCacheMap
)
4801 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4802 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4811 /* Something must gone wrong
4812 * how can we have a Section but no
4814 DPRINT("ERROR: DataSectionObject without reference!\n");
4818 DPRINT("FIXME: didn't check for outstanding write probes\n");
4830 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4831 IN MMFLUSH_TYPE FlushType
)
4833 BOOLEAN Result
= TRUE
;
4835 PMM_SECTION_SEGMENT Segment
;
4840 case MmFlushForDelete
:
4841 if (SectionObjectPointer
->ImageSectionObject
||
4842 SectionObjectPointer
->DataSectionObject
)
4847 CcRosRemoveIfClosed(SectionObjectPointer
);
4850 case MmFlushForWrite
:
4852 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4854 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4857 if (SectionObjectPointer
->ImageSectionObject
)
4859 DPRINT1("SectionObject has ImageSection\n");
4865 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4867 DPRINT("Result %d\n", Result
);
4879 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4880 OUT PVOID
* MappedBase
,
4881 IN OUT PSIZE_T ViewSize
)
4883 PROS_SECTION_OBJECT Section
;
4884 PMMSUPPORT AddressSpace
;
4888 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4890 return MiMapViewInSystemSpace(SectionObject
,
4896 DPRINT("MmMapViewInSystemSpace() called\n");
4898 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4899 AddressSpace
= MmGetKernelAddressSpace();
4901 MmLockAddressSpace(AddressSpace
);
4904 if ((*ViewSize
) == 0)
4906 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4908 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4910 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4913 MmLockSectionSegment(Section
->Segment
);
4916 Status
= MmMapViewOfSegment(AddressSpace
,
4925 MmUnlockSectionSegment(Section
->Segment
);
4926 MmUnlockAddressSpace(AddressSpace
);
4933 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4935 PMMSUPPORT AddressSpace
;
4938 DPRINT("MmUnmapViewInSystemSpace() called\n");
4940 AddressSpace
= MmGetKernelAddressSpace();
4942 MmLockAddressSpace(AddressSpace
);
4944 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4946 MmUnlockAddressSpace(AddressSpace
);
4951 /**********************************************************************
4956 * Creates a section object.
4959 * SectionObject (OUT)
4960 * Caller supplied storage for the resulting pointer
4961 * to a SECTION_OBJECT instance;
4964 * Specifies the desired access to the section can be a
4966 * STANDARD_RIGHTS_REQUIRED |
4968 * SECTION_MAP_WRITE |
4969 * SECTION_MAP_READ |
4970 * SECTION_MAP_EXECUTE
4972 * ObjectAttributes [OPTIONAL]
4973 * Initialized attributes for the object can be used
4974 * to create a named section;
4977 * Maximizes the size of the memory section. Must be
4978 * non-NULL for a page-file backed section.
4979 * If value specified for a mapped file and the file is
4980 * not large enough, file will be extended.
4982 * SectionPageProtection
4983 * Can be a combination of:
4989 * AllocationAttributes
4990 * Can be a combination of:
4995 * Handle to a file to create a section mapped to a file
4996 * instead of a memory backed section;
5007 MmCreateSection (OUT PVOID
* Section
,
5008 IN ACCESS_MASK DesiredAccess
,
5009 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
5010 IN PLARGE_INTEGER MaximumSize
,
5011 IN ULONG SectionPageProtection
,
5012 IN ULONG AllocationAttributes
,
5013 IN HANDLE FileHandle OPTIONAL
,
5014 IN PFILE_OBJECT FileObject OPTIONAL
)
5018 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
5020 /* Check if an ARM3 section is being created instead */
5021 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
5023 if (!(FileObject
) && !(FileHandle
))
5025 return MmCreateArm3Section(Section
,
5029 SectionPageProtection
,
5030 AllocationAttributes
&~ 1,
5036 /* Convert section flag to page flag */
5037 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
5039 /* Check to make sure the protection is correct. Nt* does this already */
5040 Protection
= MiMakeProtectionMask(SectionPageProtection
);
5041 if (Protection
== MM_INVALID_PROTECTION
)
5043 DPRINT1("Page protection is invalid\n");
5044 return STATUS_INVALID_PAGE_PROTECTION
;
5047 /* Check if this is going to be a data or image backed file section */
5048 if ((FileHandle
) || (FileObject
))
5050 /* These cannot be mapped with large pages */
5051 if (AllocationAttributes
& SEC_LARGE_PAGES
)
5053 DPRINT1("Large pages cannot be used with an image mapping\n");
5054 return STATUS_INVALID_PARAMETER_6
;
5057 /* Did the caller pass an object? */
5060 /* Reference the object directly */
5061 ObReferenceObject(FileObject
);
5065 /* Reference the file handle to get the object */
5066 Status
= ObReferenceObjectByHandle(FileHandle
,
5067 MmMakeFileAccess
[Protection
],
5069 ExGetPreviousMode(),
5070 (PVOID
*)&FileObject
,
5072 if (!NT_SUCCESS(Status
))
5074 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
5081 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
5082 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
5085 #ifndef NEWCC // A hack for initializing caching.
5086 // This is needed only in the old case.
5089 IO_STATUS_BLOCK Iosb
;
5092 LARGE_INTEGER ByteOffset
;
5093 ByteOffset
.QuadPart
= 0;
5094 Status
= ZwReadFile(FileHandle
,
5103 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5105 DPRINT1("CC failure: %lx\n", Status
);
5108 // Caching is initialized...
5112 if (AllocationAttributes
& SEC_IMAGE
)
5114 Status
= MmCreateImageSection(SectionObject
,
5118 SectionPageProtection
,
5119 AllocationAttributes
,
5123 else if (FileHandle
!= NULL
)
5125 Status
= MmCreateDataFileSection(SectionObject
,
5129 SectionPageProtection
,
5130 AllocationAttributes
,
5133 ObDereferenceObject(FileObject
);
5136 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5138 Status
= MmCreateCacheSection(SectionObject
,
5142 SectionPageProtection
,
5143 AllocationAttributes
,
5149 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5151 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5153 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5154 Status
= MmCreatePageFileSection(SectionObject
,
5158 SectionPageProtection
,
5159 AllocationAttributes
);