2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
48 #include "../cache/newcc.h"
49 #include "../cache/section/newmm.h"
52 #include <reactos/exeformat.h>
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 #include "ARM3/miarm.h"
61 #undef MmSetPageEntrySectionSegment
62 #define MmSetPageEntrySectionSegment(S,O,E) do { \
63 DPRINT("SetPageEntrySectionSegment(old,%p,%x,%x)\n",(S),(O)->LowPart,E); \
64 _MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__); \
67 extern MMSESSION MmSession
;
71 MiMapViewInSystemSpace(IN PVOID Section
,
73 OUT PVOID
*MappedBase
,
74 IN OUT PSIZE_T ViewSize
);
78 MmCreateArm3Section(OUT PVOID
*SectionObject
,
79 IN ACCESS_MASK DesiredAccess
,
80 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
81 IN PLARGE_INTEGER InputMaximumSize
,
82 IN ULONG SectionPageProtection
,
83 IN ULONG AllocationAttributes
,
84 IN HANDLE FileHandle OPTIONAL
,
85 IN PFILE_OBJECT FileObject OPTIONAL
);
89 MmMapViewOfArm3Section(IN PVOID SectionObject
,
91 IN OUT PVOID
*BaseAddress
,
92 IN ULONG_PTR ZeroBits
,
94 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
95 IN OUT PSIZE_T ViewSize
,
96 IN SECTION_INHERIT InheritDisposition
,
97 IN ULONG AllocationType
,
101 // PeFmtCreateSection depends on the following:
103 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
104 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
106 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
107 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
108 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
110 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
111 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
112 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
113 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
114 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
115 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
116 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
117 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
118 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
120 /* TYPES *********************************************************************/
124 PROS_SECTION_OBJECT Section
;
125 PMM_SECTION_SEGMENT Segment
;
126 LARGE_INTEGER Offset
;
129 PEPROCESS CallingProcess
;
130 ULONG_PTR SectionEntry
;
132 MM_SECTION_PAGEOUT_CONTEXT
;
134 /* GLOBALS *******************************************************************/
136 POBJECT_TYPE MmSectionObjectType
= NULL
;
138 ULONG_PTR MmSubsectionBase
;
140 static ULONG SectionCharacteristicsToProtect
[16] =
142 PAGE_NOACCESS
, /* 0 = NONE */
143 PAGE_NOACCESS
, /* 1 = SHARED */
144 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
145 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
146 PAGE_READONLY
, /* 4 = READABLE */
147 PAGE_READONLY
, /* 5 = READABLE, SHARED */
148 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
149 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
151 * FIXME? do we really need the WriteCopy field in segments? can't we use
152 * PAGE_WRITECOPY here?
154 PAGE_READWRITE
, /* 8 = WRITABLE */
155 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
156 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
157 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
158 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
159 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
160 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
161 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
164 extern ULONG MmMakeFileAccess
[];
165 ACCESS_MASK NTAPI
MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection
);
166 static GENERIC_MAPPING MmpSectionMapping
= {
167 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
168 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
169 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
172 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
174 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
175 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
178 /* FUNCTIONS *****************************************************************/
183 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
184 File Format Specification", revision 6.0 (February 1999)
186 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
187 IN SIZE_T FileHeaderSize
,
189 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
191 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
192 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
195 ULONG cbFileHeaderOffsetSize
= 0;
196 ULONG cbSectionHeadersOffset
= 0;
197 ULONG cbSectionHeadersSize
;
198 ULONG cbSectionHeadersOffsetSize
= 0;
199 ULONG cbOptHeaderSize
;
200 ULONG cbHeadersSize
= 0;
201 ULONG nSectionAlignment
;
202 ULONG nFileAlignment
;
204 const IMAGE_DOS_HEADER
* pidhDosHeader
;
205 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
206 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
207 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
208 PMM_SECTION_SEGMENT pssSegments
;
209 LARGE_INTEGER lnOffset
;
211 SIZE_T nPrevVirtualEndOfSegment
= 0;
212 ULONG nFileSizeOfHeaders
= 0;
216 ASSERT(FileHeaderSize
> 0);
218 ASSERT(ImageSectionObject
);
220 ASSERT(AllocateSegmentsCb
);
222 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
224 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
226 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
229 pidhDosHeader
= FileHeader
;
232 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
234 /* image too small to be an MZ executable */
235 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
236 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
238 /* no MZ signature */
239 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
240 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
242 /* not a Windows executable */
243 if(pidhDosHeader
->e_lfanew
<= 0)
244 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
247 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
249 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
250 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
252 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
257 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
258 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
260 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
261 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
265 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
266 * need to read the header from the file
268 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
269 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
271 ULONG cbNtHeaderSize
;
275 l_ReadHeaderFromFile
:
277 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
279 /* read the header from the file */
280 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
282 if(!NT_SUCCESS(nStatus
))
283 DIE(("ReadFile failed, status %08X\n", nStatus
));
287 ASSERT(cbReadSize
> 0);
289 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
291 /* the buffer doesn't contain the file header */
292 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
293 DIE(("The file doesn't contain the PE file header\n"));
295 pinhNtHeader
= pData
;
297 /* object still not aligned: copy it to the beginning of the buffer */
298 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
300 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
301 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
302 pinhNtHeader
= pBuffer
;
305 /* invalid NT header */
306 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
308 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
309 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
311 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
313 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
314 DIE(("The full NT header is too large\n"));
316 /* the buffer doesn't contain the whole NT header */
317 if(cbReadSize
< cbNtHeaderSize
)
318 DIE(("The file doesn't contain the full NT header\n"));
322 ULONG cbOptHeaderOffsetSize
= 0;
324 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
326 /* don't trust an invalid NT header */
327 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
328 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
330 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
331 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
333 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
334 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
336 /* the buffer doesn't contain the whole NT header: read it from the file */
337 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
338 goto l_ReadHeaderFromFile
;
341 /* read information from the NT header */
342 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
343 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
345 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
347 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
348 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
350 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
352 switch(piohOptHeader
->Magic
)
354 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
355 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
359 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
362 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
363 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
365 /* See [1], section 3.4.2 */
366 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
368 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
369 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
371 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
372 DIE(("The section alignment is smaller than the file alignment\n"));
374 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
375 nFileAlignment
= piohOptHeader
->FileAlignment
;
377 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
378 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
382 nSectionAlignment
= PAGE_SIZE
;
383 nFileAlignment
= PAGE_SIZE
;
386 ASSERT(IsPowerOf2(nSectionAlignment
));
387 ASSERT(IsPowerOf2(nFileAlignment
));
389 switch(piohOptHeader
->Magic
)
392 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
394 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
395 ImageBase
= piohOptHeader
->ImageBase
;
397 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
398 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
400 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
401 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
403 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
404 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
406 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
408 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
410 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
411 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
413 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
414 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
418 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
420 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
421 piohOptHeader
->AddressOfEntryPoint
);
424 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
425 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
427 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
429 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
431 if (piohOptHeader
->AddressOfEntryPoint
== 0)
433 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
437 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
438 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
440 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
442 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
445 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
446 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
447 * magic to any binary.
449 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
450 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
451 * the SxS support -- at which point, duh, this should be removed.
453 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
455 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
462 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
464 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
466 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
468 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
470 ImageBase
= pioh64OptHeader
->ImageBase
;
471 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
472 DIE(("ImageBase exceeds the address space\n"));
475 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
477 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
478 DIE(("SizeOfImage exceeds the address space\n"));
480 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
483 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
485 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
486 DIE(("SizeOfStackReserve exceeds the address space\n"));
488 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
491 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
493 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
494 DIE(("SizeOfStackCommit exceeds the address space\n"));
496 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
499 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
501 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
503 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
504 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
506 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
507 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
511 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
513 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
514 pioh64OptHeader
->AddressOfEntryPoint
);
517 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
518 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
520 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
522 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
524 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
526 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
530 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
531 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
533 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
534 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
541 /* [1], section 3.4.2 */
542 if((ULONG_PTR
)ImageBase
% 0x10000)
543 DIE(("ImageBase is not aligned on a 64KB boundary"));
545 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
546 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
547 ImageSectionObject
->ImageInformation
.GpValue
= 0;
548 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
549 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
551 /* SECTION HEADERS */
552 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
554 /* see [1], section 3.3 */
555 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
556 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
559 * the additional segment is for the file's headers. They need to be present for
560 * the benefit of the dynamic loader (to locate exports, defaults for thread
561 * parameters, resources, etc.)
563 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
565 /* file offset for the section headers */
566 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
567 DIE(("Offset overflow\n"));
569 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
570 DIE(("Offset overflow\n"));
572 /* size of the section headers */
573 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
574 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
576 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
577 DIE(("Section headers too large\n"));
579 /* size of the executable's headers */
580 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
582 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
583 // DIE(("SizeOfHeaders is not aligned\n"));
585 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
586 DIE(("The section headers overflow SizeOfHeaders\n"));
588 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
590 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
591 DIE(("Overflow aligning the size of headers\n"));
598 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
599 /* WARNING: piohOptHeader IS NO LONGER USABLE */
600 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
602 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
603 pishSectionHeaders
= NULL
;
607 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
608 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
610 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
611 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
615 * the buffer doesn't contain the section headers, or the alignment is wrong:
616 * read the headers from the file
618 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
619 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
624 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
626 /* read the header from the file */
627 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
629 if(!NT_SUCCESS(nStatus
))
630 DIE(("ReadFile failed with status %08X\n", nStatus
));
634 ASSERT(cbReadSize
> 0);
636 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
638 /* the buffer doesn't contain all the section headers */
639 if(cbReadSize
< cbSectionHeadersSize
)
640 DIE(("The file doesn't contain all of the section headers\n"));
642 pishSectionHeaders
= pData
;
644 /* object still not aligned: copy it to the beginning of the buffer */
645 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
647 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
648 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
649 pishSectionHeaders
= pBuffer
;
654 /* allocate the segments */
655 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
656 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
658 if(ImageSectionObject
->Segments
== NULL
)
659 DIE(("AllocateSegments failed\n"));
661 /* initialize the headers segment */
662 pssSegments
= ImageSectionObject
->Segments
;
664 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
666 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
667 DIE(("Cannot align the size of the section headers\n"));
669 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
670 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
671 DIE(("Cannot align the size of the section headers\n"));
673 pssSegments
[0].Image
.FileOffset
= 0;
674 pssSegments
[0].Protection
= PAGE_READONLY
;
675 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
676 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
677 pssSegments
[0].Image
.VirtualAddress
= 0;
678 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
679 pssSegments
[0].WriteCopy
= TRUE
;
681 /* skip the headers segment */
684 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
686 /* convert the executable sections into segments. See also [1], section 4 */
687 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
689 ULONG nCharacteristics
;
691 /* validate the alignment */
692 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
693 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
695 /* sections must be contiguous, ordered by base address and non-overlapping */
696 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
697 DIE(("Memory gap between section %u and the previous\n", i
));
699 /* ignore explicit BSS sections */
700 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
702 /* validate the alignment */
704 /* Yes, this should be a multiple of FileAlignment, but there's
705 * stuff out there that isn't. We can cope with that
707 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
708 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
711 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
712 // DIE(("PointerToRawData[%u] is not aligned\n", i));
715 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
716 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
720 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
721 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
724 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
726 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
728 /* no explicit protection */
729 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
731 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
732 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
734 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
735 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
737 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
738 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
741 /* see table above */
742 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
743 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
745 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
746 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
748 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
750 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
751 /* FIXME: always false */
752 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
753 DIE(("Cannot align the virtual size of section %u\n", i
));
755 if(pssSegments
[i
].Length
.QuadPart
== 0)
756 DIE(("Virtual size of section %u is null\n", i
));
758 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
759 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
761 /* ensure the memory image is no larger than 4GB */
762 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
763 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
764 DIE(("The image is too large\n"));
767 if(nSectionAlignment
>= PAGE_SIZE
)
768 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
771 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
781 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
782 * ARGUMENTS: PFILE_OBJECT to wait for.
783 * RETURNS: Status of the wait.
786 MmspWaitForFileLock(PFILE_OBJECT File
)
788 return STATUS_SUCCESS
;
789 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
794 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
796 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
798 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
799 PMM_SECTION_SEGMENT SectionSegments
;
803 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
804 NrSegments
= ImageSectionObject
->NrSegments
;
805 SectionSegments
= ImageSectionObject
->Segments
;
806 for (i
= 0; i
< NrSegments
; i
++)
808 if (SectionSegments
[i
].ReferenceCount
!= 0)
810 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
811 SectionSegments
[i
].ReferenceCount
);
812 KeBugCheck(MEMORY_MANAGEMENT
);
814 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
816 ExFreePool(ImageSectionObject
->Segments
);
817 ExFreePool(ImageSectionObject
);
818 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
820 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
822 PMM_SECTION_SEGMENT Segment
;
824 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
827 if (Segment
->ReferenceCount
!= 0)
829 DPRINT1("Data segment still referenced\n");
830 KeBugCheck(MEMORY_MANAGEMENT
);
832 MmFreePageTablesSectionSegment(Segment
, NULL
);
834 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
840 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
841 PLARGE_INTEGER Offset
)
845 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
848 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
849 KeBugCheck(MEMORY_MANAGEMENT
);
851 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
853 DPRINT1("Maximum share count reached\n");
854 KeBugCheck(MEMORY_MANAGEMENT
);
856 if (IS_SWAP_FROM_SSE(Entry
))
858 KeBugCheck(MEMORY_MANAGEMENT
);
860 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
861 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
866 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
867 PMM_SECTION_SEGMENT Segment
,
868 PLARGE_INTEGER Offset
,
873 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
874 BOOLEAN IsDirectMapped
= FALSE
;
878 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
879 KeBugCheck(MEMORY_MANAGEMENT
);
881 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
883 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
884 KeBugCheck(MEMORY_MANAGEMENT
);
886 if (IS_SWAP_FROM_SSE(Entry
))
888 KeBugCheck(MEMORY_MANAGEMENT
);
890 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
892 * If we reducing the share count of this entry to zero then set the entry
893 * to zero and tell the cache the page is no longer mapped.
895 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
897 PFILE_OBJECT FileObject
;
901 SWAPENTRY SavedSwapEntry
;
903 BOOLEAN IsImageSection
;
904 LARGE_INTEGER FileOffset
;
906 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
908 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
910 Page
= PFN_FROM_SSE(Entry
);
911 FileObject
= Section
->FileObject
;
912 if (FileObject
!= NULL
&&
913 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
917 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
918 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
921 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
922 IsDirectMapped
= TRUE
;
924 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
.LowPart
, Dirty
);
926 Status
= STATUS_SUCCESS
;
928 if (!NT_SUCCESS(Status
))
930 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
931 KeBugCheck(MEMORY_MANAGEMENT
);
937 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
938 if (SavedSwapEntry
== 0)
941 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
942 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
946 * Try to page out this page and set the swap entry
947 * within the section segment. There exist no rmap entry
948 * for this page. The pager thread can't page out a
949 * page without a rmap entry.
951 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
952 if (InEntry
) *InEntry
= Entry
;
953 MiSetPageEvent(NULL
, NULL
);
957 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
958 if (InEntry
) *InEntry
= 0;
959 MiSetPageEvent(NULL
, NULL
);
962 MmReleasePageMemoryConsumer(MC_USER
, Page
);
968 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
969 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
977 * We hold all locks. Nobody can do something with the current
978 * process and the current segment (also not within an other process).
981 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
982 if (!NT_SUCCESS(Status
))
984 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
985 KeBugCheck(MEMORY_MANAGEMENT
);
988 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
989 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
990 MmSetSavedSwapEntryPage(Page
, 0);
991 MiSetPageEvent(NULL
, NULL
);
993 MmReleasePageMemoryConsumer(MC_USER
, Page
);
997 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
998 KeBugCheck(MEMORY_MANAGEMENT
);
1007 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1009 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1012 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1016 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1019 PCACHE_SEGMENT CacheSeg
;
1020 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1021 CacheSeg
= CcRosLookupCacheSegment(Bcb
, (ULONG
)(SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
));
1024 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
1034 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1038 PVOID DestAddress
, SrcAddress
;
1040 Process
= PsGetCurrentProcess();
1041 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1042 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1043 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1045 return(STATUS_NO_MEMORY
);
1047 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1048 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1049 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1050 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1051 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1052 return(STATUS_SUCCESS
);
1058 MiReadPage(PMEMORY_AREA MemoryArea
,
1059 ULONG_PTR SegOffset
,
1062 * FUNCTION: Read a page for a section backed memory area.
1064 * MemoryArea - Memory area to read the page for.
1065 * Offset - Offset of the page to read.
1066 * Page - Variable that receives a page contains the read data.
1070 ULONGLONG FileOffset
;
1073 PCACHE_SEGMENT CacheSeg
;
1074 PFILE_OBJECT FileObject
;
1076 ULONG_PTR RawLength
;
1078 BOOLEAN IsImageSection
;
1081 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1082 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1083 RawLength
= (ULONG_PTR
)(MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
);
1084 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1085 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1089 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1092 * If the file system is letting us go directly to the cache and the
1093 * memory area was mapped at an offset in the file which is page aligned
1094 * then get the related cache segment.
1096 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1097 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1098 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1102 * Get the related cache segment; we use a lower level interface than
1103 * filesystems do because it is safe for us to use an offset with a
1104 * alignment less than the file system block size.
1106 Status
= CcRosGetCacheSegment(Bcb
,
1112 if (!NT_SUCCESS(Status
))
1119 * If the cache segment isn't up to date then call the file
1120 * system to read in the data.
1122 Status
= ReadCacheSegment(CacheSeg
);
1123 if (!NT_SUCCESS(Status
))
1125 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1130 /* Probe the page, since it's PDE might not be synced */
1131 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1134 * Retrieve the page from the cache segment that we actually want.
1136 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1137 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1139 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1146 ULONG_PTR CacheSegOffset
;
1149 * Allocate a page, this is rather complicated by the possibility
1150 * we might have to move other things out of memory
1152 MI_SET_USAGE(MI_USAGE_SECTION
);
1153 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1154 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1155 if (!NT_SUCCESS(Status
))
1159 Status
= CcRosGetCacheSegment(Bcb
,
1165 if (!NT_SUCCESS(Status
))
1172 * If the cache segment isn't up to date then call the file
1173 * system to read in the data.
1175 Status
= ReadCacheSegment(CacheSeg
);
1176 if (!NT_SUCCESS(Status
))
1178 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1183 Process
= PsGetCurrentProcess();
1184 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1185 CacheSegOffset
= (ULONG_PTR
)(BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
);
1186 Length
= RawLength
- SegOffset
;
1187 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1189 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1191 else if (CacheSegOffset
>= PAGE_SIZE
)
1193 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1197 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1198 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1199 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1200 Status
= CcRosGetCacheSegment(Bcb
,
1201 (ULONG
)(FileOffset
+ CacheSegOffset
),
1206 if (!NT_SUCCESS(Status
))
1213 * If the cache segment isn't up to date then call the file
1214 * system to read in the data.
1216 Status
= ReadCacheSegment(CacheSeg
);
1217 if (!NT_SUCCESS(Status
))
1219 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1223 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1224 if (Length
< PAGE_SIZE
)
1226 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1230 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1233 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1234 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1236 return(STATUS_SUCCESS
);
1241 MiReadPage(PMEMORY_AREA MemoryArea
,
1242 ULONG_PTR SegOffset
,
1245 * FUNCTION: Read a page for a section backed memory area.
1247 * MemoryArea - Memory area to read the page for.
1248 * Offset - Offset of the page to read.
1249 * Page - Variable that receives a page contains the read data.
1252 MM_REQUIRED_RESOURCES Resources
;
1255 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1257 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1258 Resources
.FileOffset
.QuadPart
= SegOffset
+
1259 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1260 Resources
.Consumer
= MC_USER
;
1261 Resources
.Amount
= PAGE_SIZE
;
1263 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]);
1265 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1266 *Page
= Resources
.Page
[0];
1273 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1274 MEMORY_AREA
* MemoryArea
,
1278 LARGE_INTEGER Offset
;
1281 PROS_SECTION_OBJECT Section
;
1282 PMM_SECTION_SEGMENT Segment
;
1287 BOOLEAN HasSwapEntry
;
1289 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1290 SWAPENTRY SwapEntry
;
1293 * There is a window between taking the page fault and locking the
1294 * address space when another thread could load the page so we check
1297 if (MmIsPagePresent(Process
, Address
))
1299 return(STATUS_SUCCESS
);
1302 if (MmIsDisabledPage(Process
, Address
))
1304 return(STATUS_ACCESS_VIOLATION
);
1308 * Check for the virtual memory area being deleted.
1310 if (MemoryArea
->DeleteInProgress
)
1312 return(STATUS_UNSUCCESSFUL
);
1315 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1316 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1317 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1319 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1320 Section
= MemoryArea
->Data
.SectionData
.Section
;
1321 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1322 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1324 ASSERT(Region
!= NULL
);
1328 MmLockSectionSegment(Segment
);
1329 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1331 * Check if this page needs to be mapped COW
1333 if ((Segment
->WriteCopy
) &&
1334 (Region
->Protect
== PAGE_READWRITE
||
1335 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1337 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1341 Attributes
= Region
->Protect
;
1345 * Check if someone else is already handling this fault, if so wait
1348 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1350 MmUnlockSectionSegment(Segment
);
1351 MmUnlockAddressSpace(AddressSpace
);
1352 MiWaitForPageEvent(NULL
, NULL
);
1353 MmLockAddressSpace(AddressSpace
);
1354 DPRINT("Address 0x%p\n", Address
);
1355 return(STATUS_MM_RESTART_OPERATION
);
1358 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1362 SWAPENTRY DummyEntry
;
1365 * Is it a wait entry?
1367 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1369 if (SwapEntry
== MM_WAIT_ENTRY
)
1371 MmUnlockSectionSegment(Segment
);
1372 MmUnlockAddressSpace(AddressSpace
);
1373 MiWaitForPageEvent(NULL
, NULL
);
1374 MmLockAddressSpace(AddressSpace
);
1375 return STATUS_MM_RESTART_OPERATION
;
1379 * Must be private page we have swapped out.
1385 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1387 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1388 KeBugCheck(MEMORY_MANAGEMENT
);
1391 MmUnlockSectionSegment(Segment
);
1392 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1393 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1395 MmUnlockAddressSpace(AddressSpace
);
1396 MI_SET_USAGE(MI_USAGE_SECTION
);
1397 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1398 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1399 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1400 if (!NT_SUCCESS(Status
))
1402 KeBugCheck(MEMORY_MANAGEMENT
);
1405 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1406 if (!NT_SUCCESS(Status
))
1408 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1409 KeBugCheck(MEMORY_MANAGEMENT
);
1411 MmLockAddressSpace(AddressSpace
);
1412 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1413 Status
= MmCreateVirtualMapping(Process
,
1418 if (!NT_SUCCESS(Status
))
1420 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1421 KeBugCheck(MEMORY_MANAGEMENT
);
1426 * Store the swap entry for later use.
1428 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1431 * Add the page to the process's working set
1433 MmInsertRmap(Page
, Process
, Address
);
1435 * Finish the operation
1437 MiSetPageEvent(Process
, Address
);
1438 DPRINT("Address 0x%p\n", Address
);
1439 return(STATUS_SUCCESS
);
1443 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1445 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1447 MmUnlockSectionSegment(Segment
);
1449 * Just map the desired physical page
1451 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1452 Status
= MmCreateVirtualMappingUnsafe(Process
,
1457 if (!NT_SUCCESS(Status
))
1459 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1460 KeBugCheck(MEMORY_MANAGEMENT
);
1465 * Cleanup and release locks
1467 MiSetPageEvent(Process
, Address
);
1468 DPRINT("Address 0x%p\n", Address
);
1469 return(STATUS_SUCCESS
);
1473 * Get the entry corresponding to the offset within the section
1475 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1479 SWAPENTRY FakeSwapEntry
;
1482 * If the entry is zero (and it can't change because we have
1483 * locked the segment) then we need to load the page.
1487 * Release all our locks and read in the page from disk
1489 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1490 MmUnlockSectionSegment(Segment
);
1491 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1492 MmUnlockAddressSpace(AddressSpace
);
1494 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1495 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1496 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1498 MI_SET_USAGE(MI_USAGE_SECTION
);
1499 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1500 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1501 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1502 if (!NT_SUCCESS(Status
))
1504 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1510 Status
= MiReadPage(MemoryArea
, (ULONG_PTR
)Offset
.QuadPart
, &Page
);
1511 if (!NT_SUCCESS(Status
))
1513 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1516 if (!NT_SUCCESS(Status
))
1519 * FIXME: What do we know in this case?
1522 * Cleanup and release locks
1524 MmLockAddressSpace(AddressSpace
);
1525 MiSetPageEvent(Process
, Address
);
1526 DPRINT("Address 0x%p\n", Address
);
1531 * Mark the offset within the section as having valid, in-memory
1534 MmLockAddressSpace(AddressSpace
);
1535 MmLockSectionSegment(Segment
);
1536 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1537 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1538 MmUnlockSectionSegment(Segment
);
1540 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1541 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1542 Page
, Process
, PAddress
, Attributes
);
1543 Status
= MmCreateVirtualMapping(Process
,
1548 if (!NT_SUCCESS(Status
))
1550 DPRINT1("Unable to create virtual mapping\n");
1551 KeBugCheck(MEMORY_MANAGEMENT
);
1553 ASSERT(MmIsPagePresent(Process
, PAddress
));
1554 MmInsertRmap(Page
, Process
, Address
);
1556 MiSetPageEvent(Process
, Address
);
1557 DPRINT("Address 0x%p\n", Address
);
1558 return(STATUS_SUCCESS
);
1560 else if (IS_SWAP_FROM_SSE(Entry
))
1562 SWAPENTRY SwapEntry
;
1564 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1567 * Release all our locks and read in the page from disk
1569 MmUnlockSectionSegment(Segment
);
1571 MmUnlockAddressSpace(AddressSpace
);
1572 MI_SET_USAGE(MI_USAGE_SECTION
);
1573 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1574 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1575 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1576 if (!NT_SUCCESS(Status
))
1578 KeBugCheck(MEMORY_MANAGEMENT
);
1581 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1582 if (!NT_SUCCESS(Status
))
1584 KeBugCheck(MEMORY_MANAGEMENT
);
1588 * Relock the address space and segment
1590 MmLockAddressSpace(AddressSpace
);
1591 MmLockSectionSegment(Segment
);
1594 * Check the entry. No one should change the status of a page
1595 * that has a pending page-in.
1597 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1598 if (Entry
!= Entry1
)
1600 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1601 KeBugCheck(MEMORY_MANAGEMENT
);
1605 * Mark the offset within the section as having valid, in-memory
1608 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1609 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1610 MmUnlockSectionSegment(Segment
);
1613 * Save the swap entry.
1615 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1616 Status
= MmCreateVirtualMapping(Process
,
1621 if (!NT_SUCCESS(Status
))
1623 DPRINT1("Unable to create virtual mapping\n");
1624 KeBugCheck(MEMORY_MANAGEMENT
);
1626 MmInsertRmap(Page
, Process
, Address
);
1627 MiSetPageEvent(Process
, Address
);
1628 DPRINT("Address 0x%p\n", Address
);
1629 return(STATUS_SUCCESS
);
1634 * If the section offset is already in-memory and valid then just
1635 * take another reference to the page
1638 Page
= PFN_FROM_SSE(Entry
);
1640 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1641 MmUnlockSectionSegment(Segment
);
1643 Status
= MmCreateVirtualMapping(Process
,
1648 if (!NT_SUCCESS(Status
))
1650 DPRINT1("Unable to create virtual mapping\n");
1651 KeBugCheck(MEMORY_MANAGEMENT
);
1653 MmInsertRmap(Page
, Process
, Address
);
1654 MiSetPageEvent(Process
, Address
);
1655 DPRINT("Address 0x%p\n", Address
);
1656 return(STATUS_SUCCESS
);
1662 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1663 MEMORY_AREA
* MemoryArea
,
1666 PMM_SECTION_SEGMENT Segment
;
1667 PROS_SECTION_OBJECT Section
;
1672 LARGE_INTEGER Offset
;
1675 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1676 SWAPENTRY SwapEntry
;
1678 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1681 * Check if the page has already been set readwrite
1683 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1685 DPRINT("Address 0x%p\n", Address
);
1686 return(STATUS_SUCCESS
);
1690 * Find the offset of the page
1692 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1693 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1694 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1696 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1697 Section
= MemoryArea
->Data
.SectionData
.Section
;
1698 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1699 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1701 ASSERT(Region
!= NULL
);
1705 MmLockSectionSegment(Segment
);
1707 OldPage
= MmGetPfnForProcess(Process
, Address
);
1708 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1710 MmUnlockSectionSegment(Segment
);
1713 * Check if we are doing COW
1715 if (!((Segment
->WriteCopy
) &&
1716 (Region
->Protect
== PAGE_READWRITE
||
1717 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1719 DPRINT("Address 0x%p\n", Address
);
1720 return(STATUS_ACCESS_VIOLATION
);
1723 if (IS_SWAP_FROM_SSE(Entry
) ||
1724 PFN_FROM_SSE(Entry
) != OldPage
)
1726 /* This is a private page. We must only change the page protection. */
1727 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1728 return(STATUS_SUCCESS
);
1732 DPRINT("OldPage == 0!\n");
1735 * Get or create a pageop
1737 MmLockSectionSegment(Segment
);
1738 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1741 * Wait for any other operations to complete
1743 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1745 MmUnlockSectionSegment(Segment
);
1746 MmUnlockAddressSpace(AddressSpace
);
1747 MiWaitForPageEvent(NULL
, NULL
);
1749 * Restart the operation
1751 MmLockAddressSpace(AddressSpace
);
1752 DPRINT("Address 0x%p\n", Address
);
1753 return(STATUS_MM_RESTART_OPERATION
);
1756 MmDeleteRmap(OldPage
, Process
, PAddress
);
1757 MmDeleteVirtualMapping(Process
, PAddress
, FALSE
, NULL
, NULL
);
1758 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1761 * Release locks now we have the pageop
1763 MmUnlockSectionSegment(Segment
);
1764 MmUnlockAddressSpace(AddressSpace
);
1769 MI_SET_USAGE(MI_USAGE_SECTION
);
1770 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1771 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1772 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1773 if (!NT_SUCCESS(Status
))
1775 KeBugCheck(MEMORY_MANAGEMENT
);
1781 MiCopyFromUserPage(NewPage
, OldPage
);
1783 MmLockAddressSpace(AddressSpace
);
1786 * Set the PTE to point to the new page
1788 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1789 Status
= MmCreateVirtualMapping(Process
,
1794 if (!NT_SUCCESS(Status
))
1796 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1797 KeBugCheck(MEMORY_MANAGEMENT
);
1802 * Unshare the old page.
1804 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1805 MmInsertRmap(NewPage
, Process
, PAddress
);
1806 MmLockSectionSegment(Segment
);
1807 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1808 MmUnlockSectionSegment(Segment
);
1810 MiSetPageEvent(Process
, Address
);
1811 DPRINT("Address 0x%p\n", Address
);
1812 return(STATUS_SUCCESS
);
1816 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1818 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1820 PFN_NUMBER Page
= 0;
1822 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1825 MmLockAddressSpace(&Process
->Vm
);
1828 MmDeleteVirtualMapping(Process
,
1835 PageOutContext
->WasDirty
= TRUE
;
1837 if (!PageOutContext
->Private
)
1839 MmLockSectionSegment(PageOutContext
->Segment
);
1840 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1841 PageOutContext
->Segment
,
1842 &PageOutContext
->Offset
,
1843 PageOutContext
->WasDirty
,
1845 &PageOutContext
->SectionEntry
);
1846 MmUnlockSectionSegment(PageOutContext
->Segment
);
1850 MmUnlockAddressSpace(&Process
->Vm
);
1853 if (PageOutContext
->Private
)
1855 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1861 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1862 MEMORY_AREA
* MemoryArea
,
1863 PVOID Address
, ULONG_PTR Entry
)
1866 MM_SECTION_PAGEOUT_CONTEXT Context
;
1867 SWAPENTRY SwapEntry
;
1868 ULONGLONG FileOffset
;
1870 PFILE_OBJECT FileObject
;
1874 BOOLEAN DirectMapped
;
1875 BOOLEAN IsImageSection
;
1876 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1879 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1882 * Get the segment and section.
1884 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1885 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1886 Context
.SectionEntry
= Entry
;
1887 Context
.CallingProcess
= Process
;
1889 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1890 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1891 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1893 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1895 FileObject
= Context
.Section
->FileObject
;
1896 DirectMapped
= FALSE
;
1898 MmLockSectionSegment(Context
.Segment
);
1901 if (FileObject
!= NULL
&&
1902 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1904 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1907 * If the file system is letting us go directly to the cache and the
1908 * memory area was mapped at an offset in the file which is page aligned
1909 * then note this is a direct mapped page.
1911 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1912 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1914 DirectMapped
= TRUE
;
1921 * This should never happen since mappings of physical memory are never
1922 * placed in the rmap lists.
1924 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1926 DPRINT1("Trying to page out from physical memory section address 0x%p "
1927 "process %p\n", Address
,
1928 Process
? Process
->UniqueProcessId
: 0);
1929 KeBugCheck(MEMORY_MANAGEMENT
);
1933 * Get the section segment entry and the physical address.
1935 if (!MmIsPagePresent(Process
, Address
))
1937 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1938 Process
? Process
->UniqueProcessId
: 0, Address
);
1939 KeBugCheck(MEMORY_MANAGEMENT
);
1941 Page
= MmGetPfnForProcess(Process
, Address
);
1942 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1945 * Check the reference count to ensure this page can be paged out
1947 if (MmGetReferenceCountPage(Page
) != 1)
1949 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1950 Page
, MmGetReferenceCountPage(Page
));
1951 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1952 MmUnlockSectionSegment(Context
.Segment
);
1953 return STATUS_UNSUCCESSFUL
;
1957 * Prepare the context structure for the rmap delete call.
1959 MmUnlockSectionSegment(Context
.Segment
);
1960 Context
.WasDirty
= FALSE
;
1961 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1962 IS_SWAP_FROM_SSE(Entry
) ||
1963 PFN_FROM_SSE(Entry
) != Page
)
1965 Context
.Private
= TRUE
;
1969 Context
.Private
= FALSE
;
1973 * Take an additional reference to the page or the cache segment.
1975 if (DirectMapped
&& !Context
.Private
)
1977 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
1979 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1980 KeBugCheck(MEMORY_MANAGEMENT
);
1985 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1986 MmReferencePage(Page
);
1987 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1990 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1992 /* Since we passed in a surrogate, we'll get back the page entry
1993 * state in our context. This is intended to make intermediate
1994 * decrements of share count not release the wait entry.
1996 Entry
= Context
.SectionEntry
;
1999 * If this wasn't a private page then we should have reduced the entry to
2000 * zero by deleting all the rmaps.
2002 if (!Context
.Private
&& Entry
!= 0)
2004 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2005 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2007 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2012 * If the page wasn't dirty then we can just free it as for a readonly page.
2013 * Since we unmapped all the mappings above we know it will not suddenly
2015 * If the page is from a pagefile section and has no swap entry,
2016 * we can't free the page at this point.
2018 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2019 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2021 if (Context
.Private
)
2023 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2024 Context
.WasDirty
? "dirty" : "clean", Address
);
2025 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2027 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2029 MmSetSavedSwapEntryPage(Page
, 0);
2030 MmLockSectionSegment(Context
.Segment
);
2031 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2032 MmUnlockSectionSegment(Context
.Segment
);
2033 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2034 MiSetPageEvent(NULL
, NULL
);
2035 return(STATUS_SUCCESS
);
2038 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2040 if (Context
.Private
)
2042 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2043 Context
.WasDirty
? "dirty" : "clean", Address
);
2044 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2046 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2048 MmSetSavedSwapEntryPage(Page
, 0);
2051 MmLockSectionSegment(Context
.Segment
);
2052 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2053 MmUnlockSectionSegment(Context
.Segment
);
2055 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2056 MiSetPageEvent(NULL
, NULL
);
2057 return(STATUS_SUCCESS
);
2060 else if (!Context
.Private
&& DirectMapped
)
2064 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2066 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2069 Status
= CcRosUnmapCacheSegment(Bcb
, (ULONG
)FileOffset
, FALSE
);
2071 Status
= STATUS_SUCCESS
;
2074 if (!NT_SUCCESS(Status
))
2076 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2077 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Bcb
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2080 MiSetPageEvent(NULL
, NULL
);
2081 return(STATUS_SUCCESS
);
2083 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2087 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2089 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2091 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2092 MiSetPageEvent(NULL
, NULL
);
2093 return(STATUS_SUCCESS
);
2095 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2097 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2098 MmSetSavedSwapEntryPage(Page
, 0);
2099 MmLockAddressSpace(AddressSpace
);
2100 Status
= MmCreatePageFileMapping(Process
,
2103 MmUnlockAddressSpace(AddressSpace
);
2104 if (!NT_SUCCESS(Status
))
2106 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2107 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2109 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2110 MiSetPageEvent(NULL
, NULL
);
2111 return(STATUS_SUCCESS
);
2115 * If necessary, allocate an entry in the paging file for this page
2119 SwapEntry
= MmAllocSwapPage();
2122 MmShowOutOfSpaceMessagePagingFile();
2123 MmLockAddressSpace(AddressSpace
);
2125 * For private pages restore the old mappings.
2127 if (Context
.Private
)
2129 Status
= MmCreateVirtualMapping(Process
,
2131 MemoryArea
->Protect
,
2134 MmSetDirtyPage(Process
, Address
);
2143 * For non-private pages if the page wasn't direct mapped then
2144 * set it back into the section segment entry so we don't loose
2145 * our copy. Otherwise it will be handled by the cache manager.
2147 Status
= MmCreateVirtualMapping(Process
,
2149 MemoryArea
->Protect
,
2152 MmSetDirtyPage(Process
, Address
);
2156 // If we got here, the previous entry should have been a wait
2157 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2158 MmLockSectionSegment(Context
.Segment
);
2159 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2160 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2161 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2162 MmUnlockSectionSegment(Context
.Segment
);
2164 MmUnlockAddressSpace(AddressSpace
);
2165 MiSetPageEvent(NULL
, NULL
);
2166 return(STATUS_PAGEFILE_QUOTA
);
2171 * Write the page to the pagefile
2173 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2174 if (!NT_SUCCESS(Status
))
2176 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2179 * As above: undo our actions.
2180 * FIXME: Also free the swap page.
2182 MmLockAddressSpace(AddressSpace
);
2183 if (Context
.Private
)
2185 Status
= MmCreateVirtualMapping(Process
,
2187 MemoryArea
->Protect
,
2190 MmSetDirtyPage(Process
, Address
);
2197 Status
= MmCreateVirtualMapping(Process
,
2199 MemoryArea
->Protect
,
2202 MmSetDirtyPage(Process
, Address
);
2206 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2207 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2209 MmUnlockAddressSpace(AddressSpace
);
2210 MiSetPageEvent(NULL
, NULL
);
2211 return(STATUS_UNSUCCESSFUL
);
2215 * Otherwise we have succeeded.
2217 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2218 MmSetSavedSwapEntryPage(Page
, 0);
2219 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2220 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2222 MmLockSectionSegment(Context
.Segment
);
2223 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2224 MmUnlockSectionSegment(Context
.Segment
);
2228 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2231 if (Context
.Private
)
2233 MmLockAddressSpace(AddressSpace
);
2234 MmLockSectionSegment(Context
.Segment
);
2235 Status
= MmCreatePageFileMapping(Process
,
2238 /* We had placed a wait entry upon entry ... replace it before leaving */
2239 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2240 MmUnlockSectionSegment(Context
.Segment
);
2241 MmUnlockAddressSpace(AddressSpace
);
2242 if (!NT_SUCCESS(Status
))
2244 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2245 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2250 MmLockAddressSpace(AddressSpace
);
2251 MmLockSectionSegment(Context
.Segment
);
2252 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2253 /* We had placed a wait entry upon entry ... replace it before leaving */
2254 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2255 MmUnlockSectionSegment(Context
.Segment
);
2256 MmUnlockAddressSpace(AddressSpace
);
2259 MiSetPageEvent(NULL
, NULL
);
2260 return(STATUS_SUCCESS
);
2265 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2266 PMEMORY_AREA MemoryArea
,
2270 LARGE_INTEGER Offset
;
2271 PROS_SECTION_OBJECT Section
;
2272 PMM_SECTION_SEGMENT Segment
;
2274 SWAPENTRY SwapEntry
;
2278 PFILE_OBJECT FileObject
;
2280 BOOLEAN DirectMapped
;
2281 BOOLEAN IsImageSection
;
2282 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2284 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2286 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2287 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2290 * Get the segment and section.
2292 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2293 Section
= MemoryArea
->Data
.SectionData
.Section
;
2294 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2296 FileObject
= Section
->FileObject
;
2297 DirectMapped
= FALSE
;
2298 if (FileObject
!= NULL
&&
2299 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2301 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2304 * If the file system is letting us go directly to the cache and the
2305 * memory area was mapped at an offset in the file which is page aligned
2306 * then note this is a direct mapped page.
2308 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2309 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2311 DirectMapped
= TRUE
;
2316 * This should never happen since mappings of physical memory are never
2317 * placed in the rmap lists.
2319 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2321 DPRINT1("Trying to write back page from physical memory mapped at %p "
2322 "process %p\n", Address
,
2323 Process
? Process
->UniqueProcessId
: 0);
2324 KeBugCheck(MEMORY_MANAGEMENT
);
2328 * Get the section segment entry and the physical address.
2330 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2331 if (!MmIsPagePresent(Process
, Address
))
2333 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2334 Process
? Process
->UniqueProcessId
: 0, Address
);
2335 KeBugCheck(MEMORY_MANAGEMENT
);
2337 Page
= MmGetPfnForProcess(Process
, Address
);
2338 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2341 * Check for a private (COWed) page.
2343 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2344 IS_SWAP_FROM_SSE(Entry
) ||
2345 PFN_FROM_SSE(Entry
) != Page
)
2355 * Speculatively set all mappings of the page to clean.
2357 MmSetCleanAllRmaps(Page
);
2360 * If this page was direct mapped from the cache then the cache manager
2361 * will take care of writing it back to disk.
2363 if (DirectMapped
&& !Private
)
2365 //LARGE_INTEGER SOffset;
2366 ASSERT(SwapEntry
== 0);
2367 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2369 CcRosMarkDirtyCacheSegment(Bcb
, Offset
.LowPart
);
2371 MmLockSectionSegment(Segment
);
2372 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2373 MmUnlockSectionSegment(Segment
);
2374 MiSetPageEvent(NULL
, NULL
);
2375 return(STATUS_SUCCESS
);
2379 * If necessary, allocate an entry in the paging file for this page
2383 SwapEntry
= MmAllocSwapPage();
2386 MmSetDirtyAllRmaps(Page
);
2387 MiSetPageEvent(NULL
, NULL
);
2388 return(STATUS_PAGEFILE_QUOTA
);
2390 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2394 * Write the page to the pagefile
2396 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2397 if (!NT_SUCCESS(Status
))
2399 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2401 MmSetDirtyAllRmaps(Page
);
2402 MiSetPageEvent(NULL
, NULL
);
2403 return(STATUS_UNSUCCESSFUL
);
2407 * Otherwise we have succeeded.
2409 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2410 MiSetPageEvent(NULL
, NULL
);
2411 return(STATUS_SUCCESS
);
2415 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2423 PMEMORY_AREA MemoryArea
;
2424 PMM_SECTION_SEGMENT Segment
;
2425 BOOLEAN DoCOW
= FALSE
;
2427 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2429 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2430 ASSERT(MemoryArea
!= NULL
);
2431 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2432 MmLockSectionSegment(Segment
);
2434 if ((Segment
->WriteCopy
) &&
2435 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2440 if (OldProtect
!= NewProtect
)
2442 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2444 SWAPENTRY SwapEntry
;
2445 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2446 ULONG Protect
= NewProtect
;
2448 /* Wait for a wait entry to disappear */
2450 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2451 if (SwapEntry
!= MM_WAIT_ENTRY
)
2453 MiWaitForPageEvent(Process
, Address
);
2457 * If we doing COW for this segment then check if the page is
2460 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2462 LARGE_INTEGER Offset
;
2466 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2467 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2468 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2470 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2471 * IS_SWAP_FROM_SSE and we'll do the right thing.
2473 Page
= MmGetPfnForProcess(Process
, Address
);
2475 Protect
= PAGE_READONLY
;
2476 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2477 IS_SWAP_FROM_SSE(Entry
) ||
2478 PFN_FROM_SSE(Entry
) != Page
)
2480 Protect
= NewProtect
;
2484 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2486 MmSetPageProtect(Process
, Address
,
2492 MmUnlockSectionSegment(Segment
);
2497 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2498 PMEMORY_AREA MemoryArea
,
2506 ULONG_PTR MaxLength
;
2508 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2509 if (Length
> MaxLength
)
2510 Length
= (ULONG
)MaxLength
;
2512 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2513 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2515 ASSERT(Region
!= NULL
);
2517 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2518 Region
->Protect
!= Protect
)
2520 return STATUS_INVALID_PAGE_PROTECTION
;
2523 *OldProtect
= Region
->Protect
;
2524 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2525 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2526 BaseAddress
, Length
, Region
->Type
, Protect
,
2527 MmAlterViewAttributes
);
2533 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2535 PMEMORY_BASIC_INFORMATION Info
,
2536 PSIZE_T ResultLength
)
2539 PVOID RegionBaseAddress
;
2540 PROS_SECTION_OBJECT Section
;
2541 PMM_SECTION_SEGMENT Segment
;
2543 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2544 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2545 Address
, &RegionBaseAddress
);
2548 return STATUS_UNSUCCESSFUL
;
2551 Section
= MemoryArea
->Data
.SectionData
.Section
;
2552 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2554 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2555 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2556 Info
->Type
= MEM_IMAGE
;
2560 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2561 Info
->Type
= MEM_MAPPED
;
2563 Info
->BaseAddress
= RegionBaseAddress
;
2564 Info
->AllocationProtect
= MemoryArea
->Protect
;
2565 Info
->RegionSize
= Region
->Length
;
2566 Info
->State
= MEM_COMMIT
;
2567 Info
->Protect
= Region
->Protect
;
2569 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2570 return(STATUS_SUCCESS
);
2575 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2578 LARGE_INTEGER Offset
;
2580 SWAPENTRY SavedSwapEntry
;
2585 MmLockSectionSegment(Segment
);
2587 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2588 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2590 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2593 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2594 if (IS_SWAP_FROM_SSE(Entry
))
2596 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2600 Page
= PFN_FROM_SSE(Entry
);
2601 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2602 if (SavedSwapEntry
!= 0)
2604 MmSetSavedSwapEntryPage(Page
, 0);
2605 MmFreeSwapPage(SavedSwapEntry
);
2607 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2612 MmUnlockSectionSegment(Segment
);
2616 MmpDeleteSection(PVOID ObjectBody
)
2618 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2620 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2621 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2626 PMM_SECTION_SEGMENT SectionSegments
;
2629 * NOTE: Section->ImageSection can be NULL for short time
2630 * during the section creating. If we fail for some reason
2631 * until the image section is properly initialized we shouldn't
2632 * process further here.
2634 if (Section
->ImageSection
== NULL
)
2637 SectionSegments
= Section
->ImageSection
->Segments
;
2638 NrSegments
= Section
->ImageSection
->NrSegments
;
2640 for (i
= 0; i
< NrSegments
; i
++)
2642 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2644 MmLockSectionSegment(&SectionSegments
[i
]);
2646 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2647 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2649 MmUnlockSectionSegment(&SectionSegments
[i
]);
2652 MmpFreePageFileSegment(&SectionSegments
[i
]);
2658 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2661 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2664 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2666 DPRINT("Freeing section segment\n");
2667 Section
->Segment
= NULL
;
2668 MmFinalizeSegment(Segment
);
2672 DPRINT("RefCount %d\n", RefCount
);
2679 * NOTE: Section->Segment can be NULL for short time
2680 * during the section creating.
2682 if (Section
->Segment
== NULL
)
2685 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2687 MmpFreePageFileSegment(Section
->Segment
);
2688 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2689 ExFreePool(Section
->Segment
);
2690 Section
->Segment
= NULL
;
2694 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2697 if (Section
->FileObject
!= NULL
)
2700 CcRosDereferenceCache(Section
->FileObject
);
2702 ObDereferenceObject(Section
->FileObject
);
2703 Section
->FileObject
= NULL
;
2708 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2710 IN ACCESS_MASK GrantedAccess
,
2711 IN ULONG ProcessHandleCount
,
2712 IN ULONG SystemHandleCount
)
2714 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2720 MmCreatePhysicalMemorySection(VOID
)
2722 PROS_SECTION_OBJECT PhysSection
;
2724 OBJECT_ATTRIBUTES Obj
;
2725 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2726 LARGE_INTEGER SectionSize
;
2730 * Create the section mapping physical memory
2732 SectionSize
.QuadPart
= 0xFFFFFFFF;
2733 InitializeObjectAttributes(&Obj
,
2738 Status
= MmCreateSection((PVOID
)&PhysSection
,
2742 PAGE_EXECUTE_READWRITE
,
2746 if (!NT_SUCCESS(Status
))
2748 DPRINT1("Failed to create PhysicalMemory section\n");
2749 KeBugCheck(MEMORY_MANAGEMENT
);
2751 Status
= ObInsertObject(PhysSection
,
2757 if (!NT_SUCCESS(Status
))
2759 ObDereferenceObject(PhysSection
);
2761 ObCloseHandle(Handle
, KernelMode
);
2762 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2763 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2765 return(STATUS_SUCCESS
);
2771 MmInitSectionImplementation(VOID
)
2773 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2774 UNICODE_STRING Name
;
2776 DPRINT("Creating Section Object Type\n");
2778 /* Initialize the section based root */
2779 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2780 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2782 /* Initialize the Section object type */
2783 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2784 RtlInitUnicodeString(&Name
, L
"Section");
2785 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2786 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2787 ObjectTypeInitializer
.PoolType
= PagedPool
;
2788 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2789 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2790 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2791 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2792 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2793 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2794 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2796 MmCreatePhysicalMemorySection();
2798 return(STATUS_SUCCESS
);
2803 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2804 ACCESS_MASK DesiredAccess
,
2805 POBJECT_ATTRIBUTES ObjectAttributes
,
2806 PLARGE_INTEGER UMaximumSize
,
2807 ULONG SectionPageProtection
,
2808 ULONG AllocationAttributes
)
2810 * Create a section which is backed by the pagefile
2813 LARGE_INTEGER MaximumSize
;
2814 PROS_SECTION_OBJECT Section
;
2815 PMM_SECTION_SEGMENT Segment
;
2818 if (UMaximumSize
== NULL
)
2820 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2821 return(STATUS_INVALID_PARAMETER
);
2823 MaximumSize
= *UMaximumSize
;
2826 * Create the section
2828 Status
= ObCreateObject(ExGetPreviousMode(),
2829 MmSectionObjectType
,
2831 ExGetPreviousMode(),
2833 sizeof(ROS_SECTION_OBJECT
),
2836 (PVOID
*)(PVOID
)&Section
);
2837 if (!NT_SUCCESS(Status
))
2839 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2846 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2847 Section
->Type
= 'SC';
2848 Section
->Size
= 'TN';
2849 Section
->SectionPageProtection
= SectionPageProtection
;
2850 Section
->AllocationAttributes
= AllocationAttributes
;
2851 Section
->MaximumSize
= MaximumSize
;
2852 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2853 TAG_MM_SECTION_SEGMENT
);
2854 if (Segment
== NULL
)
2856 ObDereferenceObject(Section
);
2857 return(STATUS_NO_MEMORY
);
2859 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2860 Section
->Segment
= Segment
;
2861 Segment
->ReferenceCount
= 1;
2862 ExInitializeFastMutex(&Segment
->Lock
);
2863 Segment
->Image
.FileOffset
= 0;
2864 Segment
->Protection
= SectionPageProtection
;
2865 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2866 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2867 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2868 Segment
->WriteCopy
= FALSE
;
2869 Segment
->Image
.VirtualAddress
= 0;
2870 Segment
->Image
.Characteristics
= 0;
2871 *SectionObject
= Section
;
2872 MiInitializeSectionPageTable(Segment
);
2873 return(STATUS_SUCCESS
);
2878 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2879 ACCESS_MASK DesiredAccess
,
2880 POBJECT_ATTRIBUTES ObjectAttributes
,
2881 PLARGE_INTEGER UMaximumSize
,
2882 ULONG SectionPageProtection
,
2883 ULONG AllocationAttributes
,
2886 * Create a section backed by a data file
2889 PROS_SECTION_OBJECT Section
;
2891 LARGE_INTEGER MaximumSize
;
2892 PFILE_OBJECT FileObject
;
2893 PMM_SECTION_SEGMENT Segment
;
2895 IO_STATUS_BLOCK Iosb
;
2896 LARGE_INTEGER Offset
;
2898 FILE_STANDARD_INFORMATION FileInfo
;
2902 * Create the section
2904 Status
= ObCreateObject(ExGetPreviousMode(),
2905 MmSectionObjectType
,
2907 ExGetPreviousMode(),
2909 sizeof(ROS_SECTION_OBJECT
),
2913 if (!NT_SUCCESS(Status
))
2920 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2921 Section
->Type
= 'SC';
2922 Section
->Size
= 'TN';
2923 Section
->SectionPageProtection
= SectionPageProtection
;
2924 Section
->AllocationAttributes
= AllocationAttributes
;
2927 * Reference the file handle
2929 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2930 Status
= ObReferenceObjectByHandle(FileHandle
,
2933 ExGetPreviousMode(),
2934 (PVOID
*)(PVOID
)&FileObject
,
2936 if (!NT_SUCCESS(Status
))
2938 ObDereferenceObject(Section
);
2943 * FIXME: This is propably not entirely correct. We can't look into
2944 * the standard FCB header because it might not be initialized yet
2945 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2946 * standard file information is filled on first request).
2948 Status
= IoQueryFileInformation(FileObject
,
2949 FileStandardInformation
,
2950 sizeof(FILE_STANDARD_INFORMATION
),
2953 Iosb
.Information
= Length
;
2954 if (!NT_SUCCESS(Status
))
2956 ObDereferenceObject(Section
);
2957 ObDereferenceObject(FileObject
);
2962 * FIXME: Revise this once a locking order for file size changes is
2965 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2967 MaximumSize
= *UMaximumSize
;
2971 MaximumSize
= FileInfo
.EndOfFile
;
2972 /* Mapping zero-sized files isn't allowed. */
2973 if (MaximumSize
.QuadPart
== 0)
2975 ObDereferenceObject(Section
);
2976 ObDereferenceObject(FileObject
);
2977 return STATUS_FILE_INVALID
;
2981 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2983 Status
= IoSetInformation(FileObject
,
2984 FileAllocationInformation
,
2985 sizeof(LARGE_INTEGER
),
2987 if (!NT_SUCCESS(Status
))
2989 ObDereferenceObject(Section
);
2990 ObDereferenceObject(FileObject
);
2991 return(STATUS_SECTION_NOT_EXTENDED
);
2995 if (FileObject
->SectionObjectPointer
== NULL
||
2996 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2999 * Read a bit so caching is initiated for the file object.
3000 * This is only needed because MiReadPage currently cannot
3001 * handle non-cached streams.
3003 Offset
.QuadPart
= 0;
3004 Status
= ZwReadFile(FileHandle
,
3013 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3015 ObDereferenceObject(Section
);
3016 ObDereferenceObject(FileObject
);
3019 if (FileObject
->SectionObjectPointer
== NULL
||
3020 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3022 /* FIXME: handle this situation */
3023 ObDereferenceObject(Section
);
3024 ObDereferenceObject(FileObject
);
3025 return STATUS_INVALID_PARAMETER
;
3032 Status
= MmspWaitForFileLock(FileObject
);
3033 if (Status
!= STATUS_SUCCESS
)
3035 ObDereferenceObject(Section
);
3036 ObDereferenceObject(FileObject
);
3041 * If this file hasn't been mapped as a data file before then allocate a
3042 * section segment to describe the data file mapping
3044 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3046 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3047 TAG_MM_SECTION_SEGMENT
);
3048 if (Segment
== NULL
)
3050 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3051 ObDereferenceObject(Section
);
3052 ObDereferenceObject(FileObject
);
3053 return(STATUS_NO_MEMORY
);
3055 Section
->Segment
= Segment
;
3056 Segment
->ReferenceCount
= 1;
3057 ExInitializeFastMutex(&Segment
->Lock
);
3059 * Set the lock before assigning the segment to the file object
3061 ExAcquireFastMutex(&Segment
->Lock
);
3062 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3064 Segment
->Image
.FileOffset
= 0;
3065 Segment
->Protection
= SectionPageProtection
;
3066 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3067 Segment
->Image
.Characteristics
= 0;
3068 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3069 if (AllocationAttributes
& SEC_RESERVE
)
3071 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3075 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3076 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3078 Segment
->Image
.VirtualAddress
= 0;
3079 Segment
->Locked
= TRUE
;
3080 MiInitializeSectionPageTable(Segment
);
3085 * If the file is already mapped as a data file then we may need
3089 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3091 Section
->Segment
= Segment
;
3092 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3093 MmLockSectionSegment(Segment
);
3095 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3096 !(AllocationAttributes
& SEC_RESERVE
))
3098 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3099 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3102 MmUnlockSectionSegment(Segment
);
3103 Section
->FileObject
= FileObject
;
3104 Section
->MaximumSize
= MaximumSize
;
3106 CcRosReferenceCache(FileObject
);
3108 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3109 *SectionObject
= Section
;
3110 return(STATUS_SUCCESS
);
3114 TODO: not that great (declaring loaders statically, having to declare all of
3115 them, having to keep them extern, etc.), will fix in the future
3117 extern NTSTATUS NTAPI PeFmtCreateSection
3119 IN CONST VOID
* FileHeader
,
3120 IN SIZE_T FileHeaderSize
,
3122 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3124 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3125 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3128 extern NTSTATUS NTAPI ElfFmtCreateSection
3130 IN CONST VOID
* FileHeader
,
3131 IN SIZE_T FileHeaderSize
,
3133 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3135 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3136 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3139 /* TODO: this is a standard DDK/PSDK macro */
3140 #ifndef RTL_NUMBER_OF
3141 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3144 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3155 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3157 SIZE_T SizeOfSegments
;
3158 PMM_SECTION_SEGMENT Segments
;
3160 /* TODO: check for integer overflow */
3161 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3163 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3165 TAG_MM_SECTION_SEGMENT
);
3168 RtlZeroMemory(Segments
, SizeOfSegments
);
3176 ExeFmtpReadFile(IN PVOID File
,
3177 IN PLARGE_INTEGER Offset
,
3180 OUT PVOID
* AllocBase
,
3181 OUT PULONG ReadSize
)
3184 LARGE_INTEGER FileOffset
;
3186 ULONG OffsetAdjustment
;
3190 PFILE_OBJECT FileObject
= File
;
3191 IO_STATUS_BLOCK Iosb
;
3193 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3197 KeBugCheck(MEMORY_MANAGEMENT
);
3200 FileOffset
= *Offset
;
3202 /* Negative/special offset: it cannot be used in this context */
3203 if(FileOffset
.u
.HighPart
< 0)
3205 KeBugCheck(MEMORY_MANAGEMENT
);
3208 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3209 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3210 FileOffset
.u
.LowPart
= AdjustOffset
;
3212 BufferSize
= Length
+ OffsetAdjustment
;
3213 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3216 * It's ok to use paged pool, because this is a temporary buffer only used in
3217 * the loading of executables. The assumption is that MmCreateSection is
3218 * always called at low IRQLs and that these buffers don't survive a brief
3219 * initialization phase
3221 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3226 KeBugCheck(MEMORY_MANAGEMENT
);
3231 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3233 UsedSize
= (ULONG
)Iosb
.Information
;
3235 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3237 Status
= STATUS_IN_PAGE_ERROR
;
3238 ASSERT(!NT_SUCCESS(Status
));
3241 if(NT_SUCCESS(Status
))
3243 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3244 *AllocBase
= Buffer
;
3245 *ReadSize
= UsedSize
- OffsetAdjustment
;
3249 ExFreePoolWithTag(Buffer
, 'rXmM');
3256 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3257 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3258 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3263 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3267 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3269 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3270 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3277 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3281 MmspAssertSegmentsSorted(ImageSectionObject
);
3283 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3285 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3289 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3290 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3291 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3299 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3303 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3305 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3306 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3314 MmspCompareSegments(const void * x
,
3317 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3318 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3321 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3322 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3326 * Ensures an image section's segments are sorted in memory
3331 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3334 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3336 MmspAssertSegmentsSorted(ImageSectionObject
);
3340 qsort(ImageSectionObject
->Segments
,
3341 ImageSectionObject
->NrSegments
,
3342 sizeof(ImageSectionObject
->Segments
[0]),
3343 MmspCompareSegments
);
3349 * Ensures an image section's segments don't overlap in memory and don't have
3350 * gaps and don't have a null size. We let them map to overlapping file regions,
3351 * though - that's not necessarily an error
3356 MmspCheckSegmentBounds
3358 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3364 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3366 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3370 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3372 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3374 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3382 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3383 * page could be OK (Windows seems to be OK with them), and larger gaps
3384 * could lead to image sections spanning several discontiguous regions
3385 * (NtMapViewOfSection could then refuse to map them, and they could
3386 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3388 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3389 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3390 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3401 * Merges and pads an image section's segments until they all are page-aligned
3402 * and have a size that is a multiple of the page size
3407 MmspPageAlignSegments
3409 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3415 PMM_SECTION_SEGMENT EffectiveSegment
;
3417 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3419 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3424 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3426 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3429 * The first segment requires special handling
3433 ULONG_PTR VirtualAddress
;
3434 ULONG_PTR VirtualOffset
;
3436 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3438 /* Round down the virtual address to the nearest page */
3439 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3441 /* Round up the virtual size to the nearest page */
3442 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3443 EffectiveSegment
->Image
.VirtualAddress
;
3445 /* Adjust the raw address and size */
3446 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3448 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3454 * Garbage in, garbage out: unaligned base addresses make the file
3455 * offset point in curious and odd places, but that's what we were
3458 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3459 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3463 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3464 ULONG_PTR EndOfEffectiveSegment
;
3466 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3467 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3470 * The current segment begins exactly where the current effective
3471 * segment ended, therefore beginning a new effective segment
3473 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3476 ASSERT(LastSegment
<= i
);
3477 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3479 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3481 if (LastSegment
!= i
)
3484 * Copy the current segment. If necessary, the effective segment
3485 * will be expanded later
3487 *EffectiveSegment
= *Segment
;
3491 * Page-align the virtual size. We know for sure the virtual address
3494 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3495 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3498 * The current segment is still part of the current effective segment:
3499 * extend the effective segment to reflect this
3501 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3503 static const ULONG FlagsToProtection
[16] =
3511 PAGE_EXECUTE_READWRITE
,
3512 PAGE_EXECUTE_READWRITE
,
3517 PAGE_EXECUTE_WRITECOPY
,
3518 PAGE_EXECUTE_WRITECOPY
,
3519 PAGE_EXECUTE_WRITECOPY
,
3520 PAGE_EXECUTE_WRITECOPY
3523 unsigned ProtectionFlags
;
3526 * Extend the file size
3529 /* Unaligned segments must be contiguous within the file */
3530 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3531 EffectiveSegment
->RawLength
.QuadPart
))
3536 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3539 * Extend the virtual size
3541 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3543 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3544 EffectiveSegment
->Image
.VirtualAddress
;
3547 * Merge the protection
3549 EffectiveSegment
->Protection
|= Segment
->Protection
;
3551 /* Clean up redundance */
3552 ProtectionFlags
= 0;
3554 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3555 ProtectionFlags
|= 1 << 0;
3557 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3558 ProtectionFlags
|= 1 << 1;
3560 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3561 ProtectionFlags
|= 1 << 2;
3563 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3564 ProtectionFlags
|= 1 << 3;
3566 ASSERT(ProtectionFlags
< 16);
3567 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3569 /* If a segment was required to be shared and cannot, fail */
3570 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3571 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3577 * We assume no holes between segments at this point
3581 KeBugCheck(MEMORY_MANAGEMENT
);
3585 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3591 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3592 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3594 LARGE_INTEGER Offset
;
3596 PVOID FileHeaderBuffer
;
3597 ULONG FileHeaderSize
;
3599 ULONG OldNrSegments
;
3604 * Read the beginning of the file (2 pages). Should be enough to contain
3605 * all (or most) of the headers
3607 Offset
.QuadPart
= 0;
3609 /* FIXME: use FileObject instead of FileHandle */
3610 Status
= ExeFmtpReadFile (FileHandle
,
3617 if (!NT_SUCCESS(Status
))
3620 if (FileHeaderSize
== 0)
3622 ExFreePool(FileHeaderBuffer
);
3623 return STATUS_UNSUCCESSFUL
;
3627 * Look for a loader that can handle this executable
3629 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3631 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3634 /* FIXME: use FileObject instead of FileHandle */
3635 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3641 ExeFmtpAllocateSegments
);
3643 if (!NT_SUCCESS(Status
))
3645 if (ImageSectionObject
->Segments
)
3647 ExFreePool(ImageSectionObject
->Segments
);
3648 ImageSectionObject
->Segments
= NULL
;
3652 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3656 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3659 * No loader handled the format
3661 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3663 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3664 ASSERT(!NT_SUCCESS(Status
));
3667 if (!NT_SUCCESS(Status
))
3670 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3675 /* FIXME? are these values platform-dependent? */
3676 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3677 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3679 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3680 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3682 if(ImageSectionObject
->BasedAddress
== NULL
)
3684 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3685 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3687 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3691 * And now the fun part: fixing the segments
3694 /* Sort them by virtual address */
3695 MmspSortSegments(ImageSectionObject
, Flags
);
3697 /* Ensure they don't overlap in memory */
3698 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3699 return STATUS_INVALID_IMAGE_FORMAT
;
3701 /* Ensure they are aligned */
3702 OldNrSegments
= ImageSectionObject
->NrSegments
;
3704 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3705 return STATUS_INVALID_IMAGE_FORMAT
;
3707 /* Trim them if the alignment phase merged some of them */
3708 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3710 PMM_SECTION_SEGMENT Segments
;
3711 SIZE_T SizeOfSegments
;
3713 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3715 Segments
= ExAllocatePoolWithTag(PagedPool
,
3717 TAG_MM_SECTION_SEGMENT
);
3719 if (Segments
== NULL
)
3720 return STATUS_INSUFFICIENT_RESOURCES
;
3722 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3723 ExFreePool(ImageSectionObject
->Segments
);
3724 ImageSectionObject
->Segments
= Segments
;
3727 /* And finish their initialization */
3728 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3730 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3731 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3732 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3735 ASSERT(NT_SUCCESS(Status
));
3740 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3741 ACCESS_MASK DesiredAccess
,
3742 POBJECT_ATTRIBUTES ObjectAttributes
,
3743 PLARGE_INTEGER UMaximumSize
,
3744 ULONG SectionPageProtection
,
3745 ULONG AllocationAttributes
,
3746 PFILE_OBJECT FileObject
)
3748 PROS_SECTION_OBJECT Section
;
3750 PMM_SECTION_SEGMENT SectionSegments
;
3751 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3754 if (FileObject
== NULL
)
3755 return STATUS_INVALID_FILE_FOR_SECTION
;
3758 * Create the section
3760 Status
= ObCreateObject (ExGetPreviousMode(),
3761 MmSectionObjectType
,
3763 ExGetPreviousMode(),
3765 sizeof(ROS_SECTION_OBJECT
),
3768 (PVOID
*)(PVOID
)&Section
);
3769 if (!NT_SUCCESS(Status
))
3771 ObDereferenceObject(FileObject
);
3778 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3779 Section
->Type
= 'SC';
3780 Section
->Size
= 'TN';
3781 Section
->SectionPageProtection
= SectionPageProtection
;
3782 Section
->AllocationAttributes
= AllocationAttributes
;
3786 * Initialized caching for this file object if previously caching
3787 * was initialized for the same on disk file
3789 Status
= CcTryToInitializeFileCache(FileObject
);
3791 Status
= STATUS_SUCCESS
;
3794 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3796 NTSTATUS StatusExeFmt
;
3798 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3799 if (ImageSectionObject
== NULL
)
3801 ObDereferenceObject(FileObject
);
3802 ObDereferenceObject(Section
);
3803 return(STATUS_NO_MEMORY
);
3806 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3808 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3810 if (!NT_SUCCESS(StatusExeFmt
))
3812 if(ImageSectionObject
->Segments
!= NULL
)
3813 ExFreePool(ImageSectionObject
->Segments
);
3815 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3816 ObDereferenceObject(Section
);
3817 ObDereferenceObject(FileObject
);
3818 return(StatusExeFmt
);
3821 Section
->ImageSection
= ImageSectionObject
;
3822 ASSERT(ImageSectionObject
->Segments
);
3827 Status
= MmspWaitForFileLock(FileObject
);
3828 if (!NT_SUCCESS(Status
))
3830 ExFreePool(ImageSectionObject
->Segments
);
3831 ExFreePool(ImageSectionObject
);
3832 ObDereferenceObject(Section
);
3833 ObDereferenceObject(FileObject
);
3837 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3838 ImageSectionObject
, NULL
))
3841 * An other thread has initialized the same image in the background
3843 ExFreePool(ImageSectionObject
->Segments
);
3844 ExFreePool(ImageSectionObject
);
3845 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3846 Section
->ImageSection
= ImageSectionObject
;
3847 SectionSegments
= ImageSectionObject
->Segments
;
3849 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3851 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3855 Status
= StatusExeFmt
;
3862 Status
= MmspWaitForFileLock(FileObject
);
3863 if (Status
!= STATUS_SUCCESS
)
3865 ObDereferenceObject(Section
);
3866 ObDereferenceObject(FileObject
);
3870 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3871 Section
->ImageSection
= ImageSectionObject
;
3872 SectionSegments
= ImageSectionObject
->Segments
;
3875 * Otherwise just reference all the section segments
3877 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3879 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3882 Status
= STATUS_SUCCESS
;
3884 Section
->FileObject
= FileObject
;
3886 CcRosReferenceCache(FileObject
);
3888 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3889 *SectionObject
= Section
;
3896 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3897 PROS_SECTION_OBJECT Section
,
3898 PMM_SECTION_SEGMENT Segment
,
3903 ULONG AllocationType
)
3909 if (Segment
->WriteCopy
)
3911 /* We have to do this because the not present fault
3912 * and access fault handlers depend on the protection
3913 * that should be granted AFTER the COW fault takes
3914 * place to be in Region->Protect. The not present fault
3915 * handler changes this to the correct protection for COW when
3916 * mapping the pages into the process's address space. If a COW
3917 * fault takes place, the access fault handler sets the page protection
3918 * to these values for the newly copied pages
3920 if (Protect
== PAGE_WRITECOPY
)
3921 Protect
= PAGE_READWRITE
;
3922 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3923 Protect
= PAGE_EXECUTE_READWRITE
;
3926 if (*BaseAddress
== NULL
)
3927 Granularity
= MM_ALLOCATION_GRANULARITY
;
3929 Granularity
= PAGE_SIZE
;
3932 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
3933 LARGE_INTEGER FileOffset
;
3934 FileOffset
.QuadPart
= ViewOffset
;
3935 ObReferenceObject(Section
);
3936 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3939 Status
= MmCreateMemoryArea(AddressSpace
,
3940 MEMORY_AREA_SECTION_VIEW
,
3948 if (!NT_SUCCESS(Status
))
3950 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3951 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3955 ObReferenceObject((PVOID
)Section
);
3957 MArea
->Data
.SectionData
.Segment
= Segment
;
3958 MArea
->Data
.SectionData
.Section
= Section
;
3959 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3960 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3961 ViewSize
, 0, Protect
);
3963 return(STATUS_SUCCESS
);
3968 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3969 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3972 PFILE_OBJECT FileObject
;
3974 LARGE_INTEGER Offset
;
3975 SWAPENTRY SavedSwapEntry
;
3976 PROS_SECTION_OBJECT Section
;
3977 PMM_SECTION_SEGMENT Segment
;
3978 PMMSUPPORT AddressSpace
;
3981 AddressSpace
= (PMMSUPPORT
)Context
;
3982 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3984 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3986 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3987 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3989 Section
= MemoryArea
->Data
.SectionData
.Section
;
3990 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3992 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3993 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
3995 MmUnlockSectionSegment(Segment
);
3996 MmUnlockAddressSpace(AddressSpace
);
3998 MiWaitForPageEvent(NULL
, NULL
);
4000 MmLockAddressSpace(AddressSpace
);
4001 MmLockSectionSegment(Segment
);
4002 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4006 * For a dirty, datafile, non-private page mark it as dirty in the
4009 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4011 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4013 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4014 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4016 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)(Offset
.QuadPart
+ Segment
->Image
.FileOffset
));
4018 ASSERT(SwapEntry
== 0);
4027 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4029 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4030 KeBugCheck(MEMORY_MANAGEMENT
);
4032 MmFreeSwapPage(SwapEntry
);
4036 if (IS_SWAP_FROM_SSE(Entry
) ||
4037 Page
!= PFN_FROM_SSE(Entry
))
4042 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4044 DPRINT1("Found a private page in a pagefile section.\n");
4045 KeBugCheck(MEMORY_MANAGEMENT
);
4048 * Just dereference private pages
4050 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4051 if (SavedSwapEntry
!= 0)
4053 MmFreeSwapPage(SavedSwapEntry
);
4054 MmSetSavedSwapEntryPage(Page
, 0);
4056 MmDeleteRmap(Page
, Process
, Address
);
4057 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4061 MmDeleteRmap(Page
, Process
, Address
);
4062 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4068 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4072 PMEMORY_AREA MemoryArea
;
4073 PROS_SECTION_OBJECT Section
;
4074 PMM_SECTION_SEGMENT Segment
;
4075 PLIST_ENTRY CurrentEntry
;
4076 PMM_REGION CurrentRegion
;
4077 PLIST_ENTRY RegionListHead
;
4079 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4081 if (MemoryArea
== NULL
)
4083 return(STATUS_UNSUCCESSFUL
);
4086 MemoryArea
->DeleteInProgress
= TRUE
;
4087 Section
= MemoryArea
->Data
.SectionData
.Section
;
4088 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4091 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4092 return MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4095 MmLockSectionSegment(Segment
);
4097 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4098 while (!IsListEmpty(RegionListHead
))
4100 CurrentEntry
= RemoveHeadList(RegionListHead
);
4101 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4102 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4105 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4107 Status
= MmFreeMemoryArea(AddressSpace
,
4114 Status
= MmFreeMemoryArea(AddressSpace
,
4119 MmUnlockSectionSegment(Segment
);
4120 ObDereferenceObject(Section
);
4126 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4127 IN PVOID BaseAddress
,
4131 PMEMORY_AREA MemoryArea
;
4132 PMMSUPPORT AddressSpace
;
4133 PROS_SECTION_OBJECT Section
;
4134 PVOID ImageBaseAddress
= 0;
4136 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4137 Process
, BaseAddress
);
4141 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4143 MmLockAddressSpace(AddressSpace
);
4144 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4146 if (MemoryArea
== NULL
||
4147 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4148 MemoryArea
->DeleteInProgress
)
4150 if (MemoryArea
) NT_ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4151 MmUnlockAddressSpace(AddressSpace
);
4152 return STATUS_NOT_MAPPED_VIEW
;
4155 MemoryArea
->DeleteInProgress
= TRUE
;
4157 Section
= MemoryArea
->Data
.SectionData
.Section
;
4159 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4163 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4164 PMM_SECTION_SEGMENT SectionSegments
;
4165 PMM_SECTION_SEGMENT Segment
;
4167 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4168 ImageSectionObject
= Section
->ImageSection
;
4169 SectionSegments
= ImageSectionObject
->Segments
;
4170 NrSegments
= ImageSectionObject
->NrSegments
;
4172 /* Search for the current segment within the section segments
4173 * and calculate the image base address */
4174 for (i
= 0; i
< NrSegments
; i
++)
4176 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4178 if (Segment
== &SectionSegments
[i
])
4180 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4185 if (i
>= NrSegments
)
4187 KeBugCheck(MEMORY_MANAGEMENT
);
4190 for (i
= 0; i
< NrSegments
; i
++)
4192 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4194 PVOID SBaseAddress
= (PVOID
)
4195 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4197 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4198 NT_ASSERT(NT_SUCCESS(Status
));
4204 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4205 NT_ASSERT(NT_SUCCESS(Status
));
4208 MmUnlockAddressSpace(AddressSpace
);
4210 /* Notify debugger */
4211 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4213 return(STATUS_SUCCESS
);
4220 * Queries the information of a section object.
4222 * @param SectionHandle
4223 * Handle to the section object. It must be opened with SECTION_QUERY
4225 * @param SectionInformationClass
4226 * Index to a certain information structure. Can be either
4227 * SectionBasicInformation or SectionImageInformation. The latter
4228 * is valid only for sections that were created with the SEC_IMAGE
4230 * @param SectionInformation
4231 * Caller supplies storage for resulting information.
4233 * Size of the supplied storage.
4234 * @param ResultLength
4242 NtQuerySection(IN HANDLE SectionHandle
,
4243 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4244 OUT PVOID SectionInformation
,
4245 IN SIZE_T SectionInformationLength
,
4246 OUT PSIZE_T ResultLength OPTIONAL
)
4248 PROS_SECTION_OBJECT Section
;
4249 KPROCESSOR_MODE PreviousMode
;
4253 PreviousMode
= ExGetPreviousMode();
4255 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4257 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4259 (ULONG
)SectionInformationLength
,
4264 if(!NT_SUCCESS(Status
))
4266 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4270 Status
= ObReferenceObjectByHandle(SectionHandle
,
4272 MmSectionObjectType
,
4274 (PVOID
*)(PVOID
)&Section
,
4276 if (NT_SUCCESS(Status
))
4278 switch (SectionInformationClass
)
4280 case SectionBasicInformation
:
4282 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4286 Sbi
->Attributes
= Section
->AllocationAttributes
;
4287 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4289 Sbi
->BaseAddress
= 0;
4290 Sbi
->Size
.QuadPart
= 0;
4294 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4295 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4298 if (ResultLength
!= NULL
)
4300 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4302 Status
= STATUS_SUCCESS
;
4304 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4306 Status
= _SEH2_GetExceptionCode();
4313 case SectionImageInformation
:
4315 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4319 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4321 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4322 ImageSectionObject
= Section
->ImageSection
;
4324 *Sii
= ImageSectionObject
->ImageInformation
;
4327 if (ResultLength
!= NULL
)
4329 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4331 Status
= STATUS_SUCCESS
;
4333 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4335 Status
= _SEH2_GetExceptionCode();
4343 ObDereferenceObject(Section
);
4349 /**********************************************************************
4351 * MmMapViewOfSection
4354 * Maps a view of a section into the virtual address space of a
4359 * Pointer to the section object.
4362 * Pointer to the process.
4365 * Desired base address (or NULL) on entry;
4366 * Actual base address of the view on exit.
4369 * Number of high order address bits that must be zero.
4372 * Size in bytes of the initially committed section of
4376 * Offset in bytes from the beginning of the section
4377 * to the beginning of the view.
4380 * Desired length of map (or zero to map all) on entry
4381 * Actual length mapped on exit.
4383 * InheritDisposition
4384 * Specified how the view is to be shared with
4388 * Type of allocation for the pages.
4391 * Protection for the committed region of the view.
4399 MmMapViewOfSection(IN PVOID SectionObject
,
4400 IN PEPROCESS Process
,
4401 IN OUT PVOID
*BaseAddress
,
4402 IN ULONG_PTR ZeroBits
,
4403 IN SIZE_T CommitSize
,
4404 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4405 IN OUT PSIZE_T ViewSize
,
4406 IN SECTION_INHERIT InheritDisposition
,
4407 IN ULONG AllocationType
,
4410 PROS_SECTION_OBJECT Section
;
4411 PMMSUPPORT AddressSpace
;
4413 NTSTATUS Status
= STATUS_SUCCESS
;
4414 BOOLEAN NotAtBase
= FALSE
;
4416 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4418 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4419 return MmMapViewOfArm3Section(SectionObject
,
4433 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4435 return STATUS_INVALID_PAGE_PROTECTION
;
4439 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4440 AddressSpace
= &Process
->Vm
;
4442 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4444 MmLockAddressSpace(AddressSpace
);
4446 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4450 ULONG_PTR ImageBase
;
4452 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4453 PMM_SECTION_SEGMENT SectionSegments
;
4455 ImageSectionObject
= Section
->ImageSection
;
4456 SectionSegments
= ImageSectionObject
->Segments
;
4457 NrSegments
= ImageSectionObject
->NrSegments
;
4459 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4462 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4466 for (i
= 0; i
< NrSegments
; i
++)
4468 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4470 ULONG_PTR MaxExtent
;
4471 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4472 SectionSegments
[i
].Length
.QuadPart
);
4473 ImageSize
= max(ImageSize
, MaxExtent
);
4477 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4479 /* Check for an illegal base address */
4480 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4481 ((ImageBase
+ ImageSize
) < ImageSize
))
4483 NT_ASSERT(*BaseAddress
== NULL
);
4484 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4485 MM_VIRTMEM_GRANULARITY
);
4488 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4490 NT_ASSERT(*BaseAddress
== NULL
);
4491 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4495 /* Check there is enough space to map the section at that point. */
4496 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4497 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4499 /* Fail if the user requested a fixed base address. */
4500 if ((*BaseAddress
) != NULL
)
4502 MmUnlockAddressSpace(AddressSpace
);
4503 return(STATUS_CONFLICTING_ADDRESSES
);
4505 /* Otherwise find a gap to map the image. */
4506 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4509 MmUnlockAddressSpace(AddressSpace
);
4510 return(STATUS_CONFLICTING_ADDRESSES
);
4512 /* Remember that we loaded image at a different base address */
4516 for (i
= 0; i
< NrSegments
; i
++)
4518 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4520 PVOID SBaseAddress
= (PVOID
)
4521 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4522 MmLockSectionSegment(&SectionSegments
[i
]);
4523 Status
= MmMapViewOfSegment(AddressSpace
,
4525 &SectionSegments
[i
],
4527 SectionSegments
[i
].Length
.LowPart
,
4528 SectionSegments
[i
].Protection
,
4531 MmUnlockSectionSegment(&SectionSegments
[i
]);
4532 if (!NT_SUCCESS(Status
))
4534 MmUnlockAddressSpace(AddressSpace
);
4540 *BaseAddress
= (PVOID
)ImageBase
;
4541 *ViewSize
= ImageSize
;
4545 /* check for write access */
4546 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4547 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4549 MmUnlockAddressSpace(AddressSpace
);
4550 return STATUS_SECTION_PROTECTION
;
4552 /* check for read access */
4553 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4554 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4556 MmUnlockAddressSpace(AddressSpace
);
4557 return STATUS_SECTION_PROTECTION
;
4559 /* check for execute access */
4560 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4561 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4563 MmUnlockAddressSpace(AddressSpace
);
4564 return STATUS_SECTION_PROTECTION
;
4567 if (ViewSize
== NULL
)
4569 /* Following this pointer would lead to us to the dark side */
4570 /* What to do? Bugcheck? Return status? Do the mambo? */
4571 KeBugCheck(MEMORY_MANAGEMENT
);
4574 if (SectionOffset
== NULL
)
4580 ViewOffset
= SectionOffset
->u
.LowPart
;
4583 if ((ViewOffset
% PAGE_SIZE
) != 0)
4585 MmUnlockAddressSpace(AddressSpace
);
4586 return(STATUS_MAPPED_ALIGNMENT
);
4589 if ((*ViewSize
) == 0)
4591 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4593 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4595 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4598 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4600 MmLockSectionSegment(Section
->Segment
);
4601 Status
= MmMapViewOfSegment(AddressSpace
,
4608 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4609 MmUnlockSectionSegment(Section
->Segment
);
4610 if (!NT_SUCCESS(Status
))
4612 MmUnlockAddressSpace(AddressSpace
);
4617 MmUnlockAddressSpace(AddressSpace
);
4618 NT_ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4621 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4623 Status
= STATUS_SUCCESS
;
4632 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4633 IN PLARGE_INTEGER NewFileSize
)
4635 /* Check whether an ImageSectionObject exists */
4636 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4638 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4642 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4644 PMM_SECTION_SEGMENT Segment
;
4646 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4649 if (Segment
->ReferenceCount
!= 0)
4652 CC_FILE_SIZES FileSizes
;
4654 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4657 /* Check size of file */
4658 if (SectionObjectPointer
->SharedCacheMap
)
4660 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4665 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4674 /* Check size of file */
4675 if (SectionObjectPointer
->SharedCacheMap
)
4677 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4678 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4687 /* Something must gone wrong
4688 * how can we have a Section but no
4690 DPRINT("ERROR: DataSectionObject without reference!\n");
4694 DPRINT("FIXME: didn't check for outstanding write probes\n");
4706 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4707 IN MMFLUSH_TYPE FlushType
)
4709 BOOLEAN Result
= TRUE
;
4711 PMM_SECTION_SEGMENT Segment
;
4716 case MmFlushForDelete
:
4717 if (SectionObjectPointer
->ImageSectionObject
||
4718 SectionObjectPointer
->DataSectionObject
)
4723 CcRosSetRemoveOnClose(SectionObjectPointer
);
4726 case MmFlushForWrite
:
4728 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4730 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4733 if (SectionObjectPointer
->ImageSectionObject
) {
4734 DPRINT1("SectionObject has ImageSection\n");
4740 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4742 DPRINT("Result %d\n", Result
);
4754 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4755 OUT PVOID
* MappedBase
,
4756 IN OUT PSIZE_T ViewSize
)
4758 PROS_SECTION_OBJECT Section
;
4759 PMMSUPPORT AddressSpace
;
4763 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4765 return MiMapViewInSystemSpace(SectionObject
,
4771 DPRINT("MmMapViewInSystemSpace() called\n");
4773 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4774 AddressSpace
= MmGetKernelAddressSpace();
4776 MmLockAddressSpace(AddressSpace
);
4779 if ((*ViewSize
) == 0)
4781 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4783 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4785 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4788 MmLockSectionSegment(Section
->Segment
);
4791 Status
= MmMapViewOfSegment(AddressSpace
,
4800 MmUnlockSectionSegment(Section
->Segment
);
4801 MmUnlockAddressSpace(AddressSpace
);
4808 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4810 PMMSUPPORT AddressSpace
;
4813 DPRINT("MmUnmapViewInSystemSpace() called\n");
4815 AddressSpace
= MmGetKernelAddressSpace();
4817 MmLockAddressSpace(AddressSpace
);
4819 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4821 MmUnlockAddressSpace(AddressSpace
);
4826 /**********************************************************************
4831 * Creates a section object.
4834 * SectionObject (OUT)
4835 * Caller supplied storage for the resulting pointer
4836 * to a SECTION_OBJECT instance;
4839 * Specifies the desired access to the section can be a
4841 * STANDARD_RIGHTS_REQUIRED |
4843 * SECTION_MAP_WRITE |
4844 * SECTION_MAP_READ |
4845 * SECTION_MAP_EXECUTE
4847 * ObjectAttributes [OPTIONAL]
4848 * Initialized attributes for the object can be used
4849 * to create a named section;
4852 * Maximizes the size of the memory section. Must be
4853 * non-NULL for a page-file backed section.
4854 * If value specified for a mapped file and the file is
4855 * not large enough, file will be extended.
4857 * SectionPageProtection
4858 * Can be a combination of:
4864 * AllocationAttributes
4865 * Can be a combination of:
4870 * Handle to a file to create a section mapped to a file
4871 * instead of a memory backed section;
4882 MmCreateSection (OUT PVOID
* Section
,
4883 IN ACCESS_MASK DesiredAccess
,
4884 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4885 IN PLARGE_INTEGER MaximumSize
,
4886 IN ULONG SectionPageProtection
,
4887 IN ULONG AllocationAttributes
,
4888 IN HANDLE FileHandle OPTIONAL
,
4889 IN PFILE_OBJECT FileObject OPTIONAL
)
4893 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4895 /* Check if an ARM3 section is being created instead */
4896 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4898 if (!(FileObject
) && !(FileHandle
))
4900 return MmCreateArm3Section(Section
,
4904 SectionPageProtection
,
4905 AllocationAttributes
&~ 1,
4911 /* Convert section flag to page flag */
4912 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4914 /* Check to make sure the protection is correct. Nt* does this already */
4915 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4916 if (Protection
== MM_INVALID_PROTECTION
)
4918 DPRINT1("Page protection is invalid\n");
4919 return STATUS_INVALID_PAGE_PROTECTION
;
4922 /* Check if this is going to be a data or image backed file section */
4923 if ((FileHandle
) || (FileObject
))
4925 /* These cannot be mapped with large pages */
4926 if (AllocationAttributes
& SEC_LARGE_PAGES
)
4928 DPRINT1("Large pages cannot be used with an image mapping\n");
4929 return STATUS_INVALID_PARAMETER_6
;
4932 /* Did the caller pass an object? */
4935 /* Reference the object directly */
4936 ObReferenceObject(FileObject
);
4940 /* Reference the file handle to get the object */
4941 Status
= ObReferenceObjectByHandle(FileHandle
,
4942 MmMakeFileAccess
[Protection
],
4944 ExGetPreviousMode(),
4945 (PVOID
*)&FileObject
,
4947 if (!NT_SUCCESS(Status
))
4949 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
4956 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
4957 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
4960 #ifndef NEWCC // A hack for initializing caching.
4961 // This is needed only in the old case.
4964 IO_STATUS_BLOCK Iosb
;
4967 LARGE_INTEGER ByteOffset
;
4968 ByteOffset
.QuadPart
= 0;
4969 Status
= ZwReadFile(FileHandle
,
4978 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
4980 DPRINT1("CC failure: %lx\n", Status
);
4983 // Caching is initialized...
4987 if (AllocationAttributes
& SEC_IMAGE
)
4989 Status
= MmCreateImageSection(SectionObject
,
4993 SectionPageProtection
,
4994 AllocationAttributes
,
4998 else if (FileHandle
!= NULL
)
5000 Status
= MmCreateDataFileSection(SectionObject
,
5004 SectionPageProtection
,
5005 AllocationAttributes
,
5008 ObDereferenceObject(FileObject
);
5011 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5013 Status
= MmCreateCacheSection(SectionObject
,
5017 SectionPageProtection
,
5018 AllocationAttributes
,
5024 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5026 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5028 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5029 Status
= MmCreatePageFileSection(SectionObject
,
5033 SectionPageProtection
,
5034 AllocationAttributes
);