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 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1767 KeBugCheck(MEMORY_MANAGEMENT
);
1770 if (!NT_SUCCESS(Status
))
1772 DPRINT1("Unable to create virtual mapping\n");
1773 KeBugCheck(MEMORY_MANAGEMENT
);
1777 * Unshare the old page.
1779 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1780 MmInsertRmap(NewPage
, Process
, PAddress
);
1781 MmLockSectionSegment(Segment
);
1782 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1783 MmUnlockSectionSegment(Segment
);
1785 MiSetPageEvent(Process
, Address
);
1786 DPRINT("Address 0x%.8X\n", Address
);
1787 return(STATUS_SUCCESS
);
1791 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1793 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1795 PFN_NUMBER Page
= 0;
1797 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1800 MmLockAddressSpace(&Process
->Vm
);
1803 MmDeleteVirtualMapping(Process
,
1810 PageOutContext
->WasDirty
= TRUE
;
1812 if (!PageOutContext
->Private
)
1814 MmLockSectionSegment(PageOutContext
->Segment
);
1815 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1816 PageOutContext
->Segment
,
1817 &PageOutContext
->Offset
,
1818 PageOutContext
->WasDirty
,
1820 &PageOutContext
->SectionEntry
);
1821 MmUnlockSectionSegment(PageOutContext
->Segment
);
1825 MmUnlockAddressSpace(&Process
->Vm
);
1828 if (PageOutContext
->Private
)
1830 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1836 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1837 MEMORY_AREA
* MemoryArea
,
1838 PVOID Address
, ULONG_PTR Entry
)
1841 MM_SECTION_PAGEOUT_CONTEXT Context
;
1842 SWAPENTRY SwapEntry
;
1843 ULONGLONG FileOffset
;
1845 PFILE_OBJECT FileObject
;
1849 BOOLEAN DirectMapped
;
1850 BOOLEAN IsImageSection
;
1851 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1854 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1857 * Get the segment and section.
1859 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1860 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1861 Context
.SectionEntry
= Entry
;
1862 Context
.CallingProcess
= Process
;
1864 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1865 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1866 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1868 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1870 FileObject
= Context
.Section
->FileObject
;
1871 DirectMapped
= FALSE
;
1873 MmLockSectionSegment(Context
.Segment
);
1876 if (FileObject
!= NULL
&&
1877 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1879 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1882 * If the file system is letting us go directly to the cache and the
1883 * memory area was mapped at an offset in the file which is page aligned
1884 * then note this is a direct mapped page.
1886 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1887 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1889 DirectMapped
= TRUE
;
1896 * This should never happen since mappings of physical memory are never
1897 * placed in the rmap lists.
1899 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1901 DPRINT1("Trying to page out from physical memory section address 0x%X "
1902 "process %d\n", Address
,
1903 Process
? Process
->UniqueProcessId
: 0);
1904 KeBugCheck(MEMORY_MANAGEMENT
);
1908 * Get the section segment entry and the physical address.
1910 if (!MmIsPagePresent(Process
, Address
))
1912 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1913 Process
? Process
->UniqueProcessId
: 0, Address
);
1914 KeBugCheck(MEMORY_MANAGEMENT
);
1916 Page
= MmGetPfnForProcess(Process
, Address
);
1917 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1920 * Check the reference count to ensure this page can be paged out
1922 if (MmGetReferenceCountPage(Page
) != 1)
1924 DPRINT("Cannot page out locked section page: 0x%p (RefCount: %d)\n",
1925 Page
, MmGetReferenceCountPage(Page
));
1926 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1927 MmUnlockSectionSegment(Context
.Segment
);
1928 return STATUS_UNSUCCESSFUL
;
1932 * Prepare the context structure for the rmap delete call.
1934 MmUnlockSectionSegment(Context
.Segment
);
1935 Context
.WasDirty
= FALSE
;
1936 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1937 IS_SWAP_FROM_SSE(Entry
) ||
1938 PFN_FROM_SSE(Entry
) != Page
)
1940 Context
.Private
= TRUE
;
1944 Context
.Private
= FALSE
;
1948 * Take an additional reference to the page or the cache segment.
1950 if (DirectMapped
&& !Context
.Private
)
1952 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
1954 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1955 KeBugCheck(MEMORY_MANAGEMENT
);
1960 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1961 MmReferencePage(Page
);
1962 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1965 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1967 /* Since we passed in a surrogate, we'll get back the page entry
1968 * state in our context. This is intended to make intermediate
1969 * decrements of share count not release the wait entry.
1971 Entry
= Context
.SectionEntry
;
1974 * If this wasn't a private page then we should have reduced the entry to
1975 * zero by deleting all the rmaps.
1977 if (!Context
.Private
&& Entry
!= 0)
1979 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1980 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1982 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
1987 * If the page wasn't dirty then we can just free it as for a readonly page.
1988 * Since we unmapped all the mappings above we know it will not suddenly
1990 * If the page is from a pagefile section and has no swap entry,
1991 * we can't free the page at this point.
1993 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1994 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1996 if (Context
.Private
)
1998 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1999 Context
.WasDirty
? "dirty" : "clean", Address
);
2000 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2002 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2004 MmSetSavedSwapEntryPage(Page
, 0);
2005 MmLockSectionSegment(Context
.Segment
);
2006 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2007 MmUnlockSectionSegment(Context
.Segment
);
2008 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2009 MiSetPageEvent(NULL
, NULL
);
2010 return(STATUS_SUCCESS
);
2013 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2015 if (Context
.Private
)
2017 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2018 Context
.WasDirty
? "dirty" : "clean", Address
);
2019 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2021 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2023 MmSetSavedSwapEntryPage(Page
, 0);
2026 MmLockSectionSegment(Context
.Segment
);
2027 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2028 MmUnlockSectionSegment(Context
.Segment
);
2030 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2031 MiSetPageEvent(NULL
, NULL
);
2032 return(STATUS_SUCCESS
);
2035 else if (!Context
.Private
&& DirectMapped
)
2039 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2041 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2044 Status
= CcRosUnmapCacheSegment(Bcb
, (ULONG
)FileOffset
, FALSE
);
2046 Status
= STATUS_SUCCESS
;
2049 if (!NT_SUCCESS(Status
))
2051 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2052 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Bcb
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2055 MiSetPageEvent(NULL
, NULL
);
2056 return(STATUS_SUCCESS
);
2058 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2062 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2064 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2066 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2067 MiSetPageEvent(NULL
, NULL
);
2068 return(STATUS_SUCCESS
);
2070 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2072 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2073 MmSetSavedSwapEntryPage(Page
, 0);
2074 MmLockAddressSpace(AddressSpace
);
2075 Status
= MmCreatePageFileMapping(Process
,
2078 MmUnlockAddressSpace(AddressSpace
);
2079 if (!NT_SUCCESS(Status
))
2081 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2082 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2084 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2085 MiSetPageEvent(NULL
, NULL
);
2086 return(STATUS_SUCCESS
);
2090 * If necessary, allocate an entry in the paging file for this page
2094 SwapEntry
= MmAllocSwapPage();
2097 MmShowOutOfSpaceMessagePagingFile();
2098 MmLockAddressSpace(AddressSpace
);
2100 * For private pages restore the old mappings.
2102 if (Context
.Private
)
2104 Status
= MmCreateVirtualMapping(Process
,
2106 MemoryArea
->Protect
,
2109 MmSetDirtyPage(Process
, Address
);
2118 * For non-private pages if the page wasn't direct mapped then
2119 * set it back into the section segment entry so we don't loose
2120 * our copy. Otherwise it will be handled by the cache manager.
2122 Status
= MmCreateVirtualMapping(Process
,
2124 MemoryArea
->Protect
,
2127 MmSetDirtyPage(Process
, Address
);
2131 // If we got here, the previous entry should have been a wait
2132 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2133 MmLockSectionSegment(Context
.Segment
);
2134 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2135 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2136 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2137 MmUnlockSectionSegment(Context
.Segment
);
2139 MmUnlockAddressSpace(AddressSpace
);
2140 MiSetPageEvent(NULL
, NULL
);
2141 return(STATUS_PAGEFILE_QUOTA
);
2146 * Write the page to the pagefile
2148 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2149 if (!NT_SUCCESS(Status
))
2151 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2154 * As above: undo our actions.
2155 * FIXME: Also free the swap page.
2157 MmLockAddressSpace(AddressSpace
);
2158 if (Context
.Private
)
2160 Status
= MmCreateVirtualMapping(Process
,
2162 MemoryArea
->Protect
,
2165 MmSetDirtyPage(Process
, Address
);
2172 Status
= MmCreateVirtualMapping(Process
,
2174 MemoryArea
->Protect
,
2177 MmSetDirtyPage(Process
, Address
);
2181 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2182 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2184 MmUnlockAddressSpace(AddressSpace
);
2185 MiSetPageEvent(NULL
, NULL
);
2186 return(STATUS_UNSUCCESSFUL
);
2190 * Otherwise we have succeeded.
2192 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2193 MmSetSavedSwapEntryPage(Page
, 0);
2194 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2195 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2197 MmLockSectionSegment(Context
.Segment
);
2198 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2199 MmUnlockSectionSegment(Context
.Segment
);
2203 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2206 if (Context
.Private
)
2208 MmLockAddressSpace(AddressSpace
);
2209 MmLockSectionSegment(Context
.Segment
);
2210 Status
= MmCreatePageFileMapping(Process
,
2213 /* We had placed a wait entry upon entry ... replace it before leaving */
2214 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2215 MmUnlockSectionSegment(Context
.Segment
);
2216 MmUnlockAddressSpace(AddressSpace
);
2217 if (!NT_SUCCESS(Status
))
2219 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2220 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2225 MmLockAddressSpace(AddressSpace
);
2226 MmLockSectionSegment(Context
.Segment
);
2227 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2228 /* We had placed a wait entry upon entry ... replace it before leaving */
2229 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2230 MmUnlockSectionSegment(Context
.Segment
);
2231 MmUnlockAddressSpace(AddressSpace
);
2234 MiSetPageEvent(NULL
, NULL
);
2235 return(STATUS_SUCCESS
);
2240 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2241 PMEMORY_AREA MemoryArea
,
2245 LARGE_INTEGER Offset
;
2246 PROS_SECTION_OBJECT Section
;
2247 PMM_SECTION_SEGMENT Segment
;
2249 SWAPENTRY SwapEntry
;
2253 PFILE_OBJECT FileObject
;
2255 BOOLEAN DirectMapped
;
2256 BOOLEAN IsImageSection
;
2257 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2259 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2261 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2262 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2265 * Get the segment and section.
2267 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2268 Section
= MemoryArea
->Data
.SectionData
.Section
;
2269 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2271 FileObject
= Section
->FileObject
;
2272 DirectMapped
= FALSE
;
2273 if (FileObject
!= NULL
&&
2274 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2276 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2279 * If the file system is letting us go directly to the cache and the
2280 * memory area was mapped at an offset in the file which is page aligned
2281 * then note this is a direct mapped page.
2283 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2284 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2286 DirectMapped
= TRUE
;
2291 * This should never happen since mappings of physical memory are never
2292 * placed in the rmap lists.
2294 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2296 DPRINT1("Trying to write back page from physical memory mapped at %X "
2297 "process %d\n", Address
,
2298 Process
? Process
->UniqueProcessId
: 0);
2299 KeBugCheck(MEMORY_MANAGEMENT
);
2303 * Get the section segment entry and the physical address.
2305 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2306 if (!MmIsPagePresent(Process
, Address
))
2308 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2309 Process
? Process
->UniqueProcessId
: 0, Address
);
2310 KeBugCheck(MEMORY_MANAGEMENT
);
2312 Page
= MmGetPfnForProcess(Process
, Address
);
2313 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2316 * Check for a private (COWed) page.
2318 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2319 IS_SWAP_FROM_SSE(Entry
) ||
2320 PFN_FROM_SSE(Entry
) != Page
)
2330 * Speculatively set all mappings of the page to clean.
2332 MmSetCleanAllRmaps(Page
);
2335 * If this page was direct mapped from the cache then the cache manager
2336 * will take care of writing it back to disk.
2338 if (DirectMapped
&& !Private
)
2340 LARGE_INTEGER SOffset
;
2341 ASSERT(SwapEntry
== 0);
2342 SOffset
.QuadPart
= Offset
.QuadPart
+ Segment
->Image
.FileOffset
;
2344 CcRosMarkDirtyCacheSegment(Bcb
, Offset
.LowPart
);
2346 MmLockSectionSegment(Segment
);
2347 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2348 MmUnlockSectionSegment(Segment
);
2349 MiSetPageEvent(NULL
, NULL
);
2350 return(STATUS_SUCCESS
);
2354 * If necessary, allocate an entry in the paging file for this page
2358 SwapEntry
= MmAllocSwapPage();
2361 MmSetDirtyAllRmaps(Page
);
2362 MiSetPageEvent(NULL
, NULL
);
2363 return(STATUS_PAGEFILE_QUOTA
);
2365 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2369 * Write the page to the pagefile
2371 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2372 if (!NT_SUCCESS(Status
))
2374 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2376 MmSetDirtyAllRmaps(Page
);
2377 MiSetPageEvent(NULL
, NULL
);
2378 return(STATUS_UNSUCCESSFUL
);
2382 * Otherwise we have succeeded.
2384 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2385 MiSetPageEvent(NULL
, NULL
);
2386 return(STATUS_SUCCESS
);
2390 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2398 PMEMORY_AREA MemoryArea
;
2399 PMM_SECTION_SEGMENT Segment
;
2400 BOOLEAN DoCOW
= FALSE
;
2402 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2404 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2405 ASSERT(MemoryArea
!= NULL
);
2406 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2407 MmLockSectionSegment(Segment
);
2409 if ((Segment
->WriteCopy
) &&
2410 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2415 if (OldProtect
!= NewProtect
)
2417 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2419 SWAPENTRY SwapEntry
;
2420 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2421 ULONG Protect
= NewProtect
;
2423 /* Wait for a wait entry to disappear */
2425 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2426 if (SwapEntry
!= MM_WAIT_ENTRY
)
2428 MiWaitForPageEvent(Process
, Address
);
2432 * If we doing COW for this segment then check if the page is
2435 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2437 LARGE_INTEGER Offset
;
2441 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2442 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2443 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2445 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2446 * IS_SWAP_FROM_SSE and we'll do the right thing.
2448 Page
= MmGetPfnForProcess(Process
, Address
);
2450 Protect
= PAGE_READONLY
;
2451 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2452 IS_SWAP_FROM_SSE(Entry
) ||
2453 PFN_FROM_SSE(Entry
) != Page
)
2455 Protect
= NewProtect
;
2459 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2461 MmSetPageProtect(Process
, Address
,
2467 MmUnlockSectionSegment(Segment
);
2472 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2473 PMEMORY_AREA MemoryArea
,
2481 ULONG_PTR MaxLength
;
2483 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2484 if (Length
> MaxLength
)
2485 Length
= (ULONG
)MaxLength
;
2487 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2488 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2490 ASSERT(Region
!= NULL
);
2492 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2493 Region
->Protect
!= Protect
)
2495 return STATUS_INVALID_PAGE_PROTECTION
;
2498 *OldProtect
= Region
->Protect
;
2499 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2500 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2501 BaseAddress
, Length
, Region
->Type
, Protect
,
2502 MmAlterViewAttributes
);
2508 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2510 PMEMORY_BASIC_INFORMATION Info
,
2511 PSIZE_T ResultLength
)
2514 PVOID RegionBaseAddress
;
2515 PROS_SECTION_OBJECT Section
;
2516 PMM_SECTION_SEGMENT Segment
;
2518 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2519 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2520 Address
, &RegionBaseAddress
);
2523 return STATUS_UNSUCCESSFUL
;
2526 Section
= MemoryArea
->Data
.SectionData
.Section
;
2527 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2529 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2530 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2531 Info
->Type
= MEM_IMAGE
;
2535 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2536 Info
->Type
= MEM_MAPPED
;
2538 Info
->BaseAddress
= RegionBaseAddress
;
2539 Info
->AllocationProtect
= MemoryArea
->Protect
;
2540 Info
->RegionSize
= Region
->Length
;
2541 Info
->State
= MEM_COMMIT
;
2542 Info
->Protect
= Region
->Protect
;
2544 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2545 return(STATUS_SUCCESS
);
2550 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2553 LARGE_INTEGER Offset
;
2555 SWAPENTRY SavedSwapEntry
;
2560 MmLockSectionSegment(Segment
);
2562 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2563 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2565 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2568 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2569 if (IS_SWAP_FROM_SSE(Entry
))
2571 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2575 Page
= PFN_FROM_SSE(Entry
);
2576 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2577 if (SavedSwapEntry
!= 0)
2579 MmSetSavedSwapEntryPage(Page
, 0);
2580 MmFreeSwapPage(SavedSwapEntry
);
2582 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2587 MmUnlockSectionSegment(Segment
);
2591 MmpDeleteSection(PVOID ObjectBody
)
2593 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2595 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2596 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2601 PMM_SECTION_SEGMENT SectionSegments
;
2604 * NOTE: Section->ImageSection can be NULL for short time
2605 * during the section creating. If we fail for some reason
2606 * until the image section is properly initialized we shouldn't
2607 * process further here.
2609 if (Section
->ImageSection
== NULL
)
2612 SectionSegments
= Section
->ImageSection
->Segments
;
2613 NrSegments
= Section
->ImageSection
->NrSegments
;
2615 for (i
= 0; i
< NrSegments
; i
++)
2617 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2619 MmLockSectionSegment(&SectionSegments
[i
]);
2621 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2622 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2624 MmUnlockSectionSegment(&SectionSegments
[i
]);
2627 MmpFreePageFileSegment(&SectionSegments
[i
]);
2633 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2636 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2639 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2641 DPRINT("Freeing section segment\n");
2642 Section
->Segment
= NULL
;
2643 MmFinalizeSegment(Segment
);
2647 DPRINT("RefCount %d\n", RefCount
);
2654 * NOTE: Section->Segment can be NULL for short time
2655 * during the section creating.
2657 if (Section
->Segment
== NULL
)
2660 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2662 MmpFreePageFileSegment(Section
->Segment
);
2663 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2664 ExFreePool(Section
->Segment
);
2665 Section
->Segment
= NULL
;
2669 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2672 if (Section
->FileObject
!= NULL
)
2675 CcRosDereferenceCache(Section
->FileObject
);
2677 ObDereferenceObject(Section
->FileObject
);
2678 Section
->FileObject
= NULL
;
2683 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2685 IN ACCESS_MASK GrantedAccess
,
2686 IN ULONG ProcessHandleCount
,
2687 IN ULONG SystemHandleCount
)
2689 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2690 Object
, ProcessHandleCount
);
2696 MmCreatePhysicalMemorySection(VOID
)
2698 PROS_SECTION_OBJECT PhysSection
;
2700 OBJECT_ATTRIBUTES Obj
;
2701 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2702 LARGE_INTEGER SectionSize
;
2706 * Create the section mapping physical memory
2708 SectionSize
.QuadPart
= 0xFFFFFFFF;
2709 InitializeObjectAttributes(&Obj
,
2714 Status
= MmCreateSection((PVOID
)&PhysSection
,
2718 PAGE_EXECUTE_READWRITE
,
2722 if (!NT_SUCCESS(Status
))
2724 DPRINT1("Failed to create PhysicalMemory section\n");
2725 KeBugCheck(MEMORY_MANAGEMENT
);
2727 Status
= ObInsertObject(PhysSection
,
2733 if (!NT_SUCCESS(Status
))
2735 ObDereferenceObject(PhysSection
);
2737 ObCloseHandle(Handle
, KernelMode
);
2738 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2739 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2741 return(STATUS_SUCCESS
);
2747 MmInitSectionImplementation(VOID
)
2749 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2750 UNICODE_STRING Name
;
2752 DPRINT("Creating Section Object Type\n");
2754 /* Initialize the section based root */
2755 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2756 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2758 /* Initialize the Section object type */
2759 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2760 RtlInitUnicodeString(&Name
, L
"Section");
2761 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2762 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2763 ObjectTypeInitializer
.PoolType
= PagedPool
;
2764 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2765 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2766 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2767 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2768 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2769 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2771 MmCreatePhysicalMemorySection();
2773 return(STATUS_SUCCESS
);
2778 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2779 ACCESS_MASK DesiredAccess
,
2780 POBJECT_ATTRIBUTES ObjectAttributes
,
2781 PLARGE_INTEGER UMaximumSize
,
2782 ULONG SectionPageProtection
,
2783 ULONG AllocationAttributes
)
2785 * Create a section which is backed by the pagefile
2788 LARGE_INTEGER MaximumSize
;
2789 PROS_SECTION_OBJECT Section
;
2790 PMM_SECTION_SEGMENT Segment
;
2793 if (UMaximumSize
== NULL
)
2795 return(STATUS_UNSUCCESSFUL
);
2797 MaximumSize
= *UMaximumSize
;
2800 * Create the section
2802 Status
= ObCreateObject(ExGetPreviousMode(),
2803 MmSectionObjectType
,
2805 ExGetPreviousMode(),
2807 sizeof(ROS_SECTION_OBJECT
),
2810 (PVOID
*)(PVOID
)&Section
);
2811 if (!NT_SUCCESS(Status
))
2819 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2820 Section
->Type
= 'SC';
2821 Section
->Size
= 'TN';
2822 Section
->SectionPageProtection
= SectionPageProtection
;
2823 Section
->AllocationAttributes
= AllocationAttributes
;
2824 Section
->MaximumSize
= MaximumSize
;
2825 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2826 TAG_MM_SECTION_SEGMENT
);
2827 if (Segment
== NULL
)
2829 ObDereferenceObject(Section
);
2830 return(STATUS_NO_MEMORY
);
2832 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2833 Section
->Segment
= Segment
;
2834 Segment
->ReferenceCount
= 1;
2835 ExInitializeFastMutex(&Segment
->Lock
);
2836 Segment
->Image
.FileOffset
= 0;
2837 Segment
->Protection
= SectionPageProtection
;
2838 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2839 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2840 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2841 Segment
->WriteCopy
= FALSE
;
2842 Segment
->Image
.VirtualAddress
= 0;
2843 Segment
->Image
.Characteristics
= 0;
2844 *SectionObject
= Section
;
2845 MiInitializeSectionPageTable(Segment
);
2846 return(STATUS_SUCCESS
);
2851 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2852 ACCESS_MASK DesiredAccess
,
2853 POBJECT_ATTRIBUTES ObjectAttributes
,
2854 PLARGE_INTEGER UMaximumSize
,
2855 ULONG SectionPageProtection
,
2856 ULONG AllocationAttributes
,
2859 * Create a section backed by a data file
2862 PROS_SECTION_OBJECT Section
;
2864 LARGE_INTEGER MaximumSize
;
2865 PFILE_OBJECT FileObject
;
2866 PMM_SECTION_SEGMENT Segment
;
2868 IO_STATUS_BLOCK Iosb
;
2869 LARGE_INTEGER Offset
;
2871 FILE_STANDARD_INFORMATION FileInfo
;
2875 * Create the section
2877 Status
= ObCreateObject(ExGetPreviousMode(),
2878 MmSectionObjectType
,
2880 ExGetPreviousMode(),
2882 sizeof(ROS_SECTION_OBJECT
),
2886 if (!NT_SUCCESS(Status
))
2893 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2894 Section
->Type
= 'SC';
2895 Section
->Size
= 'TN';
2896 Section
->SectionPageProtection
= SectionPageProtection
;
2897 Section
->AllocationAttributes
= AllocationAttributes
;
2900 * Reference the file handle
2902 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2903 Status
= ObReferenceObjectByHandle(FileHandle
,
2906 ExGetPreviousMode(),
2907 (PVOID
*)(PVOID
)&FileObject
,
2909 if (!NT_SUCCESS(Status
))
2911 ObDereferenceObject(Section
);
2916 * FIXME: This is propably not entirely correct. We can't look into
2917 * the standard FCB header because it might not be initialized yet
2918 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2919 * standard file information is filled on first request).
2921 Status
= IoQueryFileInformation(FileObject
,
2922 FileStandardInformation
,
2923 sizeof(FILE_STANDARD_INFORMATION
),
2926 Iosb
.Information
= Length
;
2927 if (!NT_SUCCESS(Status
))
2929 ObDereferenceObject(Section
);
2930 ObDereferenceObject(FileObject
);
2935 * FIXME: Revise this once a locking order for file size changes is
2938 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2940 MaximumSize
= *UMaximumSize
;
2944 MaximumSize
= FileInfo
.EndOfFile
;
2945 /* Mapping zero-sized files isn't allowed. */
2946 if (MaximumSize
.QuadPart
== 0)
2948 ObDereferenceObject(Section
);
2949 ObDereferenceObject(FileObject
);
2950 return STATUS_FILE_INVALID
;
2954 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2956 Status
= IoSetInformation(FileObject
,
2957 FileAllocationInformation
,
2958 sizeof(LARGE_INTEGER
),
2960 if (!NT_SUCCESS(Status
))
2962 ObDereferenceObject(Section
);
2963 ObDereferenceObject(FileObject
);
2964 return(STATUS_SECTION_NOT_EXTENDED
);
2968 if (FileObject
->SectionObjectPointer
== NULL
||
2969 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2972 * Read a bit so caching is initiated for the file object.
2973 * This is only needed because MiReadPage currently cannot
2974 * handle non-cached streams.
2976 Offset
.QuadPart
= 0;
2977 Status
= ZwReadFile(FileHandle
,
2986 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2988 ObDereferenceObject(Section
);
2989 ObDereferenceObject(FileObject
);
2992 if (FileObject
->SectionObjectPointer
== NULL
||
2993 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2995 /* FIXME: handle this situation */
2996 ObDereferenceObject(Section
);
2997 ObDereferenceObject(FileObject
);
2998 return STATUS_INVALID_PARAMETER
;
3005 Status
= MmspWaitForFileLock(FileObject
);
3006 if (Status
!= STATUS_SUCCESS
)
3008 ObDereferenceObject(Section
);
3009 ObDereferenceObject(FileObject
);
3014 * If this file hasn't been mapped as a data file before then allocate a
3015 * section segment to describe the data file mapping
3017 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3019 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3020 TAG_MM_SECTION_SEGMENT
);
3021 if (Segment
== NULL
)
3023 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3024 ObDereferenceObject(Section
);
3025 ObDereferenceObject(FileObject
);
3026 return(STATUS_NO_MEMORY
);
3028 Section
->Segment
= Segment
;
3029 Segment
->ReferenceCount
= 1;
3030 ExInitializeFastMutex(&Segment
->Lock
);
3032 * Set the lock before assigning the segment to the file object
3034 ExAcquireFastMutex(&Segment
->Lock
);
3035 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3037 Segment
->Image
.FileOffset
= 0;
3038 Segment
->Protection
= SectionPageProtection
;
3039 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3040 Segment
->Image
.Characteristics
= 0;
3041 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3042 if (AllocationAttributes
& SEC_RESERVE
)
3044 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3048 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3049 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3051 Segment
->Image
.VirtualAddress
= 0;
3052 Segment
->Locked
= TRUE
;
3053 MiInitializeSectionPageTable(Segment
);
3058 * If the file is already mapped as a data file then we may need
3062 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3064 Section
->Segment
= Segment
;
3065 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3066 MmLockSectionSegment(Segment
);
3068 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3069 !(AllocationAttributes
& SEC_RESERVE
))
3071 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3072 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3075 MmUnlockSectionSegment(Segment
);
3076 Section
->FileObject
= FileObject
;
3077 Section
->MaximumSize
= MaximumSize
;
3079 CcRosReferenceCache(FileObject
);
3081 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3082 *SectionObject
= Section
;
3083 return(STATUS_SUCCESS
);
3087 TODO: not that great (declaring loaders statically, having to declare all of
3088 them, having to keep them extern, etc.), will fix in the future
3090 extern NTSTATUS NTAPI PeFmtCreateSection
3092 IN CONST VOID
* FileHeader
,
3093 IN SIZE_T FileHeaderSize
,
3095 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3097 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3098 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3101 extern NTSTATUS NTAPI ElfFmtCreateSection
3103 IN CONST VOID
* FileHeader
,
3104 IN SIZE_T FileHeaderSize
,
3106 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3108 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3109 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3112 /* TODO: this is a standard DDK/PSDK macro */
3113 #ifndef RTL_NUMBER_OF
3114 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3117 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3128 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3130 SIZE_T SizeOfSegments
;
3131 PMM_SECTION_SEGMENT Segments
;
3133 /* TODO: check for integer overflow */
3134 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3136 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3138 TAG_MM_SECTION_SEGMENT
);
3141 RtlZeroMemory(Segments
, SizeOfSegments
);
3149 ExeFmtpReadFile(IN PVOID File
,
3150 IN PLARGE_INTEGER Offset
,
3153 OUT PVOID
* AllocBase
,
3154 OUT PULONG ReadSize
)
3157 LARGE_INTEGER FileOffset
;
3159 ULONG OffsetAdjustment
;
3163 PFILE_OBJECT FileObject
= File
;
3164 IO_STATUS_BLOCK Iosb
;
3166 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3170 KeBugCheck(MEMORY_MANAGEMENT
);
3173 FileOffset
= *Offset
;
3175 /* Negative/special offset: it cannot be used in this context */
3176 if(FileOffset
.u
.HighPart
< 0)
3178 KeBugCheck(MEMORY_MANAGEMENT
);
3181 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3182 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3183 FileOffset
.u
.LowPart
= AdjustOffset
;
3185 BufferSize
= Length
+ OffsetAdjustment
;
3186 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3189 * It's ok to use paged pool, because this is a temporary buffer only used in
3190 * the loading of executables. The assumption is that MmCreateSection is
3191 * always called at low IRQLs and that these buffers don't survive a brief
3192 * initialization phase
3194 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3199 KeBugCheck(MEMORY_MANAGEMENT
);
3204 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3206 UsedSize
= (ULONG
)Iosb
.Information
;
3208 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3210 Status
= STATUS_IN_PAGE_ERROR
;
3211 ASSERT(!NT_SUCCESS(Status
));
3214 if(NT_SUCCESS(Status
))
3216 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3217 *AllocBase
= Buffer
;
3218 *ReadSize
= UsedSize
- OffsetAdjustment
;
3222 ExFreePoolWithTag(Buffer
, 'rXmM');
3229 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3230 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3231 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3236 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3240 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3242 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3243 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3250 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3254 MmspAssertSegmentsSorted(ImageSectionObject
);
3256 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3258 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3262 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3263 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3264 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3272 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3276 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3278 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3279 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3287 MmspCompareSegments(const void * x
,
3290 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3291 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3294 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3295 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3299 * Ensures an image section's segments are sorted in memory
3304 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3307 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3309 MmspAssertSegmentsSorted(ImageSectionObject
);
3313 qsort(ImageSectionObject
->Segments
,
3314 ImageSectionObject
->NrSegments
,
3315 sizeof(ImageSectionObject
->Segments
[0]),
3316 MmspCompareSegments
);
3322 * Ensures an image section's segments don't overlap in memory and don't have
3323 * gaps and don't have a null size. We let them map to overlapping file regions,
3324 * though - that's not necessarily an error
3329 MmspCheckSegmentBounds
3331 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3337 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3339 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3343 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3345 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3347 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3355 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3356 * page could be OK (Windows seems to be OK with them), and larger gaps
3357 * could lead to image sections spanning several discontiguous regions
3358 * (NtMapViewOfSection could then refuse to map them, and they could
3359 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3361 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3362 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3363 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3374 * Merges and pads an image section's segments until they all are page-aligned
3375 * and have a size that is a multiple of the page size
3380 MmspPageAlignSegments
3382 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3388 PMM_SECTION_SEGMENT EffectiveSegment
;
3390 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3392 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3397 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3399 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3402 * The first segment requires special handling
3406 ULONG_PTR VirtualAddress
;
3407 ULONG_PTR VirtualOffset
;
3409 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3411 /* Round down the virtual address to the nearest page */
3412 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3414 /* Round up the virtual size to the nearest page */
3415 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3416 EffectiveSegment
->Image
.VirtualAddress
;
3418 /* Adjust the raw address and size */
3419 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3421 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3427 * Garbage in, garbage out: unaligned base addresses make the file
3428 * offset point in curious and odd places, but that's what we were
3431 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3432 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3436 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3437 ULONG_PTR EndOfEffectiveSegment
;
3439 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3440 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3443 * The current segment begins exactly where the current effective
3444 * segment ended, therefore beginning a new effective segment
3446 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3449 ASSERT(LastSegment
<= i
);
3450 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3452 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3454 if (LastSegment
!= i
)
3457 * Copy the current segment. If necessary, the effective segment
3458 * will be expanded later
3460 *EffectiveSegment
= *Segment
;
3464 * Page-align the virtual size. We know for sure the virtual address
3467 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3468 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3471 * The current segment is still part of the current effective segment:
3472 * extend the effective segment to reflect this
3474 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3476 static const ULONG FlagsToProtection
[16] =
3484 PAGE_EXECUTE_READWRITE
,
3485 PAGE_EXECUTE_READWRITE
,
3490 PAGE_EXECUTE_WRITECOPY
,
3491 PAGE_EXECUTE_WRITECOPY
,
3492 PAGE_EXECUTE_WRITECOPY
,
3493 PAGE_EXECUTE_WRITECOPY
3496 unsigned ProtectionFlags
;
3499 * Extend the file size
3502 /* Unaligned segments must be contiguous within the file */
3503 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3504 EffectiveSegment
->RawLength
.QuadPart
))
3509 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3512 * Extend the virtual size
3514 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3516 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3517 EffectiveSegment
->Image
.VirtualAddress
;
3520 * Merge the protection
3522 EffectiveSegment
->Protection
|= Segment
->Protection
;
3524 /* Clean up redundance */
3525 ProtectionFlags
= 0;
3527 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3528 ProtectionFlags
|= 1 << 0;
3530 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3531 ProtectionFlags
|= 1 << 1;
3533 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3534 ProtectionFlags
|= 1 << 2;
3536 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3537 ProtectionFlags
|= 1 << 3;
3539 ASSERT(ProtectionFlags
< 16);
3540 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3542 /* If a segment was required to be shared and cannot, fail */
3543 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3544 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3550 * We assume no holes between segments at this point
3554 KeBugCheck(MEMORY_MANAGEMENT
);
3558 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3564 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3565 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3567 LARGE_INTEGER Offset
;
3569 PVOID FileHeaderBuffer
;
3570 ULONG FileHeaderSize
;
3572 ULONG OldNrSegments
;
3577 * Read the beginning of the file (2 pages). Should be enough to contain
3578 * all (or most) of the headers
3580 Offset
.QuadPart
= 0;
3582 /* FIXME: use FileObject instead of FileHandle */
3583 Status
= ExeFmtpReadFile (FileHandle
,
3590 if (!NT_SUCCESS(Status
))
3593 if (FileHeaderSize
== 0)
3595 ExFreePool(FileHeaderBuffer
);
3596 return STATUS_UNSUCCESSFUL
;
3600 * Look for a loader that can handle this executable
3602 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3604 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3607 /* FIXME: use FileObject instead of FileHandle */
3608 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3614 ExeFmtpAllocateSegments
);
3616 if (!NT_SUCCESS(Status
))
3618 if (ImageSectionObject
->Segments
)
3620 ExFreePool(ImageSectionObject
->Segments
);
3621 ImageSectionObject
->Segments
= NULL
;
3625 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3629 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3632 * No loader handled the format
3634 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3636 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3637 ASSERT(!NT_SUCCESS(Status
));
3640 if (!NT_SUCCESS(Status
))
3643 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3648 /* FIXME? are these values platform-dependent? */
3649 if(ImageSectionObject
->StackReserve
== 0)
3650 ImageSectionObject
->StackReserve
= 0x40000;
3652 if(ImageSectionObject
->StackCommit
== 0)
3653 ImageSectionObject
->StackCommit
= 0x1000;
3655 if(ImageSectionObject
->ImageBase
== 0)
3657 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3658 ImageSectionObject
->ImageBase
= 0x10000000;
3660 ImageSectionObject
->ImageBase
= 0x00400000;
3664 * And now the fun part: fixing the segments
3667 /* Sort them by virtual address */
3668 MmspSortSegments(ImageSectionObject
, Flags
);
3670 /* Ensure they don't overlap in memory */
3671 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3672 return STATUS_INVALID_IMAGE_FORMAT
;
3674 /* Ensure they are aligned */
3675 OldNrSegments
= ImageSectionObject
->NrSegments
;
3677 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3678 return STATUS_INVALID_IMAGE_FORMAT
;
3680 /* Trim them if the alignment phase merged some of them */
3681 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3683 PMM_SECTION_SEGMENT Segments
;
3684 SIZE_T SizeOfSegments
;
3686 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3688 Segments
= ExAllocatePoolWithTag(PagedPool
,
3690 TAG_MM_SECTION_SEGMENT
);
3692 if (Segments
== NULL
)
3693 return STATUS_INSUFFICIENT_RESOURCES
;
3695 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3696 ExFreePool(ImageSectionObject
->Segments
);
3697 ImageSectionObject
->Segments
= Segments
;
3700 /* And finish their initialization */
3701 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3703 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3704 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3705 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3708 ASSERT(NT_SUCCESS(Status
));
3713 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3714 ACCESS_MASK DesiredAccess
,
3715 POBJECT_ATTRIBUTES ObjectAttributes
,
3716 PLARGE_INTEGER UMaximumSize
,
3717 ULONG SectionPageProtection
,
3718 ULONG AllocationAttributes
,
3719 PFILE_OBJECT FileObject
)
3721 PROS_SECTION_OBJECT Section
;
3723 PMM_SECTION_SEGMENT SectionSegments
;
3724 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3727 if (FileObject
== NULL
)
3728 return STATUS_INVALID_FILE_FOR_SECTION
;
3731 * Create the section
3733 Status
= ObCreateObject (ExGetPreviousMode(),
3734 MmSectionObjectType
,
3736 ExGetPreviousMode(),
3738 sizeof(ROS_SECTION_OBJECT
),
3741 (PVOID
*)(PVOID
)&Section
);
3742 if (!NT_SUCCESS(Status
))
3744 ObDereferenceObject(FileObject
);
3751 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3752 Section
->Type
= 'SC';
3753 Section
->Size
= 'TN';
3754 Section
->SectionPageProtection
= SectionPageProtection
;
3755 Section
->AllocationAttributes
= AllocationAttributes
;
3759 * Initialized caching for this file object if previously caching
3760 * was initialized for the same on disk file
3762 Status
= CcTryToInitializeFileCache(FileObject
);
3764 Status
= STATUS_SUCCESS
;
3767 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3769 NTSTATUS StatusExeFmt
;
3771 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3772 if (ImageSectionObject
== NULL
)
3774 ObDereferenceObject(FileObject
);
3775 ObDereferenceObject(Section
);
3776 return(STATUS_NO_MEMORY
);
3779 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3781 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3783 if (!NT_SUCCESS(StatusExeFmt
))
3785 if(ImageSectionObject
->Segments
!= NULL
)
3786 ExFreePool(ImageSectionObject
->Segments
);
3788 ExFreePool(ImageSectionObject
);
3789 ObDereferenceObject(Section
);
3790 ObDereferenceObject(FileObject
);
3791 return(StatusExeFmt
);
3794 Section
->ImageSection
= ImageSectionObject
;
3795 ASSERT(ImageSectionObject
->Segments
);
3800 Status
= MmspWaitForFileLock(FileObject
);
3801 if (!NT_SUCCESS(Status
))
3803 ExFreePool(ImageSectionObject
->Segments
);
3804 ExFreePool(ImageSectionObject
);
3805 ObDereferenceObject(Section
);
3806 ObDereferenceObject(FileObject
);
3810 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3811 ImageSectionObject
, NULL
))
3814 * An other thread has initialized the same image in the background
3816 ExFreePool(ImageSectionObject
->Segments
);
3817 ExFreePool(ImageSectionObject
);
3818 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3819 Section
->ImageSection
= ImageSectionObject
;
3820 SectionSegments
= ImageSectionObject
->Segments
;
3822 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3824 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3828 Status
= StatusExeFmt
;
3835 Status
= MmspWaitForFileLock(FileObject
);
3836 if (Status
!= STATUS_SUCCESS
)
3838 ObDereferenceObject(Section
);
3839 ObDereferenceObject(FileObject
);
3843 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3844 Section
->ImageSection
= ImageSectionObject
;
3845 SectionSegments
= ImageSectionObject
->Segments
;
3848 * Otherwise just reference all the section segments
3850 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3852 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3855 Status
= STATUS_SUCCESS
;
3857 Section
->FileObject
= FileObject
;
3859 CcRosReferenceCache(FileObject
);
3861 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3862 *SectionObject
= Section
;
3869 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3870 PROS_SECTION_OBJECT Section
,
3871 PMM_SECTION_SEGMENT Segment
,
3876 ULONG AllocationType
)
3880 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3882 if (Segment
->WriteCopy
)
3884 /* We have to do this because the not present fault
3885 * and access fault handlers depend on the protection
3886 * that should be granted AFTER the COW fault takes
3887 * place to be in Region->Protect. The not present fault
3888 * handler changes this to the correct protection for COW when
3889 * mapping the pages into the process's address space. If a COW
3890 * fault takes place, the access fault handler sets the page protection
3891 * to these values for the newly copied pages
3893 if (Protect
== PAGE_WRITECOPY
)
3894 Protect
= PAGE_READWRITE
;
3895 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3896 Protect
= PAGE_EXECUTE_READWRITE
;
3899 BoundaryAddressMultiple
.QuadPart
= 0;
3902 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
3903 LARGE_INTEGER FileOffset
;
3904 FileOffset
.QuadPart
= ViewOffset
;
3905 ObReferenceObject(Section
);
3906 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3909 Status
= MmCreateMemoryArea(AddressSpace
,
3910 MEMORY_AREA_SECTION_VIEW
,
3917 BoundaryAddressMultiple
);
3918 if (!NT_SUCCESS(Status
))
3920 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3921 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3925 ObReferenceObject((PVOID
)Section
);
3927 MArea
->Data
.SectionData
.Segment
= Segment
;
3928 MArea
->Data
.SectionData
.Section
= Section
;
3929 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3930 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3931 ViewSize
, 0, Protect
);
3933 return(STATUS_SUCCESS
);
3938 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3939 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3942 PFILE_OBJECT FileObject
;
3944 LARGE_INTEGER Offset
;
3945 SWAPENTRY SavedSwapEntry
;
3946 PROS_SECTION_OBJECT Section
;
3947 PMM_SECTION_SEGMENT Segment
;
3948 PMMSUPPORT AddressSpace
;
3951 AddressSpace
= (PMMSUPPORT
)Context
;
3952 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3954 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3956 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3957 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3959 Section
= MemoryArea
->Data
.SectionData
.Section
;
3960 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3962 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3963 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
3965 MmUnlockSectionSegment(Segment
);
3966 MmUnlockAddressSpace(AddressSpace
);
3968 MiWaitForPageEvent(NULL
, NULL
);
3970 MmLockAddressSpace(AddressSpace
);
3971 MmLockSectionSegment(Segment
);
3972 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3976 * For a dirty, datafile, non-private page mark it as dirty in the
3979 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3981 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3983 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3984 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3986 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)(Offset
.QuadPart
+ Segment
->Image
.FileOffset
));
3988 ASSERT(SwapEntry
== 0);
3997 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3999 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4000 KeBugCheck(MEMORY_MANAGEMENT
);
4002 MmFreeSwapPage(SwapEntry
);
4006 if (IS_SWAP_FROM_SSE(Entry
) ||
4007 Page
!= PFN_FROM_SSE(Entry
))
4012 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4014 DPRINT1("Found a private page in a pagefile section.\n");
4015 KeBugCheck(MEMORY_MANAGEMENT
);
4018 * Just dereference private pages
4020 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4021 if (SavedSwapEntry
!= 0)
4023 MmFreeSwapPage(SavedSwapEntry
);
4024 MmSetSavedSwapEntryPage(Page
, 0);
4026 MmDeleteRmap(Page
, Process
, Address
);
4027 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4031 MmDeleteRmap(Page
, Process
, Address
);
4032 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4038 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4042 PMEMORY_AREA MemoryArea
;
4043 PROS_SECTION_OBJECT Section
;
4044 PMM_SECTION_SEGMENT Segment
;
4045 PLIST_ENTRY CurrentEntry
;
4046 PMM_REGION CurrentRegion
;
4047 PLIST_ENTRY RegionListHead
;
4049 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4051 if (MemoryArea
== NULL
)
4053 return(STATUS_UNSUCCESSFUL
);
4056 MemoryArea
->DeleteInProgress
= TRUE
;
4057 Section
= MemoryArea
->Data
.SectionData
.Section
;
4058 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4061 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4062 return MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4065 MmLockSectionSegment(Segment
);
4067 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4068 while (!IsListEmpty(RegionListHead
))
4070 CurrentEntry
= RemoveHeadList(RegionListHead
);
4071 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4072 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4075 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4077 Status
= MmFreeMemoryArea(AddressSpace
,
4084 Status
= MmFreeMemoryArea(AddressSpace
,
4089 MmUnlockSectionSegment(Segment
);
4090 ObDereferenceObject(Section
);
4096 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4097 IN PVOID BaseAddress
,
4101 PMEMORY_AREA MemoryArea
;
4102 PMMSUPPORT AddressSpace
;
4103 PROS_SECTION_OBJECT Section
;
4104 PVOID ImageBaseAddress
= 0;
4106 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4107 Process
, BaseAddress
);
4111 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4113 MmLockAddressSpace(AddressSpace
);
4114 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4116 if (MemoryArea
== NULL
||
4117 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4118 MemoryArea
->DeleteInProgress
)
4120 ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4121 MmUnlockAddressSpace(AddressSpace
);
4122 return STATUS_NOT_MAPPED_VIEW
;
4125 MemoryArea
->DeleteInProgress
= TRUE
;
4127 Section
= MemoryArea
->Data
.SectionData
.Section
;
4129 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4133 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4134 PMM_SECTION_SEGMENT SectionSegments
;
4135 PMM_SECTION_SEGMENT Segment
;
4137 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4138 ImageSectionObject
= Section
->ImageSection
;
4139 SectionSegments
= ImageSectionObject
->Segments
;
4140 NrSegments
= ImageSectionObject
->NrSegments
;
4142 /* Search for the current segment within the section segments
4143 * and calculate the image base address */
4144 for (i
= 0; i
< NrSegments
; i
++)
4146 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4148 if (Segment
== &SectionSegments
[i
])
4150 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4155 if (i
>= NrSegments
)
4157 KeBugCheck(MEMORY_MANAGEMENT
);
4160 for (i
= 0; i
< NrSegments
; i
++)
4162 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4164 PVOID SBaseAddress
= (PVOID
)
4165 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4167 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4173 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4176 MmUnlockAddressSpace(AddressSpace
);
4178 /* Notify debugger */
4179 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4181 return(STATUS_SUCCESS
);
4188 * Queries the information of a section object.
4190 * @param SectionHandle
4191 * Handle to the section object. It must be opened with SECTION_QUERY
4193 * @param SectionInformationClass
4194 * Index to a certain information structure. Can be either
4195 * SectionBasicInformation or SectionImageInformation. The latter
4196 * is valid only for sections that were created with the SEC_IMAGE
4198 * @param SectionInformation
4199 * Caller supplies storage for resulting information.
4201 * Size of the supplied storage.
4202 * @param ResultLength
4210 NtQuerySection(IN HANDLE SectionHandle
,
4211 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4212 OUT PVOID SectionInformation
,
4213 IN SIZE_T SectionInformationLength
,
4214 OUT PSIZE_T ResultLength OPTIONAL
)
4216 PROS_SECTION_OBJECT Section
;
4217 KPROCESSOR_MODE PreviousMode
;
4221 PreviousMode
= ExGetPreviousMode();
4223 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4225 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4227 (ULONG
)SectionInformationLength
,
4232 if(!NT_SUCCESS(Status
))
4234 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4238 Status
= ObReferenceObjectByHandle(SectionHandle
,
4240 MmSectionObjectType
,
4242 (PVOID
*)(PVOID
)&Section
,
4244 if (NT_SUCCESS(Status
))
4246 switch (SectionInformationClass
)
4248 case SectionBasicInformation
:
4250 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4254 Sbi
->Attributes
= Section
->AllocationAttributes
;
4255 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4257 Sbi
->BaseAddress
= 0;
4258 Sbi
->Size
.QuadPart
= 0;
4262 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4263 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4266 if (ResultLength
!= NULL
)
4268 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4270 Status
= STATUS_SUCCESS
;
4272 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4274 Status
= _SEH2_GetExceptionCode();
4281 case SectionImageInformation
:
4283 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4287 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4288 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4290 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4291 ImageSectionObject
= Section
->ImageSection
;
4293 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4294 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4295 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4296 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4297 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4298 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4299 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4300 Sii
->Machine
= ImageSectionObject
->Machine
;
4301 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4304 if (ResultLength
!= NULL
)
4306 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4308 Status
= STATUS_SUCCESS
;
4310 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4312 Status
= _SEH2_GetExceptionCode();
4320 ObDereferenceObject(Section
);
4326 /**********************************************************************
4328 * MmMapViewOfSection
4331 * Maps a view of a section into the virtual address space of a
4336 * Pointer to the section object.
4339 * Pointer to the process.
4342 * Desired base address (or NULL) on entry;
4343 * Actual base address of the view on exit.
4346 * Number of high order address bits that must be zero.
4349 * Size in bytes of the initially committed section of
4353 * Offset in bytes from the beginning of the section
4354 * to the beginning of the view.
4357 * Desired length of map (or zero to map all) on entry
4358 * Actual length mapped on exit.
4360 * InheritDisposition
4361 * Specified how the view is to be shared with
4365 * Type of allocation for the pages.
4368 * Protection for the committed region of the view.
4376 MmMapViewOfSection(IN PVOID SectionObject
,
4377 IN PEPROCESS Process
,
4378 IN OUT PVOID
*BaseAddress
,
4379 IN ULONG_PTR ZeroBits
,
4380 IN SIZE_T CommitSize
,
4381 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4382 IN OUT PSIZE_T ViewSize
,
4383 IN SECTION_INHERIT InheritDisposition
,
4384 IN ULONG AllocationType
,
4387 PROS_SECTION_OBJECT Section
;
4388 PMMSUPPORT AddressSpace
;
4390 NTSTATUS Status
= STATUS_SUCCESS
;
4391 BOOLEAN NotAtBase
= FALSE
;
4393 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4395 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4396 return MmMapViewOfArm3Section(SectionObject
,
4410 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4412 return STATUS_INVALID_PAGE_PROTECTION
;
4416 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4417 AddressSpace
= &Process
->Vm
;
4419 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4421 MmLockAddressSpace(AddressSpace
);
4423 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4427 ULONG_PTR ImageBase
;
4429 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4430 PMM_SECTION_SEGMENT SectionSegments
;
4432 ImageSectionObject
= Section
->ImageSection
;
4433 SectionSegments
= ImageSectionObject
->Segments
;
4434 NrSegments
= ImageSectionObject
->NrSegments
;
4437 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4440 ImageBase
= ImageSectionObject
->ImageBase
;
4444 for (i
= 0; i
< NrSegments
; i
++)
4446 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4448 ULONG_PTR MaxExtent
;
4449 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4450 SectionSegments
[i
].Length
.QuadPart
);
4451 ImageSize
= max(ImageSize
, MaxExtent
);
4455 ImageSectionObject
->ImageSize
= (ULONG
)ImageSize
;
4457 /* Check for an illegal base address */
4458 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4460 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4463 /* Check there is enough space to map the section at that point. */
4464 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4465 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4467 /* Fail if the user requested a fixed base address. */
4468 if ((*BaseAddress
) != NULL
)
4470 MmUnlockAddressSpace(AddressSpace
);
4471 return(STATUS_UNSUCCESSFUL
);
4473 /* Otherwise find a gap to map the image. */
4474 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4477 MmUnlockAddressSpace(AddressSpace
);
4478 return(STATUS_UNSUCCESSFUL
);
4480 /* Remember that we loaded image at a different base address */
4484 for (i
= 0; i
< NrSegments
; i
++)
4486 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4488 PVOID SBaseAddress
= (PVOID
)
4489 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4490 MmLockSectionSegment(&SectionSegments
[i
]);
4491 Status
= MmMapViewOfSegment(AddressSpace
,
4493 &SectionSegments
[i
],
4495 SectionSegments
[i
].Length
.LowPart
,
4496 SectionSegments
[i
].Protection
,
4499 MmUnlockSectionSegment(&SectionSegments
[i
]);
4500 if (!NT_SUCCESS(Status
))
4502 MmUnlockAddressSpace(AddressSpace
);
4508 *BaseAddress
= (PVOID
)ImageBase
;
4509 *ViewSize
= ImageSize
;
4513 /* check for write access */
4514 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4515 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4517 MmUnlockAddressSpace(AddressSpace
);
4518 return STATUS_SECTION_PROTECTION
;
4520 /* check for read access */
4521 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4522 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4524 MmUnlockAddressSpace(AddressSpace
);
4525 return STATUS_SECTION_PROTECTION
;
4527 /* check for execute access */
4528 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4529 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4531 MmUnlockAddressSpace(AddressSpace
);
4532 return STATUS_SECTION_PROTECTION
;
4535 if (ViewSize
== NULL
)
4537 /* Following this pointer would lead to us to the dark side */
4538 /* What to do? Bugcheck? Return status? Do the mambo? */
4539 KeBugCheck(MEMORY_MANAGEMENT
);
4542 if (SectionOffset
== NULL
)
4548 ViewOffset
= SectionOffset
->u
.LowPart
;
4551 if ((ViewOffset
% PAGE_SIZE
) != 0)
4553 MmUnlockAddressSpace(AddressSpace
);
4554 return(STATUS_MAPPED_ALIGNMENT
);
4557 if ((*ViewSize
) == 0)
4559 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4561 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4563 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4566 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4568 MmLockSectionSegment(Section
->Segment
);
4569 Status
= MmMapViewOfSegment(AddressSpace
,
4576 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4577 MmUnlockSectionSegment(Section
->Segment
);
4578 if (!NT_SUCCESS(Status
))
4580 MmUnlockAddressSpace(AddressSpace
);
4585 MmUnlockAddressSpace(AddressSpace
);
4588 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4590 Status
= STATUS_SUCCESS
;
4599 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4600 IN PLARGE_INTEGER NewFileSize
)
4602 /* Check whether an ImageSectionObject exists */
4603 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4605 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4609 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4611 PMM_SECTION_SEGMENT Segment
;
4613 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4616 if (Segment
->ReferenceCount
!= 0)
4619 CC_FILE_SIZES FileSizes
;
4621 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4624 /* Check size of file */
4625 if (SectionObjectPointer
->SharedCacheMap
)
4627 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4632 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4641 /* Check size of file */
4642 if (SectionObjectPointer
->SharedCacheMap
)
4644 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4645 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4654 /* Something must gone wrong
4655 * how can we have a Section but no
4657 DPRINT("ERROR: DataSectionObject without reference!\n");
4661 DPRINT("FIXME: didn't check for outstanding write probes\n");
4673 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4674 IN MMFLUSH_TYPE FlushType
)
4676 BOOLEAN Result
= TRUE
;
4678 PMM_SECTION_SEGMENT Segment
;
4683 case MmFlushForDelete
:
4684 if (SectionObjectPointer
->ImageSectionObject
||
4685 SectionObjectPointer
->DataSectionObject
)
4690 CcRosSetRemoveOnClose(SectionObjectPointer
);
4693 case MmFlushForWrite
:
4695 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4697 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4700 if (SectionObjectPointer
->ImageSectionObject
) {
4701 DPRINT1("SectionObject has ImageSection\n");
4707 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4709 DPRINT("Result %d\n", Result
);
4721 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4722 OUT PVOID
* MappedBase
,
4723 IN OUT PSIZE_T ViewSize
)
4725 PROS_SECTION_OBJECT Section
;
4726 PMMSUPPORT AddressSpace
;
4730 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4732 return MiMapViewInSystemSpace(SectionObject
,
4738 DPRINT("MmMapViewInSystemSpace() called\n");
4740 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4741 AddressSpace
= MmGetKernelAddressSpace();
4743 MmLockAddressSpace(AddressSpace
);
4746 if ((*ViewSize
) == 0)
4748 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4750 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4752 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4755 MmLockSectionSegment(Section
->Segment
);
4758 Status
= MmMapViewOfSegment(AddressSpace
,
4767 MmUnlockSectionSegment(Section
->Segment
);
4768 MmUnlockAddressSpace(AddressSpace
);
4775 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4777 PMMSUPPORT AddressSpace
;
4780 DPRINT("MmUnmapViewInSystemSpace() called\n");
4782 AddressSpace
= MmGetKernelAddressSpace();
4784 MmLockAddressSpace(AddressSpace
);
4786 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4788 MmUnlockAddressSpace(AddressSpace
);
4793 /**********************************************************************
4798 * Creates a section object.
4801 * SectionObject (OUT)
4802 * Caller supplied storage for the resulting pointer
4803 * to a SECTION_OBJECT instance;
4806 * Specifies the desired access to the section can be a
4808 * STANDARD_RIGHTS_REQUIRED |
4810 * SECTION_MAP_WRITE |
4811 * SECTION_MAP_READ |
4812 * SECTION_MAP_EXECUTE
4814 * ObjectAttributes [OPTIONAL]
4815 * Initialized attributes for the object can be used
4816 * to create a named section;
4819 * Maximizes the size of the memory section. Must be
4820 * non-NULL for a page-file backed section.
4821 * If value specified for a mapped file and the file is
4822 * not large enough, file will be extended.
4824 * SectionPageProtection
4825 * Can be a combination of:
4831 * AllocationAttributes
4832 * Can be a combination of:
4837 * Handle to a file to create a section mapped to a file
4838 * instead of a memory backed section;
4849 MmCreateSection (OUT PVOID
* Section
,
4850 IN ACCESS_MASK DesiredAccess
,
4851 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4852 IN PLARGE_INTEGER MaximumSize
,
4853 IN ULONG SectionPageProtection
,
4854 IN ULONG AllocationAttributes
,
4855 IN HANDLE FileHandle OPTIONAL
,
4856 IN PFILE_OBJECT FileObject OPTIONAL
)
4859 ULONG Protection
, FileAccess
;
4860 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4862 /* Check if an ARM3 section is being created instead */
4863 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4865 if (!(FileObject
) && !(FileHandle
))
4867 return MmCreateArm3Section(Section
,
4871 SectionPageProtection
,
4872 AllocationAttributes
&~ 1,
4879 * Check the protection
4881 Protection
= SectionPageProtection
& ~(PAGE_GUARD
| PAGE_NOCACHE
);
4882 if (Protection
!= PAGE_READONLY
&&
4883 Protection
!= PAGE_READWRITE
&&
4884 Protection
!= PAGE_WRITECOPY
&&
4885 Protection
!= PAGE_EXECUTE
&&
4886 Protection
!= PAGE_EXECUTE_READ
&&
4887 Protection
!= PAGE_EXECUTE_READWRITE
&&
4888 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4890 return STATUS_INVALID_PAGE_PROTECTION
;
4893 if ((DesiredAccess
& SECTION_MAP_WRITE
) &&
4894 (Protection
== PAGE_READWRITE
||
4895 Protection
== PAGE_EXECUTE_READWRITE
) &&
4896 !(AllocationAttributes
& SEC_IMAGE
))
4898 DPRINT("Creating a section with WRITE access\n");
4899 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
| SYNCHRONIZE
;
4903 DPRINT("Creating a section with READ access\n");
4904 FileAccess
= FILE_READ_DATA
| SYNCHRONIZE
;
4907 /* FIXME: somehow combine this with the above checks */
4908 if (AllocationAttributes
& SEC_IMAGE
)
4909 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
4911 if (!FileObject
&& FileHandle
)
4913 Status
= ObReferenceObjectByHandle(FileHandle
,
4916 ExGetPreviousMode(),
4917 (PVOID
*)&FileObject
,
4919 if (!NT_SUCCESS(Status
))
4921 DPRINT("Failed: 0x%08lx\n", Status
);
4925 else if (FileObject
)
4926 ObReferenceObject(FileObject
);
4928 #ifndef NEWCC // A hack for initializing caching.
4929 // This is needed only in the old case.
4932 IO_STATUS_BLOCK Iosb
;
4935 LARGE_INTEGER ByteOffset
;
4936 ByteOffset
.QuadPart
= 0;
4937 Status
= ZwReadFile(FileHandle
,
4946 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
4948 // Caching is initialized...
4952 if (AllocationAttributes
& SEC_IMAGE
)
4954 Status
= MmCreateImageSection(SectionObject
,
4958 SectionPageProtection
,
4959 AllocationAttributes
,
4963 else if (FileHandle
!= NULL
)
4965 Status
= MmCreateDataFileSection(SectionObject
,
4969 SectionPageProtection
,
4970 AllocationAttributes
,
4973 ObDereferenceObject(FileObject
);
4976 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
4978 Status
= MmCreateCacheSection(SectionObject
,
4982 SectionPageProtection
,
4983 AllocationAttributes
,
4989 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
4991 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
4993 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
4994 Status
= MmCreatePageFileSection(SectionObject
,
4998 SectionPageProtection
,
4999 AllocationAttributes
);