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,%x,%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 ACCESS_MASK NTAPI
MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection
);
165 static GENERIC_MAPPING MmpSectionMapping
= {
166 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
167 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
168 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
171 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
173 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
174 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
177 /* FUNCTIONS *****************************************************************/
182 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
183 File Format Specification", revision 6.0 (February 1999)
185 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
186 IN SIZE_T FileHeaderSize
,
188 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
190 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
191 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
194 ULONG cbFileHeaderOffsetSize
= 0;
195 ULONG cbSectionHeadersOffset
= 0;
196 ULONG cbSectionHeadersSize
;
197 ULONG cbSectionHeadersOffsetSize
= 0;
198 ULONG cbOptHeaderSize
;
199 ULONG cbHeadersSize
= 0;
200 ULONG nSectionAlignment
;
201 ULONG nFileAlignment
;
202 const IMAGE_DOS_HEADER
* pidhDosHeader
;
203 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
204 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
205 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
206 PMM_SECTION_SEGMENT pssSegments
;
207 LARGE_INTEGER lnOffset
;
209 SIZE_T nPrevVirtualEndOfSegment
= 0;
210 ULONG nFileSizeOfHeaders
= 0;
214 ASSERT(FileHeaderSize
> 0);
216 ASSERT(ImageSectionObject
);
218 ASSERT(AllocateSegmentsCb
);
220 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
222 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
224 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
227 pidhDosHeader
= FileHeader
;
230 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
232 /* image too small to be an MZ executable */
233 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
234 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
236 /* no MZ signature */
237 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
238 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
240 /* not a Windows executable */
241 if(pidhDosHeader
->e_lfanew
<= 0)
242 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
245 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
247 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
248 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
250 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
255 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
256 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
258 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
259 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
263 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
264 * need to read the header from the file
266 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
267 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
269 ULONG cbNtHeaderSize
;
273 l_ReadHeaderFromFile
:
275 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
277 /* read the header from the file */
278 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
280 if(!NT_SUCCESS(nStatus
))
281 DIE(("ReadFile failed, status %08X\n", nStatus
));
285 ASSERT(cbReadSize
> 0);
287 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
289 /* the buffer doesn't contain the file header */
290 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
291 DIE(("The file doesn't contain the PE file header\n"));
293 pinhNtHeader
= pData
;
295 /* object still not aligned: copy it to the beginning of the buffer */
296 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
298 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
299 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
300 pinhNtHeader
= pBuffer
;
303 /* invalid NT header */
304 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
306 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
307 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
309 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
311 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
312 DIE(("The full NT header is too large\n"));
314 /* the buffer doesn't contain the whole NT header */
315 if(cbReadSize
< cbNtHeaderSize
)
316 DIE(("The file doesn't contain the full NT header\n"));
320 ULONG cbOptHeaderOffsetSize
= 0;
322 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
324 /* don't trust an invalid NT header */
325 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
326 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
328 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
329 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
331 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
332 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
334 /* the buffer doesn't contain the whole NT header: read it from the file */
335 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
336 goto l_ReadHeaderFromFile
;
339 /* read information from the NT header */
340 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
341 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
343 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
345 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
346 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
348 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
350 switch(piohOptHeader
->Magic
)
352 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
353 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
357 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
360 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
361 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
363 /* See [1], section 3.4.2 */
364 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
366 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
367 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
369 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
370 DIE(("The section alignment is smaller than the file alignment\n"));
372 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
373 nFileAlignment
= piohOptHeader
->FileAlignment
;
375 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
376 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
380 nSectionAlignment
= PAGE_SIZE
;
381 nFileAlignment
= PAGE_SIZE
;
384 ASSERT(IsPowerOf2(nSectionAlignment
));
385 ASSERT(IsPowerOf2(nFileAlignment
));
387 switch(piohOptHeader
->Magic
)
390 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
392 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
393 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
395 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
396 ImageSectionObject
->ImageSize
= piohOptHeader
->SizeOfImage
;
398 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
399 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
401 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
402 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
408 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
410 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
412 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
414 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
416 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
417 DIE(("ImageBase exceeds the address space\n"));
419 ImageSectionObject
->ImageBase
= (ULONG_PTR
)pioh64OptHeader
->ImageBase
;
422 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
424 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
425 DIE(("SizeOfImage exceeds the address space\n"));
427 ImageSectionObject
->ImageSize
= pioh64OptHeader
->SizeOfImage
;
430 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
432 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
433 DIE(("SizeOfStackReserve exceeds the address space\n"));
435 ImageSectionObject
->StackReserve
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackReserve
;
438 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
440 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
441 DIE(("SizeOfStackCommit exceeds the address space\n"));
443 ImageSectionObject
->StackCommit
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackCommit
;
450 /* [1], section 3.4.2 */
451 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
452 DIE(("ImageBase is not aligned on a 64KB boundary"));
454 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
456 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
458 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
459 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
461 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
462 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
466 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
468 ImageSectionObject
->EntryPoint
= ImageSectionObject
->ImageBase
+
469 piohOptHeader
->AddressOfEntryPoint
;
472 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
473 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
475 ImageSectionObject
->Executable
= TRUE
;
477 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
478 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
480 /* SECTION HEADERS */
481 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
483 /* see [1], section 3.3 */
484 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
485 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
488 * the additional segment is for the file's headers. They need to be present for
489 * the benefit of the dynamic loader (to locate exports, defaults for thread
490 * parameters, resources, etc.)
492 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
494 /* file offset for the section headers */
495 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
496 DIE(("Offset overflow\n"));
498 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
499 DIE(("Offset overflow\n"));
501 /* size of the section headers */
502 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
503 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
505 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
506 DIE(("Section headers too large\n"));
508 /* size of the executable's headers */
509 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
511 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
512 // DIE(("SizeOfHeaders is not aligned\n"));
514 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
515 DIE(("The section headers overflow SizeOfHeaders\n"));
517 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
519 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
520 DIE(("Overflow aligning the size of headers\n"));
527 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
528 /* WARNING: piohOptHeader IS NO LONGER USABLE */
529 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
531 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
532 pishSectionHeaders
= NULL
;
536 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
537 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
539 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
540 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
544 * the buffer doesn't contain the section headers, or the alignment is wrong:
545 * read the headers from the file
547 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
548 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
553 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
555 /* read the header from the file */
556 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
558 if(!NT_SUCCESS(nStatus
))
559 DIE(("ReadFile failed with status %08X\n", nStatus
));
563 ASSERT(cbReadSize
> 0);
565 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
567 /* the buffer doesn't contain all the section headers */
568 if(cbReadSize
< cbSectionHeadersSize
)
569 DIE(("The file doesn't contain all of the section headers\n"));
571 pishSectionHeaders
= pData
;
573 /* object still not aligned: copy it to the beginning of the buffer */
574 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
576 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
577 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
578 pishSectionHeaders
= pBuffer
;
583 /* allocate the segments */
584 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
585 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
587 if(ImageSectionObject
->Segments
== NULL
)
588 DIE(("AllocateSegments failed\n"));
590 /* initialize the headers segment */
591 pssSegments
= ImageSectionObject
->Segments
;
593 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
595 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
596 DIE(("Cannot align the size of the section headers\n"));
598 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
599 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
600 DIE(("Cannot align the size of the section headers\n"));
602 pssSegments
[0].Image
.FileOffset
= 0;
603 pssSegments
[0].Protection
= PAGE_READONLY
;
604 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
605 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
606 pssSegments
[0].Image
.VirtualAddress
= 0;
607 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
608 pssSegments
[0].WriteCopy
= TRUE
;
610 /* skip the headers segment */
613 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
615 /* convert the executable sections into segments. See also [1], section 4 */
616 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
618 ULONG nCharacteristics
;
620 /* validate the alignment */
621 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
622 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
624 /* sections must be contiguous, ordered by base address and non-overlapping */
625 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
626 DIE(("Memory gap between section %u and the previous\n", i
));
628 /* ignore explicit BSS sections */
629 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
631 /* validate the alignment */
633 /* Yes, this should be a multiple of FileAlignment, but there's
634 * stuff out there that isn't. We can cope with that
636 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
637 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
640 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
641 // DIE(("PointerToRawData[%u] is not aligned\n", i));
644 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
645 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
649 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
650 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
653 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
655 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
657 /* no explicit protection */
658 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
660 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
661 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
663 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
664 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
666 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
667 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
670 /* see table above */
671 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
672 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
674 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
675 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
677 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
679 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
680 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
681 DIE(("Cannot align the virtual size of section %u\n", i
));
683 if(pssSegments
[i
].Length
.QuadPart
== 0)
684 DIE(("Virtual size of section %u is null\n", i
));
686 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
687 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
689 /* ensure the memory image is no larger than 4GB */
690 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
691 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
692 DIE(("The image is too large\n"));
695 if(nSectionAlignment
>= PAGE_SIZE
)
696 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
699 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;
709 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
710 * ARGUMENTS: PFILE_OBJECT to wait for.
711 * RETURNS: Status of the wait.
714 MmspWaitForFileLock(PFILE_OBJECT File
)
716 return STATUS_SUCCESS
;
717 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
722 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
724 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
726 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
727 PMM_SECTION_SEGMENT SectionSegments
;
731 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
732 NrSegments
= ImageSectionObject
->NrSegments
;
733 SectionSegments
= ImageSectionObject
->Segments
;
734 for (i
= 0; i
< NrSegments
; i
++)
736 if (SectionSegments
[i
].ReferenceCount
!= 0)
738 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
739 SectionSegments
[i
].ReferenceCount
);
740 KeBugCheck(MEMORY_MANAGEMENT
);
742 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
744 ExFreePool(ImageSectionObject
->Segments
);
745 ExFreePool(ImageSectionObject
);
746 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
748 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
750 PMM_SECTION_SEGMENT Segment
;
752 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
755 if (Segment
->ReferenceCount
!= 0)
757 DPRINT1("Data segment still referenced\n");
758 KeBugCheck(MEMORY_MANAGEMENT
);
760 MmFreePageTablesSectionSegment(Segment
, NULL
);
762 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
768 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
769 PLARGE_INTEGER Offset
)
773 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
776 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
777 KeBugCheck(MEMORY_MANAGEMENT
);
779 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
781 DPRINT1("Maximum share count reached\n");
782 KeBugCheck(MEMORY_MANAGEMENT
);
784 if (IS_SWAP_FROM_SSE(Entry
))
786 KeBugCheck(MEMORY_MANAGEMENT
);
788 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
789 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
794 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
795 PMM_SECTION_SEGMENT Segment
,
796 PLARGE_INTEGER Offset
,
801 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
802 BOOLEAN IsDirectMapped
= FALSE
;
806 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
807 KeBugCheck(MEMORY_MANAGEMENT
);
809 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
811 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
812 KeBugCheck(MEMORY_MANAGEMENT
);
814 if (IS_SWAP_FROM_SSE(Entry
))
816 KeBugCheck(MEMORY_MANAGEMENT
);
818 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
820 * If we reducing the share count of this entry to zero then set the entry
821 * to zero and tell the cache the page is no longer mapped.
823 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
825 PFILE_OBJECT FileObject
;
829 SWAPENTRY SavedSwapEntry
;
831 BOOLEAN IsImageSection
;
832 LARGE_INTEGER FileOffset
;
834 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
836 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
838 Page
= PFN_FROM_SSE(Entry
);
839 FileObject
= Section
->FileObject
;
840 if (FileObject
!= NULL
&&
841 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
845 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
846 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
849 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
850 IsDirectMapped
= TRUE
;
852 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
.LowPart
, Dirty
);
854 Status
= STATUS_SUCCESS
;
856 if (!NT_SUCCESS(Status
))
858 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
859 KeBugCheck(MEMORY_MANAGEMENT
);
865 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
866 if (SavedSwapEntry
== 0)
869 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
870 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
874 * Try to page out this page and set the swap entry
875 * within the section segment. There exist no rmap entry
876 * for this page. The pager thread can't page out a
877 * page without a rmap entry.
879 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
880 if (InEntry
) *InEntry
= Entry
;
881 MiSetPageEvent(NULL
, NULL
);
885 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
886 if (InEntry
) *InEntry
= 0;
887 MiSetPageEvent(NULL
, NULL
);
890 MmReleasePageMemoryConsumer(MC_USER
, Page
);
896 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
897 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
905 * We hold all locks. Nobody can do something with the current
906 * process and the current segment (also not within an other process).
909 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
910 if (!NT_SUCCESS(Status
))
912 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
913 KeBugCheck(MEMORY_MANAGEMENT
);
916 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
917 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
918 MmSetSavedSwapEntryPage(Page
, 0);
919 MiSetPageEvent(NULL
, NULL
);
921 MmReleasePageMemoryConsumer(MC_USER
, Page
);
925 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
926 KeBugCheck(MEMORY_MANAGEMENT
);
935 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
937 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
940 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
944 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
947 PCACHE_SEGMENT CacheSeg
;
948 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
949 CacheSeg
= CcRosLookupCacheSegment(Bcb
, (ULONG
)(SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
));
952 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
962 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
966 PVOID DestAddress
, SrcAddress
;
968 Process
= PsGetCurrentProcess();
969 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
970 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
971 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
973 return(STATUS_NO_MEMORY
);
975 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
976 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
977 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
978 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
979 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
980 return(STATUS_SUCCESS
);
986 MiReadPage(PMEMORY_AREA MemoryArea
,
990 * FUNCTION: Read a page for a section backed memory area.
992 * MemoryArea - Memory area to read the page for.
993 * Offset - Offset of the page to read.
994 * Page - Variable that receives a page contains the read data.
998 ULONGLONG FileOffset
;
1001 PCACHE_SEGMENT CacheSeg
;
1002 PFILE_OBJECT FileObject
;
1004 ULONG_PTR RawLength
;
1006 BOOLEAN IsImageSection
;
1009 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1010 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1011 RawLength
= (ULONG_PTR
)(MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
);
1012 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1013 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1017 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1020 * If the file system is letting us go directly to the cache and the
1021 * memory area was mapped at an offset in the file which is page aligned
1022 * then get the related cache segment.
1024 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1025 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1026 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1030 * Get the related cache segment; we use a lower level interface than
1031 * filesystems do because it is safe for us to use an offset with a
1032 * alignment less than the file system block size.
1034 Status
= CcRosGetCacheSegment(Bcb
,
1040 if (!NT_SUCCESS(Status
))
1047 * If the cache segment isn't up to date then call the file
1048 * system to read in the data.
1050 Status
= ReadCacheSegment(CacheSeg
);
1051 if (!NT_SUCCESS(Status
))
1053 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1058 * Retrieve the page from the cache segment that we actually want.
1060 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1061 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1063 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1070 ULONG_PTR CacheSegOffset
;
1073 * Allocate a page, this is rather complicated by the possibility
1074 * we might have to move other things out of memory
1076 MI_SET_USAGE(MI_USAGE_SECTION
);
1077 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1078 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1079 if (!NT_SUCCESS(Status
))
1083 Status
= CcRosGetCacheSegment(Bcb
,
1089 if (!NT_SUCCESS(Status
))
1096 * If the cache segment isn't up to date then call the file
1097 * system to read in the data.
1099 Status
= ReadCacheSegment(CacheSeg
);
1100 if (!NT_SUCCESS(Status
))
1102 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1107 Process
= PsGetCurrentProcess();
1108 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1109 CacheSegOffset
= (ULONG_PTR
)(BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
);
1110 Length
= RawLength
- SegOffset
;
1111 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1113 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1115 else if (CacheSegOffset
>= PAGE_SIZE
)
1117 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1121 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1122 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1123 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1124 Status
= CcRosGetCacheSegment(Bcb
,
1125 (ULONG
)(FileOffset
+ CacheSegOffset
),
1130 if (!NT_SUCCESS(Status
))
1137 * If the cache segment isn't up to date then call the file
1138 * system to read in the data.
1140 Status
= ReadCacheSegment(CacheSeg
);
1141 if (!NT_SUCCESS(Status
))
1143 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1147 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1148 if (Length
< PAGE_SIZE
)
1150 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1154 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1157 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1158 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1160 return(STATUS_SUCCESS
);
1165 MiReadPage(PMEMORY_AREA MemoryArea
,
1166 ULONG_PTR SegOffset
,
1169 * FUNCTION: Read a page for a section backed memory area.
1171 * MemoryArea - Memory area to read the page for.
1172 * Offset - Offset of the page to read.
1173 * Page - Variable that receives a page contains the read data.
1176 MM_REQUIRED_RESOURCES Resources
;
1179 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1181 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1182 Resources
.FileOffset
.QuadPart
= SegOffset
+
1183 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1184 Resources
.Consumer
= MC_USER
;
1185 Resources
.Amount
= PAGE_SIZE
;
1187 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]);
1189 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1190 *Page
= Resources
.Page
[0];
1197 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1198 MEMORY_AREA
* MemoryArea
,
1202 LARGE_INTEGER Offset
;
1205 PROS_SECTION_OBJECT Section
;
1206 PMM_SECTION_SEGMENT Segment
;
1211 BOOLEAN HasSwapEntry
;
1213 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1214 SWAPENTRY SwapEntry
;
1217 * There is a window between taking the page fault and locking the
1218 * address space when another thread could load the page so we check
1221 if (MmIsPagePresent(Process
, Address
))
1223 return(STATUS_SUCCESS
);
1226 if (MmIsDisabledPage(Process
, Address
))
1228 return(STATUS_ACCESS_VIOLATION
);
1232 * Check for the virtual memory area being deleted.
1234 if (MemoryArea
->DeleteInProgress
)
1236 return(STATUS_UNSUCCESSFUL
);
1239 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1240 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1241 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1243 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1244 Section
= MemoryArea
->Data
.SectionData
.Section
;
1245 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1246 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1248 ASSERT(Region
!= NULL
);
1252 MmLockSectionSegment(Segment
);
1253 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1255 * Check if this page needs to be mapped COW
1257 if ((Segment
->WriteCopy
) &&
1258 (Region
->Protect
== PAGE_READWRITE
||
1259 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1261 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1265 Attributes
= Region
->Protect
;
1269 * Check if someone else is already handling this fault, if so wait
1272 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1274 MmUnlockSectionSegment(Segment
);
1275 MmUnlockAddressSpace(AddressSpace
);
1276 MiWaitForPageEvent(NULL
, NULL
);
1277 MmLockAddressSpace(AddressSpace
);
1278 DPRINT("Address 0x%.8X\n", Address
);
1279 return(STATUS_MM_RESTART_OPERATION
);
1282 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1286 SWAPENTRY DummyEntry
;
1289 * Is it a wait entry?
1291 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1293 if (SwapEntry
== MM_WAIT_ENTRY
)
1295 MmUnlockSectionSegment(Segment
);
1296 MmUnlockAddressSpace(AddressSpace
);
1297 MiWaitForPageEvent(NULL
, NULL
);
1298 MmLockAddressSpace(AddressSpace
);
1299 return STATUS_MM_RESTART_OPERATION
;
1303 * Must be private page we have swapped out.
1309 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1311 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1312 KeBugCheck(MEMORY_MANAGEMENT
);
1315 MmUnlockSectionSegment(Segment
);
1316 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1317 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1319 MmUnlockAddressSpace(AddressSpace
);
1320 MI_SET_USAGE(MI_USAGE_SECTION
);
1321 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1322 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1323 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1324 if (!NT_SUCCESS(Status
))
1326 KeBugCheck(MEMORY_MANAGEMENT
);
1329 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1330 if (!NT_SUCCESS(Status
))
1332 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1333 KeBugCheck(MEMORY_MANAGEMENT
);
1335 MmLockAddressSpace(AddressSpace
);
1336 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1337 Status
= MmCreateVirtualMapping(Process
,
1342 if (!NT_SUCCESS(Status
))
1344 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1345 KeBugCheck(MEMORY_MANAGEMENT
);
1350 * Store the swap entry for later use.
1352 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1355 * Add the page to the process's working set
1357 MmInsertRmap(Page
, Process
, Address
);
1359 * Finish the operation
1361 MiSetPageEvent(Process
, Address
);
1362 DPRINT("Address 0x%.8X\n", Address
);
1363 return(STATUS_SUCCESS
);
1367 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1369 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1371 MmUnlockSectionSegment(Segment
);
1373 * Just map the desired physical page
1375 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1376 Status
= MmCreateVirtualMappingUnsafe(Process
,
1381 if (!NT_SUCCESS(Status
))
1383 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1384 KeBugCheck(MEMORY_MANAGEMENT
);
1389 * Cleanup and release locks
1391 MiSetPageEvent(Process
, Address
);
1392 DPRINT("Address 0x%.8X\n", Address
);
1393 return(STATUS_SUCCESS
);
1397 * Map anonymous memory for BSS sections
1399 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1401 /* We'll be unlocking the address space below. Prevent us from being preempted
1402 * in faulting in the page. */
1403 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1404 MmUnlockSectionSegment(Segment
);
1405 MI_SET_USAGE(MI_USAGE_SECTION
);
1406 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1407 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1408 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1409 if (!NT_SUCCESS(Status
))
1411 MmUnlockAddressSpace(AddressSpace
);
1412 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1413 MmLockAddressSpace(AddressSpace
);
1415 if (!NT_SUCCESS(Status
))
1417 KeBugCheck(MEMORY_MANAGEMENT
);
1419 /* Remove the wait entry we placed, so that we can map the page */
1420 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1421 Status
= MmCreateVirtualMapping(Process
,
1426 if (!NT_SUCCESS(Status
))
1428 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1429 KeBugCheck(MEMORY_MANAGEMENT
);
1432 MmInsertRmap(Page
, Process
, Address
);
1435 * Cleanup and release locks
1437 MiSetPageEvent(Process
, Address
);
1438 DPRINT("Address 0x%.8X\n", Address
);
1439 return(STATUS_SUCCESS
);
1443 * Get the entry corresponding to the offset within the section
1445 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1449 SWAPENTRY FakeSwapEntry
;
1452 * If the entry is zero (and it can't change because we have
1453 * locked the segment) then we need to load the page.
1457 * Release all our locks and read in the page from disk
1459 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1460 MmUnlockSectionSegment(Segment
);
1461 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1462 MmUnlockAddressSpace(AddressSpace
);
1464 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1465 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1466 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1468 MI_SET_USAGE(MI_USAGE_SECTION
);
1469 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1470 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1471 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1472 if (!NT_SUCCESS(Status
))
1474 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1480 Status
= MiReadPage(MemoryArea
, (ULONG_PTR
)Offset
.QuadPart
, &Page
);
1481 if (!NT_SUCCESS(Status
))
1483 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1486 if (!NT_SUCCESS(Status
))
1489 * FIXME: What do we know in this case?
1492 * Cleanup and release locks
1494 MmLockAddressSpace(AddressSpace
);
1495 MiSetPageEvent(Process
, Address
);
1496 DPRINT("Address 0x%.8X\n", Address
);
1501 * Mark the offset within the section as having valid, in-memory
1504 MmLockAddressSpace(AddressSpace
);
1505 MmLockSectionSegment(Segment
);
1506 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1507 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1508 MmUnlockSectionSegment(Segment
);
1510 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1511 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1512 Page
, Process
, PAddress
, Attributes
);
1513 Status
= MmCreateVirtualMapping(Process
,
1518 if (!NT_SUCCESS(Status
))
1520 DPRINT1("Unable to create virtual mapping\n");
1521 KeBugCheck(MEMORY_MANAGEMENT
);
1523 ASSERT(MmIsPagePresent(Process
, PAddress
));
1524 MmInsertRmap(Page
, Process
, Address
);
1526 MiSetPageEvent(Process
, Address
);
1527 DPRINT("Address 0x%.8X\n", Address
);
1528 return(STATUS_SUCCESS
);
1530 else if (IS_SWAP_FROM_SSE(Entry
))
1532 SWAPENTRY SwapEntry
;
1534 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1537 * Release all our locks and read in the page from disk
1539 MmUnlockSectionSegment(Segment
);
1541 MmUnlockAddressSpace(AddressSpace
);
1542 MI_SET_USAGE(MI_USAGE_SECTION
);
1543 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1544 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1545 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1546 if (!NT_SUCCESS(Status
))
1548 KeBugCheck(MEMORY_MANAGEMENT
);
1551 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1552 if (!NT_SUCCESS(Status
))
1554 KeBugCheck(MEMORY_MANAGEMENT
);
1558 * Relock the address space and segment
1560 MmLockAddressSpace(AddressSpace
);
1561 MmLockSectionSegment(Segment
);
1564 * Check the entry. No one should change the status of a page
1565 * that has a pending page-in.
1567 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1568 if (Entry
!= Entry1
)
1570 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1571 KeBugCheck(MEMORY_MANAGEMENT
);
1575 * Mark the offset within the section as having valid, in-memory
1578 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1579 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1580 MmUnlockSectionSegment(Segment
);
1583 * Save the swap entry.
1585 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1586 Status
= MmCreateVirtualMapping(Process
,
1591 if (!NT_SUCCESS(Status
))
1593 DPRINT1("Unable to create virtual mapping\n");
1594 KeBugCheck(MEMORY_MANAGEMENT
);
1596 MmInsertRmap(Page
, Process
, Address
);
1597 MiSetPageEvent(Process
, Address
);
1598 DPRINT("Address 0x%.8X\n", Address
);
1599 return(STATUS_SUCCESS
);
1604 * If the section offset is already in-memory and valid then just
1605 * take another reference to the page
1608 Page
= PFN_FROM_SSE(Entry
);
1610 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1611 MmUnlockSectionSegment(Segment
);
1613 Status
= MmCreateVirtualMapping(Process
,
1618 if (!NT_SUCCESS(Status
))
1620 DPRINT1("Unable to create virtual mapping\n");
1621 KeBugCheck(MEMORY_MANAGEMENT
);
1623 MmInsertRmap(Page
, Process
, Address
);
1624 MiSetPageEvent(Process
, Address
);
1625 DPRINT("Address 0x%.8X\n", Address
);
1626 return(STATUS_SUCCESS
);
1632 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1633 MEMORY_AREA
* MemoryArea
,
1636 PMM_SECTION_SEGMENT Segment
;
1637 PROS_SECTION_OBJECT Section
;
1642 LARGE_INTEGER Offset
;
1645 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1646 SWAPENTRY SwapEntry
;
1648 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
);
1651 * Check if the page has already been set readwrite
1653 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1655 DPRINT("Address 0x%.8X\n", Address
);
1656 return(STATUS_SUCCESS
);
1660 * Find the offset of the page
1662 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1663 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1664 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1666 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1667 Section
= MemoryArea
->Data
.SectionData
.Section
;
1668 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1669 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1671 ASSERT(Region
!= NULL
);
1675 MmLockSectionSegment(Segment
);
1677 OldPage
= MmGetPfnForProcess(Process
, Address
);
1678 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1680 MmUnlockSectionSegment(Segment
);
1683 * Check if we are doing COW
1685 if (!((Segment
->WriteCopy
) &&
1686 (Region
->Protect
== PAGE_READWRITE
||
1687 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1689 DPRINT("Address 0x%.8X\n", Address
);
1690 return(STATUS_ACCESS_VIOLATION
);
1693 if (IS_SWAP_FROM_SSE(Entry
) ||
1694 PFN_FROM_SSE(Entry
) != OldPage
)
1696 /* This is a private page. We must only change the page protection. */
1697 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1698 return(STATUS_SUCCESS
);
1702 DPRINT("OldPage == 0!\n");
1705 * Get or create a pageop
1707 MmLockSectionSegment(Segment
);
1708 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1711 * Wait for any other operations to complete
1713 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1715 MmUnlockSectionSegment(Segment
);
1716 MmUnlockAddressSpace(AddressSpace
);
1717 MiWaitForPageEvent(NULL
, NULL
);
1719 * Restart the operation
1721 MmLockAddressSpace(AddressSpace
);
1722 DPRINT("Address 0x%.8X\n", Address
);
1723 return(STATUS_MM_RESTART_OPERATION
);
1726 MmDeleteRmap(OldPage
, Process
, PAddress
);
1727 MmDeleteVirtualMapping(Process
, PAddress
, FALSE
, NULL
, NULL
);
1728 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1731 * Release locks now we have the pageop
1733 MmUnlockSectionSegment(Segment
);
1734 MmUnlockAddressSpace(AddressSpace
);
1739 MI_SET_USAGE(MI_USAGE_SECTION
);
1740 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1741 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1742 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1743 if (!NT_SUCCESS(Status
))
1745 KeBugCheck(MEMORY_MANAGEMENT
);
1751 MiCopyFromUserPage(NewPage
, OldPage
);
1753 MmLockAddressSpace(AddressSpace
);
1756 * Set the PTE to point to the new page
1758 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1759 Status
= MmCreateVirtualMapping(Process
,
1764 if (!NT_SUCCESS(Status
))
1766 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1767 KeBugCheck(MEMORY_MANAGEMENT
);
1772 * Unshare the old page.
1774 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1775 MmInsertRmap(NewPage
, Process
, PAddress
);
1776 MmLockSectionSegment(Segment
);
1777 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1778 MmUnlockSectionSegment(Segment
);
1780 MiSetPageEvent(Process
, Address
);
1781 DPRINT("Address 0x%.8X\n", Address
);
1782 return(STATUS_SUCCESS
);
1786 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1788 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1790 PFN_NUMBER Page
= 0;
1792 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1795 MmLockAddressSpace(&Process
->Vm
);
1798 MmDeleteVirtualMapping(Process
,
1805 PageOutContext
->WasDirty
= TRUE
;
1807 if (!PageOutContext
->Private
)
1809 MmLockSectionSegment(PageOutContext
->Segment
);
1810 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1811 PageOutContext
->Segment
,
1812 &PageOutContext
->Offset
,
1813 PageOutContext
->WasDirty
,
1815 &PageOutContext
->SectionEntry
);
1816 MmUnlockSectionSegment(PageOutContext
->Segment
);
1820 MmUnlockAddressSpace(&Process
->Vm
);
1823 if (PageOutContext
->Private
)
1825 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1831 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1832 MEMORY_AREA
* MemoryArea
,
1833 PVOID Address
, ULONG_PTR Entry
)
1836 MM_SECTION_PAGEOUT_CONTEXT Context
;
1837 SWAPENTRY SwapEntry
;
1838 ULONGLONG FileOffset
;
1840 PFILE_OBJECT FileObject
;
1844 BOOLEAN DirectMapped
;
1845 BOOLEAN IsImageSection
;
1846 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1849 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1852 * Get the segment and section.
1854 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1855 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1856 Context
.SectionEntry
= Entry
;
1857 Context
.CallingProcess
= Process
;
1859 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1860 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1861 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1863 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1865 FileObject
= Context
.Section
->FileObject
;
1866 DirectMapped
= FALSE
;
1868 MmLockSectionSegment(Context
.Segment
);
1871 if (FileObject
!= NULL
&&
1872 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1874 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1877 * If the file system is letting us go directly to the cache and the
1878 * memory area was mapped at an offset in the file which is page aligned
1879 * then note this is a direct mapped page.
1881 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1882 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1884 DirectMapped
= TRUE
;
1891 * This should never happen since mappings of physical memory are never
1892 * placed in the rmap lists.
1894 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1896 DPRINT1("Trying to page out from physical memory section address 0x%X "
1897 "process %d\n", Address
,
1898 Process
? Process
->UniqueProcessId
: 0);
1899 KeBugCheck(MEMORY_MANAGEMENT
);
1903 * Get the section segment entry and the physical address.
1905 if (!MmIsPagePresent(Process
, Address
))
1907 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1908 Process
? Process
->UniqueProcessId
: 0, Address
);
1909 KeBugCheck(MEMORY_MANAGEMENT
);
1911 Page
= MmGetPfnForProcess(Process
, Address
);
1912 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1915 * Check the reference count to ensure this page can be paged out
1917 if (MmGetReferenceCountPage(Page
) != 1)
1919 DPRINT("Cannot page out locked section page: 0x%p (RefCount: %d)\n",
1920 Page
, MmGetReferenceCountPage(Page
));
1921 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1922 MmUnlockSectionSegment(Context
.Segment
);
1923 return STATUS_UNSUCCESSFUL
;
1927 * Prepare the context structure for the rmap delete call.
1929 MmUnlockSectionSegment(Context
.Segment
);
1930 Context
.WasDirty
= FALSE
;
1931 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1932 IS_SWAP_FROM_SSE(Entry
) ||
1933 PFN_FROM_SSE(Entry
) != Page
)
1935 Context
.Private
= TRUE
;
1939 Context
.Private
= FALSE
;
1943 * Take an additional reference to the page or the cache segment.
1945 if (DirectMapped
&& !Context
.Private
)
1947 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
1949 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1950 KeBugCheck(MEMORY_MANAGEMENT
);
1955 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1956 MmReferencePage(Page
);
1957 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1960 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1962 /* Since we passed in a surrogate, we'll get back the page entry
1963 * state in our context. This is intended to make intermediate
1964 * decrements of share count not release the wait entry.
1966 Entry
= Context
.SectionEntry
;
1969 * If this wasn't a private page then we should have reduced the entry to
1970 * zero by deleting all the rmaps.
1972 if (!Context
.Private
&& Entry
!= 0)
1974 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1975 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1977 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
1982 * If the page wasn't dirty then we can just free it as for a readonly page.
1983 * Since we unmapped all the mappings above we know it will not suddenly
1985 * If the page is from a pagefile section and has no swap entry,
1986 * we can't free the page at this point.
1988 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1989 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1991 if (Context
.Private
)
1993 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1994 Context
.WasDirty
? "dirty" : "clean", Address
);
1995 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
1997 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1999 MmSetSavedSwapEntryPage(Page
, 0);
2000 MmLockSectionSegment(Context
.Segment
);
2001 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2002 MmUnlockSectionSegment(Context
.Segment
);
2003 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2004 MiSetPageEvent(NULL
, NULL
);
2005 return(STATUS_SUCCESS
);
2008 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2010 if (Context
.Private
)
2012 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2013 Context
.WasDirty
? "dirty" : "clean", Address
);
2014 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2016 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2018 MmSetSavedSwapEntryPage(Page
, 0);
2021 MmLockSectionSegment(Context
.Segment
);
2022 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2023 MmUnlockSectionSegment(Context
.Segment
);
2025 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2026 MiSetPageEvent(NULL
, NULL
);
2027 return(STATUS_SUCCESS
);
2030 else if (!Context
.Private
&& DirectMapped
)
2034 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2036 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2039 Status
= CcRosUnmapCacheSegment(Bcb
, (ULONG
)FileOffset
, FALSE
);
2041 Status
= STATUS_SUCCESS
;
2044 if (!NT_SUCCESS(Status
))
2046 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2047 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Bcb
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2050 MiSetPageEvent(NULL
, NULL
);
2051 return(STATUS_SUCCESS
);
2053 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2057 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2059 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2061 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2062 MiSetPageEvent(NULL
, NULL
);
2063 return(STATUS_SUCCESS
);
2065 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2067 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2068 MmSetSavedSwapEntryPage(Page
, 0);
2069 MmLockAddressSpace(AddressSpace
);
2070 Status
= MmCreatePageFileMapping(Process
,
2073 MmUnlockAddressSpace(AddressSpace
);
2074 if (!NT_SUCCESS(Status
))
2076 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2077 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2079 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2080 MiSetPageEvent(NULL
, NULL
);
2081 return(STATUS_SUCCESS
);
2085 * If necessary, allocate an entry in the paging file for this page
2089 SwapEntry
= MmAllocSwapPage();
2092 MmShowOutOfSpaceMessagePagingFile();
2093 MmLockAddressSpace(AddressSpace
);
2095 * For private pages restore the old mappings.
2097 if (Context
.Private
)
2099 Status
= MmCreateVirtualMapping(Process
,
2101 MemoryArea
->Protect
,
2104 MmSetDirtyPage(Process
, Address
);
2113 * For non-private pages if the page wasn't direct mapped then
2114 * set it back into the section segment entry so we don't loose
2115 * our copy. Otherwise it will be handled by the cache manager.
2117 Status
= MmCreateVirtualMapping(Process
,
2119 MemoryArea
->Protect
,
2122 MmSetDirtyPage(Process
, Address
);
2126 // If we got here, the previous entry should have been a wait
2127 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2128 MmLockSectionSegment(Context
.Segment
);
2129 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2130 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2131 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2132 MmUnlockSectionSegment(Context
.Segment
);
2134 MmUnlockAddressSpace(AddressSpace
);
2135 MiSetPageEvent(NULL
, NULL
);
2136 return(STATUS_PAGEFILE_QUOTA
);
2141 * Write the page to the pagefile
2143 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2144 if (!NT_SUCCESS(Status
))
2146 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2149 * As above: undo our actions.
2150 * FIXME: Also free the swap page.
2152 MmLockAddressSpace(AddressSpace
);
2153 if (Context
.Private
)
2155 Status
= MmCreateVirtualMapping(Process
,
2157 MemoryArea
->Protect
,
2160 MmSetDirtyPage(Process
, Address
);
2167 Status
= MmCreateVirtualMapping(Process
,
2169 MemoryArea
->Protect
,
2172 MmSetDirtyPage(Process
, Address
);
2176 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2177 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2179 MmUnlockAddressSpace(AddressSpace
);
2180 MiSetPageEvent(NULL
, NULL
);
2181 return(STATUS_UNSUCCESSFUL
);
2185 * Otherwise we have succeeded.
2187 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2188 MmSetSavedSwapEntryPage(Page
, 0);
2189 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2190 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2192 MmLockSectionSegment(Context
.Segment
);
2193 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2194 MmUnlockSectionSegment(Context
.Segment
);
2198 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2201 if (Context
.Private
)
2203 MmLockAddressSpace(AddressSpace
);
2204 MmLockSectionSegment(Context
.Segment
);
2205 Status
= MmCreatePageFileMapping(Process
,
2208 /* We had placed a wait entry upon entry ... replace it before leaving */
2209 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2210 MmUnlockSectionSegment(Context
.Segment
);
2211 MmUnlockAddressSpace(AddressSpace
);
2212 if (!NT_SUCCESS(Status
))
2214 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2215 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2220 MmLockAddressSpace(AddressSpace
);
2221 MmLockSectionSegment(Context
.Segment
);
2222 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2223 /* We had placed a wait entry upon entry ... replace it before leaving */
2224 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2225 MmUnlockSectionSegment(Context
.Segment
);
2226 MmUnlockAddressSpace(AddressSpace
);
2229 MiSetPageEvent(NULL
, NULL
);
2230 return(STATUS_SUCCESS
);
2235 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2236 PMEMORY_AREA MemoryArea
,
2240 LARGE_INTEGER Offset
;
2241 PROS_SECTION_OBJECT Section
;
2242 PMM_SECTION_SEGMENT Segment
;
2244 SWAPENTRY SwapEntry
;
2248 PFILE_OBJECT FileObject
;
2250 BOOLEAN DirectMapped
;
2251 BOOLEAN IsImageSection
;
2252 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2254 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2256 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2257 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2260 * Get the segment and section.
2262 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2263 Section
= MemoryArea
->Data
.SectionData
.Section
;
2264 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2266 FileObject
= Section
->FileObject
;
2267 DirectMapped
= FALSE
;
2268 if (FileObject
!= NULL
&&
2269 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2271 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2274 * If the file system is letting us go directly to the cache and the
2275 * memory area was mapped at an offset in the file which is page aligned
2276 * then note this is a direct mapped page.
2278 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2279 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2281 DirectMapped
= TRUE
;
2286 * This should never happen since mappings of physical memory are never
2287 * placed in the rmap lists.
2289 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2291 DPRINT1("Trying to write back page from physical memory mapped at %X "
2292 "process %d\n", Address
,
2293 Process
? Process
->UniqueProcessId
: 0);
2294 KeBugCheck(MEMORY_MANAGEMENT
);
2298 * Get the section segment entry and the physical address.
2300 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2301 if (!MmIsPagePresent(Process
, Address
))
2303 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2304 Process
? Process
->UniqueProcessId
: 0, Address
);
2305 KeBugCheck(MEMORY_MANAGEMENT
);
2307 Page
= MmGetPfnForProcess(Process
, Address
);
2308 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2311 * Check for a private (COWed) page.
2313 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2314 IS_SWAP_FROM_SSE(Entry
) ||
2315 PFN_FROM_SSE(Entry
) != Page
)
2325 * Speculatively set all mappings of the page to clean.
2327 MmSetCleanAllRmaps(Page
);
2330 * If this page was direct mapped from the cache then the cache manager
2331 * will take care of writing it back to disk.
2333 if (DirectMapped
&& !Private
)
2335 LARGE_INTEGER SOffset
;
2336 ASSERT(SwapEntry
== 0);
2337 SOffset
.QuadPart
= Offset
.QuadPart
+ Segment
->Image
.FileOffset
;
2339 CcRosMarkDirtyCacheSegment(Bcb
, Offset
.LowPart
);
2341 MmLockSectionSegment(Segment
);
2342 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2343 MmUnlockSectionSegment(Segment
);
2344 MiSetPageEvent(NULL
, NULL
);
2345 return(STATUS_SUCCESS
);
2349 * If necessary, allocate an entry in the paging file for this page
2353 SwapEntry
= MmAllocSwapPage();
2356 MmSetDirtyAllRmaps(Page
);
2357 MiSetPageEvent(NULL
, NULL
);
2358 return(STATUS_PAGEFILE_QUOTA
);
2360 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2364 * Write the page to the pagefile
2366 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2367 if (!NT_SUCCESS(Status
))
2369 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2371 MmSetDirtyAllRmaps(Page
);
2372 MiSetPageEvent(NULL
, NULL
);
2373 return(STATUS_UNSUCCESSFUL
);
2377 * Otherwise we have succeeded.
2379 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2380 MiSetPageEvent(NULL
, NULL
);
2381 return(STATUS_SUCCESS
);
2385 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2393 PMEMORY_AREA MemoryArea
;
2394 PMM_SECTION_SEGMENT Segment
;
2395 BOOLEAN DoCOW
= FALSE
;
2397 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2399 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2400 ASSERT(MemoryArea
!= NULL
);
2401 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2402 MmLockSectionSegment(Segment
);
2404 if ((Segment
->WriteCopy
) &&
2405 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2410 if (OldProtect
!= NewProtect
)
2412 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2414 SWAPENTRY SwapEntry
;
2415 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2416 ULONG Protect
= NewProtect
;
2418 /* Wait for a wait entry to disappear */
2420 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2421 if (SwapEntry
!= MM_WAIT_ENTRY
)
2423 MiWaitForPageEvent(Process
, Address
);
2427 * If we doing COW for this segment then check if the page is
2430 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2432 LARGE_INTEGER Offset
;
2436 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2437 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2438 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2440 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2441 * IS_SWAP_FROM_SSE and we'll do the right thing.
2443 Page
= MmGetPfnForProcess(Process
, Address
);
2445 Protect
= PAGE_READONLY
;
2446 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2447 IS_SWAP_FROM_SSE(Entry
) ||
2448 PFN_FROM_SSE(Entry
) != Page
)
2450 Protect
= NewProtect
;
2454 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2456 MmSetPageProtect(Process
, Address
,
2462 MmUnlockSectionSegment(Segment
);
2467 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2468 PMEMORY_AREA MemoryArea
,
2476 ULONG_PTR MaxLength
;
2478 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2479 if (Length
> MaxLength
)
2480 Length
= (ULONG
)MaxLength
;
2482 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2483 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2485 ASSERT(Region
!= NULL
);
2487 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2488 Region
->Protect
!= Protect
)
2490 return STATUS_INVALID_PAGE_PROTECTION
;
2493 *OldProtect
= Region
->Protect
;
2494 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2495 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2496 BaseAddress
, Length
, Region
->Type
, Protect
,
2497 MmAlterViewAttributes
);
2503 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2505 PMEMORY_BASIC_INFORMATION Info
,
2506 PSIZE_T ResultLength
)
2509 PVOID RegionBaseAddress
;
2510 PROS_SECTION_OBJECT Section
;
2511 PMM_SECTION_SEGMENT Segment
;
2513 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2514 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2515 Address
, &RegionBaseAddress
);
2518 return STATUS_UNSUCCESSFUL
;
2521 Section
= MemoryArea
->Data
.SectionData
.Section
;
2522 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2524 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2525 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2526 Info
->Type
= MEM_IMAGE
;
2530 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2531 Info
->Type
= MEM_MAPPED
;
2533 Info
->BaseAddress
= RegionBaseAddress
;
2534 Info
->AllocationProtect
= MemoryArea
->Protect
;
2535 Info
->RegionSize
= Region
->Length
;
2536 Info
->State
= MEM_COMMIT
;
2537 Info
->Protect
= Region
->Protect
;
2539 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2540 return(STATUS_SUCCESS
);
2545 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2548 LARGE_INTEGER Offset
;
2550 SWAPENTRY SavedSwapEntry
;
2555 MmLockSectionSegment(Segment
);
2557 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2558 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2560 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2563 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2564 if (IS_SWAP_FROM_SSE(Entry
))
2566 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2570 Page
= PFN_FROM_SSE(Entry
);
2571 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2572 if (SavedSwapEntry
!= 0)
2574 MmSetSavedSwapEntryPage(Page
, 0);
2575 MmFreeSwapPage(SavedSwapEntry
);
2577 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2582 MmUnlockSectionSegment(Segment
);
2586 MmpDeleteSection(PVOID ObjectBody
)
2588 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2590 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2591 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2596 PMM_SECTION_SEGMENT SectionSegments
;
2599 * NOTE: Section->ImageSection can be NULL for short time
2600 * during the section creating. If we fail for some reason
2601 * until the image section is properly initialized we shouldn't
2602 * process further here.
2604 if (Section
->ImageSection
== NULL
)
2607 SectionSegments
= Section
->ImageSection
->Segments
;
2608 NrSegments
= Section
->ImageSection
->NrSegments
;
2610 for (i
= 0; i
< NrSegments
; i
++)
2612 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2614 MmLockSectionSegment(&SectionSegments
[i
]);
2616 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2617 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2619 MmUnlockSectionSegment(&SectionSegments
[i
]);
2622 MmpFreePageFileSegment(&SectionSegments
[i
]);
2628 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2631 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2634 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2636 DPRINT("Freeing section segment\n");
2637 Section
->Segment
= NULL
;
2638 MmFinalizeSegment(Segment
);
2642 DPRINT("RefCount %d\n", RefCount
);
2649 * NOTE: Section->Segment can be NULL for short time
2650 * during the section creating.
2652 if (Section
->Segment
== NULL
)
2655 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2657 MmpFreePageFileSegment(Section
->Segment
);
2658 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2659 ExFreePool(Section
->Segment
);
2660 Section
->Segment
= NULL
;
2664 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2667 if (Section
->FileObject
!= NULL
)
2670 CcRosDereferenceCache(Section
->FileObject
);
2672 ObDereferenceObject(Section
->FileObject
);
2673 Section
->FileObject
= NULL
;
2678 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2680 IN ACCESS_MASK GrantedAccess
,
2681 IN ULONG ProcessHandleCount
,
2682 IN ULONG SystemHandleCount
)
2684 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2685 Object
, ProcessHandleCount
);
2691 MmCreatePhysicalMemorySection(VOID
)
2693 PROS_SECTION_OBJECT PhysSection
;
2695 OBJECT_ATTRIBUTES Obj
;
2696 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2697 LARGE_INTEGER SectionSize
;
2701 * Create the section mapping physical memory
2703 SectionSize
.QuadPart
= 0xFFFFFFFF;
2704 InitializeObjectAttributes(&Obj
,
2709 Status
= MmCreateSection((PVOID
)&PhysSection
,
2713 PAGE_EXECUTE_READWRITE
,
2717 if (!NT_SUCCESS(Status
))
2719 DPRINT1("Failed to create PhysicalMemory section\n");
2720 KeBugCheck(MEMORY_MANAGEMENT
);
2722 Status
= ObInsertObject(PhysSection
,
2728 if (!NT_SUCCESS(Status
))
2730 ObDereferenceObject(PhysSection
);
2732 ObCloseHandle(Handle
, KernelMode
);
2733 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2734 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2736 return(STATUS_SUCCESS
);
2742 MmInitSectionImplementation(VOID
)
2744 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2745 UNICODE_STRING Name
;
2747 DPRINT("Creating Section Object Type\n");
2749 /* Initialize the section based root */
2750 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2751 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2753 /* Initialize the Section object type */
2754 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2755 RtlInitUnicodeString(&Name
, L
"Section");
2756 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2757 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2758 ObjectTypeInitializer
.PoolType
= PagedPool
;
2759 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2760 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2761 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2762 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2763 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2764 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2765 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2767 MmCreatePhysicalMemorySection();
2769 return(STATUS_SUCCESS
);
2774 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2775 ACCESS_MASK DesiredAccess
,
2776 POBJECT_ATTRIBUTES ObjectAttributes
,
2777 PLARGE_INTEGER UMaximumSize
,
2778 ULONG SectionPageProtection
,
2779 ULONG AllocationAttributes
)
2781 * Create a section which is backed by the pagefile
2784 LARGE_INTEGER MaximumSize
;
2785 PROS_SECTION_OBJECT Section
;
2786 PMM_SECTION_SEGMENT Segment
;
2789 if (UMaximumSize
== NULL
)
2791 return(STATUS_UNSUCCESSFUL
);
2793 MaximumSize
= *UMaximumSize
;
2796 * Create the section
2798 Status
= ObCreateObject(ExGetPreviousMode(),
2799 MmSectionObjectType
,
2801 ExGetPreviousMode(),
2803 sizeof(ROS_SECTION_OBJECT
),
2806 (PVOID
*)(PVOID
)&Section
);
2807 if (!NT_SUCCESS(Status
))
2815 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2816 Section
->Type
= 'SC';
2817 Section
->Size
= 'TN';
2818 Section
->SectionPageProtection
= SectionPageProtection
;
2819 Section
->AllocationAttributes
= AllocationAttributes
;
2820 Section
->MaximumSize
= MaximumSize
;
2821 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2822 TAG_MM_SECTION_SEGMENT
);
2823 if (Segment
== NULL
)
2825 ObDereferenceObject(Section
);
2826 return(STATUS_NO_MEMORY
);
2828 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2829 Section
->Segment
= Segment
;
2830 Segment
->ReferenceCount
= 1;
2831 ExInitializeFastMutex(&Segment
->Lock
);
2832 Segment
->Image
.FileOffset
= 0;
2833 Segment
->Protection
= SectionPageProtection
;
2834 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2835 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2836 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2837 Segment
->WriteCopy
= FALSE
;
2838 Segment
->Image
.VirtualAddress
= 0;
2839 Segment
->Image
.Characteristics
= 0;
2840 *SectionObject
= Section
;
2841 MiInitializeSectionPageTable(Segment
);
2842 return(STATUS_SUCCESS
);
2847 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2848 ACCESS_MASK DesiredAccess
,
2849 POBJECT_ATTRIBUTES ObjectAttributes
,
2850 PLARGE_INTEGER UMaximumSize
,
2851 ULONG SectionPageProtection
,
2852 ULONG AllocationAttributes
,
2855 * Create a section backed by a data file
2858 PROS_SECTION_OBJECT Section
;
2860 LARGE_INTEGER MaximumSize
;
2861 PFILE_OBJECT FileObject
;
2862 PMM_SECTION_SEGMENT Segment
;
2864 IO_STATUS_BLOCK Iosb
;
2865 LARGE_INTEGER Offset
;
2867 FILE_STANDARD_INFORMATION FileInfo
;
2871 * Create the section
2873 Status
= ObCreateObject(ExGetPreviousMode(),
2874 MmSectionObjectType
,
2876 ExGetPreviousMode(),
2878 sizeof(ROS_SECTION_OBJECT
),
2882 if (!NT_SUCCESS(Status
))
2889 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2890 Section
->Type
= 'SC';
2891 Section
->Size
= 'TN';
2892 Section
->SectionPageProtection
= SectionPageProtection
;
2893 Section
->AllocationAttributes
= AllocationAttributes
;
2896 * Reference the file handle
2898 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2899 Status
= ObReferenceObjectByHandle(FileHandle
,
2902 ExGetPreviousMode(),
2903 (PVOID
*)(PVOID
)&FileObject
,
2905 if (!NT_SUCCESS(Status
))
2907 ObDereferenceObject(Section
);
2912 * FIXME: This is propably not entirely correct. We can't look into
2913 * the standard FCB header because it might not be initialized yet
2914 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2915 * standard file information is filled on first request).
2917 Status
= IoQueryFileInformation(FileObject
,
2918 FileStandardInformation
,
2919 sizeof(FILE_STANDARD_INFORMATION
),
2922 Iosb
.Information
= Length
;
2923 if (!NT_SUCCESS(Status
))
2925 ObDereferenceObject(Section
);
2926 ObDereferenceObject(FileObject
);
2931 * FIXME: Revise this once a locking order for file size changes is
2934 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2936 MaximumSize
= *UMaximumSize
;
2940 MaximumSize
= FileInfo
.EndOfFile
;
2941 /* Mapping zero-sized files isn't allowed. */
2942 if (MaximumSize
.QuadPart
== 0)
2944 ObDereferenceObject(Section
);
2945 ObDereferenceObject(FileObject
);
2946 return STATUS_FILE_INVALID
;
2950 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2952 Status
= IoSetInformation(FileObject
,
2953 FileAllocationInformation
,
2954 sizeof(LARGE_INTEGER
),
2956 if (!NT_SUCCESS(Status
))
2958 ObDereferenceObject(Section
);
2959 ObDereferenceObject(FileObject
);
2960 return(STATUS_SECTION_NOT_EXTENDED
);
2964 if (FileObject
->SectionObjectPointer
== NULL
||
2965 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2968 * Read a bit so caching is initiated for the file object.
2969 * This is only needed because MiReadPage currently cannot
2970 * handle non-cached streams.
2972 Offset
.QuadPart
= 0;
2973 Status
= ZwReadFile(FileHandle
,
2982 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2984 ObDereferenceObject(Section
);
2985 ObDereferenceObject(FileObject
);
2988 if (FileObject
->SectionObjectPointer
== NULL
||
2989 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2991 /* FIXME: handle this situation */
2992 ObDereferenceObject(Section
);
2993 ObDereferenceObject(FileObject
);
2994 return STATUS_INVALID_PARAMETER
;
3001 Status
= MmspWaitForFileLock(FileObject
);
3002 if (Status
!= STATUS_SUCCESS
)
3004 ObDereferenceObject(Section
);
3005 ObDereferenceObject(FileObject
);
3010 * If this file hasn't been mapped as a data file before then allocate a
3011 * section segment to describe the data file mapping
3013 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3015 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3016 TAG_MM_SECTION_SEGMENT
);
3017 if (Segment
== NULL
)
3019 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3020 ObDereferenceObject(Section
);
3021 ObDereferenceObject(FileObject
);
3022 return(STATUS_NO_MEMORY
);
3024 Section
->Segment
= Segment
;
3025 Segment
->ReferenceCount
= 1;
3026 ExInitializeFastMutex(&Segment
->Lock
);
3028 * Set the lock before assigning the segment to the file object
3030 ExAcquireFastMutex(&Segment
->Lock
);
3031 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3033 Segment
->Image
.FileOffset
= 0;
3034 Segment
->Protection
= SectionPageProtection
;
3035 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3036 Segment
->Image
.Characteristics
= 0;
3037 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3038 if (AllocationAttributes
& SEC_RESERVE
)
3040 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3044 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3045 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3047 Segment
->Image
.VirtualAddress
= 0;
3048 Segment
->Locked
= TRUE
;
3049 MiInitializeSectionPageTable(Segment
);
3054 * If the file is already mapped as a data file then we may need
3058 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3060 Section
->Segment
= Segment
;
3061 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3062 MmLockSectionSegment(Segment
);
3064 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3065 !(AllocationAttributes
& SEC_RESERVE
))
3067 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3068 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3071 MmUnlockSectionSegment(Segment
);
3072 Section
->FileObject
= FileObject
;
3073 Section
->MaximumSize
= MaximumSize
;
3075 CcRosReferenceCache(FileObject
);
3077 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3078 *SectionObject
= Section
;
3079 return(STATUS_SUCCESS
);
3083 TODO: not that great (declaring loaders statically, having to declare all of
3084 them, having to keep them extern, etc.), will fix in the future
3086 extern NTSTATUS NTAPI PeFmtCreateSection
3088 IN CONST VOID
* FileHeader
,
3089 IN SIZE_T FileHeaderSize
,
3091 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3093 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3094 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3097 extern NTSTATUS NTAPI ElfFmtCreateSection
3099 IN CONST VOID
* FileHeader
,
3100 IN SIZE_T FileHeaderSize
,
3102 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3104 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3105 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3108 /* TODO: this is a standard DDK/PSDK macro */
3109 #ifndef RTL_NUMBER_OF
3110 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3113 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3124 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3126 SIZE_T SizeOfSegments
;
3127 PMM_SECTION_SEGMENT Segments
;
3129 /* TODO: check for integer overflow */
3130 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3132 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3134 TAG_MM_SECTION_SEGMENT
);
3137 RtlZeroMemory(Segments
, SizeOfSegments
);
3145 ExeFmtpReadFile(IN PVOID File
,
3146 IN PLARGE_INTEGER Offset
,
3149 OUT PVOID
* AllocBase
,
3150 OUT PULONG ReadSize
)
3153 LARGE_INTEGER FileOffset
;
3155 ULONG OffsetAdjustment
;
3159 PFILE_OBJECT FileObject
= File
;
3160 IO_STATUS_BLOCK Iosb
;
3162 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3166 KeBugCheck(MEMORY_MANAGEMENT
);
3169 FileOffset
= *Offset
;
3171 /* Negative/special offset: it cannot be used in this context */
3172 if(FileOffset
.u
.HighPart
< 0)
3174 KeBugCheck(MEMORY_MANAGEMENT
);
3177 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3178 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3179 FileOffset
.u
.LowPart
= AdjustOffset
;
3181 BufferSize
= Length
+ OffsetAdjustment
;
3182 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3185 * It's ok to use paged pool, because this is a temporary buffer only used in
3186 * the loading of executables. The assumption is that MmCreateSection is
3187 * always called at low IRQLs and that these buffers don't survive a brief
3188 * initialization phase
3190 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3195 KeBugCheck(MEMORY_MANAGEMENT
);
3200 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3202 UsedSize
= (ULONG
)Iosb
.Information
;
3204 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3206 Status
= STATUS_IN_PAGE_ERROR
;
3207 ASSERT(!NT_SUCCESS(Status
));
3210 if(NT_SUCCESS(Status
))
3212 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3213 *AllocBase
= Buffer
;
3214 *ReadSize
= UsedSize
- OffsetAdjustment
;
3218 ExFreePoolWithTag(Buffer
, 'rXmM');
3225 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3226 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3227 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3232 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3236 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3238 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3239 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3246 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3250 MmspAssertSegmentsSorted(ImageSectionObject
);
3252 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3254 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3258 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3259 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3260 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3268 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3272 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3274 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3275 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3283 MmspCompareSegments(const void * x
,
3286 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3287 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3290 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3291 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3295 * Ensures an image section's segments are sorted in memory
3300 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3303 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3305 MmspAssertSegmentsSorted(ImageSectionObject
);
3309 qsort(ImageSectionObject
->Segments
,
3310 ImageSectionObject
->NrSegments
,
3311 sizeof(ImageSectionObject
->Segments
[0]),
3312 MmspCompareSegments
);
3318 * Ensures an image section's segments don't overlap in memory and don't have
3319 * gaps and don't have a null size. We let them map to overlapping file regions,
3320 * though - that's not necessarily an error
3325 MmspCheckSegmentBounds
3327 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3333 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3335 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3339 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3341 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3343 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3351 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3352 * page could be OK (Windows seems to be OK with them), and larger gaps
3353 * could lead to image sections spanning several discontiguous regions
3354 * (NtMapViewOfSection could then refuse to map them, and they could
3355 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3357 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3358 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3359 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3370 * Merges and pads an image section's segments until they all are page-aligned
3371 * and have a size that is a multiple of the page size
3376 MmspPageAlignSegments
3378 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3384 PMM_SECTION_SEGMENT EffectiveSegment
;
3386 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3388 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3393 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3395 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3398 * The first segment requires special handling
3402 ULONG_PTR VirtualAddress
;
3403 ULONG_PTR VirtualOffset
;
3405 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3407 /* Round down the virtual address to the nearest page */
3408 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3410 /* Round up the virtual size to the nearest page */
3411 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3412 EffectiveSegment
->Image
.VirtualAddress
;
3414 /* Adjust the raw address and size */
3415 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3417 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3423 * Garbage in, garbage out: unaligned base addresses make the file
3424 * offset point in curious and odd places, but that's what we were
3427 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3428 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3432 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3433 ULONG_PTR EndOfEffectiveSegment
;
3435 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3436 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3439 * The current segment begins exactly where the current effective
3440 * segment ended, therefore beginning a new effective segment
3442 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3445 ASSERT(LastSegment
<= i
);
3446 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3448 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3450 if (LastSegment
!= i
)
3453 * Copy the current segment. If necessary, the effective segment
3454 * will be expanded later
3456 *EffectiveSegment
= *Segment
;
3460 * Page-align the virtual size. We know for sure the virtual address
3463 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3464 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3467 * The current segment is still part of the current effective segment:
3468 * extend the effective segment to reflect this
3470 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3472 static const ULONG FlagsToProtection
[16] =
3480 PAGE_EXECUTE_READWRITE
,
3481 PAGE_EXECUTE_READWRITE
,
3486 PAGE_EXECUTE_WRITECOPY
,
3487 PAGE_EXECUTE_WRITECOPY
,
3488 PAGE_EXECUTE_WRITECOPY
,
3489 PAGE_EXECUTE_WRITECOPY
3492 unsigned ProtectionFlags
;
3495 * Extend the file size
3498 /* Unaligned segments must be contiguous within the file */
3499 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3500 EffectiveSegment
->RawLength
.QuadPart
))
3505 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3508 * Extend the virtual size
3510 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3512 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3513 EffectiveSegment
->Image
.VirtualAddress
;
3516 * Merge the protection
3518 EffectiveSegment
->Protection
|= Segment
->Protection
;
3520 /* Clean up redundance */
3521 ProtectionFlags
= 0;
3523 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3524 ProtectionFlags
|= 1 << 0;
3526 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3527 ProtectionFlags
|= 1 << 1;
3529 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3530 ProtectionFlags
|= 1 << 2;
3532 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3533 ProtectionFlags
|= 1 << 3;
3535 ASSERT(ProtectionFlags
< 16);
3536 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3538 /* If a segment was required to be shared and cannot, fail */
3539 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3540 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3546 * We assume no holes between segments at this point
3550 KeBugCheck(MEMORY_MANAGEMENT
);
3554 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3560 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3561 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3563 LARGE_INTEGER Offset
;
3565 PVOID FileHeaderBuffer
;
3566 ULONG FileHeaderSize
;
3568 ULONG OldNrSegments
;
3573 * Read the beginning of the file (2 pages). Should be enough to contain
3574 * all (or most) of the headers
3576 Offset
.QuadPart
= 0;
3578 /* FIXME: use FileObject instead of FileHandle */
3579 Status
= ExeFmtpReadFile (FileHandle
,
3586 if (!NT_SUCCESS(Status
))
3589 if (FileHeaderSize
== 0)
3591 ExFreePool(FileHeaderBuffer
);
3592 return STATUS_UNSUCCESSFUL
;
3596 * Look for a loader that can handle this executable
3598 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3600 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3603 /* FIXME: use FileObject instead of FileHandle */
3604 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3610 ExeFmtpAllocateSegments
);
3612 if (!NT_SUCCESS(Status
))
3614 if (ImageSectionObject
->Segments
)
3616 ExFreePool(ImageSectionObject
->Segments
);
3617 ImageSectionObject
->Segments
= NULL
;
3621 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3625 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3628 * No loader handled the format
3630 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3632 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3633 ASSERT(!NT_SUCCESS(Status
));
3636 if (!NT_SUCCESS(Status
))
3639 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3644 /* FIXME? are these values platform-dependent? */
3645 if(ImageSectionObject
->StackReserve
== 0)
3646 ImageSectionObject
->StackReserve
= 0x40000;
3648 if(ImageSectionObject
->StackCommit
== 0)
3649 ImageSectionObject
->StackCommit
= 0x1000;
3651 if(ImageSectionObject
->ImageBase
== 0)
3653 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3654 ImageSectionObject
->ImageBase
= 0x10000000;
3656 ImageSectionObject
->ImageBase
= 0x00400000;
3660 * And now the fun part: fixing the segments
3663 /* Sort them by virtual address */
3664 MmspSortSegments(ImageSectionObject
, Flags
);
3666 /* Ensure they don't overlap in memory */
3667 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3668 return STATUS_INVALID_IMAGE_FORMAT
;
3670 /* Ensure they are aligned */
3671 OldNrSegments
= ImageSectionObject
->NrSegments
;
3673 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3674 return STATUS_INVALID_IMAGE_FORMAT
;
3676 /* Trim them if the alignment phase merged some of them */
3677 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3679 PMM_SECTION_SEGMENT Segments
;
3680 SIZE_T SizeOfSegments
;
3682 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3684 Segments
= ExAllocatePoolWithTag(PagedPool
,
3686 TAG_MM_SECTION_SEGMENT
);
3688 if (Segments
== NULL
)
3689 return STATUS_INSUFFICIENT_RESOURCES
;
3691 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3692 ExFreePool(ImageSectionObject
->Segments
);
3693 ImageSectionObject
->Segments
= Segments
;
3696 /* And finish their initialization */
3697 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3699 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3700 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3701 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3704 ASSERT(NT_SUCCESS(Status
));
3709 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3710 ACCESS_MASK DesiredAccess
,
3711 POBJECT_ATTRIBUTES ObjectAttributes
,
3712 PLARGE_INTEGER UMaximumSize
,
3713 ULONG SectionPageProtection
,
3714 ULONG AllocationAttributes
,
3715 PFILE_OBJECT FileObject
)
3717 PROS_SECTION_OBJECT Section
;
3719 PMM_SECTION_SEGMENT SectionSegments
;
3720 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3723 if (FileObject
== NULL
)
3724 return STATUS_INVALID_FILE_FOR_SECTION
;
3727 * Create the section
3729 Status
= ObCreateObject (ExGetPreviousMode(),
3730 MmSectionObjectType
,
3732 ExGetPreviousMode(),
3734 sizeof(ROS_SECTION_OBJECT
),
3737 (PVOID
*)(PVOID
)&Section
);
3738 if (!NT_SUCCESS(Status
))
3740 ObDereferenceObject(FileObject
);
3747 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3748 Section
->Type
= 'SC';
3749 Section
->Size
= 'TN';
3750 Section
->SectionPageProtection
= SectionPageProtection
;
3751 Section
->AllocationAttributes
= AllocationAttributes
;
3755 * Initialized caching for this file object if previously caching
3756 * was initialized for the same on disk file
3758 Status
= CcTryToInitializeFileCache(FileObject
);
3760 Status
= STATUS_SUCCESS
;
3763 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3765 NTSTATUS StatusExeFmt
;
3767 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3768 if (ImageSectionObject
== NULL
)
3770 ObDereferenceObject(FileObject
);
3771 ObDereferenceObject(Section
);
3772 return(STATUS_NO_MEMORY
);
3775 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3777 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3779 if (!NT_SUCCESS(StatusExeFmt
))
3781 if(ImageSectionObject
->Segments
!= NULL
)
3782 ExFreePool(ImageSectionObject
->Segments
);
3784 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3785 ObDereferenceObject(Section
);
3786 ObDereferenceObject(FileObject
);
3787 return(StatusExeFmt
);
3790 Section
->ImageSection
= ImageSectionObject
;
3791 ASSERT(ImageSectionObject
->Segments
);
3796 Status
= MmspWaitForFileLock(FileObject
);
3797 if (!NT_SUCCESS(Status
))
3799 ExFreePool(ImageSectionObject
->Segments
);
3800 ExFreePool(ImageSectionObject
);
3801 ObDereferenceObject(Section
);
3802 ObDereferenceObject(FileObject
);
3806 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3807 ImageSectionObject
, NULL
))
3810 * An other thread has initialized the same image in the background
3812 ExFreePool(ImageSectionObject
->Segments
);
3813 ExFreePool(ImageSectionObject
);
3814 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3815 Section
->ImageSection
= ImageSectionObject
;
3816 SectionSegments
= ImageSectionObject
->Segments
;
3818 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3820 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3824 Status
= StatusExeFmt
;
3831 Status
= MmspWaitForFileLock(FileObject
);
3832 if (Status
!= STATUS_SUCCESS
)
3834 ObDereferenceObject(Section
);
3835 ObDereferenceObject(FileObject
);
3839 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3840 Section
->ImageSection
= ImageSectionObject
;
3841 SectionSegments
= ImageSectionObject
->Segments
;
3844 * Otherwise just reference all the section segments
3846 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3848 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3851 Status
= STATUS_SUCCESS
;
3853 Section
->FileObject
= FileObject
;
3855 CcRosReferenceCache(FileObject
);
3857 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3858 *SectionObject
= Section
;
3865 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3866 PROS_SECTION_OBJECT Section
,
3867 PMM_SECTION_SEGMENT Segment
,
3872 ULONG AllocationType
)
3876 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3878 if (Segment
->WriteCopy
)
3880 /* We have to do this because the not present fault
3881 * and access fault handlers depend on the protection
3882 * that should be granted AFTER the COW fault takes
3883 * place to be in Region->Protect. The not present fault
3884 * handler changes this to the correct protection for COW when
3885 * mapping the pages into the process's address space. If a COW
3886 * fault takes place, the access fault handler sets the page protection
3887 * to these values for the newly copied pages
3889 if (Protect
== PAGE_WRITECOPY
)
3890 Protect
= PAGE_READWRITE
;
3891 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3892 Protect
= PAGE_EXECUTE_READWRITE
;
3895 BoundaryAddressMultiple
.QuadPart
= 0;
3898 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
3899 LARGE_INTEGER FileOffset
;
3900 FileOffset
.QuadPart
= ViewOffset
;
3901 ObReferenceObject(Section
);
3902 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3905 Status
= MmCreateMemoryArea(AddressSpace
,
3906 MEMORY_AREA_SECTION_VIEW
,
3913 BoundaryAddressMultiple
);
3914 if (!NT_SUCCESS(Status
))
3916 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3917 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3921 ObReferenceObject((PVOID
)Section
);
3923 MArea
->Data
.SectionData
.Segment
= Segment
;
3924 MArea
->Data
.SectionData
.Section
= Section
;
3925 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3926 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3927 ViewSize
, 0, Protect
);
3929 return(STATUS_SUCCESS
);
3934 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3935 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3938 PFILE_OBJECT FileObject
;
3940 LARGE_INTEGER Offset
;
3941 SWAPENTRY SavedSwapEntry
;
3942 PROS_SECTION_OBJECT Section
;
3943 PMM_SECTION_SEGMENT Segment
;
3944 PMMSUPPORT AddressSpace
;
3947 AddressSpace
= (PMMSUPPORT
)Context
;
3948 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3950 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3952 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3953 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3955 Section
= MemoryArea
->Data
.SectionData
.Section
;
3956 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3958 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3959 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
3961 MmUnlockSectionSegment(Segment
);
3962 MmUnlockAddressSpace(AddressSpace
);
3964 MiWaitForPageEvent(NULL
, NULL
);
3966 MmLockAddressSpace(AddressSpace
);
3967 MmLockSectionSegment(Segment
);
3968 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3972 * For a dirty, datafile, non-private page mark it as dirty in the
3975 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3977 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3979 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3980 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3982 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)(Offset
.QuadPart
+ Segment
->Image
.FileOffset
));
3984 ASSERT(SwapEntry
== 0);
3993 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3995 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3996 KeBugCheck(MEMORY_MANAGEMENT
);
3998 MmFreeSwapPage(SwapEntry
);
4002 if (IS_SWAP_FROM_SSE(Entry
) ||
4003 Page
!= PFN_FROM_SSE(Entry
))
4008 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4010 DPRINT1("Found a private page in a pagefile section.\n");
4011 KeBugCheck(MEMORY_MANAGEMENT
);
4014 * Just dereference private pages
4016 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4017 if (SavedSwapEntry
!= 0)
4019 MmFreeSwapPage(SavedSwapEntry
);
4020 MmSetSavedSwapEntryPage(Page
, 0);
4022 MmDeleteRmap(Page
, Process
, Address
);
4023 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4027 MmDeleteRmap(Page
, Process
, Address
);
4028 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4034 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4038 PMEMORY_AREA MemoryArea
;
4039 PROS_SECTION_OBJECT Section
;
4040 PMM_SECTION_SEGMENT Segment
;
4041 PLIST_ENTRY CurrentEntry
;
4042 PMM_REGION CurrentRegion
;
4043 PLIST_ENTRY RegionListHead
;
4045 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4047 if (MemoryArea
== NULL
)
4049 return(STATUS_UNSUCCESSFUL
);
4052 MemoryArea
->DeleteInProgress
= TRUE
;
4053 Section
= MemoryArea
->Data
.SectionData
.Section
;
4054 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4057 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4058 return MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4061 MmLockSectionSegment(Segment
);
4063 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4064 while (!IsListEmpty(RegionListHead
))
4066 CurrentEntry
= RemoveHeadList(RegionListHead
);
4067 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4068 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4071 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4073 Status
= MmFreeMemoryArea(AddressSpace
,
4080 Status
= MmFreeMemoryArea(AddressSpace
,
4085 MmUnlockSectionSegment(Segment
);
4086 ObDereferenceObject(Section
);
4092 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4093 IN PVOID BaseAddress
,
4097 PMEMORY_AREA MemoryArea
;
4098 PMMSUPPORT AddressSpace
;
4099 PROS_SECTION_OBJECT Section
;
4100 PVOID ImageBaseAddress
= 0;
4102 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4103 Process
, BaseAddress
);
4107 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4109 MmLockAddressSpace(AddressSpace
);
4110 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4112 if (MemoryArea
== NULL
||
4113 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4114 MemoryArea
->DeleteInProgress
)
4116 ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4117 MmUnlockAddressSpace(AddressSpace
);
4118 return STATUS_NOT_MAPPED_VIEW
;
4121 MemoryArea
->DeleteInProgress
= TRUE
;
4123 Section
= MemoryArea
->Data
.SectionData
.Section
;
4125 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4129 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4130 PMM_SECTION_SEGMENT SectionSegments
;
4131 PMM_SECTION_SEGMENT Segment
;
4133 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4134 ImageSectionObject
= Section
->ImageSection
;
4135 SectionSegments
= ImageSectionObject
->Segments
;
4136 NrSegments
= ImageSectionObject
->NrSegments
;
4138 /* Search for the current segment within the section segments
4139 * and calculate the image base address */
4140 for (i
= 0; i
< NrSegments
; i
++)
4142 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4144 if (Segment
== &SectionSegments
[i
])
4146 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4151 if (i
>= NrSegments
)
4153 KeBugCheck(MEMORY_MANAGEMENT
);
4156 for (i
= 0; i
< NrSegments
; i
++)
4158 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4160 PVOID SBaseAddress
= (PVOID
)
4161 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4163 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4169 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4172 MmUnlockAddressSpace(AddressSpace
);
4174 /* Notify debugger */
4175 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4177 return(STATUS_SUCCESS
);
4184 * Queries the information of a section object.
4186 * @param SectionHandle
4187 * Handle to the section object. It must be opened with SECTION_QUERY
4189 * @param SectionInformationClass
4190 * Index to a certain information structure. Can be either
4191 * SectionBasicInformation or SectionImageInformation. The latter
4192 * is valid only for sections that were created with the SEC_IMAGE
4194 * @param SectionInformation
4195 * Caller supplies storage for resulting information.
4197 * Size of the supplied storage.
4198 * @param ResultLength
4206 NtQuerySection(IN HANDLE SectionHandle
,
4207 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4208 OUT PVOID SectionInformation
,
4209 IN SIZE_T SectionInformationLength
,
4210 OUT PSIZE_T ResultLength OPTIONAL
)
4212 PROS_SECTION_OBJECT Section
;
4213 KPROCESSOR_MODE PreviousMode
;
4217 PreviousMode
= ExGetPreviousMode();
4219 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4221 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4223 (ULONG
)SectionInformationLength
,
4228 if(!NT_SUCCESS(Status
))
4230 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4234 Status
= ObReferenceObjectByHandle(SectionHandle
,
4236 MmSectionObjectType
,
4238 (PVOID
*)(PVOID
)&Section
,
4240 if (NT_SUCCESS(Status
))
4242 switch (SectionInformationClass
)
4244 case SectionBasicInformation
:
4246 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4250 Sbi
->Attributes
= Section
->AllocationAttributes
;
4251 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4253 Sbi
->BaseAddress
= 0;
4254 Sbi
->Size
.QuadPart
= 0;
4258 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4259 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4262 if (ResultLength
!= NULL
)
4264 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4266 Status
= STATUS_SUCCESS
;
4268 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4270 Status
= _SEH2_GetExceptionCode();
4277 case SectionImageInformation
:
4279 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4283 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4284 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4286 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4287 ImageSectionObject
= Section
->ImageSection
;
4289 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4290 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4291 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4292 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4293 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4294 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4295 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4296 Sii
->Machine
= ImageSectionObject
->Machine
;
4297 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4300 if (ResultLength
!= NULL
)
4302 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4304 Status
= STATUS_SUCCESS
;
4306 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4308 Status
= _SEH2_GetExceptionCode();
4316 ObDereferenceObject(Section
);
4322 /**********************************************************************
4324 * MmMapViewOfSection
4327 * Maps a view of a section into the virtual address space of a
4332 * Pointer to the section object.
4335 * Pointer to the process.
4338 * Desired base address (or NULL) on entry;
4339 * Actual base address of the view on exit.
4342 * Number of high order address bits that must be zero.
4345 * Size in bytes of the initially committed section of
4349 * Offset in bytes from the beginning of the section
4350 * to the beginning of the view.
4353 * Desired length of map (or zero to map all) on entry
4354 * Actual length mapped on exit.
4356 * InheritDisposition
4357 * Specified how the view is to be shared with
4361 * Type of allocation for the pages.
4364 * Protection for the committed region of the view.
4372 MmMapViewOfSection(IN PVOID SectionObject
,
4373 IN PEPROCESS Process
,
4374 IN OUT PVOID
*BaseAddress
,
4375 IN ULONG_PTR ZeroBits
,
4376 IN SIZE_T CommitSize
,
4377 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4378 IN OUT PSIZE_T ViewSize
,
4379 IN SECTION_INHERIT InheritDisposition
,
4380 IN ULONG AllocationType
,
4383 PROS_SECTION_OBJECT Section
;
4384 PMMSUPPORT AddressSpace
;
4386 NTSTATUS Status
= STATUS_SUCCESS
;
4387 BOOLEAN NotAtBase
= FALSE
;
4389 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4391 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4392 return MmMapViewOfArm3Section(SectionObject
,
4406 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4408 return STATUS_INVALID_PAGE_PROTECTION
;
4412 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4413 AddressSpace
= &Process
->Vm
;
4415 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4417 MmLockAddressSpace(AddressSpace
);
4419 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4423 ULONG_PTR ImageBase
;
4425 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4426 PMM_SECTION_SEGMENT SectionSegments
;
4428 ImageSectionObject
= Section
->ImageSection
;
4429 SectionSegments
= ImageSectionObject
->Segments
;
4430 NrSegments
= ImageSectionObject
->NrSegments
;
4433 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4436 ImageBase
= ImageSectionObject
->ImageBase
;
4440 for (i
= 0; i
< NrSegments
; i
++)
4442 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4444 ULONG_PTR MaxExtent
;
4445 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4446 SectionSegments
[i
].Length
.QuadPart
);
4447 ImageSize
= max(ImageSize
, MaxExtent
);
4451 ImageSectionObject
->ImageSize
= (ULONG
)ImageSize
;
4453 /* Check for an illegal base address */
4454 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4456 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4459 /* Check there is enough space to map the section at that point. */
4460 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4461 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4463 /* Fail if the user requested a fixed base address. */
4464 if ((*BaseAddress
) != NULL
)
4466 MmUnlockAddressSpace(AddressSpace
);
4467 return(STATUS_UNSUCCESSFUL
);
4469 /* Otherwise find a gap to map the image. */
4470 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4473 MmUnlockAddressSpace(AddressSpace
);
4474 return(STATUS_UNSUCCESSFUL
);
4476 /* Remember that we loaded image at a different base address */
4480 for (i
= 0; i
< NrSegments
; i
++)
4482 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4484 PVOID SBaseAddress
= (PVOID
)
4485 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4486 MmLockSectionSegment(&SectionSegments
[i
]);
4487 Status
= MmMapViewOfSegment(AddressSpace
,
4489 &SectionSegments
[i
],
4491 SectionSegments
[i
].Length
.LowPart
,
4492 SectionSegments
[i
].Protection
,
4495 MmUnlockSectionSegment(&SectionSegments
[i
]);
4496 if (!NT_SUCCESS(Status
))
4498 MmUnlockAddressSpace(AddressSpace
);
4504 *BaseAddress
= (PVOID
)ImageBase
;
4505 *ViewSize
= ImageSize
;
4509 /* check for write access */
4510 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4511 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4513 MmUnlockAddressSpace(AddressSpace
);
4514 return STATUS_SECTION_PROTECTION
;
4516 /* check for read access */
4517 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4518 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4520 MmUnlockAddressSpace(AddressSpace
);
4521 return STATUS_SECTION_PROTECTION
;
4523 /* check for execute access */
4524 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4525 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4527 MmUnlockAddressSpace(AddressSpace
);
4528 return STATUS_SECTION_PROTECTION
;
4531 if (ViewSize
== NULL
)
4533 /* Following this pointer would lead to us to the dark side */
4534 /* What to do? Bugcheck? Return status? Do the mambo? */
4535 KeBugCheck(MEMORY_MANAGEMENT
);
4538 if (SectionOffset
== NULL
)
4544 ViewOffset
= SectionOffset
->u
.LowPart
;
4547 if ((ViewOffset
% PAGE_SIZE
) != 0)
4549 MmUnlockAddressSpace(AddressSpace
);
4550 return(STATUS_MAPPED_ALIGNMENT
);
4553 if ((*ViewSize
) == 0)
4555 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4557 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4559 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4562 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4564 MmLockSectionSegment(Section
->Segment
);
4565 Status
= MmMapViewOfSegment(AddressSpace
,
4572 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4573 MmUnlockSectionSegment(Section
->Segment
);
4574 if (!NT_SUCCESS(Status
))
4576 MmUnlockAddressSpace(AddressSpace
);
4581 MmUnlockAddressSpace(AddressSpace
);
4584 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4586 Status
= STATUS_SUCCESS
;
4595 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4596 IN PLARGE_INTEGER NewFileSize
)
4598 /* Check whether an ImageSectionObject exists */
4599 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4601 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4605 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4607 PMM_SECTION_SEGMENT Segment
;
4609 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4612 if (Segment
->ReferenceCount
!= 0)
4615 CC_FILE_SIZES FileSizes
;
4617 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4620 /* Check size of file */
4621 if (SectionObjectPointer
->SharedCacheMap
)
4623 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4628 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4637 /* Check size of file */
4638 if (SectionObjectPointer
->SharedCacheMap
)
4640 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4641 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4650 /* Something must gone wrong
4651 * how can we have a Section but no
4653 DPRINT("ERROR: DataSectionObject without reference!\n");
4657 DPRINT("FIXME: didn't check for outstanding write probes\n");
4669 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4670 IN MMFLUSH_TYPE FlushType
)
4672 BOOLEAN Result
= TRUE
;
4674 PMM_SECTION_SEGMENT Segment
;
4679 case MmFlushForDelete
:
4680 if (SectionObjectPointer
->ImageSectionObject
||
4681 SectionObjectPointer
->DataSectionObject
)
4686 CcRosSetRemoveOnClose(SectionObjectPointer
);
4689 case MmFlushForWrite
:
4691 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4693 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4696 if (SectionObjectPointer
->ImageSectionObject
) {
4697 DPRINT1("SectionObject has ImageSection\n");
4703 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4705 DPRINT("Result %d\n", Result
);
4717 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4718 OUT PVOID
* MappedBase
,
4719 IN OUT PSIZE_T ViewSize
)
4721 PROS_SECTION_OBJECT Section
;
4722 PMMSUPPORT AddressSpace
;
4726 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4728 return MiMapViewInSystemSpace(SectionObject
,
4734 DPRINT("MmMapViewInSystemSpace() called\n");
4736 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4737 AddressSpace
= MmGetKernelAddressSpace();
4739 MmLockAddressSpace(AddressSpace
);
4742 if ((*ViewSize
) == 0)
4744 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4746 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4748 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4751 MmLockSectionSegment(Section
->Segment
);
4754 Status
= MmMapViewOfSegment(AddressSpace
,
4763 MmUnlockSectionSegment(Section
->Segment
);
4764 MmUnlockAddressSpace(AddressSpace
);
4771 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4773 PMMSUPPORT AddressSpace
;
4776 DPRINT("MmUnmapViewInSystemSpace() called\n");
4778 AddressSpace
= MmGetKernelAddressSpace();
4780 MmLockAddressSpace(AddressSpace
);
4782 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4784 MmUnlockAddressSpace(AddressSpace
);
4789 /**********************************************************************
4794 * Creates a section object.
4797 * SectionObject (OUT)
4798 * Caller supplied storage for the resulting pointer
4799 * to a SECTION_OBJECT instance;
4802 * Specifies the desired access to the section can be a
4804 * STANDARD_RIGHTS_REQUIRED |
4806 * SECTION_MAP_WRITE |
4807 * SECTION_MAP_READ |
4808 * SECTION_MAP_EXECUTE
4810 * ObjectAttributes [OPTIONAL]
4811 * Initialized attributes for the object can be used
4812 * to create a named section;
4815 * Maximizes the size of the memory section. Must be
4816 * non-NULL for a page-file backed section.
4817 * If value specified for a mapped file and the file is
4818 * not large enough, file will be extended.
4820 * SectionPageProtection
4821 * Can be a combination of:
4827 * AllocationAttributes
4828 * Can be a combination of:
4833 * Handle to a file to create a section mapped to a file
4834 * instead of a memory backed section;
4845 MmCreateSection (OUT PVOID
* Section
,
4846 IN ACCESS_MASK DesiredAccess
,
4847 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4848 IN PLARGE_INTEGER MaximumSize
,
4849 IN ULONG SectionPageProtection
,
4850 IN ULONG AllocationAttributes
,
4851 IN HANDLE FileHandle OPTIONAL
,
4852 IN PFILE_OBJECT FileObject OPTIONAL
)
4855 ULONG Protection
, FileAccess
;
4856 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4858 /* Check if an ARM3 section is being created instead */
4859 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4861 if (!(FileObject
) && !(FileHandle
))
4863 return MmCreateArm3Section(Section
,
4867 SectionPageProtection
,
4868 AllocationAttributes
&~ 1,
4875 * Check the protection
4877 Protection
= SectionPageProtection
& ~(PAGE_GUARD
| PAGE_NOCACHE
);
4878 if (Protection
!= PAGE_READONLY
&&
4879 Protection
!= PAGE_READWRITE
&&
4880 Protection
!= PAGE_WRITECOPY
&&
4881 Protection
!= PAGE_EXECUTE
&&
4882 Protection
!= PAGE_EXECUTE_READ
&&
4883 Protection
!= PAGE_EXECUTE_READWRITE
&&
4884 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4886 return STATUS_INVALID_PAGE_PROTECTION
;
4889 if ((DesiredAccess
& SECTION_MAP_WRITE
) &&
4890 (Protection
== PAGE_READWRITE
||
4891 Protection
== PAGE_EXECUTE_READWRITE
) &&
4892 !(AllocationAttributes
& SEC_IMAGE
))
4894 DPRINT("Creating a section with WRITE access\n");
4895 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
| SYNCHRONIZE
;
4899 DPRINT("Creating a section with READ access\n");
4900 FileAccess
= FILE_READ_DATA
| SYNCHRONIZE
;
4903 /* FIXME: somehow combine this with the above checks */
4904 if (AllocationAttributes
& SEC_IMAGE
)
4905 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
4907 if (!FileObject
&& FileHandle
)
4909 Status
= ObReferenceObjectByHandle(FileHandle
,
4912 ExGetPreviousMode(),
4913 (PVOID
*)&FileObject
,
4915 if (!NT_SUCCESS(Status
))
4917 DPRINT("Failed: 0x%08lx\n", Status
);
4921 else if (FileObject
)
4922 ObReferenceObject(FileObject
);
4924 #ifndef NEWCC // A hack for initializing caching.
4925 // This is needed only in the old case.
4928 IO_STATUS_BLOCK Iosb
;
4931 LARGE_INTEGER ByteOffset
;
4932 ByteOffset
.QuadPart
= 0;
4933 Status
= ZwReadFile(FileHandle
,
4942 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
4944 // Caching is initialized...
4948 if (AllocationAttributes
& SEC_IMAGE
)
4950 Status
= MmCreateImageSection(SectionObject
,
4954 SectionPageProtection
,
4955 AllocationAttributes
,
4959 else if (FileHandle
!= NULL
)
4961 Status
= MmCreateDataFileSection(SectionObject
,
4965 SectionPageProtection
,
4966 AllocationAttributes
,
4969 ObDereferenceObject(FileObject
);
4972 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
4974 Status
= MmCreateCacheSection(SectionObject
,
4978 SectionPageProtection
,
4979 AllocationAttributes
,
4985 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
4987 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
4989 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
4990 Status
= MmCreatePageFileSection(SectionObject
,
4994 SectionPageProtection
,
4995 AllocationAttributes
);