2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
48 #include <cache/newcc.h>
49 #include <cache/section/newmm.h>
52 #include <reactos/exeformat.h>
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 #include "ARM3/miarm.h"
61 #undef MmSetPageEntrySectionSegment
62 #define MmSetPageEntrySectionSegment(S,O,E) do { \
63 DPRINT("SetPageEntrySectionSegment(old,%p,%x,%x)\n",(S),(O)->LowPart,E); \
64 _MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__); \
67 extern MMSESSION MmSession
;
71 MiMapViewInSystemSpace(IN PVOID Section
,
73 OUT PVOID
*MappedBase
,
74 IN OUT PSIZE_T ViewSize
);
78 MmCreateArm3Section(OUT PVOID
*SectionObject
,
79 IN ACCESS_MASK DesiredAccess
,
80 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
81 IN PLARGE_INTEGER InputMaximumSize
,
82 IN ULONG SectionPageProtection
,
83 IN ULONG AllocationAttributes
,
84 IN HANDLE FileHandle OPTIONAL
,
85 IN PFILE_OBJECT FileObject OPTIONAL
);
89 MmMapViewOfArm3Section(IN PVOID SectionObject
,
91 IN OUT PVOID
*BaseAddress
,
92 IN ULONG_PTR ZeroBits
,
94 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
95 IN OUT PSIZE_T ViewSize
,
96 IN SECTION_INHERIT InheritDisposition
,
97 IN ULONG AllocationType
,
101 // PeFmtCreateSection depends on the following:
103 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
104 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
106 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
107 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
108 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
110 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
111 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
112 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
113 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
114 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
115 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
116 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
117 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
118 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
120 /* TYPES *********************************************************************/
124 PROS_SECTION_OBJECT Section
;
125 PMM_SECTION_SEGMENT Segment
;
126 LARGE_INTEGER Offset
;
129 PEPROCESS CallingProcess
;
130 ULONG_PTR SectionEntry
;
132 MM_SECTION_PAGEOUT_CONTEXT
;
134 /* GLOBALS *******************************************************************/
136 POBJECT_TYPE MmSectionObjectType
= NULL
;
138 ULONG_PTR MmSubsectionBase
;
140 static ULONG SectionCharacteristicsToProtect
[16] =
142 PAGE_NOACCESS
, /* 0 = NONE */
143 PAGE_NOACCESS
, /* 1 = SHARED */
144 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
145 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
146 PAGE_READONLY
, /* 4 = READABLE */
147 PAGE_READONLY
, /* 5 = READABLE, SHARED */
148 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
149 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
151 * FIXME? do we really need the WriteCopy field in segments? can't we use
152 * PAGE_WRITECOPY here?
154 PAGE_READWRITE
, /* 8 = WRITABLE */
155 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
156 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
157 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
158 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
159 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
160 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
161 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
164 extern ULONG MmMakeFileAccess
[];
165 ACCESS_MASK NTAPI
MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection
);
166 static GENERIC_MAPPING MmpSectionMapping
=
168 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
169 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
170 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
175 /* FUNCTIONS *****************************************************************/
180 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
181 File Format Specification", revision 6.0 (February 1999)
183 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
184 IN SIZE_T FileHeaderSize
,
186 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
188 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
189 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
192 ULONG cbFileHeaderOffsetSize
= 0;
193 ULONG cbSectionHeadersOffset
= 0;
194 ULONG cbSectionHeadersSize
;
195 ULONG cbSectionHeadersOffsetSize
= 0;
196 ULONG cbOptHeaderSize
;
197 ULONG cbHeadersSize
= 0;
198 ULONG nSectionAlignment
;
199 ULONG nFileAlignment
;
201 const IMAGE_DOS_HEADER
* pidhDosHeader
;
202 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
203 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
204 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
205 PMM_SECTION_SEGMENT pssSegments
;
206 LARGE_INTEGER lnOffset
;
208 SIZE_T nPrevVirtualEndOfSegment
= 0;
209 ULONG nFileSizeOfHeaders
= 0;
214 ASSERT(FileHeaderSize
> 0);
216 ASSERT(ImageSectionObject
);
218 ASSERT(AllocateSegmentsCb
);
220 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
222 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
224 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
227 pidhDosHeader
= FileHeader
;
230 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
232 /* image too small to be an MZ executable */
233 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
234 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
236 /* no MZ signature */
237 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
238 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
241 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
243 /* not a Windows executable */
244 if(pidhDosHeader
->e_lfanew
<= 0)
245 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
247 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
248 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
250 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
255 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
256 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
258 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
259 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
263 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
264 * need to read the header from the file
266 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
267 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
269 ULONG cbNtHeaderSize
;
273 l_ReadHeaderFromFile
:
275 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
277 /* read the header from the file */
278 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
280 if(!NT_SUCCESS(nStatus
))
282 NTSTATUS ReturnedStatus
= nStatus
;
284 /* If it attempted to read past the end of the file, it means e_lfanew is invalid */
285 if (ReturnedStatus
== STATUS_END_OF_FILE
) nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
287 DIE(("ReadFile failed, status %08X\n", ReturnedStatus
));
292 ASSERT(cbReadSize
> 0);
294 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
296 /* the buffer doesn't contain the file header */
297 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
298 DIE(("The file doesn't contain the PE file header\n"));
300 pinhNtHeader
= pData
;
302 /* object still not aligned: copy it to the beginning of the buffer */
303 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
305 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
306 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
307 pinhNtHeader
= pBuffer
;
310 /* invalid NT header */
311 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
313 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
314 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
316 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
318 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
319 DIE(("The full NT header is too large\n"));
321 /* the buffer doesn't contain the whole NT header */
322 if(cbReadSize
< cbNtHeaderSize
)
323 DIE(("The file doesn't contain the full NT header\n"));
327 ULONG cbOptHeaderOffsetSize
= 0;
329 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
331 /* don't trust an invalid NT header */
332 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
333 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
335 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
336 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
338 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
340 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
341 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
343 /* the buffer doesn't contain the whole NT header: read it from the file */
344 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
345 goto l_ReadHeaderFromFile
;
348 /* read information from the NT header */
349 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
350 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
352 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
354 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
355 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
357 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
359 switch(piohOptHeader
->Magic
)
361 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
363 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
368 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
371 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
372 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
374 /* See [1], section 3.4.2 */
375 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
377 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
378 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
380 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
381 DIE(("The section alignment is smaller than the file alignment\n"));
383 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
384 nFileAlignment
= piohOptHeader
->FileAlignment
;
386 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
387 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
391 nSectionAlignment
= PAGE_SIZE
;
392 nFileAlignment
= PAGE_SIZE
;
395 ASSERT(IsPowerOf2(nSectionAlignment
));
396 ASSERT(IsPowerOf2(nFileAlignment
));
398 switch(piohOptHeader
->Magic
)
401 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
403 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
404 ImageBase
= piohOptHeader
->ImageBase
;
406 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
407 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
409 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
410 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
412 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
413 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
415 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
417 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
419 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
420 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
422 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
423 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
427 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
429 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
430 piohOptHeader
->AddressOfEntryPoint
);
433 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
434 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
436 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
438 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
440 if (piohOptHeader
->AddressOfEntryPoint
== 0)
442 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
446 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
447 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
449 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
451 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
454 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
455 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
456 * magic to any binary.
458 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
459 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
460 * the SxS support -- at which point, duh, this should be removed.
462 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
464 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
471 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
473 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
475 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
477 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
479 ImageBase
= pioh64OptHeader
->ImageBase
;
480 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
481 DIE(("ImageBase exceeds the address space\n"));
484 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
486 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
487 DIE(("SizeOfImage exceeds the address space\n"));
489 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
492 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
494 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
495 DIE(("SizeOfStackReserve exceeds the address space\n"));
497 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
500 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
502 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
503 DIE(("SizeOfStackCommit exceeds the address space\n"));
505 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
508 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
510 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
512 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
513 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
515 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
516 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
520 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
522 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
523 pioh64OptHeader
->AddressOfEntryPoint
);
526 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
527 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
529 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
531 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
533 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
535 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
539 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
540 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
542 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
543 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
550 /* [1], section 3.4.2 */
551 if((ULONG_PTR
)ImageBase
% 0x10000)
552 DIE(("ImageBase is not aligned on a 64KB boundary"));
554 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
555 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
556 ImageSectionObject
->ImageInformation
.GpValue
= 0;
557 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
558 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
560 /* SECTION HEADERS */
561 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
563 /* see [1], section 3.3 */
564 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
565 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
568 * the additional segment is for the file's headers. They need to be present for
569 * the benefit of the dynamic loader (to locate exports, defaults for thread
570 * parameters, resources, etc.)
572 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
574 /* file offset for the section headers */
575 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
576 DIE(("Offset overflow\n"));
578 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
579 DIE(("Offset overflow\n"));
581 /* size of the section headers */
582 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
583 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
585 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
586 DIE(("Section headers too large\n"));
588 /* size of the executable's headers */
589 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
591 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
592 // DIE(("SizeOfHeaders is not aligned\n"));
594 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
595 DIE(("The section headers overflow SizeOfHeaders\n"));
597 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
599 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
600 DIE(("Overflow aligning the size of headers\n"));
607 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
608 /* WARNING: piohOptHeader IS NO LONGER USABLE */
609 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
611 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
612 pishSectionHeaders
= NULL
;
616 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
617 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
619 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
620 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
624 * the buffer doesn't contain the section headers, or the alignment is wrong:
625 * read the headers from the file
627 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
628 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
633 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
635 /* read the header from the file */
636 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
638 if(!NT_SUCCESS(nStatus
))
639 DIE(("ReadFile failed with status %08X\n", nStatus
));
643 ASSERT(cbReadSize
> 0);
645 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
647 /* the buffer doesn't contain all the section headers */
648 if(cbReadSize
< cbSectionHeadersSize
)
649 DIE(("The file doesn't contain all of the section headers\n"));
651 pishSectionHeaders
= pData
;
653 /* object still not aligned: copy it to the beginning of the buffer */
654 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
656 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
657 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
658 pishSectionHeaders
= pBuffer
;
663 /* allocate the segments */
664 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
665 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
667 if(ImageSectionObject
->Segments
== NULL
)
668 DIE(("AllocateSegments failed\n"));
670 /* initialize the headers segment */
671 pssSegments
= ImageSectionObject
->Segments
;
673 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
675 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
676 DIE(("Cannot align the size of the section headers\n"));
678 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
679 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
680 DIE(("Cannot align the size of the section headers\n"));
682 pssSegments
[0].Image
.FileOffset
= 0;
683 pssSegments
[0].Protection
= PAGE_READONLY
;
684 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
685 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
686 pssSegments
[0].Image
.VirtualAddress
= 0;
687 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
688 pssSegments
[0].WriteCopy
= TRUE
;
690 /* skip the headers segment */
693 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
695 /* convert the executable sections into segments. See also [1], section 4 */
696 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
698 ULONG nCharacteristics
;
700 /* validate the alignment */
701 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
702 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
704 /* sections must be contiguous, ordered by base address and non-overlapping */
705 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
706 DIE(("Memory gap between section %u and the previous\n", i
));
708 /* ignore explicit BSS sections */
709 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
711 /* validate the alignment */
713 /* Yes, this should be a multiple of FileAlignment, but there's
714 * stuff out there that isn't. We can cope with that
716 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
717 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
720 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
721 // DIE(("PointerToRawData[%u] is not aligned\n", i));
724 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
725 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
729 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
730 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
733 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
735 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
737 /* no explicit protection */
738 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
740 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
741 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
743 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
744 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
746 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
747 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
750 /* see table above */
751 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
752 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
754 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
755 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
757 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
759 AlignedLength
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
760 if(AlignedLength
< pssSegments
[i
].Length
.LowPart
)
761 DIE(("Cannot align the virtual size of section %u\n", i
));
763 pssSegments
[i
].Length
.LowPart
= AlignedLength
;
765 if(pssSegments
[i
].Length
.QuadPart
== 0)
766 DIE(("Virtual size of section %u is null\n", i
));
768 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
769 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
771 /* ensure the memory image is no larger than 4GB */
772 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
773 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
774 DIE(("The image is too large\n"));
777 if(nSectionAlignment
>= PAGE_SIZE
)
778 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
781 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
791 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
792 * ARGUMENTS: PFILE_OBJECT to wait for.
793 * RETURNS: Status of the wait.
796 MmspWaitForFileLock(PFILE_OBJECT File
)
798 return STATUS_SUCCESS
;
799 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
804 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
806 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
808 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
809 PMM_SECTION_SEGMENT SectionSegments
;
813 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
814 NrSegments
= ImageSectionObject
->NrSegments
;
815 SectionSegments
= ImageSectionObject
->Segments
;
816 for (i
= 0; i
< NrSegments
; i
++)
818 if (SectionSegments
[i
].ReferenceCount
!= 0)
820 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
821 SectionSegments
[i
].ReferenceCount
);
822 KeBugCheck(MEMORY_MANAGEMENT
);
824 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
826 ExFreePool(ImageSectionObject
->Segments
);
827 ExFreePool(ImageSectionObject
);
828 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
830 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
832 PMM_SECTION_SEGMENT Segment
;
834 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
837 if (Segment
->ReferenceCount
!= 0)
839 DPRINT1("Data segment still referenced\n");
840 KeBugCheck(MEMORY_MANAGEMENT
);
842 MmFreePageTablesSectionSegment(Segment
, NULL
);
844 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
850 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
851 PLARGE_INTEGER Offset
)
855 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
858 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
859 KeBugCheck(MEMORY_MANAGEMENT
);
861 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
863 DPRINT1("Maximum share count reached\n");
864 KeBugCheck(MEMORY_MANAGEMENT
);
866 if (IS_SWAP_FROM_SSE(Entry
))
868 KeBugCheck(MEMORY_MANAGEMENT
);
870 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
871 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
876 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
877 PMM_SECTION_SEGMENT Segment
,
878 PLARGE_INTEGER Offset
,
883 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
884 BOOLEAN IsDirectMapped
= FALSE
;
888 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
889 KeBugCheck(MEMORY_MANAGEMENT
);
891 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
893 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
894 KeBugCheck(MEMORY_MANAGEMENT
);
896 if (IS_SWAP_FROM_SSE(Entry
))
898 KeBugCheck(MEMORY_MANAGEMENT
);
900 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
902 * If we reducing the share count of this entry to zero then set the entry
903 * to zero and tell the cache the page is no longer mapped.
905 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
907 PFILE_OBJECT FileObject
;
908 SWAPENTRY SavedSwapEntry
;
911 PROS_SHARED_CACHE_MAP SharedCacheMap
;
912 BOOLEAN IsImageSection
;
913 LARGE_INTEGER FileOffset
;
915 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
916 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
919 Page
= PFN_FROM_SSE(Entry
);
920 FileObject
= Section
->FileObject
;
921 if (FileObject
!= NULL
&&
922 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
926 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
927 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
930 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
931 IsDirectMapped
= TRUE
;
933 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
.QuadPart
, Dirty
);
935 Status
= STATUS_SUCCESS
;
937 if (!NT_SUCCESS(Status
))
939 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
940 KeBugCheck(MEMORY_MANAGEMENT
);
946 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
947 if (SavedSwapEntry
== 0)
950 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
951 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
955 * Try to page out this page and set the swap entry
956 * within the section segment. There exist no rmap entry
957 * for this page. The pager thread can't page out a
958 * page without a rmap entry.
960 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
961 if (InEntry
) *InEntry
= Entry
;
962 MiSetPageEvent(NULL
, NULL
);
966 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
967 if (InEntry
) *InEntry
= 0;
968 MiSetPageEvent(NULL
, NULL
);
971 MmReleasePageMemoryConsumer(MC_USER
, Page
);
977 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
978 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
986 * We hold all locks. Nobody can do something with the current
987 * process and the current segment (also not within an other process).
990 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
991 if (!NT_SUCCESS(Status
))
993 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
994 KeBugCheck(MEMORY_MANAGEMENT
);
997 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
998 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
999 MmSetSavedSwapEntryPage(Page
, 0);
1000 MiSetPageEvent(NULL
, NULL
);
1002 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1006 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1007 KeBugCheck(MEMORY_MANAGEMENT
);
1016 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1018 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1021 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1025 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1027 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1029 SharedCacheMap
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1030 Vacb
= CcRosLookupVacb(SharedCacheMap
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
);
1033 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, FALSE
, TRUE
);
1043 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1047 PVOID DestAddress
, SrcAddress
;
1049 Process
= PsGetCurrentProcess();
1050 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1051 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1052 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1054 return(STATUS_NO_MEMORY
);
1056 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1057 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1058 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1059 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1060 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1061 return(STATUS_SUCCESS
);
1067 MiReadPage(PMEMORY_AREA MemoryArea
,
1071 * FUNCTION: Read a page for a section backed memory area.
1073 * MemoryArea - Memory area to read the page for.
1074 * Offset - Offset of the page to read.
1075 * Page - Variable that receives a page contains the read data.
1078 LONGLONG BaseOffset
;
1079 LONGLONG FileOffset
;
1083 PFILE_OBJECT FileObject
;
1086 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1087 BOOLEAN IsImageSection
;
1090 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1091 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1092 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
;
1093 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1094 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1096 ASSERT(SharedCacheMap
);
1098 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1101 * If the file system is letting us go directly to the cache and the
1102 * memory area was mapped at an offset in the file which is page aligned
1103 * then get the related VACB.
1105 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1106 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1107 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1111 * Get the related VACB; we use a lower level interface than
1112 * filesystems do because it is safe for us to use an offset with an
1113 * alignment less than the file system block size.
1115 Status
= CcRosGetVacb(SharedCacheMap
,
1121 if (!NT_SUCCESS(Status
))
1128 * If the VACB isn't up to date then call the file
1129 * system to read in the data.
1131 Status
= CcReadVirtualAddress(Vacb
);
1132 if (!NT_SUCCESS(Status
))
1134 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1139 /* Probe the page, since it's PDE might not be synced */
1140 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1143 * Retrieve the page from the view that we actually want.
1145 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1146 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1148 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, TRUE
);
1155 LONGLONG VacbOffset
;
1158 * Allocate a page, this is rather complicated by the possibility
1159 * we might have to move other things out of memory
1161 MI_SET_USAGE(MI_USAGE_SECTION
);
1162 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1163 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1164 if (!NT_SUCCESS(Status
))
1168 Status
= CcRosGetVacb(SharedCacheMap
,
1174 if (!NT_SUCCESS(Status
))
1181 * If the VACB isn't up to date then call the file
1182 * system to read in the data.
1184 Status
= CcReadVirtualAddress(Vacb
);
1185 if (!NT_SUCCESS(Status
))
1187 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1192 Process
= PsGetCurrentProcess();
1193 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1194 VacbOffset
= BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
;
1195 Length
= RawLength
- SegOffset
;
1196 if (Length
<= VacbOffset
&& Length
<= PAGE_SIZE
)
1198 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1200 else if (VacbOffset
>= PAGE_SIZE
)
1202 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1206 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, VacbOffset
);
1207 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1208 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1209 Status
= CcRosGetVacb(SharedCacheMap
,
1210 FileOffset
+ VacbOffset
,
1215 if (!NT_SUCCESS(Status
))
1222 * If the VACB isn't up to date then call the file
1223 * system to read in the data.
1225 Status
= CcReadVirtualAddress(Vacb
);
1226 if (!NT_SUCCESS(Status
))
1228 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1232 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1233 if (Length
< PAGE_SIZE
)
1235 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, Length
- VacbOffset
);
1239 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, PAGE_SIZE
- VacbOffset
);
1242 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1243 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1245 return(STATUS_SUCCESS
);
1250 MiReadPage(PMEMORY_AREA MemoryArea
,
1254 * FUNCTION: Read a page for a section backed memory area.
1256 * MemoryArea - Memory area to read the page for.
1257 * Offset - Offset of the page to read.
1258 * Page - Variable that receives a page contains the read data.
1261 MM_REQUIRED_RESOURCES Resources
;
1264 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1266 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1267 Resources
.FileOffset
.QuadPart
= SegOffset
+
1268 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1269 Resources
.Consumer
= MC_USER
;
1270 Resources
.Amount
= PAGE_SIZE
;
1272 DPRINT("%S, offset 0x%x, len 0x%x, page 0x%x\n", ((PFILE_OBJECT
)Resources
.Context
)->FileName
.Buffer
, Resources
.FileOffset
.LowPart
, Resources
.Amount
, Resources
.Page
[0]);
1274 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1275 *Page
= Resources
.Page
[0];
1282 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1283 MEMORY_AREA
* MemoryArea
,
1287 LARGE_INTEGER Offset
;
1290 PROS_SECTION_OBJECT Section
;
1291 PMM_SECTION_SEGMENT Segment
;
1296 BOOLEAN HasSwapEntry
;
1298 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1299 SWAPENTRY SwapEntry
;
1302 * There is a window between taking the page fault and locking the
1303 * address space when another thread could load the page so we check
1306 if (MmIsPagePresent(Process
, Address
))
1308 return(STATUS_SUCCESS
);
1311 if (MmIsDisabledPage(Process
, Address
))
1313 return(STATUS_ACCESS_VIOLATION
);
1317 * Check for the virtual memory area being deleted.
1319 if (MemoryArea
->DeleteInProgress
)
1321 return(STATUS_UNSUCCESSFUL
);
1324 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1325 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1326 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1328 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1329 Section
= MemoryArea
->Data
.SectionData
.Section
;
1330 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1331 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1333 ASSERT(Region
!= NULL
);
1337 MmLockSectionSegment(Segment
);
1338 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1340 * Check if this page needs to be mapped COW
1342 if ((Segment
->WriteCopy
) &&
1343 (Region
->Protect
== PAGE_READWRITE
||
1344 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1346 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1350 Attributes
= Region
->Protect
;
1354 * Check if someone else is already handling this fault, if so wait
1357 if (Entry
&& MM_IS_WAIT_PTE(Entry
))
1359 MmUnlockSectionSegment(Segment
);
1360 MmUnlockAddressSpace(AddressSpace
);
1361 MiWaitForPageEvent(NULL
, NULL
);
1362 MmLockAddressSpace(AddressSpace
);
1363 DPRINT("Address 0x%p\n", Address
);
1364 return(STATUS_MM_RESTART_OPERATION
);
1367 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1369 /* See if we should use a private page */
1370 if ((HasSwapEntry
) || (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
))
1372 SWAPENTRY DummyEntry
;
1375 * Is it a wait entry?
1379 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1381 if (SwapEntry
== MM_WAIT_ENTRY
)
1383 MmUnlockSectionSegment(Segment
);
1384 MmUnlockAddressSpace(AddressSpace
);
1385 MiWaitForPageEvent(NULL
, NULL
);
1386 MmLockAddressSpace(AddressSpace
);
1387 return STATUS_MM_RESTART_OPERATION
;
1391 * Must be private page we have swapped out.
1397 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1399 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1400 KeBugCheck(MEMORY_MANAGEMENT
);
1402 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1405 MmUnlockSectionSegment(Segment
);
1407 /* Tell everyone else we are serving the fault. */
1408 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1410 MmUnlockAddressSpace(AddressSpace
);
1411 MI_SET_USAGE(MI_USAGE_SECTION
);
1412 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1413 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1414 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1415 if (!NT_SUCCESS(Status
))
1417 KeBugCheck(MEMORY_MANAGEMENT
);
1422 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1423 if (!NT_SUCCESS(Status
))
1425 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1426 KeBugCheck(MEMORY_MANAGEMENT
);
1430 MmLockAddressSpace(AddressSpace
);
1431 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1432 Status
= MmCreateVirtualMapping(Process
,
1437 if (!NT_SUCCESS(Status
))
1439 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1440 KeBugCheck(MEMORY_MANAGEMENT
);
1445 * Store the swap entry for later use.
1448 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1451 * Add the page to the process's working set
1453 MmInsertRmap(Page
, Process
, Address
);
1455 * Finish the operation
1457 MiSetPageEvent(Process
, Address
);
1458 DPRINT("Address 0x%p\n", Address
);
1459 return(STATUS_SUCCESS
);
1463 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1465 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1467 MmUnlockSectionSegment(Segment
);
1469 * Just map the desired physical page
1471 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1472 Status
= MmCreateVirtualMappingUnsafe(Process
,
1477 if (!NT_SUCCESS(Status
))
1479 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1480 KeBugCheck(MEMORY_MANAGEMENT
);
1485 * Cleanup and release locks
1487 MiSetPageEvent(Process
, Address
);
1488 DPRINT("Address 0x%p\n", Address
);
1489 return(STATUS_SUCCESS
);
1493 * Get the entry corresponding to the offset within the section
1495 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1499 SWAPENTRY FakeSwapEntry
;
1502 * If the entry is zero (and it can't change because we have
1503 * locked the segment) then we need to load the page.
1507 * Release all our locks and read in the page from disk
1509 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1510 MmUnlockSectionSegment(Segment
);
1511 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1512 MmUnlockAddressSpace(AddressSpace
);
1514 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1515 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1516 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1518 MI_SET_USAGE(MI_USAGE_SECTION
);
1519 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1520 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1521 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1522 if (!NT_SUCCESS(Status
))
1524 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1530 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1531 if (!NT_SUCCESS(Status
))
1533 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1536 if (!NT_SUCCESS(Status
))
1539 * FIXME: What do we know in this case?
1542 * Cleanup and release locks
1544 MmLockAddressSpace(AddressSpace
);
1545 MiSetPageEvent(Process
, Address
);
1546 DPRINT("Address 0x%p\n", Address
);
1550 /* Lock both segment and process address space while we proceed. */
1551 MmLockAddressSpace(AddressSpace
);
1552 MmLockSectionSegment(Segment
);
1554 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1555 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1556 Page
, Process
, PAddress
, Attributes
);
1557 Status
= MmCreateVirtualMapping(Process
,
1562 if (!NT_SUCCESS(Status
))
1564 DPRINT1("Unable to create virtual mapping\n");
1565 KeBugCheck(MEMORY_MANAGEMENT
);
1567 ASSERT(MmIsPagePresent(Process
, PAddress
));
1568 MmInsertRmap(Page
, Process
, Address
);
1570 /* Set this section offset has being backed by our new page. */
1571 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1572 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1573 MmUnlockSectionSegment(Segment
);
1575 MiSetPageEvent(Process
, Address
);
1576 DPRINT("Address 0x%p\n", Address
);
1577 return(STATUS_SUCCESS
);
1579 else if (IS_SWAP_FROM_SSE(Entry
))
1581 SWAPENTRY SwapEntry
;
1583 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1585 /* See if a page op is running on this segment. */
1586 if (SwapEntry
== MM_WAIT_ENTRY
)
1588 MmUnlockSectionSegment(Segment
);
1589 MmUnlockAddressSpace(AddressSpace
);
1590 MiWaitForPageEvent(NULL
, NULL
);
1591 MmLockAddressSpace(AddressSpace
);
1592 return STATUS_MM_RESTART_OPERATION
;
1596 * Release all our locks and read in the page from disk
1598 MmUnlockSectionSegment(Segment
);
1600 MmUnlockAddressSpace(AddressSpace
);
1601 MI_SET_USAGE(MI_USAGE_SECTION
);
1602 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1603 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1604 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1605 if (!NT_SUCCESS(Status
))
1607 KeBugCheck(MEMORY_MANAGEMENT
);
1610 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1611 if (!NT_SUCCESS(Status
))
1613 KeBugCheck(MEMORY_MANAGEMENT
);
1617 * Relock the address space and segment
1619 MmLockAddressSpace(AddressSpace
);
1620 MmLockSectionSegment(Segment
);
1623 * Check the entry. No one should change the status of a page
1624 * that has a pending page-in.
1626 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1627 if (Entry
!= Entry1
)
1629 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1630 KeBugCheck(MEMORY_MANAGEMENT
);
1634 * Save the swap entry.
1636 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1638 /* Map the page into the process address space */
1639 Status
= MmCreateVirtualMapping(Process
,
1644 if (!NT_SUCCESS(Status
))
1646 DPRINT1("Unable to create virtual mapping\n");
1647 KeBugCheck(MEMORY_MANAGEMENT
);
1649 MmInsertRmap(Page
, Process
, Address
);
1652 * Mark the offset within the section as having valid, in-memory
1655 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1656 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1657 MmUnlockSectionSegment(Segment
);
1659 MiSetPageEvent(Process
, Address
);
1660 DPRINT("Address 0x%p\n", Address
);
1661 return(STATUS_SUCCESS
);
1665 /* We already have a page on this section offset. Map it into the process address space. */
1666 Page
= PFN_FROM_SSE(Entry
);
1668 Status
= MmCreateVirtualMapping(Process
,
1673 if (!NT_SUCCESS(Status
))
1675 DPRINT1("Unable to create virtual mapping\n");
1676 KeBugCheck(MEMORY_MANAGEMENT
);
1678 MmInsertRmap(Page
, Process
, Address
);
1680 /* Take a reference on it */
1681 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1682 MmUnlockSectionSegment(Segment
);
1684 MiSetPageEvent(Process
, Address
);
1685 DPRINT("Address 0x%p\n", Address
);
1686 return(STATUS_SUCCESS
);
1692 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1693 MEMORY_AREA
* MemoryArea
,
1696 PMM_SECTION_SEGMENT Segment
;
1697 PROS_SECTION_OBJECT Section
;
1702 LARGE_INTEGER Offset
;
1705 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1707 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1709 /* Make sure we have a page mapping for this address. */
1710 Status
= MmNotPresentFaultSectionView(AddressSpace
, MemoryArea
, Address
, TRUE
);
1711 if (!NT_SUCCESS(Status
))
1713 /* This is invalid access ! */
1718 * Check if the page has already been set readwrite
1720 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1722 DPRINT("Address 0x%p\n", Address
);
1723 return(STATUS_SUCCESS
);
1727 * Find the offset of the page
1729 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1730 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1731 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1733 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1734 Section
= MemoryArea
->Data
.SectionData
.Section
;
1735 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1736 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1738 ASSERT(Region
!= NULL
);
1741 * Check if we are doing COW
1743 if (!((Segment
->WriteCopy
) &&
1744 (Region
->Protect
== PAGE_READWRITE
||
1745 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1747 DPRINT("Address 0x%p\n", Address
);
1748 return(STATUS_ACCESS_VIOLATION
);
1751 /* Get the page mapping this section offset. */
1752 MmLockSectionSegment(Segment
);
1753 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1755 /* Get the current page mapping for the process */
1756 ASSERT(MmIsPagePresent(Process
, PAddress
));
1757 OldPage
= MmGetPfnForProcess(Process
, PAddress
);
1758 ASSERT(OldPage
!= 0);
1760 if (IS_SWAP_FROM_SSE(Entry
) ||
1761 PFN_FROM_SSE(Entry
) != OldPage
)
1763 MmUnlockSectionSegment(Segment
);
1764 /* This is a private page. We must only change the page protection. */
1765 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1766 return(STATUS_SUCCESS
);
1772 MI_SET_USAGE(MI_USAGE_SECTION
);
1773 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1774 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1775 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1776 if (!NT_SUCCESS(Status
))
1778 KeBugCheck(MEMORY_MANAGEMENT
);
1784 MiCopyFromUserPage(NewPage
, OldPage
);
1787 * Unshare the old page.
1789 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1790 MmDeleteVirtualMapping(Process
, PAddress
, NULL
, NULL
);
1791 MmDeleteRmap(OldPage
, Process
, PAddress
);
1792 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1793 MmUnlockSectionSegment(Segment
);
1796 * Set the PTE to point to the new page
1798 Status
= MmCreateVirtualMapping(Process
,
1803 if (!NT_SUCCESS(Status
))
1805 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1806 KeBugCheck(MEMORY_MANAGEMENT
);
1809 MmInsertRmap(NewPage
, Process
, PAddress
);
1811 MiSetPageEvent(Process
, Address
);
1812 DPRINT("Address 0x%p\n", Address
);
1813 return(STATUS_SUCCESS
);
1817 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1819 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1821 PFN_NUMBER Page
= 0;
1823 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1826 MmLockAddressSpace(&Process
->Vm
);
1829 MmDeleteVirtualMapping(Process
,
1835 PageOutContext
->WasDirty
= TRUE
;
1837 if (!PageOutContext
->Private
)
1839 MmLockSectionSegment(PageOutContext
->Segment
);
1840 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1841 PageOutContext
->Segment
,
1842 &PageOutContext
->Offset
,
1843 PageOutContext
->WasDirty
,
1845 &PageOutContext
->SectionEntry
);
1846 MmUnlockSectionSegment(PageOutContext
->Segment
);
1850 MmUnlockAddressSpace(&Process
->Vm
);
1853 if (PageOutContext
->Private
)
1855 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1861 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1862 MEMORY_AREA
* MemoryArea
,
1863 PVOID Address
, ULONG_PTR Entry
)
1866 MM_SECTION_PAGEOUT_CONTEXT Context
;
1867 SWAPENTRY SwapEntry
;
1870 ULONGLONG FileOffset
;
1871 PFILE_OBJECT FileObject
;
1872 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1873 BOOLEAN IsImageSection
;
1875 BOOLEAN DirectMapped
;
1876 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1879 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1882 * Get the segment and section.
1884 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1885 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1886 Context
.SectionEntry
= Entry
;
1887 Context
.CallingProcess
= Process
;
1889 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
1890 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1892 DirectMapped
= FALSE
;
1894 MmLockSectionSegment(Context
.Segment
);
1897 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1898 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1899 FileObject
= Context
.Section
->FileObject
;
1901 if (FileObject
!= NULL
&&
1902 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1904 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1907 * If the file system is letting us go directly to the cache and the
1908 * memory area was mapped at an offset in the file which is page aligned
1909 * then note this is a direct mapped page.
1911 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1912 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1914 DirectMapped
= TRUE
;
1921 * This should never happen since mappings of physical memory are never
1922 * placed in the rmap lists.
1924 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1926 DPRINT1("Trying to page out from physical memory section address 0x%p "
1927 "process %p\n", Address
,
1928 Process
? Process
->UniqueProcessId
: 0);
1929 KeBugCheck(MEMORY_MANAGEMENT
);
1933 * Get the section segment entry and the physical address.
1935 if (!MmIsPagePresent(Process
, Address
))
1937 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1938 Process
? Process
->UniqueProcessId
: 0, Address
);
1939 KeBugCheck(MEMORY_MANAGEMENT
);
1941 Page
= MmGetPfnForProcess(Process
, Address
);
1942 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1945 * Check the reference count to ensure this page can be paged out
1947 if (MmGetReferenceCountPage(Page
) != 1)
1949 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1950 Page
, MmGetReferenceCountPage(Page
));
1951 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1952 MmUnlockSectionSegment(Context
.Segment
);
1953 return STATUS_UNSUCCESSFUL
;
1957 * Prepare the context structure for the rmap delete call.
1959 MmUnlockSectionSegment(Context
.Segment
);
1960 Context
.WasDirty
= FALSE
;
1961 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1962 IS_SWAP_FROM_SSE(Entry
) ||
1963 PFN_FROM_SSE(Entry
) != Page
)
1965 Context
.Private
= TRUE
;
1969 Context
.Private
= FALSE
;
1973 * Take an additional reference to the page or the VACB.
1975 if (DirectMapped
&& !Context
.Private
)
1977 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
1979 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1980 KeBugCheck(MEMORY_MANAGEMENT
);
1985 OldIrql
= MiAcquirePfnLock();
1986 MmReferencePage(Page
);
1987 MiReleasePfnLock(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 CcRosMarkDirtyFile(SharedCacheMap
, Offset
.QuadPart
);
2379 MmLockSectionSegment(Segment
);
2380 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2381 MmUnlockSectionSegment(Segment
);
2382 MiSetPageEvent(NULL
, NULL
);
2383 return(STATUS_SUCCESS
);
2387 * If necessary, allocate an entry in the paging file for this page
2391 SwapEntry
= MmAllocSwapPage();
2394 MmSetDirtyAllRmaps(Page
);
2395 MiSetPageEvent(NULL
, NULL
);
2396 return(STATUS_PAGEFILE_QUOTA
);
2398 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2402 * Write the page to the pagefile
2404 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2405 if (!NT_SUCCESS(Status
))
2407 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2409 MmSetDirtyAllRmaps(Page
);
2410 MiSetPageEvent(NULL
, NULL
);
2411 return(STATUS_UNSUCCESSFUL
);
2415 * Otherwise we have succeeded.
2417 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2418 MiSetPageEvent(NULL
, NULL
);
2419 return(STATUS_SUCCESS
);
2423 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2431 PMEMORY_AREA MemoryArea
;
2432 PMM_SECTION_SEGMENT Segment
;
2433 BOOLEAN DoCOW
= FALSE
;
2435 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2437 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2438 ASSERT(MemoryArea
!= NULL
);
2439 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2440 MmLockSectionSegment(Segment
);
2442 if ((Segment
->WriteCopy
) &&
2443 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2448 if (OldProtect
!= NewProtect
)
2450 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2452 SWAPENTRY SwapEntry
;
2453 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2454 ULONG Protect
= NewProtect
;
2456 /* Wait for a wait entry to disappear */
2459 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2460 if (SwapEntry
!= MM_WAIT_ENTRY
)
2462 MiWaitForPageEvent(Process
, Address
);
2467 * If we doing COW for this segment then check if the page is
2470 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2472 LARGE_INTEGER Offset
;
2476 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2477 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2478 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2480 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2481 * IS_SWAP_FROM_SSE and we'll do the right thing.
2483 Page
= MmGetPfnForProcess(Process
, Address
);
2485 Protect
= PAGE_READONLY
;
2486 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2487 IS_SWAP_FROM_SSE(Entry
) ||
2488 PFN_FROM_SSE(Entry
) != Page
)
2490 Protect
= NewProtect
;
2494 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2496 MmSetPageProtect(Process
, Address
,
2502 MmUnlockSectionSegment(Segment
);
2507 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2508 PMEMORY_AREA MemoryArea
,
2516 ULONG_PTR MaxLength
;
2518 MaxLength
= MA_GetEndingAddress(MemoryArea
) - (ULONG_PTR
)BaseAddress
;
2519 if (Length
> MaxLength
)
2520 Length
= (ULONG
)MaxLength
;
2522 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2523 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2525 ASSERT(Region
!= NULL
);
2527 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2528 Region
->Protect
!= Protect
)
2530 return STATUS_INVALID_PAGE_PROTECTION
;
2533 *OldProtect
= Region
->Protect
;
2534 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
2535 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2536 BaseAddress
, Length
, Region
->Type
, Protect
,
2537 MmAlterViewAttributes
);
2543 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2545 PMEMORY_BASIC_INFORMATION Info
,
2546 PSIZE_T ResultLength
)
2549 PVOID RegionBaseAddress
;
2550 PROS_SECTION_OBJECT Section
;
2551 PMM_SECTION_SEGMENT Segment
;
2553 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2554 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2555 Address
, &RegionBaseAddress
);
2558 return STATUS_UNSUCCESSFUL
;
2561 Section
= MemoryArea
->Data
.SectionData
.Section
;
2562 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2564 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2565 Info
->AllocationBase
= (PUCHAR
)MA_GetStartingAddress(MemoryArea
) - Segment
->Image
.VirtualAddress
;
2566 Info
->Type
= MEM_IMAGE
;
2570 Info
->AllocationBase
= (PVOID
)MA_GetStartingAddress(MemoryArea
);
2571 Info
->Type
= MEM_MAPPED
;
2573 Info
->BaseAddress
= RegionBaseAddress
;
2574 Info
->AllocationProtect
= MemoryArea
->Protect
;
2575 Info
->RegionSize
= Region
->Length
;
2576 Info
->State
= MEM_COMMIT
;
2577 Info
->Protect
= Region
->Protect
;
2579 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2580 return(STATUS_SUCCESS
);
2585 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2588 LARGE_INTEGER Offset
;
2590 SWAPENTRY SavedSwapEntry
;
2595 MmLockSectionSegment(Segment
);
2597 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2598 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2600 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2603 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2604 if (IS_SWAP_FROM_SSE(Entry
))
2606 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2610 Page
= PFN_FROM_SSE(Entry
);
2611 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2612 if (SavedSwapEntry
!= 0)
2614 MmSetSavedSwapEntryPage(Page
, 0);
2615 MmFreeSwapPage(SavedSwapEntry
);
2617 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2622 MmUnlockSectionSegment(Segment
);
2626 MmpDeleteSection(PVOID ObjectBody
)
2628 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2630 /* Check if it's an ARM3, or ReactOS section */
2631 if (!MiIsRosSectionObject(Section
))
2633 MiDeleteARM3Section(ObjectBody
);
2637 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2638 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2643 PMM_SECTION_SEGMENT SectionSegments
;
2646 * NOTE: Section->ImageSection can be NULL for short time
2647 * during the section creating. If we fail for some reason
2648 * until the image section is properly initialized we shouldn't
2649 * process further here.
2651 if (Section
->ImageSection
== NULL
)
2654 SectionSegments
= Section
->ImageSection
->Segments
;
2655 NrSegments
= Section
->ImageSection
->NrSegments
;
2657 for (i
= 0; i
< NrSegments
; i
++)
2659 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2661 MmLockSectionSegment(&SectionSegments
[i
]);
2663 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2664 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2666 MmUnlockSectionSegment(&SectionSegments
[i
]);
2669 MmpFreePageFileSegment(&SectionSegments
[i
]);
2675 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2678 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2681 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2683 DPRINT("Freeing section segment\n");
2684 Section
->Segment
= NULL
;
2685 MmFinalizeSegment(Segment
);
2689 DPRINT("RefCount %d\n", RefCount
);
2696 * NOTE: Section->Segment can be NULL for short time
2697 * during the section creating.
2699 if (Section
->Segment
== NULL
)
2702 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2704 MmpFreePageFileSegment(Section
->Segment
);
2705 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2706 ExFreePool(Section
->Segment
);
2707 Section
->Segment
= NULL
;
2711 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2714 if (Section
->FileObject
!= NULL
)
2717 CcRosDereferenceCache(Section
->FileObject
);
2719 ObDereferenceObject(Section
->FileObject
);
2720 Section
->FileObject
= NULL
;
2725 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2727 IN ACCESS_MASK GrantedAccess
,
2728 IN ULONG ProcessHandleCount
,
2729 IN ULONG SystemHandleCount
)
2731 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2737 MmCreatePhysicalMemorySection(VOID
)
2739 PROS_SECTION_OBJECT PhysSection
;
2741 OBJECT_ATTRIBUTES Obj
;
2742 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2743 LARGE_INTEGER SectionSize
;
2747 * Create the section mapping physical memory
2749 SectionSize
.QuadPart
= 0xFFFFFFFF;
2750 InitializeObjectAttributes(&Obj
,
2752 OBJ_PERMANENT
| OBJ_KERNEL_EXCLUSIVE
,
2755 Status
= MmCreateSection((PVOID
)&PhysSection
,
2759 PAGE_EXECUTE_READWRITE
,
2763 if (!NT_SUCCESS(Status
))
2765 DPRINT1("Failed to create PhysicalMemory section\n");
2766 KeBugCheck(MEMORY_MANAGEMENT
);
2768 Status
= ObInsertObject(PhysSection
,
2774 if (!NT_SUCCESS(Status
))
2776 ObDereferenceObject(PhysSection
);
2778 ObCloseHandle(Handle
, KernelMode
);
2779 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2780 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2782 return(STATUS_SUCCESS
);
2788 MmInitSectionImplementation(VOID
)
2790 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2791 UNICODE_STRING Name
;
2793 DPRINT("Creating Section Object Type\n");
2795 /* Initialize the section based root */
2796 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2797 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2799 /* Initialize the Section object type */
2800 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2801 RtlInitUnicodeString(&Name
, L
"Section");
2802 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2803 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2804 ObjectTypeInitializer
.PoolType
= PagedPool
;
2805 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2806 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2807 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2808 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2809 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2810 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2811 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2813 MmCreatePhysicalMemorySection();
2815 return(STATUS_SUCCESS
);
2820 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2821 ACCESS_MASK DesiredAccess
,
2822 POBJECT_ATTRIBUTES ObjectAttributes
,
2823 PLARGE_INTEGER UMaximumSize
,
2824 ULONG SectionPageProtection
,
2825 ULONG AllocationAttributes
)
2827 * Create a section which is backed by the pagefile
2830 LARGE_INTEGER MaximumSize
;
2831 PROS_SECTION_OBJECT Section
;
2832 PMM_SECTION_SEGMENT Segment
;
2835 if (UMaximumSize
== NULL
)
2837 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2838 return(STATUS_INVALID_PARAMETER
);
2840 MaximumSize
= *UMaximumSize
;
2843 * Create the section
2845 Status
= ObCreateObject(ExGetPreviousMode(),
2846 MmSectionObjectType
,
2848 ExGetPreviousMode(),
2850 sizeof(ROS_SECTION_OBJECT
),
2853 (PVOID
*)(PVOID
)&Section
);
2854 if (!NT_SUCCESS(Status
))
2856 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2863 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2864 Section
->Type
= 'SC';
2865 Section
->Size
= 'TN';
2866 Section
->SectionPageProtection
= SectionPageProtection
;
2867 Section
->AllocationAttributes
= AllocationAttributes
;
2868 Section
->MaximumSize
= MaximumSize
;
2869 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2870 TAG_MM_SECTION_SEGMENT
);
2871 if (Segment
== NULL
)
2873 ObDereferenceObject(Section
);
2874 return(STATUS_NO_MEMORY
);
2876 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2877 Section
->Segment
= Segment
;
2878 Segment
->ReferenceCount
= 1;
2879 ExInitializeFastMutex(&Segment
->Lock
);
2880 Segment
->Image
.FileOffset
= 0;
2881 Segment
->Protection
= SectionPageProtection
;
2882 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2883 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2884 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2885 Segment
->WriteCopy
= FALSE
;
2886 Segment
->Image
.VirtualAddress
= 0;
2887 Segment
->Image
.Characteristics
= 0;
2888 *SectionObject
= Section
;
2889 MiInitializeSectionPageTable(Segment
);
2890 return(STATUS_SUCCESS
);
2895 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2896 ACCESS_MASK DesiredAccess
,
2897 POBJECT_ATTRIBUTES ObjectAttributes
,
2898 PLARGE_INTEGER UMaximumSize
,
2899 ULONG SectionPageProtection
,
2900 ULONG AllocationAttributes
,
2901 PFILE_OBJECT FileObject
)
2903 * Create a section backed by a data file
2906 PROS_SECTION_OBJECT Section
;
2908 LARGE_INTEGER MaximumSize
;
2909 PMM_SECTION_SEGMENT Segment
;
2910 FILE_STANDARD_INFORMATION FileInfo
;
2914 * Create the section
2916 Status
= ObCreateObject(ExGetPreviousMode(),
2917 MmSectionObjectType
,
2919 ExGetPreviousMode(),
2921 sizeof(ROS_SECTION_OBJECT
),
2925 if (!NT_SUCCESS(Status
))
2927 ObDereferenceObject(FileObject
);
2933 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2934 Section
->Type
= 'SC';
2935 Section
->Size
= 'TN';
2936 Section
->SectionPageProtection
= SectionPageProtection
;
2937 Section
->AllocationAttributes
= AllocationAttributes
;
2940 * FIXME: This is propably not entirely correct. We can't look into
2941 * the standard FCB header because it might not be initialized yet
2942 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2943 * standard file information is filled on first request).
2945 Status
= IoQueryFileInformation(FileObject
,
2946 FileStandardInformation
,
2947 sizeof(FILE_STANDARD_INFORMATION
),
2950 if (!NT_SUCCESS(Status
))
2952 ObDereferenceObject(Section
);
2953 ObDereferenceObject(FileObject
);
2958 * FIXME: Revise this once a locking order for file size changes is
2961 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2963 MaximumSize
= *UMaximumSize
;
2967 MaximumSize
= FileInfo
.EndOfFile
;
2968 /* Mapping zero-sized files isn't allowed. */
2969 if (MaximumSize
.QuadPart
== 0)
2971 ObDereferenceObject(Section
);
2972 ObDereferenceObject(FileObject
);
2973 return STATUS_MAPPED_FILE_SIZE_ZERO
;
2977 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2979 Status
= IoSetInformation(FileObject
,
2980 FileEndOfFileInformation
,
2981 sizeof(LARGE_INTEGER
),
2983 if (!NT_SUCCESS(Status
))
2985 ObDereferenceObject(Section
);
2986 ObDereferenceObject(FileObject
);
2987 return(STATUS_SECTION_NOT_EXTENDED
);
2991 if (FileObject
->SectionObjectPointer
== NULL
||
2992 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2994 ObDereferenceObject(Section
);
2995 ObDereferenceObject(FileObject
);
2996 return STATUS_INVALID_FILE_FOR_SECTION
;
3002 Status
= MmspWaitForFileLock(FileObject
);
3003 if (Status
!= STATUS_SUCCESS
)
3005 ObDereferenceObject(Section
);
3006 ObDereferenceObject(FileObject
);
3011 * If this file hasn't been mapped as a data file before then allocate a
3012 * section segment to describe the data file mapping
3014 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3016 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3017 TAG_MM_SECTION_SEGMENT
);
3018 if (Segment
== NULL
)
3020 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3021 ObDereferenceObject(Section
);
3022 ObDereferenceObject(FileObject
);
3023 return(STATUS_NO_MEMORY
);
3025 Section
->Segment
= Segment
;
3026 Segment
->ReferenceCount
= 1;
3027 ExInitializeFastMutex(&Segment
->Lock
);
3029 * Set the lock before assigning the segment to the file object
3031 ExAcquireFastMutex(&Segment
->Lock
);
3032 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3034 Segment
->Image
.FileOffset
= 0;
3035 Segment
->Protection
= SectionPageProtection
;
3036 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3037 Segment
->Image
.Characteristics
= 0;
3038 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3039 if (AllocationAttributes
& SEC_RESERVE
)
3041 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3045 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3046 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3048 Segment
->Image
.VirtualAddress
= 0;
3049 Segment
->Locked
= TRUE
;
3050 MiInitializeSectionPageTable(Segment
);
3055 * If the file is already mapped as a data file then we may need
3059 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3061 Section
->Segment
= Segment
;
3062 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3063 MmLockSectionSegment(Segment
);
3065 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3066 !(AllocationAttributes
& SEC_RESERVE
))
3068 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3069 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3072 MmUnlockSectionSegment(Segment
);
3073 Section
->FileObject
= FileObject
;
3074 Section
->MaximumSize
= MaximumSize
;
3076 CcRosReferenceCache(FileObject
);
3078 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3079 *SectionObject
= Section
;
3080 return(STATUS_SUCCESS
);
3084 TODO: not that great (declaring loaders statically, having to declare all of
3085 them, having to keep them extern, etc.), will fix in the future
3087 extern NTSTATUS NTAPI PeFmtCreateSection
3089 IN CONST VOID
* FileHeader
,
3090 IN SIZE_T FileHeaderSize
,
3092 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3094 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3095 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3098 extern NTSTATUS NTAPI ElfFmtCreateSection
3100 IN CONST VOID
* FileHeader
,
3101 IN SIZE_T FileHeaderSize
,
3103 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3105 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3106 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3109 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3120 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3122 SIZE_T SizeOfSegments
;
3123 PMM_SECTION_SEGMENT Segments
;
3125 /* TODO: check for integer overflow */
3126 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3128 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3130 TAG_MM_SECTION_SEGMENT
);
3133 RtlZeroMemory(Segments
, SizeOfSegments
);
3141 ExeFmtpReadFile(IN PVOID File
,
3142 IN PLARGE_INTEGER Offset
,
3145 OUT PVOID
* AllocBase
,
3146 OUT PULONG ReadSize
)
3149 LARGE_INTEGER FileOffset
;
3151 ULONG OffsetAdjustment
;
3155 PFILE_OBJECT FileObject
= File
;
3156 IO_STATUS_BLOCK Iosb
;
3158 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3162 KeBugCheck(MEMORY_MANAGEMENT
);
3165 FileOffset
= *Offset
;
3167 /* Negative/special offset: it cannot be used in this context */
3168 if(FileOffset
.u
.HighPart
< 0)
3170 KeBugCheck(MEMORY_MANAGEMENT
);
3173 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3174 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3175 FileOffset
.u
.LowPart
= AdjustOffset
;
3177 BufferSize
= Length
+ OffsetAdjustment
;
3178 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3180 /* Flush data since we're about to perform a non-cached read */
3181 CcFlushCache(FileObject
->SectionObjectPointer
,
3187 * It's ok to use paged pool, because this is a temporary buffer only used in
3188 * the loading of executables. The assumption is that MmCreateSection is
3189 * always called at low IRQLs and that these buffers don't survive a brief
3190 * initialization phase
3192 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3197 return STATUS_INSUFFICIENT_RESOURCES
;
3202 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3204 UsedSize
= (ULONG
)Iosb
.Information
;
3206 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3208 Status
= STATUS_IN_PAGE_ERROR
;
3209 ASSERT(!NT_SUCCESS(Status
));
3212 if(NT_SUCCESS(Status
))
3214 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3215 *AllocBase
= Buffer
;
3216 *ReadSize
= UsedSize
- OffsetAdjustment
;
3220 ExFreePoolWithTag(Buffer
, 'rXmM');
3227 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3228 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3229 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3234 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3238 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3240 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3241 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3248 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3252 MmspAssertSegmentsSorted(ImageSectionObject
);
3254 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3256 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3260 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3261 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3262 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3270 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3274 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3276 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3277 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3285 MmspCompareSegments(const void * x
,
3288 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3289 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3292 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3293 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3297 * Ensures an image section's segments are sorted in memory
3302 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3305 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3307 MmspAssertSegmentsSorted(ImageSectionObject
);
3311 qsort(ImageSectionObject
->Segments
,
3312 ImageSectionObject
->NrSegments
,
3313 sizeof(ImageSectionObject
->Segments
[0]),
3314 MmspCompareSegments
);
3320 * Ensures an image section's segments don't overlap in memory and don't have
3321 * gaps and don't have a null size. We let them map to overlapping file regions,
3322 * though - that's not necessarily an error
3327 MmspCheckSegmentBounds
3329 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3335 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3337 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3341 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3343 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3345 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3353 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3354 * page could be OK (Windows seems to be OK with them), and larger gaps
3355 * could lead to image sections spanning several discontiguous regions
3356 * (NtMapViewOfSection could then refuse to map them, and they could
3357 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3359 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3360 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3361 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3372 * Merges and pads an image section's segments until they all are page-aligned
3373 * and have a size that is a multiple of the page size
3378 MmspPageAlignSegments
3380 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3386 PMM_SECTION_SEGMENT EffectiveSegment
;
3388 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3390 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3395 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3397 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3400 * The first segment requires special handling
3404 ULONG_PTR VirtualAddress
;
3405 ULONG_PTR VirtualOffset
;
3407 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3409 /* Round down the virtual address to the nearest page */
3410 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3412 /* Round up the virtual size to the nearest page */
3413 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3414 EffectiveSegment
->Image
.VirtualAddress
;
3416 /* Adjust the raw address and size */
3417 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3419 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3425 * Garbage in, garbage out: unaligned base addresses make the file
3426 * offset point in curious and odd places, but that's what we were
3429 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3430 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3434 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3435 ULONG_PTR EndOfEffectiveSegment
;
3437 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3438 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3441 * The current segment begins exactly where the current effective
3442 * segment ended, therefore beginning a new effective segment
3444 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3447 ASSERT(LastSegment
<= i
);
3448 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3450 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3452 if (LastSegment
!= i
)
3455 * Copy the current segment. If necessary, the effective segment
3456 * will be expanded later
3458 *EffectiveSegment
= *Segment
;
3462 * Page-align the virtual size. We know for sure the virtual address
3465 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3466 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3469 * The current segment is still part of the current effective segment:
3470 * extend the effective segment to reflect this
3472 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3474 static const ULONG FlagsToProtection
[16] =
3482 PAGE_EXECUTE_READWRITE
,
3483 PAGE_EXECUTE_READWRITE
,
3488 PAGE_EXECUTE_WRITECOPY
,
3489 PAGE_EXECUTE_WRITECOPY
,
3490 PAGE_EXECUTE_WRITECOPY
,
3491 PAGE_EXECUTE_WRITECOPY
3494 unsigned ProtectionFlags
;
3497 * Extend the file size
3500 /* Unaligned segments must be contiguous within the file */
3501 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3502 EffectiveSegment
->RawLength
.QuadPart
))
3507 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3510 * Extend the virtual size
3512 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3514 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3515 EffectiveSegment
->Image
.VirtualAddress
;
3518 * Merge the protection
3520 EffectiveSegment
->Protection
|= Segment
->Protection
;
3522 /* Clean up redundance */
3523 ProtectionFlags
= 0;
3525 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3526 ProtectionFlags
|= 1 << 0;
3528 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3529 ProtectionFlags
|= 1 << 1;
3531 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3532 ProtectionFlags
|= 1 << 2;
3534 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3535 ProtectionFlags
|= 1 << 3;
3537 ASSERT(ProtectionFlags
< 16);
3538 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3540 /* If a segment was required to be shared and cannot, fail */
3541 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3542 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3548 * We assume no holes between segments at this point
3552 KeBugCheck(MEMORY_MANAGEMENT
);
3556 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3562 ExeFmtpCreateImageSection(PFILE_OBJECT FileObject
,
3563 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3565 LARGE_INTEGER Offset
;
3567 PVOID FileHeaderBuffer
;
3568 ULONG FileHeaderSize
;
3570 ULONG OldNrSegments
;
3575 * Read the beginning of the file (2 pages). Should be enough to contain
3576 * all (or most) of the headers
3578 Offset
.QuadPart
= 0;
3580 Status
= ExeFmtpReadFile (FileObject
,
3587 if (!NT_SUCCESS(Status
))
3590 if (FileHeaderSize
== 0)
3592 ExFreePool(FileHeaderBuffer
);
3593 return STATUS_UNSUCCESSFUL
;
3597 * Look for a loader that can handle this executable
3599 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3601 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3604 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3610 ExeFmtpAllocateSegments
);
3612 if (!NT_SUCCESS(Status
))
3614 if (ImageSectionObject
->Segments
)
3616 ExFreePool(ImageSectionObject
->Segments
);
3617 ImageSectionObject
->Segments
= NULL
;
3621 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3625 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3628 * No loader handled the format
3630 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3632 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3633 ASSERT(!NT_SUCCESS(Status
));
3636 if (!NT_SUCCESS(Status
))
3639 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3644 /* FIXME? are these values platform-dependent? */
3645 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3646 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3648 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3649 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3651 if(ImageSectionObject
->BasedAddress
== NULL
)
3653 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3654 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3656 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3660 * And now the fun part: fixing the segments
3663 /* Sort them by virtual address */
3664 MmspSortSegments(ImageSectionObject
, Flags
);
3666 /* Ensure they don't overlap in memory */
3667 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3668 return STATUS_INVALID_IMAGE_FORMAT
;
3670 /* Ensure they are aligned */
3671 OldNrSegments
= ImageSectionObject
->NrSegments
;
3673 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3674 return STATUS_INVALID_IMAGE_FORMAT
;
3676 /* Trim them if the alignment phase merged some of them */
3677 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3679 PMM_SECTION_SEGMENT Segments
;
3680 SIZE_T SizeOfSegments
;
3682 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3684 Segments
= ExAllocatePoolWithTag(PagedPool
,
3686 TAG_MM_SECTION_SEGMENT
);
3688 if (Segments
== NULL
)
3689 return STATUS_INSUFFICIENT_RESOURCES
;
3691 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3692 ExFreePool(ImageSectionObject
->Segments
);
3693 ImageSectionObject
->Segments
= Segments
;
3696 /* And finish their initialization */
3697 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3699 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3700 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3701 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3704 ASSERT(NT_SUCCESS(Status
));
3709 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3710 ACCESS_MASK DesiredAccess
,
3711 POBJECT_ATTRIBUTES ObjectAttributes
,
3712 PLARGE_INTEGER UMaximumSize
,
3713 ULONG SectionPageProtection
,
3714 ULONG AllocationAttributes
,
3715 PFILE_OBJECT FileObject
)
3717 PROS_SECTION_OBJECT Section
;
3719 PMM_SECTION_SEGMENT SectionSegments
;
3720 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3723 if (FileObject
== NULL
)
3724 return STATUS_INVALID_FILE_FOR_SECTION
;
3727 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3729 DPRINT1("Denying section creation due to missing cache initialization\n");
3730 return STATUS_INVALID_FILE_FOR_SECTION
;
3735 * Create the section
3737 Status
= ObCreateObject (ExGetPreviousMode(),
3738 MmSectionObjectType
,
3740 ExGetPreviousMode(),
3742 sizeof(ROS_SECTION_OBJECT
),
3745 (PVOID
*)(PVOID
)&Section
);
3746 if (!NT_SUCCESS(Status
))
3748 ObDereferenceObject(FileObject
);
3755 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3756 Section
->Type
= 'SC';
3757 Section
->Size
= 'TN';
3758 Section
->SectionPageProtection
= SectionPageProtection
;
3759 Section
->AllocationAttributes
= AllocationAttributes
;
3761 if (FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3763 NTSTATUS StatusExeFmt
;
3765 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3766 if (ImageSectionObject
== NULL
)
3768 ObDereferenceObject(FileObject
);
3769 ObDereferenceObject(Section
);
3770 return(STATUS_NO_MEMORY
);
3773 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3775 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3777 if (!NT_SUCCESS(StatusExeFmt
))
3779 if(ImageSectionObject
->Segments
!= NULL
)
3780 ExFreePool(ImageSectionObject
->Segments
);
3783 * If image file is empty, then return that the file is invalid for section
3785 Status
= StatusExeFmt
;
3786 if (StatusExeFmt
== STATUS_END_OF_FILE
)
3788 Status
= STATUS_INVALID_FILE_FOR_SECTION
;
3791 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3792 ObDereferenceObject(Section
);
3793 ObDereferenceObject(FileObject
);
3797 Section
->ImageSection
= ImageSectionObject
;
3798 ASSERT(ImageSectionObject
->Segments
);
3803 Status
= MmspWaitForFileLock(FileObject
);
3804 if (!NT_SUCCESS(Status
))
3806 ExFreePool(ImageSectionObject
->Segments
);
3807 ExFreePool(ImageSectionObject
);
3808 ObDereferenceObject(Section
);
3809 ObDereferenceObject(FileObject
);
3813 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3814 ImageSectionObject
, NULL
))
3817 * An other thread has initialized the same image in the background
3819 ExFreePool(ImageSectionObject
->Segments
);
3820 ExFreePool(ImageSectionObject
);
3821 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3822 Section
->ImageSection
= ImageSectionObject
;
3823 SectionSegments
= ImageSectionObject
->Segments
;
3825 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3827 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3831 Status
= StatusExeFmt
;
3838 Status
= MmspWaitForFileLock(FileObject
);
3839 if (Status
!= STATUS_SUCCESS
)
3841 ObDereferenceObject(Section
);
3842 ObDereferenceObject(FileObject
);
3846 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3847 Section
->ImageSection
= ImageSectionObject
;
3848 SectionSegments
= ImageSectionObject
->Segments
;
3851 * Otherwise just reference all the section segments
3853 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3855 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3858 Status
= STATUS_SUCCESS
;
3860 Section
->FileObject
= FileObject
;
3862 CcRosReferenceCache(FileObject
);
3864 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3865 *SectionObject
= Section
;
3872 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3873 PROS_SECTION_OBJECT Section
,
3874 PMM_SECTION_SEGMENT Segment
,
3879 ULONG AllocationType
)
3885 if (Segment
->WriteCopy
)
3887 /* We have to do this because the not present fault
3888 * and access fault handlers depend on the protection
3889 * that should be granted AFTER the COW fault takes
3890 * place to be in Region->Protect. The not present fault
3891 * handler changes this to the correct protection for COW when
3892 * mapping the pages into the process's address space. If a COW
3893 * fault takes place, the access fault handler sets the page protection
3894 * to these values for the newly copied pages
3896 if (Protect
== PAGE_WRITECOPY
)
3897 Protect
= PAGE_READWRITE
;
3898 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3899 Protect
= PAGE_EXECUTE_READWRITE
;
3902 if (*BaseAddress
== NULL
)
3903 Granularity
= MM_ALLOCATION_GRANULARITY
;
3905 Granularity
= PAGE_SIZE
;
3908 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3910 LARGE_INTEGER FileOffset
;
3911 FileOffset
.QuadPart
= ViewOffset
;
3912 ObReferenceObject(Section
);
3913 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3916 Status
= MmCreateMemoryArea(AddressSpace
,
3917 MEMORY_AREA_SECTION_VIEW
,
3924 if (!NT_SUCCESS(Status
))
3926 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3927 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3931 ObReferenceObject((PVOID
)Section
);
3933 MArea
->Data
.SectionData
.Segment
= Segment
;
3934 MArea
->Data
.SectionData
.Section
= Section
;
3935 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3936 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3938 MArea
->VadNode
.u
.VadFlags
.VadType
= VadImageMap
;
3941 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3942 ViewSize
, 0, Protect
);
3944 return(STATUS_SUCCESS
);
3949 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3950 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3954 PFILE_OBJECT FileObject
;
3955 PROS_SHARED_CACHE_MAP SharedCacheMap
;
3957 LARGE_INTEGER Offset
;
3958 SWAPENTRY SavedSwapEntry
;
3959 PROS_SECTION_OBJECT Section
;
3960 PMM_SECTION_SEGMENT Segment
;
3961 PMMSUPPORT AddressSpace
;
3964 AddressSpace
= (PMMSUPPORT
)Context
;
3965 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3967 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3969 Offset
.QuadPart
= ((ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)) +
3970 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3972 Section
= MemoryArea
->Data
.SectionData
.Section
;
3973 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3975 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3976 while (Entry
&& MM_IS_WAIT_PTE(Entry
))
3978 MmUnlockSectionSegment(Segment
);
3979 MmUnlockAddressSpace(AddressSpace
);
3981 MiWaitForPageEvent(NULL
, NULL
);
3983 MmLockAddressSpace(AddressSpace
);
3984 MmLockSectionSegment(Segment
);
3985 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3989 * For a dirty, datafile, non-private page mark it as dirty in the
3992 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3994 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3997 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3998 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3999 CcRosMarkDirtyFile(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4001 ASSERT(SwapEntry
== 0);
4010 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4012 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4013 KeBugCheck(MEMORY_MANAGEMENT
);
4015 MmFreeSwapPage(SwapEntry
);
4019 if (IS_SWAP_FROM_SSE(Entry
) ||
4020 Page
!= PFN_FROM_SSE(Entry
))
4025 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4027 DPRINT1("Found a private page in a pagefile section.\n");
4028 KeBugCheck(MEMORY_MANAGEMENT
);
4031 * Just dereference private pages
4033 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4034 if (SavedSwapEntry
!= 0)
4036 MmFreeSwapPage(SavedSwapEntry
);
4037 MmSetSavedSwapEntryPage(Page
, 0);
4039 MmDeleteRmap(Page
, Process
, Address
);
4040 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4044 MmDeleteRmap(Page
, Process
, Address
);
4045 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4051 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4055 PMEMORY_AREA MemoryArea
;
4056 PROS_SECTION_OBJECT Section
;
4057 PMM_SECTION_SEGMENT Segment
;
4058 PLIST_ENTRY CurrentEntry
;
4059 PMM_REGION CurrentRegion
;
4060 PLIST_ENTRY RegionListHead
;
4062 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4064 if (MemoryArea
== NULL
)
4066 return(STATUS_UNSUCCESSFUL
);
4069 Section
= MemoryArea
->Data
.SectionData
.Section
;
4070 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4073 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4075 MmUnlockAddressSpace(AddressSpace
);
4076 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4077 MmLockAddressSpace(AddressSpace
);
4083 MemoryArea
->DeleteInProgress
= TRUE
;
4085 MmLockSectionSegment(Segment
);
4087 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4088 while (!IsListEmpty(RegionListHead
))
4090 CurrentEntry
= RemoveHeadList(RegionListHead
);
4091 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4092 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4095 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4097 Status
= MmFreeMemoryArea(AddressSpace
,
4104 Status
= MmFreeMemoryArea(AddressSpace
,
4109 MmUnlockSectionSegment(Segment
);
4110 ObDereferenceObject(Section
);
4116 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4117 IN PVOID BaseAddress
,
4118 IN BOOLEAN SkipDebuggerNotify
)
4121 PMEMORY_AREA MemoryArea
;
4122 PMMSUPPORT AddressSpace
;
4123 PROS_SECTION_OBJECT Section
;
4124 PVOID ImageBaseAddress
= 0;
4126 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4127 Process
, BaseAddress
);
4131 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4133 MmLockAddressSpace(AddressSpace
);
4134 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4136 if (MemoryArea
== NULL
||
4137 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4138 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4139 MemoryArea
->DeleteInProgress
)
4141 if (MemoryArea
) ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4142 MmUnlockAddressSpace(AddressSpace
);
4143 return STATUS_NOT_MAPPED_VIEW
;
4146 Section
= MemoryArea
->Data
.SectionData
.Section
;
4148 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4152 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4153 PMM_SECTION_SEGMENT SectionSegments
;
4154 PMM_SECTION_SEGMENT Segment
;
4156 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4157 ImageSectionObject
= Section
->ImageSection
;
4158 SectionSegments
= ImageSectionObject
->Segments
;
4159 NrSegments
= ImageSectionObject
->NrSegments
;
4161 MemoryArea
->DeleteInProgress
= TRUE
;
4163 /* Search for the current segment within the section segments
4164 * and calculate the image base address */
4165 for (i
= 0; i
< NrSegments
; i
++)
4167 if (Segment
== &SectionSegments
[i
])
4169 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4173 if (i
>= NrSegments
)
4175 KeBugCheck(MEMORY_MANAGEMENT
);
4178 for (i
= 0; i
< NrSegments
; i
++)
4180 PVOID SBaseAddress
= (PVOID
)
4181 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4183 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4184 if (!NT_SUCCESS(Status
))
4186 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4187 SBaseAddress
, Process
, Status
);
4188 ASSERT(NT_SUCCESS(Status
));
4194 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4195 if (!NT_SUCCESS(Status
))
4197 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4198 BaseAddress
, Process
, Status
);
4199 ASSERT(NT_SUCCESS(Status
));
4203 MmUnlockAddressSpace(AddressSpace
);
4205 /* Notify debugger */
4206 if (ImageBaseAddress
&& !SkipDebuggerNotify
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4208 return(STATUS_SUCCESS
);
4215 * Queries the information of a section object.
4217 * @param SectionHandle
4218 * Handle to the section object. It must be opened with SECTION_QUERY
4220 * @param SectionInformationClass
4221 * Index to a certain information structure. Can be either
4222 * SectionBasicInformation or SectionImageInformation. The latter
4223 * is valid only for sections that were created with the SEC_IMAGE
4225 * @param SectionInformation
4226 * Caller supplies storage for resulting information.
4228 * Size of the supplied storage.
4229 * @param ResultLength
4239 _In_ HANDLE SectionHandle
,
4240 _In_ SECTION_INFORMATION_CLASS SectionInformationClass
,
4241 _Out_ PVOID SectionInformation
,
4242 _In_ SIZE_T SectionInformationLength
,
4243 _Out_opt_ PSIZE_T ResultLength
)
4246 KPROCESSOR_MODE PreviousMode
;
4250 PreviousMode
= ExGetPreviousMode();
4251 if (PreviousMode
!= KernelMode
)
4255 ProbeForWrite(SectionInformation
,
4256 SectionInformationLength
,
4258 if (ResultLength
!= NULL
)
4260 ProbeForWrite(ResultLength
,
4261 sizeof(*ResultLength
),
4265 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4267 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4272 if (SectionInformationClass
== SectionBasicInformation
)
4274 if (SectionInformationLength
< sizeof(SECTION_BASIC_INFORMATION
))
4276 return STATUS_INFO_LENGTH_MISMATCH
;
4279 else if (SectionInformationClass
== SectionImageInformation
)
4281 if (SectionInformationLength
< sizeof(SECTION_IMAGE_INFORMATION
))
4283 return STATUS_INFO_LENGTH_MISMATCH
;
4288 return STATUS_INVALID_INFO_CLASS
;
4291 Status
= ObReferenceObjectByHandle(SectionHandle
,
4293 MmSectionObjectType
,
4295 (PVOID
*)(PVOID
)&Section
,
4297 if (!NT_SUCCESS(Status
))
4299 DPRINT1("Failed to reference section: 0x%lx\n", Status
);
4303 if (MiIsRosSectionObject(Section
))
4305 PROS_SECTION_OBJECT RosSection
= (PROS_SECTION_OBJECT
)Section
;
4307 switch (SectionInformationClass
)
4309 case SectionBasicInformation
:
4311 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4315 Sbi
->Attributes
= RosSection
->AllocationAttributes
;
4316 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4318 Sbi
->BaseAddress
= 0;
4319 Sbi
->Size
.QuadPart
= 0;
4323 Sbi
->BaseAddress
= (PVOID
)RosSection
->Segment
->Image
.VirtualAddress
;
4324 Sbi
->Size
.QuadPart
= RosSection
->Segment
->Length
.QuadPart
;
4327 if (ResultLength
!= NULL
)
4329 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4331 Status
= STATUS_SUCCESS
;
4333 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4335 Status
= _SEH2_GetExceptionCode();
4342 case SectionImageInformation
:
4344 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4348 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4350 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4351 ImageSectionObject
= RosSection
->ImageSection
;
4353 *Sii
= ImageSectionObject
->ImageInformation
;
4356 if (ResultLength
!= NULL
)
4358 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4360 Status
= STATUS_SUCCESS
;
4362 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4364 Status
= _SEH2_GetExceptionCode();
4374 switch(SectionInformationClass
)
4376 case SectionBasicInformation
:
4378 SECTION_BASIC_INFORMATION Sbi
;
4380 Sbi
.Size
= Section
->SizeOfSection
;
4381 Sbi
.BaseAddress
= (PVOID
)Section
->Address
.StartingVpn
;
4384 if (Section
->u
.Flags
.Image
)
4385 Sbi
.Attributes
|= SEC_IMAGE
;
4386 if (Section
->u
.Flags
.Commit
)
4387 Sbi
.Attributes
|= SEC_COMMIT
;
4388 if (Section
->u
.Flags
.Reserve
)
4389 Sbi
.Attributes
|= SEC_RESERVE
;
4390 if (Section
->u
.Flags
.File
)
4391 Sbi
.Attributes
|= SEC_FILE
;
4392 if (Section
->u
.Flags
.Image
)
4393 Sbi
.Attributes
|= SEC_IMAGE
;
4395 /* FIXME : Complete/test the list of flags passed back from NtCreateSection */
4399 *((SECTION_BASIC_INFORMATION
*)SectionInformation
) = Sbi
;
4401 *ResultLength
= sizeof(Sbi
);
4403 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4405 Status
= _SEH2_GetExceptionCode();
4410 case SectionImageInformation
:
4412 if (!Section
->u
.Flags
.Image
)
4414 Status
= STATUS_SECTION_NOT_IMAGE
;
4418 /* Currently not supported */
4426 ObDereferenceObject(Section
);
4431 /**********************************************************************
4433 * MmMapViewOfSection
4436 * Maps a view of a section into the virtual address space of a
4441 * Pointer to the section object.
4444 * Pointer to the process.
4447 * Desired base address (or NULL) on entry;
4448 * Actual base address of the view on exit.
4451 * Number of high order address bits that must be zero.
4454 * Size in bytes of the initially committed section of
4458 * Offset in bytes from the beginning of the section
4459 * to the beginning of the view.
4462 * Desired length of map (or zero to map all) on entry
4463 * Actual length mapped on exit.
4465 * InheritDisposition
4466 * Specified how the view is to be shared with
4470 * Type of allocation for the pages.
4473 * Protection for the committed region of the view.
4481 MmMapViewOfSection(IN PVOID SectionObject
,
4482 IN PEPROCESS Process
,
4483 IN OUT PVOID
*BaseAddress
,
4484 IN ULONG_PTR ZeroBits
,
4485 IN SIZE_T CommitSize
,
4486 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4487 IN OUT PSIZE_T ViewSize
,
4488 IN SECTION_INHERIT InheritDisposition
,
4489 IN ULONG AllocationType
,
4492 PROS_SECTION_OBJECT Section
;
4493 PMMSUPPORT AddressSpace
;
4495 NTSTATUS Status
= STATUS_SUCCESS
;
4496 BOOLEAN NotAtBase
= FALSE
;
4498 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4500 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4501 return MmMapViewOfArm3Section(SectionObject
,
4515 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4517 return STATUS_INVALID_PAGE_PROTECTION
;
4520 /* FIXME: We should keep this, but it would break code checking equality */
4521 Protect
&= ~PAGE_NOCACHE
;
4523 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4524 AddressSpace
= &Process
->Vm
;
4526 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4528 MmLockAddressSpace(AddressSpace
);
4530 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4534 ULONG_PTR ImageBase
;
4536 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4537 PMM_SECTION_SEGMENT SectionSegments
;
4539 ImageSectionObject
= Section
->ImageSection
;
4540 SectionSegments
= ImageSectionObject
->Segments
;
4541 NrSegments
= ImageSectionObject
->NrSegments
;
4543 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4546 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4550 for (i
= 0; i
< NrSegments
; i
++)
4552 ULONG_PTR MaxExtent
;
4553 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4554 SectionSegments
[i
].Length
.QuadPart
);
4555 ImageSize
= max(ImageSize
, MaxExtent
);
4558 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4560 /* Check for an illegal base address */
4561 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4562 ((ImageBase
+ ImageSize
) < ImageSize
))
4564 ASSERT(*BaseAddress
== NULL
);
4565 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4566 MM_VIRTMEM_GRANULARITY
);
4569 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4571 ASSERT(*BaseAddress
== NULL
);
4572 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4576 /* Check there is enough space to map the section at that point. */
4577 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4578 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4580 /* Fail if the user requested a fixed base address. */
4581 if ((*BaseAddress
) != NULL
)
4583 MmUnlockAddressSpace(AddressSpace
);
4584 return(STATUS_CONFLICTING_ADDRESSES
);
4586 /* Otherwise find a gap to map the image. */
4587 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4590 MmUnlockAddressSpace(AddressSpace
);
4591 return(STATUS_CONFLICTING_ADDRESSES
);
4593 /* Remember that we loaded image at a different base address */
4597 for (i
= 0; i
< NrSegments
; i
++)
4599 PVOID SBaseAddress
= (PVOID
)
4600 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4601 MmLockSectionSegment(&SectionSegments
[i
]);
4602 Status
= MmMapViewOfSegment(AddressSpace
,
4604 &SectionSegments
[i
],
4606 SectionSegments
[i
].Length
.LowPart
,
4607 SectionSegments
[i
].Protection
,
4610 MmUnlockSectionSegment(&SectionSegments
[i
]);
4611 if (!NT_SUCCESS(Status
))
4613 MmUnlockAddressSpace(AddressSpace
);
4618 *BaseAddress
= (PVOID
)ImageBase
;
4619 *ViewSize
= ImageSize
;
4623 /* check for write access */
4624 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4625 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4627 MmUnlockAddressSpace(AddressSpace
);
4628 return STATUS_SECTION_PROTECTION
;
4630 /* check for read access */
4631 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4632 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4634 MmUnlockAddressSpace(AddressSpace
);
4635 return STATUS_SECTION_PROTECTION
;
4637 /* check for execute access */
4638 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4639 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4641 MmUnlockAddressSpace(AddressSpace
);
4642 return STATUS_SECTION_PROTECTION
;
4645 if (SectionOffset
== NULL
)
4651 ViewOffset
= SectionOffset
->u
.LowPart
;
4654 if ((ViewOffset
% PAGE_SIZE
) != 0)
4656 MmUnlockAddressSpace(AddressSpace
);
4657 return(STATUS_MAPPED_ALIGNMENT
);
4660 if ((*ViewSize
) == 0)
4662 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4664 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4666 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4669 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4671 MmLockSectionSegment(Section
->Segment
);
4672 Status
= MmMapViewOfSegment(AddressSpace
,
4679 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4680 MmUnlockSectionSegment(Section
->Segment
);
4681 if (!NT_SUCCESS(Status
))
4683 MmUnlockAddressSpace(AddressSpace
);
4688 MmUnlockAddressSpace(AddressSpace
);
4689 ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4692 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4694 Status
= STATUS_SUCCESS
;
4703 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4704 IN PLARGE_INTEGER NewFileSize
)
4706 /* Check whether an ImageSectionObject exists */
4707 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4709 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4713 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4715 PMM_SECTION_SEGMENT Segment
;
4717 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4720 if (Segment
->ReferenceCount
!= 0)
4723 CC_FILE_SIZES FileSizes
;
4725 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4728 /* Check size of file */
4729 if (SectionObjectPointer
->SharedCacheMap
)
4731 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4736 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4745 /* Check size of file */
4746 if (SectionObjectPointer
->SharedCacheMap
)
4748 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4749 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4758 /* Something must gone wrong
4759 * how can we have a Section but no
4761 DPRINT("ERROR: DataSectionObject without reference!\n");
4765 DPRINT("FIXME: didn't check for outstanding write probes\n");
4777 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4778 IN MMFLUSH_TYPE FlushType
)
4780 BOOLEAN Result
= TRUE
;
4782 PMM_SECTION_SEGMENT Segment
;
4787 case MmFlushForDelete
:
4788 if (SectionObjectPointer
->ImageSectionObject
||
4789 SectionObjectPointer
->DataSectionObject
)
4794 CcRosRemoveIfClosed(SectionObjectPointer
);
4797 case MmFlushForWrite
:
4799 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4801 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4804 if (SectionObjectPointer
->ImageSectionObject
)
4806 DPRINT1("SectionObject has ImageSection\n");
4812 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4814 DPRINT("Result %d\n", Result
);
4826 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4827 OUT PVOID
* MappedBase
,
4828 IN OUT PSIZE_T ViewSize
)
4830 PROS_SECTION_OBJECT Section
;
4831 PMMSUPPORT AddressSpace
;
4835 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4837 return MiMapViewInSystemSpace(SectionObject
,
4843 DPRINT("MmMapViewInSystemSpace() called\n");
4845 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4846 AddressSpace
= MmGetKernelAddressSpace();
4848 MmLockAddressSpace(AddressSpace
);
4851 if ((*ViewSize
) == 0)
4853 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4855 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4857 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4860 MmLockSectionSegment(Section
->Segment
);
4863 Status
= MmMapViewOfSegment(AddressSpace
,
4872 MmUnlockSectionSegment(Section
->Segment
);
4873 MmUnlockAddressSpace(AddressSpace
);
4880 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4882 PMMSUPPORT AddressSpace
;
4885 DPRINT("MmUnmapViewInSystemSpace() called\n");
4887 AddressSpace
= MmGetKernelAddressSpace();
4889 MmLockAddressSpace(AddressSpace
);
4891 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4893 MmUnlockAddressSpace(AddressSpace
);
4898 /**********************************************************************
4903 * Creates a section object.
4906 * SectionObject (OUT)
4907 * Caller supplied storage for the resulting pointer
4908 * to a SECTION_OBJECT instance;
4911 * Specifies the desired access to the section can be a
4913 * STANDARD_RIGHTS_REQUIRED |
4915 * SECTION_MAP_WRITE |
4916 * SECTION_MAP_READ |
4917 * SECTION_MAP_EXECUTE
4919 * ObjectAttributes [OPTIONAL]
4920 * Initialized attributes for the object can be used
4921 * to create a named section;
4924 * Maximizes the size of the memory section. Must be
4925 * non-NULL for a page-file backed section.
4926 * If value specified for a mapped file and the file is
4927 * not large enough, file will be extended.
4929 * SectionPageProtection
4930 * Can be a combination of:
4936 * AllocationAttributes
4937 * Can be a combination of:
4942 * Handle to a file to create a section mapped to a file
4943 * instead of a memory backed section;
4954 MmCreateSection (OUT PVOID
* Section
,
4955 IN ACCESS_MASK DesiredAccess
,
4956 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4957 IN PLARGE_INTEGER MaximumSize
,
4958 IN ULONG SectionPageProtection
,
4959 IN ULONG AllocationAttributes
,
4960 IN HANDLE FileHandle OPTIONAL
,
4961 IN PFILE_OBJECT FileObject OPTIONAL
)
4965 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4967 /* Check if an ARM3 section is being created instead */
4968 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4970 if (!(FileObject
) && !(FileHandle
))
4972 return MmCreateArm3Section(Section
,
4976 SectionPageProtection
,
4977 AllocationAttributes
&~ 1,
4983 /* Convert section flag to page flag */
4984 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4986 /* Check to make sure the protection is correct. Nt* does this already */
4987 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4988 if (Protection
== MM_INVALID_PROTECTION
)
4990 DPRINT1("Page protection is invalid\n");
4991 return STATUS_INVALID_PAGE_PROTECTION
;
4994 /* Check if this is going to be a data or image backed file section */
4995 if ((FileHandle
) || (FileObject
))
4997 /* These cannot be mapped with large pages */
4998 if (AllocationAttributes
& SEC_LARGE_PAGES
)
5000 DPRINT1("Large pages cannot be used with an image mapping\n");
5001 return STATUS_INVALID_PARAMETER_6
;
5004 /* Did the caller pass an object? */
5007 /* Reference the object directly */
5008 ObReferenceObject(FileObject
);
5012 /* Reference the file handle to get the object */
5013 Status
= ObReferenceObjectByHandle(FileHandle
,
5014 MmMakeFileAccess
[Protection
],
5016 ExGetPreviousMode(),
5017 (PVOID
*)&FileObject
,
5019 if (!NT_SUCCESS(Status
))
5021 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
5028 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
5029 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
5032 #ifndef NEWCC // A hack for initializing caching.
5033 // This is needed only in the old case.
5036 IO_STATUS_BLOCK Iosb
;
5039 LARGE_INTEGER ByteOffset
;
5040 ByteOffset
.QuadPart
= 0;
5041 Status
= ZwReadFile(FileHandle
,
5050 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5052 DPRINT1("CC failure: %lx\n", Status
);
5054 ObDereferenceObject(FileObject
);
5057 // Caching is initialized...
5059 // Hack of the hack: actually, it might not be initialized if FSD init on effective right and if file is null-size
5060 // In such case, force cache by initiating a write IRP
5061 if (Status
== STATUS_END_OF_FILE
&& !(AllocationAttributes
& SEC_IMAGE
) && FileObject
!= NULL
&&
5062 (FileObject
->SectionObjectPointer
== NULL
|| FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
))
5065 Status
= ZwWriteFile(FileHandle
,
5074 if (NT_SUCCESS(Status
))
5077 Zero
.QuadPart
= 0LL;
5079 Status
= IoSetInformation(FileObject
,
5080 FileEndOfFileInformation
,
5081 sizeof(LARGE_INTEGER
),
5083 ASSERT(NT_SUCCESS(Status
));
5089 if (AllocationAttributes
& SEC_IMAGE
)
5091 Status
= MmCreateImageSection(SectionObject
,
5095 SectionPageProtection
,
5096 AllocationAttributes
,
5100 else if (FileHandle
!= NULL
)
5102 Status
= MmCreateDataFileSection(SectionObject
,
5106 SectionPageProtection
,
5107 AllocationAttributes
,
5111 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5113 Status
= MmCreateCacheSection(SectionObject
,
5117 SectionPageProtection
,
5118 AllocationAttributes
,
5124 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5126 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5128 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5129 Status
= MmCreatePageFileSection(SectionObject
,
5133 SectionPageProtection
,
5134 AllocationAttributes
);
5136 ObDereferenceObject(FileObject
);