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
= {
167 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
168 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
169 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
172 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
174 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
175 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
178 /* FUNCTIONS *****************************************************************/
183 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
184 File Format Specification", revision 6.0 (February 1999)
186 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
187 IN SIZE_T FileHeaderSize
,
189 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
191 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
192 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
195 ULONG cbFileHeaderOffsetSize
= 0;
196 ULONG cbSectionHeadersOffset
= 0;
197 ULONG cbSectionHeadersSize
;
198 ULONG cbSectionHeadersOffsetSize
= 0;
199 ULONG cbOptHeaderSize
;
200 ULONG cbHeadersSize
= 0;
201 ULONG nSectionAlignment
;
202 ULONG nFileAlignment
;
204 const IMAGE_DOS_HEADER
* pidhDosHeader
;
205 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
206 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
207 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
208 PMM_SECTION_SEGMENT pssSegments
;
209 LARGE_INTEGER lnOffset
;
211 SIZE_T nPrevVirtualEndOfSegment
= 0;
212 ULONG nFileSizeOfHeaders
= 0;
216 ASSERT(FileHeaderSize
> 0);
218 ASSERT(ImageSectionObject
);
220 ASSERT(AllocateSegmentsCb
);
222 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
224 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
226 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
229 pidhDosHeader
= FileHeader
;
232 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
234 /* image too small to be an MZ executable */
235 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
236 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
238 /* no MZ signature */
239 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
240 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
242 /* not a Windows executable */
243 if(pidhDosHeader
->e_lfanew
<= 0)
244 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
247 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
249 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
250 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
252 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
257 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
258 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
260 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
261 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
265 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
266 * need to read the header from the file
268 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
269 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
271 ULONG cbNtHeaderSize
;
275 l_ReadHeaderFromFile
:
277 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
279 /* read the header from the file */
280 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
282 if(!NT_SUCCESS(nStatus
))
284 NTSTATUS ReturnedStatus
= nStatus
;
286 /* If it attempted to read past the end of the file, it means e_lfanew is invalid */
287 if (ReturnedStatus
== STATUS_END_OF_FILE
) nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
289 DIE(("ReadFile failed, status %08X\n", ReturnedStatus
));
294 ASSERT(cbReadSize
> 0);
296 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
298 /* the buffer doesn't contain the file header */
299 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
300 DIE(("The file doesn't contain the PE file header\n"));
302 pinhNtHeader
= pData
;
304 /* object still not aligned: copy it to the beginning of the buffer */
305 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
307 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
308 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
309 pinhNtHeader
= pBuffer
;
312 /* invalid NT header */
313 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
315 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
316 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
318 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
320 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
321 DIE(("The full NT header is too large\n"));
323 /* the buffer doesn't contain the whole NT header */
324 if(cbReadSize
< cbNtHeaderSize
)
325 DIE(("The file doesn't contain the full NT header\n"));
329 ULONG cbOptHeaderOffsetSize
= 0;
331 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
333 /* don't trust an invalid NT header */
334 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
335 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
337 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
338 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
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
:
362 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
366 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
369 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
370 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
372 /* See [1], section 3.4.2 */
373 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
375 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
376 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
378 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
379 DIE(("The section alignment is smaller than the file alignment\n"));
381 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
382 nFileAlignment
= piohOptHeader
->FileAlignment
;
384 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
385 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
389 nSectionAlignment
= PAGE_SIZE
;
390 nFileAlignment
= PAGE_SIZE
;
393 ASSERT(IsPowerOf2(nSectionAlignment
));
394 ASSERT(IsPowerOf2(nFileAlignment
));
396 switch(piohOptHeader
->Magic
)
399 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
401 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
402 ImageBase
= piohOptHeader
->ImageBase
;
404 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
405 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
407 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
408 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
410 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
411 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
413 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
415 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
417 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
418 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
420 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
421 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
425 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
427 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
428 piohOptHeader
->AddressOfEntryPoint
);
431 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
432 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
434 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
436 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
438 if (piohOptHeader
->AddressOfEntryPoint
== 0)
440 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
444 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
445 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
447 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
449 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
452 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
453 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
454 * magic to any binary.
456 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
457 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
458 * the SxS support -- at which point, duh, this should be removed.
460 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
462 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
469 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
471 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
473 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
475 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
477 ImageBase
= pioh64OptHeader
->ImageBase
;
478 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
479 DIE(("ImageBase exceeds the address space\n"));
482 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
484 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
485 DIE(("SizeOfImage exceeds the address space\n"));
487 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
490 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
492 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
493 DIE(("SizeOfStackReserve exceeds the address space\n"));
495 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
498 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
500 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
501 DIE(("SizeOfStackCommit exceeds the address space\n"));
503 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
506 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
508 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
510 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
511 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
513 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
514 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
518 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
520 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
521 pioh64OptHeader
->AddressOfEntryPoint
);
524 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
525 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
527 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
529 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
531 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
533 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
537 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
538 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
540 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
541 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
548 /* [1], section 3.4.2 */
549 if((ULONG_PTR
)ImageBase
% 0x10000)
550 DIE(("ImageBase is not aligned on a 64KB boundary"));
552 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
553 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
554 ImageSectionObject
->ImageInformation
.GpValue
= 0;
555 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
556 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
558 /* SECTION HEADERS */
559 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
561 /* see [1], section 3.3 */
562 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
563 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
566 * the additional segment is for the file's headers. They need to be present for
567 * the benefit of the dynamic loader (to locate exports, defaults for thread
568 * parameters, resources, etc.)
570 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
572 /* file offset for the section headers */
573 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
574 DIE(("Offset overflow\n"));
576 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
577 DIE(("Offset overflow\n"));
579 /* size of the section headers */
580 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
581 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
583 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
584 DIE(("Section headers too large\n"));
586 /* size of the executable's headers */
587 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
589 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
590 // DIE(("SizeOfHeaders is not aligned\n"));
592 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
593 DIE(("The section headers overflow SizeOfHeaders\n"));
595 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
597 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
598 DIE(("Overflow aligning the size of headers\n"));
605 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
606 /* WARNING: piohOptHeader IS NO LONGER USABLE */
607 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
609 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
610 pishSectionHeaders
= NULL
;
614 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
615 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
617 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
618 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
622 * the buffer doesn't contain the section headers, or the alignment is wrong:
623 * read the headers from the file
625 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
626 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
631 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
633 /* read the header from the file */
634 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
636 if(!NT_SUCCESS(nStatus
))
637 DIE(("ReadFile failed with status %08X\n", nStatus
));
641 ASSERT(cbReadSize
> 0);
643 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
645 /* the buffer doesn't contain all the section headers */
646 if(cbReadSize
< cbSectionHeadersSize
)
647 DIE(("The file doesn't contain all of the section headers\n"));
649 pishSectionHeaders
= pData
;
651 /* object still not aligned: copy it to the beginning of the buffer */
652 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
654 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
655 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
656 pishSectionHeaders
= pBuffer
;
661 /* allocate the segments */
662 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
663 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
665 if(ImageSectionObject
->Segments
== NULL
)
666 DIE(("AllocateSegments failed\n"));
668 /* initialize the headers segment */
669 pssSegments
= ImageSectionObject
->Segments
;
671 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
673 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
674 DIE(("Cannot align the size of the section headers\n"));
676 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
677 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
678 DIE(("Cannot align the size of the section headers\n"));
680 pssSegments
[0].Image
.FileOffset
= 0;
681 pssSegments
[0].Protection
= PAGE_READONLY
;
682 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
683 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
684 pssSegments
[0].Image
.VirtualAddress
= 0;
685 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
686 pssSegments
[0].WriteCopy
= TRUE
;
688 /* skip the headers segment */
691 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
693 /* convert the executable sections into segments. See also [1], section 4 */
694 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
696 ULONG nCharacteristics
;
698 /* validate the alignment */
699 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
700 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
702 /* sections must be contiguous, ordered by base address and non-overlapping */
703 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
704 DIE(("Memory gap between section %u and the previous\n", i
));
706 /* ignore explicit BSS sections */
707 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
709 /* validate the alignment */
711 /* Yes, this should be a multiple of FileAlignment, but there's
712 * stuff out there that isn't. We can cope with that
714 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
715 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
718 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
719 // DIE(("PointerToRawData[%u] is not aligned\n", i));
722 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
723 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
727 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
728 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
731 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
733 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
735 /* no explicit protection */
736 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
738 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
739 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
741 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
742 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
744 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
745 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
748 /* see table above */
749 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
750 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
752 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
753 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
755 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
757 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
758 /* FIXME: always false */
759 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
760 DIE(("Cannot align the virtual size of section %u\n", i
));
762 if(pssSegments
[i
].Length
.QuadPart
== 0)
763 DIE(("Virtual size of section %u is null\n", i
));
765 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
766 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
768 /* ensure the memory image is no larger than 4GB */
769 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
770 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
771 DIE(("The image is too large\n"));
774 if(nSectionAlignment
>= PAGE_SIZE
)
775 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
778 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
788 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
789 * ARGUMENTS: PFILE_OBJECT to wait for.
790 * RETURNS: Status of the wait.
793 MmspWaitForFileLock(PFILE_OBJECT File
)
795 return STATUS_SUCCESS
;
796 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
801 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
803 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
805 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
806 PMM_SECTION_SEGMENT SectionSegments
;
810 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
811 NrSegments
= ImageSectionObject
->NrSegments
;
812 SectionSegments
= ImageSectionObject
->Segments
;
813 for (i
= 0; i
< NrSegments
; i
++)
815 if (SectionSegments
[i
].ReferenceCount
!= 0)
817 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
818 SectionSegments
[i
].ReferenceCount
);
819 KeBugCheck(MEMORY_MANAGEMENT
);
821 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
823 ExFreePool(ImageSectionObject
->Segments
);
824 ExFreePool(ImageSectionObject
);
825 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
827 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
829 PMM_SECTION_SEGMENT Segment
;
831 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
834 if (Segment
->ReferenceCount
!= 0)
836 DPRINT1("Data segment still referenced\n");
837 KeBugCheck(MEMORY_MANAGEMENT
);
839 MmFreePageTablesSectionSegment(Segment
, NULL
);
841 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
847 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
848 PLARGE_INTEGER Offset
)
852 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
855 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
856 KeBugCheck(MEMORY_MANAGEMENT
);
858 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
860 DPRINT1("Maximum share count reached\n");
861 KeBugCheck(MEMORY_MANAGEMENT
);
863 if (IS_SWAP_FROM_SSE(Entry
))
865 KeBugCheck(MEMORY_MANAGEMENT
);
867 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
868 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
873 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
874 PMM_SECTION_SEGMENT Segment
,
875 PLARGE_INTEGER Offset
,
880 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
881 BOOLEAN IsDirectMapped
= FALSE
;
885 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
886 KeBugCheck(MEMORY_MANAGEMENT
);
888 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
890 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
891 KeBugCheck(MEMORY_MANAGEMENT
);
893 if (IS_SWAP_FROM_SSE(Entry
))
895 KeBugCheck(MEMORY_MANAGEMENT
);
897 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
899 * If we reducing the share count of this entry to zero then set the entry
900 * to zero and tell the cache the page is no longer mapped.
902 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
904 PFILE_OBJECT FileObject
;
906 PROS_SHARED_CACHE_MAP SharedCacheMap
;
908 SWAPENTRY SavedSwapEntry
;
910 BOOLEAN IsImageSection
;
911 LARGE_INTEGER FileOffset
;
913 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
915 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
917 Page
= PFN_FROM_SSE(Entry
);
918 FileObject
= Section
->FileObject
;
919 if (FileObject
!= NULL
&&
920 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
924 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
925 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
928 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
929 IsDirectMapped
= TRUE
;
931 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
.QuadPart
, Dirty
);
933 Status
= STATUS_SUCCESS
;
935 if (!NT_SUCCESS(Status
))
937 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
938 KeBugCheck(MEMORY_MANAGEMENT
);
944 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
945 if (SavedSwapEntry
== 0)
948 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
949 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
953 * Try to page out this page and set the swap entry
954 * within the section segment. There exist no rmap entry
955 * for this page. The pager thread can't page out a
956 * page without a rmap entry.
958 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
959 if (InEntry
) *InEntry
= Entry
;
960 MiSetPageEvent(NULL
, NULL
);
964 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
965 if (InEntry
) *InEntry
= 0;
966 MiSetPageEvent(NULL
, NULL
);
969 MmReleasePageMemoryConsumer(MC_USER
, Page
);
975 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
976 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
984 * We hold all locks. Nobody can do something with the current
985 * process and the current segment (also not within an other process).
988 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
989 if (!NT_SUCCESS(Status
))
991 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
992 KeBugCheck(MEMORY_MANAGEMENT
);
995 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
996 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
997 MmSetSavedSwapEntryPage(Page
, 0);
998 MiSetPageEvent(NULL
, NULL
);
1000 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1004 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1005 KeBugCheck(MEMORY_MANAGEMENT
);
1014 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1016 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1019 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1023 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1025 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1027 SharedCacheMap
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1028 Vacb
= CcRosLookupVacb(SharedCacheMap
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
);
1031 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, FALSE
, TRUE
);
1041 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1045 PVOID DestAddress
, SrcAddress
;
1047 Process
= PsGetCurrentProcess();
1048 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1049 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1050 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1052 return(STATUS_NO_MEMORY
);
1054 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1055 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1056 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1057 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1058 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1059 return(STATUS_SUCCESS
);
1065 MiReadPage(PMEMORY_AREA MemoryArea
,
1069 * FUNCTION: Read a page for a section backed memory area.
1071 * MemoryArea - Memory area to read the page for.
1072 * Offset - Offset of the page to read.
1073 * Page - Variable that receives a page contains the read data.
1076 LONGLONG BaseOffset
;
1077 LONGLONG FileOffset
;
1081 PFILE_OBJECT FileObject
;
1084 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1085 BOOLEAN IsImageSection
;
1088 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1089 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1090 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
;
1091 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1092 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1094 ASSERT(SharedCacheMap
);
1096 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1099 * If the file system is letting us go directly to the cache and the
1100 * memory area was mapped at an offset in the file which is page aligned
1101 * then get the related VACB.
1103 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1104 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1105 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1109 * Get the related VACB; we use a lower level interface than
1110 * filesystems do because it is safe for us to use an offset with an
1111 * alignment less than the file system block size.
1113 Status
= CcRosGetVacb(SharedCacheMap
,
1119 if (!NT_SUCCESS(Status
))
1126 * If the VACB isn't up to date then call the file
1127 * system to read in the data.
1129 Status
= CcReadVirtualAddress(Vacb
);
1130 if (!NT_SUCCESS(Status
))
1132 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1137 /* Probe the page, since it's PDE might not be synced */
1138 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1141 * Retrieve the page from the view that we actually want.
1143 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1144 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1146 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, TRUE
);
1153 LONGLONG VacbOffset
;
1156 * Allocate a page, this is rather complicated by the possibility
1157 * we might have to move other things out of memory
1159 MI_SET_USAGE(MI_USAGE_SECTION
);
1160 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1161 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1162 if (!NT_SUCCESS(Status
))
1166 Status
= CcRosGetVacb(SharedCacheMap
,
1172 if (!NT_SUCCESS(Status
))
1179 * If the VACB isn't up to date then call the file
1180 * system to read in the data.
1182 Status
= CcReadVirtualAddress(Vacb
);
1183 if (!NT_SUCCESS(Status
))
1185 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1190 Process
= PsGetCurrentProcess();
1191 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1192 VacbOffset
= BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
;
1193 Length
= RawLength
- SegOffset
;
1194 if (Length
<= VacbOffset
&& Length
<= PAGE_SIZE
)
1196 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1198 else if (VacbOffset
>= PAGE_SIZE
)
1200 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1204 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, VacbOffset
);
1205 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1206 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1207 Status
= CcRosGetVacb(SharedCacheMap
,
1208 FileOffset
+ VacbOffset
,
1213 if (!NT_SUCCESS(Status
))
1220 * If the VACB isn't up to date then call the file
1221 * system to read in the data.
1223 Status
= CcReadVirtualAddress(Vacb
);
1224 if (!NT_SUCCESS(Status
))
1226 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1230 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1231 if (Length
< PAGE_SIZE
)
1233 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, Length
- VacbOffset
);
1237 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, PAGE_SIZE
- VacbOffset
);
1240 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1241 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1243 return(STATUS_SUCCESS
);
1248 MiReadPage(PMEMORY_AREA MemoryArea
,
1252 * FUNCTION: Read a page for a section backed memory area.
1254 * MemoryArea - Memory area to read the page for.
1255 * Offset - Offset of the page to read.
1256 * Page - Variable that receives a page contains the read data.
1259 MM_REQUIRED_RESOURCES Resources
;
1262 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1264 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1265 Resources
.FileOffset
.QuadPart
= SegOffset
+
1266 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1267 Resources
.Consumer
= MC_USER
;
1268 Resources
.Amount
= PAGE_SIZE
;
1270 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]);
1272 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1273 *Page
= Resources
.Page
[0];
1280 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1281 MEMORY_AREA
* MemoryArea
,
1285 LARGE_INTEGER Offset
;
1288 PROS_SECTION_OBJECT Section
;
1289 PMM_SECTION_SEGMENT Segment
;
1294 BOOLEAN HasSwapEntry
;
1296 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1297 SWAPENTRY SwapEntry
;
1300 * There is a window between taking the page fault and locking the
1301 * address space when another thread could load the page so we check
1304 if (MmIsPagePresent(Process
, Address
))
1306 return(STATUS_SUCCESS
);
1309 if (MmIsDisabledPage(Process
, Address
))
1311 return(STATUS_ACCESS_VIOLATION
);
1315 * Check for the virtual memory area being deleted.
1317 if (MemoryArea
->DeleteInProgress
)
1319 return(STATUS_UNSUCCESSFUL
);
1322 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1323 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1324 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1326 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1327 Section
= MemoryArea
->Data
.SectionData
.Section
;
1328 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1329 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1331 ASSERT(Region
!= NULL
);
1335 MmLockSectionSegment(Segment
);
1336 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1338 * Check if this page needs to be mapped COW
1340 if ((Segment
->WriteCopy
) &&
1341 (Region
->Protect
== PAGE_READWRITE
||
1342 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1344 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1348 Attributes
= Region
->Protect
;
1352 * Check if someone else is already handling this fault, if so wait
1355 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1357 MmUnlockSectionSegment(Segment
);
1358 MmUnlockAddressSpace(AddressSpace
);
1359 MiWaitForPageEvent(NULL
, NULL
);
1360 MmLockAddressSpace(AddressSpace
);
1361 DPRINT("Address 0x%p\n", Address
);
1362 return(STATUS_MM_RESTART_OPERATION
);
1365 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1369 SWAPENTRY DummyEntry
;
1372 * Is it a wait entry?
1374 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1376 if (SwapEntry
== MM_WAIT_ENTRY
)
1378 MmUnlockSectionSegment(Segment
);
1379 MmUnlockAddressSpace(AddressSpace
);
1380 MiWaitForPageEvent(NULL
, NULL
);
1381 MmLockAddressSpace(AddressSpace
);
1382 return STATUS_MM_RESTART_OPERATION
;
1386 * Must be private page we have swapped out.
1392 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1394 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1395 KeBugCheck(MEMORY_MANAGEMENT
);
1398 MmUnlockSectionSegment(Segment
);
1399 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1400 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1402 MmUnlockAddressSpace(AddressSpace
);
1403 MI_SET_USAGE(MI_USAGE_SECTION
);
1404 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1405 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1406 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1407 if (!NT_SUCCESS(Status
))
1409 KeBugCheck(MEMORY_MANAGEMENT
);
1412 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1413 if (!NT_SUCCESS(Status
))
1415 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1416 KeBugCheck(MEMORY_MANAGEMENT
);
1418 MmLockAddressSpace(AddressSpace
);
1419 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1420 Status
= MmCreateVirtualMapping(Process
,
1425 if (!NT_SUCCESS(Status
))
1427 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1428 KeBugCheck(MEMORY_MANAGEMENT
);
1433 * Store the swap entry for later use.
1435 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1438 * Add the page to the process's working set
1440 MmInsertRmap(Page
, Process
, Address
);
1442 * Finish the operation
1444 MiSetPageEvent(Process
, Address
);
1445 DPRINT("Address 0x%p\n", Address
);
1446 return(STATUS_SUCCESS
);
1450 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1452 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1454 MmUnlockSectionSegment(Segment
);
1456 * Just map the desired physical page
1458 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1459 Status
= MmCreateVirtualMappingUnsafe(Process
,
1464 if (!NT_SUCCESS(Status
))
1466 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1467 KeBugCheck(MEMORY_MANAGEMENT
);
1472 * Cleanup and release locks
1474 MiSetPageEvent(Process
, Address
);
1475 DPRINT("Address 0x%p\n", Address
);
1476 return(STATUS_SUCCESS
);
1480 * Get the entry corresponding to the offset within the section
1482 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1486 SWAPENTRY FakeSwapEntry
;
1489 * If the entry is zero (and it can't change because we have
1490 * locked the segment) then we need to load the page.
1494 * Release all our locks and read in the page from disk
1496 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1497 MmUnlockSectionSegment(Segment
);
1498 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1499 MmUnlockAddressSpace(AddressSpace
);
1501 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1502 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1503 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1505 MI_SET_USAGE(MI_USAGE_SECTION
);
1506 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1507 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1508 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1509 if (!NT_SUCCESS(Status
))
1511 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1517 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1518 if (!NT_SUCCESS(Status
))
1520 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1523 if (!NT_SUCCESS(Status
))
1526 * FIXME: What do we know in this case?
1529 * Cleanup and release locks
1531 MmLockAddressSpace(AddressSpace
);
1532 MiSetPageEvent(Process
, Address
);
1533 DPRINT("Address 0x%p\n", Address
);
1538 * Mark the offset within the section as having valid, in-memory
1541 MmLockAddressSpace(AddressSpace
);
1542 MmLockSectionSegment(Segment
);
1543 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1544 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1545 MmUnlockSectionSegment(Segment
);
1547 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1548 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1549 Page
, Process
, PAddress
, Attributes
);
1550 Status
= MmCreateVirtualMapping(Process
,
1555 if (!NT_SUCCESS(Status
))
1557 DPRINT1("Unable to create virtual mapping\n");
1558 KeBugCheck(MEMORY_MANAGEMENT
);
1560 ASSERT(MmIsPagePresent(Process
, PAddress
));
1561 MmInsertRmap(Page
, Process
, Address
);
1563 MiSetPageEvent(Process
, Address
);
1564 DPRINT("Address 0x%p\n", Address
);
1565 return(STATUS_SUCCESS
);
1567 else if (IS_SWAP_FROM_SSE(Entry
))
1569 SWAPENTRY SwapEntry
;
1571 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1574 * Release all our locks and read in the page from disk
1576 MmUnlockSectionSegment(Segment
);
1578 MmUnlockAddressSpace(AddressSpace
);
1579 MI_SET_USAGE(MI_USAGE_SECTION
);
1580 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1581 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1582 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1583 if (!NT_SUCCESS(Status
))
1585 KeBugCheck(MEMORY_MANAGEMENT
);
1588 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1589 if (!NT_SUCCESS(Status
))
1591 KeBugCheck(MEMORY_MANAGEMENT
);
1595 * Relock the address space and segment
1597 MmLockAddressSpace(AddressSpace
);
1598 MmLockSectionSegment(Segment
);
1601 * Check the entry. No one should change the status of a page
1602 * that has a pending page-in.
1604 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1605 if (Entry
!= Entry1
)
1607 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1608 KeBugCheck(MEMORY_MANAGEMENT
);
1612 * Mark the offset within the section as having valid, in-memory
1615 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1616 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1617 MmUnlockSectionSegment(Segment
);
1620 * Save the swap entry.
1622 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1623 Status
= MmCreateVirtualMapping(Process
,
1628 if (!NT_SUCCESS(Status
))
1630 DPRINT1("Unable to create virtual mapping\n");
1631 KeBugCheck(MEMORY_MANAGEMENT
);
1633 MmInsertRmap(Page
, Process
, Address
);
1634 MiSetPageEvent(Process
, Address
);
1635 DPRINT("Address 0x%p\n", Address
);
1636 return(STATUS_SUCCESS
);
1641 * If the section offset is already in-memory and valid then just
1642 * take another reference to the page
1645 Page
= PFN_FROM_SSE(Entry
);
1647 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1648 MmUnlockSectionSegment(Segment
);
1650 Status
= MmCreateVirtualMapping(Process
,
1655 if (!NT_SUCCESS(Status
))
1657 DPRINT1("Unable to create virtual mapping\n");
1658 KeBugCheck(MEMORY_MANAGEMENT
);
1660 MmInsertRmap(Page
, Process
, Address
);
1661 MiSetPageEvent(Process
, Address
);
1662 DPRINT("Address 0x%p\n", Address
);
1663 return(STATUS_SUCCESS
);
1669 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1670 MEMORY_AREA
* MemoryArea
,
1673 PMM_SECTION_SEGMENT Segment
;
1674 PROS_SECTION_OBJECT Section
;
1679 LARGE_INTEGER Offset
;
1682 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1683 SWAPENTRY SwapEntry
;
1685 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1688 * Check if the page has already been set readwrite
1690 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1692 DPRINT("Address 0x%p\n", Address
);
1693 return(STATUS_SUCCESS
);
1697 * Find the offset of the page
1699 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1700 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1701 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1703 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1704 Section
= MemoryArea
->Data
.SectionData
.Section
;
1705 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1706 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1708 ASSERT(Region
!= NULL
);
1712 MmLockSectionSegment(Segment
);
1714 OldPage
= MmGetPfnForProcess(Process
, Address
);
1715 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1717 MmUnlockSectionSegment(Segment
);
1720 * Check if we are doing COW
1722 if (!((Segment
->WriteCopy
) &&
1723 (Region
->Protect
== PAGE_READWRITE
||
1724 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1726 DPRINT("Address 0x%p\n", Address
);
1727 return(STATUS_ACCESS_VIOLATION
);
1730 if (IS_SWAP_FROM_SSE(Entry
) ||
1731 PFN_FROM_SSE(Entry
) != OldPage
)
1733 /* This is a private page. We must only change the page protection. */
1734 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1735 return(STATUS_SUCCESS
);
1739 DPRINT("OldPage == 0!\n");
1742 * Get or create a pageop
1744 MmLockSectionSegment(Segment
);
1745 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1748 * Wait for any other operations to complete
1750 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1752 MmUnlockSectionSegment(Segment
);
1753 MmUnlockAddressSpace(AddressSpace
);
1754 MiWaitForPageEvent(NULL
, NULL
);
1756 * Restart the operation
1758 MmLockAddressSpace(AddressSpace
);
1759 DPRINT("Address 0x%p\n", Address
);
1760 return(STATUS_MM_RESTART_OPERATION
);
1763 MmDeleteRmap(OldPage
, Process
, PAddress
);
1764 MmDeleteVirtualMapping(Process
, PAddress
, FALSE
, NULL
, NULL
);
1765 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1768 * Release locks now we have the pageop
1770 MmUnlockSectionSegment(Segment
);
1771 MmUnlockAddressSpace(AddressSpace
);
1776 MI_SET_USAGE(MI_USAGE_SECTION
);
1777 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1778 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1779 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1780 if (!NT_SUCCESS(Status
))
1782 KeBugCheck(MEMORY_MANAGEMENT
);
1788 MiCopyFromUserPage(NewPage
, OldPage
);
1790 MmLockAddressSpace(AddressSpace
);
1793 * Set the PTE to point to the new page
1795 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1796 Status
= MmCreateVirtualMapping(Process
,
1801 if (!NT_SUCCESS(Status
))
1803 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1804 KeBugCheck(MEMORY_MANAGEMENT
);
1809 * Unshare the old page.
1811 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1812 MmInsertRmap(NewPage
, Process
, PAddress
);
1813 MmLockSectionSegment(Segment
);
1814 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1815 MmUnlockSectionSegment(Segment
);
1817 MiSetPageEvent(Process
, Address
);
1818 DPRINT("Address 0x%p\n", Address
);
1819 return(STATUS_SUCCESS
);
1823 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1825 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1827 PFN_NUMBER Page
= 0;
1829 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1832 MmLockAddressSpace(&Process
->Vm
);
1835 MmDeleteVirtualMapping(Process
,
1842 PageOutContext
->WasDirty
= TRUE
;
1844 if (!PageOutContext
->Private
)
1846 MmLockSectionSegment(PageOutContext
->Segment
);
1847 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1848 PageOutContext
->Segment
,
1849 &PageOutContext
->Offset
,
1850 PageOutContext
->WasDirty
,
1852 &PageOutContext
->SectionEntry
);
1853 MmUnlockSectionSegment(PageOutContext
->Segment
);
1857 MmUnlockAddressSpace(&Process
->Vm
);
1860 if (PageOutContext
->Private
)
1862 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1868 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1869 MEMORY_AREA
* MemoryArea
,
1870 PVOID Address
, ULONG_PTR Entry
)
1873 MM_SECTION_PAGEOUT_CONTEXT Context
;
1874 SWAPENTRY SwapEntry
;
1875 ULONGLONG FileOffset
;
1877 PFILE_OBJECT FileObject
;
1879 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1881 BOOLEAN DirectMapped
;
1882 BOOLEAN IsImageSection
;
1883 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1886 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1889 * Get the segment and section.
1891 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1892 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1893 Context
.SectionEntry
= Entry
;
1894 Context
.CallingProcess
= Process
;
1896 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1897 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1898 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1900 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1902 FileObject
= Context
.Section
->FileObject
;
1903 DirectMapped
= FALSE
;
1905 MmLockSectionSegment(Context
.Segment
);
1908 if (FileObject
!= NULL
&&
1909 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1911 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1914 * If the file system is letting us go directly to the cache and the
1915 * memory area was mapped at an offset in the file which is page aligned
1916 * then note this is a direct mapped page.
1918 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1919 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1921 DirectMapped
= TRUE
;
1928 * This should never happen since mappings of physical memory are never
1929 * placed in the rmap lists.
1931 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1933 DPRINT1("Trying to page out from physical memory section address 0x%p "
1934 "process %p\n", Address
,
1935 Process
? Process
->UniqueProcessId
: 0);
1936 KeBugCheck(MEMORY_MANAGEMENT
);
1940 * Get the section segment entry and the physical address.
1942 if (!MmIsPagePresent(Process
, Address
))
1944 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1945 Process
? Process
->UniqueProcessId
: 0, Address
);
1946 KeBugCheck(MEMORY_MANAGEMENT
);
1948 Page
= MmGetPfnForProcess(Process
, Address
);
1949 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1952 * Check the reference count to ensure this page can be paged out
1954 if (MmGetReferenceCountPage(Page
) != 1)
1956 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1957 Page
, MmGetReferenceCountPage(Page
));
1958 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1959 MmUnlockSectionSegment(Context
.Segment
);
1960 return STATUS_UNSUCCESSFUL
;
1964 * Prepare the context structure for the rmap delete call.
1966 MmUnlockSectionSegment(Context
.Segment
);
1967 Context
.WasDirty
= FALSE
;
1968 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1969 IS_SWAP_FROM_SSE(Entry
) ||
1970 PFN_FROM_SSE(Entry
) != Page
)
1972 Context
.Private
= TRUE
;
1976 Context
.Private
= FALSE
;
1980 * Take an additional reference to the page or the VACB.
1982 if (DirectMapped
&& !Context
.Private
)
1984 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
1986 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1987 KeBugCheck(MEMORY_MANAGEMENT
);
1992 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1993 MmReferencePage(Page
);
1994 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1997 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1999 /* Since we passed in a surrogate, we'll get back the page entry
2000 * state in our context. This is intended to make intermediate
2001 * decrements of share count not release the wait entry.
2003 Entry
= Context
.SectionEntry
;
2006 * If this wasn't a private page then we should have reduced the entry to
2007 * zero by deleting all the rmaps.
2009 if (!Context
.Private
&& Entry
!= 0)
2011 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2012 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2014 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2019 * If the page wasn't dirty then we can just free it as for a readonly page.
2020 * Since we unmapped all the mappings above we know it will not suddenly
2022 * If the page is from a pagefile section and has no swap entry,
2023 * we can't free the page at this point.
2025 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2026 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2028 if (Context
.Private
)
2030 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2031 Context
.WasDirty
? "dirty" : "clean", Address
);
2032 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2034 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2036 MmSetSavedSwapEntryPage(Page
, 0);
2037 MmLockSectionSegment(Context
.Segment
);
2038 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2039 MmUnlockSectionSegment(Context
.Segment
);
2040 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2041 MiSetPageEvent(NULL
, NULL
);
2042 return(STATUS_SUCCESS
);
2045 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2047 if (Context
.Private
)
2049 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2050 Context
.WasDirty
? "dirty" : "clean", Address
);
2051 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2053 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2055 MmSetSavedSwapEntryPage(Page
, 0);
2058 MmLockSectionSegment(Context
.Segment
);
2059 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2060 MmUnlockSectionSegment(Context
.Segment
);
2062 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2063 MiSetPageEvent(NULL
, NULL
);
2064 return(STATUS_SUCCESS
);
2067 else if (!Context
.Private
&& DirectMapped
)
2071 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2073 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2076 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
, FALSE
);
2078 Status
= STATUS_SUCCESS
;
2081 if (!NT_SUCCESS(Status
))
2083 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2084 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2087 MiSetPageEvent(NULL
, NULL
);
2088 return(STATUS_SUCCESS
);
2090 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2094 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2096 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2098 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2099 MiSetPageEvent(NULL
, NULL
);
2100 return(STATUS_SUCCESS
);
2102 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2104 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2105 MmSetSavedSwapEntryPage(Page
, 0);
2106 MmLockAddressSpace(AddressSpace
);
2107 Status
= MmCreatePageFileMapping(Process
,
2110 MmUnlockAddressSpace(AddressSpace
);
2111 if (!NT_SUCCESS(Status
))
2113 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2114 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2116 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2117 MiSetPageEvent(NULL
, NULL
);
2118 return(STATUS_SUCCESS
);
2122 * If necessary, allocate an entry in the paging file for this page
2126 SwapEntry
= MmAllocSwapPage();
2129 MmShowOutOfSpaceMessagePagingFile();
2130 MmLockAddressSpace(AddressSpace
);
2132 * For private pages restore the old mappings.
2134 if (Context
.Private
)
2136 Status
= MmCreateVirtualMapping(Process
,
2138 MemoryArea
->Protect
,
2141 MmSetDirtyPage(Process
, Address
);
2150 * For non-private pages if the page wasn't direct mapped then
2151 * set it back into the section segment entry so we don't loose
2152 * our copy. Otherwise it will be handled by the cache manager.
2154 Status
= MmCreateVirtualMapping(Process
,
2156 MemoryArea
->Protect
,
2159 MmSetDirtyPage(Process
, Address
);
2163 // If we got here, the previous entry should have been a wait
2164 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2165 MmLockSectionSegment(Context
.Segment
);
2166 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2167 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2168 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2169 MmUnlockSectionSegment(Context
.Segment
);
2171 MmUnlockAddressSpace(AddressSpace
);
2172 MiSetPageEvent(NULL
, NULL
);
2173 return(STATUS_PAGEFILE_QUOTA
);
2178 * Write the page to the pagefile
2180 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2181 if (!NT_SUCCESS(Status
))
2183 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2186 * As above: undo our actions.
2187 * FIXME: Also free the swap page.
2189 MmLockAddressSpace(AddressSpace
);
2190 if (Context
.Private
)
2192 Status
= MmCreateVirtualMapping(Process
,
2194 MemoryArea
->Protect
,
2197 MmSetDirtyPage(Process
, Address
);
2204 Status
= MmCreateVirtualMapping(Process
,
2206 MemoryArea
->Protect
,
2209 MmSetDirtyPage(Process
, Address
);
2213 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2214 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2216 MmUnlockAddressSpace(AddressSpace
);
2217 MiSetPageEvent(NULL
, NULL
);
2218 return(STATUS_UNSUCCESSFUL
);
2222 * Otherwise we have succeeded.
2224 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2225 MmSetSavedSwapEntryPage(Page
, 0);
2226 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2227 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2229 MmLockSectionSegment(Context
.Segment
);
2230 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2231 MmUnlockSectionSegment(Context
.Segment
);
2235 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2238 if (Context
.Private
)
2240 MmLockAddressSpace(AddressSpace
);
2241 MmLockSectionSegment(Context
.Segment
);
2242 Status
= MmCreatePageFileMapping(Process
,
2245 /* We had placed a wait entry upon entry ... replace it before leaving */
2246 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2247 MmUnlockSectionSegment(Context
.Segment
);
2248 MmUnlockAddressSpace(AddressSpace
);
2249 if (!NT_SUCCESS(Status
))
2251 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2252 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2257 MmLockAddressSpace(AddressSpace
);
2258 MmLockSectionSegment(Context
.Segment
);
2259 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2260 /* We had placed a wait entry upon entry ... replace it before leaving */
2261 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2262 MmUnlockSectionSegment(Context
.Segment
);
2263 MmUnlockAddressSpace(AddressSpace
);
2266 MiSetPageEvent(NULL
, NULL
);
2267 return(STATUS_SUCCESS
);
2272 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2273 PMEMORY_AREA MemoryArea
,
2277 LARGE_INTEGER Offset
;
2278 PROS_SECTION_OBJECT Section
;
2279 PMM_SECTION_SEGMENT Segment
;
2281 SWAPENTRY SwapEntry
;
2285 PFILE_OBJECT FileObject
;
2286 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2287 BOOLEAN DirectMapped
;
2288 BOOLEAN IsImageSection
;
2289 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2291 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2293 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2294 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2297 * Get the segment and section.
2299 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2300 Section
= MemoryArea
->Data
.SectionData
.Section
;
2301 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2303 FileObject
= Section
->FileObject
;
2304 DirectMapped
= FALSE
;
2305 if (FileObject
!= NULL
&&
2306 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2308 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2311 * If the file system is letting us go directly to the cache and the
2312 * memory area was mapped at an offset in the file which is page aligned
2313 * then note this is a direct mapped page.
2315 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2316 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2318 DirectMapped
= TRUE
;
2323 * This should never happen since mappings of physical memory are never
2324 * placed in the rmap lists.
2326 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2328 DPRINT1("Trying to write back page from physical memory mapped at %p "
2329 "process %p\n", Address
,
2330 Process
? Process
->UniqueProcessId
: 0);
2331 KeBugCheck(MEMORY_MANAGEMENT
);
2335 * Get the section segment entry and the physical address.
2337 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2338 if (!MmIsPagePresent(Process
, Address
))
2340 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2341 Process
? Process
->UniqueProcessId
: 0, Address
);
2342 KeBugCheck(MEMORY_MANAGEMENT
);
2344 Page
= MmGetPfnForProcess(Process
, Address
);
2345 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2348 * Check for a private (COWed) page.
2350 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2351 IS_SWAP_FROM_SSE(Entry
) ||
2352 PFN_FROM_SSE(Entry
) != Page
)
2362 * Speculatively set all mappings of the page to clean.
2364 MmSetCleanAllRmaps(Page
);
2367 * If this page was direct mapped from the cache then the cache manager
2368 * will take care of writing it back to disk.
2370 if (DirectMapped
&& !Private
)
2372 //LARGE_INTEGER SOffset;
2373 ASSERT(SwapEntry
== 0);
2374 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2376 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
);
2378 MmLockSectionSegment(Segment
);
2379 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2380 MmUnlockSectionSegment(Segment
);
2381 MiSetPageEvent(NULL
, NULL
);
2382 return(STATUS_SUCCESS
);
2386 * If necessary, allocate an entry in the paging file for this page
2390 SwapEntry
= MmAllocSwapPage();
2393 MmSetDirtyAllRmaps(Page
);
2394 MiSetPageEvent(NULL
, NULL
);
2395 return(STATUS_PAGEFILE_QUOTA
);
2397 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2401 * Write the page to the pagefile
2403 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2404 if (!NT_SUCCESS(Status
))
2406 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2408 MmSetDirtyAllRmaps(Page
);
2409 MiSetPageEvent(NULL
, NULL
);
2410 return(STATUS_UNSUCCESSFUL
);
2414 * Otherwise we have succeeded.
2416 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2417 MiSetPageEvent(NULL
, NULL
);
2418 return(STATUS_SUCCESS
);
2422 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2430 PMEMORY_AREA MemoryArea
;
2431 PMM_SECTION_SEGMENT Segment
;
2432 BOOLEAN DoCOW
= FALSE
;
2434 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2436 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2437 ASSERT(MemoryArea
!= NULL
);
2438 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2439 MmLockSectionSegment(Segment
);
2441 if ((Segment
->WriteCopy
) &&
2442 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2447 if (OldProtect
!= NewProtect
)
2449 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2451 SWAPENTRY SwapEntry
;
2452 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2453 ULONG Protect
= NewProtect
;
2455 /* Wait for a wait entry to disappear */
2457 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2458 if (SwapEntry
!= MM_WAIT_ENTRY
)
2460 MiWaitForPageEvent(Process
, Address
);
2464 * If we doing COW for this segment then check if the page is
2467 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2469 LARGE_INTEGER Offset
;
2473 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2474 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2475 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2477 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2478 * IS_SWAP_FROM_SSE and we'll do the right thing.
2480 Page
= MmGetPfnForProcess(Process
, Address
);
2482 Protect
= PAGE_READONLY
;
2483 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2484 IS_SWAP_FROM_SSE(Entry
) ||
2485 PFN_FROM_SSE(Entry
) != Page
)
2487 Protect
= NewProtect
;
2491 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2493 MmSetPageProtect(Process
, Address
,
2499 MmUnlockSectionSegment(Segment
);
2504 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2505 PMEMORY_AREA MemoryArea
,
2513 ULONG_PTR MaxLength
;
2515 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2516 if (Length
> MaxLength
)
2517 Length
= (ULONG
)MaxLength
;
2519 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2520 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2522 ASSERT(Region
!= NULL
);
2524 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2525 Region
->Protect
!= Protect
)
2527 return STATUS_INVALID_PAGE_PROTECTION
;
2530 *OldProtect
= Region
->Protect
;
2531 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2532 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2533 BaseAddress
, Length
, Region
->Type
, Protect
,
2534 MmAlterViewAttributes
);
2540 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2542 PMEMORY_BASIC_INFORMATION Info
,
2543 PSIZE_T ResultLength
)
2546 PVOID RegionBaseAddress
;
2547 PROS_SECTION_OBJECT Section
;
2548 PMM_SECTION_SEGMENT Segment
;
2550 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2551 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2552 Address
, &RegionBaseAddress
);
2555 return STATUS_UNSUCCESSFUL
;
2558 Section
= MemoryArea
->Data
.SectionData
.Section
;
2559 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2561 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2562 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2563 Info
->Type
= MEM_IMAGE
;
2567 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2568 Info
->Type
= MEM_MAPPED
;
2570 Info
->BaseAddress
= RegionBaseAddress
;
2571 Info
->AllocationProtect
= MemoryArea
->Protect
;
2572 Info
->RegionSize
= Region
->Length
;
2573 Info
->State
= MEM_COMMIT
;
2574 Info
->Protect
= Region
->Protect
;
2576 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2577 return(STATUS_SUCCESS
);
2582 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2585 LARGE_INTEGER Offset
;
2587 SWAPENTRY SavedSwapEntry
;
2592 MmLockSectionSegment(Segment
);
2594 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2595 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2597 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2600 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2601 if (IS_SWAP_FROM_SSE(Entry
))
2603 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2607 Page
= PFN_FROM_SSE(Entry
);
2608 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2609 if (SavedSwapEntry
!= 0)
2611 MmSetSavedSwapEntryPage(Page
, 0);
2612 MmFreeSwapPage(SavedSwapEntry
);
2614 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2619 MmUnlockSectionSegment(Segment
);
2623 MmpDeleteSection(PVOID ObjectBody
)
2625 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2627 /* Check if it's an ARM3, or ReactOS section */
2628 if (!MiIsRosSectionObject(Section
))
2630 MiDeleteARM3Section(ObjectBody
);
2634 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2635 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2640 PMM_SECTION_SEGMENT SectionSegments
;
2643 * NOTE: Section->ImageSection can be NULL for short time
2644 * during the section creating. If we fail for some reason
2645 * until the image section is properly initialized we shouldn't
2646 * process further here.
2648 if (Section
->ImageSection
== NULL
)
2651 SectionSegments
= Section
->ImageSection
->Segments
;
2652 NrSegments
= Section
->ImageSection
->NrSegments
;
2654 for (i
= 0; i
< NrSegments
; i
++)
2656 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2658 MmLockSectionSegment(&SectionSegments
[i
]);
2660 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2661 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2663 MmUnlockSectionSegment(&SectionSegments
[i
]);
2666 MmpFreePageFileSegment(&SectionSegments
[i
]);
2672 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2675 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2678 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2680 DPRINT("Freeing section segment\n");
2681 Section
->Segment
= NULL
;
2682 MmFinalizeSegment(Segment
);
2686 DPRINT("RefCount %d\n", RefCount
);
2693 * NOTE: Section->Segment can be NULL for short time
2694 * during the section creating.
2696 if (Section
->Segment
== NULL
)
2699 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2701 MmpFreePageFileSegment(Section
->Segment
);
2702 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2703 ExFreePool(Section
->Segment
);
2704 Section
->Segment
= NULL
;
2708 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2711 if (Section
->FileObject
!= NULL
)
2714 CcRosDereferenceCache(Section
->FileObject
);
2716 ObDereferenceObject(Section
->FileObject
);
2717 Section
->FileObject
= NULL
;
2722 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2724 IN ACCESS_MASK GrantedAccess
,
2725 IN ULONG ProcessHandleCount
,
2726 IN ULONG SystemHandleCount
)
2728 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2734 MmCreatePhysicalMemorySection(VOID
)
2736 PROS_SECTION_OBJECT PhysSection
;
2738 OBJECT_ATTRIBUTES Obj
;
2739 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2740 LARGE_INTEGER SectionSize
;
2744 * Create the section mapping physical memory
2746 SectionSize
.QuadPart
= 0xFFFFFFFF;
2747 InitializeObjectAttributes(&Obj
,
2752 Status
= MmCreateSection((PVOID
)&PhysSection
,
2756 PAGE_EXECUTE_READWRITE
,
2760 if (!NT_SUCCESS(Status
))
2762 DPRINT1("Failed to create PhysicalMemory section\n");
2763 KeBugCheck(MEMORY_MANAGEMENT
);
2765 Status
= ObInsertObject(PhysSection
,
2771 if (!NT_SUCCESS(Status
))
2773 ObDereferenceObject(PhysSection
);
2775 ObCloseHandle(Handle
, KernelMode
);
2776 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2777 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2779 return(STATUS_SUCCESS
);
2785 MmInitSectionImplementation(VOID
)
2787 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2788 UNICODE_STRING Name
;
2790 DPRINT("Creating Section Object Type\n");
2792 /* Initialize the section based root */
2793 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2794 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2796 /* Initialize the Section object type */
2797 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2798 RtlInitUnicodeString(&Name
, L
"Section");
2799 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2800 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2801 ObjectTypeInitializer
.PoolType
= PagedPool
;
2802 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2803 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2804 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2805 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2806 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2807 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2808 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2810 MmCreatePhysicalMemorySection();
2812 return(STATUS_SUCCESS
);
2817 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2818 ACCESS_MASK DesiredAccess
,
2819 POBJECT_ATTRIBUTES ObjectAttributes
,
2820 PLARGE_INTEGER UMaximumSize
,
2821 ULONG SectionPageProtection
,
2822 ULONG AllocationAttributes
)
2824 * Create a section which is backed by the pagefile
2827 LARGE_INTEGER MaximumSize
;
2828 PROS_SECTION_OBJECT Section
;
2829 PMM_SECTION_SEGMENT Segment
;
2832 if (UMaximumSize
== NULL
)
2834 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2835 return(STATUS_INVALID_PARAMETER
);
2837 MaximumSize
= *UMaximumSize
;
2840 * Create the section
2842 Status
= ObCreateObject(ExGetPreviousMode(),
2843 MmSectionObjectType
,
2845 ExGetPreviousMode(),
2847 sizeof(ROS_SECTION_OBJECT
),
2850 (PVOID
*)(PVOID
)&Section
);
2851 if (!NT_SUCCESS(Status
))
2853 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2860 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2861 Section
->Type
= 'SC';
2862 Section
->Size
= 'TN';
2863 Section
->SectionPageProtection
= SectionPageProtection
;
2864 Section
->AllocationAttributes
= AllocationAttributes
;
2865 Section
->MaximumSize
= MaximumSize
;
2866 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2867 TAG_MM_SECTION_SEGMENT
);
2868 if (Segment
== NULL
)
2870 ObDereferenceObject(Section
);
2871 return(STATUS_NO_MEMORY
);
2873 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2874 Section
->Segment
= Segment
;
2875 Segment
->ReferenceCount
= 1;
2876 ExInitializeFastMutex(&Segment
->Lock
);
2877 Segment
->Image
.FileOffset
= 0;
2878 Segment
->Protection
= SectionPageProtection
;
2879 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2880 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2881 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2882 Segment
->WriteCopy
= FALSE
;
2883 Segment
->Image
.VirtualAddress
= 0;
2884 Segment
->Image
.Characteristics
= 0;
2885 *SectionObject
= Section
;
2886 MiInitializeSectionPageTable(Segment
);
2887 return(STATUS_SUCCESS
);
2892 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2893 ACCESS_MASK DesiredAccess
,
2894 POBJECT_ATTRIBUTES ObjectAttributes
,
2895 PLARGE_INTEGER UMaximumSize
,
2896 ULONG SectionPageProtection
,
2897 ULONG AllocationAttributes
,
2900 * Create a section backed by a data file
2903 PROS_SECTION_OBJECT Section
;
2905 LARGE_INTEGER MaximumSize
;
2906 PFILE_OBJECT FileObject
;
2907 PMM_SECTION_SEGMENT Segment
;
2909 IO_STATUS_BLOCK Iosb
;
2910 LARGE_INTEGER Offset
;
2912 FILE_STANDARD_INFORMATION FileInfo
;
2916 * Create the section
2918 Status
= ObCreateObject(ExGetPreviousMode(),
2919 MmSectionObjectType
,
2921 ExGetPreviousMode(),
2923 sizeof(ROS_SECTION_OBJECT
),
2927 if (!NT_SUCCESS(Status
))
2934 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2935 Section
->Type
= 'SC';
2936 Section
->Size
= 'TN';
2937 Section
->SectionPageProtection
= SectionPageProtection
;
2938 Section
->AllocationAttributes
= AllocationAttributes
;
2941 * Reference the file handle
2943 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2944 Status
= ObReferenceObjectByHandle(FileHandle
,
2947 ExGetPreviousMode(),
2948 (PVOID
*)(PVOID
)&FileObject
,
2950 if (!NT_SUCCESS(Status
))
2952 ObDereferenceObject(Section
);
2957 * FIXME: This is propably not entirely correct. We can't look into
2958 * the standard FCB header because it might not be initialized yet
2959 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2960 * standard file information is filled on first request).
2962 Status
= IoQueryFileInformation(FileObject
,
2963 FileStandardInformation
,
2964 sizeof(FILE_STANDARD_INFORMATION
),
2967 Iosb
.Information
= Length
;
2968 if (!NT_SUCCESS(Status
))
2970 ObDereferenceObject(Section
);
2971 ObDereferenceObject(FileObject
);
2976 * FIXME: Revise this once a locking order for file size changes is
2979 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2981 MaximumSize
= *UMaximumSize
;
2985 MaximumSize
= FileInfo
.EndOfFile
;
2986 /* Mapping zero-sized files isn't allowed. */
2987 if (MaximumSize
.QuadPart
== 0)
2989 ObDereferenceObject(Section
);
2990 ObDereferenceObject(FileObject
);
2991 return STATUS_FILE_INVALID
;
2995 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2997 Status
= IoSetInformation(FileObject
,
2998 FileAllocationInformation
,
2999 sizeof(LARGE_INTEGER
),
3001 if (!NT_SUCCESS(Status
))
3003 ObDereferenceObject(Section
);
3004 ObDereferenceObject(FileObject
);
3005 return(STATUS_SECTION_NOT_EXTENDED
);
3009 if (FileObject
->SectionObjectPointer
== NULL
||
3010 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3013 * Read a bit so caching is initiated for the file object.
3014 * This is only needed because MiReadPage currently cannot
3015 * handle non-cached streams.
3017 Offset
.QuadPart
= 0;
3018 Status
= ZwReadFile(FileHandle
,
3027 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3029 ObDereferenceObject(Section
);
3030 ObDereferenceObject(FileObject
);
3033 if (FileObject
->SectionObjectPointer
== NULL
||
3034 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3036 /* FIXME: handle this situation */
3037 ObDereferenceObject(Section
);
3038 ObDereferenceObject(FileObject
);
3039 return STATUS_INVALID_PARAMETER
;
3046 Status
= MmspWaitForFileLock(FileObject
);
3047 if (Status
!= STATUS_SUCCESS
)
3049 ObDereferenceObject(Section
);
3050 ObDereferenceObject(FileObject
);
3055 * If this file hasn't been mapped as a data file before then allocate a
3056 * section segment to describe the data file mapping
3058 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3060 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3061 TAG_MM_SECTION_SEGMENT
);
3062 if (Segment
== NULL
)
3064 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3065 ObDereferenceObject(Section
);
3066 ObDereferenceObject(FileObject
);
3067 return(STATUS_NO_MEMORY
);
3069 Section
->Segment
= Segment
;
3070 Segment
->ReferenceCount
= 1;
3071 ExInitializeFastMutex(&Segment
->Lock
);
3073 * Set the lock before assigning the segment to the file object
3075 ExAcquireFastMutex(&Segment
->Lock
);
3076 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3078 Segment
->Image
.FileOffset
= 0;
3079 Segment
->Protection
= SectionPageProtection
;
3080 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3081 Segment
->Image
.Characteristics
= 0;
3082 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3083 if (AllocationAttributes
& SEC_RESERVE
)
3085 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3089 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3090 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3092 Segment
->Image
.VirtualAddress
= 0;
3093 Segment
->Locked
= TRUE
;
3094 MiInitializeSectionPageTable(Segment
);
3099 * If the file is already mapped as a data file then we may need
3103 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3105 Section
->Segment
= Segment
;
3106 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3107 MmLockSectionSegment(Segment
);
3109 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3110 !(AllocationAttributes
& SEC_RESERVE
))
3112 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3113 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3116 MmUnlockSectionSegment(Segment
);
3117 Section
->FileObject
= FileObject
;
3118 Section
->MaximumSize
= MaximumSize
;
3120 CcRosReferenceCache(FileObject
);
3122 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3123 *SectionObject
= Section
;
3124 return(STATUS_SUCCESS
);
3128 TODO: not that great (declaring loaders statically, having to declare all of
3129 them, having to keep them extern, etc.), will fix in the future
3131 extern NTSTATUS NTAPI PeFmtCreateSection
3133 IN CONST VOID
* FileHeader
,
3134 IN SIZE_T FileHeaderSize
,
3136 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3138 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3139 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3142 extern NTSTATUS NTAPI ElfFmtCreateSection
3144 IN CONST VOID
* FileHeader
,
3145 IN SIZE_T FileHeaderSize
,
3147 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3149 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3150 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3153 /* TODO: this is a standard DDK/PSDK macro */
3154 #ifndef RTL_NUMBER_OF
3155 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3158 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3169 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3171 SIZE_T SizeOfSegments
;
3172 PMM_SECTION_SEGMENT Segments
;
3174 /* TODO: check for integer overflow */
3175 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3177 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3179 TAG_MM_SECTION_SEGMENT
);
3182 RtlZeroMemory(Segments
, SizeOfSegments
);
3190 ExeFmtpReadFile(IN PVOID File
,
3191 IN PLARGE_INTEGER Offset
,
3194 OUT PVOID
* AllocBase
,
3195 OUT PULONG ReadSize
)
3198 LARGE_INTEGER FileOffset
;
3200 ULONG OffsetAdjustment
;
3204 PFILE_OBJECT FileObject
= File
;
3205 IO_STATUS_BLOCK Iosb
;
3207 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3211 KeBugCheck(MEMORY_MANAGEMENT
);
3214 FileOffset
= *Offset
;
3216 /* Negative/special offset: it cannot be used in this context */
3217 if(FileOffset
.u
.HighPart
< 0)
3219 KeBugCheck(MEMORY_MANAGEMENT
);
3222 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3223 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3224 FileOffset
.u
.LowPart
= AdjustOffset
;
3226 BufferSize
= Length
+ OffsetAdjustment
;
3227 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3230 * It's ok to use paged pool, because this is a temporary buffer only used in
3231 * the loading of executables. The assumption is that MmCreateSection is
3232 * always called at low IRQLs and that these buffers don't survive a brief
3233 * initialization phase
3235 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3240 KeBugCheck(MEMORY_MANAGEMENT
);
3245 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3247 UsedSize
= (ULONG
)Iosb
.Information
;
3249 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3251 Status
= STATUS_IN_PAGE_ERROR
;
3252 ASSERT(!NT_SUCCESS(Status
));
3255 if(NT_SUCCESS(Status
))
3257 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3258 *AllocBase
= Buffer
;
3259 *ReadSize
= UsedSize
- OffsetAdjustment
;
3263 ExFreePoolWithTag(Buffer
, 'rXmM');
3270 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3271 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3272 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3277 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3281 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3283 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3284 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3291 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3295 MmspAssertSegmentsSorted(ImageSectionObject
);
3297 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3299 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3303 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3304 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3305 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3313 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3317 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3319 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3320 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3328 MmspCompareSegments(const void * x
,
3331 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3332 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3335 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3336 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3340 * Ensures an image section's segments are sorted in memory
3345 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3348 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3350 MmspAssertSegmentsSorted(ImageSectionObject
);
3354 qsort(ImageSectionObject
->Segments
,
3355 ImageSectionObject
->NrSegments
,
3356 sizeof(ImageSectionObject
->Segments
[0]),
3357 MmspCompareSegments
);
3363 * Ensures an image section's segments don't overlap in memory and don't have
3364 * gaps and don't have a null size. We let them map to overlapping file regions,
3365 * though - that's not necessarily an error
3370 MmspCheckSegmentBounds
3372 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3378 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3380 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3384 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3386 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3388 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3396 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3397 * page could be OK (Windows seems to be OK with them), and larger gaps
3398 * could lead to image sections spanning several discontiguous regions
3399 * (NtMapViewOfSection could then refuse to map them, and they could
3400 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3402 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3403 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3404 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3415 * Merges and pads an image section's segments until they all are page-aligned
3416 * and have a size that is a multiple of the page size
3421 MmspPageAlignSegments
3423 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3429 PMM_SECTION_SEGMENT EffectiveSegment
;
3431 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3433 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3438 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3440 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3443 * The first segment requires special handling
3447 ULONG_PTR VirtualAddress
;
3448 ULONG_PTR VirtualOffset
;
3450 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3452 /* Round down the virtual address to the nearest page */
3453 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3455 /* Round up the virtual size to the nearest page */
3456 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3457 EffectiveSegment
->Image
.VirtualAddress
;
3459 /* Adjust the raw address and size */
3460 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3462 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3468 * Garbage in, garbage out: unaligned base addresses make the file
3469 * offset point in curious and odd places, but that's what we were
3472 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3473 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3477 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3478 ULONG_PTR EndOfEffectiveSegment
;
3480 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3481 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3484 * The current segment begins exactly where the current effective
3485 * segment ended, therefore beginning a new effective segment
3487 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3490 ASSERT(LastSegment
<= i
);
3491 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3493 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3495 if (LastSegment
!= i
)
3498 * Copy the current segment. If necessary, the effective segment
3499 * will be expanded later
3501 *EffectiveSegment
= *Segment
;
3505 * Page-align the virtual size. We know for sure the virtual address
3508 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3509 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3512 * The current segment is still part of the current effective segment:
3513 * extend the effective segment to reflect this
3515 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3517 static const ULONG FlagsToProtection
[16] =
3525 PAGE_EXECUTE_READWRITE
,
3526 PAGE_EXECUTE_READWRITE
,
3531 PAGE_EXECUTE_WRITECOPY
,
3532 PAGE_EXECUTE_WRITECOPY
,
3533 PAGE_EXECUTE_WRITECOPY
,
3534 PAGE_EXECUTE_WRITECOPY
3537 unsigned ProtectionFlags
;
3540 * Extend the file size
3543 /* Unaligned segments must be contiguous within the file */
3544 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3545 EffectiveSegment
->RawLength
.QuadPart
))
3550 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3553 * Extend the virtual size
3555 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3557 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3558 EffectiveSegment
->Image
.VirtualAddress
;
3561 * Merge the protection
3563 EffectiveSegment
->Protection
|= Segment
->Protection
;
3565 /* Clean up redundance */
3566 ProtectionFlags
= 0;
3568 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3569 ProtectionFlags
|= 1 << 0;
3571 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3572 ProtectionFlags
|= 1 << 1;
3574 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3575 ProtectionFlags
|= 1 << 2;
3577 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3578 ProtectionFlags
|= 1 << 3;
3580 ASSERT(ProtectionFlags
< 16);
3581 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3583 /* If a segment was required to be shared and cannot, fail */
3584 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3585 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3591 * We assume no holes between segments at this point
3595 KeBugCheck(MEMORY_MANAGEMENT
);
3599 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3605 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3606 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3608 LARGE_INTEGER Offset
;
3610 PVOID FileHeaderBuffer
;
3611 ULONG FileHeaderSize
;
3613 ULONG OldNrSegments
;
3618 * Read the beginning of the file (2 pages). Should be enough to contain
3619 * all (or most) of the headers
3621 Offset
.QuadPart
= 0;
3623 /* FIXME: use FileObject instead of FileHandle */
3624 Status
= ExeFmtpReadFile (FileHandle
,
3631 if (!NT_SUCCESS(Status
))
3634 if (FileHeaderSize
== 0)
3636 ExFreePool(FileHeaderBuffer
);
3637 return STATUS_UNSUCCESSFUL
;
3641 * Look for a loader that can handle this executable
3643 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3645 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3648 /* FIXME: use FileObject instead of FileHandle */
3649 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3655 ExeFmtpAllocateSegments
);
3657 if (!NT_SUCCESS(Status
))
3659 if (ImageSectionObject
->Segments
)
3661 ExFreePool(ImageSectionObject
->Segments
);
3662 ImageSectionObject
->Segments
= NULL
;
3666 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3670 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3673 * No loader handled the format
3675 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3677 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3678 ASSERT(!NT_SUCCESS(Status
));
3681 if (!NT_SUCCESS(Status
))
3684 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3689 /* FIXME? are these values platform-dependent? */
3690 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3691 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3693 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3694 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3696 if(ImageSectionObject
->BasedAddress
== NULL
)
3698 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3699 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3701 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3705 * And now the fun part: fixing the segments
3708 /* Sort them by virtual address */
3709 MmspSortSegments(ImageSectionObject
, Flags
);
3711 /* Ensure they don't overlap in memory */
3712 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3713 return STATUS_INVALID_IMAGE_FORMAT
;
3715 /* Ensure they are aligned */
3716 OldNrSegments
= ImageSectionObject
->NrSegments
;
3718 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3719 return STATUS_INVALID_IMAGE_FORMAT
;
3721 /* Trim them if the alignment phase merged some of them */
3722 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3724 PMM_SECTION_SEGMENT Segments
;
3725 SIZE_T SizeOfSegments
;
3727 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3729 Segments
= ExAllocatePoolWithTag(PagedPool
,
3731 TAG_MM_SECTION_SEGMENT
);
3733 if (Segments
== NULL
)
3734 return STATUS_INSUFFICIENT_RESOURCES
;
3736 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3737 ExFreePool(ImageSectionObject
->Segments
);
3738 ImageSectionObject
->Segments
= Segments
;
3741 /* And finish their initialization */
3742 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3744 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3745 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3746 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3749 ASSERT(NT_SUCCESS(Status
));
3754 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3755 ACCESS_MASK DesiredAccess
,
3756 POBJECT_ATTRIBUTES ObjectAttributes
,
3757 PLARGE_INTEGER UMaximumSize
,
3758 ULONG SectionPageProtection
,
3759 ULONG AllocationAttributes
,
3760 PFILE_OBJECT FileObject
)
3762 PROS_SECTION_OBJECT Section
;
3764 PMM_SECTION_SEGMENT SectionSegments
;
3765 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3768 if (FileObject
== NULL
)
3769 return STATUS_INVALID_FILE_FOR_SECTION
;
3772 * Create the section
3774 Status
= ObCreateObject (ExGetPreviousMode(),
3775 MmSectionObjectType
,
3777 ExGetPreviousMode(),
3779 sizeof(ROS_SECTION_OBJECT
),
3782 (PVOID
*)(PVOID
)&Section
);
3783 if (!NT_SUCCESS(Status
))
3785 ObDereferenceObject(FileObject
);
3792 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3793 Section
->Type
= 'SC';
3794 Section
->Size
= 'TN';
3795 Section
->SectionPageProtection
= SectionPageProtection
;
3796 Section
->AllocationAttributes
= AllocationAttributes
;
3800 * Initialized caching for this file object if previously caching
3801 * was initialized for the same on disk file
3803 Status
= CcTryToInitializeFileCache(FileObject
);
3805 Status
= STATUS_SUCCESS
;
3808 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3810 NTSTATUS StatusExeFmt
;
3812 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3813 if (ImageSectionObject
== NULL
)
3815 ObDereferenceObject(FileObject
);
3816 ObDereferenceObject(Section
);
3817 return(STATUS_NO_MEMORY
);
3820 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3822 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3824 if (!NT_SUCCESS(StatusExeFmt
))
3826 if(ImageSectionObject
->Segments
!= NULL
)
3827 ExFreePool(ImageSectionObject
->Segments
);
3829 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3830 ObDereferenceObject(Section
);
3831 ObDereferenceObject(FileObject
);
3832 return(StatusExeFmt
);
3835 Section
->ImageSection
= ImageSectionObject
;
3836 ASSERT(ImageSectionObject
->Segments
);
3841 Status
= MmspWaitForFileLock(FileObject
);
3842 if (!NT_SUCCESS(Status
))
3844 ExFreePool(ImageSectionObject
->Segments
);
3845 ExFreePool(ImageSectionObject
);
3846 ObDereferenceObject(Section
);
3847 ObDereferenceObject(FileObject
);
3851 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3852 ImageSectionObject
, NULL
))
3855 * An other thread has initialized the same image in the background
3857 ExFreePool(ImageSectionObject
->Segments
);
3858 ExFreePool(ImageSectionObject
);
3859 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3860 Section
->ImageSection
= ImageSectionObject
;
3861 SectionSegments
= ImageSectionObject
->Segments
;
3863 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3865 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3869 Status
= StatusExeFmt
;
3876 Status
= MmspWaitForFileLock(FileObject
);
3877 if (Status
!= STATUS_SUCCESS
)
3879 ObDereferenceObject(Section
);
3880 ObDereferenceObject(FileObject
);
3884 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3885 Section
->ImageSection
= ImageSectionObject
;
3886 SectionSegments
= ImageSectionObject
->Segments
;
3889 * Otherwise just reference all the section segments
3891 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3893 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3896 Status
= STATUS_SUCCESS
;
3898 Section
->FileObject
= FileObject
;
3900 CcRosReferenceCache(FileObject
);
3902 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3903 *SectionObject
= Section
;
3910 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3911 PROS_SECTION_OBJECT Section
,
3912 PMM_SECTION_SEGMENT Segment
,
3917 ULONG AllocationType
)
3923 if (Segment
->WriteCopy
)
3925 /* We have to do this because the not present fault
3926 * and access fault handlers depend on the protection
3927 * that should be granted AFTER the COW fault takes
3928 * place to be in Region->Protect. The not present fault
3929 * handler changes this to the correct protection for COW when
3930 * mapping the pages into the process's address space. If a COW
3931 * fault takes place, the access fault handler sets the page protection
3932 * to these values for the newly copied pages
3934 if (Protect
== PAGE_WRITECOPY
)
3935 Protect
= PAGE_READWRITE
;
3936 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3937 Protect
= PAGE_EXECUTE_READWRITE
;
3940 if (*BaseAddress
== NULL
)
3941 Granularity
= MM_ALLOCATION_GRANULARITY
;
3943 Granularity
= PAGE_SIZE
;
3946 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
3947 LARGE_INTEGER FileOffset
;
3948 FileOffset
.QuadPart
= ViewOffset
;
3949 ObReferenceObject(Section
);
3950 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3953 Status
= MmCreateMemoryArea(AddressSpace
,
3954 MEMORY_AREA_SECTION_VIEW
,
3962 if (!NT_SUCCESS(Status
))
3964 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3965 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3969 ObReferenceObject((PVOID
)Section
);
3971 MArea
->Data
.SectionData
.Segment
= Segment
;
3972 MArea
->Data
.SectionData
.Section
= Section
;
3973 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3974 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3975 ViewSize
, 0, Protect
);
3977 return(STATUS_SUCCESS
);
3982 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3983 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3986 PFILE_OBJECT FileObject
;
3987 PROS_SHARED_CACHE_MAP SharedCacheMap
;
3988 LARGE_INTEGER Offset
;
3989 SWAPENTRY SavedSwapEntry
;
3990 PROS_SECTION_OBJECT Section
;
3991 PMM_SECTION_SEGMENT Segment
;
3992 PMMSUPPORT AddressSpace
;
3995 AddressSpace
= (PMMSUPPORT
)Context
;
3996 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3998 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4000 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
4001 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
4003 Section
= MemoryArea
->Data
.SectionData
.Section
;
4004 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4006 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4007 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
4009 MmUnlockSectionSegment(Segment
);
4010 MmUnlockAddressSpace(AddressSpace
);
4012 MiWaitForPageEvent(NULL
, NULL
);
4014 MmLockAddressSpace(AddressSpace
);
4015 MmLockSectionSegment(Segment
);
4016 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4020 * For a dirty, datafile, non-private page mark it as dirty in the
4023 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4025 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4027 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4028 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4030 CcRosMarkDirtyVacb(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4032 ASSERT(SwapEntry
== 0);
4041 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4043 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4044 KeBugCheck(MEMORY_MANAGEMENT
);
4046 MmFreeSwapPage(SwapEntry
);
4050 if (IS_SWAP_FROM_SSE(Entry
) ||
4051 Page
!= PFN_FROM_SSE(Entry
))
4056 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4058 DPRINT1("Found a private page in a pagefile section.\n");
4059 KeBugCheck(MEMORY_MANAGEMENT
);
4062 * Just dereference private pages
4064 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4065 if (SavedSwapEntry
!= 0)
4067 MmFreeSwapPage(SavedSwapEntry
);
4068 MmSetSavedSwapEntryPage(Page
, 0);
4070 MmDeleteRmap(Page
, Process
, Address
);
4071 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4075 MmDeleteRmap(Page
, Process
, Address
);
4076 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4082 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4086 PMEMORY_AREA MemoryArea
;
4087 PROS_SECTION_OBJECT Section
;
4088 PMM_SECTION_SEGMENT Segment
;
4089 PLIST_ENTRY CurrentEntry
;
4090 PMM_REGION CurrentRegion
;
4091 PLIST_ENTRY RegionListHead
;
4093 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4095 if (MemoryArea
== NULL
)
4097 return(STATUS_UNSUCCESSFUL
);
4100 Section
= MemoryArea
->Data
.SectionData
.Section
;
4101 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4104 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4106 MmUnlockAddressSpace(AddressSpace
);
4107 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4108 MmLockAddressSpace(AddressSpace
);
4114 MemoryArea
->DeleteInProgress
= TRUE
;
4116 MmLockSectionSegment(Segment
);
4118 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4119 while (!IsListEmpty(RegionListHead
))
4121 CurrentEntry
= RemoveHeadList(RegionListHead
);
4122 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4123 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4126 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4128 Status
= MmFreeMemoryArea(AddressSpace
,
4135 Status
= MmFreeMemoryArea(AddressSpace
,
4140 MmUnlockSectionSegment(Segment
);
4141 ObDereferenceObject(Section
);
4147 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4148 IN PVOID BaseAddress
,
4152 PMEMORY_AREA MemoryArea
;
4153 PMMSUPPORT AddressSpace
;
4154 PROS_SECTION_OBJECT Section
;
4155 PVOID ImageBaseAddress
= 0;
4157 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4158 Process
, BaseAddress
);
4162 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4164 MmLockAddressSpace(AddressSpace
);
4165 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4167 if (MemoryArea
== NULL
||
4168 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4169 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4170 MemoryArea
->DeleteInProgress
)
4172 if (MemoryArea
) NT_ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4173 MmUnlockAddressSpace(AddressSpace
);
4174 return STATUS_NOT_MAPPED_VIEW
;
4177 Section
= MemoryArea
->Data
.SectionData
.Section
;
4179 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4183 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4184 PMM_SECTION_SEGMENT SectionSegments
;
4185 PMM_SECTION_SEGMENT Segment
;
4187 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4188 ImageSectionObject
= Section
->ImageSection
;
4189 SectionSegments
= ImageSectionObject
->Segments
;
4190 NrSegments
= ImageSectionObject
->NrSegments
;
4192 MemoryArea
->DeleteInProgress
= TRUE
;
4194 /* Search for the current segment within the section segments
4195 * and calculate the image base address */
4196 for (i
= 0; i
< NrSegments
; i
++)
4198 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4200 if (Segment
== &SectionSegments
[i
])
4202 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4207 if (i
>= NrSegments
)
4209 KeBugCheck(MEMORY_MANAGEMENT
);
4212 for (i
= 0; i
< NrSegments
; i
++)
4214 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4216 PVOID SBaseAddress
= (PVOID
)
4217 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4219 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4220 NT_ASSERT(NT_SUCCESS(Status
));
4226 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4227 NT_ASSERT(NT_SUCCESS(Status
));
4230 MmUnlockAddressSpace(AddressSpace
);
4232 /* Notify debugger */
4233 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4235 return(STATUS_SUCCESS
);
4242 * Queries the information of a section object.
4244 * @param SectionHandle
4245 * Handle to the section object. It must be opened with SECTION_QUERY
4247 * @param SectionInformationClass
4248 * Index to a certain information structure. Can be either
4249 * SectionBasicInformation or SectionImageInformation. The latter
4250 * is valid only for sections that were created with the SEC_IMAGE
4252 * @param SectionInformation
4253 * Caller supplies storage for resulting information.
4255 * Size of the supplied storage.
4256 * @param ResultLength
4264 NtQuerySection(IN HANDLE SectionHandle
,
4265 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4266 OUT PVOID SectionInformation
,
4267 IN SIZE_T SectionInformationLength
,
4268 OUT PSIZE_T ResultLength OPTIONAL
)
4270 PROS_SECTION_OBJECT Section
;
4271 KPROCESSOR_MODE PreviousMode
;
4275 PreviousMode
= ExGetPreviousMode();
4277 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4279 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4281 (ULONG
)SectionInformationLength
,
4286 if(!NT_SUCCESS(Status
))
4288 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4292 Status
= ObReferenceObjectByHandle(SectionHandle
,
4294 MmSectionObjectType
,
4296 (PVOID
*)(PVOID
)&Section
,
4298 if (NT_SUCCESS(Status
))
4300 switch (SectionInformationClass
)
4302 case SectionBasicInformation
:
4304 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4308 Sbi
->Attributes
= Section
->AllocationAttributes
;
4309 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4311 Sbi
->BaseAddress
= 0;
4312 Sbi
->Size
.QuadPart
= 0;
4316 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4317 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4320 if (ResultLength
!= NULL
)
4322 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4324 Status
= STATUS_SUCCESS
;
4326 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4328 Status
= _SEH2_GetExceptionCode();
4335 case SectionImageInformation
:
4337 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4341 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4343 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4344 ImageSectionObject
= Section
->ImageSection
;
4346 *Sii
= ImageSectionObject
->ImageInformation
;
4349 if (ResultLength
!= NULL
)
4351 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4353 Status
= STATUS_SUCCESS
;
4355 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4357 Status
= _SEH2_GetExceptionCode();
4365 ObDereferenceObject(Section
);
4371 /**********************************************************************
4373 * MmMapViewOfSection
4376 * Maps a view of a section into the virtual address space of a
4381 * Pointer to the section object.
4384 * Pointer to the process.
4387 * Desired base address (or NULL) on entry;
4388 * Actual base address of the view on exit.
4391 * Number of high order address bits that must be zero.
4394 * Size in bytes of the initially committed section of
4398 * Offset in bytes from the beginning of the section
4399 * to the beginning of the view.
4402 * Desired length of map (or zero to map all) on entry
4403 * Actual length mapped on exit.
4405 * InheritDisposition
4406 * Specified how the view is to be shared with
4410 * Type of allocation for the pages.
4413 * Protection for the committed region of the view.
4421 MmMapViewOfSection(IN PVOID SectionObject
,
4422 IN PEPROCESS Process
,
4423 IN OUT PVOID
*BaseAddress
,
4424 IN ULONG_PTR ZeroBits
,
4425 IN SIZE_T CommitSize
,
4426 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4427 IN OUT PSIZE_T ViewSize
,
4428 IN SECTION_INHERIT InheritDisposition
,
4429 IN ULONG AllocationType
,
4432 PROS_SECTION_OBJECT Section
;
4433 PMMSUPPORT AddressSpace
;
4435 NTSTATUS Status
= STATUS_SUCCESS
;
4436 BOOLEAN NotAtBase
= FALSE
;
4438 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4440 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4441 return MmMapViewOfArm3Section(SectionObject
,
4455 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4457 return STATUS_INVALID_PAGE_PROTECTION
;
4461 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4462 AddressSpace
= &Process
->Vm
;
4464 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4466 MmLockAddressSpace(AddressSpace
);
4468 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4472 ULONG_PTR ImageBase
;
4474 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4475 PMM_SECTION_SEGMENT SectionSegments
;
4477 ImageSectionObject
= Section
->ImageSection
;
4478 SectionSegments
= ImageSectionObject
->Segments
;
4479 NrSegments
= ImageSectionObject
->NrSegments
;
4481 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4484 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4488 for (i
= 0; i
< NrSegments
; i
++)
4490 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4492 ULONG_PTR MaxExtent
;
4493 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4494 SectionSegments
[i
].Length
.QuadPart
);
4495 ImageSize
= max(ImageSize
, MaxExtent
);
4499 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4501 /* Check for an illegal base address */
4502 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4503 ((ImageBase
+ ImageSize
) < ImageSize
))
4505 NT_ASSERT(*BaseAddress
== NULL
);
4506 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4507 MM_VIRTMEM_GRANULARITY
);
4510 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4512 NT_ASSERT(*BaseAddress
== NULL
);
4513 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4517 /* Check there is enough space to map the section at that point. */
4518 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4519 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4521 /* Fail if the user requested a fixed base address. */
4522 if ((*BaseAddress
) != NULL
)
4524 MmUnlockAddressSpace(AddressSpace
);
4525 return(STATUS_CONFLICTING_ADDRESSES
);
4527 /* Otherwise find a gap to map the image. */
4528 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4531 MmUnlockAddressSpace(AddressSpace
);
4532 return(STATUS_CONFLICTING_ADDRESSES
);
4534 /* Remember that we loaded image at a different base address */
4538 for (i
= 0; i
< NrSegments
; i
++)
4540 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4542 PVOID SBaseAddress
= (PVOID
)
4543 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4544 MmLockSectionSegment(&SectionSegments
[i
]);
4545 Status
= MmMapViewOfSegment(AddressSpace
,
4547 &SectionSegments
[i
],
4549 SectionSegments
[i
].Length
.LowPart
,
4550 SectionSegments
[i
].Protection
,
4553 MmUnlockSectionSegment(&SectionSegments
[i
]);
4554 if (!NT_SUCCESS(Status
))
4556 MmUnlockAddressSpace(AddressSpace
);
4562 *BaseAddress
= (PVOID
)ImageBase
;
4563 *ViewSize
= ImageSize
;
4567 /* check for write access */
4568 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4569 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4571 MmUnlockAddressSpace(AddressSpace
);
4572 return STATUS_SECTION_PROTECTION
;
4574 /* check for read access */
4575 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4576 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4578 MmUnlockAddressSpace(AddressSpace
);
4579 return STATUS_SECTION_PROTECTION
;
4581 /* check for execute access */
4582 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4583 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4585 MmUnlockAddressSpace(AddressSpace
);
4586 return STATUS_SECTION_PROTECTION
;
4589 if (ViewSize
== NULL
)
4591 /* Following this pointer would lead to us to the dark side */
4592 /* What to do? Bugcheck? Return status? Do the mambo? */
4593 KeBugCheck(MEMORY_MANAGEMENT
);
4596 if (SectionOffset
== NULL
)
4602 ViewOffset
= SectionOffset
->u
.LowPart
;
4605 if ((ViewOffset
% PAGE_SIZE
) != 0)
4607 MmUnlockAddressSpace(AddressSpace
);
4608 return(STATUS_MAPPED_ALIGNMENT
);
4611 if ((*ViewSize
) == 0)
4613 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4615 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4617 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4620 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4622 MmLockSectionSegment(Section
->Segment
);
4623 Status
= MmMapViewOfSegment(AddressSpace
,
4630 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4631 MmUnlockSectionSegment(Section
->Segment
);
4632 if (!NT_SUCCESS(Status
))
4634 MmUnlockAddressSpace(AddressSpace
);
4639 MmUnlockAddressSpace(AddressSpace
);
4640 NT_ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4643 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4645 Status
= STATUS_SUCCESS
;
4654 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4655 IN PLARGE_INTEGER NewFileSize
)
4657 /* Check whether an ImageSectionObject exists */
4658 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4660 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4664 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4666 PMM_SECTION_SEGMENT Segment
;
4668 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4671 if (Segment
->ReferenceCount
!= 0)
4674 CC_FILE_SIZES FileSizes
;
4676 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4679 /* Check size of file */
4680 if (SectionObjectPointer
->SharedCacheMap
)
4682 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4687 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4696 /* Check size of file */
4697 if (SectionObjectPointer
->SharedCacheMap
)
4699 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4700 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4709 /* Something must gone wrong
4710 * how can we have a Section but no
4712 DPRINT("ERROR: DataSectionObject without reference!\n");
4716 DPRINT("FIXME: didn't check for outstanding write probes\n");
4728 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4729 IN MMFLUSH_TYPE FlushType
)
4731 BOOLEAN Result
= TRUE
;
4733 PMM_SECTION_SEGMENT Segment
;
4738 case MmFlushForDelete
:
4739 if (SectionObjectPointer
->ImageSectionObject
||
4740 SectionObjectPointer
->DataSectionObject
)
4745 CcRosRemoveIfClosed(SectionObjectPointer
);
4748 case MmFlushForWrite
:
4750 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4752 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4755 if (SectionObjectPointer
->ImageSectionObject
) {
4756 DPRINT1("SectionObject has ImageSection\n");
4762 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4764 DPRINT("Result %d\n", Result
);
4776 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4777 OUT PVOID
* MappedBase
,
4778 IN OUT PSIZE_T ViewSize
)
4780 PROS_SECTION_OBJECT Section
;
4781 PMMSUPPORT AddressSpace
;
4785 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4787 return MiMapViewInSystemSpace(SectionObject
,
4793 DPRINT("MmMapViewInSystemSpace() called\n");
4795 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4796 AddressSpace
= MmGetKernelAddressSpace();
4798 MmLockAddressSpace(AddressSpace
);
4801 if ((*ViewSize
) == 0)
4803 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4805 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4807 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4810 MmLockSectionSegment(Section
->Segment
);
4813 Status
= MmMapViewOfSegment(AddressSpace
,
4822 MmUnlockSectionSegment(Section
->Segment
);
4823 MmUnlockAddressSpace(AddressSpace
);
4830 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4832 PMMSUPPORT AddressSpace
;
4835 DPRINT("MmUnmapViewInSystemSpace() called\n");
4837 AddressSpace
= MmGetKernelAddressSpace();
4839 MmLockAddressSpace(AddressSpace
);
4841 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4843 MmUnlockAddressSpace(AddressSpace
);
4848 /**********************************************************************
4853 * Creates a section object.
4856 * SectionObject (OUT)
4857 * Caller supplied storage for the resulting pointer
4858 * to a SECTION_OBJECT instance;
4861 * Specifies the desired access to the section can be a
4863 * STANDARD_RIGHTS_REQUIRED |
4865 * SECTION_MAP_WRITE |
4866 * SECTION_MAP_READ |
4867 * SECTION_MAP_EXECUTE
4869 * ObjectAttributes [OPTIONAL]
4870 * Initialized attributes for the object can be used
4871 * to create a named section;
4874 * Maximizes the size of the memory section. Must be
4875 * non-NULL for a page-file backed section.
4876 * If value specified for a mapped file and the file is
4877 * not large enough, file will be extended.
4879 * SectionPageProtection
4880 * Can be a combination of:
4886 * AllocationAttributes
4887 * Can be a combination of:
4892 * Handle to a file to create a section mapped to a file
4893 * instead of a memory backed section;
4904 MmCreateSection (OUT PVOID
* Section
,
4905 IN ACCESS_MASK DesiredAccess
,
4906 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4907 IN PLARGE_INTEGER MaximumSize
,
4908 IN ULONG SectionPageProtection
,
4909 IN ULONG AllocationAttributes
,
4910 IN HANDLE FileHandle OPTIONAL
,
4911 IN PFILE_OBJECT FileObject OPTIONAL
)
4915 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4917 /* Check if an ARM3 section is being created instead */
4918 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4920 if (!(FileObject
) && !(FileHandle
))
4922 return MmCreateArm3Section(Section
,
4926 SectionPageProtection
,
4927 AllocationAttributes
&~ 1,
4933 /* Convert section flag to page flag */
4934 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4936 /* Check to make sure the protection is correct. Nt* does this already */
4937 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4938 if (Protection
== MM_INVALID_PROTECTION
)
4940 DPRINT1("Page protection is invalid\n");
4941 return STATUS_INVALID_PAGE_PROTECTION
;
4944 /* Check if this is going to be a data or image backed file section */
4945 if ((FileHandle
) || (FileObject
))
4947 /* These cannot be mapped with large pages */
4948 if (AllocationAttributes
& SEC_LARGE_PAGES
)
4950 DPRINT1("Large pages cannot be used with an image mapping\n");
4951 return STATUS_INVALID_PARAMETER_6
;
4954 /* Did the caller pass an object? */
4957 /* Reference the object directly */
4958 ObReferenceObject(FileObject
);
4962 /* Reference the file handle to get the object */
4963 Status
= ObReferenceObjectByHandle(FileHandle
,
4964 MmMakeFileAccess
[Protection
],
4966 ExGetPreviousMode(),
4967 (PVOID
*)&FileObject
,
4969 if (!NT_SUCCESS(Status
))
4971 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
4978 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
4979 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
4982 #ifndef NEWCC // A hack for initializing caching.
4983 // This is needed only in the old case.
4986 IO_STATUS_BLOCK Iosb
;
4989 LARGE_INTEGER ByteOffset
;
4990 ByteOffset
.QuadPart
= 0;
4991 Status
= ZwReadFile(FileHandle
,
5000 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5002 DPRINT1("CC failure: %lx\n", Status
);
5005 // Caching is initialized...
5009 if (AllocationAttributes
& SEC_IMAGE
)
5011 Status
= MmCreateImageSection(SectionObject
,
5015 SectionPageProtection
,
5016 AllocationAttributes
,
5020 else if (FileHandle
!= NULL
)
5022 Status
= MmCreateDataFileSection(SectionObject
,
5026 SectionPageProtection
,
5027 AllocationAttributes
,
5030 ObDereferenceObject(FileObject
);
5033 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5035 Status
= MmCreateCacheSection(SectionObject
,
5039 SectionPageProtection
,
5040 AllocationAttributes
,
5046 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5048 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5050 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5051 Status
= MmCreatePageFileSection(SectionObject
,
5055 SectionPageProtection
,
5056 AllocationAttributes
);