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
=
168 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
169 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
170 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
175 /* FUNCTIONS *****************************************************************/
180 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
181 File Format Specification", revision 6.0 (February 1999)
183 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
184 IN SIZE_T FileHeaderSize
,
186 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
188 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
189 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
192 ULONG cbFileHeaderOffsetSize
= 0;
193 ULONG cbSectionHeadersOffset
= 0;
194 ULONG cbSectionHeadersSize
;
195 ULONG cbSectionHeadersOffsetSize
= 0;
196 ULONG cbOptHeaderSize
;
197 ULONG cbHeadersSize
= 0;
198 ULONG nSectionAlignment
;
199 ULONG nFileAlignment
;
200 ULONG_PTR ImageBase
= 0;
201 const IMAGE_DOS_HEADER
* pidhDosHeader
;
202 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
203 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
204 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
205 PMM_SECTION_SEGMENT pssSegments
;
206 LARGE_INTEGER lnOffset
;
208 SIZE_T nPrevVirtualEndOfSegment
= 0;
209 ULONG nFileSizeOfHeaders
= 0;
214 ASSERT(FileHeaderSize
> 0);
216 ASSERT(ImageSectionObject
);
218 ASSERT(AllocateSegmentsCb
);
220 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
222 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
224 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
227 pidhDosHeader
= FileHeader
;
230 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
232 /* image too small to be an MZ executable */
233 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
234 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
236 /* no MZ signature */
237 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
238 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
241 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
243 /* not a Windows executable */
244 if(pidhDosHeader
->e_lfanew
<= 0)
245 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
247 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
248 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
250 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
255 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
256 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
258 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
259 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
263 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
264 * need to read the header from the file
266 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
267 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
269 ULONG cbNtHeaderSize
;
273 l_ReadHeaderFromFile
:
275 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
277 /* read the header from the file */
278 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
280 if(!NT_SUCCESS(nStatus
))
282 NTSTATUS ReturnedStatus
= nStatus
;
284 /* If it attempted to read past the end of the file, it means e_lfanew is invalid */
285 if (ReturnedStatus
== STATUS_END_OF_FILE
) nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
287 DIE(("ReadFile failed, status %08X\n", ReturnedStatus
));
292 ASSERT(cbReadSize
> 0);
294 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
296 /* the buffer doesn't contain the file header */
297 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
298 DIE(("The file doesn't contain the PE file header\n"));
300 pinhNtHeader
= pData
;
302 /* object still not aligned: copy it to the beginning of the buffer */
303 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
305 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
306 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
307 pinhNtHeader
= pBuffer
;
310 /* invalid NT header */
311 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
313 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
314 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
316 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
318 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
319 DIE(("The full NT header is too large\n"));
321 /* the buffer doesn't contain the whole NT header */
322 if(cbReadSize
< cbNtHeaderSize
)
323 DIE(("The file doesn't contain the full NT header\n"));
327 ULONG cbOptHeaderOffsetSize
= 0;
329 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
331 /* don't trust an invalid NT header */
332 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
333 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
335 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
336 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
338 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
340 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
341 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
343 /* the buffer doesn't contain the whole NT header: read it from the file */
344 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
345 goto l_ReadHeaderFromFile
;
348 /* read information from the NT header */
349 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
350 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
352 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
354 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
355 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
357 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
359 switch(piohOptHeader
->Magic
)
361 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
363 nStatus
= STATUS_INVALID_IMAGE_WIN_64
;
364 DIE(("Win64 optional header, unsupported\n"));
368 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
371 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
374 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
375 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
377 /* See [1], section 3.4.2 */
378 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
380 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
381 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
383 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
384 DIE(("The section alignment is smaller than the file alignment\n"));
386 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
387 nFileAlignment
= piohOptHeader
->FileAlignment
;
389 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
390 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
394 nSectionAlignment
= PAGE_SIZE
;
395 nFileAlignment
= PAGE_SIZE
;
398 ASSERT(IsPowerOf2(nSectionAlignment
));
399 ASSERT(IsPowerOf2(nFileAlignment
));
401 switch(piohOptHeader
->Magic
)
404 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
406 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
407 ImageBase
= piohOptHeader
->ImageBase
;
409 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
410 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
412 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
413 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
415 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
416 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
418 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
420 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
422 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
423 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
425 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
426 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
430 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
432 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
433 piohOptHeader
->AddressOfEntryPoint
);
436 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
437 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
439 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
441 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
443 if (piohOptHeader
->AddressOfEntryPoint
== 0)
445 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
449 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
450 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
452 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
454 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
457 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
458 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
459 * magic to any binary.
461 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
462 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
463 * the SxS support -- at which point, duh, this should be removed.
465 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
467 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
474 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
476 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
478 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
480 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
482 ImageBase
= pioh64OptHeader
->ImageBase
;
483 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
484 DIE(("ImageBase exceeds the address space\n"));
487 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
489 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
490 DIE(("SizeOfImage exceeds the address space\n"));
492 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
495 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
497 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
498 DIE(("SizeOfStackReserve exceeds the address space\n"));
500 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
503 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
505 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
506 DIE(("SizeOfStackCommit exceeds the address space\n"));
508 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
511 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
513 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
515 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
516 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
518 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
519 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
523 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
525 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
526 pioh64OptHeader
->AddressOfEntryPoint
);
529 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
530 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
532 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
534 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
536 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
538 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
542 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
543 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
545 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
546 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
553 /* [1], section 3.4.2 */
554 if((ULONG_PTR
)ImageBase
% 0x10000)
555 DIE(("ImageBase is not aligned on a 64KB boundary"));
557 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
558 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
559 ImageSectionObject
->ImageInformation
.GpValue
= 0;
560 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
561 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
563 /* SECTION HEADERS */
564 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
566 /* see [1], section 3.3 */
567 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
568 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
571 * the additional segment is for the file's headers. They need to be present for
572 * the benefit of the dynamic loader (to locate exports, defaults for thread
573 * parameters, resources, etc.)
575 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
577 /* file offset for the section headers */
578 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
579 DIE(("Offset overflow\n"));
581 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
582 DIE(("Offset overflow\n"));
584 /* size of the section headers */
585 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
586 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
588 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
589 DIE(("Section headers too large\n"));
591 /* size of the executable's headers */
592 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
594 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
595 // DIE(("SizeOfHeaders is not aligned\n"));
597 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
598 DIE(("The section headers overflow SizeOfHeaders\n"));
600 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
602 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
603 DIE(("Overflow aligning the size of headers\n"));
610 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
611 /* WARNING: piohOptHeader IS NO LONGER USABLE */
612 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
614 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
615 pishSectionHeaders
= NULL
;
619 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
620 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
622 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
623 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
627 * the buffer doesn't contain the section headers, or the alignment is wrong:
628 * read the headers from the file
630 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
631 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
636 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
638 /* read the header from the file */
639 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
641 if(!NT_SUCCESS(nStatus
))
642 DIE(("ReadFile failed with status %08X\n", nStatus
));
646 ASSERT(cbReadSize
> 0);
648 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
650 /* the buffer doesn't contain all the section headers */
651 if(cbReadSize
< cbSectionHeadersSize
)
652 DIE(("The file doesn't contain all of the section headers\n"));
654 pishSectionHeaders
= pData
;
656 /* object still not aligned: copy it to the beginning of the buffer */
657 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
659 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
660 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
661 pishSectionHeaders
= pBuffer
;
666 /* allocate the segments */
667 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
668 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
670 if(ImageSectionObject
->Segments
== NULL
)
671 DIE(("AllocateSegments failed\n"));
673 /* initialize the headers segment */
674 pssSegments
= ImageSectionObject
->Segments
;
676 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
678 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
679 DIE(("Cannot align the size of the section headers\n"));
681 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
682 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
683 DIE(("Cannot align the size of the section headers\n"));
685 pssSegments
[0].Image
.FileOffset
= 0;
686 pssSegments
[0].Protection
= PAGE_READONLY
;
687 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
688 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
689 pssSegments
[0].Image
.VirtualAddress
= 0;
690 pssSegments
[0].Image
.Characteristics
= 0;
691 pssSegments
[0].WriteCopy
= TRUE
;
693 /* skip the headers segment */
696 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
698 /* convert the executable sections into segments. See also [1], section 4 */
699 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
701 ULONG nCharacteristics
;
703 /* validate the alignment */
704 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
705 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
707 /* sections must be contiguous, ordered by base address and non-overlapping */
708 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
709 DIE(("Memory gap between section %u and the previous\n", i
));
711 /* ignore explicit BSS sections */
712 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
714 /* validate the alignment */
716 /* Yes, this should be a multiple of FileAlignment, but there's
717 * stuff out there that isn't. We can cope with that
719 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
720 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
723 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
724 // DIE(("PointerToRawData[%u] is not aligned\n", i));
727 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
728 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
732 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
733 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
736 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
738 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
740 /* no explicit protection */
741 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
743 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
744 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
746 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
747 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
749 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
750 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
753 /* see table above */
754 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
755 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
757 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
758 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
760 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
762 AlignedLength
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
763 if(AlignedLength
< pssSegments
[i
].Length
.LowPart
)
764 DIE(("Cannot align the virtual size of section %u\n", i
));
766 pssSegments
[i
].Length
.LowPart
= AlignedLength
;
768 if(pssSegments
[i
].Length
.QuadPart
== 0)
769 DIE(("Virtual size of section %u is null\n", i
));
771 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
772 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
774 /* ensure the memory image is no larger than 4GB */
775 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
776 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
777 DIE(("The image is too large\n"));
780 if(nSectionAlignment
>= PAGE_SIZE
)
781 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
784 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
794 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
795 * ARGUMENTS: PFILE_OBJECT to wait for.
796 * RETURNS: Status of the wait.
799 MmspWaitForFileLock(PFILE_OBJECT File
)
801 return STATUS_SUCCESS
;
802 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
807 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
809 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
811 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
812 PMM_SECTION_SEGMENT SectionSegments
;
816 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
817 NrSegments
= ImageSectionObject
->NrSegments
;
818 SectionSegments
= ImageSectionObject
->Segments
;
819 for (i
= 0; i
< NrSegments
; i
++)
821 if (SectionSegments
[i
].ReferenceCount
!= 0)
823 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
824 SectionSegments
[i
].ReferenceCount
);
825 KeBugCheck(MEMORY_MANAGEMENT
);
827 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
829 ExFreePool(ImageSectionObject
->Segments
);
830 ExFreePool(ImageSectionObject
);
831 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
833 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
835 PMM_SECTION_SEGMENT Segment
;
837 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
840 if (Segment
->ReferenceCount
!= 0)
842 DPRINT1("Data segment still referenced\n");
843 KeBugCheck(MEMORY_MANAGEMENT
);
845 MmFreePageTablesSectionSegment(Segment
, NULL
);
847 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
853 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
854 PLARGE_INTEGER Offset
)
858 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
861 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
862 KeBugCheck(MEMORY_MANAGEMENT
);
864 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
866 DPRINT1("Maximum share count reached\n");
867 KeBugCheck(MEMORY_MANAGEMENT
);
869 if (IS_SWAP_FROM_SSE(Entry
))
871 KeBugCheck(MEMORY_MANAGEMENT
);
873 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
874 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
879 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
880 PMM_SECTION_SEGMENT Segment
,
881 PLARGE_INTEGER Offset
,
886 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
887 BOOLEAN IsDirectMapped
= FALSE
;
891 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
892 KeBugCheck(MEMORY_MANAGEMENT
);
894 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
896 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
897 KeBugCheck(MEMORY_MANAGEMENT
);
899 if (IS_SWAP_FROM_SSE(Entry
))
901 KeBugCheck(MEMORY_MANAGEMENT
);
903 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
905 * If we reducing the share count of this entry to zero then set the entry
906 * to zero and tell the cache the page is no longer mapped.
908 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
910 PFILE_OBJECT FileObject
;
911 SWAPENTRY SavedSwapEntry
;
914 PROS_SHARED_CACHE_MAP SharedCacheMap
;
915 BOOLEAN IsImageSection
;
916 LARGE_INTEGER FileOffset
;
918 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
919 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
922 Page
= PFN_FROM_SSE(Entry
);
923 FileObject
= Section
->FileObject
;
924 if (FileObject
!= NULL
&&
925 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
929 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
930 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
933 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
934 IsDirectMapped
= TRUE
;
936 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
.QuadPart
, Dirty
);
938 Status
= STATUS_SUCCESS
;
940 if (!NT_SUCCESS(Status
))
942 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
943 KeBugCheck(MEMORY_MANAGEMENT
);
949 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
950 if (SavedSwapEntry
== 0)
953 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
954 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
958 * Try to page out this page and set the swap entry
959 * within the section segment. There exist no rmap entry
960 * for this page. The pager thread can't page out a
961 * page without a rmap entry.
963 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
964 if (InEntry
) *InEntry
= Entry
;
965 MiSetPageEvent(NULL
, NULL
);
969 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
970 if (InEntry
) *InEntry
= 0;
971 MiSetPageEvent(NULL
, NULL
);
974 MmReleasePageMemoryConsumer(MC_USER
, Page
);
980 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
981 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
989 * We hold all locks. Nobody can do something with the current
990 * process and the current segment (also not within an other process).
993 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
994 if (!NT_SUCCESS(Status
))
996 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
997 KeBugCheck(MEMORY_MANAGEMENT
);
1000 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
1001 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
1002 MmSetSavedSwapEntryPage(Page
, 0);
1003 MiSetPageEvent(NULL
, NULL
);
1005 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1009 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1010 KeBugCheck(MEMORY_MANAGEMENT
);
1019 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1021 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1024 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1028 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1030 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1032 SharedCacheMap
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1033 Vacb
= CcRosLookupVacb(SharedCacheMap
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
);
1036 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, FALSE
, TRUE
);
1046 MiCopyFromUserPage(PFN_NUMBER DestPage
, const VOID
*SrcAddress
)
1052 Process
= PsGetCurrentProcess();
1053 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1054 if (DestAddress
== NULL
)
1056 return(STATUS_NO_MEMORY
);
1058 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1059 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1060 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1061 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1062 return(STATUS_SUCCESS
);
1068 MiReadPage(PMEMORY_AREA MemoryArea
,
1072 * FUNCTION: Read a page for a section backed memory area.
1074 * MemoryArea - Memory area to read the page for.
1075 * Offset - Offset of the page to read.
1076 * Page - Variable that receives a page contains the read data.
1079 LONGLONG BaseOffset
;
1080 LONGLONG FileOffset
;
1084 PFILE_OBJECT FileObject
;
1087 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1088 BOOLEAN IsImageSection
;
1091 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1092 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1093 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
;
1094 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1095 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1097 ASSERT(SharedCacheMap
);
1099 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1102 * If the file system is letting us go directly to the cache and the
1103 * memory area was mapped at an offset in the file which is page aligned
1104 * then get the related VACB.
1106 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1107 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1108 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1112 * Get the related VACB; we use a lower level interface than
1113 * filesystems do because it is safe for us to use an offset with an
1114 * alignment less than the file system block size.
1116 Status
= CcRosGetVacb(SharedCacheMap
,
1122 if (!NT_SUCCESS(Status
))
1129 * If the VACB isn't up to date then call the file
1130 * system to read in the data.
1132 Status
= CcReadVirtualAddress(Vacb
);
1133 if (!NT_SUCCESS(Status
))
1135 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1140 /* Probe the page, since it's PDE might not be synced */
1141 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1144 * Retrieve the page from the view that we actually want.
1146 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1147 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1149 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, TRUE
);
1156 LONGLONG VacbOffset
;
1159 * Allocate a page, this is rather complicated by the possibility
1160 * we might have to move other things out of memory
1162 MI_SET_USAGE(MI_USAGE_SECTION
);
1163 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1164 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1165 if (!NT_SUCCESS(Status
))
1169 Status
= CcRosGetVacb(SharedCacheMap
,
1175 if (!NT_SUCCESS(Status
))
1182 * If the VACB isn't up to date then call the file
1183 * system to read in the data.
1185 Status
= CcReadVirtualAddress(Vacb
);
1186 if (!NT_SUCCESS(Status
))
1188 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1193 Process
= PsGetCurrentProcess();
1194 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1195 VacbOffset
= BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
;
1196 Length
= RawLength
- SegOffset
;
1197 if (Length
<= VacbOffset
&& Length
<= PAGE_SIZE
)
1199 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1201 else if (VacbOffset
>= PAGE_SIZE
)
1203 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1207 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, VacbOffset
);
1208 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1209 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1210 Status
= CcRosGetVacb(SharedCacheMap
,
1211 FileOffset
+ VacbOffset
,
1216 if (!NT_SUCCESS(Status
))
1223 * If the VACB isn't up to date then call the file
1224 * system to read in the data.
1226 Status
= CcReadVirtualAddress(Vacb
);
1227 if (!NT_SUCCESS(Status
))
1229 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1233 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1234 if (Length
< PAGE_SIZE
)
1236 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, Length
- VacbOffset
);
1240 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, PAGE_SIZE
- VacbOffset
);
1243 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1244 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1246 return(STATUS_SUCCESS
);
1251 MiReadPage(PMEMORY_AREA MemoryArea
,
1255 * FUNCTION: Read a page for a section backed memory area.
1257 * MemoryArea - Memory area to read the page for.
1258 * Offset - Offset of the page to read.
1259 * Page - Variable that receives a page contains the read data.
1262 MM_REQUIRED_RESOURCES Resources
;
1265 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1267 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1268 Resources
.FileOffset
.QuadPart
= SegOffset
+
1269 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1270 Resources
.Consumer
= MC_USER
;
1271 Resources
.Amount
= PAGE_SIZE
;
1273 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]);
1275 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1276 *Page
= Resources
.Page
[0];
1282 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
1290 PMEMORY_AREA MemoryArea
;
1291 PMM_SECTION_SEGMENT Segment
;
1292 BOOLEAN DoCOW
= FALSE
;
1294 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1296 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1297 ASSERT(MemoryArea
!= NULL
);
1298 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1299 MmLockSectionSegment(Segment
);
1301 if ((Segment
->WriteCopy
) &&
1302 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1307 if (OldProtect
!= NewProtect
)
1309 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1311 SWAPENTRY SwapEntry
;
1312 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1313 ULONG Protect
= NewProtect
;
1315 /* Wait for a wait entry to disappear */
1318 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1319 if (SwapEntry
!= MM_WAIT_ENTRY
)
1321 MiWaitForPageEvent(Process
, Address
);
1326 * If we doing COW for this segment then check if the page is
1329 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
1331 LARGE_INTEGER Offset
;
1335 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
1336 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1337 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1339 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
1340 * IS_SWAP_FROM_SSE and we'll do the right thing.
1342 Page
= MmGetPfnForProcess(Process
, Address
);
1344 Protect
= PAGE_READONLY
;
1345 if (IS_SWAP_FROM_SSE(Entry
) || PFN_FROM_SSE(Entry
) != Page
)
1347 Protect
= NewProtect
;
1351 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
1353 MmSetPageProtect(Process
, Address
,
1359 MmUnlockSectionSegment(Segment
);
1364 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1365 MEMORY_AREA
* MemoryArea
,
1369 LARGE_INTEGER Offset
;
1372 PROS_SECTION_OBJECT Section
;
1373 PMM_SECTION_SEGMENT Segment
;
1378 BOOLEAN HasSwapEntry
;
1380 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1381 SWAPENTRY SwapEntry
;
1384 * There is a window between taking the page fault and locking the
1385 * address space when another thread could load the page so we check
1388 if (MmIsPagePresent(Process
, Address
))
1390 return(STATUS_SUCCESS
);
1393 if (MmIsDisabledPage(Process
, Address
))
1395 return(STATUS_ACCESS_VIOLATION
);
1399 * Check for the virtual memory area being deleted.
1401 if (MemoryArea
->DeleteInProgress
)
1403 return(STATUS_UNSUCCESSFUL
);
1406 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1407 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1408 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1410 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1411 Section
= MemoryArea
->Data
.SectionData
.Section
;
1412 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1413 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1415 ASSERT(Region
!= NULL
);
1417 /* Check for a NOACCESS mapping */
1418 if (Region
->Protect
& PAGE_NOACCESS
)
1420 return STATUS_ACCESS_VIOLATION
;
1423 if (Region
->Protect
& PAGE_GUARD
)
1426 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
1427 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1428 Address
, PAGE_SIZE
, Region
->Type
, Region
->Protect
& ~PAGE_GUARD
,
1429 MmAlterViewAttributes
);
1431 if (!NT_SUCCESS(Status
))
1433 DPRINT1("Removing PAGE_GUARD protection failed : 0x%08x.\n", Status
);
1436 return STATUS_GUARD_PAGE_VIOLATION
;
1442 MmLockSectionSegment(Segment
);
1443 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1445 * Check if this page needs to be mapped COW
1447 if ((Segment
->WriteCopy
) &&
1448 (Region
->Protect
== PAGE_READWRITE
||
1449 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1451 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1455 Attributes
= Region
->Protect
;
1459 * Check if someone else is already handling this fault, if so wait
1462 if (Entry
&& MM_IS_WAIT_PTE(Entry
))
1464 MmUnlockSectionSegment(Segment
);
1465 MmUnlockAddressSpace(AddressSpace
);
1466 MiWaitForPageEvent(NULL
, NULL
);
1467 MmLockAddressSpace(AddressSpace
);
1468 DPRINT("Address 0x%p\n", Address
);
1469 return(STATUS_MM_RESTART_OPERATION
);
1472 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1474 /* See if we should use a private page */
1477 SWAPENTRY DummyEntry
;
1480 * Is it a wait entry?
1484 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1486 if (SwapEntry
== MM_WAIT_ENTRY
)
1488 MmUnlockSectionSegment(Segment
);
1489 MmUnlockAddressSpace(AddressSpace
);
1490 MiWaitForPageEvent(NULL
, NULL
);
1491 MmLockAddressSpace(AddressSpace
);
1492 return STATUS_MM_RESTART_OPERATION
;
1496 * Must be private page we have swapped out.
1502 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1504 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1505 KeBugCheck(MEMORY_MANAGEMENT
);
1507 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1510 MmUnlockSectionSegment(Segment
);
1512 /* Tell everyone else we are serving the fault. */
1513 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1515 MmUnlockAddressSpace(AddressSpace
);
1516 MI_SET_USAGE(MI_USAGE_SECTION
);
1517 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1518 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1519 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1520 if (!NT_SUCCESS(Status
))
1522 KeBugCheck(MEMORY_MANAGEMENT
);
1527 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1528 if (!NT_SUCCESS(Status
))
1530 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1531 KeBugCheck(MEMORY_MANAGEMENT
);
1535 MmLockAddressSpace(AddressSpace
);
1536 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1537 Status
= MmCreateVirtualMapping(Process
,
1542 if (!NT_SUCCESS(Status
))
1544 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1545 KeBugCheck(MEMORY_MANAGEMENT
);
1550 * Store the swap entry for later use.
1553 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1556 * Add the page to the process's working set
1558 MmInsertRmap(Page
, Process
, Address
);
1560 * Finish the operation
1562 MiSetPageEvent(Process
, Address
);
1563 DPRINT("Address 0x%p\n", Address
);
1564 return(STATUS_SUCCESS
);
1568 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1570 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1572 MmUnlockSectionSegment(Segment
);
1574 * Just map the desired physical page
1576 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1577 Status
= MmCreateVirtualMappingUnsafe(Process
,
1582 if (!NT_SUCCESS(Status
))
1584 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1585 KeBugCheck(MEMORY_MANAGEMENT
);
1590 * Cleanup and release locks
1592 MiSetPageEvent(Process
, Address
);
1593 DPRINT("Address 0x%p\n", Address
);
1594 return(STATUS_SUCCESS
);
1598 * Get the entry corresponding to the offset within the section
1600 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1604 SWAPENTRY FakeSwapEntry
;
1607 * If the entry is zero (and it can't change because we have
1608 * locked the segment) then we need to load the page.
1612 * Release all our locks and read in the page from disk
1614 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1615 MmUnlockSectionSegment(Segment
);
1616 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1617 MmUnlockAddressSpace(AddressSpace
);
1619 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1620 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1621 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1623 MI_SET_USAGE(MI_USAGE_SECTION
);
1624 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1625 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1626 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1627 if (!NT_SUCCESS(Status
))
1629 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1635 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1636 if (!NT_SUCCESS(Status
))
1638 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1641 if (!NT_SUCCESS(Status
))
1644 * FIXME: What do we know in this case?
1647 * Cleanup and release locks
1649 MmLockAddressSpace(AddressSpace
);
1650 MiSetPageEvent(Process
, Address
);
1651 DPRINT("Address 0x%p\n", Address
);
1655 /* Lock both segment and process address space while we proceed. */
1656 MmLockAddressSpace(AddressSpace
);
1657 MmLockSectionSegment(Segment
);
1659 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1660 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1661 Page
, Process
, PAddress
, Attributes
);
1662 Status
= MmCreateVirtualMapping(Process
,
1667 if (!NT_SUCCESS(Status
))
1669 DPRINT1("Unable to create virtual mapping\n");
1670 KeBugCheck(MEMORY_MANAGEMENT
);
1672 ASSERT(MmIsPagePresent(Process
, PAddress
));
1673 MmInsertRmap(Page
, Process
, Address
);
1675 /* Set this section offset has being backed by our new page. */
1676 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1677 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1678 MmUnlockSectionSegment(Segment
);
1680 MiSetPageEvent(Process
, Address
);
1681 DPRINT("Address 0x%p\n", Address
);
1682 return(STATUS_SUCCESS
);
1684 else if (IS_SWAP_FROM_SSE(Entry
))
1686 SWAPENTRY SwapEntry
;
1688 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1690 /* See if a page op is running on this segment. */
1691 if (SwapEntry
== MM_WAIT_ENTRY
)
1693 MmUnlockSectionSegment(Segment
);
1694 MmUnlockAddressSpace(AddressSpace
);
1695 MiWaitForPageEvent(NULL
, NULL
);
1696 MmLockAddressSpace(AddressSpace
);
1697 return STATUS_MM_RESTART_OPERATION
;
1701 * Release all our locks and read in the page from disk
1703 MmUnlockSectionSegment(Segment
);
1705 MmUnlockAddressSpace(AddressSpace
);
1706 MI_SET_USAGE(MI_USAGE_SECTION
);
1707 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1708 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1709 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1710 if (!NT_SUCCESS(Status
))
1712 KeBugCheck(MEMORY_MANAGEMENT
);
1715 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1716 if (!NT_SUCCESS(Status
))
1718 KeBugCheck(MEMORY_MANAGEMENT
);
1722 * Relock the address space and segment
1724 MmLockAddressSpace(AddressSpace
);
1725 MmLockSectionSegment(Segment
);
1728 * Check the entry. No one should change the status of a page
1729 * that has a pending page-in.
1731 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1732 if (Entry
!= Entry1
)
1734 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1735 KeBugCheck(MEMORY_MANAGEMENT
);
1739 * Save the swap entry.
1741 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1743 /* Map the page into the process address space */
1744 Status
= MmCreateVirtualMapping(Process
,
1749 if (!NT_SUCCESS(Status
))
1751 DPRINT1("Unable to create virtual mapping\n");
1752 KeBugCheck(MEMORY_MANAGEMENT
);
1754 MmInsertRmap(Page
, Process
, Address
);
1757 * Mark the offset within the section as having valid, in-memory
1760 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1761 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1762 MmUnlockSectionSegment(Segment
);
1764 MiSetPageEvent(Process
, Address
);
1765 DPRINT("Address 0x%p\n", Address
);
1766 return(STATUS_SUCCESS
);
1770 /* We already have a page on this section offset. Map it into the process address space. */
1771 Page
= PFN_FROM_SSE(Entry
);
1773 Status
= MmCreateVirtualMapping(Process
,
1778 if (!NT_SUCCESS(Status
))
1780 DPRINT1("Unable to create virtual mapping\n");
1781 KeBugCheck(MEMORY_MANAGEMENT
);
1783 MmInsertRmap(Page
, Process
, Address
);
1785 /* Take a reference on it */
1786 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1787 MmUnlockSectionSegment(Segment
);
1789 MiSetPageEvent(Process
, Address
);
1790 DPRINT("Address 0x%p\n", Address
);
1791 return(STATUS_SUCCESS
);
1797 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1798 MEMORY_AREA
* MemoryArea
,
1801 PMM_SECTION_SEGMENT Segment
;
1802 PROS_SECTION_OBJECT Section
;
1807 LARGE_INTEGER Offset
;
1810 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1812 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1814 /* Make sure we have a page mapping for this address. */
1815 Status
= MmNotPresentFaultSectionView(AddressSpace
, MemoryArea
, Address
, TRUE
);
1816 if (!NT_SUCCESS(Status
))
1818 /* This is invalid access ! */
1823 * Check if the page has already been set readwrite
1825 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1827 DPRINT("Address 0x%p\n", Address
);
1828 return(STATUS_SUCCESS
);
1832 * Find the offset of the page
1834 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1835 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1836 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1838 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1839 Section
= MemoryArea
->Data
.SectionData
.Section
;
1840 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1841 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1843 ASSERT(Region
!= NULL
);
1846 * Check if we are doing COW
1848 if (!((Segment
->WriteCopy
) &&
1849 (Region
->Protect
== PAGE_READWRITE
||
1850 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1852 DPRINT("Address 0x%p\n", Address
);
1853 return(STATUS_ACCESS_VIOLATION
);
1856 /* Get the page mapping this section offset. */
1857 MmLockSectionSegment(Segment
);
1858 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1860 /* Get the current page mapping for the process */
1861 ASSERT(MmIsPagePresent(Process
, PAddress
));
1862 OldPage
= MmGetPfnForProcess(Process
, PAddress
);
1863 ASSERT(OldPage
!= 0);
1865 if (IS_SWAP_FROM_SSE(Entry
) ||
1866 PFN_FROM_SSE(Entry
) != OldPage
)
1868 MmUnlockSectionSegment(Segment
);
1869 /* This is a private page. We must only change the page protection. */
1870 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1871 return(STATUS_SUCCESS
);
1877 MI_SET_USAGE(MI_USAGE_SECTION
);
1878 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1879 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1880 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1881 if (!NT_SUCCESS(Status
))
1883 KeBugCheck(MEMORY_MANAGEMENT
);
1889 NT_VERIFY(NT_SUCCESS(MiCopyFromUserPage(NewPage
, PAddress
)));
1892 * Unshare the old page.
1894 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1895 MmDeleteVirtualMapping(Process
, PAddress
, NULL
, NULL
);
1896 MmDeleteRmap(OldPage
, Process
, PAddress
);
1897 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1898 MmUnlockSectionSegment(Segment
);
1901 * Set the PTE to point to the new page
1903 Status
= MmCreateVirtualMapping(Process
,
1908 if (!NT_SUCCESS(Status
))
1910 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1911 KeBugCheck(MEMORY_MANAGEMENT
);
1914 MmInsertRmap(NewPage
, Process
, PAddress
);
1916 MiSetPageEvent(Process
, Address
);
1917 DPRINT("Address 0x%p\n", Address
);
1918 return(STATUS_SUCCESS
);
1922 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1924 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1926 PFN_NUMBER Page
= 0;
1928 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1931 MmLockAddressSpace(&Process
->Vm
);
1934 MmDeleteVirtualMapping(Process
,
1940 PageOutContext
->WasDirty
= TRUE
;
1942 if (!PageOutContext
->Private
)
1944 MmLockSectionSegment(PageOutContext
->Segment
);
1945 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1946 PageOutContext
->Segment
,
1947 &PageOutContext
->Offset
,
1948 PageOutContext
->WasDirty
,
1950 &PageOutContext
->SectionEntry
);
1951 MmUnlockSectionSegment(PageOutContext
->Segment
);
1955 MmUnlockAddressSpace(&Process
->Vm
);
1958 if (PageOutContext
->Private
)
1960 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1966 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1967 MEMORY_AREA
* MemoryArea
,
1968 PVOID Address
, ULONG_PTR Entry
)
1971 MM_SECTION_PAGEOUT_CONTEXT Context
;
1972 SWAPENTRY SwapEntry
;
1975 ULONGLONG FileOffset
;
1976 PFILE_OBJECT FileObject
;
1977 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1978 BOOLEAN IsImageSection
;
1980 BOOLEAN DirectMapped
;
1981 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1984 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1987 * Get the segment and section.
1989 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1990 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1991 Context
.SectionEntry
= Entry
;
1992 Context
.CallingProcess
= Process
;
1994 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
1995 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1997 DirectMapped
= FALSE
;
1999 MmLockSectionSegment(Context
.Segment
);
2002 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
2003 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2004 FileObject
= Context
.Section
->FileObject
;
2006 if (FileObject
!= NULL
&&
2007 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2009 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2012 * If the file system is letting us go directly to the cache and the
2013 * memory area was mapped at an offset in the file which is page aligned
2014 * then note this is a direct mapped page.
2016 if ((FileOffset
% PAGE_SIZE
) == 0 &&
2017 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2019 DirectMapped
= TRUE
;
2026 * This should never happen since mappings of physical memory are never
2027 * placed in the rmap lists.
2029 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2031 DPRINT1("Trying to page out from physical memory section address 0x%p "
2032 "process %p\n", Address
,
2033 Process
? Process
->UniqueProcessId
: 0);
2034 KeBugCheck(MEMORY_MANAGEMENT
);
2038 * Get the section segment entry and the physical address.
2040 if (!MmIsPagePresent(Process
, Address
))
2042 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2043 Process
? Process
->UniqueProcessId
: 0, Address
);
2044 KeBugCheck(MEMORY_MANAGEMENT
);
2046 Page
= MmGetPfnForProcess(Process
, Address
);
2047 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2050 * Check the reference count to ensure this page can be paged out
2052 if (MmGetReferenceCountPage(Page
) != 1)
2054 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
2055 Page
, MmGetReferenceCountPage(Page
));
2056 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2057 MmUnlockSectionSegment(Context
.Segment
);
2058 return STATUS_UNSUCCESSFUL
;
2062 * Prepare the context structure for the rmap delete call.
2064 MmUnlockSectionSegment(Context
.Segment
);
2065 Context
.WasDirty
= FALSE
;
2066 if (IS_SWAP_FROM_SSE(Entry
) || PFN_FROM_SSE(Entry
) != Page
)
2068 Context
.Private
= TRUE
;
2072 Context
.Private
= FALSE
;
2076 * Take an additional reference to the page or the VACB.
2078 if (DirectMapped
&& !Context
.Private
)
2080 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
2082 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2083 KeBugCheck(MEMORY_MANAGEMENT
);
2088 OldIrql
= MiAcquirePfnLock();
2089 MmReferencePage(Page
);
2090 MiReleasePfnLock(OldIrql
);
2093 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2095 /* Since we passed in a surrogate, we'll get back the page entry
2096 * state in our context. This is intended to make intermediate
2097 * decrements of share count not release the wait entry.
2099 Entry
= Context
.SectionEntry
;
2102 * If this wasn't a private page then we should have reduced the entry to
2103 * zero by deleting all the rmaps.
2105 if (!Context
.Private
&& Entry
!= 0)
2107 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2108 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2110 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2115 * If the page wasn't dirty then we can just free it as for a readonly page.
2116 * Since we unmapped all the mappings above we know it will not suddenly
2118 * If the page is from a pagefile section and has no swap entry,
2119 * we can't free the page at this point.
2121 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2122 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2124 if (Context
.Private
)
2126 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2127 Context
.WasDirty
? "dirty" : "clean", Address
);
2128 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2130 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2132 MmSetSavedSwapEntryPage(Page
, 0);
2133 MmLockSectionSegment(Context
.Segment
);
2134 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2135 MmUnlockSectionSegment(Context
.Segment
);
2136 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2137 MiSetPageEvent(NULL
, NULL
);
2138 return(STATUS_SUCCESS
);
2141 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2143 if (Context
.Private
)
2145 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2146 Context
.WasDirty
? "dirty" : "clean", Address
);
2147 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2149 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2151 MmSetSavedSwapEntryPage(Page
, 0);
2154 MmLockSectionSegment(Context
.Segment
);
2155 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2156 MmUnlockSectionSegment(Context
.Segment
);
2158 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2159 MiSetPageEvent(NULL
, NULL
);
2160 return(STATUS_SUCCESS
);
2163 else if (!Context
.Private
&& DirectMapped
)
2167 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2169 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2172 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
, FALSE
);
2174 Status
= STATUS_SUCCESS
;
2177 if (!NT_SUCCESS(Status
))
2179 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2180 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2183 MiSetPageEvent(NULL
, NULL
);
2184 return(STATUS_SUCCESS
);
2186 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2190 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2192 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2194 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2195 MiSetPageEvent(NULL
, NULL
);
2196 return(STATUS_SUCCESS
);
2198 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2200 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2201 MmSetSavedSwapEntryPage(Page
, 0);
2202 MmLockAddressSpace(AddressSpace
);
2203 Status
= MmCreatePageFileMapping(Process
,
2206 MmUnlockAddressSpace(AddressSpace
);
2207 if (!NT_SUCCESS(Status
))
2209 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2210 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2212 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2213 MiSetPageEvent(NULL
, NULL
);
2214 return(STATUS_SUCCESS
);
2218 * If necessary, allocate an entry in the paging file for this page
2222 SwapEntry
= MmAllocSwapPage();
2225 MmShowOutOfSpaceMessagePagingFile();
2226 MmLockAddressSpace(AddressSpace
);
2228 * For private pages restore the old mappings.
2230 if (Context
.Private
)
2232 Status
= MmCreateVirtualMapping(Process
,
2234 MemoryArea
->Protect
,
2237 MmSetDirtyPage(Process
, Address
);
2246 MmLockSectionSegment(Context
.Segment
);
2249 * For non-private pages if the page wasn't direct mapped then
2250 * set it back into the section segment entry so we don't loose
2251 * our copy. Otherwise it will be handled by the cache manager.
2253 Status
= MmCreateVirtualMapping(Process
,
2255 MemoryArea
->Protect
,
2258 MmSetDirtyPage(Process
, Address
);
2262 // If we got here, the previous entry should have been a wait
2263 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2264 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2265 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2266 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2267 MmUnlockSectionSegment(Context
.Segment
);
2269 MmUnlockAddressSpace(AddressSpace
);
2270 MiSetPageEvent(NULL
, NULL
);
2271 return(STATUS_PAGEFILE_QUOTA
);
2276 * Write the page to the pagefile
2278 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2279 if (!NT_SUCCESS(Status
))
2281 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2284 * As above: undo our actions.
2285 * FIXME: Also free the swap page.
2287 MmLockAddressSpace(AddressSpace
);
2288 if (Context
.Private
)
2290 Status
= MmCreateVirtualMapping(Process
,
2292 MemoryArea
->Protect
,
2295 MmSetDirtyPage(Process
, Address
);
2302 MmLockSectionSegment(Context
.Segment
);
2303 Status
= MmCreateVirtualMapping(Process
,
2305 MemoryArea
->Protect
,
2308 MmSetDirtyPage(Process
, Address
);
2312 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2313 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2314 MmUnlockSectionSegment(Context
.Segment
);
2316 MmUnlockAddressSpace(AddressSpace
);
2317 MiSetPageEvent(NULL
, NULL
);
2318 return(STATUS_UNSUCCESSFUL
);
2322 * Otherwise we have succeeded.
2324 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2325 MmSetSavedSwapEntryPage(Page
, 0);
2326 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2327 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2329 MmLockSectionSegment(Context
.Segment
);
2330 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2331 MmUnlockSectionSegment(Context
.Segment
);
2335 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2338 if (Context
.Private
)
2340 MmLockAddressSpace(AddressSpace
);
2341 MmLockSectionSegment(Context
.Segment
);
2342 Status
= MmCreatePageFileMapping(Process
,
2345 /* We had placed a wait entry upon entry ... replace it before leaving */
2346 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2347 MmUnlockSectionSegment(Context
.Segment
);
2348 MmUnlockAddressSpace(AddressSpace
);
2349 if (!NT_SUCCESS(Status
))
2351 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2352 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2357 MmLockAddressSpace(AddressSpace
);
2358 MmLockSectionSegment(Context
.Segment
);
2359 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2360 /* We had placed a wait entry upon entry ... replace it before leaving */
2361 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2362 MmUnlockSectionSegment(Context
.Segment
);
2363 MmUnlockAddressSpace(AddressSpace
);
2366 MiSetPageEvent(NULL
, NULL
);
2367 return(STATUS_SUCCESS
);
2372 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2373 PMEMORY_AREA MemoryArea
,
2377 LARGE_INTEGER Offset
;
2378 PROS_SECTION_OBJECT Section
;
2379 PMM_SECTION_SEGMENT Segment
;
2381 SWAPENTRY SwapEntry
;
2385 PFILE_OBJECT FileObject
;
2387 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2389 BOOLEAN DirectMapped
;
2390 BOOLEAN IsImageSection
;
2391 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2393 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2395 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2396 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2399 * Get the segment and section.
2401 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2402 Section
= MemoryArea
->Data
.SectionData
.Section
;
2403 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2405 FileObject
= Section
->FileObject
;
2406 DirectMapped
= FALSE
;
2407 if (FileObject
!= NULL
&&
2408 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2411 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2415 * If the file system is letting us go directly to the cache and the
2416 * memory area was mapped at an offset in the file which is page aligned
2417 * then note this is a direct mapped page.
2419 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2420 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2422 DirectMapped
= TRUE
;
2427 * This should never happen since mappings of physical memory are never
2428 * placed in the rmap lists.
2430 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2432 DPRINT1("Trying to write back page from physical memory mapped at %p "
2433 "process %p\n", Address
,
2434 Process
? Process
->UniqueProcessId
: 0);
2435 KeBugCheck(MEMORY_MANAGEMENT
);
2439 * Get the section segment entry and the physical address.
2441 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2442 if (!MmIsPagePresent(Process
, Address
))
2444 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2445 Process
? Process
->UniqueProcessId
: 0, Address
);
2446 KeBugCheck(MEMORY_MANAGEMENT
);
2448 Page
= MmGetPfnForProcess(Process
, Address
);
2449 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2452 * Check for a private (COWed) page.
2454 if (IS_SWAP_FROM_SSE(Entry
) || PFN_FROM_SSE(Entry
) != Page
)
2464 * Speculatively set all mappings of the page to clean.
2466 MmSetCleanAllRmaps(Page
);
2469 * If this page was direct mapped from the cache then the cache manager
2470 * will take care of writing it back to disk.
2472 if (DirectMapped
&& !Private
)
2474 //LARGE_INTEGER SOffset;
2475 ASSERT(SwapEntry
== 0);
2476 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2478 CcRosMarkDirtyFile(SharedCacheMap
, Offset
.QuadPart
);
2480 MmLockSectionSegment(Segment
);
2481 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2482 MmUnlockSectionSegment(Segment
);
2483 MiSetPageEvent(NULL
, NULL
);
2484 return(STATUS_SUCCESS
);
2488 * If necessary, allocate an entry in the paging file for this page
2492 SwapEntry
= MmAllocSwapPage();
2495 MmSetDirtyAllRmaps(Page
);
2496 MiSetPageEvent(NULL
, NULL
);
2497 return(STATUS_PAGEFILE_QUOTA
);
2499 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2503 * Write the page to the pagefile
2505 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2506 if (!NT_SUCCESS(Status
))
2508 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2510 MmSetDirtyAllRmaps(Page
);
2511 MiSetPageEvent(NULL
, NULL
);
2512 return(STATUS_UNSUCCESSFUL
);
2516 * Otherwise we have succeeded.
2518 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2519 MiSetPageEvent(NULL
, NULL
);
2520 return(STATUS_SUCCESS
);
2525 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2526 PMEMORY_AREA MemoryArea
,
2534 ULONG_PTR MaxLength
;
2536 MaxLength
= MA_GetEndingAddress(MemoryArea
) - (ULONG_PTR
)BaseAddress
;
2537 if (Length
> MaxLength
)
2538 Length
= (ULONG
)MaxLength
;
2540 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2541 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2543 ASSERT(Region
!= NULL
);
2545 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2546 Region
->Protect
!= Protect
)
2548 return STATUS_INVALID_PAGE_PROTECTION
;
2551 *OldProtect
= Region
->Protect
;
2552 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
2553 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2554 BaseAddress
, Length
, Region
->Type
, Protect
,
2555 MmAlterViewAttributes
);
2561 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2563 PMEMORY_BASIC_INFORMATION Info
,
2564 PSIZE_T ResultLength
)
2567 PVOID RegionBaseAddress
;
2568 PROS_SECTION_OBJECT Section
;
2569 PMM_SECTION_SEGMENT Segment
;
2571 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2572 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2573 Address
, &RegionBaseAddress
);
2576 return STATUS_UNSUCCESSFUL
;
2579 Section
= MemoryArea
->Data
.SectionData
.Section
;
2580 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2582 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2583 Info
->AllocationBase
= (PUCHAR
)MA_GetStartingAddress(MemoryArea
) - Segment
->Image
.VirtualAddress
;
2584 Info
->Type
= MEM_IMAGE
;
2588 Info
->AllocationBase
= (PVOID
)MA_GetStartingAddress(MemoryArea
);
2589 Info
->Type
= MEM_MAPPED
;
2591 Info
->BaseAddress
= RegionBaseAddress
;
2592 Info
->AllocationProtect
= MemoryArea
->Protect
;
2593 Info
->RegionSize
= Region
->Length
;
2594 Info
->State
= MEM_COMMIT
;
2595 Info
->Protect
= Region
->Protect
;
2597 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2598 return(STATUS_SUCCESS
);
2603 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2606 LARGE_INTEGER Offset
;
2608 SWAPENTRY SavedSwapEntry
;
2613 MmLockSectionSegment(Segment
);
2615 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2616 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2618 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2621 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2622 if (IS_SWAP_FROM_SSE(Entry
))
2624 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2628 Page
= PFN_FROM_SSE(Entry
);
2629 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2630 if (SavedSwapEntry
!= 0)
2632 MmSetSavedSwapEntryPage(Page
, 0);
2633 MmFreeSwapPage(SavedSwapEntry
);
2635 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2640 MmUnlockSectionSegment(Segment
);
2644 MmpDeleteSection(PVOID ObjectBody
)
2646 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2648 /* Check if it's an ARM3, or ReactOS section */
2649 if (!MiIsRosSectionObject(Section
))
2651 MiDeleteARM3Section(ObjectBody
);
2655 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2656 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2661 PMM_SECTION_SEGMENT SectionSegments
;
2664 * NOTE: Section->ImageSection can be NULL for short time
2665 * during the section creating. If we fail for some reason
2666 * until the image section is properly initialized we shouldn't
2667 * process further here.
2669 if (Section
->ImageSection
== NULL
)
2672 SectionSegments
= Section
->ImageSection
->Segments
;
2673 NrSegments
= Section
->ImageSection
->NrSegments
;
2675 for (i
= 0; i
< NrSegments
; i
++)
2677 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2679 MmLockSectionSegment(&SectionSegments
[i
]);
2681 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2682 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2684 MmUnlockSectionSegment(&SectionSegments
[i
]);
2687 MmpFreePageFileSegment(&SectionSegments
[i
]);
2693 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2696 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2699 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2701 DPRINT("Freeing section segment\n");
2702 Section
->Segment
= NULL
;
2703 MmFinalizeSegment(Segment
);
2707 DPRINT("RefCount %d\n", RefCount
);
2714 * NOTE: Section->Segment can be NULL for short time
2715 * during the section creating.
2717 if (Section
->Segment
== NULL
)
2720 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2722 MmpFreePageFileSegment(Section
->Segment
);
2723 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2724 ExFreePool(Section
->Segment
);
2725 Section
->Segment
= NULL
;
2729 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2732 if (Section
->FileObject
!= NULL
)
2735 CcRosDereferenceCache(Section
->FileObject
);
2737 ObDereferenceObject(Section
->FileObject
);
2738 Section
->FileObject
= NULL
;
2743 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2745 IN ACCESS_MASK GrantedAccess
,
2746 IN ULONG ProcessHandleCount
,
2747 IN ULONG SystemHandleCount
)
2749 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2755 MmCreatePhysicalMemorySection(VOID
)
2757 PROS_SECTION_OBJECT PhysSection
;
2759 OBJECT_ATTRIBUTES Obj
;
2760 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2761 LARGE_INTEGER SectionSize
;
2765 * Create the section mapping physical memory
2767 SectionSize
.QuadPart
= 0xFFFFFFFF;
2768 InitializeObjectAttributes(&Obj
,
2770 OBJ_PERMANENT
| OBJ_KERNEL_EXCLUSIVE
,
2773 Status
= MmCreateSection((PVOID
)&PhysSection
,
2777 PAGE_EXECUTE_READWRITE
,
2781 if (!NT_SUCCESS(Status
))
2783 DPRINT1("Failed to create PhysicalMemory section\n");
2784 KeBugCheck(MEMORY_MANAGEMENT
);
2786 Status
= ObInsertObject(PhysSection
,
2792 if (!NT_SUCCESS(Status
))
2794 ObDereferenceObject(PhysSection
);
2796 ObCloseHandle(Handle
, KernelMode
);
2797 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2798 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2800 return(STATUS_SUCCESS
);
2806 MmInitSectionImplementation(VOID
)
2808 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2809 UNICODE_STRING Name
;
2811 DPRINT("Creating Section Object Type\n");
2813 /* Initialize the section based root */
2814 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2815 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2817 /* Initialize the Section object type */
2818 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2819 RtlInitUnicodeString(&Name
, L
"Section");
2820 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2821 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2822 ObjectTypeInitializer
.PoolType
= PagedPool
;
2823 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2824 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2825 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2826 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2827 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2828 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2829 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2831 MmCreatePhysicalMemorySection();
2833 return(STATUS_SUCCESS
);
2838 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2839 ACCESS_MASK DesiredAccess
,
2840 POBJECT_ATTRIBUTES ObjectAttributes
,
2841 PLARGE_INTEGER UMaximumSize
,
2842 ULONG SectionPageProtection
,
2843 ULONG AllocationAttributes
)
2845 * Create a section which is backed by the pagefile
2848 LARGE_INTEGER MaximumSize
;
2849 PROS_SECTION_OBJECT Section
;
2850 PMM_SECTION_SEGMENT Segment
;
2853 if (UMaximumSize
== NULL
)
2855 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2856 return(STATUS_INVALID_PARAMETER
);
2858 MaximumSize
= *UMaximumSize
;
2861 * Create the section
2863 Status
= ObCreateObject(ExGetPreviousMode(),
2864 MmSectionObjectType
,
2866 ExGetPreviousMode(),
2868 sizeof(ROS_SECTION_OBJECT
),
2871 (PVOID
*)(PVOID
)&Section
);
2872 if (!NT_SUCCESS(Status
))
2874 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2881 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2882 Section
->Type
= 'SC';
2883 Section
->Size
= 'TN';
2884 Section
->SectionPageProtection
= SectionPageProtection
;
2885 Section
->AllocationAttributes
= AllocationAttributes
;
2886 Section
->MaximumSize
= MaximumSize
;
2887 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2888 TAG_MM_SECTION_SEGMENT
);
2889 if (Segment
== NULL
)
2891 ObDereferenceObject(Section
);
2892 return(STATUS_NO_MEMORY
);
2894 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2895 Section
->Segment
= Segment
;
2896 Segment
->ReferenceCount
= 1;
2897 ExInitializeFastMutex(&Segment
->Lock
);
2898 Segment
->Image
.FileOffset
= 0;
2899 Segment
->Protection
= SectionPageProtection
;
2900 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2901 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2902 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2903 Segment
->WriteCopy
= FALSE
;
2904 Segment
->Image
.VirtualAddress
= 0;
2905 Segment
->Image
.Characteristics
= 0;
2906 *SectionObject
= Section
;
2907 MiInitializeSectionPageTable(Segment
);
2908 return(STATUS_SUCCESS
);
2913 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2914 ACCESS_MASK DesiredAccess
,
2915 POBJECT_ATTRIBUTES ObjectAttributes
,
2916 PLARGE_INTEGER UMaximumSize
,
2917 ULONG SectionPageProtection
,
2918 ULONG AllocationAttributes
,
2919 PFILE_OBJECT FileObject
)
2921 * Create a section backed by a data file
2924 PROS_SECTION_OBJECT Section
;
2926 LARGE_INTEGER MaximumSize
;
2927 PMM_SECTION_SEGMENT Segment
;
2928 FILE_STANDARD_INFORMATION FileInfo
;
2932 * Create the section
2934 Status
= ObCreateObject(ExGetPreviousMode(),
2935 MmSectionObjectType
,
2937 ExGetPreviousMode(),
2939 sizeof(ROS_SECTION_OBJECT
),
2943 if (!NT_SUCCESS(Status
))
2945 ObDereferenceObject(FileObject
);
2951 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2952 Section
->Type
= 'SC';
2953 Section
->Size
= 'TN';
2954 Section
->SectionPageProtection
= SectionPageProtection
;
2955 Section
->AllocationAttributes
= AllocationAttributes
;
2958 * FIXME: This is propably not entirely correct. We can't look into
2959 * the standard FCB header because it might not be initialized yet
2960 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2961 * standard file information is filled on first request).
2963 Status
= IoQueryFileInformation(FileObject
,
2964 FileStandardInformation
,
2965 sizeof(FILE_STANDARD_INFORMATION
),
2968 if (!NT_SUCCESS(Status
))
2970 ObDereferenceObject(Section
);
2971 ObDereferenceObject(FileObject
);
2976 * FIXME: Revise this once a locking order for file size changes is
2979 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2981 MaximumSize
= *UMaximumSize
;
2985 MaximumSize
= FileInfo
.EndOfFile
;
2986 /* Mapping zero-sized files isn't allowed. */
2987 if (MaximumSize
.QuadPart
== 0)
2989 ObDereferenceObject(Section
);
2990 ObDereferenceObject(FileObject
);
2991 return STATUS_MAPPED_FILE_SIZE_ZERO
;
2995 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2997 Status
= IoSetInformation(FileObject
,
2998 FileEndOfFileInformation
,
2999 sizeof(LARGE_INTEGER
),
3001 if (!NT_SUCCESS(Status
))
3003 ObDereferenceObject(Section
);
3004 ObDereferenceObject(FileObject
);
3005 return(STATUS_SECTION_NOT_EXTENDED
);
3009 if (FileObject
->SectionObjectPointer
== NULL
||
3010 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3012 ObDereferenceObject(Section
);
3013 ObDereferenceObject(FileObject
);
3014 return STATUS_INVALID_FILE_FOR_SECTION
;
3020 Status
= MmspWaitForFileLock(FileObject
);
3021 if (Status
!= STATUS_SUCCESS
)
3023 ObDereferenceObject(Section
);
3024 ObDereferenceObject(FileObject
);
3029 * If this file hasn't been mapped as a data file before then allocate a
3030 * section segment to describe the data file mapping
3032 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3034 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3035 TAG_MM_SECTION_SEGMENT
);
3036 if (Segment
== NULL
)
3038 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3039 ObDereferenceObject(Section
);
3040 ObDereferenceObject(FileObject
);
3041 return(STATUS_NO_MEMORY
);
3043 Section
->Segment
= Segment
;
3044 Segment
->ReferenceCount
= 1;
3045 ExInitializeFastMutex(&Segment
->Lock
);
3047 * Set the lock before assigning the segment to the file object
3049 ExAcquireFastMutex(&Segment
->Lock
);
3050 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3052 Segment
->Image
.FileOffset
= 0;
3053 Segment
->Protection
= SectionPageProtection
;
3054 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3055 Segment
->Image
.Characteristics
= 0;
3056 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3057 if (AllocationAttributes
& SEC_RESERVE
)
3059 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3063 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3064 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3066 Segment
->Image
.VirtualAddress
= 0;
3067 Segment
->Locked
= TRUE
;
3068 MiInitializeSectionPageTable(Segment
);
3073 * If the file is already mapped as a data file then we may need
3077 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3079 Section
->Segment
= Segment
;
3080 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3081 MmLockSectionSegment(Segment
);
3083 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3084 !(AllocationAttributes
& SEC_RESERVE
))
3086 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3087 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3090 MmUnlockSectionSegment(Segment
);
3091 Section
->FileObject
= FileObject
;
3092 Section
->MaximumSize
= MaximumSize
;
3094 CcRosReferenceCache(FileObject
);
3096 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3097 *SectionObject
= Section
;
3098 return(STATUS_SUCCESS
);
3102 TODO: not that great (declaring loaders statically, having to declare all of
3103 them, having to keep them extern, etc.), will fix in the future
3105 extern NTSTATUS NTAPI PeFmtCreateSection
3107 IN CONST VOID
* FileHeader
,
3108 IN SIZE_T FileHeaderSize
,
3110 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3112 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3113 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3116 extern NTSTATUS NTAPI ElfFmtCreateSection
3118 IN CONST VOID
* FileHeader
,
3119 IN SIZE_T FileHeaderSize
,
3121 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3123 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3124 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3127 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3138 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3140 SIZE_T SizeOfSegments
;
3141 PMM_SECTION_SEGMENT Segments
;
3143 /* TODO: check for integer overflow */
3144 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3146 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3148 TAG_MM_SECTION_SEGMENT
);
3151 RtlZeroMemory(Segments
, SizeOfSegments
);
3159 ExeFmtpReadFile(IN PVOID File
,
3160 IN PLARGE_INTEGER Offset
,
3163 OUT PVOID
* AllocBase
,
3164 OUT PULONG ReadSize
)
3167 LARGE_INTEGER FileOffset
;
3169 ULONG OffsetAdjustment
;
3173 PFILE_OBJECT FileObject
= File
;
3174 IO_STATUS_BLOCK Iosb
;
3176 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3180 KeBugCheck(MEMORY_MANAGEMENT
);
3183 FileOffset
= *Offset
;
3185 /* Negative/special offset: it cannot be used in this context */
3186 if(FileOffset
.u
.HighPart
< 0)
3188 KeBugCheck(MEMORY_MANAGEMENT
);
3191 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3192 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3193 FileOffset
.u
.LowPart
= AdjustOffset
;
3195 BufferSize
= Length
+ OffsetAdjustment
;
3196 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3198 /* Flush data since we're about to perform a non-cached read */
3199 CcFlushCache(FileObject
->SectionObjectPointer
,
3205 * It's ok to use paged pool, because this is a temporary buffer only used in
3206 * the loading of executables. The assumption is that MmCreateSection is
3207 * always called at low IRQLs and that these buffers don't survive a brief
3208 * initialization phase
3210 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3215 return STATUS_INSUFFICIENT_RESOURCES
;
3220 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3222 UsedSize
= (ULONG
)Iosb
.Information
;
3224 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3226 Status
= STATUS_IN_PAGE_ERROR
;
3227 ASSERT(!NT_SUCCESS(Status
));
3230 if(NT_SUCCESS(Status
))
3232 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3233 *AllocBase
= Buffer
;
3234 *ReadSize
= UsedSize
- OffsetAdjustment
;
3238 ExFreePoolWithTag(Buffer
, 'rXmM');
3245 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3246 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3247 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3252 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3256 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3258 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3259 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3266 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3270 MmspAssertSegmentsSorted(ImageSectionObject
);
3272 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3274 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3278 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3279 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3280 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3288 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3292 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3294 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3295 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3303 MmspCompareSegments(const void * x
,
3306 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3307 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3310 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3311 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3315 * Ensures an image section's segments are sorted in memory
3320 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3323 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3325 MmspAssertSegmentsSorted(ImageSectionObject
);
3329 qsort(ImageSectionObject
->Segments
,
3330 ImageSectionObject
->NrSegments
,
3331 sizeof(ImageSectionObject
->Segments
[0]),
3332 MmspCompareSegments
);
3338 * Ensures an image section's segments don't overlap in memory and don't have
3339 * gaps and don't have a null size. We let them map to overlapping file regions,
3340 * though - that's not necessarily an error
3345 MmspCheckSegmentBounds
3347 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3353 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3355 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3359 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3361 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3363 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3371 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3372 * page could be OK (Windows seems to be OK with them), and larger gaps
3373 * could lead to image sections spanning several discontiguous regions
3374 * (NtMapViewOfSection could then refuse to map them, and they could
3375 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3377 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3378 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3379 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3390 * Merges and pads an image section's segments until they all are page-aligned
3391 * and have a size that is a multiple of the page size
3396 MmspPageAlignSegments
3398 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3404 PMM_SECTION_SEGMENT EffectiveSegment
;
3406 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3408 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3413 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3415 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3418 * The first segment requires special handling
3422 ULONG_PTR VirtualAddress
;
3423 ULONG_PTR VirtualOffset
;
3425 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3427 /* Round down the virtual address to the nearest page */
3428 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3430 /* Round up the virtual size to the nearest page */
3431 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3432 EffectiveSegment
->Image
.VirtualAddress
;
3434 /* Adjust the raw address and size */
3435 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3437 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3443 * Garbage in, garbage out: unaligned base addresses make the file
3444 * offset point in curious and odd places, but that's what we were
3447 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3448 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3452 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3453 ULONG_PTR EndOfEffectiveSegment
;
3455 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3456 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3459 * The current segment begins exactly where the current effective
3460 * segment ended, therefore beginning a new effective segment
3462 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3465 ASSERT(LastSegment
<= i
);
3466 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3468 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3470 if (LastSegment
!= i
)
3473 * Copy the current segment. If necessary, the effective segment
3474 * will be expanded later
3476 *EffectiveSegment
= *Segment
;
3480 * Page-align the virtual size. We know for sure the virtual address
3483 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3484 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3487 * The current segment is still part of the current effective segment:
3488 * extend the effective segment to reflect this
3490 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3492 static const ULONG FlagsToProtection
[16] =
3500 PAGE_EXECUTE_READWRITE
,
3501 PAGE_EXECUTE_READWRITE
,
3506 PAGE_EXECUTE_WRITECOPY
,
3507 PAGE_EXECUTE_WRITECOPY
,
3508 PAGE_EXECUTE_WRITECOPY
,
3509 PAGE_EXECUTE_WRITECOPY
3512 unsigned ProtectionFlags
;
3515 * Extend the file size
3518 /* Unaligned segments must be contiguous within the file */
3519 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3520 EffectiveSegment
->RawLength
.QuadPart
))
3525 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3528 * Extend the virtual size
3530 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3532 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3533 EffectiveSegment
->Image
.VirtualAddress
;
3536 * Merge the protection
3538 EffectiveSegment
->Protection
|= Segment
->Protection
;
3540 /* Clean up redundance */
3541 ProtectionFlags
= 0;
3543 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3544 ProtectionFlags
|= 1 << 0;
3546 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3547 ProtectionFlags
|= 1 << 1;
3549 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3550 ProtectionFlags
|= 1 << 2;
3552 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3553 ProtectionFlags
|= 1 << 3;
3555 ASSERT(ProtectionFlags
< 16);
3556 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3558 /* If a segment was required to be shared and cannot, fail */
3559 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3560 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3566 * We assume no holes between segments at this point
3570 KeBugCheck(MEMORY_MANAGEMENT
);
3574 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3580 ExeFmtpCreateImageSection(PFILE_OBJECT FileObject
,
3581 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3583 LARGE_INTEGER Offset
;
3585 PVOID FileHeaderBuffer
;
3586 ULONG FileHeaderSize
;
3588 ULONG OldNrSegments
;
3593 * Read the beginning of the file (2 pages). Should be enough to contain
3594 * all (or most) of the headers
3596 Offset
.QuadPart
= 0;
3598 Status
= ExeFmtpReadFile (FileObject
,
3605 if (!NT_SUCCESS(Status
))
3608 if (FileHeaderSize
== 0)
3610 ExFreePool(FileHeaderBuffer
);
3611 return STATUS_UNSUCCESSFUL
;
3615 * Look for a loader that can handle this executable
3617 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3619 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3622 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3628 ExeFmtpAllocateSegments
);
3630 if (!NT_SUCCESS(Status
))
3632 if (ImageSectionObject
->Segments
)
3634 ExFreePool(ImageSectionObject
->Segments
);
3635 ImageSectionObject
->Segments
= NULL
;
3639 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3643 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3646 * No loader handled the format
3648 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3650 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3651 ASSERT(!NT_SUCCESS(Status
));
3654 if (!NT_SUCCESS(Status
))
3657 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3662 /* FIXME? are these values platform-dependent? */
3663 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3664 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3666 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3667 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3669 if(ImageSectionObject
->BasedAddress
== NULL
)
3671 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3672 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3674 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3678 * And now the fun part: fixing the segments
3681 /* Sort them by virtual address */
3682 MmspSortSegments(ImageSectionObject
, Flags
);
3684 /* Ensure they don't overlap in memory */
3685 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3686 return STATUS_INVALID_IMAGE_FORMAT
;
3688 /* Ensure they are aligned */
3689 OldNrSegments
= ImageSectionObject
->NrSegments
;
3691 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3692 return STATUS_INVALID_IMAGE_FORMAT
;
3694 /* Trim them if the alignment phase merged some of them */
3695 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3697 PMM_SECTION_SEGMENT Segments
;
3698 SIZE_T SizeOfSegments
;
3700 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3702 Segments
= ExAllocatePoolWithTag(PagedPool
,
3704 TAG_MM_SECTION_SEGMENT
);
3706 if (Segments
== NULL
)
3707 return STATUS_INSUFFICIENT_RESOURCES
;
3709 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3710 ExFreePool(ImageSectionObject
->Segments
);
3711 ImageSectionObject
->Segments
= Segments
;
3714 /* And finish their initialization */
3715 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3717 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3718 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3719 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3722 ASSERT(NT_SUCCESS(Status
));
3727 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3728 ACCESS_MASK DesiredAccess
,
3729 POBJECT_ATTRIBUTES ObjectAttributes
,
3730 PLARGE_INTEGER UMaximumSize
,
3731 ULONG SectionPageProtection
,
3732 ULONG AllocationAttributes
,
3733 PFILE_OBJECT FileObject
)
3735 PROS_SECTION_OBJECT Section
;
3737 PMM_SECTION_SEGMENT SectionSegments
;
3738 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3741 if (FileObject
== NULL
)
3742 return STATUS_INVALID_FILE_FOR_SECTION
;
3745 if (!CcIsFileCached(FileObject
))
3747 DPRINT1("Denying section creation due to missing cache initialization\n");
3748 return STATUS_INVALID_FILE_FOR_SECTION
;
3753 * Create the section
3755 Status
= ObCreateObject (ExGetPreviousMode(),
3756 MmSectionObjectType
,
3758 ExGetPreviousMode(),
3760 sizeof(ROS_SECTION_OBJECT
),
3763 (PVOID
*)(PVOID
)&Section
);
3764 if (!NT_SUCCESS(Status
))
3766 ObDereferenceObject(FileObject
);
3773 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3774 Section
->Type
= 'SC';
3775 Section
->Size
= 'TN';
3776 Section
->SectionPageProtection
= SectionPageProtection
;
3777 Section
->AllocationAttributes
= AllocationAttributes
;
3779 if (FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3781 NTSTATUS StatusExeFmt
;
3783 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3784 if (ImageSectionObject
== NULL
)
3786 ObDereferenceObject(FileObject
);
3787 ObDereferenceObject(Section
);
3788 return(STATUS_NO_MEMORY
);
3791 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3793 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3795 if (!NT_SUCCESS(StatusExeFmt
))
3797 if(ImageSectionObject
->Segments
!= NULL
)
3798 ExFreePool(ImageSectionObject
->Segments
);
3801 * If image file is empty, then return that the file is invalid for section
3803 Status
= StatusExeFmt
;
3804 if (StatusExeFmt
== STATUS_END_OF_FILE
)
3806 Status
= STATUS_INVALID_FILE_FOR_SECTION
;
3809 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3810 ObDereferenceObject(Section
);
3811 ObDereferenceObject(FileObject
);
3815 Section
->ImageSection
= ImageSectionObject
;
3816 ASSERT(ImageSectionObject
->Segments
);
3821 Status
= MmspWaitForFileLock(FileObject
);
3822 if (!NT_SUCCESS(Status
))
3824 ExFreePool(ImageSectionObject
->Segments
);
3825 ExFreePool(ImageSectionObject
);
3826 ObDereferenceObject(Section
);
3827 ObDereferenceObject(FileObject
);
3831 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3832 ImageSectionObject
, NULL
))
3835 * An other thread has initialized the same image in the background
3837 ExFreePool(ImageSectionObject
->Segments
);
3838 ExFreePool(ImageSectionObject
);
3839 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3840 Section
->ImageSection
= ImageSectionObject
;
3841 SectionSegments
= ImageSectionObject
->Segments
;
3843 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3845 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3849 Status
= StatusExeFmt
;
3856 Status
= MmspWaitForFileLock(FileObject
);
3857 if (Status
!= STATUS_SUCCESS
)
3859 ObDereferenceObject(Section
);
3860 ObDereferenceObject(FileObject
);
3864 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3865 Section
->ImageSection
= ImageSectionObject
;
3866 SectionSegments
= ImageSectionObject
->Segments
;
3869 * Otherwise just reference all the section segments
3871 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3873 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3876 Status
= STATUS_SUCCESS
;
3878 Section
->FileObject
= FileObject
;
3880 CcRosReferenceCache(FileObject
);
3882 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3883 *SectionObject
= Section
;
3890 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3891 PROS_SECTION_OBJECT Section
,
3892 PMM_SECTION_SEGMENT Segment
,
3897 ULONG AllocationType
)
3903 if (Segment
->WriteCopy
)
3905 /* We have to do this because the not present fault
3906 * and access fault handlers depend on the protection
3907 * that should be granted AFTER the COW fault takes
3908 * place to be in Region->Protect. The not present fault
3909 * handler changes this to the correct protection for COW when
3910 * mapping the pages into the process's address space. If a COW
3911 * fault takes place, the access fault handler sets the page protection
3912 * to these values for the newly copied pages
3914 if (Protect
== PAGE_WRITECOPY
)
3915 Protect
= PAGE_READWRITE
;
3916 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3917 Protect
= PAGE_EXECUTE_READWRITE
;
3920 if (*BaseAddress
== NULL
)
3921 Granularity
= MM_ALLOCATION_GRANULARITY
;
3923 Granularity
= PAGE_SIZE
;
3926 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3928 LARGE_INTEGER FileOffset
;
3929 FileOffset
.QuadPart
= ViewOffset
;
3930 ObReferenceObject(Section
);
3931 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3934 Status
= MmCreateMemoryArea(AddressSpace
,
3935 MEMORY_AREA_SECTION_VIEW
,
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 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3956 MArea
->VadNode
.u
.VadFlags
.VadType
= VadImageMap
;
3959 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3960 ViewSize
, 0, Protect
);
3962 return(STATUS_SUCCESS
);
3967 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3968 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3972 PFILE_OBJECT FileObject
;
3973 PROS_SHARED_CACHE_MAP SharedCacheMap
;
3975 LARGE_INTEGER Offset
;
3976 SWAPENTRY SavedSwapEntry
;
3977 PROS_SECTION_OBJECT Section
;
3978 PMM_SECTION_SEGMENT Segment
;
3979 PMMSUPPORT AddressSpace
;
3982 AddressSpace
= (PMMSUPPORT
)Context
;
3983 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3985 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3987 Offset
.QuadPart
= ((ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)) +
3988 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3990 Section
= MemoryArea
->Data
.SectionData
.Section
;
3991 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3993 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3994 while (Entry
&& MM_IS_WAIT_PTE(Entry
))
3996 MmUnlockSectionSegment(Segment
);
3997 MmUnlockAddressSpace(AddressSpace
);
3999 MiWaitForPageEvent(NULL
, NULL
);
4001 MmLockAddressSpace(AddressSpace
);
4002 MmLockSectionSegment(Segment
);
4003 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4007 * For a dirty, datafile, non-private page mark it as dirty in the
4010 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4012 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4015 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4016 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4017 CcRosMarkDirtyFile(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4019 ASSERT(SwapEntry
== 0);
4028 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4030 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4031 KeBugCheck(MEMORY_MANAGEMENT
);
4033 MmFreeSwapPage(SwapEntry
);
4037 if (IS_SWAP_FROM_SSE(Entry
) ||
4038 Page
!= PFN_FROM_SSE(Entry
))
4043 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4045 DPRINT1("Found a private page in a pagefile section.\n");
4046 KeBugCheck(MEMORY_MANAGEMENT
);
4049 * Just dereference private pages
4051 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4052 if (SavedSwapEntry
!= 0)
4054 MmFreeSwapPage(SavedSwapEntry
);
4055 MmSetSavedSwapEntryPage(Page
, 0);
4057 MmDeleteRmap(Page
, Process
, Address
);
4058 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4062 MmDeleteRmap(Page
, Process
, Address
);
4063 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4069 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4073 PMEMORY_AREA MemoryArea
;
4074 PROS_SECTION_OBJECT Section
;
4075 PMM_SECTION_SEGMENT Segment
;
4076 PLIST_ENTRY CurrentEntry
;
4077 PMM_REGION CurrentRegion
;
4078 PLIST_ENTRY RegionListHead
;
4080 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4082 if (MemoryArea
== NULL
)
4084 return(STATUS_UNSUCCESSFUL
);
4087 Section
= MemoryArea
->Data
.SectionData
.Section
;
4088 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4091 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4093 MmUnlockAddressSpace(AddressSpace
);
4094 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4095 MmLockAddressSpace(AddressSpace
);
4101 MemoryArea
->DeleteInProgress
= TRUE
;
4103 MmLockSectionSegment(Segment
);
4105 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4106 while (!IsListEmpty(RegionListHead
))
4108 CurrentEntry
= RemoveHeadList(RegionListHead
);
4109 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4110 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4113 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4115 Status
= MmFreeMemoryArea(AddressSpace
,
4122 Status
= MmFreeMemoryArea(AddressSpace
,
4127 MmUnlockSectionSegment(Segment
);
4128 ObDereferenceObject(Section
);
4134 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4135 IN PVOID BaseAddress
,
4136 IN BOOLEAN SkipDebuggerNotify
)
4139 PMEMORY_AREA MemoryArea
;
4140 PMMSUPPORT AddressSpace
;
4141 PROS_SECTION_OBJECT Section
;
4142 PVOID ImageBaseAddress
= 0;
4144 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4145 Process
, BaseAddress
);
4149 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4151 MmLockAddressSpace(AddressSpace
);
4152 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4154 if (MemoryArea
== NULL
||
4155 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4156 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4157 MemoryArea
->DeleteInProgress
)
4159 if (MemoryArea
) ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4160 MmUnlockAddressSpace(AddressSpace
);
4161 return STATUS_NOT_MAPPED_VIEW
;
4164 Section
= MemoryArea
->Data
.SectionData
.Section
;
4166 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4170 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4171 PMM_SECTION_SEGMENT SectionSegments
;
4172 PMM_SECTION_SEGMENT Segment
;
4174 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4175 ImageSectionObject
= Section
->ImageSection
;
4176 SectionSegments
= ImageSectionObject
->Segments
;
4177 NrSegments
= ImageSectionObject
->NrSegments
;
4179 MemoryArea
->DeleteInProgress
= TRUE
;
4181 /* Search for the current segment within the section segments
4182 * and calculate the image base address */
4183 for (i
= 0; i
< NrSegments
; i
++)
4185 if (Segment
== &SectionSegments
[i
])
4187 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4191 if (i
>= NrSegments
)
4193 KeBugCheck(MEMORY_MANAGEMENT
);
4196 for (i
= 0; i
< NrSegments
; i
++)
4198 PVOID SBaseAddress
= (PVOID
)
4199 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4201 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4202 if (!NT_SUCCESS(Status
))
4204 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4205 SBaseAddress
, Process
, Status
);
4206 ASSERT(NT_SUCCESS(Status
));
4212 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4213 if (!NT_SUCCESS(Status
))
4215 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4216 BaseAddress
, Process
, Status
);
4217 ASSERT(NT_SUCCESS(Status
));
4221 MmUnlockAddressSpace(AddressSpace
);
4223 /* Notify debugger */
4224 if (ImageBaseAddress
&& !SkipDebuggerNotify
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4226 return(STATUS_SUCCESS
);
4233 * Queries the information of a section object.
4235 * @param SectionHandle
4236 * Handle to the section object. It must be opened with SECTION_QUERY
4238 * @param SectionInformationClass
4239 * Index to a certain information structure. Can be either
4240 * SectionBasicInformation or SectionImageInformation. The latter
4241 * is valid only for sections that were created with the SEC_IMAGE
4243 * @param SectionInformation
4244 * Caller supplies storage for resulting information.
4246 * Size of the supplied storage.
4247 * @param ResultLength
4257 _In_ HANDLE SectionHandle
,
4258 _In_ SECTION_INFORMATION_CLASS SectionInformationClass
,
4259 _Out_ PVOID SectionInformation
,
4260 _In_ SIZE_T SectionInformationLength
,
4261 _Out_opt_ PSIZE_T ResultLength
)
4264 KPROCESSOR_MODE PreviousMode
;
4268 PreviousMode
= ExGetPreviousMode();
4269 if (PreviousMode
!= KernelMode
)
4273 ProbeForWrite(SectionInformation
,
4274 SectionInformationLength
,
4276 if (ResultLength
!= NULL
)
4278 ProbeForWrite(ResultLength
,
4279 sizeof(*ResultLength
),
4283 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4285 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4290 if (SectionInformationClass
== SectionBasicInformation
)
4292 if (SectionInformationLength
< sizeof(SECTION_BASIC_INFORMATION
))
4294 return STATUS_INFO_LENGTH_MISMATCH
;
4297 else if (SectionInformationClass
== SectionImageInformation
)
4299 if (SectionInformationLength
< sizeof(SECTION_IMAGE_INFORMATION
))
4301 return STATUS_INFO_LENGTH_MISMATCH
;
4306 return STATUS_INVALID_INFO_CLASS
;
4309 Status
= ObReferenceObjectByHandle(SectionHandle
,
4311 MmSectionObjectType
,
4313 (PVOID
*)(PVOID
)&Section
,
4315 if (!NT_SUCCESS(Status
))
4317 DPRINT1("Failed to reference section: 0x%lx\n", Status
);
4321 if (MiIsRosSectionObject(Section
))
4323 PROS_SECTION_OBJECT RosSection
= (PROS_SECTION_OBJECT
)Section
;
4325 switch (SectionInformationClass
)
4327 case SectionBasicInformation
:
4329 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4333 Sbi
->Attributes
= RosSection
->AllocationAttributes
;
4334 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4336 Sbi
->BaseAddress
= 0;
4337 Sbi
->Size
.QuadPart
= 0;
4341 Sbi
->BaseAddress
= (PVOID
)RosSection
->Segment
->Image
.VirtualAddress
;
4342 Sbi
->Size
.QuadPart
= RosSection
->Segment
->Length
.QuadPart
;
4345 if (ResultLength
!= NULL
)
4347 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4349 Status
= STATUS_SUCCESS
;
4351 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4353 Status
= _SEH2_GetExceptionCode();
4360 case SectionImageInformation
:
4362 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4366 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4368 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4369 ImageSectionObject
= RosSection
->ImageSection
;
4371 *Sii
= ImageSectionObject
->ImageInformation
;
4374 if (ResultLength
!= NULL
)
4376 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4378 Status
= STATUS_SUCCESS
;
4380 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4382 Status
= _SEH2_GetExceptionCode();
4392 switch(SectionInformationClass
)
4394 case SectionBasicInformation
:
4396 SECTION_BASIC_INFORMATION Sbi
;
4398 Sbi
.Size
= Section
->SizeOfSection
;
4399 Sbi
.BaseAddress
= (PVOID
)Section
->Address
.StartingVpn
;
4402 if (Section
->u
.Flags
.Image
)
4403 Sbi
.Attributes
|= SEC_IMAGE
;
4404 if (Section
->u
.Flags
.Commit
)
4405 Sbi
.Attributes
|= SEC_COMMIT
;
4406 if (Section
->u
.Flags
.Reserve
)
4407 Sbi
.Attributes
|= SEC_RESERVE
;
4408 if (Section
->u
.Flags
.File
)
4409 Sbi
.Attributes
|= SEC_FILE
;
4410 if (Section
->u
.Flags
.Image
)
4411 Sbi
.Attributes
|= SEC_IMAGE
;
4413 /* FIXME : Complete/test the list of flags passed back from NtCreateSection */
4417 *((SECTION_BASIC_INFORMATION
*)SectionInformation
) = Sbi
;
4419 *ResultLength
= sizeof(Sbi
);
4421 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4423 Status
= _SEH2_GetExceptionCode();
4428 case SectionImageInformation
:
4430 if (!Section
->u
.Flags
.Image
)
4432 Status
= STATUS_SECTION_NOT_IMAGE
;
4436 /* Currently not supported */
4444 ObDereferenceObject(Section
);
4449 /**********************************************************************
4451 * MmMapViewOfSection
4454 * Maps a view of a section into the virtual address space of a
4459 * Pointer to the section object.
4462 * Pointer to the process.
4465 * Desired base address (or NULL) on entry;
4466 * Actual base address of the view on exit.
4469 * Number of high order address bits that must be zero.
4472 * Size in bytes of the initially committed section of
4476 * Offset in bytes from the beginning of the section
4477 * to the beginning of the view.
4480 * Desired length of map (or zero to map all) on entry
4481 * Actual length mapped on exit.
4483 * InheritDisposition
4484 * Specified how the view is to be shared with
4488 * Type of allocation for the pages.
4491 * Protection for the committed region of the view.
4499 MmMapViewOfSection(IN PVOID SectionObject
,
4500 IN PEPROCESS Process
,
4501 IN OUT PVOID
*BaseAddress
,
4502 IN ULONG_PTR ZeroBits
,
4503 IN SIZE_T CommitSize
,
4504 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4505 IN OUT PSIZE_T ViewSize
,
4506 IN SECTION_INHERIT InheritDisposition
,
4507 IN ULONG AllocationType
,
4510 PROS_SECTION_OBJECT Section
;
4511 PMMSUPPORT AddressSpace
;
4513 NTSTATUS Status
= STATUS_SUCCESS
;
4514 BOOLEAN NotAtBase
= FALSE
;
4516 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4518 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4519 return MmMapViewOfArm3Section(SectionObject
,
4533 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4535 return STATUS_INVALID_PAGE_PROTECTION
;
4538 /* FIXME: We should keep this, but it would break code checking equality */
4539 Protect
&= ~PAGE_NOCACHE
;
4541 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4542 AddressSpace
= &Process
->Vm
;
4544 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4546 MmLockAddressSpace(AddressSpace
);
4548 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4552 ULONG_PTR ImageBase
;
4554 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4555 PMM_SECTION_SEGMENT SectionSegments
;
4557 ImageSectionObject
= Section
->ImageSection
;
4558 SectionSegments
= ImageSectionObject
->Segments
;
4559 NrSegments
= ImageSectionObject
->NrSegments
;
4561 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4564 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4568 for (i
= 0; i
< NrSegments
; i
++)
4570 ULONG_PTR MaxExtent
;
4571 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4572 SectionSegments
[i
].Length
.QuadPart
);
4573 ImageSize
= max(ImageSize
, MaxExtent
);
4576 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4578 /* Check for an illegal base address */
4579 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4580 ((ImageBase
+ ImageSize
) < ImageSize
))
4582 ASSERT(*BaseAddress
== NULL
);
4583 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4584 MM_VIRTMEM_GRANULARITY
);
4587 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4589 ASSERT(*BaseAddress
== NULL
);
4590 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4594 /* Check there is enough space to map the section at that point. */
4595 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4596 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4598 /* Fail if the user requested a fixed base address. */
4599 if ((*BaseAddress
) != NULL
)
4601 MmUnlockAddressSpace(AddressSpace
);
4602 return(STATUS_CONFLICTING_ADDRESSES
);
4604 /* Otherwise find a gap to map the image. */
4605 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4608 MmUnlockAddressSpace(AddressSpace
);
4609 return(STATUS_CONFLICTING_ADDRESSES
);
4611 /* Remember that we loaded image at a different base address */
4615 for (i
= 0; i
< NrSegments
; i
++)
4617 PVOID SBaseAddress
= (PVOID
)
4618 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4619 MmLockSectionSegment(&SectionSegments
[i
]);
4620 Status
= MmMapViewOfSegment(AddressSpace
,
4622 &SectionSegments
[i
],
4624 SectionSegments
[i
].Length
.LowPart
,
4625 SectionSegments
[i
].Protection
,
4628 MmUnlockSectionSegment(&SectionSegments
[i
]);
4629 if (!NT_SUCCESS(Status
))
4631 MmUnlockAddressSpace(AddressSpace
);
4636 *BaseAddress
= (PVOID
)ImageBase
;
4637 *ViewSize
= ImageSize
;
4641 /* check for write access */
4642 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4643 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4645 MmUnlockAddressSpace(AddressSpace
);
4646 return STATUS_SECTION_PROTECTION
;
4648 /* check for read access */
4649 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4650 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4652 MmUnlockAddressSpace(AddressSpace
);
4653 return STATUS_SECTION_PROTECTION
;
4655 /* check for execute access */
4656 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4657 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4659 MmUnlockAddressSpace(AddressSpace
);
4660 return STATUS_SECTION_PROTECTION
;
4663 if (SectionOffset
== NULL
)
4669 ViewOffset
= SectionOffset
->u
.LowPart
;
4672 if ((ViewOffset
% PAGE_SIZE
) != 0)
4674 MmUnlockAddressSpace(AddressSpace
);
4675 return(STATUS_MAPPED_ALIGNMENT
);
4678 if ((*ViewSize
) == 0)
4680 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4682 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4684 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4687 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4689 MmLockSectionSegment(Section
->Segment
);
4690 Status
= MmMapViewOfSegment(AddressSpace
,
4697 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4698 MmUnlockSectionSegment(Section
->Segment
);
4699 if (!NT_SUCCESS(Status
))
4701 MmUnlockAddressSpace(AddressSpace
);
4706 MmUnlockAddressSpace(AddressSpace
);
4707 ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4710 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4712 Status
= STATUS_SUCCESS
;
4721 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4722 IN PLARGE_INTEGER NewFileSize
)
4724 /* Check whether an ImageSectionObject exists */
4725 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4727 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4731 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4733 PMM_SECTION_SEGMENT Segment
;
4735 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4738 if (Segment
->ReferenceCount
!= 0)
4741 CC_FILE_SIZES FileSizes
;
4743 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4746 /* Check size of file */
4747 if (SectionObjectPointer
->SharedCacheMap
)
4749 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4754 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4763 /* Check size of file */
4764 if (SectionObjectPointer
->SharedCacheMap
)
4766 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4767 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4776 /* Something must gone wrong
4777 * how can we have a Section but no
4779 DPRINT("ERROR: DataSectionObject without reference!\n");
4783 DPRINT("FIXME: didn't check for outstanding write probes\n");
4795 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4796 IN MMFLUSH_TYPE FlushType
)
4798 BOOLEAN Result
= TRUE
;
4800 PMM_SECTION_SEGMENT Segment
;
4805 case MmFlushForDelete
:
4806 if (SectionObjectPointer
->ImageSectionObject
||
4807 SectionObjectPointer
->DataSectionObject
)
4812 CcRosRemoveIfClosed(SectionObjectPointer
);
4815 case MmFlushForWrite
:
4817 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4819 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4822 if (SectionObjectPointer
->ImageSectionObject
)
4824 DPRINT1("SectionObject has ImageSection\n");
4830 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4832 DPRINT("Result %d\n", Result
);
4844 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4845 OUT PVOID
* MappedBase
,
4846 IN OUT PSIZE_T ViewSize
)
4848 PROS_SECTION_OBJECT Section
;
4849 PMMSUPPORT AddressSpace
;
4853 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4855 return MiMapViewInSystemSpace(SectionObject
,
4861 DPRINT("MmMapViewInSystemSpace() called\n");
4863 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4864 AddressSpace
= MmGetKernelAddressSpace();
4866 MmLockAddressSpace(AddressSpace
);
4869 if ((*ViewSize
) == 0)
4871 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4873 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4875 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4878 MmLockSectionSegment(Section
->Segment
);
4881 Status
= MmMapViewOfSegment(AddressSpace
,
4890 MmUnlockSectionSegment(Section
->Segment
);
4891 MmUnlockAddressSpace(AddressSpace
);
4898 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4900 PMMSUPPORT AddressSpace
;
4903 DPRINT("MmUnmapViewInSystemSpace() called\n");
4905 AddressSpace
= MmGetKernelAddressSpace();
4907 MmLockAddressSpace(AddressSpace
);
4909 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4911 MmUnlockAddressSpace(AddressSpace
);
4916 /**********************************************************************
4921 * Creates a section object.
4924 * SectionObject (OUT)
4925 * Caller supplied storage for the resulting pointer
4926 * to a SECTION_OBJECT instance;
4929 * Specifies the desired access to the section can be a
4931 * STANDARD_RIGHTS_REQUIRED |
4933 * SECTION_MAP_WRITE |
4934 * SECTION_MAP_READ |
4935 * SECTION_MAP_EXECUTE
4937 * ObjectAttributes [OPTIONAL]
4938 * Initialized attributes for the object can be used
4939 * to create a named section;
4942 * Maximizes the size of the memory section. Must be
4943 * non-NULL for a page-file backed section.
4944 * If value specified for a mapped file and the file is
4945 * not large enough, file will be extended.
4947 * SectionPageProtection
4948 * Can be a combination of:
4954 * AllocationAttributes
4955 * Can be a combination of:
4960 * Handle to a file to create a section mapped to a file
4961 * instead of a memory backed section;
4972 MmCreateSection (OUT PVOID
* Section
,
4973 IN ACCESS_MASK DesiredAccess
,
4974 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4975 IN PLARGE_INTEGER MaximumSize
,
4976 IN ULONG SectionPageProtection
,
4977 IN ULONG AllocationAttributes
,
4978 IN HANDLE FileHandle OPTIONAL
,
4979 IN PFILE_OBJECT FileObject OPTIONAL
)
4983 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4985 /* Check if an ARM3 section is being created instead */
4986 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4988 if (!(FileObject
) && !(FileHandle
))
4990 return MmCreateArm3Section(Section
,
4994 SectionPageProtection
,
4995 AllocationAttributes
&~ 1,
5001 /* Convert section flag to page flag */
5002 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
5004 /* Check to make sure the protection is correct. Nt* does this already */
5005 Protection
= MiMakeProtectionMask(SectionPageProtection
);
5006 if (Protection
== MM_INVALID_PROTECTION
)
5008 DPRINT1("Page protection is invalid\n");
5009 return STATUS_INVALID_PAGE_PROTECTION
;
5012 /* Check if this is going to be a data or image backed file section */
5013 if ((FileHandle
) || (FileObject
))
5015 /* These cannot be mapped with large pages */
5016 if (AllocationAttributes
& SEC_LARGE_PAGES
)
5018 DPRINT1("Large pages cannot be used with an image mapping\n");
5019 return STATUS_INVALID_PARAMETER_6
;
5022 /* Did the caller pass an object? */
5025 /* Reference the object directly */
5026 ObReferenceObject(FileObject
);
5030 /* Reference the file handle to get the object */
5031 Status
= ObReferenceObjectByHandle(FileHandle
,
5032 MmMakeFileAccess
[Protection
],
5034 ExGetPreviousMode(),
5035 (PVOID
*)&FileObject
,
5037 if (!NT_SUCCESS(Status
))
5039 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
5046 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
5047 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
5050 #ifndef NEWCC // A hack for initializing caching.
5051 // This is needed only in the old case.
5054 IO_STATUS_BLOCK Iosb
;
5057 LARGE_INTEGER ByteOffset
;
5058 ByteOffset
.QuadPart
= 0;
5059 Status
= ZwReadFile(FileHandle
,
5068 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5070 DPRINT1("CC failure: %lx\n", Status
);
5072 ObDereferenceObject(FileObject
);
5075 // Caching is initialized...
5077 // Hack of the hack: actually, it might not be initialized if FSD init on effective right and if file is null-size
5078 // In such case, force cache by initiating a write IRP
5079 if (Status
== STATUS_END_OF_FILE
&& !(AllocationAttributes
& SEC_IMAGE
) && FileObject
!= NULL
&&
5080 (FileObject
->SectionObjectPointer
== NULL
|| FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
))
5083 Status
= ZwWriteFile(FileHandle
,
5092 if (NT_SUCCESS(Status
))
5095 Zero
.QuadPart
= 0LL;
5097 Status
= IoSetInformation(FileObject
,
5098 FileEndOfFileInformation
,
5099 sizeof(LARGE_INTEGER
),
5101 ASSERT(NT_SUCCESS(Status
));
5107 if (AllocationAttributes
& SEC_IMAGE
)
5109 Status
= MmCreateImageSection(SectionObject
,
5113 SectionPageProtection
,
5114 AllocationAttributes
,
5118 else if (FileHandle
!= NULL
)
5120 Status
= MmCreateDataFileSection(SectionObject
,
5124 SectionPageProtection
,
5125 AllocationAttributes
,
5129 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5131 Status
= MmCreateCacheSection(SectionObject
,
5135 SectionPageProtection
,
5136 AllocationAttributes
,
5142 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5144 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5146 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5147 Status
= MmCreatePageFileSection(SectionObject
,
5151 SectionPageProtection
,
5152 AllocationAttributes
);
5154 ObDereferenceObject(FileObject
);