2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
48 #include "../cache/newcc.h"
49 #include "../cache/section/newmm.h"
52 #include <reactos/exeformat.h>
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 #include "ARM3/miarm.h"
61 #undef MmSetPageEntrySectionSegment
62 #define MmSetPageEntrySectionSegment(S,O,E) do { \
63 DPRINT("SetPageEntrySectionSegment(old,%p,%x,%x)\n",(S),(O)->LowPart,E); \
64 _MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__); \
67 extern MMSESSION MmSession
;
71 MiMapViewInSystemSpace(IN PVOID Section
,
73 OUT PVOID
*MappedBase
,
74 IN OUT PSIZE_T ViewSize
);
78 MmCreateArm3Section(OUT PVOID
*SectionObject
,
79 IN ACCESS_MASK DesiredAccess
,
80 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
81 IN PLARGE_INTEGER InputMaximumSize
,
82 IN ULONG SectionPageProtection
,
83 IN ULONG AllocationAttributes
,
84 IN HANDLE FileHandle OPTIONAL
,
85 IN PFILE_OBJECT FileObject OPTIONAL
);
89 MmMapViewOfArm3Section(IN PVOID SectionObject
,
91 IN OUT PVOID
*BaseAddress
,
92 IN ULONG_PTR ZeroBits
,
94 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
95 IN OUT PSIZE_T ViewSize
,
96 IN SECTION_INHERIT InheritDisposition
,
97 IN ULONG AllocationType
,
101 // PeFmtCreateSection depends on the following:
103 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
104 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
106 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
107 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
108 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
110 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
111 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
112 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
113 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
114 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
115 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
116 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
117 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
118 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
120 /* TYPES *********************************************************************/
124 PROS_SECTION_OBJECT Section
;
125 PMM_SECTION_SEGMENT Segment
;
126 LARGE_INTEGER Offset
;
129 PEPROCESS CallingProcess
;
130 ULONG_PTR SectionEntry
;
132 MM_SECTION_PAGEOUT_CONTEXT
;
134 /* GLOBALS *******************************************************************/
136 POBJECT_TYPE MmSectionObjectType
= NULL
;
138 ULONG_PTR MmSubsectionBase
;
140 static ULONG SectionCharacteristicsToProtect
[16] =
142 PAGE_NOACCESS
, /* 0 = NONE */
143 PAGE_NOACCESS
, /* 1 = SHARED */
144 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
145 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
146 PAGE_READONLY
, /* 4 = READABLE */
147 PAGE_READONLY
, /* 5 = READABLE, SHARED */
148 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
149 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
151 * FIXME? do we really need the WriteCopy field in segments? can't we use
152 * PAGE_WRITECOPY here?
154 PAGE_READWRITE
, /* 8 = WRITABLE */
155 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
156 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
157 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
158 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
159 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
160 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
161 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
164 extern ULONG MmMakeFileAccess
[];
165 ACCESS_MASK NTAPI
MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection
);
166 static GENERIC_MAPPING MmpSectionMapping
= {
167 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
168 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
169 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
172 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
174 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
175 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
178 /* FUNCTIONS *****************************************************************/
183 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
184 File Format Specification", revision 6.0 (February 1999)
186 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
187 IN SIZE_T FileHeaderSize
,
189 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
191 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
192 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
195 ULONG cbFileHeaderOffsetSize
= 0;
196 ULONG cbSectionHeadersOffset
= 0;
197 ULONG cbSectionHeadersSize
;
198 ULONG cbSectionHeadersOffsetSize
= 0;
199 ULONG cbOptHeaderSize
;
200 ULONG cbHeadersSize
= 0;
201 ULONG nSectionAlignment
;
202 ULONG nFileAlignment
;
204 const IMAGE_DOS_HEADER
* pidhDosHeader
;
205 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
206 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
207 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
208 PMM_SECTION_SEGMENT pssSegments
;
209 LARGE_INTEGER lnOffset
;
211 SIZE_T nPrevVirtualEndOfSegment
= 0;
212 ULONG nFileSizeOfHeaders
= 0;
216 ASSERT(FileHeaderSize
> 0);
218 ASSERT(ImageSectionObject
);
220 ASSERT(AllocateSegmentsCb
);
222 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
224 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
226 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
229 pidhDosHeader
= FileHeader
;
232 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
234 /* image too small to be an MZ executable */
235 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
236 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
238 /* no MZ signature */
239 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
240 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
242 /* not a Windows executable */
243 if(pidhDosHeader
->e_lfanew
<= 0)
244 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
247 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
249 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
250 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
252 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
257 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
258 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
260 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
261 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
265 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
266 * need to read the header from the file
268 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
269 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
271 ULONG cbNtHeaderSize
;
275 l_ReadHeaderFromFile
:
277 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
279 /* read the header from the file */
280 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
282 if(!NT_SUCCESS(nStatus
))
283 DIE(("ReadFile failed, status %08X\n", nStatus
));
287 ASSERT(cbReadSize
> 0);
289 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
291 /* the buffer doesn't contain the file header */
292 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
293 DIE(("The file doesn't contain the PE file header\n"));
295 pinhNtHeader
= pData
;
297 /* object still not aligned: copy it to the beginning of the buffer */
298 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
300 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
301 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
302 pinhNtHeader
= pBuffer
;
305 /* invalid NT header */
306 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
308 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
309 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
311 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
313 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
314 DIE(("The full NT header is too large\n"));
316 /* the buffer doesn't contain the whole NT header */
317 if(cbReadSize
< cbNtHeaderSize
)
318 DIE(("The file doesn't contain the full NT header\n"));
322 ULONG cbOptHeaderOffsetSize
= 0;
324 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
326 /* don't trust an invalid NT header */
327 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
328 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
330 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
331 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
333 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
334 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
336 /* the buffer doesn't contain the whole NT header: read it from the file */
337 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
338 goto l_ReadHeaderFromFile
;
341 /* read information from the NT header */
342 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
343 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
345 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
347 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
348 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
350 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
352 switch(piohOptHeader
->Magic
)
354 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
355 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
359 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
362 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
363 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
365 /* See [1], section 3.4.2 */
366 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
368 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
369 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
371 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
372 DIE(("The section alignment is smaller than the file alignment\n"));
374 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
375 nFileAlignment
= piohOptHeader
->FileAlignment
;
377 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
378 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
382 nSectionAlignment
= PAGE_SIZE
;
383 nFileAlignment
= PAGE_SIZE
;
386 ASSERT(IsPowerOf2(nSectionAlignment
));
387 ASSERT(IsPowerOf2(nFileAlignment
));
389 switch(piohOptHeader
->Magic
)
392 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
394 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
395 ImageBase
= piohOptHeader
->ImageBase
;
397 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
398 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
400 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
401 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
403 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
404 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
406 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
408 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
410 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
411 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
413 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
414 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
418 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
420 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
421 piohOptHeader
->AddressOfEntryPoint
);
424 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
425 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
427 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
429 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
431 if (piohOptHeader
->AddressOfEntryPoint
== 0)
433 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
437 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
438 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
440 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
442 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
445 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
446 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
447 * magic to any binary.
449 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
450 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
451 * the SxS support -- at which point, duh, this should be removed.
453 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
455 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
462 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
464 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
466 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
468 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
470 ImageBase
= pioh64OptHeader
->ImageBase
;
471 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
472 DIE(("ImageBase exceeds the address space\n"));
475 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
477 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
478 DIE(("SizeOfImage exceeds the address space\n"));
480 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
483 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
485 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
486 DIE(("SizeOfStackReserve exceeds the address space\n"));
488 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
491 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
493 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
494 DIE(("SizeOfStackCommit exceeds the address space\n"));
496 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
499 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
501 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
503 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
504 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
506 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
507 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
511 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
513 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
514 pioh64OptHeader
->AddressOfEntryPoint
);
517 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
518 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
520 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
522 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
524 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
526 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
530 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
531 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
533 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
534 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
540 /* [1], section 3.4.2 */
541 if((ULONG_PTR
)ImageBase
% 0x10000)
542 DIE(("ImageBase is not aligned on a 64KB boundary"));
544 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
545 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
546 ImageSectionObject
->ImageInformation
.GpValue
= 0;
547 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
548 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
550 /* SECTION HEADERS */
551 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
553 /* see [1], section 3.3 */
554 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
555 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
558 * the additional segment is for the file's headers. They need to be present for
559 * the benefit of the dynamic loader (to locate exports, defaults for thread
560 * parameters, resources, etc.)
562 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
564 /* file offset for the section headers */
565 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
566 DIE(("Offset overflow\n"));
568 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
569 DIE(("Offset overflow\n"));
571 /* size of the section headers */
572 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
573 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
575 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
576 DIE(("Section headers too large\n"));
578 /* size of the executable's headers */
579 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
581 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
582 // DIE(("SizeOfHeaders is not aligned\n"));
584 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
585 DIE(("The section headers overflow SizeOfHeaders\n"));
587 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
589 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
590 DIE(("Overflow aligning the size of headers\n"));
597 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
598 /* WARNING: piohOptHeader IS NO LONGER USABLE */
599 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
601 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
602 pishSectionHeaders
= NULL
;
606 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
607 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
609 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
610 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
614 * the buffer doesn't contain the section headers, or the alignment is wrong:
615 * read the headers from the file
617 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
618 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
623 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
625 /* read the header from the file */
626 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
628 if(!NT_SUCCESS(nStatus
))
629 DIE(("ReadFile failed with status %08X\n", nStatus
));
633 ASSERT(cbReadSize
> 0);
635 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
637 /* the buffer doesn't contain all the section headers */
638 if(cbReadSize
< cbSectionHeadersSize
)
639 DIE(("The file doesn't contain all of the section headers\n"));
641 pishSectionHeaders
= pData
;
643 /* object still not aligned: copy it to the beginning of the buffer */
644 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
646 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
647 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
648 pishSectionHeaders
= pBuffer
;
653 /* allocate the segments */
654 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
655 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
657 if(ImageSectionObject
->Segments
== NULL
)
658 DIE(("AllocateSegments failed\n"));
660 /* initialize the headers segment */
661 pssSegments
= ImageSectionObject
->Segments
;
663 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
665 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
666 DIE(("Cannot align the size of the section headers\n"));
668 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
669 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
670 DIE(("Cannot align the size of the section headers\n"));
672 pssSegments
[0].Image
.FileOffset
= 0;
673 pssSegments
[0].Protection
= PAGE_READONLY
;
674 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
675 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
676 pssSegments
[0].Image
.VirtualAddress
= 0;
677 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
678 pssSegments
[0].WriteCopy
= TRUE
;
680 /* skip the headers segment */
683 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
685 /* convert the executable sections into segments. See also [1], section 4 */
686 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
688 ULONG nCharacteristics
;
690 /* validate the alignment */
691 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
692 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
694 /* sections must be contiguous, ordered by base address and non-overlapping */
695 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
696 DIE(("Memory gap between section %u and the previous\n", i
));
698 /* ignore explicit BSS sections */
699 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
701 /* validate the alignment */
703 /* Yes, this should be a multiple of FileAlignment, but there's
704 * stuff out there that isn't. We can cope with that
706 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
707 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
710 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
711 // DIE(("PointerToRawData[%u] is not aligned\n", i));
714 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
715 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
719 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
720 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
723 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
725 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
727 /* no explicit protection */
728 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
730 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
731 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
733 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
734 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
736 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
737 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
740 /* see table above */
741 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
742 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
744 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
745 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
747 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
749 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
750 /* FIXME: always false */
751 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
752 DIE(("Cannot align the virtual size of section %u\n", i
));
754 if(pssSegments
[i
].Length
.QuadPart
== 0)
755 DIE(("Virtual size of section %u is null\n", i
));
757 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
758 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
760 /* ensure the memory image is no larger than 4GB */
761 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
762 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
763 DIE(("The image is too large\n"));
766 if(nSectionAlignment
>= PAGE_SIZE
)
767 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
770 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
780 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
781 * ARGUMENTS: PFILE_OBJECT to wait for.
782 * RETURNS: Status of the wait.
785 MmspWaitForFileLock(PFILE_OBJECT File
)
787 return STATUS_SUCCESS
;
788 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
793 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
795 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
797 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
798 PMM_SECTION_SEGMENT SectionSegments
;
802 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
803 NrSegments
= ImageSectionObject
->NrSegments
;
804 SectionSegments
= ImageSectionObject
->Segments
;
805 for (i
= 0; i
< NrSegments
; i
++)
807 if (SectionSegments
[i
].ReferenceCount
!= 0)
809 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
810 SectionSegments
[i
].ReferenceCount
);
811 KeBugCheck(MEMORY_MANAGEMENT
);
813 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
815 ExFreePool(ImageSectionObject
->Segments
);
816 ExFreePool(ImageSectionObject
);
817 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
819 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
821 PMM_SECTION_SEGMENT Segment
;
823 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
826 if (Segment
->ReferenceCount
!= 0)
828 DPRINT1("Data segment still referenced\n");
829 KeBugCheck(MEMORY_MANAGEMENT
);
831 MmFreePageTablesSectionSegment(Segment
, NULL
);
833 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
839 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
840 PLARGE_INTEGER Offset
)
844 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
847 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
848 KeBugCheck(MEMORY_MANAGEMENT
);
850 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
852 DPRINT1("Maximum share count reached\n");
853 KeBugCheck(MEMORY_MANAGEMENT
);
855 if (IS_SWAP_FROM_SSE(Entry
))
857 KeBugCheck(MEMORY_MANAGEMENT
);
859 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
860 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
865 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
866 PMM_SECTION_SEGMENT Segment
,
867 PLARGE_INTEGER Offset
,
872 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
873 BOOLEAN IsDirectMapped
= FALSE
;
877 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
878 KeBugCheck(MEMORY_MANAGEMENT
);
880 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
882 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
883 KeBugCheck(MEMORY_MANAGEMENT
);
885 if (IS_SWAP_FROM_SSE(Entry
))
887 KeBugCheck(MEMORY_MANAGEMENT
);
889 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
891 * If we reducing the share count of this entry to zero then set the entry
892 * to zero and tell the cache the page is no longer mapped.
894 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
896 PFILE_OBJECT FileObject
;
900 SWAPENTRY SavedSwapEntry
;
902 BOOLEAN IsImageSection
;
903 LARGE_INTEGER FileOffset
;
905 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
907 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
909 Page
= PFN_FROM_SSE(Entry
);
910 FileObject
= Section
->FileObject
;
911 if (FileObject
!= NULL
&&
912 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
916 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
917 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
920 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
921 IsDirectMapped
= TRUE
;
923 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
.LowPart
, Dirty
);
925 Status
= STATUS_SUCCESS
;
927 if (!NT_SUCCESS(Status
))
929 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
930 KeBugCheck(MEMORY_MANAGEMENT
);
936 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
937 if (SavedSwapEntry
== 0)
940 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
941 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
945 * Try to page out this page and set the swap entry
946 * within the section segment. There exist no rmap entry
947 * for this page. The pager thread can't page out a
948 * page without a rmap entry.
950 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
951 if (InEntry
) *InEntry
= Entry
;
952 MiSetPageEvent(NULL
, NULL
);
956 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
957 if (InEntry
) *InEntry
= 0;
958 MiSetPageEvent(NULL
, NULL
);
961 MmReleasePageMemoryConsumer(MC_USER
, Page
);
967 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
968 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
976 * We hold all locks. Nobody can do something with the current
977 * process and the current segment (also not within an other process).
980 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
981 if (!NT_SUCCESS(Status
))
983 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
984 KeBugCheck(MEMORY_MANAGEMENT
);
987 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
988 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
989 MmSetSavedSwapEntryPage(Page
, 0);
990 MiSetPageEvent(NULL
, NULL
);
992 MmReleasePageMemoryConsumer(MC_USER
, Page
);
996 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
997 KeBugCheck(MEMORY_MANAGEMENT
);
1006 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1008 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1011 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1015 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1018 PCACHE_SEGMENT CacheSeg
;
1019 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1020 CacheSeg
= CcRosLookupCacheSegment(Bcb
, (ULONG
)(SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
));
1023 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
1033 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1037 PVOID DestAddress
, SrcAddress
;
1039 Process
= PsGetCurrentProcess();
1040 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1041 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1042 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1044 return(STATUS_NO_MEMORY
);
1046 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1047 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1048 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1049 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1050 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1051 return(STATUS_SUCCESS
);
1057 MiReadPage(PMEMORY_AREA MemoryArea
,
1058 ULONG_PTR SegOffset
,
1061 * FUNCTION: Read a page for a section backed memory area.
1063 * MemoryArea - Memory area to read the page for.
1064 * Offset - Offset of the page to read.
1065 * Page - Variable that receives a page contains the read data.
1069 ULONGLONG FileOffset
;
1072 PCACHE_SEGMENT CacheSeg
;
1073 PFILE_OBJECT FileObject
;
1075 ULONG_PTR RawLength
;
1077 BOOLEAN IsImageSection
;
1080 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1081 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1082 RawLength
= (ULONG_PTR
)(MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
);
1083 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1084 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1088 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1091 * If the file system is letting us go directly to the cache and the
1092 * memory area was mapped at an offset in the file which is page aligned
1093 * then get the related cache segment.
1095 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1096 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1097 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1101 * Get the related cache segment; we use a lower level interface than
1102 * filesystems do because it is safe for us to use an offset with a
1103 * alignment less than the file system block size.
1105 Status
= CcRosGetCacheSegment(Bcb
,
1111 if (!NT_SUCCESS(Status
))
1118 * If the cache segment isn't up to date then call the file
1119 * system to read in the data.
1121 Status
= ReadCacheSegment(CacheSeg
);
1122 if (!NT_SUCCESS(Status
))
1124 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1129 /* Probe the page, since it's PDE might not be synced */
1130 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1133 * Retrieve the page from the cache segment that we actually want.
1135 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1136 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1138 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1145 ULONG_PTR CacheSegOffset
;
1148 * Allocate a page, this is rather complicated by the possibility
1149 * we might have to move other things out of memory
1151 MI_SET_USAGE(MI_USAGE_SECTION
);
1152 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1153 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1154 if (!NT_SUCCESS(Status
))
1158 Status
= CcRosGetCacheSegment(Bcb
,
1164 if (!NT_SUCCESS(Status
))
1171 * If the cache segment isn't up to date then call the file
1172 * system to read in the data.
1174 Status
= ReadCacheSegment(CacheSeg
);
1175 if (!NT_SUCCESS(Status
))
1177 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1182 Process
= PsGetCurrentProcess();
1183 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1184 CacheSegOffset
= (ULONG_PTR
)(BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
);
1185 Length
= RawLength
- SegOffset
;
1186 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1188 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1190 else if (CacheSegOffset
>= PAGE_SIZE
)
1192 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1196 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1197 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1198 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1199 Status
= CcRosGetCacheSegment(Bcb
,
1200 (ULONG
)(FileOffset
+ CacheSegOffset
),
1205 if (!NT_SUCCESS(Status
))
1212 * If the cache segment isn't up to date then call the file
1213 * system to read in the data.
1215 Status
= ReadCacheSegment(CacheSeg
);
1216 if (!NT_SUCCESS(Status
))
1218 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1222 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1223 if (Length
< PAGE_SIZE
)
1225 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1229 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1232 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1233 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1235 return(STATUS_SUCCESS
);
1240 MiReadPage(PMEMORY_AREA MemoryArea
,
1241 ULONG_PTR SegOffset
,
1244 * FUNCTION: Read a page for a section backed memory area.
1246 * MemoryArea - Memory area to read the page for.
1247 * Offset - Offset of the page to read.
1248 * Page - Variable that receives a page contains the read data.
1251 MM_REQUIRED_RESOURCES Resources
;
1254 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1256 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1257 Resources
.FileOffset
.QuadPart
= SegOffset
+
1258 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1259 Resources
.Consumer
= MC_USER
;
1260 Resources
.Amount
= PAGE_SIZE
;
1262 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]);
1264 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1265 *Page
= Resources
.Page
[0];
1272 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1273 MEMORY_AREA
* MemoryArea
,
1277 LARGE_INTEGER Offset
;
1280 PROS_SECTION_OBJECT Section
;
1281 PMM_SECTION_SEGMENT Segment
;
1286 BOOLEAN HasSwapEntry
;
1288 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1289 SWAPENTRY SwapEntry
;
1292 * There is a window between taking the page fault and locking the
1293 * address space when another thread could load the page so we check
1296 if (MmIsPagePresent(Process
, Address
))
1298 return(STATUS_SUCCESS
);
1301 if (MmIsDisabledPage(Process
, Address
))
1303 return(STATUS_ACCESS_VIOLATION
);
1307 * Check for the virtual memory area being deleted.
1309 if (MemoryArea
->DeleteInProgress
)
1311 return(STATUS_UNSUCCESSFUL
);
1314 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1315 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1316 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1318 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1319 Section
= MemoryArea
->Data
.SectionData
.Section
;
1320 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1321 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1323 ASSERT(Region
!= NULL
);
1327 MmLockSectionSegment(Segment
);
1328 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1330 * Check if this page needs to be mapped COW
1332 if ((Segment
->WriteCopy
) &&
1333 (Region
->Protect
== PAGE_READWRITE
||
1334 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1336 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1340 Attributes
= Region
->Protect
;
1344 * Check if someone else is already handling this fault, if so wait
1347 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1349 MmUnlockSectionSegment(Segment
);
1350 MmUnlockAddressSpace(AddressSpace
);
1351 MiWaitForPageEvent(NULL
, NULL
);
1352 MmLockAddressSpace(AddressSpace
);
1353 DPRINT("Address 0x%p\n", Address
);
1354 return(STATUS_MM_RESTART_OPERATION
);
1357 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1361 SWAPENTRY DummyEntry
;
1364 * Is it a wait entry?
1366 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1368 if (SwapEntry
== MM_WAIT_ENTRY
)
1370 MmUnlockSectionSegment(Segment
);
1371 MmUnlockAddressSpace(AddressSpace
);
1372 MiWaitForPageEvent(NULL
, NULL
);
1373 MmLockAddressSpace(AddressSpace
);
1374 return STATUS_MM_RESTART_OPERATION
;
1378 * Must be private page we have swapped out.
1384 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1386 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1387 KeBugCheck(MEMORY_MANAGEMENT
);
1390 MmUnlockSectionSegment(Segment
);
1391 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1392 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1394 MmUnlockAddressSpace(AddressSpace
);
1395 MI_SET_USAGE(MI_USAGE_SECTION
);
1396 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1397 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1398 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1399 if (!NT_SUCCESS(Status
))
1401 KeBugCheck(MEMORY_MANAGEMENT
);
1404 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1405 if (!NT_SUCCESS(Status
))
1407 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1408 KeBugCheck(MEMORY_MANAGEMENT
);
1410 MmLockAddressSpace(AddressSpace
);
1411 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1412 Status
= MmCreateVirtualMapping(Process
,
1417 if (!NT_SUCCESS(Status
))
1419 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1420 KeBugCheck(MEMORY_MANAGEMENT
);
1425 * Store the swap entry for later use.
1427 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1430 * Add the page to the process's working set
1432 MmInsertRmap(Page
, Process
, Address
);
1434 * Finish the operation
1436 MiSetPageEvent(Process
, Address
);
1437 DPRINT("Address 0x%p\n", Address
);
1438 return(STATUS_SUCCESS
);
1442 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1444 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1446 MmUnlockSectionSegment(Segment
);
1448 * Just map the desired physical page
1450 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1451 Status
= MmCreateVirtualMappingUnsafe(Process
,
1456 if (!NT_SUCCESS(Status
))
1458 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1459 KeBugCheck(MEMORY_MANAGEMENT
);
1464 * Cleanup and release locks
1466 MiSetPageEvent(Process
, Address
);
1467 DPRINT("Address 0x%p\n", Address
);
1468 return(STATUS_SUCCESS
);
1472 * Get the entry corresponding to the offset within the section
1474 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1478 SWAPENTRY FakeSwapEntry
;
1481 * If the entry is zero (and it can't change because we have
1482 * locked the segment) then we need to load the page.
1486 * Release all our locks and read in the page from disk
1488 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1489 MmUnlockSectionSegment(Segment
);
1490 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1491 MmUnlockAddressSpace(AddressSpace
);
1493 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1494 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1495 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1497 MI_SET_USAGE(MI_USAGE_SECTION
);
1498 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1499 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1500 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1501 if (!NT_SUCCESS(Status
))
1503 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1509 Status
= MiReadPage(MemoryArea
, (ULONG_PTR
)Offset
.QuadPart
, &Page
);
1510 if (!NT_SUCCESS(Status
))
1512 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1515 if (!NT_SUCCESS(Status
))
1518 * FIXME: What do we know in this case?
1521 * Cleanup and release locks
1523 MmLockAddressSpace(AddressSpace
);
1524 MiSetPageEvent(Process
, Address
);
1525 DPRINT("Address 0x%p\n", Address
);
1530 * Mark the offset within the section as having valid, in-memory
1533 MmLockAddressSpace(AddressSpace
);
1534 MmLockSectionSegment(Segment
);
1535 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1536 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1537 MmUnlockSectionSegment(Segment
);
1539 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1540 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1541 Page
, Process
, PAddress
, Attributes
);
1542 Status
= MmCreateVirtualMapping(Process
,
1547 if (!NT_SUCCESS(Status
))
1549 DPRINT1("Unable to create virtual mapping\n");
1550 KeBugCheck(MEMORY_MANAGEMENT
);
1552 ASSERT(MmIsPagePresent(Process
, PAddress
));
1553 MmInsertRmap(Page
, Process
, Address
);
1555 MiSetPageEvent(Process
, Address
);
1556 DPRINT("Address 0x%p\n", Address
);
1557 return(STATUS_SUCCESS
);
1559 else if (IS_SWAP_FROM_SSE(Entry
))
1561 SWAPENTRY SwapEntry
;
1563 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1566 * Release all our locks and read in the page from disk
1568 MmUnlockSectionSegment(Segment
);
1570 MmUnlockAddressSpace(AddressSpace
);
1571 MI_SET_USAGE(MI_USAGE_SECTION
);
1572 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1573 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1574 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1575 if (!NT_SUCCESS(Status
))
1577 KeBugCheck(MEMORY_MANAGEMENT
);
1580 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1581 if (!NT_SUCCESS(Status
))
1583 KeBugCheck(MEMORY_MANAGEMENT
);
1587 * Relock the address space and segment
1589 MmLockAddressSpace(AddressSpace
);
1590 MmLockSectionSegment(Segment
);
1593 * Check the entry. No one should change the status of a page
1594 * that has a pending page-in.
1596 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1597 if (Entry
!= Entry1
)
1599 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1600 KeBugCheck(MEMORY_MANAGEMENT
);
1604 * Mark the offset within the section as having valid, in-memory
1607 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1608 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1609 MmUnlockSectionSegment(Segment
);
1612 * Save the swap entry.
1614 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1615 Status
= MmCreateVirtualMapping(Process
,
1620 if (!NT_SUCCESS(Status
))
1622 DPRINT1("Unable to create virtual mapping\n");
1623 KeBugCheck(MEMORY_MANAGEMENT
);
1625 MmInsertRmap(Page
, Process
, Address
);
1626 MiSetPageEvent(Process
, Address
);
1627 DPRINT("Address 0x%p\n", Address
);
1628 return(STATUS_SUCCESS
);
1633 * If the section offset is already in-memory and valid then just
1634 * take another reference to the page
1637 Page
= PFN_FROM_SSE(Entry
);
1639 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1640 MmUnlockSectionSegment(Segment
);
1642 Status
= MmCreateVirtualMapping(Process
,
1647 if (!NT_SUCCESS(Status
))
1649 DPRINT1("Unable to create virtual mapping\n");
1650 KeBugCheck(MEMORY_MANAGEMENT
);
1652 MmInsertRmap(Page
, Process
, Address
);
1653 MiSetPageEvent(Process
, Address
);
1654 DPRINT("Address 0x%p\n", Address
);
1655 return(STATUS_SUCCESS
);
1661 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1662 MEMORY_AREA
* MemoryArea
,
1665 PMM_SECTION_SEGMENT Segment
;
1666 PROS_SECTION_OBJECT Section
;
1671 LARGE_INTEGER Offset
;
1674 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1675 SWAPENTRY SwapEntry
;
1677 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1680 * Check if the page has already been set readwrite
1682 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1684 DPRINT("Address 0x%p\n", Address
);
1685 return(STATUS_SUCCESS
);
1689 * Find the offset of the page
1691 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1692 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1693 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1695 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1696 Section
= MemoryArea
->Data
.SectionData
.Section
;
1697 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1698 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1700 ASSERT(Region
!= NULL
);
1704 MmLockSectionSegment(Segment
);
1706 OldPage
= MmGetPfnForProcess(Process
, Address
);
1707 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1709 MmUnlockSectionSegment(Segment
);
1712 * Check if we are doing COW
1714 if (!((Segment
->WriteCopy
) &&
1715 (Region
->Protect
== PAGE_READWRITE
||
1716 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1718 DPRINT("Address 0x%p\n", Address
);
1719 return(STATUS_ACCESS_VIOLATION
);
1722 if (IS_SWAP_FROM_SSE(Entry
) ||
1723 PFN_FROM_SSE(Entry
) != OldPage
)
1725 /* This is a private page. We must only change the page protection. */
1726 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1727 return(STATUS_SUCCESS
);
1731 DPRINT("OldPage == 0!\n");
1734 * Get or create a pageop
1736 MmLockSectionSegment(Segment
);
1737 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1740 * Wait for any other operations to complete
1742 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1744 MmUnlockSectionSegment(Segment
);
1745 MmUnlockAddressSpace(AddressSpace
);
1746 MiWaitForPageEvent(NULL
, NULL
);
1748 * Restart the operation
1750 MmLockAddressSpace(AddressSpace
);
1751 DPRINT("Address 0x%p\n", Address
);
1752 return(STATUS_MM_RESTART_OPERATION
);
1755 MmDeleteRmap(OldPage
, Process
, PAddress
);
1756 MmDeleteVirtualMapping(Process
, PAddress
, FALSE
, NULL
, NULL
);
1757 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1760 * Release locks now we have the pageop
1762 MmUnlockSectionSegment(Segment
);
1763 MmUnlockAddressSpace(AddressSpace
);
1768 MI_SET_USAGE(MI_USAGE_SECTION
);
1769 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1770 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1771 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1772 if (!NT_SUCCESS(Status
))
1774 KeBugCheck(MEMORY_MANAGEMENT
);
1780 MiCopyFromUserPage(NewPage
, OldPage
);
1782 MmLockAddressSpace(AddressSpace
);
1785 * Set the PTE to point to the new page
1787 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1788 Status
= MmCreateVirtualMapping(Process
,
1793 if (!NT_SUCCESS(Status
))
1795 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1796 KeBugCheck(MEMORY_MANAGEMENT
);
1801 * Unshare the old page.
1803 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1804 MmInsertRmap(NewPage
, Process
, PAddress
);
1805 MmLockSectionSegment(Segment
);
1806 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1807 MmUnlockSectionSegment(Segment
);
1809 MiSetPageEvent(Process
, Address
);
1810 DPRINT("Address 0x%p\n", Address
);
1811 return(STATUS_SUCCESS
);
1815 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1817 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1819 PFN_NUMBER Page
= 0;
1821 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1824 MmLockAddressSpace(&Process
->Vm
);
1827 MmDeleteVirtualMapping(Process
,
1834 PageOutContext
->WasDirty
= TRUE
;
1836 if (!PageOutContext
->Private
)
1838 MmLockSectionSegment(PageOutContext
->Segment
);
1839 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1840 PageOutContext
->Segment
,
1841 &PageOutContext
->Offset
,
1842 PageOutContext
->WasDirty
,
1844 &PageOutContext
->SectionEntry
);
1845 MmUnlockSectionSegment(PageOutContext
->Segment
);
1849 MmUnlockAddressSpace(&Process
->Vm
);
1852 if (PageOutContext
->Private
)
1854 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1860 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1861 MEMORY_AREA
* MemoryArea
,
1862 PVOID Address
, ULONG_PTR Entry
)
1865 MM_SECTION_PAGEOUT_CONTEXT Context
;
1866 SWAPENTRY SwapEntry
;
1867 ULONGLONG FileOffset
;
1869 PFILE_OBJECT FileObject
;
1873 BOOLEAN DirectMapped
;
1874 BOOLEAN IsImageSection
;
1875 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1878 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1881 * Get the segment and section.
1883 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1884 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1885 Context
.SectionEntry
= Entry
;
1886 Context
.CallingProcess
= Process
;
1888 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1889 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1890 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1892 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1894 FileObject
= Context
.Section
->FileObject
;
1895 DirectMapped
= FALSE
;
1897 MmLockSectionSegment(Context
.Segment
);
1900 if (FileObject
!= NULL
&&
1901 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1903 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1906 * If the file system is letting us go directly to the cache and the
1907 * memory area was mapped at an offset in the file which is page aligned
1908 * then note this is a direct mapped page.
1910 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1911 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1913 DirectMapped
= TRUE
;
1920 * This should never happen since mappings of physical memory are never
1921 * placed in the rmap lists.
1923 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1925 DPRINT1("Trying to page out from physical memory section address 0x%p "
1926 "process %p\n", Address
,
1927 Process
? Process
->UniqueProcessId
: 0);
1928 KeBugCheck(MEMORY_MANAGEMENT
);
1932 * Get the section segment entry and the physical address.
1934 if (!MmIsPagePresent(Process
, Address
))
1936 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1937 Process
? Process
->UniqueProcessId
: 0, Address
);
1938 KeBugCheck(MEMORY_MANAGEMENT
);
1940 Page
= MmGetPfnForProcess(Process
, Address
);
1941 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1944 * Check the reference count to ensure this page can be paged out
1946 if (MmGetReferenceCountPage(Page
) != 1)
1948 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1949 Page
, MmGetReferenceCountPage(Page
));
1950 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1951 MmUnlockSectionSegment(Context
.Segment
);
1952 return STATUS_UNSUCCESSFUL
;
1956 * Prepare the context structure for the rmap delete call.
1958 MmUnlockSectionSegment(Context
.Segment
);
1959 Context
.WasDirty
= FALSE
;
1960 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1961 IS_SWAP_FROM_SSE(Entry
) ||
1962 PFN_FROM_SSE(Entry
) != Page
)
1964 Context
.Private
= TRUE
;
1968 Context
.Private
= FALSE
;
1972 * Take an additional reference to the page or the cache segment.
1974 if (DirectMapped
&& !Context
.Private
)
1976 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
1978 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1979 KeBugCheck(MEMORY_MANAGEMENT
);
1984 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1985 MmReferencePage(Page
);
1986 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1989 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1991 /* Since we passed in a surrogate, we'll get back the page entry
1992 * state in our context. This is intended to make intermediate
1993 * decrements of share count not release the wait entry.
1995 Entry
= Context
.SectionEntry
;
1998 * If this wasn't a private page then we should have reduced the entry to
1999 * zero by deleting all the rmaps.
2001 if (!Context
.Private
&& Entry
!= 0)
2003 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2004 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2006 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2011 * If the page wasn't dirty then we can just free it as for a readonly page.
2012 * Since we unmapped all the mappings above we know it will not suddenly
2014 * If the page is from a pagefile section and has no swap entry,
2015 * we can't free the page at this point.
2017 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2018 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2020 if (Context
.Private
)
2022 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2023 Context
.WasDirty
? "dirty" : "clean", Address
);
2024 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2026 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2028 MmSetSavedSwapEntryPage(Page
, 0);
2029 MmLockSectionSegment(Context
.Segment
);
2030 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2031 MmUnlockSectionSegment(Context
.Segment
);
2032 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2033 MiSetPageEvent(NULL
, NULL
);
2034 return(STATUS_SUCCESS
);
2037 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2039 if (Context
.Private
)
2041 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2042 Context
.WasDirty
? "dirty" : "clean", Address
);
2043 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2045 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2047 MmSetSavedSwapEntryPage(Page
, 0);
2050 MmLockSectionSegment(Context
.Segment
);
2051 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2052 MmUnlockSectionSegment(Context
.Segment
);
2054 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2055 MiSetPageEvent(NULL
, NULL
);
2056 return(STATUS_SUCCESS
);
2059 else if (!Context
.Private
&& DirectMapped
)
2063 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2065 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2068 Status
= CcRosUnmapCacheSegment(Bcb
, (ULONG
)FileOffset
, FALSE
);
2070 Status
= STATUS_SUCCESS
;
2073 if (!NT_SUCCESS(Status
))
2075 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2076 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Bcb
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2079 MiSetPageEvent(NULL
, NULL
);
2080 return(STATUS_SUCCESS
);
2082 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2086 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2088 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2090 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2091 MiSetPageEvent(NULL
, NULL
);
2092 return(STATUS_SUCCESS
);
2094 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2096 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2097 MmSetSavedSwapEntryPage(Page
, 0);
2098 MmLockAddressSpace(AddressSpace
);
2099 Status
= MmCreatePageFileMapping(Process
,
2102 MmUnlockAddressSpace(AddressSpace
);
2103 if (!NT_SUCCESS(Status
))
2105 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2106 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2108 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2109 MiSetPageEvent(NULL
, NULL
);
2110 return(STATUS_SUCCESS
);
2114 * If necessary, allocate an entry in the paging file for this page
2118 SwapEntry
= MmAllocSwapPage();
2121 MmShowOutOfSpaceMessagePagingFile();
2122 MmLockAddressSpace(AddressSpace
);
2124 * For private pages restore the old mappings.
2126 if (Context
.Private
)
2128 Status
= MmCreateVirtualMapping(Process
,
2130 MemoryArea
->Protect
,
2133 MmSetDirtyPage(Process
, Address
);
2142 * For non-private pages if the page wasn't direct mapped then
2143 * set it back into the section segment entry so we don't loose
2144 * our copy. Otherwise it will be handled by the cache manager.
2146 Status
= MmCreateVirtualMapping(Process
,
2148 MemoryArea
->Protect
,
2151 MmSetDirtyPage(Process
, Address
);
2155 // If we got here, the previous entry should have been a wait
2156 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2157 MmLockSectionSegment(Context
.Segment
);
2158 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2159 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2160 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2161 MmUnlockSectionSegment(Context
.Segment
);
2163 MmUnlockAddressSpace(AddressSpace
);
2164 MiSetPageEvent(NULL
, NULL
);
2165 return(STATUS_PAGEFILE_QUOTA
);
2170 * Write the page to the pagefile
2172 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2173 if (!NT_SUCCESS(Status
))
2175 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2178 * As above: undo our actions.
2179 * FIXME: Also free the swap page.
2181 MmLockAddressSpace(AddressSpace
);
2182 if (Context
.Private
)
2184 Status
= MmCreateVirtualMapping(Process
,
2186 MemoryArea
->Protect
,
2189 MmSetDirtyPage(Process
, Address
);
2196 Status
= MmCreateVirtualMapping(Process
,
2198 MemoryArea
->Protect
,
2201 MmSetDirtyPage(Process
, Address
);
2205 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2206 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2208 MmUnlockAddressSpace(AddressSpace
);
2209 MiSetPageEvent(NULL
, NULL
);
2210 return(STATUS_UNSUCCESSFUL
);
2214 * Otherwise we have succeeded.
2216 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2217 MmSetSavedSwapEntryPage(Page
, 0);
2218 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2219 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2221 MmLockSectionSegment(Context
.Segment
);
2222 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2223 MmUnlockSectionSegment(Context
.Segment
);
2227 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2230 if (Context
.Private
)
2232 MmLockAddressSpace(AddressSpace
);
2233 MmLockSectionSegment(Context
.Segment
);
2234 Status
= MmCreatePageFileMapping(Process
,
2237 /* We had placed a wait entry upon entry ... replace it before leaving */
2238 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2239 MmUnlockSectionSegment(Context
.Segment
);
2240 MmUnlockAddressSpace(AddressSpace
);
2241 if (!NT_SUCCESS(Status
))
2243 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2244 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2249 MmLockAddressSpace(AddressSpace
);
2250 MmLockSectionSegment(Context
.Segment
);
2251 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2252 /* We had placed a wait entry upon entry ... replace it before leaving */
2253 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2254 MmUnlockSectionSegment(Context
.Segment
);
2255 MmUnlockAddressSpace(AddressSpace
);
2258 MiSetPageEvent(NULL
, NULL
);
2259 return(STATUS_SUCCESS
);
2264 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2265 PMEMORY_AREA MemoryArea
,
2269 LARGE_INTEGER Offset
;
2270 PROS_SECTION_OBJECT Section
;
2271 PMM_SECTION_SEGMENT Segment
;
2273 SWAPENTRY SwapEntry
;
2277 PFILE_OBJECT FileObject
;
2279 BOOLEAN DirectMapped
;
2280 BOOLEAN IsImageSection
;
2281 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2283 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2285 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2286 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2289 * Get the segment and section.
2291 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2292 Section
= MemoryArea
->Data
.SectionData
.Section
;
2293 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2295 FileObject
= Section
->FileObject
;
2296 DirectMapped
= FALSE
;
2297 if (FileObject
!= NULL
&&
2298 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2300 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2303 * If the file system is letting us go directly to the cache and the
2304 * memory area was mapped at an offset in the file which is page aligned
2305 * then note this is a direct mapped page.
2307 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2308 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2310 DirectMapped
= TRUE
;
2315 * This should never happen since mappings of physical memory are never
2316 * placed in the rmap lists.
2318 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2320 DPRINT1("Trying to write back page from physical memory mapped at %p "
2321 "process %p\n", Address
,
2322 Process
? Process
->UniqueProcessId
: 0);
2323 KeBugCheck(MEMORY_MANAGEMENT
);
2327 * Get the section segment entry and the physical address.
2329 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2330 if (!MmIsPagePresent(Process
, Address
))
2332 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2333 Process
? Process
->UniqueProcessId
: 0, Address
);
2334 KeBugCheck(MEMORY_MANAGEMENT
);
2336 Page
= MmGetPfnForProcess(Process
, Address
);
2337 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2340 * Check for a private (COWed) page.
2342 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2343 IS_SWAP_FROM_SSE(Entry
) ||
2344 PFN_FROM_SSE(Entry
) != Page
)
2354 * Speculatively set all mappings of the page to clean.
2356 MmSetCleanAllRmaps(Page
);
2359 * If this page was direct mapped from the cache then the cache manager
2360 * will take care of writing it back to disk.
2362 if (DirectMapped
&& !Private
)
2364 //LARGE_INTEGER SOffset;
2365 ASSERT(SwapEntry
== 0);
2366 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2368 CcRosMarkDirtyCacheSegment(Bcb
, Offset
.LowPart
);
2370 MmLockSectionSegment(Segment
);
2371 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2372 MmUnlockSectionSegment(Segment
);
2373 MiSetPageEvent(NULL
, NULL
);
2374 return(STATUS_SUCCESS
);
2378 * If necessary, allocate an entry in the paging file for this page
2382 SwapEntry
= MmAllocSwapPage();
2385 MmSetDirtyAllRmaps(Page
);
2386 MiSetPageEvent(NULL
, NULL
);
2387 return(STATUS_PAGEFILE_QUOTA
);
2389 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2393 * Write the page to the pagefile
2395 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2396 if (!NT_SUCCESS(Status
))
2398 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2400 MmSetDirtyAllRmaps(Page
);
2401 MiSetPageEvent(NULL
, NULL
);
2402 return(STATUS_UNSUCCESSFUL
);
2406 * Otherwise we have succeeded.
2408 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2409 MiSetPageEvent(NULL
, NULL
);
2410 return(STATUS_SUCCESS
);
2414 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2422 PMEMORY_AREA MemoryArea
;
2423 PMM_SECTION_SEGMENT Segment
;
2424 BOOLEAN DoCOW
= FALSE
;
2426 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2428 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2429 ASSERT(MemoryArea
!= NULL
);
2430 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2431 MmLockSectionSegment(Segment
);
2433 if ((Segment
->WriteCopy
) &&
2434 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2439 if (OldProtect
!= NewProtect
)
2441 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2443 SWAPENTRY SwapEntry
;
2444 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2445 ULONG Protect
= NewProtect
;
2447 /* Wait for a wait entry to disappear */
2449 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2450 if (SwapEntry
!= MM_WAIT_ENTRY
)
2452 MiWaitForPageEvent(Process
, Address
);
2456 * If we doing COW for this segment then check if the page is
2459 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2461 LARGE_INTEGER Offset
;
2465 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2466 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2467 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2469 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2470 * IS_SWAP_FROM_SSE and we'll do the right thing.
2472 Page
= MmGetPfnForProcess(Process
, Address
);
2474 Protect
= PAGE_READONLY
;
2475 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2476 IS_SWAP_FROM_SSE(Entry
) ||
2477 PFN_FROM_SSE(Entry
) != Page
)
2479 Protect
= NewProtect
;
2483 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2485 MmSetPageProtect(Process
, Address
,
2491 MmUnlockSectionSegment(Segment
);
2496 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2497 PMEMORY_AREA MemoryArea
,
2505 ULONG_PTR MaxLength
;
2507 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2508 if (Length
> MaxLength
)
2509 Length
= (ULONG
)MaxLength
;
2511 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2512 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2514 ASSERT(Region
!= NULL
);
2516 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2517 Region
->Protect
!= Protect
)
2519 return STATUS_INVALID_PAGE_PROTECTION
;
2522 *OldProtect
= Region
->Protect
;
2523 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2524 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2525 BaseAddress
, Length
, Region
->Type
, Protect
,
2526 MmAlterViewAttributes
);
2532 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2534 PMEMORY_BASIC_INFORMATION Info
,
2535 PSIZE_T ResultLength
)
2538 PVOID RegionBaseAddress
;
2539 PROS_SECTION_OBJECT Section
;
2540 PMM_SECTION_SEGMENT Segment
;
2542 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2543 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2544 Address
, &RegionBaseAddress
);
2547 return STATUS_UNSUCCESSFUL
;
2550 Section
= MemoryArea
->Data
.SectionData
.Section
;
2551 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2553 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2554 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2555 Info
->Type
= MEM_IMAGE
;
2559 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2560 Info
->Type
= MEM_MAPPED
;
2562 Info
->BaseAddress
= RegionBaseAddress
;
2563 Info
->AllocationProtect
= MemoryArea
->Protect
;
2564 Info
->RegionSize
= Region
->Length
;
2565 Info
->State
= MEM_COMMIT
;
2566 Info
->Protect
= Region
->Protect
;
2568 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2569 return(STATUS_SUCCESS
);
2574 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2577 LARGE_INTEGER Offset
;
2579 SWAPENTRY SavedSwapEntry
;
2584 MmLockSectionSegment(Segment
);
2586 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2587 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2589 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2592 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2593 if (IS_SWAP_FROM_SSE(Entry
))
2595 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2599 Page
= PFN_FROM_SSE(Entry
);
2600 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2601 if (SavedSwapEntry
!= 0)
2603 MmSetSavedSwapEntryPage(Page
, 0);
2604 MmFreeSwapPage(SavedSwapEntry
);
2606 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2611 MmUnlockSectionSegment(Segment
);
2615 MmpDeleteSection(PVOID ObjectBody
)
2617 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2619 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2620 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2625 PMM_SECTION_SEGMENT SectionSegments
;
2628 * NOTE: Section->ImageSection can be NULL for short time
2629 * during the section creating. If we fail for some reason
2630 * until the image section is properly initialized we shouldn't
2631 * process further here.
2633 if (Section
->ImageSection
== NULL
)
2636 SectionSegments
= Section
->ImageSection
->Segments
;
2637 NrSegments
= Section
->ImageSection
->NrSegments
;
2639 for (i
= 0; i
< NrSegments
; i
++)
2641 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2643 MmLockSectionSegment(&SectionSegments
[i
]);
2645 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2646 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2648 MmUnlockSectionSegment(&SectionSegments
[i
]);
2651 MmpFreePageFileSegment(&SectionSegments
[i
]);
2657 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2660 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2663 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2665 DPRINT("Freeing section segment\n");
2666 Section
->Segment
= NULL
;
2667 MmFinalizeSegment(Segment
);
2671 DPRINT("RefCount %d\n", RefCount
);
2678 * NOTE: Section->Segment can be NULL for short time
2679 * during the section creating.
2681 if (Section
->Segment
== NULL
)
2684 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2686 MmpFreePageFileSegment(Section
->Segment
);
2687 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2688 ExFreePool(Section
->Segment
);
2689 Section
->Segment
= NULL
;
2693 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2696 if (Section
->FileObject
!= NULL
)
2699 CcRosDereferenceCache(Section
->FileObject
);
2701 ObDereferenceObject(Section
->FileObject
);
2702 Section
->FileObject
= NULL
;
2707 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2709 IN ACCESS_MASK GrantedAccess
,
2710 IN ULONG ProcessHandleCount
,
2711 IN ULONG SystemHandleCount
)
2713 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2719 MmCreatePhysicalMemorySection(VOID
)
2721 PROS_SECTION_OBJECT PhysSection
;
2723 OBJECT_ATTRIBUTES Obj
;
2724 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2725 LARGE_INTEGER SectionSize
;
2729 * Create the section mapping physical memory
2731 SectionSize
.QuadPart
= 0xFFFFFFFF;
2732 InitializeObjectAttributes(&Obj
,
2737 Status
= MmCreateSection((PVOID
)&PhysSection
,
2741 PAGE_EXECUTE_READWRITE
,
2745 if (!NT_SUCCESS(Status
))
2747 DPRINT1("Failed to create PhysicalMemory section\n");
2748 KeBugCheck(MEMORY_MANAGEMENT
);
2750 Status
= ObInsertObject(PhysSection
,
2756 if (!NT_SUCCESS(Status
))
2758 ObDereferenceObject(PhysSection
);
2760 ObCloseHandle(Handle
, KernelMode
);
2761 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2762 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2764 return(STATUS_SUCCESS
);
2770 MmInitSectionImplementation(VOID
)
2772 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2773 UNICODE_STRING Name
;
2775 DPRINT("Creating Section Object Type\n");
2777 /* Initialize the section based root */
2778 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2779 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2781 /* Initialize the Section object type */
2782 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2783 RtlInitUnicodeString(&Name
, L
"Section");
2784 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2785 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2786 ObjectTypeInitializer
.PoolType
= PagedPool
;
2787 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2788 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2789 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2790 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2791 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2792 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2793 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2795 MmCreatePhysicalMemorySection();
2797 return(STATUS_SUCCESS
);
2802 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2803 ACCESS_MASK DesiredAccess
,
2804 POBJECT_ATTRIBUTES ObjectAttributes
,
2805 PLARGE_INTEGER UMaximumSize
,
2806 ULONG SectionPageProtection
,
2807 ULONG AllocationAttributes
)
2809 * Create a section which is backed by the pagefile
2812 LARGE_INTEGER MaximumSize
;
2813 PROS_SECTION_OBJECT Section
;
2814 PMM_SECTION_SEGMENT Segment
;
2817 if (UMaximumSize
== NULL
)
2819 return(STATUS_UNSUCCESSFUL
);
2821 MaximumSize
= *UMaximumSize
;
2824 * Create the section
2826 Status
= ObCreateObject(ExGetPreviousMode(),
2827 MmSectionObjectType
,
2829 ExGetPreviousMode(),
2831 sizeof(ROS_SECTION_OBJECT
),
2834 (PVOID
*)(PVOID
)&Section
);
2835 if (!NT_SUCCESS(Status
))
2843 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2844 Section
->Type
= 'SC';
2845 Section
->Size
= 'TN';
2846 Section
->SectionPageProtection
= SectionPageProtection
;
2847 Section
->AllocationAttributes
= AllocationAttributes
;
2848 Section
->MaximumSize
= MaximumSize
;
2849 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2850 TAG_MM_SECTION_SEGMENT
);
2851 if (Segment
== NULL
)
2853 ObDereferenceObject(Section
);
2854 return(STATUS_NO_MEMORY
);
2856 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2857 Section
->Segment
= Segment
;
2858 Segment
->ReferenceCount
= 1;
2859 ExInitializeFastMutex(&Segment
->Lock
);
2860 Segment
->Image
.FileOffset
= 0;
2861 Segment
->Protection
= SectionPageProtection
;
2862 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2863 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2864 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2865 Segment
->WriteCopy
= FALSE
;
2866 Segment
->Image
.VirtualAddress
= 0;
2867 Segment
->Image
.Characteristics
= 0;
2868 *SectionObject
= Section
;
2869 MiInitializeSectionPageTable(Segment
);
2870 return(STATUS_SUCCESS
);
2875 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2876 ACCESS_MASK DesiredAccess
,
2877 POBJECT_ATTRIBUTES ObjectAttributes
,
2878 PLARGE_INTEGER UMaximumSize
,
2879 ULONG SectionPageProtection
,
2880 ULONG AllocationAttributes
,
2883 * Create a section backed by a data file
2886 PROS_SECTION_OBJECT Section
;
2888 LARGE_INTEGER MaximumSize
;
2889 PFILE_OBJECT FileObject
;
2890 PMM_SECTION_SEGMENT Segment
;
2892 IO_STATUS_BLOCK Iosb
;
2893 LARGE_INTEGER Offset
;
2895 FILE_STANDARD_INFORMATION FileInfo
;
2899 * Create the section
2901 Status
= ObCreateObject(ExGetPreviousMode(),
2902 MmSectionObjectType
,
2904 ExGetPreviousMode(),
2906 sizeof(ROS_SECTION_OBJECT
),
2910 if (!NT_SUCCESS(Status
))
2917 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2918 Section
->Type
= 'SC';
2919 Section
->Size
= 'TN';
2920 Section
->SectionPageProtection
= SectionPageProtection
;
2921 Section
->AllocationAttributes
= AllocationAttributes
;
2924 * Reference the file handle
2926 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2927 Status
= ObReferenceObjectByHandle(FileHandle
,
2930 ExGetPreviousMode(),
2931 (PVOID
*)(PVOID
)&FileObject
,
2933 if (!NT_SUCCESS(Status
))
2935 ObDereferenceObject(Section
);
2940 * FIXME: This is propably not entirely correct. We can't look into
2941 * the standard FCB header because it might not be initialized yet
2942 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2943 * standard file information is filled on first request).
2945 Status
= IoQueryFileInformation(FileObject
,
2946 FileStandardInformation
,
2947 sizeof(FILE_STANDARD_INFORMATION
),
2950 Iosb
.Information
= Length
;
2951 if (!NT_SUCCESS(Status
))
2953 ObDereferenceObject(Section
);
2954 ObDereferenceObject(FileObject
);
2959 * FIXME: Revise this once a locking order for file size changes is
2962 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2964 MaximumSize
= *UMaximumSize
;
2968 MaximumSize
= FileInfo
.EndOfFile
;
2969 /* Mapping zero-sized files isn't allowed. */
2970 if (MaximumSize
.QuadPart
== 0)
2972 ObDereferenceObject(Section
);
2973 ObDereferenceObject(FileObject
);
2974 return STATUS_FILE_INVALID
;
2978 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2980 Status
= IoSetInformation(FileObject
,
2981 FileAllocationInformation
,
2982 sizeof(LARGE_INTEGER
),
2984 if (!NT_SUCCESS(Status
))
2986 ObDereferenceObject(Section
);
2987 ObDereferenceObject(FileObject
);
2988 return(STATUS_SECTION_NOT_EXTENDED
);
2992 if (FileObject
->SectionObjectPointer
== NULL
||
2993 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2996 * Read a bit so caching is initiated for the file object.
2997 * This is only needed because MiReadPage currently cannot
2998 * handle non-cached streams.
3000 Offset
.QuadPart
= 0;
3001 Status
= ZwReadFile(FileHandle
,
3010 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3012 ObDereferenceObject(Section
);
3013 ObDereferenceObject(FileObject
);
3016 if (FileObject
->SectionObjectPointer
== NULL
||
3017 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3019 /* FIXME: handle this situation */
3020 ObDereferenceObject(Section
);
3021 ObDereferenceObject(FileObject
);
3022 return STATUS_INVALID_PARAMETER
;
3029 Status
= MmspWaitForFileLock(FileObject
);
3030 if (Status
!= STATUS_SUCCESS
)
3032 ObDereferenceObject(Section
);
3033 ObDereferenceObject(FileObject
);
3038 * If this file hasn't been mapped as a data file before then allocate a
3039 * section segment to describe the data file mapping
3041 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3043 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3044 TAG_MM_SECTION_SEGMENT
);
3045 if (Segment
== NULL
)
3047 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3048 ObDereferenceObject(Section
);
3049 ObDereferenceObject(FileObject
);
3050 return(STATUS_NO_MEMORY
);
3052 Section
->Segment
= Segment
;
3053 Segment
->ReferenceCount
= 1;
3054 ExInitializeFastMutex(&Segment
->Lock
);
3056 * Set the lock before assigning the segment to the file object
3058 ExAcquireFastMutex(&Segment
->Lock
);
3059 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3061 Segment
->Image
.FileOffset
= 0;
3062 Segment
->Protection
= SectionPageProtection
;
3063 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3064 Segment
->Image
.Characteristics
= 0;
3065 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3066 if (AllocationAttributes
& SEC_RESERVE
)
3068 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3072 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3073 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3075 Segment
->Image
.VirtualAddress
= 0;
3076 Segment
->Locked
= TRUE
;
3077 MiInitializeSectionPageTable(Segment
);
3082 * If the file is already mapped as a data file then we may need
3086 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3088 Section
->Segment
= Segment
;
3089 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3090 MmLockSectionSegment(Segment
);
3092 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3093 !(AllocationAttributes
& SEC_RESERVE
))
3095 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3096 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3099 MmUnlockSectionSegment(Segment
);
3100 Section
->FileObject
= FileObject
;
3101 Section
->MaximumSize
= MaximumSize
;
3103 CcRosReferenceCache(FileObject
);
3105 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3106 *SectionObject
= Section
;
3107 return(STATUS_SUCCESS
);
3111 TODO: not that great (declaring loaders statically, having to declare all of
3112 them, having to keep them extern, etc.), will fix in the future
3114 extern NTSTATUS NTAPI PeFmtCreateSection
3116 IN CONST VOID
* FileHeader
,
3117 IN SIZE_T FileHeaderSize
,
3119 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3121 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3122 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3125 extern NTSTATUS NTAPI ElfFmtCreateSection
3127 IN CONST VOID
* FileHeader
,
3128 IN SIZE_T FileHeaderSize
,
3130 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3132 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3133 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3136 /* TODO: this is a standard DDK/PSDK macro */
3137 #ifndef RTL_NUMBER_OF
3138 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3141 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3152 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3154 SIZE_T SizeOfSegments
;
3155 PMM_SECTION_SEGMENT Segments
;
3157 /* TODO: check for integer overflow */
3158 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3160 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3162 TAG_MM_SECTION_SEGMENT
);
3165 RtlZeroMemory(Segments
, SizeOfSegments
);
3173 ExeFmtpReadFile(IN PVOID File
,
3174 IN PLARGE_INTEGER Offset
,
3177 OUT PVOID
* AllocBase
,
3178 OUT PULONG ReadSize
)
3181 LARGE_INTEGER FileOffset
;
3183 ULONG OffsetAdjustment
;
3187 PFILE_OBJECT FileObject
= File
;
3188 IO_STATUS_BLOCK Iosb
;
3190 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3194 KeBugCheck(MEMORY_MANAGEMENT
);
3197 FileOffset
= *Offset
;
3199 /* Negative/special offset: it cannot be used in this context */
3200 if(FileOffset
.u
.HighPart
< 0)
3202 KeBugCheck(MEMORY_MANAGEMENT
);
3205 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3206 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3207 FileOffset
.u
.LowPart
= AdjustOffset
;
3209 BufferSize
= Length
+ OffsetAdjustment
;
3210 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3213 * It's ok to use paged pool, because this is a temporary buffer only used in
3214 * the loading of executables. The assumption is that MmCreateSection is
3215 * always called at low IRQLs and that these buffers don't survive a brief
3216 * initialization phase
3218 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3223 KeBugCheck(MEMORY_MANAGEMENT
);
3228 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3230 UsedSize
= (ULONG
)Iosb
.Information
;
3232 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3234 Status
= STATUS_IN_PAGE_ERROR
;
3235 ASSERT(!NT_SUCCESS(Status
));
3238 if(NT_SUCCESS(Status
))
3240 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3241 *AllocBase
= Buffer
;
3242 *ReadSize
= UsedSize
- OffsetAdjustment
;
3246 ExFreePoolWithTag(Buffer
, 'rXmM');
3253 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3254 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3255 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3260 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3264 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3266 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3267 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3274 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3278 MmspAssertSegmentsSorted(ImageSectionObject
);
3280 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3282 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3286 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3287 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3288 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3296 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3300 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3302 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3303 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3311 MmspCompareSegments(const void * x
,
3314 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3315 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3318 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3319 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3323 * Ensures an image section's segments are sorted in memory
3328 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3331 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3333 MmspAssertSegmentsSorted(ImageSectionObject
);
3337 qsort(ImageSectionObject
->Segments
,
3338 ImageSectionObject
->NrSegments
,
3339 sizeof(ImageSectionObject
->Segments
[0]),
3340 MmspCompareSegments
);
3346 * Ensures an image section's segments don't overlap in memory and don't have
3347 * gaps and don't have a null size. We let them map to overlapping file regions,
3348 * though - that's not necessarily an error
3353 MmspCheckSegmentBounds
3355 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3361 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3363 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3367 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3369 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3371 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3379 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3380 * page could be OK (Windows seems to be OK with them), and larger gaps
3381 * could lead to image sections spanning several discontiguous regions
3382 * (NtMapViewOfSection could then refuse to map them, and they could
3383 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3385 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3386 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3387 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3398 * Merges and pads an image section's segments until they all are page-aligned
3399 * and have a size that is a multiple of the page size
3404 MmspPageAlignSegments
3406 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3412 PMM_SECTION_SEGMENT EffectiveSegment
;
3414 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3416 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3421 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3423 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3426 * The first segment requires special handling
3430 ULONG_PTR VirtualAddress
;
3431 ULONG_PTR VirtualOffset
;
3433 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3435 /* Round down the virtual address to the nearest page */
3436 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3438 /* Round up the virtual size to the nearest page */
3439 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3440 EffectiveSegment
->Image
.VirtualAddress
;
3442 /* Adjust the raw address and size */
3443 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3445 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3451 * Garbage in, garbage out: unaligned base addresses make the file
3452 * offset point in curious and odd places, but that's what we were
3455 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3456 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3460 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3461 ULONG_PTR EndOfEffectiveSegment
;
3463 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3464 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3467 * The current segment begins exactly where the current effective
3468 * segment ended, therefore beginning a new effective segment
3470 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3473 ASSERT(LastSegment
<= i
);
3474 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3476 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3478 if (LastSegment
!= i
)
3481 * Copy the current segment. If necessary, the effective segment
3482 * will be expanded later
3484 *EffectiveSegment
= *Segment
;
3488 * Page-align the virtual size. We know for sure the virtual address
3491 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3492 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3495 * The current segment is still part of the current effective segment:
3496 * extend the effective segment to reflect this
3498 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3500 static const ULONG FlagsToProtection
[16] =
3508 PAGE_EXECUTE_READWRITE
,
3509 PAGE_EXECUTE_READWRITE
,
3514 PAGE_EXECUTE_WRITECOPY
,
3515 PAGE_EXECUTE_WRITECOPY
,
3516 PAGE_EXECUTE_WRITECOPY
,
3517 PAGE_EXECUTE_WRITECOPY
3520 unsigned ProtectionFlags
;
3523 * Extend the file size
3526 /* Unaligned segments must be contiguous within the file */
3527 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3528 EffectiveSegment
->RawLength
.QuadPart
))
3533 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3536 * Extend the virtual size
3538 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3540 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3541 EffectiveSegment
->Image
.VirtualAddress
;
3544 * Merge the protection
3546 EffectiveSegment
->Protection
|= Segment
->Protection
;
3548 /* Clean up redundance */
3549 ProtectionFlags
= 0;
3551 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3552 ProtectionFlags
|= 1 << 0;
3554 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3555 ProtectionFlags
|= 1 << 1;
3557 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3558 ProtectionFlags
|= 1 << 2;
3560 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3561 ProtectionFlags
|= 1 << 3;
3563 ASSERT(ProtectionFlags
< 16);
3564 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3566 /* If a segment was required to be shared and cannot, fail */
3567 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3568 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3574 * We assume no holes between segments at this point
3578 KeBugCheck(MEMORY_MANAGEMENT
);
3582 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3588 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3589 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3591 LARGE_INTEGER Offset
;
3593 PVOID FileHeaderBuffer
;
3594 ULONG FileHeaderSize
;
3596 ULONG OldNrSegments
;
3601 * Read the beginning of the file (2 pages). Should be enough to contain
3602 * all (or most) of the headers
3604 Offset
.QuadPart
= 0;
3606 /* FIXME: use FileObject instead of FileHandle */
3607 Status
= ExeFmtpReadFile (FileHandle
,
3614 if (!NT_SUCCESS(Status
))
3617 if (FileHeaderSize
== 0)
3619 ExFreePool(FileHeaderBuffer
);
3620 return STATUS_UNSUCCESSFUL
;
3624 * Look for a loader that can handle this executable
3626 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3628 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3631 /* FIXME: use FileObject instead of FileHandle */
3632 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3638 ExeFmtpAllocateSegments
);
3640 if (!NT_SUCCESS(Status
))
3642 if (ImageSectionObject
->Segments
)
3644 ExFreePool(ImageSectionObject
->Segments
);
3645 ImageSectionObject
->Segments
= NULL
;
3649 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3653 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3656 * No loader handled the format
3658 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3660 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3661 ASSERT(!NT_SUCCESS(Status
));
3664 if (!NT_SUCCESS(Status
))
3667 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3672 /* FIXME? are these values platform-dependent? */
3673 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3674 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3676 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3677 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3679 if(ImageSectionObject
->BasedAddress
== NULL
)
3681 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3682 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3684 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3688 * And now the fun part: fixing the segments
3691 /* Sort them by virtual address */
3692 MmspSortSegments(ImageSectionObject
, Flags
);
3694 /* Ensure they don't overlap in memory */
3695 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3696 return STATUS_INVALID_IMAGE_FORMAT
;
3698 /* Ensure they are aligned */
3699 OldNrSegments
= ImageSectionObject
->NrSegments
;
3701 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3702 return STATUS_INVALID_IMAGE_FORMAT
;
3704 /* Trim them if the alignment phase merged some of them */
3705 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3707 PMM_SECTION_SEGMENT Segments
;
3708 SIZE_T SizeOfSegments
;
3710 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3712 Segments
= ExAllocatePoolWithTag(PagedPool
,
3714 TAG_MM_SECTION_SEGMENT
);
3716 if (Segments
== NULL
)
3717 return STATUS_INSUFFICIENT_RESOURCES
;
3719 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3720 ExFreePool(ImageSectionObject
->Segments
);
3721 ImageSectionObject
->Segments
= Segments
;
3724 /* And finish their initialization */
3725 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3727 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3728 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3729 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3732 ASSERT(NT_SUCCESS(Status
));
3737 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3738 ACCESS_MASK DesiredAccess
,
3739 POBJECT_ATTRIBUTES ObjectAttributes
,
3740 PLARGE_INTEGER UMaximumSize
,
3741 ULONG SectionPageProtection
,
3742 ULONG AllocationAttributes
,
3743 PFILE_OBJECT FileObject
)
3745 PROS_SECTION_OBJECT Section
;
3747 PMM_SECTION_SEGMENT SectionSegments
;
3748 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3751 if (FileObject
== NULL
)
3752 return STATUS_INVALID_FILE_FOR_SECTION
;
3755 * Create the section
3757 Status
= ObCreateObject (ExGetPreviousMode(),
3758 MmSectionObjectType
,
3760 ExGetPreviousMode(),
3762 sizeof(ROS_SECTION_OBJECT
),
3765 (PVOID
*)(PVOID
)&Section
);
3766 if (!NT_SUCCESS(Status
))
3768 ObDereferenceObject(FileObject
);
3775 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3776 Section
->Type
= 'SC';
3777 Section
->Size
= 'TN';
3778 Section
->SectionPageProtection
= SectionPageProtection
;
3779 Section
->AllocationAttributes
= AllocationAttributes
;
3783 * Initialized caching for this file object if previously caching
3784 * was initialized for the same on disk file
3786 Status
= CcTryToInitializeFileCache(FileObject
);
3788 Status
= STATUS_SUCCESS
;
3791 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3793 NTSTATUS StatusExeFmt
;
3795 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3796 if (ImageSectionObject
== NULL
)
3798 ObDereferenceObject(FileObject
);
3799 ObDereferenceObject(Section
);
3800 return(STATUS_NO_MEMORY
);
3803 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3805 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3807 if (!NT_SUCCESS(StatusExeFmt
))
3809 if(ImageSectionObject
->Segments
!= NULL
)
3810 ExFreePool(ImageSectionObject
->Segments
);
3812 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3813 ObDereferenceObject(Section
);
3814 ObDereferenceObject(FileObject
);
3815 return(StatusExeFmt
);
3818 Section
->ImageSection
= ImageSectionObject
;
3819 ASSERT(ImageSectionObject
->Segments
);
3824 Status
= MmspWaitForFileLock(FileObject
);
3825 if (!NT_SUCCESS(Status
))
3827 ExFreePool(ImageSectionObject
->Segments
);
3828 ExFreePool(ImageSectionObject
);
3829 ObDereferenceObject(Section
);
3830 ObDereferenceObject(FileObject
);
3834 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3835 ImageSectionObject
, NULL
))
3838 * An other thread has initialized the same image in the background
3840 ExFreePool(ImageSectionObject
->Segments
);
3841 ExFreePool(ImageSectionObject
);
3842 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3843 Section
->ImageSection
= ImageSectionObject
;
3844 SectionSegments
= ImageSectionObject
->Segments
;
3846 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3848 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3852 Status
= StatusExeFmt
;
3859 Status
= MmspWaitForFileLock(FileObject
);
3860 if (Status
!= STATUS_SUCCESS
)
3862 ObDereferenceObject(Section
);
3863 ObDereferenceObject(FileObject
);
3867 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3868 Section
->ImageSection
= ImageSectionObject
;
3869 SectionSegments
= ImageSectionObject
->Segments
;
3872 * Otherwise just reference all the section segments
3874 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3876 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3879 Status
= STATUS_SUCCESS
;
3881 Section
->FileObject
= FileObject
;
3883 CcRosReferenceCache(FileObject
);
3885 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3886 *SectionObject
= Section
;
3893 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3894 PROS_SECTION_OBJECT Section
,
3895 PMM_SECTION_SEGMENT Segment
,
3900 ULONG AllocationType
)
3904 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3906 if (Segment
->WriteCopy
)
3908 /* We have to do this because the not present fault
3909 * and access fault handlers depend on the protection
3910 * that should be granted AFTER the COW fault takes
3911 * place to be in Region->Protect. The not present fault
3912 * handler changes this to the correct protection for COW when
3913 * mapping the pages into the process's address space. If a COW
3914 * fault takes place, the access fault handler sets the page protection
3915 * to these values for the newly copied pages
3917 if (Protect
== PAGE_WRITECOPY
)
3918 Protect
= PAGE_READWRITE
;
3919 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3920 Protect
= PAGE_EXECUTE_READWRITE
;
3923 BoundaryAddressMultiple
.QuadPart
= 0;
3926 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
3927 LARGE_INTEGER FileOffset
;
3928 FileOffset
.QuadPart
= ViewOffset
;
3929 ObReferenceObject(Section
);
3930 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3933 Status
= MmCreateMemoryArea(AddressSpace
,
3934 MEMORY_AREA_SECTION_VIEW
,
3941 BoundaryAddressMultiple
);
3942 if (!NT_SUCCESS(Status
))
3944 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3945 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3949 ObReferenceObject((PVOID
)Section
);
3951 MArea
->Data
.SectionData
.Segment
= Segment
;
3952 MArea
->Data
.SectionData
.Section
= Section
;
3953 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3954 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3955 ViewSize
, 0, Protect
);
3957 return(STATUS_SUCCESS
);
3962 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3963 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3966 PFILE_OBJECT FileObject
;
3968 LARGE_INTEGER Offset
;
3969 SWAPENTRY SavedSwapEntry
;
3970 PROS_SECTION_OBJECT Section
;
3971 PMM_SECTION_SEGMENT Segment
;
3972 PMMSUPPORT AddressSpace
;
3975 AddressSpace
= (PMMSUPPORT
)Context
;
3976 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3978 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3980 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3981 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3983 Section
= MemoryArea
->Data
.SectionData
.Section
;
3984 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3986 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3987 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
3989 MmUnlockSectionSegment(Segment
);
3990 MmUnlockAddressSpace(AddressSpace
);
3992 MiWaitForPageEvent(NULL
, NULL
);
3994 MmLockAddressSpace(AddressSpace
);
3995 MmLockSectionSegment(Segment
);
3996 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4000 * For a dirty, datafile, non-private page mark it as dirty in the
4003 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4005 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4007 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4008 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4010 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)(Offset
.QuadPart
+ Segment
->Image
.FileOffset
));
4012 ASSERT(SwapEntry
== 0);
4021 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4023 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4024 KeBugCheck(MEMORY_MANAGEMENT
);
4026 MmFreeSwapPage(SwapEntry
);
4030 if (IS_SWAP_FROM_SSE(Entry
) ||
4031 Page
!= PFN_FROM_SSE(Entry
))
4036 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4038 DPRINT1("Found a private page in a pagefile section.\n");
4039 KeBugCheck(MEMORY_MANAGEMENT
);
4042 * Just dereference private pages
4044 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4045 if (SavedSwapEntry
!= 0)
4047 MmFreeSwapPage(SavedSwapEntry
);
4048 MmSetSavedSwapEntryPage(Page
, 0);
4050 MmDeleteRmap(Page
, Process
, Address
);
4051 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4055 MmDeleteRmap(Page
, Process
, Address
);
4056 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4062 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4066 PMEMORY_AREA MemoryArea
;
4067 PROS_SECTION_OBJECT Section
;
4068 PMM_SECTION_SEGMENT Segment
;
4069 PLIST_ENTRY CurrentEntry
;
4070 PMM_REGION CurrentRegion
;
4071 PLIST_ENTRY RegionListHead
;
4073 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4075 if (MemoryArea
== NULL
)
4077 return(STATUS_UNSUCCESSFUL
);
4080 MemoryArea
->DeleteInProgress
= TRUE
;
4081 Section
= MemoryArea
->Data
.SectionData
.Section
;
4082 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4085 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4086 return MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4089 MmLockSectionSegment(Segment
);
4091 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4092 while (!IsListEmpty(RegionListHead
))
4094 CurrentEntry
= RemoveHeadList(RegionListHead
);
4095 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4096 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4099 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4101 Status
= MmFreeMemoryArea(AddressSpace
,
4108 Status
= MmFreeMemoryArea(AddressSpace
,
4113 MmUnlockSectionSegment(Segment
);
4114 ObDereferenceObject(Section
);
4120 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4121 IN PVOID BaseAddress
,
4125 PMEMORY_AREA MemoryArea
;
4126 PMMSUPPORT AddressSpace
;
4127 PROS_SECTION_OBJECT Section
;
4128 PVOID ImageBaseAddress
= 0;
4130 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4131 Process
, BaseAddress
);
4135 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4137 MmLockAddressSpace(AddressSpace
);
4138 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4140 if (MemoryArea
== NULL
||
4141 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4142 MemoryArea
->DeleteInProgress
)
4144 if (MemoryArea
) NT_ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4145 MmUnlockAddressSpace(AddressSpace
);
4146 return STATUS_NOT_MAPPED_VIEW
;
4149 MemoryArea
->DeleteInProgress
= TRUE
;
4151 Section
= MemoryArea
->Data
.SectionData
.Section
;
4153 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4157 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4158 PMM_SECTION_SEGMENT SectionSegments
;
4159 PMM_SECTION_SEGMENT Segment
;
4161 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4162 ImageSectionObject
= Section
->ImageSection
;
4163 SectionSegments
= ImageSectionObject
->Segments
;
4164 NrSegments
= ImageSectionObject
->NrSegments
;
4166 /* Search for the current segment within the section segments
4167 * and calculate the image base address */
4168 for (i
= 0; i
< NrSegments
; i
++)
4170 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4172 if (Segment
== &SectionSegments
[i
])
4174 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4179 if (i
>= NrSegments
)
4181 KeBugCheck(MEMORY_MANAGEMENT
);
4184 for (i
= 0; i
< NrSegments
; i
++)
4186 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4188 PVOID SBaseAddress
= (PVOID
)
4189 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4191 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4192 NT_ASSERT(NT_SUCCESS(Status
));
4198 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4199 NT_ASSERT(NT_SUCCESS(Status
));
4202 MmUnlockAddressSpace(AddressSpace
);
4204 /* Notify debugger */
4205 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4207 return(STATUS_SUCCESS
);
4214 * Queries the information of a section object.
4216 * @param SectionHandle
4217 * Handle to the section object. It must be opened with SECTION_QUERY
4219 * @param SectionInformationClass
4220 * Index to a certain information structure. Can be either
4221 * SectionBasicInformation or SectionImageInformation. The latter
4222 * is valid only for sections that were created with the SEC_IMAGE
4224 * @param SectionInformation
4225 * Caller supplies storage for resulting information.
4227 * Size of the supplied storage.
4228 * @param ResultLength
4236 NtQuerySection(IN HANDLE SectionHandle
,
4237 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4238 OUT PVOID SectionInformation
,
4239 IN SIZE_T SectionInformationLength
,
4240 OUT PSIZE_T ResultLength OPTIONAL
)
4242 PROS_SECTION_OBJECT Section
;
4243 KPROCESSOR_MODE PreviousMode
;
4247 PreviousMode
= ExGetPreviousMode();
4249 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4251 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4253 (ULONG
)SectionInformationLength
,
4258 if(!NT_SUCCESS(Status
))
4260 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4264 Status
= ObReferenceObjectByHandle(SectionHandle
,
4266 MmSectionObjectType
,
4268 (PVOID
*)(PVOID
)&Section
,
4270 if (NT_SUCCESS(Status
))
4272 switch (SectionInformationClass
)
4274 case SectionBasicInformation
:
4276 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4280 Sbi
->Attributes
= Section
->AllocationAttributes
;
4281 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4283 Sbi
->BaseAddress
= 0;
4284 Sbi
->Size
.QuadPart
= 0;
4288 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4289 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4292 if (ResultLength
!= NULL
)
4294 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4296 Status
= STATUS_SUCCESS
;
4298 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4300 Status
= _SEH2_GetExceptionCode();
4307 case SectionImageInformation
:
4309 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4313 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4315 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4316 ImageSectionObject
= Section
->ImageSection
;
4318 *Sii
= ImageSectionObject
->ImageInformation
;
4321 if (ResultLength
!= NULL
)
4323 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4325 Status
= STATUS_SUCCESS
;
4327 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4329 Status
= _SEH2_GetExceptionCode();
4337 ObDereferenceObject(Section
);
4343 /**********************************************************************
4345 * MmMapViewOfSection
4348 * Maps a view of a section into the virtual address space of a
4353 * Pointer to the section object.
4356 * Pointer to the process.
4359 * Desired base address (or NULL) on entry;
4360 * Actual base address of the view on exit.
4363 * Number of high order address bits that must be zero.
4366 * Size in bytes of the initially committed section of
4370 * Offset in bytes from the beginning of the section
4371 * to the beginning of the view.
4374 * Desired length of map (or zero to map all) on entry
4375 * Actual length mapped on exit.
4377 * InheritDisposition
4378 * Specified how the view is to be shared with
4382 * Type of allocation for the pages.
4385 * Protection for the committed region of the view.
4393 MmMapViewOfSection(IN PVOID SectionObject
,
4394 IN PEPROCESS Process
,
4395 IN OUT PVOID
*BaseAddress
,
4396 IN ULONG_PTR ZeroBits
,
4397 IN SIZE_T CommitSize
,
4398 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4399 IN OUT PSIZE_T ViewSize
,
4400 IN SECTION_INHERIT InheritDisposition
,
4401 IN ULONG AllocationType
,
4404 PROS_SECTION_OBJECT Section
;
4405 PMMSUPPORT AddressSpace
;
4407 NTSTATUS Status
= STATUS_SUCCESS
;
4408 BOOLEAN NotAtBase
= FALSE
;
4410 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4412 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4413 return MmMapViewOfArm3Section(SectionObject
,
4427 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4429 return STATUS_INVALID_PAGE_PROTECTION
;
4433 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4434 AddressSpace
= &Process
->Vm
;
4436 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4438 MmLockAddressSpace(AddressSpace
);
4440 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4444 ULONG_PTR ImageBase
;
4446 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4447 PMM_SECTION_SEGMENT SectionSegments
;
4449 ImageSectionObject
= Section
->ImageSection
;
4450 SectionSegments
= ImageSectionObject
->Segments
;
4451 NrSegments
= ImageSectionObject
->NrSegments
;
4453 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4456 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4460 for (i
= 0; i
< NrSegments
; i
++)
4462 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4464 ULONG_PTR MaxExtent
;
4465 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4466 SectionSegments
[i
].Length
.QuadPart
);
4467 ImageSize
= max(ImageSize
, MaxExtent
);
4471 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4473 /* Check for an illegal base address */
4474 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4476 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4479 /* Check there is enough space to map the section at that point. */
4480 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4481 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4483 /* Fail if the user requested a fixed base address. */
4484 if ((*BaseAddress
) != NULL
)
4486 MmUnlockAddressSpace(AddressSpace
);
4487 return(STATUS_UNSUCCESSFUL
);
4489 /* Otherwise find a gap to map the image. */
4490 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4493 MmUnlockAddressSpace(AddressSpace
);
4494 return(STATUS_UNSUCCESSFUL
);
4496 /* Remember that we loaded image at a different base address */
4500 for (i
= 0; i
< NrSegments
; i
++)
4502 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4504 PVOID SBaseAddress
= (PVOID
)
4505 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4506 MmLockSectionSegment(&SectionSegments
[i
]);
4507 Status
= MmMapViewOfSegment(AddressSpace
,
4509 &SectionSegments
[i
],
4511 SectionSegments
[i
].Length
.LowPart
,
4512 SectionSegments
[i
].Protection
,
4515 MmUnlockSectionSegment(&SectionSegments
[i
]);
4516 if (!NT_SUCCESS(Status
))
4518 MmUnlockAddressSpace(AddressSpace
);
4524 *BaseAddress
= (PVOID
)ImageBase
;
4525 *ViewSize
= ImageSize
;
4529 /* check for write access */
4530 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4531 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4533 MmUnlockAddressSpace(AddressSpace
);
4534 return STATUS_SECTION_PROTECTION
;
4536 /* check for read access */
4537 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4538 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4540 MmUnlockAddressSpace(AddressSpace
);
4541 return STATUS_SECTION_PROTECTION
;
4543 /* check for execute access */
4544 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4545 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4547 MmUnlockAddressSpace(AddressSpace
);
4548 return STATUS_SECTION_PROTECTION
;
4551 if (ViewSize
== NULL
)
4553 /* Following this pointer would lead to us to the dark side */
4554 /* What to do? Bugcheck? Return status? Do the mambo? */
4555 KeBugCheck(MEMORY_MANAGEMENT
);
4558 if (SectionOffset
== NULL
)
4564 ViewOffset
= SectionOffset
->u
.LowPart
;
4567 if ((ViewOffset
% PAGE_SIZE
) != 0)
4569 MmUnlockAddressSpace(AddressSpace
);
4570 return(STATUS_MAPPED_ALIGNMENT
);
4573 if ((*ViewSize
) == 0)
4575 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4577 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4579 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4582 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4584 MmLockSectionSegment(Section
->Segment
);
4585 Status
= MmMapViewOfSegment(AddressSpace
,
4592 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4593 MmUnlockSectionSegment(Section
->Segment
);
4594 if (!NT_SUCCESS(Status
))
4596 MmUnlockAddressSpace(AddressSpace
);
4601 MmUnlockAddressSpace(AddressSpace
);
4604 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4606 Status
= STATUS_SUCCESS
;
4615 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4616 IN PLARGE_INTEGER NewFileSize
)
4618 /* Check whether an ImageSectionObject exists */
4619 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4621 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4625 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4627 PMM_SECTION_SEGMENT Segment
;
4629 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4632 if (Segment
->ReferenceCount
!= 0)
4635 CC_FILE_SIZES FileSizes
;
4637 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4640 /* Check size of file */
4641 if (SectionObjectPointer
->SharedCacheMap
)
4643 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4648 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4657 /* Check size of file */
4658 if (SectionObjectPointer
->SharedCacheMap
)
4660 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4661 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4670 /* Something must gone wrong
4671 * how can we have a Section but no
4673 DPRINT("ERROR: DataSectionObject without reference!\n");
4677 DPRINT("FIXME: didn't check for outstanding write probes\n");
4689 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4690 IN MMFLUSH_TYPE FlushType
)
4692 BOOLEAN Result
= TRUE
;
4694 PMM_SECTION_SEGMENT Segment
;
4699 case MmFlushForDelete
:
4700 if (SectionObjectPointer
->ImageSectionObject
||
4701 SectionObjectPointer
->DataSectionObject
)
4706 CcRosSetRemoveOnClose(SectionObjectPointer
);
4709 case MmFlushForWrite
:
4711 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4713 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4716 if (SectionObjectPointer
->ImageSectionObject
) {
4717 DPRINT1("SectionObject has ImageSection\n");
4723 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4725 DPRINT("Result %d\n", Result
);
4737 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4738 OUT PVOID
* MappedBase
,
4739 IN OUT PSIZE_T ViewSize
)
4741 PROS_SECTION_OBJECT Section
;
4742 PMMSUPPORT AddressSpace
;
4746 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4748 return MiMapViewInSystemSpace(SectionObject
,
4754 DPRINT("MmMapViewInSystemSpace() called\n");
4756 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4757 AddressSpace
= MmGetKernelAddressSpace();
4759 MmLockAddressSpace(AddressSpace
);
4762 if ((*ViewSize
) == 0)
4764 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4766 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4768 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4771 MmLockSectionSegment(Section
->Segment
);
4774 Status
= MmMapViewOfSegment(AddressSpace
,
4783 MmUnlockSectionSegment(Section
->Segment
);
4784 MmUnlockAddressSpace(AddressSpace
);
4791 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4793 PMMSUPPORT AddressSpace
;
4796 DPRINT("MmUnmapViewInSystemSpace() called\n");
4798 AddressSpace
= MmGetKernelAddressSpace();
4800 MmLockAddressSpace(AddressSpace
);
4802 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4804 MmUnlockAddressSpace(AddressSpace
);
4809 /**********************************************************************
4814 * Creates a section object.
4817 * SectionObject (OUT)
4818 * Caller supplied storage for the resulting pointer
4819 * to a SECTION_OBJECT instance;
4822 * Specifies the desired access to the section can be a
4824 * STANDARD_RIGHTS_REQUIRED |
4826 * SECTION_MAP_WRITE |
4827 * SECTION_MAP_READ |
4828 * SECTION_MAP_EXECUTE
4830 * ObjectAttributes [OPTIONAL]
4831 * Initialized attributes for the object can be used
4832 * to create a named section;
4835 * Maximizes the size of the memory section. Must be
4836 * non-NULL for a page-file backed section.
4837 * If value specified for a mapped file and the file is
4838 * not large enough, file will be extended.
4840 * SectionPageProtection
4841 * Can be a combination of:
4847 * AllocationAttributes
4848 * Can be a combination of:
4853 * Handle to a file to create a section mapped to a file
4854 * instead of a memory backed section;
4865 MmCreateSection (OUT PVOID
* Section
,
4866 IN ACCESS_MASK DesiredAccess
,
4867 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4868 IN PLARGE_INTEGER MaximumSize
,
4869 IN ULONG SectionPageProtection
,
4870 IN ULONG AllocationAttributes
,
4871 IN HANDLE FileHandle OPTIONAL
,
4872 IN PFILE_OBJECT FileObject OPTIONAL
)
4876 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4878 /* Check if an ARM3 section is being created instead */
4879 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4881 if (!(FileObject
) && !(FileHandle
))
4883 return MmCreateArm3Section(Section
,
4887 SectionPageProtection
,
4888 AllocationAttributes
&~ 1,
4894 /* Convert section flag to page flag */
4895 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
4897 /* Check to make sure the protection is correct. Nt* does this already */
4898 Protection
= MiMakeProtectionMask(SectionPageProtection
);
4899 if (Protection
== MM_INVALID_PROTECTION
)
4901 DPRINT1("Page protection is invalid\n");
4902 return STATUS_INVALID_PAGE_PROTECTION
;
4905 /* Check if this is going to be a data or image backed file section */
4906 if ((FileHandle
) || (FileObject
))
4908 /* These cannot be mapped with large pages */
4909 if (AllocationAttributes
& SEC_LARGE_PAGES
)
4911 DPRINT1("Large pages cannot be used with an image mapping\n");
4912 return STATUS_INVALID_PARAMETER_6
;
4915 /* Did the caller pass an object? */
4918 /* Reference the object directly */
4919 ObReferenceObject(FileObject
);
4923 /* Reference the file handle to get the object */
4924 Status
= ObReferenceObjectByHandle(FileHandle
,
4925 MmMakeFileAccess
[Protection
],
4927 ExGetPreviousMode(),
4928 (PVOID
*)&FileObject
,
4930 if (!NT_SUCCESS(Status
))
4932 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
4939 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
4940 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
4943 #ifndef NEWCC // A hack for initializing caching.
4944 // This is needed only in the old case.
4947 IO_STATUS_BLOCK Iosb
;
4950 LARGE_INTEGER ByteOffset
;
4951 ByteOffset
.QuadPart
= 0;
4952 Status
= ZwReadFile(FileHandle
,
4961 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
4963 DPRINT1("CC failure: %lx\n", Status
);
4966 // Caching is initialized...
4970 if (AllocationAttributes
& SEC_IMAGE
)
4972 Status
= MmCreateImageSection(SectionObject
,
4976 SectionPageProtection
,
4977 AllocationAttributes
,
4981 else if (FileHandle
!= NULL
)
4983 Status
= MmCreateDataFileSection(SectionObject
,
4987 SectionPageProtection
,
4988 AllocationAttributes
,
4991 ObDereferenceObject(FileObject
);
4994 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
4996 Status
= MmCreateCacheSection(SectionObject
,
5000 SectionPageProtection
,
5001 AllocationAttributes
,
5007 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5009 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5011 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5012 Status
= MmCreatePageFileSection(SectionObject
,
5016 SectionPageProtection
,
5017 AllocationAttributes
);