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 /* check if this is an old MZ executable */
243 if(pidhDosHeader
->e_lfarlc
< 0x40)
244 DIE(("Old-style MZ executable found, e_lfarlc is %d\n", pidhDosHeader
->e_lfarlc
));
246 /* not a Windows executable */
247 if(pidhDosHeader
->e_lfanew
<= 0)
248 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
251 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
253 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
254 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
256 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
261 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
262 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
264 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
265 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
269 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
270 * need to read the header from the file
272 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
273 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
275 ULONG cbNtHeaderSize
;
279 l_ReadHeaderFromFile
:
281 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
283 /* read the header from the file */
284 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
286 if(!NT_SUCCESS(nStatus
))
287 DIE(("ReadFile failed, status %08X\n", nStatus
));
291 ASSERT(cbReadSize
> 0);
293 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
295 /* the buffer doesn't contain the file header */
296 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
297 DIE(("The file doesn't contain the PE file header\n"));
299 pinhNtHeader
= pData
;
301 /* object still not aligned: copy it to the beginning of the buffer */
302 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
304 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
305 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
306 pinhNtHeader
= pBuffer
;
309 /* invalid NT header */
310 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
312 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
313 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
315 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
317 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
318 DIE(("The full NT header is too large\n"));
320 /* the buffer doesn't contain the whole NT header */
321 if(cbReadSize
< cbNtHeaderSize
)
322 DIE(("The file doesn't contain the full NT header\n"));
326 ULONG cbOptHeaderOffsetSize
= 0;
328 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
330 /* don't trust an invalid NT header */
331 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
332 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
334 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
335 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
337 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
338 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
340 /* the buffer doesn't contain the whole NT header: read it from the file */
341 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
342 goto l_ReadHeaderFromFile
;
345 /* read information from the NT header */
346 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
347 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
349 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
351 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
352 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
354 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
356 switch(piohOptHeader
->Magic
)
358 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
359 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
363 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
366 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
367 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
369 /* See [1], section 3.4.2 */
370 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
372 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
373 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
375 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
376 DIE(("The section alignment is smaller than the file alignment\n"));
378 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
379 nFileAlignment
= piohOptHeader
->FileAlignment
;
381 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
382 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
386 nSectionAlignment
= PAGE_SIZE
;
387 nFileAlignment
= PAGE_SIZE
;
390 ASSERT(IsPowerOf2(nSectionAlignment
));
391 ASSERT(IsPowerOf2(nFileAlignment
));
393 switch(piohOptHeader
->Magic
)
396 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
398 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
399 ImageBase
= piohOptHeader
->ImageBase
;
401 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
402 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
404 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
405 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
407 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
408 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
410 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
412 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
414 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
415 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
417 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
418 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
422 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
424 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
425 piohOptHeader
->AddressOfEntryPoint
);
428 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
429 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
431 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
433 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
435 if (piohOptHeader
->AddressOfEntryPoint
== 0)
437 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
441 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
442 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
444 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
446 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
449 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
450 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
451 * magic to any binary.
453 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
454 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
455 * the SxS support -- at which point, duh, this should be removed.
457 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
459 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
466 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
468 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
470 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
472 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
474 ImageBase
= pioh64OptHeader
->ImageBase
;
475 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
476 DIE(("ImageBase exceeds the address space\n"));
479 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
481 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
482 DIE(("SizeOfImage exceeds the address space\n"));
484 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
487 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
489 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
490 DIE(("SizeOfStackReserve exceeds the address space\n"));
492 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
495 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
497 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
498 DIE(("SizeOfStackCommit exceeds the address space\n"));
500 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
503 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
505 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
507 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
508 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
510 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
511 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
515 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
517 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
518 pioh64OptHeader
->AddressOfEntryPoint
);
521 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
522 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
524 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
526 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
528 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
530 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
534 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
535 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
537 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
538 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
545 /* [1], section 3.4.2 */
546 if((ULONG_PTR
)ImageBase
% 0x10000)
547 DIE(("ImageBase is not aligned on a 64KB boundary"));
549 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
550 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
551 ImageSectionObject
->ImageInformation
.GpValue
= 0;
552 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
553 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
555 /* SECTION HEADERS */
556 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
558 /* see [1], section 3.3 */
559 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
560 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
563 * the additional segment is for the file's headers. They need to be present for
564 * the benefit of the dynamic loader (to locate exports, defaults for thread
565 * parameters, resources, etc.)
567 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
569 /* file offset for the section headers */
570 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
571 DIE(("Offset overflow\n"));
573 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
574 DIE(("Offset overflow\n"));
576 /* size of the section headers */
577 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
578 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
580 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
581 DIE(("Section headers too large\n"));
583 /* size of the executable's headers */
584 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
586 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
587 // DIE(("SizeOfHeaders is not aligned\n"));
589 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
590 DIE(("The section headers overflow SizeOfHeaders\n"));
592 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
594 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
595 DIE(("Overflow aligning the size of headers\n"));
602 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
603 /* WARNING: piohOptHeader IS NO LONGER USABLE */
604 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
606 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
607 pishSectionHeaders
= NULL
;
611 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
612 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
614 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
615 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
619 * the buffer doesn't contain the section headers, or the alignment is wrong:
620 * read the headers from the file
622 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
623 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
628 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
630 /* read the header from the file */
631 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
633 if(!NT_SUCCESS(nStatus
))
634 DIE(("ReadFile failed with status %08X\n", nStatus
));
638 ASSERT(cbReadSize
> 0);
640 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
642 /* the buffer doesn't contain all the section headers */
643 if(cbReadSize
< cbSectionHeadersSize
)
644 DIE(("The file doesn't contain all of the section headers\n"));
646 pishSectionHeaders
= pData
;
648 /* object still not aligned: copy it to the beginning of the buffer */
649 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
651 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
652 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
653 pishSectionHeaders
= pBuffer
;
658 /* allocate the segments */
659 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
660 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
662 if(ImageSectionObject
->Segments
== NULL
)
663 DIE(("AllocateSegments failed\n"));
665 /* initialize the headers segment */
666 pssSegments
= ImageSectionObject
->Segments
;
668 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
670 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
671 DIE(("Cannot align the size of the section headers\n"));
673 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
674 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
675 DIE(("Cannot align the size of the section headers\n"));
677 pssSegments
[0].Image
.FileOffset
= 0;
678 pssSegments
[0].Protection
= PAGE_READONLY
;
679 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
680 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
681 pssSegments
[0].Image
.VirtualAddress
= 0;
682 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
683 pssSegments
[0].WriteCopy
= TRUE
;
685 /* skip the headers segment */
688 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
690 /* convert the executable sections into segments. See also [1], section 4 */
691 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
693 ULONG nCharacteristics
;
695 /* validate the alignment */
696 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
697 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
699 /* sections must be contiguous, ordered by base address and non-overlapping */
700 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
701 DIE(("Memory gap between section %u and the previous\n", i
));
703 /* ignore explicit BSS sections */
704 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
706 /* validate the alignment */
708 /* Yes, this should be a multiple of FileAlignment, but there's
709 * stuff out there that isn't. We can cope with that
711 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
712 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
715 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
716 // DIE(("PointerToRawData[%u] is not aligned\n", i));
719 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
720 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
724 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
725 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
728 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
730 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
732 /* no explicit protection */
733 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
735 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
736 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
738 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
739 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
741 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
742 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
745 /* see table above */
746 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
747 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
749 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
750 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
752 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
754 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
755 /* FIXME: always false */
756 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
757 DIE(("Cannot align the virtual size of section %u\n", i
));
759 if(pssSegments
[i
].Length
.QuadPart
== 0)
760 DIE(("Virtual size of section %u is null\n", i
));
762 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
763 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
765 /* ensure the memory image is no larger than 4GB */
766 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
767 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
768 DIE(("The image is too large\n"));
771 if(nSectionAlignment
>= PAGE_SIZE
)
772 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
775 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
785 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
786 * ARGUMENTS: PFILE_OBJECT to wait for.
787 * RETURNS: Status of the wait.
790 MmspWaitForFileLock(PFILE_OBJECT File
)
792 return STATUS_SUCCESS
;
793 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
798 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
800 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
802 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
803 PMM_SECTION_SEGMENT SectionSegments
;
807 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
808 NrSegments
= ImageSectionObject
->NrSegments
;
809 SectionSegments
= ImageSectionObject
->Segments
;
810 for (i
= 0; i
< NrSegments
; i
++)
812 if (SectionSegments
[i
].ReferenceCount
!= 0)
814 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
815 SectionSegments
[i
].ReferenceCount
);
816 KeBugCheck(MEMORY_MANAGEMENT
);
818 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
820 ExFreePool(ImageSectionObject
->Segments
);
821 ExFreePool(ImageSectionObject
);
822 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
824 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
826 PMM_SECTION_SEGMENT Segment
;
828 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
831 if (Segment
->ReferenceCount
!= 0)
833 DPRINT1("Data segment still referenced\n");
834 KeBugCheck(MEMORY_MANAGEMENT
);
836 MmFreePageTablesSectionSegment(Segment
, NULL
);
838 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
844 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
845 PLARGE_INTEGER Offset
)
849 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
852 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
853 KeBugCheck(MEMORY_MANAGEMENT
);
855 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
857 DPRINT1("Maximum share count reached\n");
858 KeBugCheck(MEMORY_MANAGEMENT
);
860 if (IS_SWAP_FROM_SSE(Entry
))
862 KeBugCheck(MEMORY_MANAGEMENT
);
864 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
865 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
870 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
871 PMM_SECTION_SEGMENT Segment
,
872 PLARGE_INTEGER Offset
,
877 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
878 BOOLEAN IsDirectMapped
= FALSE
;
882 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
883 KeBugCheck(MEMORY_MANAGEMENT
);
885 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
887 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
888 KeBugCheck(MEMORY_MANAGEMENT
);
890 if (IS_SWAP_FROM_SSE(Entry
))
892 KeBugCheck(MEMORY_MANAGEMENT
);
894 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
896 * If we reducing the share count of this entry to zero then set the entry
897 * to zero and tell the cache the page is no longer mapped.
899 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
901 PFILE_OBJECT FileObject
;
905 SWAPENTRY SavedSwapEntry
;
907 BOOLEAN IsImageSection
;
908 LARGE_INTEGER FileOffset
;
910 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
912 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
914 Page
= PFN_FROM_SSE(Entry
);
915 FileObject
= Section
->FileObject
;
916 if (FileObject
!= NULL
&&
917 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
921 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
922 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
925 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
926 IsDirectMapped
= TRUE
;
928 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
.LowPart
, Dirty
);
930 Status
= STATUS_SUCCESS
;
932 if (!NT_SUCCESS(Status
))
934 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
935 KeBugCheck(MEMORY_MANAGEMENT
);
941 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
942 if (SavedSwapEntry
== 0)
945 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
946 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
950 * Try to page out this page and set the swap entry
951 * within the section segment. There exist no rmap entry
952 * for this page. The pager thread can't page out a
953 * page without a rmap entry.
955 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
956 if (InEntry
) *InEntry
= Entry
;
957 MiSetPageEvent(NULL
, NULL
);
961 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
962 if (InEntry
) *InEntry
= 0;
963 MiSetPageEvent(NULL
, NULL
);
966 MmReleasePageMemoryConsumer(MC_USER
, Page
);
972 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
973 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
981 * We hold all locks. Nobody can do something with the current
982 * process and the current segment (also not within an other process).
985 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
986 if (!NT_SUCCESS(Status
))
988 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
989 KeBugCheck(MEMORY_MANAGEMENT
);
992 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
993 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
994 MmSetSavedSwapEntryPage(Page
, 0);
995 MiSetPageEvent(NULL
, NULL
);
997 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1001 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1002 KeBugCheck(MEMORY_MANAGEMENT
);
1011 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1013 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1016 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1020 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1023 PCACHE_SEGMENT CacheSeg
;
1024 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1025 CacheSeg
= CcRosLookupCacheSegment(Bcb
, (ULONG
)(SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
));
1028 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
1038 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1042 PVOID DestAddress
, SrcAddress
;
1044 Process
= PsGetCurrentProcess();
1045 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1046 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1047 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1049 return(STATUS_NO_MEMORY
);
1051 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1052 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1053 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1054 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1055 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1056 return(STATUS_SUCCESS
);
1062 MiReadPage(PMEMORY_AREA MemoryArea
,
1063 ULONG_PTR SegOffset
,
1066 * FUNCTION: Read a page for a section backed memory area.
1068 * MemoryArea - Memory area to read the page for.
1069 * Offset - Offset of the page to read.
1070 * Page - Variable that receives a page contains the read data.
1074 ULONGLONG FileOffset
;
1077 PCACHE_SEGMENT CacheSeg
;
1078 PFILE_OBJECT FileObject
;
1080 ULONG_PTR RawLength
;
1082 BOOLEAN IsImageSection
;
1085 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1086 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1087 RawLength
= (ULONG_PTR
)(MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
);
1088 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1089 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1093 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1096 * If the file system is letting us go directly to the cache and the
1097 * memory area was mapped at an offset in the file which is page aligned
1098 * then get the related cache segment.
1100 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1101 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1102 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1106 * Get the related cache segment; we use a lower level interface than
1107 * filesystems do because it is safe for us to use an offset with a
1108 * alignment less than the file system block size.
1110 Status
= CcRosGetCacheSegment(Bcb
,
1116 if (!NT_SUCCESS(Status
))
1123 * If the cache segment isn't up to date then call the file
1124 * system to read in the data.
1126 Status
= ReadCacheSegment(CacheSeg
);
1127 if (!NT_SUCCESS(Status
))
1129 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1134 /* Probe the page, since it's PDE might not be synced */
1135 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1138 * Retrieve the page from the cache segment that we actually want.
1140 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1141 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1143 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1150 ULONG_PTR CacheSegOffset
;
1153 * Allocate a page, this is rather complicated by the possibility
1154 * we might have to move other things out of memory
1156 MI_SET_USAGE(MI_USAGE_SECTION
);
1157 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1158 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1159 if (!NT_SUCCESS(Status
))
1163 Status
= CcRosGetCacheSegment(Bcb
,
1169 if (!NT_SUCCESS(Status
))
1176 * If the cache segment isn't up to date then call the file
1177 * system to read in the data.
1179 Status
= ReadCacheSegment(CacheSeg
);
1180 if (!NT_SUCCESS(Status
))
1182 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1187 Process
= PsGetCurrentProcess();
1188 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1189 CacheSegOffset
= (ULONG_PTR
)(BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
);
1190 Length
= RawLength
- SegOffset
;
1191 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1193 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1195 else if (CacheSegOffset
>= PAGE_SIZE
)
1197 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1201 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1202 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1203 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1204 Status
= CcRosGetCacheSegment(Bcb
,
1205 (ULONG
)(FileOffset
+ CacheSegOffset
),
1210 if (!NT_SUCCESS(Status
))
1217 * If the cache segment isn't up to date then call the file
1218 * system to read in the data.
1220 Status
= ReadCacheSegment(CacheSeg
);
1221 if (!NT_SUCCESS(Status
))
1223 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1227 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1228 if (Length
< PAGE_SIZE
)
1230 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1234 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1237 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1238 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1240 return(STATUS_SUCCESS
);
1245 MiReadPage(PMEMORY_AREA MemoryArea
,
1246 ULONG_PTR SegOffset
,
1249 * FUNCTION: Read a page for a section backed memory area.
1251 * MemoryArea - Memory area to read the page for.
1252 * Offset - Offset of the page to read.
1253 * Page - Variable that receives a page contains the read data.
1256 MM_REQUIRED_RESOURCES Resources
;
1259 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1261 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1262 Resources
.FileOffset
.QuadPart
= SegOffset
+
1263 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1264 Resources
.Consumer
= MC_USER
;
1265 Resources
.Amount
= PAGE_SIZE
;
1267 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]);
1269 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1270 *Page
= Resources
.Page
[0];
1277 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1278 MEMORY_AREA
* MemoryArea
,
1282 LARGE_INTEGER Offset
;
1285 PROS_SECTION_OBJECT Section
;
1286 PMM_SECTION_SEGMENT Segment
;
1291 BOOLEAN HasSwapEntry
;
1293 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1294 SWAPENTRY SwapEntry
;
1297 * There is a window between taking the page fault and locking the
1298 * address space when another thread could load the page so we check
1301 if (MmIsPagePresent(Process
, Address
))
1303 return(STATUS_SUCCESS
);
1306 if (MmIsDisabledPage(Process
, Address
))
1308 return(STATUS_ACCESS_VIOLATION
);
1312 * Check for the virtual memory area being deleted.
1314 if (MemoryArea
->DeleteInProgress
)
1316 return(STATUS_UNSUCCESSFUL
);
1319 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1320 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1321 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1323 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1324 Section
= MemoryArea
->Data
.SectionData
.Section
;
1325 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1326 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1328 ASSERT(Region
!= NULL
);
1332 MmLockSectionSegment(Segment
);
1333 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1335 * Check if this page needs to be mapped COW
1337 if ((Segment
->WriteCopy
) &&
1338 (Region
->Protect
== PAGE_READWRITE
||
1339 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1341 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1345 Attributes
= Region
->Protect
;
1349 * Check if someone else is already handling this fault, if so wait
1352 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1354 MmUnlockSectionSegment(Segment
);
1355 MmUnlockAddressSpace(AddressSpace
);
1356 MiWaitForPageEvent(NULL
, NULL
);
1357 MmLockAddressSpace(AddressSpace
);
1358 DPRINT("Address 0x%p\n", Address
);
1359 return(STATUS_MM_RESTART_OPERATION
);
1362 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1366 SWAPENTRY DummyEntry
;
1369 * Is it a wait entry?
1371 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1373 if (SwapEntry
== MM_WAIT_ENTRY
)
1375 MmUnlockSectionSegment(Segment
);
1376 MmUnlockAddressSpace(AddressSpace
);
1377 MiWaitForPageEvent(NULL
, NULL
);
1378 MmLockAddressSpace(AddressSpace
);
1379 return STATUS_MM_RESTART_OPERATION
;
1383 * Must be private page we have swapped out.
1389 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1391 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1392 KeBugCheck(MEMORY_MANAGEMENT
);
1395 MmUnlockSectionSegment(Segment
);
1396 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1397 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1399 MmUnlockAddressSpace(AddressSpace
);
1400 MI_SET_USAGE(MI_USAGE_SECTION
);
1401 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1402 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1403 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1404 if (!NT_SUCCESS(Status
))
1406 KeBugCheck(MEMORY_MANAGEMENT
);
1409 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1410 if (!NT_SUCCESS(Status
))
1412 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1413 KeBugCheck(MEMORY_MANAGEMENT
);
1415 MmLockAddressSpace(AddressSpace
);
1416 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1417 Status
= MmCreateVirtualMapping(Process
,
1422 if (!NT_SUCCESS(Status
))
1424 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1425 KeBugCheck(MEMORY_MANAGEMENT
);
1430 * Store the swap entry for later use.
1432 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1435 * Add the page to the process's working set
1437 MmInsertRmap(Page
, Process
, Address
);
1439 * Finish the operation
1441 MiSetPageEvent(Process
, Address
);
1442 DPRINT("Address 0x%p\n", Address
);
1443 return(STATUS_SUCCESS
);
1447 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1449 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1451 MmUnlockSectionSegment(Segment
);
1453 * Just map the desired physical page
1455 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1456 Status
= MmCreateVirtualMappingUnsafe(Process
,
1461 if (!NT_SUCCESS(Status
))
1463 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1464 KeBugCheck(MEMORY_MANAGEMENT
);
1469 * Cleanup and release locks
1471 MiSetPageEvent(Process
, Address
);
1472 DPRINT("Address 0x%p\n", Address
);
1473 return(STATUS_SUCCESS
);
1477 * Get the entry corresponding to the offset within the section
1479 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1483 SWAPENTRY FakeSwapEntry
;
1486 * If the entry is zero (and it can't change because we have
1487 * locked the segment) then we need to load the page.
1491 * Release all our locks and read in the page from disk
1493 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1494 MmUnlockSectionSegment(Segment
);
1495 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1496 MmUnlockAddressSpace(AddressSpace
);
1498 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1499 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1500 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1502 MI_SET_USAGE(MI_USAGE_SECTION
);
1503 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1504 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1505 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1506 if (!NT_SUCCESS(Status
))
1508 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1514 Status
= MiReadPage(MemoryArea
, (ULONG_PTR
)Offset
.QuadPart
, &Page
);
1515 if (!NT_SUCCESS(Status
))
1517 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1520 if (!NT_SUCCESS(Status
))
1523 * FIXME: What do we know in this case?
1526 * Cleanup and release locks
1528 MmLockAddressSpace(AddressSpace
);
1529 MiSetPageEvent(Process
, Address
);
1530 DPRINT("Address 0x%p\n", Address
);
1535 * Mark the offset within the section as having valid, in-memory
1538 MmLockAddressSpace(AddressSpace
);
1539 MmLockSectionSegment(Segment
);
1540 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1541 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1542 MmUnlockSectionSegment(Segment
);
1544 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1545 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1546 Page
, Process
, PAddress
, Attributes
);
1547 Status
= MmCreateVirtualMapping(Process
,
1552 if (!NT_SUCCESS(Status
))
1554 DPRINT1("Unable to create virtual mapping\n");
1555 KeBugCheck(MEMORY_MANAGEMENT
);
1557 ASSERT(MmIsPagePresent(Process
, PAddress
));
1558 MmInsertRmap(Page
, Process
, Address
);
1560 MiSetPageEvent(Process
, Address
);
1561 DPRINT("Address 0x%p\n", Address
);
1562 return(STATUS_SUCCESS
);
1564 else if (IS_SWAP_FROM_SSE(Entry
))
1566 SWAPENTRY SwapEntry
;
1568 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1571 * Release all our locks and read in the page from disk
1573 MmUnlockSectionSegment(Segment
);
1575 MmUnlockAddressSpace(AddressSpace
);
1576 MI_SET_USAGE(MI_USAGE_SECTION
);
1577 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1578 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1579 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1580 if (!NT_SUCCESS(Status
))
1582 KeBugCheck(MEMORY_MANAGEMENT
);
1585 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1586 if (!NT_SUCCESS(Status
))
1588 KeBugCheck(MEMORY_MANAGEMENT
);
1592 * Relock the address space and segment
1594 MmLockAddressSpace(AddressSpace
);
1595 MmLockSectionSegment(Segment
);
1598 * Check the entry. No one should change the status of a page
1599 * that has a pending page-in.
1601 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1602 if (Entry
!= Entry1
)
1604 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1605 KeBugCheck(MEMORY_MANAGEMENT
);
1609 * Mark the offset within the section as having valid, in-memory
1612 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1613 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1614 MmUnlockSectionSegment(Segment
);
1617 * Save the swap entry.
1619 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1620 Status
= MmCreateVirtualMapping(Process
,
1625 if (!NT_SUCCESS(Status
))
1627 DPRINT1("Unable to create virtual mapping\n");
1628 KeBugCheck(MEMORY_MANAGEMENT
);
1630 MmInsertRmap(Page
, Process
, Address
);
1631 MiSetPageEvent(Process
, Address
);
1632 DPRINT("Address 0x%p\n", Address
);
1633 return(STATUS_SUCCESS
);
1638 * If the section offset is already in-memory and valid then just
1639 * take another reference to the page
1642 Page
= PFN_FROM_SSE(Entry
);
1644 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1645 MmUnlockSectionSegment(Segment
);
1647 Status
= MmCreateVirtualMapping(Process
,
1652 if (!NT_SUCCESS(Status
))
1654 DPRINT1("Unable to create virtual mapping\n");
1655 KeBugCheck(MEMORY_MANAGEMENT
);
1657 MmInsertRmap(Page
, Process
, Address
);
1658 MiSetPageEvent(Process
, Address
);
1659 DPRINT("Address 0x%p\n", Address
);
1660 return(STATUS_SUCCESS
);
1666 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1667 MEMORY_AREA
* MemoryArea
,
1670 PMM_SECTION_SEGMENT Segment
;
1671 PROS_SECTION_OBJECT Section
;
1676 LARGE_INTEGER Offset
;
1679 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1680 SWAPENTRY SwapEntry
;
1682 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1685 * Check if the page has already been set readwrite
1687 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1689 DPRINT("Address 0x%p\n", Address
);
1690 return(STATUS_SUCCESS
);
1694 * Find the offset of the page
1696 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1697 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1698 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1700 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1701 Section
= MemoryArea
->Data
.SectionData
.Section
;
1702 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1703 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1705 ASSERT(Region
!= NULL
);
1709 MmLockSectionSegment(Segment
);
1711 OldPage
= MmGetPfnForProcess(Process
, Address
);
1712 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1714 MmUnlockSectionSegment(Segment
);
1717 * Check if we are doing COW
1719 if (!((Segment
->WriteCopy
) &&
1720 (Region
->Protect
== PAGE_READWRITE
||
1721 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1723 DPRINT("Address 0x%p\n", Address
);
1724 return(STATUS_ACCESS_VIOLATION
);
1727 if (IS_SWAP_FROM_SSE(Entry
) ||
1728 PFN_FROM_SSE(Entry
) != OldPage
)
1730 /* This is a private page. We must only change the page protection. */
1731 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1732 return(STATUS_SUCCESS
);
1736 DPRINT("OldPage == 0!\n");
1739 * Get or create a pageop
1741 MmLockSectionSegment(Segment
);
1742 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1745 * Wait for any other operations to complete
1747 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1749 MmUnlockSectionSegment(Segment
);
1750 MmUnlockAddressSpace(AddressSpace
);
1751 MiWaitForPageEvent(NULL
, NULL
);
1753 * Restart the operation
1755 MmLockAddressSpace(AddressSpace
);
1756 DPRINT("Address 0x%p\n", Address
);
1757 return(STATUS_MM_RESTART_OPERATION
);
1760 MmDeleteRmap(OldPage
, Process
, PAddress
);
1761 MmDeleteVirtualMapping(Process
, PAddress
, FALSE
, NULL
, NULL
);
1762 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1765 * Release locks now we have the pageop
1767 MmUnlockSectionSegment(Segment
);
1768 MmUnlockAddressSpace(AddressSpace
);
1773 MI_SET_USAGE(MI_USAGE_SECTION
);
1774 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1775 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1776 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1777 if (!NT_SUCCESS(Status
))
1779 KeBugCheck(MEMORY_MANAGEMENT
);
1785 MiCopyFromUserPage(NewPage
, OldPage
);
1787 MmLockAddressSpace(AddressSpace
);
1790 * Set the PTE to point to the new page
1792 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1793 Status
= MmCreateVirtualMapping(Process
,
1798 if (!NT_SUCCESS(Status
))
1800 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1801 KeBugCheck(MEMORY_MANAGEMENT
);
1806 * Unshare the old page.
1808 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1809 MmInsertRmap(NewPage
, Process
, PAddress
);
1810 MmLockSectionSegment(Segment
);
1811 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1812 MmUnlockSectionSegment(Segment
);
1814 MiSetPageEvent(Process
, Address
);
1815 DPRINT("Address 0x%p\n", Address
);
1816 return(STATUS_SUCCESS
);
1820 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1822 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1824 PFN_NUMBER Page
= 0;
1826 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1829 MmLockAddressSpace(&Process
->Vm
);
1832 MmDeleteVirtualMapping(Process
,
1839 PageOutContext
->WasDirty
= TRUE
;
1841 if (!PageOutContext
->Private
)
1843 MmLockSectionSegment(PageOutContext
->Segment
);
1844 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1845 PageOutContext
->Segment
,
1846 &PageOutContext
->Offset
,
1847 PageOutContext
->WasDirty
,
1849 &PageOutContext
->SectionEntry
);
1850 MmUnlockSectionSegment(PageOutContext
->Segment
);
1854 MmUnlockAddressSpace(&Process
->Vm
);
1857 if (PageOutContext
->Private
)
1859 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1865 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1866 MEMORY_AREA
* MemoryArea
,
1867 PVOID Address
, ULONG_PTR Entry
)
1870 MM_SECTION_PAGEOUT_CONTEXT Context
;
1871 SWAPENTRY SwapEntry
;
1872 ULONGLONG FileOffset
;
1874 PFILE_OBJECT FileObject
;
1878 BOOLEAN DirectMapped
;
1879 BOOLEAN IsImageSection
;
1880 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1883 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1886 * Get the segment and section.
1888 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1889 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1890 Context
.SectionEntry
= Entry
;
1891 Context
.CallingProcess
= Process
;
1893 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1894 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1895 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1897 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1899 FileObject
= Context
.Section
->FileObject
;
1900 DirectMapped
= FALSE
;
1902 MmLockSectionSegment(Context
.Segment
);
1905 if (FileObject
!= NULL
&&
1906 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1908 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1911 * If the file system is letting us go directly to the cache and the
1912 * memory area was mapped at an offset in the file which is page aligned
1913 * then note this is a direct mapped page.
1915 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1916 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1918 DirectMapped
= TRUE
;
1925 * This should never happen since mappings of physical memory are never
1926 * placed in the rmap lists.
1928 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1930 DPRINT1("Trying to page out from physical memory section address 0x%p "
1931 "process %p\n", Address
,
1932 Process
? Process
->UniqueProcessId
: 0);
1933 KeBugCheck(MEMORY_MANAGEMENT
);
1937 * Get the section segment entry and the physical address.
1939 if (!MmIsPagePresent(Process
, Address
))
1941 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1942 Process
? Process
->UniqueProcessId
: 0, Address
);
1943 KeBugCheck(MEMORY_MANAGEMENT
);
1945 Page
= MmGetPfnForProcess(Process
, Address
);
1946 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1949 * Check the reference count to ensure this page can be paged out
1951 if (MmGetReferenceCountPage(Page
) != 1)
1953 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1954 Page
, MmGetReferenceCountPage(Page
));
1955 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1956 MmUnlockSectionSegment(Context
.Segment
);
1957 return STATUS_UNSUCCESSFUL
;
1961 * Prepare the context structure for the rmap delete call.
1963 MmUnlockSectionSegment(Context
.Segment
);
1964 Context
.WasDirty
= FALSE
;
1965 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1966 IS_SWAP_FROM_SSE(Entry
) ||
1967 PFN_FROM_SSE(Entry
) != Page
)
1969 Context
.Private
= TRUE
;
1973 Context
.Private
= FALSE
;
1977 * Take an additional reference to the page or the cache segment.
1979 if (DirectMapped
&& !Context
.Private
)
1981 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
1983 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1984 KeBugCheck(MEMORY_MANAGEMENT
);
1989 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1990 MmReferencePage(Page
);
1991 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1994 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1996 /* Since we passed in a surrogate, we'll get back the page entry
1997 * state in our context. This is intended to make intermediate
1998 * decrements of share count not release the wait entry.
2000 Entry
= Context
.SectionEntry
;
2003 * If this wasn't a private page then we should have reduced the entry to
2004 * zero by deleting all the rmaps.
2006 if (!Context
.Private
&& Entry
!= 0)
2008 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2009 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2011 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2016 * If the page wasn't dirty then we can just free it as for a readonly page.
2017 * Since we unmapped all the mappings above we know it will not suddenly
2019 * If the page is from a pagefile section and has no swap entry,
2020 * we can't free the page at this point.
2022 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2023 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2025 if (Context
.Private
)
2027 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2028 Context
.WasDirty
? "dirty" : "clean", Address
);
2029 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2031 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2033 MmSetSavedSwapEntryPage(Page
, 0);
2034 MmLockSectionSegment(Context
.Segment
);
2035 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2036 MmUnlockSectionSegment(Context
.Segment
);
2037 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2038 MiSetPageEvent(NULL
, NULL
);
2039 return(STATUS_SUCCESS
);
2042 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2044 if (Context
.Private
)
2046 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2047 Context
.WasDirty
? "dirty" : "clean", Address
);
2048 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2050 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2052 MmSetSavedSwapEntryPage(Page
, 0);
2055 MmLockSectionSegment(Context
.Segment
);
2056 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2057 MmUnlockSectionSegment(Context
.Segment
);
2059 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2060 MiSetPageEvent(NULL
, NULL
);
2061 return(STATUS_SUCCESS
);
2064 else if (!Context
.Private
&& DirectMapped
)
2068 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2070 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2073 Status
= CcRosUnmapCacheSegment(Bcb
, (ULONG
)FileOffset
, FALSE
);
2075 Status
= STATUS_SUCCESS
;
2078 if (!NT_SUCCESS(Status
))
2080 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2081 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Bcb
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2084 MiSetPageEvent(NULL
, NULL
);
2085 return(STATUS_SUCCESS
);
2087 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2091 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2093 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2095 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2096 MiSetPageEvent(NULL
, NULL
);
2097 return(STATUS_SUCCESS
);
2099 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2101 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2102 MmSetSavedSwapEntryPage(Page
, 0);
2103 MmLockAddressSpace(AddressSpace
);
2104 Status
= MmCreatePageFileMapping(Process
,
2107 MmUnlockAddressSpace(AddressSpace
);
2108 if (!NT_SUCCESS(Status
))
2110 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2111 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2113 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2114 MiSetPageEvent(NULL
, NULL
);
2115 return(STATUS_SUCCESS
);
2119 * If necessary, allocate an entry in the paging file for this page
2123 SwapEntry
= MmAllocSwapPage();
2126 MmShowOutOfSpaceMessagePagingFile();
2127 MmLockAddressSpace(AddressSpace
);
2129 * For private pages restore the old mappings.
2131 if (Context
.Private
)
2133 Status
= MmCreateVirtualMapping(Process
,
2135 MemoryArea
->Protect
,
2138 MmSetDirtyPage(Process
, Address
);
2147 * For non-private pages if the page wasn't direct mapped then
2148 * set it back into the section segment entry so we don't loose
2149 * our copy. Otherwise it will be handled by the cache manager.
2151 Status
= MmCreateVirtualMapping(Process
,
2153 MemoryArea
->Protect
,
2156 MmSetDirtyPage(Process
, Address
);
2160 // If we got here, the previous entry should have been a wait
2161 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2162 MmLockSectionSegment(Context
.Segment
);
2163 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2164 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2165 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2166 MmUnlockSectionSegment(Context
.Segment
);
2168 MmUnlockAddressSpace(AddressSpace
);
2169 MiSetPageEvent(NULL
, NULL
);
2170 return(STATUS_PAGEFILE_QUOTA
);
2175 * Write the page to the pagefile
2177 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2178 if (!NT_SUCCESS(Status
))
2180 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2183 * As above: undo our actions.
2184 * FIXME: Also free the swap page.
2186 MmLockAddressSpace(AddressSpace
);
2187 if (Context
.Private
)
2189 Status
= MmCreateVirtualMapping(Process
,
2191 MemoryArea
->Protect
,
2194 MmSetDirtyPage(Process
, Address
);
2201 Status
= MmCreateVirtualMapping(Process
,
2203 MemoryArea
->Protect
,
2206 MmSetDirtyPage(Process
, Address
);
2210 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2211 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2213 MmUnlockAddressSpace(AddressSpace
);
2214 MiSetPageEvent(NULL
, NULL
);
2215 return(STATUS_UNSUCCESSFUL
);
2219 * Otherwise we have succeeded.
2221 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2222 MmSetSavedSwapEntryPage(Page
, 0);
2223 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2224 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2226 MmLockSectionSegment(Context
.Segment
);
2227 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2228 MmUnlockSectionSegment(Context
.Segment
);
2232 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2235 if (Context
.Private
)
2237 MmLockAddressSpace(AddressSpace
);
2238 MmLockSectionSegment(Context
.Segment
);
2239 Status
= MmCreatePageFileMapping(Process
,
2242 /* We had placed a wait entry upon entry ... replace it before leaving */
2243 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2244 MmUnlockSectionSegment(Context
.Segment
);
2245 MmUnlockAddressSpace(AddressSpace
);
2246 if (!NT_SUCCESS(Status
))
2248 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2249 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2254 MmLockAddressSpace(AddressSpace
);
2255 MmLockSectionSegment(Context
.Segment
);
2256 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2257 /* We had placed a wait entry upon entry ... replace it before leaving */
2258 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2259 MmUnlockSectionSegment(Context
.Segment
);
2260 MmUnlockAddressSpace(AddressSpace
);
2263 MiSetPageEvent(NULL
, NULL
);
2264 return(STATUS_SUCCESS
);
2269 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2270 PMEMORY_AREA MemoryArea
,
2274 LARGE_INTEGER Offset
;
2275 PROS_SECTION_OBJECT Section
;
2276 PMM_SECTION_SEGMENT Segment
;
2278 SWAPENTRY SwapEntry
;
2282 PFILE_OBJECT FileObject
;
2284 BOOLEAN DirectMapped
;
2285 BOOLEAN IsImageSection
;
2286 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2288 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2290 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2291 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2294 * Get the segment and section.
2296 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2297 Section
= MemoryArea
->Data
.SectionData
.Section
;
2298 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2300 FileObject
= Section
->FileObject
;
2301 DirectMapped
= FALSE
;
2302 if (FileObject
!= NULL
&&
2303 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2305 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2308 * If the file system is letting us go directly to the cache and the
2309 * memory area was mapped at an offset in the file which is page aligned
2310 * then note this is a direct mapped page.
2312 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2313 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2315 DirectMapped
= TRUE
;
2320 * This should never happen since mappings of physical memory are never
2321 * placed in the rmap lists.
2323 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2325 DPRINT1("Trying to write back page from physical memory mapped at %p "
2326 "process %p\n", Address
,
2327 Process
? Process
->UniqueProcessId
: 0);
2328 KeBugCheck(MEMORY_MANAGEMENT
);
2332 * Get the section segment entry and the physical address.
2334 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2335 if (!MmIsPagePresent(Process
, Address
))
2337 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2338 Process
? Process
->UniqueProcessId
: 0, Address
);
2339 KeBugCheck(MEMORY_MANAGEMENT
);
2341 Page
= MmGetPfnForProcess(Process
, Address
);
2342 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2345 * Check for a private (COWed) page.
2347 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2348 IS_SWAP_FROM_SSE(Entry
) ||
2349 PFN_FROM_SSE(Entry
) != Page
)
2359 * Speculatively set all mappings of the page to clean.
2361 MmSetCleanAllRmaps(Page
);
2364 * If this page was direct mapped from the cache then the cache manager
2365 * will take care of writing it back to disk.
2367 if (DirectMapped
&& !Private
)
2369 //LARGE_INTEGER SOffset;
2370 ASSERT(SwapEntry
== 0);
2371 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2373 CcRosMarkDirtyCacheSegment(Bcb
, Offset
.LowPart
);
2375 MmLockSectionSegment(Segment
);
2376 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2377 MmUnlockSectionSegment(Segment
);
2378 MiSetPageEvent(NULL
, NULL
);
2379 return(STATUS_SUCCESS
);
2383 * If necessary, allocate an entry in the paging file for this page
2387 SwapEntry
= MmAllocSwapPage();
2390 MmSetDirtyAllRmaps(Page
);
2391 MiSetPageEvent(NULL
, NULL
);
2392 return(STATUS_PAGEFILE_QUOTA
);
2394 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2398 * Write the page to the pagefile
2400 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2401 if (!NT_SUCCESS(Status
))
2403 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2405 MmSetDirtyAllRmaps(Page
);
2406 MiSetPageEvent(NULL
, NULL
);
2407 return(STATUS_UNSUCCESSFUL
);
2411 * Otherwise we have succeeded.
2413 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2414 MiSetPageEvent(NULL
, NULL
);
2415 return(STATUS_SUCCESS
);
2419 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2427 PMEMORY_AREA MemoryArea
;
2428 PMM_SECTION_SEGMENT Segment
;
2429 BOOLEAN DoCOW
= FALSE
;
2431 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2433 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2434 ASSERT(MemoryArea
!= NULL
);
2435 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2436 MmLockSectionSegment(Segment
);
2438 if ((Segment
->WriteCopy
) &&
2439 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2444 if (OldProtect
!= NewProtect
)
2446 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2448 SWAPENTRY SwapEntry
;
2449 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2450 ULONG Protect
= NewProtect
;
2452 /* Wait for a wait entry to disappear */
2454 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2455 if (SwapEntry
!= MM_WAIT_ENTRY
)
2457 MiWaitForPageEvent(Process
, Address
);
2461 * If we doing COW for this segment then check if the page is
2464 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2466 LARGE_INTEGER Offset
;
2470 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2471 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2472 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2474 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2475 * IS_SWAP_FROM_SSE and we'll do the right thing.
2477 Page
= MmGetPfnForProcess(Process
, Address
);
2479 Protect
= PAGE_READONLY
;
2480 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2481 IS_SWAP_FROM_SSE(Entry
) ||
2482 PFN_FROM_SSE(Entry
) != Page
)
2484 Protect
= NewProtect
;
2488 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2490 MmSetPageProtect(Process
, Address
,
2496 MmUnlockSectionSegment(Segment
);
2501 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2502 PMEMORY_AREA MemoryArea
,
2510 ULONG_PTR MaxLength
;
2512 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2513 if (Length
> MaxLength
)
2514 Length
= (ULONG
)MaxLength
;
2516 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2517 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2519 ASSERT(Region
!= NULL
);
2521 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2522 Region
->Protect
!= Protect
)
2524 return STATUS_INVALID_PAGE_PROTECTION
;
2527 *OldProtect
= Region
->Protect
;
2528 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2529 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2530 BaseAddress
, Length
, Region
->Type
, Protect
,
2531 MmAlterViewAttributes
);
2537 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2539 PMEMORY_BASIC_INFORMATION Info
,
2540 PSIZE_T ResultLength
)
2543 PVOID RegionBaseAddress
;
2544 PROS_SECTION_OBJECT Section
;
2545 PMM_SECTION_SEGMENT Segment
;
2547 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2548 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2549 Address
, &RegionBaseAddress
);
2552 return STATUS_UNSUCCESSFUL
;
2555 Section
= MemoryArea
->Data
.SectionData
.Section
;
2556 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2558 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2559 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2560 Info
->Type
= MEM_IMAGE
;
2564 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2565 Info
->Type
= MEM_MAPPED
;
2567 Info
->BaseAddress
= RegionBaseAddress
;
2568 Info
->AllocationProtect
= MemoryArea
->Protect
;
2569 Info
->RegionSize
= Region
->Length
;
2570 Info
->State
= MEM_COMMIT
;
2571 Info
->Protect
= Region
->Protect
;
2573 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2574 return(STATUS_SUCCESS
);
2579 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2582 LARGE_INTEGER Offset
;
2584 SWAPENTRY SavedSwapEntry
;
2589 MmLockSectionSegment(Segment
);
2591 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2592 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2594 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2597 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2598 if (IS_SWAP_FROM_SSE(Entry
))
2600 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2604 Page
= PFN_FROM_SSE(Entry
);
2605 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2606 if (SavedSwapEntry
!= 0)
2608 MmSetSavedSwapEntryPage(Page
, 0);
2609 MmFreeSwapPage(SavedSwapEntry
);
2611 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2616 MmUnlockSectionSegment(Segment
);
2620 MmpDeleteSection(PVOID ObjectBody
)
2622 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2624 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2625 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2630 PMM_SECTION_SEGMENT SectionSegments
;
2633 * NOTE: Section->ImageSection can be NULL for short time
2634 * during the section creating. If we fail for some reason
2635 * until the image section is properly initialized we shouldn't
2636 * process further here.
2638 if (Section
->ImageSection
== NULL
)
2641 SectionSegments
= Section
->ImageSection
->Segments
;
2642 NrSegments
= Section
->ImageSection
->NrSegments
;
2644 for (i
= 0; i
< NrSegments
; i
++)
2646 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2648 MmLockSectionSegment(&SectionSegments
[i
]);
2650 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2651 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2653 MmUnlockSectionSegment(&SectionSegments
[i
]);
2656 MmpFreePageFileSegment(&SectionSegments
[i
]);
2662 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2665 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2668 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2670 DPRINT("Freeing section segment\n");
2671 Section
->Segment
= NULL
;
2672 MmFinalizeSegment(Segment
);
2676 DPRINT("RefCount %d\n", RefCount
);
2683 * NOTE: Section->Segment can be NULL for short time
2684 * during the section creating.
2686 if (Section
->Segment
== NULL
)
2689 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2691 MmpFreePageFileSegment(Section
->Segment
);
2692 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2693 ExFreePool(Section
->Segment
);
2694 Section
->Segment
= NULL
;
2698 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2701 if (Section
->FileObject
!= NULL
)
2704 CcRosDereferenceCache(Section
->FileObject
);
2706 ObDereferenceObject(Section
->FileObject
);
2707 Section
->FileObject
= NULL
;
2712 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2714 IN ACCESS_MASK GrantedAccess
,
2715 IN ULONG ProcessHandleCount
,
2716 IN ULONG SystemHandleCount
)
2718 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2724 MmCreatePhysicalMemorySection(VOID
)
2726 PROS_SECTION_OBJECT PhysSection
;
2728 OBJECT_ATTRIBUTES Obj
;
2729 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2730 LARGE_INTEGER SectionSize
;
2734 * Create the section mapping physical memory
2736 SectionSize
.QuadPart
= 0xFFFFFFFF;
2737 InitializeObjectAttributes(&Obj
,
2742 Status
= MmCreateSection((PVOID
)&PhysSection
,
2746 PAGE_EXECUTE_READWRITE
,
2750 if (!NT_SUCCESS(Status
))
2752 DPRINT1("Failed to create PhysicalMemory section\n");
2753 KeBugCheck(MEMORY_MANAGEMENT
);
2755 Status
= ObInsertObject(PhysSection
,
2761 if (!NT_SUCCESS(Status
))
2763 ObDereferenceObject(PhysSection
);
2765 ObCloseHandle(Handle
, KernelMode
);
2766 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2767 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2769 return(STATUS_SUCCESS
);
2775 MmInitSectionImplementation(VOID
)
2777 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2778 UNICODE_STRING Name
;
2780 DPRINT("Creating Section Object Type\n");
2782 /* Initialize the section based root */
2783 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2784 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2786 /* Initialize the Section object type */
2787 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2788 RtlInitUnicodeString(&Name
, L
"Section");
2789 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2790 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2791 ObjectTypeInitializer
.PoolType
= PagedPool
;
2792 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2793 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2794 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2795 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2796 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2797 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2798 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2800 MmCreatePhysicalMemorySection();
2802 return(STATUS_SUCCESS
);
2807 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2808 ACCESS_MASK DesiredAccess
,
2809 POBJECT_ATTRIBUTES ObjectAttributes
,
2810 PLARGE_INTEGER UMaximumSize
,
2811 ULONG SectionPageProtection
,
2812 ULONG AllocationAttributes
)
2814 * Create a section which is backed by the pagefile
2817 LARGE_INTEGER MaximumSize
;
2818 PROS_SECTION_OBJECT Section
;
2819 PMM_SECTION_SEGMENT Segment
;
2822 if (UMaximumSize
== NULL
)
2824 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2825 return(STATUS_INVALID_PARAMETER
);
2827 MaximumSize
= *UMaximumSize
;
2830 * Create the section
2832 Status
= ObCreateObject(ExGetPreviousMode(),
2833 MmSectionObjectType
,
2835 ExGetPreviousMode(),
2837 sizeof(ROS_SECTION_OBJECT
),
2840 (PVOID
*)(PVOID
)&Section
);
2841 if (!NT_SUCCESS(Status
))
2843 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2850 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2851 Section
->Type
= 'SC';
2852 Section
->Size
= 'TN';
2853 Section
->SectionPageProtection
= SectionPageProtection
;
2854 Section
->AllocationAttributes
= AllocationAttributes
;
2855 Section
->MaximumSize
= MaximumSize
;
2856 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2857 TAG_MM_SECTION_SEGMENT
);
2858 if (Segment
== NULL
)
2860 ObDereferenceObject(Section
);
2861 return(STATUS_NO_MEMORY
);
2863 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2864 Section
->Segment
= Segment
;
2865 Segment
->ReferenceCount
= 1;
2866 ExInitializeFastMutex(&Segment
->Lock
);
2867 Segment
->Image
.FileOffset
= 0;
2868 Segment
->Protection
= SectionPageProtection
;
2869 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2870 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2871 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2872 Segment
->WriteCopy
= FALSE
;
2873 Segment
->Image
.VirtualAddress
= 0;
2874 Segment
->Image
.Characteristics
= 0;
2875 *SectionObject
= Section
;
2876 MiInitializeSectionPageTable(Segment
);
2877 return(STATUS_SUCCESS
);
2882 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2883 ACCESS_MASK DesiredAccess
,
2884 POBJECT_ATTRIBUTES ObjectAttributes
,
2885 PLARGE_INTEGER UMaximumSize
,
2886 ULONG SectionPageProtection
,
2887 ULONG AllocationAttributes
,
2890 * Create a section backed by a data file
2893 PROS_SECTION_OBJECT Section
;
2895 LARGE_INTEGER MaximumSize
;
2896 PFILE_OBJECT FileObject
;
2897 PMM_SECTION_SEGMENT Segment
;
2899 IO_STATUS_BLOCK Iosb
;
2900 LARGE_INTEGER Offset
;
2902 FILE_STANDARD_INFORMATION FileInfo
;
2906 * Create the section
2908 Status
= ObCreateObject(ExGetPreviousMode(),
2909 MmSectionObjectType
,
2911 ExGetPreviousMode(),
2913 sizeof(ROS_SECTION_OBJECT
),
2917 if (!NT_SUCCESS(Status
))
2924 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2925 Section
->Type
= 'SC';
2926 Section
->Size
= 'TN';
2927 Section
->SectionPageProtection
= SectionPageProtection
;
2928 Section
->AllocationAttributes
= AllocationAttributes
;
2931 * Reference the file handle
2933 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2934 Status
= ObReferenceObjectByHandle(FileHandle
,
2937 ExGetPreviousMode(),
2938 (PVOID
*)(PVOID
)&FileObject
,
2940 if (!NT_SUCCESS(Status
))
2942 ObDereferenceObject(Section
);
2947 * FIXME: This is propably not entirely correct. We can't look into
2948 * the standard FCB header because it might not be initialized yet
2949 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2950 * standard file information is filled on first request).
2952 Status
= IoQueryFileInformation(FileObject
,
2953 FileStandardInformation
,
2954 sizeof(FILE_STANDARD_INFORMATION
),
2957 Iosb
.Information
= Length
;
2958 if (!NT_SUCCESS(Status
))
2960 ObDereferenceObject(Section
);
2961 ObDereferenceObject(FileObject
);
2966 * FIXME: Revise this once a locking order for file size changes is
2969 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2971 MaximumSize
= *UMaximumSize
;
2975 MaximumSize
= FileInfo
.EndOfFile
;
2976 /* Mapping zero-sized files isn't allowed. */
2977 if (MaximumSize
.QuadPart
== 0)
2979 ObDereferenceObject(Section
);
2980 ObDereferenceObject(FileObject
);
2981 return STATUS_FILE_INVALID
;
2985 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2987 Status
= IoSetInformation(FileObject
,
2988 FileAllocationInformation
,
2989 sizeof(LARGE_INTEGER
),
2991 if (!NT_SUCCESS(Status
))
2993 ObDereferenceObject(Section
);
2994 ObDereferenceObject(FileObject
);
2995 return(STATUS_SECTION_NOT_EXTENDED
);
2999 if (FileObject
->SectionObjectPointer
== NULL
||
3000 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3003 * Read a bit so caching is initiated for the file object.
3004 * This is only needed because MiReadPage currently cannot
3005 * handle non-cached streams.
3007 Offset
.QuadPart
= 0;
3008 Status
= ZwReadFile(FileHandle
,
3017 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3019 ObDereferenceObject(Section
);
3020 ObDereferenceObject(FileObject
);
3023 if (FileObject
->SectionObjectPointer
== NULL
||
3024 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3026 /* FIXME: handle this situation */
3027 ObDereferenceObject(Section
);
3028 ObDereferenceObject(FileObject
);
3029 return STATUS_INVALID_PARAMETER
;
3036 Status
= MmspWaitForFileLock(FileObject
);
3037 if (Status
!= STATUS_SUCCESS
)
3039 ObDereferenceObject(Section
);
3040 ObDereferenceObject(FileObject
);
3045 * If this file hasn't been mapped as a data file before then allocate a
3046 * section segment to describe the data file mapping
3048 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3050 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3051 TAG_MM_SECTION_SEGMENT
);
3052 if (Segment
== NULL
)
3054 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3055 ObDereferenceObject(Section
);
3056 ObDereferenceObject(FileObject
);
3057 return(STATUS_NO_MEMORY
);
3059 Section
->Segment
= Segment
;
3060 Segment
->ReferenceCount
= 1;
3061 ExInitializeFastMutex(&Segment
->Lock
);
3063 * Set the lock before assigning the segment to the file object
3065 ExAcquireFastMutex(&Segment
->Lock
);
3066 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3068 Segment
->Image
.FileOffset
= 0;
3069 Segment
->Protection
= SectionPageProtection
;
3070 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3071 Segment
->Image
.Characteristics
= 0;
3072 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3073 if (AllocationAttributes
& SEC_RESERVE
)
3075 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3079 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3080 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3082 Segment
->Image
.VirtualAddress
= 0;
3083 Segment
->Locked
= TRUE
;
3084 MiInitializeSectionPageTable(Segment
);
3089 * If the file is already mapped as a data file then we may need
3093 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3095 Section
->Segment
= Segment
;
3096 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3097 MmLockSectionSegment(Segment
);
3099 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3100 !(AllocationAttributes
& SEC_RESERVE
))
3102 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3103 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3106 MmUnlockSectionSegment(Segment
);
3107 Section
->FileObject
= FileObject
;
3108 Section
->MaximumSize
= MaximumSize
;
3110 CcRosReferenceCache(FileObject
);
3112 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3113 *SectionObject
= Section
;
3114 return(STATUS_SUCCESS
);
3118 TODO: not that great (declaring loaders statically, having to declare all of
3119 them, having to keep them extern, etc.), will fix in the future
3121 extern NTSTATUS NTAPI PeFmtCreateSection
3123 IN CONST VOID
* FileHeader
,
3124 IN SIZE_T FileHeaderSize
,
3126 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3128 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3129 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3132 extern NTSTATUS NTAPI ElfFmtCreateSection
3134 IN CONST VOID
* FileHeader
,
3135 IN SIZE_T FileHeaderSize
,
3137 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3139 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3140 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3143 /* TODO: this is a standard DDK/PSDK macro */
3144 #ifndef RTL_NUMBER_OF
3145 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3148 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3159 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3161 SIZE_T SizeOfSegments
;
3162 PMM_SECTION_SEGMENT Segments
;
3164 /* TODO: check for integer overflow */
3165 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3167 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3169 TAG_MM_SECTION_SEGMENT
);
3172 RtlZeroMemory(Segments
, SizeOfSegments
);
3180 ExeFmtpReadFile(IN PVOID File
,
3181 IN PLARGE_INTEGER Offset
,
3184 OUT PVOID
* AllocBase
,
3185 OUT PULONG ReadSize
)
3188 LARGE_INTEGER FileOffset
;
3190 ULONG OffsetAdjustment
;
3194 PFILE_OBJECT FileObject
= File
;
3195 IO_STATUS_BLOCK Iosb
;
3197 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3201 KeBugCheck(MEMORY_MANAGEMENT
);
3204 FileOffset
= *Offset
;
3206 /* Negative/special offset: it cannot be used in this context */
3207 if(FileOffset
.u
.HighPart
< 0)
3209 KeBugCheck(MEMORY_MANAGEMENT
);
3212 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3213 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3214 FileOffset
.u
.LowPart
= AdjustOffset
;
3216 BufferSize
= Length
+ OffsetAdjustment
;
3217 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3220 * It's ok to use paged pool, because this is a temporary buffer only used in
3221 * the loading of executables. The assumption is that MmCreateSection is
3222 * always called at low IRQLs and that these buffers don't survive a brief
3223 * initialization phase
3225 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3230 KeBugCheck(MEMORY_MANAGEMENT
);
3235 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3237 UsedSize
= (ULONG
)Iosb
.Information
;
3239 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3241 Status
= STATUS_IN_PAGE_ERROR
;
3242 ASSERT(!NT_SUCCESS(Status
));
3245 if(NT_SUCCESS(Status
))
3247 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3248 *AllocBase
= Buffer
;
3249 *ReadSize
= UsedSize
- OffsetAdjustment
;
3253 ExFreePoolWithTag(Buffer
, 'rXmM');
3260 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3261 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3262 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3267 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3271 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3273 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3274 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3281 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3285 MmspAssertSegmentsSorted(ImageSectionObject
);
3287 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3289 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3293 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3294 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3295 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3303 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3307 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3309 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3310 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3318 MmspCompareSegments(const void * x
,
3321 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3322 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3325 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3326 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3330 * Ensures an image section's segments are sorted in memory
3335 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3338 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3340 MmspAssertSegmentsSorted(ImageSectionObject
);
3344 qsort(ImageSectionObject
->Segments
,
3345 ImageSectionObject
->NrSegments
,
3346 sizeof(ImageSectionObject
->Segments
[0]),
3347 MmspCompareSegments
);
3353 * Ensures an image section's segments don't overlap in memory and don't have
3354 * gaps and don't have a null size. We let them map to overlapping file regions,
3355 * though - that's not necessarily an error
3360 MmspCheckSegmentBounds
3362 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3368 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3370 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3374 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3376 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3378 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3386 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3387 * page could be OK (Windows seems to be OK with them), and larger gaps
3388 * could lead to image sections spanning several discontiguous regions
3389 * (NtMapViewOfSection could then refuse to map them, and they could
3390 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3392 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3393 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3394 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3405 * Merges and pads an image section's segments until they all are page-aligned
3406 * and have a size that is a multiple of the page size
3411 MmspPageAlignSegments
3413 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3419 PMM_SECTION_SEGMENT EffectiveSegment
;
3421 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3423 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3428 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3430 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3433 * The first segment requires special handling
3437 ULONG_PTR VirtualAddress
;
3438 ULONG_PTR VirtualOffset
;
3440 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3442 /* Round down the virtual address to the nearest page */
3443 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3445 /* Round up the virtual size to the nearest page */
3446 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3447 EffectiveSegment
->Image
.VirtualAddress
;
3449 /* Adjust the raw address and size */
3450 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3452 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3458 * Garbage in, garbage out: unaligned base addresses make the file
3459 * offset point in curious and odd places, but that's what we were
3462 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3463 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3467 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3468 ULONG_PTR EndOfEffectiveSegment
;
3470 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3471 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3474 * The current segment begins exactly where the current effective
3475 * segment ended, therefore beginning a new effective segment
3477 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3480 ASSERT(LastSegment
<= i
);
3481 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3483 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3485 if (LastSegment
!= i
)
3488 * Copy the current segment. If necessary, the effective segment
3489 * will be expanded later
3491 *EffectiveSegment
= *Segment
;
3495 * Page-align the virtual size. We know for sure the virtual address
3498 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3499 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3502 * The current segment is still part of the current effective segment:
3503 * extend the effective segment to reflect this
3505 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3507 static const ULONG FlagsToProtection
[16] =
3515 PAGE_EXECUTE_READWRITE
,
3516 PAGE_EXECUTE_READWRITE
,
3521 PAGE_EXECUTE_WRITECOPY
,
3522 PAGE_EXECUTE_WRITECOPY
,
3523 PAGE_EXECUTE_WRITECOPY
,
3524 PAGE_EXECUTE_WRITECOPY
3527 unsigned ProtectionFlags
;
3530 * Extend the file size
3533 /* Unaligned segments must be contiguous within the file */
3534 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3535 EffectiveSegment
->RawLength
.QuadPart
))
3540 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3543 * Extend the virtual size
3545 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3547 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3548 EffectiveSegment
->Image
.VirtualAddress
;
3551 * Merge the protection
3553 EffectiveSegment
->Protection
|= Segment
->Protection
;
3555 /* Clean up redundance */
3556 ProtectionFlags
= 0;
3558 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3559 ProtectionFlags
|= 1 << 0;
3561 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3562 ProtectionFlags
|= 1 << 1;
3564 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3565 ProtectionFlags
|= 1 << 2;
3567 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3568 ProtectionFlags
|= 1 << 3;
3570 ASSERT(ProtectionFlags
< 16);
3571 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3573 /* If a segment was required to be shared and cannot, fail */
3574 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3575 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3581 * We assume no holes between segments at this point
3585 KeBugCheck(MEMORY_MANAGEMENT
);
3589 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3595 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3596 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3598 LARGE_INTEGER Offset
;
3600 PVOID FileHeaderBuffer
;
3601 ULONG FileHeaderSize
;
3603 ULONG OldNrSegments
;
3608 * Read the beginning of the file (2 pages). Should be enough to contain
3609 * all (or most) of the headers
3611 Offset
.QuadPart
= 0;
3613 /* FIXME: use FileObject instead of FileHandle */
3614 Status
= ExeFmtpReadFile (FileHandle
,
3621 if (!NT_SUCCESS(Status
))
3624 if (FileHeaderSize
== 0)
3626 ExFreePool(FileHeaderBuffer
);
3627 return STATUS_UNSUCCESSFUL
;
3631 * Look for a loader that can handle this executable
3633 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3635 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3638 /* FIXME: use FileObject instead of FileHandle */
3639 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3645 ExeFmtpAllocateSegments
);
3647 if (!NT_SUCCESS(Status
))
3649 if (ImageSectionObject
->Segments
)
3651 ExFreePool(ImageSectionObject
->Segments
);
3652 ImageSectionObject
->Segments
= NULL
;
3656 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3660 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3663 * No loader handled the format
3665 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3667 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3668 ASSERT(!NT_SUCCESS(Status
));
3671 if (!NT_SUCCESS(Status
))
3674 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3679 /* FIXME? are these values platform-dependent? */
3680 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3681 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3683 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3684 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3686 if(ImageSectionObject
->BasedAddress
== NULL
)
3688 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3689 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3691 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3695 * And now the fun part: fixing the segments
3698 /* Sort them by virtual address */
3699 MmspSortSegments(ImageSectionObject
, Flags
);
3701 /* Ensure they don't overlap in memory */
3702 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3703 return STATUS_INVALID_IMAGE_FORMAT
;
3705 /* Ensure they are aligned */
3706 OldNrSegments
= ImageSectionObject
->NrSegments
;
3708 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3709 return STATUS_INVALID_IMAGE_FORMAT
;
3711 /* Trim them if the alignment phase merged some of them */
3712 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3714 PMM_SECTION_SEGMENT Segments
;
3715 SIZE_T SizeOfSegments
;
3717 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3719 Segments
= ExAllocatePoolWithTag(PagedPool
,
3721 TAG_MM_SECTION_SEGMENT
);
3723 if (Segments
== NULL
)
3724 return STATUS_INSUFFICIENT_RESOURCES
;
3726 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3727 ExFreePool(ImageSectionObject
->Segments
);
3728 ImageSectionObject
->Segments
= Segments
;
3731 /* And finish their initialization */
3732 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3734 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3735 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3736 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3739 ASSERT(NT_SUCCESS(Status
));
3744 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3745 ACCESS_MASK DesiredAccess
,
3746 POBJECT_ATTRIBUTES ObjectAttributes
,
3747 PLARGE_INTEGER UMaximumSize
,
3748 ULONG SectionPageProtection
,
3749 ULONG AllocationAttributes
,
3750 PFILE_OBJECT FileObject
)
3752 PROS_SECTION_OBJECT Section
;
3754 PMM_SECTION_SEGMENT SectionSegments
;
3755 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3758 if (FileObject
== NULL
)
3759 return STATUS_INVALID_FILE_FOR_SECTION
;
3762 * Create the section
3764 Status
= ObCreateObject (ExGetPreviousMode(),
3765 MmSectionObjectType
,
3767 ExGetPreviousMode(),
3769 sizeof(ROS_SECTION_OBJECT
),
3772 (PVOID
*)(PVOID
)&Section
);
3773 if (!NT_SUCCESS(Status
))
3775 ObDereferenceObject(FileObject
);
3782 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3783 Section
->Type
= 'SC';
3784 Section
->Size
= 'TN';
3785 Section
->SectionPageProtection
= SectionPageProtection
;
3786 Section
->AllocationAttributes
= AllocationAttributes
;
3790 * Initialized caching for this file object if previously caching
3791 * was initialized for the same on disk file
3793 Status
= CcTryToInitializeFileCache(FileObject
);
3795 Status
= STATUS_SUCCESS
;
3798 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3800 NTSTATUS StatusExeFmt
;
3802 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3803 if (ImageSectionObject
== NULL
)
3805 ObDereferenceObject(FileObject
);
3806 ObDereferenceObject(Section
);
3807 return(STATUS_NO_MEMORY
);
3810 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3812 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3814 if (!NT_SUCCESS(StatusExeFmt
))
3816 if(ImageSectionObject
->Segments
!= NULL
)
3817 ExFreePool(ImageSectionObject
->Segments
);
3819 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3820 ObDereferenceObject(Section
);
3821 ObDereferenceObject(FileObject
);
3822 return(StatusExeFmt
);
3825 Section
->ImageSection
= ImageSectionObject
;
3826 ASSERT(ImageSectionObject
->Segments
);
3831 Status
= MmspWaitForFileLock(FileObject
);
3832 if (!NT_SUCCESS(Status
))
3834 ExFreePool(ImageSectionObject
->Segments
);
3835 ExFreePool(ImageSectionObject
);
3836 ObDereferenceObject(Section
);
3837 ObDereferenceObject(FileObject
);
3841 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3842 ImageSectionObject
, NULL
))
3845 * An other thread has initialized the same image in the background
3847 ExFreePool(ImageSectionObject
->Segments
);
3848 ExFreePool(ImageSectionObject
);
3849 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3850 Section
->ImageSection
= ImageSectionObject
;
3851 SectionSegments
= ImageSectionObject
->Segments
;
3853 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3855 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3859 Status
= StatusExeFmt
;
3866 Status
= MmspWaitForFileLock(FileObject
);
3867 if (Status
!= STATUS_SUCCESS
)
3869 ObDereferenceObject(Section
);
3870 ObDereferenceObject(FileObject
);
3874 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3875 Section
->ImageSection
= ImageSectionObject
;
3876 SectionSegments
= ImageSectionObject
->Segments
;
3879 * Otherwise just reference all the section segments
3881 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3883 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3886 Status
= STATUS_SUCCESS
;
3888 Section
->FileObject
= FileObject
;
3890 CcRosReferenceCache(FileObject
);
3892 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3893 *SectionObject
= Section
;
3900 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3901 PROS_SECTION_OBJECT Section
,
3902 PMM_SECTION_SEGMENT Segment
,
3907 ULONG AllocationType
)
3913 if (Segment
->WriteCopy
)
3915 /* We have to do this because the not present fault
3916 * and access fault handlers depend on the protection
3917 * that should be granted AFTER the COW fault takes
3918 * place to be in Region->Protect. The not present fault
3919 * handler changes this to the correct protection for COW when
3920 * mapping the pages into the process's address space. If a COW
3921 * fault takes place, the access fault handler sets the page protection
3922 * to these values for the newly copied pages
3924 if (Protect
== PAGE_WRITECOPY
)
3925 Protect
= PAGE_READWRITE
;
3926 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3927 Protect
= PAGE_EXECUTE_READWRITE
;
3930 if (*BaseAddress
== NULL
)
3931 Granularity
= MM_ALLOCATION_GRANULARITY
;
3933 Granularity
= PAGE_SIZE
;
3936 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
3937 LARGE_INTEGER FileOffset
;
3938 FileOffset
.QuadPart
= ViewOffset
;
3939 ObReferenceObject(Section
);
3940 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3943 Status
= MmCreateMemoryArea(AddressSpace
,
3944 MEMORY_AREA_SECTION_VIEW
,
3952 if (!NT_SUCCESS(Status
))
3954 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3955 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3959 ObReferenceObject((PVOID
)Section
);
3961 MArea
->Data
.SectionData
.Segment
= Segment
;
3962 MArea
->Data
.SectionData
.Section
= Section
;
3963 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3964 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3965 ViewSize
, 0, Protect
);
3967 return(STATUS_SUCCESS
);
3972 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3973 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3976 PFILE_OBJECT FileObject
;
3978 LARGE_INTEGER Offset
;
3979 SWAPENTRY SavedSwapEntry
;
3980 PROS_SECTION_OBJECT Section
;
3981 PMM_SECTION_SEGMENT Segment
;
3982 PMMSUPPORT AddressSpace
;
3985 AddressSpace
= (PMMSUPPORT
)Context
;
3986 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3988 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3990 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3991 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3993 Section
= MemoryArea
->Data
.SectionData
.Section
;
3994 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3996 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3997 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
3999 MmUnlockSectionSegment(Segment
);
4000 MmUnlockAddressSpace(AddressSpace
);
4002 MiWaitForPageEvent(NULL
, NULL
);
4004 MmLockAddressSpace(AddressSpace
);
4005 MmLockSectionSegment(Segment
);
4006 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4010 * For a dirty, datafile, non-private page mark it as dirty in the
4013 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4015 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4017 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4018 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4020 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)(Offset
.QuadPart
+ Segment
->Image
.FileOffset
));
4022 ASSERT(SwapEntry
== 0);
4031 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4033 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4034 KeBugCheck(MEMORY_MANAGEMENT
);
4036 MmFreeSwapPage(SwapEntry
);
4040 if (IS_SWAP_FROM_SSE(Entry
) ||
4041 Page
!= PFN_FROM_SSE(Entry
))
4046 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4048 DPRINT1("Found a private page in a pagefile section.\n");
4049 KeBugCheck(MEMORY_MANAGEMENT
);
4052 * Just dereference private pages
4054 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4055 if (SavedSwapEntry
!= 0)
4057 MmFreeSwapPage(SavedSwapEntry
);
4058 MmSetSavedSwapEntryPage(Page
, 0);
4060 MmDeleteRmap(Page
, Process
, Address
);
4061 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4065 MmDeleteRmap(Page
, Process
, Address
);
4066 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4072 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4076 PMEMORY_AREA MemoryArea
;
4077 PROS_SECTION_OBJECT Section
;
4078 PMM_SECTION_SEGMENT Segment
;
4079 PLIST_ENTRY CurrentEntry
;
4080 PMM_REGION CurrentRegion
;
4081 PLIST_ENTRY RegionListHead
;
4083 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4085 if (MemoryArea
== NULL
)
4087 return(STATUS_UNSUCCESSFUL
);
4090 MemoryArea
->DeleteInProgress
= TRUE
;
4091 Section
= MemoryArea
->Data
.SectionData
.Section
;
4092 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4095 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4096 return MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4099 MmLockSectionSegment(Segment
);
4101 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4102 while (!IsListEmpty(RegionListHead
))
4104 CurrentEntry
= RemoveHeadList(RegionListHead
);
4105 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4106 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4109 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4111 Status
= MmFreeMemoryArea(AddressSpace
,
4118 Status
= MmFreeMemoryArea(AddressSpace
,
4123 MmUnlockSectionSegment(Segment
);
4124 ObDereferenceObject(Section
);
4130 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4131 IN PVOID BaseAddress
,
4135 PMEMORY_AREA MemoryArea
;
4136 PMMSUPPORT AddressSpace
;
4137 PROS_SECTION_OBJECT Section
;
4138 PVOID ImageBaseAddress
= 0;
4140 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4141 Process
, BaseAddress
);
4145 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4147 MmLockAddressSpace(AddressSpace
);
4148 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4150 if (MemoryArea
== NULL
||
4151 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4152 MemoryArea
->DeleteInProgress
)
4154 if (MemoryArea
) NT_ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4155 MmUnlockAddressSpace(AddressSpace
);
4156 return STATUS_NOT_MAPPED_VIEW
;
4159 MemoryArea
->DeleteInProgress
= TRUE
;
4161 Section
= MemoryArea
->Data
.SectionData
.Section
;
4163 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4167 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4168 PMM_SECTION_SEGMENT SectionSegments
;
4169 PMM_SECTION_SEGMENT Segment
;
4171 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4172 ImageSectionObject
= Section
->ImageSection
;
4173 SectionSegments
= ImageSectionObject
->Segments
;
4174 NrSegments
= ImageSectionObject
->NrSegments
;
4176 /* Search for the current segment within the section segments
4177 * and calculate the image base address */
4178 for (i
= 0; i
< NrSegments
; i
++)
4180 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4182 if (Segment
== &SectionSegments
[i
])
4184 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4189 if (i
>= NrSegments
)
4191 KeBugCheck(MEMORY_MANAGEMENT
);
4194 for (i
= 0; i
< NrSegments
; i
++)
4196 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4198 PVOID SBaseAddress
= (PVOID
)
4199 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4201 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4202 NT_ASSERT(NT_SUCCESS(Status
));
4208 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4209 NT_ASSERT(NT_SUCCESS(Status
));
4212 MmUnlockAddressSpace(AddressSpace
);
4214 /* Notify debugger */
4215 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4217 return(STATUS_SUCCESS
);
4224 * Queries the information of a section object.
4226 * @param SectionHandle
4227 * Handle to the section object. It must be opened with SECTION_QUERY
4229 * @param SectionInformationClass
4230 * Index to a certain information structure. Can be either
4231 * SectionBasicInformation or SectionImageInformation. The latter
4232 * is valid only for sections that were created with the SEC_IMAGE
4234 * @param SectionInformation
4235 * Caller supplies storage for resulting information.
4237 * Size of the supplied storage.
4238 * @param ResultLength
4246 NtQuerySection(IN HANDLE SectionHandle
,
4247 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4248 OUT PVOID SectionInformation
,
4249 IN SIZE_T SectionInformationLength
,
4250 OUT PSIZE_T ResultLength OPTIONAL
)
4252 PROS_SECTION_OBJECT Section
;
4253 KPROCESSOR_MODE PreviousMode
;
4257 PreviousMode
= ExGetPreviousMode();
4259 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4261 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4263 (ULONG
)SectionInformationLength
,
4268 if(!NT_SUCCESS(Status
))
4270 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4274 Status
= ObReferenceObjectByHandle(SectionHandle
,
4276 MmSectionObjectType
,
4278 (PVOID
*)(PVOID
)&Section
,
4280 if (NT_SUCCESS(Status
))
4282 switch (SectionInformationClass
)
4284 case SectionBasicInformation
:
4286 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4290 Sbi
->Attributes
= Section
->AllocationAttributes
;
4291 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4293 Sbi
->BaseAddress
= 0;
4294 Sbi
->Size
.QuadPart
= 0;
4298 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4299 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4302 if (ResultLength
!= NULL
)
4304 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4306 Status
= STATUS_SUCCESS
;
4308 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4310 Status
= _SEH2_GetExceptionCode();
4317 case SectionImageInformation
:
4319 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4323 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4325 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4326 ImageSectionObject
= Section
->ImageSection
;
4328 *Sii
= ImageSectionObject
->ImageInformation
;
4331 if (ResultLength
!= NULL
)
4333 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4335 Status
= STATUS_SUCCESS
;
4337 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4339 Status
= _SEH2_GetExceptionCode();
4347 ObDereferenceObject(Section
);
4353 /**********************************************************************
4355 * MmMapViewOfSection
4358 * Maps a view of a section into the virtual address space of a
4363 * Pointer to the section object.
4366 * Pointer to the process.
4369 * Desired base address (or NULL) on entry;
4370 * Actual base address of the view on exit.
4373 * Number of high order address bits that must be zero.
4376 * Size in bytes of the initially committed section of
4380 * Offset in bytes from the beginning of the section
4381 * to the beginning of the view.
4384 * Desired length of map (or zero to map all) on entry
4385 * Actual length mapped on exit.
4387 * InheritDisposition
4388 * Specified how the view is to be shared with
4392 * Type of allocation for the pages.
4395 * Protection for the committed region of the view.
4403 MmMapViewOfSection(IN PVOID SectionObject
,
4404 IN PEPROCESS Process
,
4405 IN OUT PVOID
*BaseAddress
,
4406 IN ULONG_PTR ZeroBits
,
4407 IN SIZE_T CommitSize
,
4408 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4409 IN OUT PSIZE_T ViewSize
,
4410 IN SECTION_INHERIT InheritDisposition
,
4411 IN ULONG AllocationType
,
4414 PROS_SECTION_OBJECT Section
;
4415 PMMSUPPORT AddressSpace
;
4417 NTSTATUS Status
= STATUS_SUCCESS
;
4418 BOOLEAN NotAtBase
= FALSE
;
4420 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4422 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4423 return MmMapViewOfArm3Section(SectionObject
,
4437 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4439 return STATUS_INVALID_PAGE_PROTECTION
;
4443 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4444 AddressSpace
= &Process
->Vm
;
4446 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4448 MmLockAddressSpace(AddressSpace
);
4450 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4454 ULONG_PTR ImageBase
;
4456 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4457 PMM_SECTION_SEGMENT SectionSegments
;
4459 ImageSectionObject
= Section
->ImageSection
;
4460 SectionSegments
= ImageSectionObject
->Segments
;
4461 NrSegments
= ImageSectionObject
->NrSegments
;
4463 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4466 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4470 for (i
= 0; i
< NrSegments
; i
++)
4472 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4474 ULONG_PTR MaxExtent
;
4475 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4476 SectionSegments
[i
].Length
.QuadPart
);
4477 ImageSize
= max(ImageSize
, MaxExtent
);
4481 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4483 /* Check for an illegal base address */
4484 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4485 ((ImageBase
+ ImageSize
) < ImageSize
))
4487 NT_ASSERT(*BaseAddress
== NULL
);
4488 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4489 MM_VIRTMEM_GRANULARITY
);
4492 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4494 NT_ASSERT(*BaseAddress
== NULL
);
4495 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4499 /* Check there is enough space to map the section at that point. */
4500 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4501 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4503 /* Fail if the user requested a fixed base address. */
4504 if ((*BaseAddress
) != NULL
)
4506 MmUnlockAddressSpace(AddressSpace
);
4507 return(STATUS_CONFLICTING_ADDRESSES
);
4509 /* Otherwise find a gap to map the image. */
4510 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4513 MmUnlockAddressSpace(AddressSpace
);
4514 return(STATUS_CONFLICTING_ADDRESSES
);
4516 /* Remember that we loaded image at a different base address */
4520 for (i
= 0; i
< NrSegments
; i
++)
4522 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4524 PVOID SBaseAddress
= (PVOID
)
4525 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4526 MmLockSectionSegment(&SectionSegments
[i
]);
4527 Status
= MmMapViewOfSegment(AddressSpace
,
4529 &SectionSegments
[i
],
4531 SectionSegments
[i
].Length
.LowPart
,
4532 SectionSegments
[i
].Protection
,
4535 MmUnlockSectionSegment(&SectionSegments
[i
]);
4536 if (!NT_SUCCESS(Status
))
4538 MmUnlockAddressSpace(AddressSpace
);
4544 *BaseAddress
= (PVOID
)ImageBase
;
4545 *ViewSize
= ImageSize
;
4549 /* check for write access */
4550 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4551 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4553 MmUnlockAddressSpace(AddressSpace
);
4554 return STATUS_SECTION_PROTECTION
;
4556 /* check for read access */
4557 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4558 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4560 MmUnlockAddressSpace(AddressSpace
);
4561 return STATUS_SECTION_PROTECTION
;
4563 /* check for execute access */
4564 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4565 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4567 MmUnlockAddressSpace(AddressSpace
);
4568 return STATUS_SECTION_PROTECTION
;
4571 if (ViewSize
== NULL
)
4573 /* Following this pointer would lead to us to the dark side */
4574 /* What to do? Bugcheck? Return status? Do the mambo? */
4575 KeBugCheck(MEMORY_MANAGEMENT
);
4578 if (SectionOffset
== NULL
)
4584 ViewOffset
= SectionOffset
->u
.LowPart
;
4587 if ((ViewOffset
% PAGE_SIZE
) != 0)
4589 MmUnlockAddressSpace(AddressSpace
);
4590 return(STATUS_MAPPED_ALIGNMENT
);
4593 if ((*ViewSize
) == 0)
4595 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4597 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4599 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4602 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4604 MmLockSectionSegment(Section
->Segment
);
4605 Status
= MmMapViewOfSegment(AddressSpace
,
4612 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4613 MmUnlockSectionSegment(Section
->Segment
);
4614 if (!NT_SUCCESS(Status
))
4616 MmUnlockAddressSpace(AddressSpace
);
4621 MmUnlockAddressSpace(AddressSpace
);
4622 NT_ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4625 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4627 Status
= STATUS_SUCCESS
;
4636 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4637 IN PLARGE_INTEGER NewFileSize
)
4639 /* Check whether an ImageSectionObject exists */
4640 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4642 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4646 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4648 PMM_SECTION_SEGMENT Segment
;
4650 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4653 if (Segment
->ReferenceCount
!= 0)
4656 CC_FILE_SIZES FileSizes
;
4658 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4661 /* Check size of file */
4662 if (SectionObjectPointer
->SharedCacheMap
)
4664 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4669 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4678 /* Check size of file */
4679 if (SectionObjectPointer
->SharedCacheMap
)
4681 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4682 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4691 /* Something must gone wrong
4692 * how can we have a Section but no
4694 DPRINT("ERROR: DataSectionObject without reference!\n");
4698 DPRINT("FIXME: didn't check for outstanding write probes\n");
4710 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4711 IN MMFLUSH_TYPE FlushType
)
4713 BOOLEAN Result
= TRUE
;
4715 PMM_SECTION_SEGMENT Segment
;
4720 case MmFlushForDelete
:
4721 if (SectionObjectPointer
->ImageSectionObject
||
4722 SectionObjectPointer
->DataSectionObject
)
4727 CcRosSetRemoveOnClose(SectionObjectPointer
);
4730 case MmFlushForWrite
:
4732 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4734 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4737 if (SectionObjectPointer
->ImageSectionObject
) {
4738 DPRINT1("SectionObject has ImageSection\n");
4744 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4746 DPRINT("Result %d\n", Result
);
4758 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4759 OUT PVOID
* MappedBase
,
4760 IN OUT PSIZE_T ViewSize
)
4762 PROS_SECTION_OBJECT Section
;
4763 PMMSUPPORT AddressSpace
;
4767 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4769 return MiMapViewInSystemSpace(SectionObject
,
4775 DPRINT("MmMapViewInSystemSpace() called\n");
4777 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4778 AddressSpace
= MmGetKernelAddressSpace();
4780 MmLockAddressSpace(AddressSpace
);
4783 if ((*ViewSize
) == 0)
4785 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4787 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4789 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4792 MmLockSectionSegment(Section
->Segment
);
4795 Status
= MmMapViewOfSegment(AddressSpace
,
4804 MmUnlockSectionSegment(Section
->Segment
);
4805 MmUnlockAddressSpace(AddressSpace
);
4812 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4814 PMMSUPPORT AddressSpace
;
4817 DPRINT("MmUnmapViewInSystemSpace() called\n");
4819 AddressSpace
= MmGetKernelAddressSpace();
4821 MmLockAddressSpace(AddressSpace
);
4823 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4825 MmUnlockAddressSpace(AddressSpace
);
4830 /**********************************************************************
4835 * Creates a section object.
4838 * SectionObject (OUT)
4839 * Caller supplied storage for the resulting pointer
4840 * to a SECTION_OBJECT instance;
4843 * Specifies the desired access to the section can be a
4845 * STANDARD_RIGHTS_REQUIRED |
4847 * SECTION_MAP_WRITE |
4848 * SECTION_MAP_READ |
4849 * SECTION_MAP_EXECUTE
4851 * ObjectAttributes [OPTIONAL]
4852 * Initialized attributes for the object can be used
4853 * to create a named section;
4856 * Maximizes the size of the memory section. Must be
4857 * non-NULL for a page-file backed section.
4858 * If value specified for a mapped file and the file is
4859 * not large enough, file will be extended.
4861 * SectionPageProtection
4862 * Can be a combination of:
4868 * AllocationAttributes
4869 * Can be a combination of:
4874 * Handle to a file to create a section mapped to a file
4875 * instead of a memory backed section;
4886 MmCreateSection (OUT PVOID
* Section
,
4887 IN ACCESS_MASK DesiredAccess
,
4888 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4889 IN PLARGE_INTEGER MaximumSize
,
4890 IN ULONG SectionPageProtection
,
4891 IN ULONG AllocationAttributes
,
4892 IN HANDLE FileHandle OPTIONAL
,
4893 IN PFILE_OBJECT FileObject OPTIONAL
)
4897 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4899 /* Check if an ARM3 section is being created instead */
4900 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4902 if (!(FileObject
) && !(FileHandle
))
4904 return MmCreateArm3Section(Section
,
4908 SectionPageProtection
,
4909 AllocationAttributes
&~ 1,
4915 /* Convert section flag to page flag */
4916 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4918 /* Check to make sure the protection is correct. Nt* does this already */
4919 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4920 if (Protection
== MM_INVALID_PROTECTION
)
4922 DPRINT1("Page protection is invalid\n");
4923 return STATUS_INVALID_PAGE_PROTECTION
;
4926 /* Check if this is going to be a data or image backed file section */
4927 if ((FileHandle
) || (FileObject
))
4929 /* These cannot be mapped with large pages */
4930 if (AllocationAttributes
& SEC_LARGE_PAGES
)
4932 DPRINT1("Large pages cannot be used with an image mapping\n");
4933 return STATUS_INVALID_PARAMETER_6
;
4936 /* Did the caller pass an object? */
4939 /* Reference the object directly */
4940 ObReferenceObject(FileObject
);
4944 /* Reference the file handle to get the object */
4945 Status
= ObReferenceObjectByHandle(FileHandle
,
4946 MmMakeFileAccess
[Protection
],
4948 ExGetPreviousMode(),
4949 (PVOID
*)&FileObject
,
4951 if (!NT_SUCCESS(Status
))
4953 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
4960 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
4961 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
4964 #ifndef NEWCC // A hack for initializing caching.
4965 // This is needed only in the old case.
4968 IO_STATUS_BLOCK Iosb
;
4971 LARGE_INTEGER ByteOffset
;
4972 ByteOffset
.QuadPart
= 0;
4973 Status
= ZwReadFile(FileHandle
,
4982 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
4984 DPRINT1("CC failure: %lx\n", Status
);
4987 // Caching is initialized...
4991 if (AllocationAttributes
& SEC_IMAGE
)
4993 Status
= MmCreateImageSection(SectionObject
,
4997 SectionPageProtection
,
4998 AllocationAttributes
,
5002 else if (FileHandle
!= NULL
)
5004 Status
= MmCreateDataFileSection(SectionObject
,
5008 SectionPageProtection
,
5009 AllocationAttributes
,
5012 ObDereferenceObject(FileObject
);
5015 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5017 Status
= MmCreateCacheSection(SectionObject
,
5021 SectionPageProtection
,
5022 AllocationAttributes
,
5028 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5030 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5032 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5033 Status
= MmCreatePageFileSection(SectionObject
,
5037 SectionPageProtection
,
5038 AllocationAttributes
);