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_HDR32_MAGIC
:
363 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
368 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
369 nStatus
= STATUS_INVALID_IMAGE_WIN_64
;
372 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
375 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
376 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
378 /* See [1], section 3.4.2 */
379 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
381 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
382 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
384 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
385 DIE(("The section alignment is smaller than the file alignment\n"));
387 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
388 nFileAlignment
= piohOptHeader
->FileAlignment
;
390 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
391 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
395 nSectionAlignment
= PAGE_SIZE
;
396 nFileAlignment
= PAGE_SIZE
;
399 ASSERT(IsPowerOf2(nSectionAlignment
));
400 ASSERT(IsPowerOf2(nFileAlignment
));
402 switch(piohOptHeader
->Magic
)
405 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
407 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
408 ImageBase
= piohOptHeader
->ImageBase
;
410 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
411 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
413 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
414 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
416 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
417 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
419 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
421 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
423 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
424 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
426 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
427 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
431 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
433 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
434 piohOptHeader
->AddressOfEntryPoint
);
437 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
438 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
440 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
442 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
444 if (piohOptHeader
->AddressOfEntryPoint
== 0)
446 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
450 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
451 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
453 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
455 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
458 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
459 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
460 * magic to any binary.
462 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
463 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
464 * the SxS support -- at which point, duh, this should be removed.
466 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
468 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
475 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
477 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
479 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
481 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
483 ImageBase
= pioh64OptHeader
->ImageBase
;
484 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
485 DIE(("ImageBase exceeds the address space\n"));
488 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
490 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
491 DIE(("SizeOfImage exceeds the address space\n"));
493 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
496 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
498 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
499 DIE(("SizeOfStackReserve exceeds the address space\n"));
501 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
504 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
506 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
507 DIE(("SizeOfStackCommit exceeds the address space\n"));
509 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
512 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
514 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
516 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
517 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
519 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
520 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
524 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
526 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
527 pioh64OptHeader
->AddressOfEntryPoint
);
530 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
531 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
533 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
535 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
537 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
539 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
543 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
544 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
546 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
547 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
554 /* [1], section 3.4.2 */
555 if((ULONG_PTR
)ImageBase
% 0x10000)
556 DIE(("ImageBase is not aligned on a 64KB boundary"));
558 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
559 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
560 ImageSectionObject
->ImageInformation
.GpValue
= 0;
561 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
562 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
564 /* SECTION HEADERS */
565 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
567 /* see [1], section 3.3 */
568 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
569 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
572 * the additional segment is for the file's headers. They need to be present for
573 * the benefit of the dynamic loader (to locate exports, defaults for thread
574 * parameters, resources, etc.)
576 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
578 /* file offset for the section headers */
579 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
580 DIE(("Offset overflow\n"));
582 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
583 DIE(("Offset overflow\n"));
585 /* size of the section headers */
586 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
587 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
589 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
590 DIE(("Section headers too large\n"));
592 /* size of the executable's headers */
593 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
595 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
596 // DIE(("SizeOfHeaders is not aligned\n"));
598 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
599 DIE(("The section headers overflow SizeOfHeaders\n"));
601 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
603 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
604 DIE(("Overflow aligning the size of headers\n"));
611 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
612 /* WARNING: piohOptHeader IS NO LONGER USABLE */
613 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
615 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
616 pishSectionHeaders
= NULL
;
620 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
621 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
623 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
624 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
628 * the buffer doesn't contain the section headers, or the alignment is wrong:
629 * read the headers from the file
631 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
632 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
637 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
639 /* read the header from the file */
640 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
642 if(!NT_SUCCESS(nStatus
))
643 DIE(("ReadFile failed with status %08X\n", nStatus
));
647 ASSERT(cbReadSize
> 0);
649 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
651 /* the buffer doesn't contain all the section headers */
652 if(cbReadSize
< cbSectionHeadersSize
)
653 DIE(("The file doesn't contain all of the section headers\n"));
655 pishSectionHeaders
= pData
;
657 /* object still not aligned: copy it to the beginning of the buffer */
658 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
660 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
661 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
662 pishSectionHeaders
= pBuffer
;
667 /* allocate the segments */
668 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
669 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
671 if(ImageSectionObject
->Segments
== NULL
)
672 DIE(("AllocateSegments failed\n"));
674 /* initialize the headers segment */
675 pssSegments
= ImageSectionObject
->Segments
;
677 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
679 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
680 DIE(("Cannot align the size of the section headers\n"));
682 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
683 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
684 DIE(("Cannot align the size of the section headers\n"));
686 pssSegments
[0].Image
.FileOffset
= 0;
687 pssSegments
[0].Protection
= PAGE_READONLY
;
688 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
689 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
690 pssSegments
[0].Image
.VirtualAddress
= 0;
691 pssSegments
[0].Image
.Characteristics
= 0;
692 pssSegments
[0].WriteCopy
= TRUE
;
694 /* skip the headers segment */
697 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
699 /* convert the executable sections into segments. See also [1], section 4 */
700 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
702 ULONG nCharacteristics
;
704 /* validate the alignment */
705 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
706 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
708 /* sections must be contiguous, ordered by base address and non-overlapping */
709 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
710 DIE(("Memory gap between section %u and the previous\n", i
));
712 /* ignore explicit BSS sections */
713 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
715 /* validate the alignment */
717 /* Yes, this should be a multiple of FileAlignment, but there's
718 * stuff out there that isn't. We can cope with that
720 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
721 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
724 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
725 // DIE(("PointerToRawData[%u] is not aligned\n", i));
728 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
729 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
733 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
734 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
737 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
739 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
741 /* no explicit protection */
742 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
744 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
745 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
747 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
748 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
750 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
751 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
754 /* see table above */
755 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
756 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
758 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
759 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
761 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
763 AlignedLength
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
764 if(AlignedLength
< pssSegments
[i
].Length
.LowPart
)
765 DIE(("Cannot align the virtual size of section %u\n", i
));
767 pssSegments
[i
].Length
.LowPart
= AlignedLength
;
769 if(pssSegments
[i
].Length
.QuadPart
== 0)
770 DIE(("Virtual size of section %u is null\n", i
));
772 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
773 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
775 /* ensure the memory image is no larger than 4GB */
776 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
777 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
778 DIE(("The image is too large\n"));
781 if(nSectionAlignment
>= PAGE_SIZE
)
782 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
785 nStatus
= STATUS_SUCCESS
;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
795 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
796 * ARGUMENTS: PFILE_OBJECT to wait for.
797 * RETURNS: Status of the wait.
800 MmspWaitForFileLock(PFILE_OBJECT File
)
802 return STATUS_SUCCESS
;
803 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
808 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
810 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
812 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
813 PMM_SECTION_SEGMENT SectionSegments
;
817 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
818 NrSegments
= ImageSectionObject
->NrSegments
;
819 SectionSegments
= ImageSectionObject
->Segments
;
820 for (i
= 0; i
< NrSegments
; i
++)
822 if (SectionSegments
[i
].ReferenceCount
!= 0)
824 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
825 SectionSegments
[i
].ReferenceCount
);
826 KeBugCheck(MEMORY_MANAGEMENT
);
828 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
830 ExFreePool(ImageSectionObject
->Segments
);
831 ExFreePool(ImageSectionObject
);
832 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
834 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
836 PMM_SECTION_SEGMENT Segment
;
838 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
841 if (Segment
->ReferenceCount
!= 0)
843 DPRINT1("Data segment still referenced\n");
844 KeBugCheck(MEMORY_MANAGEMENT
);
846 MmFreePageTablesSectionSegment(Segment
, NULL
);
848 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
854 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
855 PLARGE_INTEGER Offset
)
859 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
862 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
863 KeBugCheck(MEMORY_MANAGEMENT
);
865 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
867 DPRINT1("Maximum share count reached\n");
868 KeBugCheck(MEMORY_MANAGEMENT
);
870 if (IS_SWAP_FROM_SSE(Entry
))
872 KeBugCheck(MEMORY_MANAGEMENT
);
874 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
875 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
880 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
881 PMM_SECTION_SEGMENT Segment
,
882 PLARGE_INTEGER Offset
,
887 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
888 BOOLEAN IsDirectMapped
= FALSE
;
892 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
893 KeBugCheck(MEMORY_MANAGEMENT
);
895 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
897 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
898 KeBugCheck(MEMORY_MANAGEMENT
);
900 if (IS_SWAP_FROM_SSE(Entry
))
902 KeBugCheck(MEMORY_MANAGEMENT
);
904 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
906 * If we reducing the share count of this entry to zero then set the entry
907 * to zero and tell the cache the page is no longer mapped.
909 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
911 PFILE_OBJECT FileObject
;
912 SWAPENTRY SavedSwapEntry
;
915 PROS_SHARED_CACHE_MAP SharedCacheMap
;
916 BOOLEAN IsImageSection
;
917 LARGE_INTEGER FileOffset
;
919 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
920 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
923 Page
= PFN_FROM_SSE(Entry
);
924 FileObject
= Section
->FileObject
;
925 if (FileObject
!= NULL
&&
926 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
930 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
931 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
934 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
935 IsDirectMapped
= TRUE
;
937 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
.QuadPart
, Dirty
);
939 Status
= STATUS_SUCCESS
;
941 if (!NT_SUCCESS(Status
))
943 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
944 KeBugCheck(MEMORY_MANAGEMENT
);
950 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
951 if (SavedSwapEntry
== 0)
954 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
955 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
959 * Try to page out this page and set the swap entry
960 * within the section segment. There exist no rmap entry
961 * for this page. The pager thread can't page out a
962 * page without a rmap entry.
964 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
965 if (InEntry
) *InEntry
= Entry
;
966 MiSetPageEvent(NULL
, NULL
);
970 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
971 if (InEntry
) *InEntry
= 0;
972 MiSetPageEvent(NULL
, NULL
);
975 MmReleasePageMemoryConsumer(MC_USER
, Page
);
981 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
982 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
990 * We hold all locks. Nobody can do something with the current
991 * process and the current segment (also not within an other process).
994 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
995 if (!NT_SUCCESS(Status
))
997 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
998 KeBugCheck(MEMORY_MANAGEMENT
);
1001 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
1002 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
1003 MmSetSavedSwapEntryPage(Page
, 0);
1004 MiSetPageEvent(NULL
, NULL
);
1006 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1010 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1011 KeBugCheck(MEMORY_MANAGEMENT
);
1020 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1022 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1025 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1029 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1031 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1033 SharedCacheMap
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1034 Vacb
= CcRosLookupVacb(SharedCacheMap
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
);
1037 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, FALSE
, TRUE
);
1047 MiCopyFromUserPage(PFN_NUMBER DestPage
, const VOID
*SrcAddress
)
1053 Process
= PsGetCurrentProcess();
1054 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1055 if (DestAddress
== NULL
)
1057 return(STATUS_NO_MEMORY
);
1059 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1060 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1061 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1062 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1063 return(STATUS_SUCCESS
);
1069 MiReadPage(PMEMORY_AREA MemoryArea
,
1073 * FUNCTION: Read a page for a section backed memory area.
1075 * MemoryArea - Memory area to read the page for.
1076 * Offset - Offset of the page to read.
1077 * Page - Variable that receives a page contains the read data.
1080 LONGLONG BaseOffset
;
1081 LONGLONG FileOffset
;
1085 PFILE_OBJECT FileObject
;
1088 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1089 BOOLEAN IsImageSection
;
1092 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1093 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1094 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
;
1095 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1096 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1098 ASSERT(SharedCacheMap
);
1100 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1103 * If the file system is letting us go directly to the cache and the
1104 * memory area was mapped at an offset in the file which is page aligned
1105 * then get the related VACB.
1107 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1108 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1109 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1113 * Get the related VACB; we use a lower level interface than
1114 * filesystems do because it is safe for us to use an offset with an
1115 * alignment less than the file system block size.
1117 Status
= CcRosGetVacb(SharedCacheMap
,
1123 if (!NT_SUCCESS(Status
))
1130 * If the VACB isn't up to date then call the file
1131 * system to read in the data.
1133 Status
= CcReadVirtualAddress(Vacb
);
1134 if (!NT_SUCCESS(Status
))
1136 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1141 /* Probe the page, since it's PDE might not be synced */
1142 (void)*((volatile char*)BaseAddress
+ FileOffset
- BaseOffset
);
1145 * Retrieve the page from the view that we actually want.
1147 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1148 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1150 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, TRUE
);
1157 LONGLONG VacbOffset
;
1160 * Allocate a page, this is rather complicated by the possibility
1161 * we might have to move other things out of memory
1163 MI_SET_USAGE(MI_USAGE_SECTION
);
1164 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1165 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1166 if (!NT_SUCCESS(Status
))
1170 Status
= CcRosGetVacb(SharedCacheMap
,
1176 if (!NT_SUCCESS(Status
))
1183 * If the VACB isn't up to date then call the file
1184 * system to read in the data.
1186 Status
= CcReadVirtualAddress(Vacb
);
1187 if (!NT_SUCCESS(Status
))
1189 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1194 Process
= PsGetCurrentProcess();
1195 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1196 VacbOffset
= BaseOffset
+ VACB_MAPPING_GRANULARITY
- FileOffset
;
1197 Length
= RawLength
- SegOffset
;
1198 if (Length
<= VacbOffset
&& Length
<= PAGE_SIZE
)
1200 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1202 else if (VacbOffset
>= PAGE_SIZE
)
1204 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1208 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, VacbOffset
);
1209 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1210 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1211 Status
= CcRosGetVacb(SharedCacheMap
,
1212 FileOffset
+ VacbOffset
,
1217 if (!NT_SUCCESS(Status
))
1224 * If the VACB isn't up to date then call the file
1225 * system to read in the data.
1227 Status
= CcReadVirtualAddress(Vacb
);
1228 if (!NT_SUCCESS(Status
))
1230 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
1234 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1235 if (Length
< PAGE_SIZE
)
1237 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, Length
- VacbOffset
);
1241 memcpy((char*)PageAddr
+ VacbOffset
, BaseAddress
, PAGE_SIZE
- VacbOffset
);
1244 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1245 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
1247 return(STATUS_SUCCESS
);
1252 MiReadPage(PMEMORY_AREA MemoryArea
,
1256 * FUNCTION: Read a page for a section backed memory area.
1258 * MemoryArea - Memory area to read the page for.
1259 * Offset - Offset of the page to read.
1260 * Page - Variable that receives a page contains the read data.
1263 MM_REQUIRED_RESOURCES Resources
;
1266 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1268 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1269 Resources
.FileOffset
.QuadPart
= SegOffset
+
1270 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1271 Resources
.Consumer
= MC_USER
;
1272 Resources
.Amount
= PAGE_SIZE
;
1274 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]);
1276 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1277 *Page
= Resources
.Page
[0];
1283 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
1291 PMEMORY_AREA MemoryArea
;
1292 PMM_SECTION_SEGMENT Segment
;
1293 BOOLEAN DoCOW
= FALSE
;
1295 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1297 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1298 ASSERT(MemoryArea
!= NULL
);
1299 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1300 MmLockSectionSegment(Segment
);
1302 if ((Segment
->WriteCopy
) &&
1303 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1308 if (OldProtect
!= NewProtect
)
1310 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1312 SWAPENTRY SwapEntry
;
1313 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1314 ULONG Protect
= NewProtect
;
1316 /* Wait for a wait entry to disappear */
1319 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1320 if (SwapEntry
!= MM_WAIT_ENTRY
)
1322 MiWaitForPageEvent(Process
, Address
);
1327 * If we doing COW for this segment then check if the page is
1330 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
1332 LARGE_INTEGER Offset
;
1336 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
1337 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1338 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1340 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
1341 * IS_SWAP_FROM_SSE and we'll do the right thing.
1343 Page
= MmGetPfnForProcess(Process
, Address
);
1345 Protect
= PAGE_READONLY
;
1346 if (IS_SWAP_FROM_SSE(Entry
) || PFN_FROM_SSE(Entry
) != Page
)
1348 Protect
= NewProtect
;
1352 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
1354 MmSetPageProtect(Process
, Address
,
1360 MmUnlockSectionSegment(Segment
);
1365 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1366 MEMORY_AREA
* MemoryArea
,
1370 LARGE_INTEGER Offset
;
1373 PROS_SECTION_OBJECT Section
;
1374 PMM_SECTION_SEGMENT Segment
;
1379 BOOLEAN HasSwapEntry
;
1381 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1382 SWAPENTRY SwapEntry
;
1385 * There is a window between taking the page fault and locking the
1386 * address space when another thread could load the page so we check
1389 if (MmIsPagePresent(Process
, Address
))
1391 return(STATUS_SUCCESS
);
1394 if (MmIsDisabledPage(Process
, Address
))
1396 return(STATUS_ACCESS_VIOLATION
);
1400 * Check for the virtual memory area being deleted.
1402 if (MemoryArea
->DeleteInProgress
)
1404 return(STATUS_UNSUCCESSFUL
);
1407 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1408 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1409 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1411 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1412 Section
= MemoryArea
->Data
.SectionData
.Section
;
1413 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1414 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1416 ASSERT(Region
!= NULL
);
1418 /* Check for a NOACCESS mapping */
1419 if (Region
->Protect
& PAGE_NOACCESS
)
1421 return STATUS_ACCESS_VIOLATION
;
1424 if (Region
->Protect
& PAGE_GUARD
)
1427 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
1428 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1429 Address
, PAGE_SIZE
, Region
->Type
, Region
->Protect
& ~PAGE_GUARD
,
1430 MmAlterViewAttributes
);
1432 if (!NT_SUCCESS(Status
))
1434 DPRINT1("Removing PAGE_GUARD protection failed : 0x%08x.\n", Status
);
1437 return STATUS_GUARD_PAGE_VIOLATION
;
1443 MmLockSectionSegment(Segment
);
1444 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1446 * Check if this page needs to be mapped COW
1448 if ((Segment
->WriteCopy
) &&
1449 (Region
->Protect
== PAGE_READWRITE
||
1450 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1452 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1456 Attributes
= Region
->Protect
;
1460 * Check if someone else is already handling this fault, if so wait
1463 if (Entry
&& MM_IS_WAIT_PTE(Entry
))
1465 MmUnlockSectionSegment(Segment
);
1466 MmUnlockAddressSpace(AddressSpace
);
1467 MiWaitForPageEvent(NULL
, NULL
);
1468 MmLockAddressSpace(AddressSpace
);
1469 DPRINT("Address 0x%p\n", Address
);
1470 return(STATUS_MM_RESTART_OPERATION
);
1473 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1475 /* See if we should use a private page */
1478 SWAPENTRY DummyEntry
;
1481 * Is it a wait entry?
1485 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1487 if (SwapEntry
== MM_WAIT_ENTRY
)
1489 MmUnlockSectionSegment(Segment
);
1490 MmUnlockAddressSpace(AddressSpace
);
1491 MiWaitForPageEvent(NULL
, NULL
);
1492 MmLockAddressSpace(AddressSpace
);
1493 return STATUS_MM_RESTART_OPERATION
;
1497 * Must be private page we have swapped out.
1503 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1505 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1506 KeBugCheck(MEMORY_MANAGEMENT
);
1508 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1511 MmUnlockSectionSegment(Segment
);
1513 /* Tell everyone else we are serving the fault. */
1514 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1516 MmUnlockAddressSpace(AddressSpace
);
1517 MI_SET_USAGE(MI_USAGE_SECTION
);
1518 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1519 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1520 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1521 if (!NT_SUCCESS(Status
))
1523 KeBugCheck(MEMORY_MANAGEMENT
);
1528 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1529 if (!NT_SUCCESS(Status
))
1531 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1532 KeBugCheck(MEMORY_MANAGEMENT
);
1536 MmLockAddressSpace(AddressSpace
);
1537 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1538 Status
= MmCreateVirtualMapping(Process
,
1543 if (!NT_SUCCESS(Status
))
1545 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1546 KeBugCheck(MEMORY_MANAGEMENT
);
1551 * Store the swap entry for later use.
1554 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1557 * Add the page to the process's working set
1559 MmInsertRmap(Page
, Process
, Address
);
1561 * Finish the operation
1563 MiSetPageEvent(Process
, Address
);
1564 DPRINT("Address 0x%p\n", Address
);
1565 return(STATUS_SUCCESS
);
1569 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1571 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1573 MmUnlockSectionSegment(Segment
);
1575 * Just map the desired physical page
1577 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1578 Status
= MmCreateVirtualMappingUnsafe(Process
,
1583 if (!NT_SUCCESS(Status
))
1585 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1586 KeBugCheck(MEMORY_MANAGEMENT
);
1591 * Cleanup and release locks
1593 MiSetPageEvent(Process
, Address
);
1594 DPRINT("Address 0x%p\n", Address
);
1595 return(STATUS_SUCCESS
);
1599 * Get the entry corresponding to the offset within the section
1601 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1605 SWAPENTRY FakeSwapEntry
;
1608 * If the entry is zero (and it can't change because we have
1609 * locked the segment) then we need to load the page.
1613 * Release all our locks and read in the page from disk
1615 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1616 MmUnlockSectionSegment(Segment
);
1617 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1618 MmUnlockAddressSpace(AddressSpace
);
1620 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1621 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1622 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1624 MI_SET_USAGE(MI_USAGE_SECTION
);
1625 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1626 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1627 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1628 if (!NT_SUCCESS(Status
))
1630 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1636 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1637 if (!NT_SUCCESS(Status
))
1639 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1642 if (!NT_SUCCESS(Status
))
1645 * FIXME: What do we know in this case?
1648 * Cleanup and release locks
1650 MmLockAddressSpace(AddressSpace
);
1651 MiSetPageEvent(Process
, Address
);
1652 DPRINT("Address 0x%p\n", Address
);
1656 /* Lock both segment and process address space while we proceed. */
1657 MmLockAddressSpace(AddressSpace
);
1658 MmLockSectionSegment(Segment
);
1660 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1661 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1662 Page
, Process
, PAddress
, Attributes
);
1663 Status
= MmCreateVirtualMapping(Process
,
1668 if (!NT_SUCCESS(Status
))
1670 DPRINT1("Unable to create virtual mapping\n");
1671 KeBugCheck(MEMORY_MANAGEMENT
);
1673 ASSERT(MmIsPagePresent(Process
, PAddress
));
1674 MmInsertRmap(Page
, Process
, Address
);
1676 /* Set this section offset has being backed by our new page. */
1677 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1678 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1679 MmUnlockSectionSegment(Segment
);
1681 MiSetPageEvent(Process
, Address
);
1682 DPRINT("Address 0x%p\n", Address
);
1683 return(STATUS_SUCCESS
);
1685 else if (IS_SWAP_FROM_SSE(Entry
))
1687 SWAPENTRY SwapEntry
;
1689 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1691 /* See if a page op is running on this segment. */
1692 if (SwapEntry
== MM_WAIT_ENTRY
)
1694 MmUnlockSectionSegment(Segment
);
1695 MmUnlockAddressSpace(AddressSpace
);
1696 MiWaitForPageEvent(NULL
, NULL
);
1697 MmLockAddressSpace(AddressSpace
);
1698 return STATUS_MM_RESTART_OPERATION
;
1702 * Release all our locks and read in the page from disk
1704 MmUnlockSectionSegment(Segment
);
1706 MmUnlockAddressSpace(AddressSpace
);
1707 MI_SET_USAGE(MI_USAGE_SECTION
);
1708 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1709 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1710 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1711 if (!NT_SUCCESS(Status
))
1713 KeBugCheck(MEMORY_MANAGEMENT
);
1716 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1717 if (!NT_SUCCESS(Status
))
1719 KeBugCheck(MEMORY_MANAGEMENT
);
1723 * Relock the address space and segment
1725 MmLockAddressSpace(AddressSpace
);
1726 MmLockSectionSegment(Segment
);
1729 * Check the entry. No one should change the status of a page
1730 * that has a pending page-in.
1732 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1733 if (Entry
!= Entry1
)
1735 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1736 KeBugCheck(MEMORY_MANAGEMENT
);
1740 * Save the swap entry.
1742 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1744 /* Map the page into the process address space */
1745 Status
= MmCreateVirtualMapping(Process
,
1750 if (!NT_SUCCESS(Status
))
1752 DPRINT1("Unable to create virtual mapping\n");
1753 KeBugCheck(MEMORY_MANAGEMENT
);
1755 MmInsertRmap(Page
, Process
, Address
);
1758 * Mark the offset within the section as having valid, in-memory
1761 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1762 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1763 MmUnlockSectionSegment(Segment
);
1765 MiSetPageEvent(Process
, Address
);
1766 DPRINT("Address 0x%p\n", Address
);
1767 return(STATUS_SUCCESS
);
1771 /* We already have a page on this section offset. Map it into the process address space. */
1772 Page
= PFN_FROM_SSE(Entry
);
1774 Status
= MmCreateVirtualMapping(Process
,
1779 if (!NT_SUCCESS(Status
))
1781 DPRINT1("Unable to create virtual mapping\n");
1782 KeBugCheck(MEMORY_MANAGEMENT
);
1784 MmInsertRmap(Page
, Process
, Address
);
1786 /* Take a reference on it */
1787 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1788 MmUnlockSectionSegment(Segment
);
1790 MiSetPageEvent(Process
, Address
);
1791 DPRINT("Address 0x%p\n", Address
);
1792 return(STATUS_SUCCESS
);
1798 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1799 MEMORY_AREA
* MemoryArea
,
1802 PMM_SECTION_SEGMENT Segment
;
1803 PROS_SECTION_OBJECT Section
;
1808 LARGE_INTEGER Offset
;
1811 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1813 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1815 /* Make sure we have a page mapping for this address. */
1816 Status
= MmNotPresentFaultSectionView(AddressSpace
, MemoryArea
, Address
, TRUE
);
1817 if (!NT_SUCCESS(Status
))
1819 /* This is invalid access ! */
1824 * Check if the page has already been set readwrite
1826 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1828 DPRINT("Address 0x%p\n", Address
);
1829 return(STATUS_SUCCESS
);
1833 * Find the offset of the page
1835 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1836 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- MA_GetStartingAddress(MemoryArea
)
1837 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1839 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1840 Section
= MemoryArea
->Data
.SectionData
.Section
;
1841 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
1842 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1844 ASSERT(Region
!= NULL
);
1847 * Check if we are doing COW
1849 if (!((Segment
->WriteCopy
) &&
1850 (Region
->Protect
== PAGE_READWRITE
||
1851 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1853 DPRINT("Address 0x%p\n", Address
);
1854 return(STATUS_ACCESS_VIOLATION
);
1857 /* Get the page mapping this section offset. */
1858 MmLockSectionSegment(Segment
);
1859 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1861 /* Get the current page mapping for the process */
1862 ASSERT(MmIsPagePresent(Process
, PAddress
));
1863 OldPage
= MmGetPfnForProcess(Process
, PAddress
);
1864 ASSERT(OldPage
!= 0);
1866 if (IS_SWAP_FROM_SSE(Entry
) ||
1867 PFN_FROM_SSE(Entry
) != OldPage
)
1869 MmUnlockSectionSegment(Segment
);
1870 /* This is a private page. We must only change the page protection. */
1871 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1872 return(STATUS_SUCCESS
);
1878 MI_SET_USAGE(MI_USAGE_SECTION
);
1879 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1880 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1881 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1882 if (!NT_SUCCESS(Status
))
1884 KeBugCheck(MEMORY_MANAGEMENT
);
1890 NT_VERIFY(NT_SUCCESS(MiCopyFromUserPage(NewPage
, PAddress
)));
1893 * Unshare the old page.
1895 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1896 MmDeleteVirtualMapping(Process
, PAddress
, NULL
, NULL
);
1897 MmDeleteRmap(OldPage
, Process
, PAddress
);
1898 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1899 MmUnlockSectionSegment(Segment
);
1902 * Set the PTE to point to the new page
1904 Status
= MmCreateVirtualMapping(Process
,
1909 if (!NT_SUCCESS(Status
))
1911 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1912 KeBugCheck(MEMORY_MANAGEMENT
);
1915 MmInsertRmap(NewPage
, Process
, PAddress
);
1917 MiSetPageEvent(Process
, Address
);
1918 DPRINT("Address 0x%p\n", Address
);
1919 return(STATUS_SUCCESS
);
1923 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1925 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1927 PFN_NUMBER Page
= 0;
1929 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1932 MmLockAddressSpace(&Process
->Vm
);
1935 MmDeleteVirtualMapping(Process
,
1941 PageOutContext
->WasDirty
= TRUE
;
1943 if (!PageOutContext
->Private
)
1945 MmLockSectionSegment(PageOutContext
->Segment
);
1946 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1947 PageOutContext
->Segment
,
1948 &PageOutContext
->Offset
,
1949 PageOutContext
->WasDirty
,
1951 &PageOutContext
->SectionEntry
);
1952 MmUnlockSectionSegment(PageOutContext
->Segment
);
1956 MmUnlockAddressSpace(&Process
->Vm
);
1959 if (PageOutContext
->Private
)
1961 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1967 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1968 MEMORY_AREA
* MemoryArea
,
1969 PVOID Address
, ULONG_PTR Entry
)
1972 MM_SECTION_PAGEOUT_CONTEXT Context
;
1973 SWAPENTRY SwapEntry
;
1976 ULONGLONG FileOffset
;
1977 PFILE_OBJECT FileObject
;
1978 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
1979 BOOLEAN IsImageSection
;
1981 BOOLEAN DirectMapped
;
1982 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1985 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1988 * Get the segment and section.
1990 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1991 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1992 Context
.SectionEntry
= Entry
;
1993 Context
.CallingProcess
= Process
;
1995 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
1996 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1998 DirectMapped
= FALSE
;
2000 MmLockSectionSegment(Context
.Segment
);
2003 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
2004 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2005 FileObject
= Context
.Section
->FileObject
;
2007 if (FileObject
!= NULL
&&
2008 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2010 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2013 * If the file system is letting us go directly to the cache and the
2014 * memory area was mapped at an offset in the file which is page aligned
2015 * then note this is a direct mapped page.
2017 if ((FileOffset
% PAGE_SIZE
) == 0 &&
2018 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2020 DirectMapped
= TRUE
;
2027 * This should never happen since mappings of physical memory are never
2028 * placed in the rmap lists.
2030 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2032 DPRINT1("Trying to page out from physical memory section address 0x%p "
2033 "process %p\n", Address
,
2034 Process
? Process
->UniqueProcessId
: 0);
2035 KeBugCheck(MEMORY_MANAGEMENT
);
2039 * Get the section segment entry and the physical address.
2041 if (!MmIsPagePresent(Process
, Address
))
2043 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2044 Process
? Process
->UniqueProcessId
: 0, Address
);
2045 KeBugCheck(MEMORY_MANAGEMENT
);
2047 Page
= MmGetPfnForProcess(Process
, Address
);
2048 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2051 * Check the reference count to ensure this page can be paged out
2053 if (MmGetReferenceCountPage(Page
) != 1)
2055 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
2056 Page
, MmGetReferenceCountPage(Page
));
2057 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2058 MmUnlockSectionSegment(Context
.Segment
);
2059 return STATUS_UNSUCCESSFUL
;
2063 * Prepare the context structure for the rmap delete call.
2065 MmUnlockSectionSegment(Context
.Segment
);
2066 Context
.WasDirty
= FALSE
;
2067 if (IS_SWAP_FROM_SSE(Entry
) || PFN_FROM_SSE(Entry
) != Page
)
2069 Context
.Private
= TRUE
;
2073 Context
.Private
= FALSE
;
2077 * Take an additional reference to the page or the VACB.
2079 if (DirectMapped
&& !Context
.Private
)
2081 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.QuadPart
))
2083 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2084 KeBugCheck(MEMORY_MANAGEMENT
);
2089 OldIrql
= MiAcquirePfnLock();
2090 MmReferencePage(Page
);
2091 MiReleasePfnLock(OldIrql
);
2094 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2096 /* Since we passed in a surrogate, we'll get back the page entry
2097 * state in our context. This is intended to make intermediate
2098 * decrements of share count not release the wait entry.
2100 Entry
= Context
.SectionEntry
;
2103 * If this wasn't a private page then we should have reduced the entry to
2104 * zero by deleting all the rmaps.
2106 if (!Context
.Private
&& Entry
!= 0)
2108 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2109 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2111 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2116 * If the page wasn't dirty then we can just free it as for a readonly page.
2117 * Since we unmapped all the mappings above we know it will not suddenly
2119 * If the page is from a pagefile section and has no swap entry,
2120 * we can't free the page at this point.
2122 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2123 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2125 if (Context
.Private
)
2127 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2128 Context
.WasDirty
? "dirty" : "clean", Address
);
2129 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2131 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2133 MmSetSavedSwapEntryPage(Page
, 0);
2134 MmLockSectionSegment(Context
.Segment
);
2135 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2136 MmUnlockSectionSegment(Context
.Segment
);
2137 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2138 MiSetPageEvent(NULL
, NULL
);
2139 return(STATUS_SUCCESS
);
2142 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2144 if (Context
.Private
)
2146 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2147 Context
.WasDirty
? "dirty" : "clean", Address
);
2148 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2150 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2152 MmSetSavedSwapEntryPage(Page
, 0);
2155 MmLockSectionSegment(Context
.Segment
);
2156 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2157 MmUnlockSectionSegment(Context
.Segment
);
2159 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2160 MiSetPageEvent(NULL
, NULL
);
2161 return(STATUS_SUCCESS
);
2164 else if (!Context
.Private
&& DirectMapped
)
2168 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2170 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2173 Status
= CcRosUnmapVacb(SharedCacheMap
, FileOffset
, FALSE
);
2175 Status
= STATUS_SUCCESS
;
2178 if (!NT_SUCCESS(Status
))
2180 DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status
);
2181 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)SharedCacheMap
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2184 MiSetPageEvent(NULL
, NULL
);
2185 return(STATUS_SUCCESS
);
2187 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2191 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2193 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2195 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2196 MiSetPageEvent(NULL
, NULL
);
2197 return(STATUS_SUCCESS
);
2199 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2201 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2202 MmSetSavedSwapEntryPage(Page
, 0);
2203 MmLockAddressSpace(AddressSpace
);
2204 Status
= MmCreatePageFileMapping(Process
,
2207 MmUnlockAddressSpace(AddressSpace
);
2208 if (!NT_SUCCESS(Status
))
2210 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2211 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2213 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2214 MiSetPageEvent(NULL
, NULL
);
2215 return(STATUS_SUCCESS
);
2219 * If necessary, allocate an entry in the paging file for this page
2223 SwapEntry
= MmAllocSwapPage();
2226 MmShowOutOfSpaceMessagePagingFile();
2227 MmLockAddressSpace(AddressSpace
);
2229 * For private pages restore the old mappings.
2231 if (Context
.Private
)
2233 Status
= MmCreateVirtualMapping(Process
,
2235 MemoryArea
->Protect
,
2238 MmSetDirtyPage(Process
, Address
);
2247 MmLockSectionSegment(Context
.Segment
);
2250 * For non-private pages if the page wasn't direct mapped then
2251 * set it back into the section segment entry so we don't loose
2252 * our copy. Otherwise it will be handled by the cache manager.
2254 Status
= MmCreateVirtualMapping(Process
,
2256 MemoryArea
->Protect
,
2259 MmSetDirtyPage(Process
, Address
);
2263 // If we got here, the previous entry should have been a wait
2264 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2265 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2266 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2267 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2268 MmUnlockSectionSegment(Context
.Segment
);
2270 MmUnlockAddressSpace(AddressSpace
);
2271 MiSetPageEvent(NULL
, NULL
);
2272 return(STATUS_PAGEFILE_QUOTA
);
2277 * Write the page to the pagefile
2279 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2280 if (!NT_SUCCESS(Status
))
2282 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2285 * As above: undo our actions.
2286 * FIXME: Also free the swap page.
2288 MmLockAddressSpace(AddressSpace
);
2289 if (Context
.Private
)
2291 Status
= MmCreateVirtualMapping(Process
,
2293 MemoryArea
->Protect
,
2296 MmSetDirtyPage(Process
, Address
);
2303 MmLockSectionSegment(Context
.Segment
);
2304 Status
= MmCreateVirtualMapping(Process
,
2306 MemoryArea
->Protect
,
2309 MmSetDirtyPage(Process
, Address
);
2313 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2314 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2315 MmUnlockSectionSegment(Context
.Segment
);
2317 MmUnlockAddressSpace(AddressSpace
);
2318 MiSetPageEvent(NULL
, NULL
);
2319 return(STATUS_UNSUCCESSFUL
);
2323 * Otherwise we have succeeded.
2325 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2326 MmSetSavedSwapEntryPage(Page
, 0);
2327 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2328 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2330 MmLockSectionSegment(Context
.Segment
);
2331 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2332 MmUnlockSectionSegment(Context
.Segment
);
2336 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2339 if (Context
.Private
)
2341 MmLockAddressSpace(AddressSpace
);
2342 MmLockSectionSegment(Context
.Segment
);
2343 Status
= MmCreatePageFileMapping(Process
,
2346 /* We had placed a wait entry upon entry ... replace it before leaving */
2347 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2348 MmUnlockSectionSegment(Context
.Segment
);
2349 MmUnlockAddressSpace(AddressSpace
);
2350 if (!NT_SUCCESS(Status
))
2352 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2353 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2358 MmLockAddressSpace(AddressSpace
);
2359 MmLockSectionSegment(Context
.Segment
);
2360 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2361 /* We had placed a wait entry upon entry ... replace it before leaving */
2362 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2363 MmUnlockSectionSegment(Context
.Segment
);
2364 MmUnlockAddressSpace(AddressSpace
);
2367 MiSetPageEvent(NULL
, NULL
);
2368 return(STATUS_SUCCESS
);
2373 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2374 PMEMORY_AREA MemoryArea
,
2378 LARGE_INTEGER Offset
;
2379 PROS_SECTION_OBJECT Section
;
2380 PMM_SECTION_SEGMENT Segment
;
2382 SWAPENTRY SwapEntry
;
2386 PFILE_OBJECT FileObject
;
2388 PROS_SHARED_CACHE_MAP SharedCacheMap
= NULL
;
2390 BOOLEAN DirectMapped
;
2391 BOOLEAN IsImageSection
;
2392 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2394 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2396 Offset
.QuadPart
= (ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)
2397 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2400 * Get the segment and section.
2402 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2403 Section
= MemoryArea
->Data
.SectionData
.Section
;
2404 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2406 FileObject
= Section
->FileObject
;
2407 DirectMapped
= FALSE
;
2408 if (FileObject
!= NULL
&&
2409 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2412 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2416 * If the file system is letting us go directly to the cache and the
2417 * memory area was mapped at an offset in the file which is page aligned
2418 * then note this is a direct mapped page.
2420 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2421 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2423 DirectMapped
= TRUE
;
2428 * This should never happen since mappings of physical memory are never
2429 * placed in the rmap lists.
2431 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2433 DPRINT1("Trying to write back page from physical memory mapped at %p "
2434 "process %p\n", Address
,
2435 Process
? Process
->UniqueProcessId
: 0);
2436 KeBugCheck(MEMORY_MANAGEMENT
);
2440 * Get the section segment entry and the physical address.
2442 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2443 if (!MmIsPagePresent(Process
, Address
))
2445 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2446 Process
? Process
->UniqueProcessId
: 0, Address
);
2447 KeBugCheck(MEMORY_MANAGEMENT
);
2449 Page
= MmGetPfnForProcess(Process
, Address
);
2450 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2453 * Check for a private (COWed) page.
2455 if (IS_SWAP_FROM_SSE(Entry
) || PFN_FROM_SSE(Entry
) != Page
)
2465 * Speculatively set all mappings of the page to clean.
2467 MmSetCleanAllRmaps(Page
);
2470 * If this page was direct mapped from the cache then the cache manager
2471 * will take care of writing it back to disk.
2473 if (DirectMapped
&& !Private
)
2475 //LARGE_INTEGER SOffset;
2476 ASSERT(SwapEntry
== 0);
2477 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2479 CcRosMarkDirtyFile(SharedCacheMap
, Offset
.QuadPart
);
2481 MmLockSectionSegment(Segment
);
2482 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2483 MmUnlockSectionSegment(Segment
);
2484 MiSetPageEvent(NULL
, NULL
);
2485 return(STATUS_SUCCESS
);
2489 * If necessary, allocate an entry in the paging file for this page
2493 SwapEntry
= MmAllocSwapPage();
2496 MmSetDirtyAllRmaps(Page
);
2497 MiSetPageEvent(NULL
, NULL
);
2498 return(STATUS_PAGEFILE_QUOTA
);
2500 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2504 * Write the page to the pagefile
2506 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2507 if (!NT_SUCCESS(Status
))
2509 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2511 MmSetDirtyAllRmaps(Page
);
2512 MiSetPageEvent(NULL
, NULL
);
2513 return(STATUS_UNSUCCESSFUL
);
2517 * Otherwise we have succeeded.
2519 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2520 MiSetPageEvent(NULL
, NULL
);
2521 return(STATUS_SUCCESS
);
2526 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2527 PMEMORY_AREA MemoryArea
,
2535 ULONG_PTR MaxLength
;
2537 MaxLength
= MA_GetEndingAddress(MemoryArea
) - (ULONG_PTR
)BaseAddress
;
2538 if (Length
> MaxLength
)
2539 Length
= (ULONG
)MaxLength
;
2541 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2542 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2544 ASSERT(Region
!= NULL
);
2546 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2547 Region
->Protect
!= Protect
)
2549 return STATUS_INVALID_PAGE_PROTECTION
;
2552 *OldProtect
= Region
->Protect
;
2553 Status
= MmAlterRegion(AddressSpace
, (PVOID
)MA_GetStartingAddress(MemoryArea
),
2554 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2555 BaseAddress
, Length
, Region
->Type
, Protect
,
2556 MmAlterViewAttributes
);
2562 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2564 PMEMORY_BASIC_INFORMATION Info
,
2565 PSIZE_T ResultLength
)
2568 PVOID RegionBaseAddress
;
2569 PROS_SECTION_OBJECT Section
;
2570 PMM_SECTION_SEGMENT Segment
;
2572 Region
= MmFindRegion((PVOID
)MA_GetStartingAddress(MemoryArea
),
2573 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2574 Address
, &RegionBaseAddress
);
2577 return STATUS_UNSUCCESSFUL
;
2580 Section
= MemoryArea
->Data
.SectionData
.Section
;
2581 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2583 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2584 Info
->AllocationBase
= (PUCHAR
)MA_GetStartingAddress(MemoryArea
) - Segment
->Image
.VirtualAddress
;
2585 Info
->Type
= MEM_IMAGE
;
2589 Info
->AllocationBase
= (PVOID
)MA_GetStartingAddress(MemoryArea
);
2590 Info
->Type
= MEM_MAPPED
;
2592 Info
->BaseAddress
= RegionBaseAddress
;
2593 Info
->AllocationProtect
= MemoryArea
->Protect
;
2594 Info
->RegionSize
= Region
->Length
;
2595 Info
->State
= MEM_COMMIT
;
2596 Info
->Protect
= Region
->Protect
;
2598 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2599 return(STATUS_SUCCESS
);
2604 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2607 LARGE_INTEGER Offset
;
2609 SWAPENTRY SavedSwapEntry
;
2614 MmLockSectionSegment(Segment
);
2616 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2617 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2619 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2622 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2623 if (IS_SWAP_FROM_SSE(Entry
))
2625 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2629 Page
= PFN_FROM_SSE(Entry
);
2630 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2631 if (SavedSwapEntry
!= 0)
2633 MmSetSavedSwapEntryPage(Page
, 0);
2634 MmFreeSwapPage(SavedSwapEntry
);
2636 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2641 MmUnlockSectionSegment(Segment
);
2645 MmpDeleteSection(PVOID ObjectBody
)
2647 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2649 /* Check if it's an ARM3, or ReactOS section */
2650 if (!MiIsRosSectionObject(Section
))
2652 MiDeleteARM3Section(ObjectBody
);
2656 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2657 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2662 PMM_SECTION_SEGMENT SectionSegments
;
2665 * NOTE: Section->ImageSection can be NULL for short time
2666 * during the section creating. If we fail for some reason
2667 * until the image section is properly initialized we shouldn't
2668 * process further here.
2670 if (Section
->ImageSection
== NULL
)
2673 SectionSegments
= Section
->ImageSection
->Segments
;
2674 NrSegments
= Section
->ImageSection
->NrSegments
;
2676 for (i
= 0; i
< NrSegments
; i
++)
2678 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2680 MmLockSectionSegment(&SectionSegments
[i
]);
2682 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2683 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2685 MmUnlockSectionSegment(&SectionSegments
[i
]);
2688 MmpFreePageFileSegment(&SectionSegments
[i
]);
2694 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2697 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2700 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2702 DPRINT("Freeing section segment\n");
2703 Section
->Segment
= NULL
;
2704 MmFinalizeSegment(Segment
);
2708 DPRINT("RefCount %d\n", RefCount
);
2715 * NOTE: Section->Segment can be NULL for short time
2716 * during the section creating.
2718 if (Section
->Segment
== NULL
)
2721 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2723 MmpFreePageFileSegment(Section
->Segment
);
2724 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2725 ExFreePool(Section
->Segment
);
2726 Section
->Segment
= NULL
;
2730 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2733 if (Section
->FileObject
!= NULL
)
2736 CcRosDereferenceCache(Section
->FileObject
);
2738 ObDereferenceObject(Section
->FileObject
);
2739 Section
->FileObject
= NULL
;
2744 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2746 IN ACCESS_MASK GrantedAccess
,
2747 IN ULONG ProcessHandleCount
,
2748 IN ULONG SystemHandleCount
)
2750 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2756 MmCreatePhysicalMemorySection(VOID
)
2758 PROS_SECTION_OBJECT PhysSection
;
2760 OBJECT_ATTRIBUTES Obj
;
2761 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2762 LARGE_INTEGER SectionSize
;
2766 * Create the section mapping physical memory
2768 SectionSize
.QuadPart
= 0xFFFFFFFF;
2769 InitializeObjectAttributes(&Obj
,
2771 OBJ_PERMANENT
| OBJ_KERNEL_EXCLUSIVE
,
2774 Status
= MmCreateSection((PVOID
)&PhysSection
,
2778 PAGE_EXECUTE_READWRITE
,
2782 if (!NT_SUCCESS(Status
))
2784 DPRINT1("Failed to create PhysicalMemory section\n");
2785 KeBugCheck(MEMORY_MANAGEMENT
);
2787 Status
= ObInsertObject(PhysSection
,
2793 if (!NT_SUCCESS(Status
))
2795 ObDereferenceObject(PhysSection
);
2797 ObCloseHandle(Handle
, KernelMode
);
2798 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2799 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2801 return(STATUS_SUCCESS
);
2807 MmInitSectionImplementation(VOID
)
2809 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2810 UNICODE_STRING Name
;
2812 DPRINT("Creating Section Object Type\n");
2814 /* Initialize the section based root */
2815 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2816 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2818 /* Initialize the Section object type */
2819 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2820 RtlInitUnicodeString(&Name
, L
"Section");
2821 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2822 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2823 ObjectTypeInitializer
.PoolType
= PagedPool
;
2824 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2825 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2826 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2827 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2828 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2829 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2830 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2832 MmCreatePhysicalMemorySection();
2834 return(STATUS_SUCCESS
);
2839 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2840 ACCESS_MASK DesiredAccess
,
2841 POBJECT_ATTRIBUTES ObjectAttributes
,
2842 PLARGE_INTEGER UMaximumSize
,
2843 ULONG SectionPageProtection
,
2844 ULONG AllocationAttributes
)
2846 * Create a section which is backed by the pagefile
2849 LARGE_INTEGER MaximumSize
;
2850 PROS_SECTION_OBJECT Section
;
2851 PMM_SECTION_SEGMENT Segment
;
2854 if (UMaximumSize
== NULL
)
2856 DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
2857 return(STATUS_INVALID_PARAMETER
);
2859 MaximumSize
= *UMaximumSize
;
2862 * Create the section
2864 Status
= ObCreateObject(ExGetPreviousMode(),
2865 MmSectionObjectType
,
2867 ExGetPreviousMode(),
2869 sizeof(ROS_SECTION_OBJECT
),
2872 (PVOID
*)(PVOID
)&Section
);
2873 if (!NT_SUCCESS(Status
))
2875 DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status
);
2882 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2883 Section
->Type
= 'SC';
2884 Section
->Size
= 'TN';
2885 Section
->SectionPageProtection
= SectionPageProtection
;
2886 Section
->AllocationAttributes
= AllocationAttributes
;
2887 Section
->MaximumSize
= MaximumSize
;
2888 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2889 TAG_MM_SECTION_SEGMENT
);
2890 if (Segment
== NULL
)
2892 ObDereferenceObject(Section
);
2893 return(STATUS_NO_MEMORY
);
2895 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2896 Section
->Segment
= Segment
;
2897 Segment
->ReferenceCount
= 1;
2898 ExInitializeFastMutex(&Segment
->Lock
);
2899 Segment
->Image
.FileOffset
= 0;
2900 Segment
->Protection
= SectionPageProtection
;
2901 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2902 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2903 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2904 Segment
->WriteCopy
= FALSE
;
2905 Segment
->Image
.VirtualAddress
= 0;
2906 Segment
->Image
.Characteristics
= 0;
2907 *SectionObject
= Section
;
2908 MiInitializeSectionPageTable(Segment
);
2909 return(STATUS_SUCCESS
);
2914 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2915 ACCESS_MASK DesiredAccess
,
2916 POBJECT_ATTRIBUTES ObjectAttributes
,
2917 PLARGE_INTEGER UMaximumSize
,
2918 ULONG SectionPageProtection
,
2919 ULONG AllocationAttributes
,
2920 PFILE_OBJECT FileObject
)
2922 * Create a section backed by a data file
2925 PROS_SECTION_OBJECT Section
;
2927 LARGE_INTEGER MaximumSize
;
2928 PMM_SECTION_SEGMENT Segment
;
2929 FILE_STANDARD_INFORMATION FileInfo
;
2933 * Create the section
2935 Status
= ObCreateObject(ExGetPreviousMode(),
2936 MmSectionObjectType
,
2938 ExGetPreviousMode(),
2940 sizeof(ROS_SECTION_OBJECT
),
2944 if (!NT_SUCCESS(Status
))
2946 ObDereferenceObject(FileObject
);
2952 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2953 Section
->Type
= 'SC';
2954 Section
->Size
= 'TN';
2955 Section
->SectionPageProtection
= SectionPageProtection
;
2956 Section
->AllocationAttributes
= AllocationAttributes
;
2959 * FIXME: This is propably not entirely correct. We can't look into
2960 * the standard FCB header because it might not be initialized yet
2961 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2962 * standard file information is filled on first request).
2964 Status
= IoQueryFileInformation(FileObject
,
2965 FileStandardInformation
,
2966 sizeof(FILE_STANDARD_INFORMATION
),
2969 if (!NT_SUCCESS(Status
))
2971 ObDereferenceObject(Section
);
2972 ObDereferenceObject(FileObject
);
2977 * FIXME: Revise this once a locking order for file size changes is
2980 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2982 MaximumSize
= *UMaximumSize
;
2986 MaximumSize
= FileInfo
.EndOfFile
;
2987 /* Mapping zero-sized files isn't allowed. */
2988 if (MaximumSize
.QuadPart
== 0)
2990 ObDereferenceObject(Section
);
2991 ObDereferenceObject(FileObject
);
2992 return STATUS_MAPPED_FILE_SIZE_ZERO
;
2996 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2998 Status
= IoSetInformation(FileObject
,
2999 FileEndOfFileInformation
,
3000 sizeof(LARGE_INTEGER
),
3002 if (!NT_SUCCESS(Status
))
3004 ObDereferenceObject(Section
);
3005 ObDereferenceObject(FileObject
);
3006 return(STATUS_SECTION_NOT_EXTENDED
);
3010 if (FileObject
->SectionObjectPointer
== NULL
||
3011 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3013 ObDereferenceObject(Section
);
3014 ObDereferenceObject(FileObject
);
3015 return STATUS_INVALID_FILE_FOR_SECTION
;
3021 Status
= MmspWaitForFileLock(FileObject
);
3022 if (Status
!= STATUS_SUCCESS
)
3024 ObDereferenceObject(Section
);
3025 ObDereferenceObject(FileObject
);
3030 * If this file hasn't been mapped as a data file before then allocate a
3031 * section segment to describe the data file mapping
3033 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3035 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3036 TAG_MM_SECTION_SEGMENT
);
3037 if (Segment
== NULL
)
3039 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3040 ObDereferenceObject(Section
);
3041 ObDereferenceObject(FileObject
);
3042 return(STATUS_NO_MEMORY
);
3044 Section
->Segment
= Segment
;
3045 Segment
->ReferenceCount
= 1;
3046 ExInitializeFastMutex(&Segment
->Lock
);
3048 * Set the lock before assigning the segment to the file object
3050 ExAcquireFastMutex(&Segment
->Lock
);
3051 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3053 Segment
->Image
.FileOffset
= 0;
3054 Segment
->Protection
= SectionPageProtection
;
3055 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3056 Segment
->Image
.Characteristics
= 0;
3057 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3058 if (AllocationAttributes
& SEC_RESERVE
)
3060 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3064 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3065 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3067 Segment
->Image
.VirtualAddress
= 0;
3068 Segment
->Locked
= TRUE
;
3069 MiInitializeSectionPageTable(Segment
);
3074 * If the file is already mapped as a data file then we may need
3078 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3080 Section
->Segment
= Segment
;
3081 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3082 MmLockSectionSegment(Segment
);
3084 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3085 !(AllocationAttributes
& SEC_RESERVE
))
3087 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3088 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3091 MmUnlockSectionSegment(Segment
);
3092 Section
->FileObject
= FileObject
;
3093 Section
->MaximumSize
= MaximumSize
;
3095 CcRosReferenceCache(FileObject
);
3097 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3098 *SectionObject
= Section
;
3099 return(STATUS_SUCCESS
);
3103 TODO: not that great (declaring loaders statically, having to declare all of
3104 them, having to keep them extern, etc.), will fix in the future
3106 extern NTSTATUS NTAPI PeFmtCreateSection
3108 IN CONST VOID
* FileHeader
,
3109 IN SIZE_T FileHeaderSize
,
3111 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3113 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3114 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3117 extern NTSTATUS NTAPI ElfFmtCreateSection
3119 IN CONST VOID
* FileHeader
,
3120 IN SIZE_T FileHeaderSize
,
3122 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3124 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3125 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3128 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3139 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3141 SIZE_T SizeOfSegments
;
3142 PMM_SECTION_SEGMENT Segments
;
3144 /* TODO: check for integer overflow */
3145 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3147 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3149 TAG_MM_SECTION_SEGMENT
);
3152 RtlZeroMemory(Segments
, SizeOfSegments
);
3160 ExeFmtpReadFile(IN PVOID File
,
3161 IN PLARGE_INTEGER Offset
,
3164 OUT PVOID
* AllocBase
,
3165 OUT PULONG ReadSize
)
3168 LARGE_INTEGER FileOffset
;
3170 ULONG OffsetAdjustment
;
3174 PFILE_OBJECT FileObject
= File
;
3175 IO_STATUS_BLOCK Iosb
;
3177 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3181 KeBugCheck(MEMORY_MANAGEMENT
);
3184 FileOffset
= *Offset
;
3186 /* Negative/special offset: it cannot be used in this context */
3187 if(FileOffset
.u
.HighPart
< 0)
3189 KeBugCheck(MEMORY_MANAGEMENT
);
3192 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3193 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3194 FileOffset
.u
.LowPart
= AdjustOffset
;
3196 BufferSize
= Length
+ OffsetAdjustment
;
3197 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3199 /* Flush data since we're about to perform a non-cached read */
3200 CcFlushCache(FileObject
->SectionObjectPointer
,
3206 * It's ok to use paged pool, because this is a temporary buffer only used in
3207 * the loading of executables. The assumption is that MmCreateSection is
3208 * always called at low IRQLs and that these buffers don't survive a brief
3209 * initialization phase
3211 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3216 return STATUS_INSUFFICIENT_RESOURCES
;
3221 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3223 UsedSize
= (ULONG
)Iosb
.Information
;
3225 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3227 Status
= STATUS_IN_PAGE_ERROR
;
3228 ASSERT(!NT_SUCCESS(Status
));
3231 if(NT_SUCCESS(Status
))
3233 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3234 *AllocBase
= Buffer
;
3235 *ReadSize
= UsedSize
- OffsetAdjustment
;
3239 ExFreePoolWithTag(Buffer
, 'rXmM');
3246 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3247 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3248 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3253 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3257 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3259 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3260 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3267 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3271 MmspAssertSegmentsSorted(ImageSectionObject
);
3273 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3275 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3279 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3280 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3281 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3289 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3293 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3295 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3296 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3304 MmspCompareSegments(const void * x
,
3307 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3308 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3311 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3312 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3316 * Ensures an image section's segments are sorted in memory
3321 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3324 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3326 MmspAssertSegmentsSorted(ImageSectionObject
);
3330 qsort(ImageSectionObject
->Segments
,
3331 ImageSectionObject
->NrSegments
,
3332 sizeof(ImageSectionObject
->Segments
[0]),
3333 MmspCompareSegments
);
3339 * Ensures an image section's segments don't overlap in memory and don't have
3340 * gaps and don't have a null size. We let them map to overlapping file regions,
3341 * though - that's not necessarily an error
3346 MmspCheckSegmentBounds
3348 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3354 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3356 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3360 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3362 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3364 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3372 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3373 * page could be OK (Windows seems to be OK with them), and larger gaps
3374 * could lead to image sections spanning several discontiguous regions
3375 * (NtMapViewOfSection could then refuse to map them, and they could
3376 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3378 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3379 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3380 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3391 * Merges and pads an image section's segments until they all are page-aligned
3392 * and have a size that is a multiple of the page size
3397 MmspPageAlignSegments
3399 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3405 PMM_SECTION_SEGMENT EffectiveSegment
;
3407 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3409 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3414 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3416 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3419 * The first segment requires special handling
3423 ULONG_PTR VirtualAddress
;
3424 ULONG_PTR VirtualOffset
;
3426 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3428 /* Round down the virtual address to the nearest page */
3429 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3431 /* Round up the virtual size to the nearest page */
3432 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3433 EffectiveSegment
->Image
.VirtualAddress
;
3435 /* Adjust the raw address and size */
3436 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3438 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3444 * Garbage in, garbage out: unaligned base addresses make the file
3445 * offset point in curious and odd places, but that's what we were
3448 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3449 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3453 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3454 ULONG_PTR EndOfEffectiveSegment
;
3456 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3457 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3460 * The current segment begins exactly where the current effective
3461 * segment ended, therefore beginning a new effective segment
3463 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3466 ASSERT(LastSegment
<= i
);
3467 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3469 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3471 if (LastSegment
!= i
)
3474 * Copy the current segment. If necessary, the effective segment
3475 * will be expanded later
3477 *EffectiveSegment
= *Segment
;
3481 * Page-align the virtual size. We know for sure the virtual address
3484 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3485 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3488 * The current segment is still part of the current effective segment:
3489 * extend the effective segment to reflect this
3491 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3493 static const ULONG FlagsToProtection
[16] =
3501 PAGE_EXECUTE_READWRITE
,
3502 PAGE_EXECUTE_READWRITE
,
3507 PAGE_EXECUTE_WRITECOPY
,
3508 PAGE_EXECUTE_WRITECOPY
,
3509 PAGE_EXECUTE_WRITECOPY
,
3510 PAGE_EXECUTE_WRITECOPY
3513 unsigned ProtectionFlags
;
3516 * Extend the file size
3519 /* Unaligned segments must be contiguous within the file */
3520 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3521 EffectiveSegment
->RawLength
.QuadPart
))
3526 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3529 * Extend the virtual size
3531 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3533 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3534 EffectiveSegment
->Image
.VirtualAddress
;
3537 * Merge the protection
3539 EffectiveSegment
->Protection
|= Segment
->Protection
;
3541 /* Clean up redundance */
3542 ProtectionFlags
= 0;
3544 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3545 ProtectionFlags
|= 1 << 0;
3547 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3548 ProtectionFlags
|= 1 << 1;
3550 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3551 ProtectionFlags
|= 1 << 2;
3553 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3554 ProtectionFlags
|= 1 << 3;
3556 ASSERT(ProtectionFlags
< 16);
3557 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3559 /* If a segment was required to be shared and cannot, fail */
3560 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3561 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3567 * We assume no holes between segments at this point
3571 KeBugCheck(MEMORY_MANAGEMENT
);
3575 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3581 ExeFmtpCreateImageSection(PFILE_OBJECT FileObject
,
3582 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3584 LARGE_INTEGER Offset
;
3586 PVOID FileHeaderBuffer
;
3587 ULONG FileHeaderSize
;
3589 ULONG OldNrSegments
;
3594 * Read the beginning of the file (2 pages). Should be enough to contain
3595 * all (or most) of the headers
3597 Offset
.QuadPart
= 0;
3599 Status
= ExeFmtpReadFile (FileObject
,
3606 if (!NT_SUCCESS(Status
))
3609 if (FileHeaderSize
== 0)
3611 ExFreePool(FileHeaderBuffer
);
3612 return STATUS_UNSUCCESSFUL
;
3616 * Look for a loader that can handle this executable
3618 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3620 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3623 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3629 ExeFmtpAllocateSegments
);
3631 if (!NT_SUCCESS(Status
))
3633 if (ImageSectionObject
->Segments
)
3635 ExFreePool(ImageSectionObject
->Segments
);
3636 ImageSectionObject
->Segments
= NULL
;
3640 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3644 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3647 * No loader handled the format
3649 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3651 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3652 ASSERT(!NT_SUCCESS(Status
));
3655 if (!NT_SUCCESS(Status
))
3658 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3663 /* FIXME? are these values platform-dependent? */
3664 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3665 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3667 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3668 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3670 if(ImageSectionObject
->BasedAddress
== NULL
)
3672 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3673 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3675 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3679 * And now the fun part: fixing the segments
3682 /* Sort them by virtual address */
3683 MmspSortSegments(ImageSectionObject
, Flags
);
3685 /* Ensure they don't overlap in memory */
3686 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3687 return STATUS_INVALID_IMAGE_FORMAT
;
3689 /* Ensure they are aligned */
3690 OldNrSegments
= ImageSectionObject
->NrSegments
;
3692 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3693 return STATUS_INVALID_IMAGE_FORMAT
;
3695 /* Trim them if the alignment phase merged some of them */
3696 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3698 PMM_SECTION_SEGMENT Segments
;
3699 SIZE_T SizeOfSegments
;
3701 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3703 Segments
= ExAllocatePoolWithTag(PagedPool
,
3705 TAG_MM_SECTION_SEGMENT
);
3707 if (Segments
== NULL
)
3708 return STATUS_INSUFFICIENT_RESOURCES
;
3710 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3711 ExFreePool(ImageSectionObject
->Segments
);
3712 ImageSectionObject
->Segments
= Segments
;
3715 /* And finish their initialization */
3716 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3718 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3719 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3720 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3723 ASSERT(NT_SUCCESS(Status
));
3728 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3729 ACCESS_MASK DesiredAccess
,
3730 POBJECT_ATTRIBUTES ObjectAttributes
,
3731 PLARGE_INTEGER UMaximumSize
,
3732 ULONG SectionPageProtection
,
3733 ULONG AllocationAttributes
,
3734 PFILE_OBJECT FileObject
)
3736 PROS_SECTION_OBJECT Section
;
3738 PMM_SECTION_SEGMENT SectionSegments
;
3739 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3742 if (FileObject
== NULL
)
3743 return STATUS_INVALID_FILE_FOR_SECTION
;
3746 if (!CcIsFileCached(FileObject
))
3748 DPRINT1("Denying section creation due to missing cache initialization\n");
3749 return STATUS_INVALID_FILE_FOR_SECTION
;
3754 * Create the section
3756 Status
= ObCreateObject (ExGetPreviousMode(),
3757 MmSectionObjectType
,
3759 ExGetPreviousMode(),
3761 sizeof(ROS_SECTION_OBJECT
),
3764 (PVOID
*)(PVOID
)&Section
);
3765 if (!NT_SUCCESS(Status
))
3767 ObDereferenceObject(FileObject
);
3774 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3775 Section
->Type
= 'SC';
3776 Section
->Size
= 'TN';
3777 Section
->SectionPageProtection
= SectionPageProtection
;
3778 Section
->AllocationAttributes
= AllocationAttributes
;
3780 if (FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3782 NTSTATUS StatusExeFmt
;
3784 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3785 if (ImageSectionObject
== NULL
)
3787 ObDereferenceObject(FileObject
);
3788 ObDereferenceObject(Section
);
3789 return(STATUS_NO_MEMORY
);
3792 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3794 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3796 if (!NT_SUCCESS(StatusExeFmt
))
3798 if(ImageSectionObject
->Segments
!= NULL
)
3799 ExFreePool(ImageSectionObject
->Segments
);
3802 * If image file is empty, then return that the file is invalid for section
3804 Status
= StatusExeFmt
;
3805 if (StatusExeFmt
== STATUS_END_OF_FILE
)
3807 Status
= STATUS_INVALID_FILE_FOR_SECTION
;
3810 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3811 ObDereferenceObject(Section
);
3812 ObDereferenceObject(FileObject
);
3816 Section
->ImageSection
= ImageSectionObject
;
3817 ASSERT(ImageSectionObject
->Segments
);
3822 Status
= MmspWaitForFileLock(FileObject
);
3823 if (!NT_SUCCESS(Status
))
3825 ExFreePool(ImageSectionObject
->Segments
);
3826 ExFreePool(ImageSectionObject
);
3827 ObDereferenceObject(Section
);
3828 ObDereferenceObject(FileObject
);
3832 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3833 ImageSectionObject
, NULL
))
3836 * An other thread has initialized the same image in the background
3838 ExFreePool(ImageSectionObject
->Segments
);
3839 ExFreePool(ImageSectionObject
);
3840 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3841 Section
->ImageSection
= ImageSectionObject
;
3842 SectionSegments
= ImageSectionObject
->Segments
;
3844 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3846 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3850 Status
= StatusExeFmt
;
3857 Status
= MmspWaitForFileLock(FileObject
);
3858 if (Status
!= STATUS_SUCCESS
)
3860 ObDereferenceObject(Section
);
3861 ObDereferenceObject(FileObject
);
3865 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3866 Section
->ImageSection
= ImageSectionObject
;
3867 SectionSegments
= ImageSectionObject
->Segments
;
3870 * Otherwise just reference all the section segments
3872 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3874 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3877 Status
= STATUS_SUCCESS
;
3879 Section
->FileObject
= FileObject
;
3881 CcRosReferenceCache(FileObject
);
3883 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3884 *SectionObject
= Section
;
3891 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3892 PROS_SECTION_OBJECT Section
,
3893 PMM_SECTION_SEGMENT Segment
,
3898 ULONG AllocationType
)
3904 if (Segment
->WriteCopy
)
3906 /* We have to do this because the not present fault
3907 * and access fault handlers depend on the protection
3908 * that should be granted AFTER the COW fault takes
3909 * place to be in Region->Protect. The not present fault
3910 * handler changes this to the correct protection for COW when
3911 * mapping the pages into the process's address space. If a COW
3912 * fault takes place, the access fault handler sets the page protection
3913 * to these values for the newly copied pages
3915 if (Protect
== PAGE_WRITECOPY
)
3916 Protect
= PAGE_READWRITE
;
3917 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3918 Protect
= PAGE_EXECUTE_READWRITE
;
3921 if (*BaseAddress
== NULL
)
3922 Granularity
= MM_ALLOCATION_GRANULARITY
;
3924 Granularity
= PAGE_SIZE
;
3927 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3929 LARGE_INTEGER FileOffset
;
3930 FileOffset
.QuadPart
= ViewOffset
;
3931 ObReferenceObject(Section
);
3932 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3935 Status
= MmCreateMemoryArea(AddressSpace
,
3936 MEMORY_AREA_SECTION_VIEW
,
3943 if (!NT_SUCCESS(Status
))
3945 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3946 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3950 ObReferenceObject((PVOID
)Section
);
3952 MArea
->Data
.SectionData
.Segment
= Segment
;
3953 MArea
->Data
.SectionData
.Section
= Section
;
3954 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3955 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3957 MArea
->VadNode
.u
.VadFlags
.VadType
= VadImageMap
;
3960 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3961 ViewSize
, 0, Protect
);
3963 return(STATUS_SUCCESS
);
3968 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3969 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3973 PFILE_OBJECT FileObject
;
3974 PROS_SHARED_CACHE_MAP SharedCacheMap
;
3976 LARGE_INTEGER Offset
;
3977 SWAPENTRY SavedSwapEntry
;
3978 PROS_SECTION_OBJECT Section
;
3979 PMM_SECTION_SEGMENT Segment
;
3980 PMMSUPPORT AddressSpace
;
3983 AddressSpace
= (PMMSUPPORT
)Context
;
3984 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3986 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3988 Offset
.QuadPart
= ((ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
)) +
3989 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3991 Section
= MemoryArea
->Data
.SectionData
.Section
;
3992 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3994 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3995 while (Entry
&& MM_IS_WAIT_PTE(Entry
))
3997 MmUnlockSectionSegment(Segment
);
3998 MmUnlockAddressSpace(AddressSpace
);
4000 MiWaitForPageEvent(NULL
, NULL
);
4002 MmLockAddressSpace(AddressSpace
);
4003 MmLockSectionSegment(Segment
);
4004 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4008 * For a dirty, datafile, non-private page mark it as dirty in the
4011 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4013 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4016 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4017 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4018 CcRosMarkDirtyFile(SharedCacheMap
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4020 ASSERT(SwapEntry
== 0);
4029 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4031 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4032 KeBugCheck(MEMORY_MANAGEMENT
);
4034 MmFreeSwapPage(SwapEntry
);
4038 if (IS_SWAP_FROM_SSE(Entry
) ||
4039 Page
!= PFN_FROM_SSE(Entry
))
4044 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4046 DPRINT1("Found a private page in a pagefile section.\n");
4047 KeBugCheck(MEMORY_MANAGEMENT
);
4050 * Just dereference private pages
4052 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4053 if (SavedSwapEntry
!= 0)
4055 MmFreeSwapPage(SavedSwapEntry
);
4056 MmSetSavedSwapEntryPage(Page
, 0);
4058 MmDeleteRmap(Page
, Process
, Address
);
4059 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4063 MmDeleteRmap(Page
, Process
, Address
);
4064 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4070 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4074 PMEMORY_AREA MemoryArea
;
4075 PROS_SECTION_OBJECT Section
;
4076 PMM_SECTION_SEGMENT Segment
;
4077 PLIST_ENTRY CurrentEntry
;
4078 PMM_REGION CurrentRegion
;
4079 PLIST_ENTRY RegionListHead
;
4081 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4083 if (MemoryArea
== NULL
)
4085 return(STATUS_UNSUCCESSFUL
);
4088 Section
= MemoryArea
->Data
.SectionData
.Section
;
4089 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4092 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4094 MmUnlockAddressSpace(AddressSpace
);
4095 Status
= MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4096 MmLockAddressSpace(AddressSpace
);
4102 MemoryArea
->DeleteInProgress
= TRUE
;
4104 MmLockSectionSegment(Segment
);
4106 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4107 while (!IsListEmpty(RegionListHead
))
4109 CurrentEntry
= RemoveHeadList(RegionListHead
);
4110 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4111 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4114 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4116 Status
= MmFreeMemoryArea(AddressSpace
,
4123 Status
= MmFreeMemoryArea(AddressSpace
,
4128 MmUnlockSectionSegment(Segment
);
4129 ObDereferenceObject(Section
);
4135 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4136 IN PVOID BaseAddress
,
4137 IN BOOLEAN SkipDebuggerNotify
)
4140 PMEMORY_AREA MemoryArea
;
4141 PMMSUPPORT AddressSpace
;
4142 PROS_SECTION_OBJECT Section
;
4143 PVOID ImageBaseAddress
= 0;
4145 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4146 Process
, BaseAddress
);
4150 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4152 MmLockAddressSpace(AddressSpace
);
4153 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4155 if (MemoryArea
== NULL
||
4156 ((MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
) &&
4157 (MemoryArea
->Type
!= MEMORY_AREA_CACHE
)) ||
4158 MemoryArea
->DeleteInProgress
)
4160 if (MemoryArea
) ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4161 MmUnlockAddressSpace(AddressSpace
);
4162 return STATUS_NOT_MAPPED_VIEW
;
4165 Section
= MemoryArea
->Data
.SectionData
.Section
;
4167 if ((Section
!= NULL
) && (Section
->AllocationAttributes
& SEC_IMAGE
))
4171 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4172 PMM_SECTION_SEGMENT SectionSegments
;
4173 PMM_SECTION_SEGMENT Segment
;
4175 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4176 ImageSectionObject
= Section
->ImageSection
;
4177 SectionSegments
= ImageSectionObject
->Segments
;
4178 NrSegments
= ImageSectionObject
->NrSegments
;
4180 MemoryArea
->DeleteInProgress
= TRUE
;
4182 /* Search for the current segment within the section segments
4183 * and calculate the image base address */
4184 for (i
= 0; i
< NrSegments
; i
++)
4186 if (Segment
== &SectionSegments
[i
])
4188 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4192 if (i
>= NrSegments
)
4194 KeBugCheck(MEMORY_MANAGEMENT
);
4197 for (i
= 0; i
< NrSegments
; i
++)
4199 PVOID SBaseAddress
= (PVOID
)
4200 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4202 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4203 if (!NT_SUCCESS(Status
))
4205 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4206 SBaseAddress
, Process
, Status
);
4207 ASSERT(NT_SUCCESS(Status
));
4213 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4214 if (!NT_SUCCESS(Status
))
4216 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
4217 BaseAddress
, Process
, Status
);
4218 ASSERT(NT_SUCCESS(Status
));
4222 MmUnlockAddressSpace(AddressSpace
);
4224 /* Notify debugger */
4225 if (ImageBaseAddress
&& !SkipDebuggerNotify
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4227 return(STATUS_SUCCESS
);
4234 * Queries the information of a section object.
4236 * @param SectionHandle
4237 * Handle to the section object. It must be opened with SECTION_QUERY
4239 * @param SectionInformationClass
4240 * Index to a certain information structure. Can be either
4241 * SectionBasicInformation or SectionImageInformation. The latter
4242 * is valid only for sections that were created with the SEC_IMAGE
4244 * @param SectionInformation
4245 * Caller supplies storage for resulting information.
4247 * Size of the supplied storage.
4248 * @param ResultLength
4258 _In_ HANDLE SectionHandle
,
4259 _In_ SECTION_INFORMATION_CLASS SectionInformationClass
,
4260 _Out_ PVOID SectionInformation
,
4261 _In_ SIZE_T SectionInformationLength
,
4262 _Out_opt_ PSIZE_T ResultLength
)
4265 KPROCESSOR_MODE PreviousMode
;
4269 PreviousMode
= ExGetPreviousMode();
4270 if (PreviousMode
!= KernelMode
)
4274 ProbeForWrite(SectionInformation
,
4275 SectionInformationLength
,
4277 if (ResultLength
!= NULL
)
4279 ProbeForWrite(ResultLength
,
4280 sizeof(*ResultLength
),
4284 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4286 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4291 if (SectionInformationClass
== SectionBasicInformation
)
4293 if (SectionInformationLength
< sizeof(SECTION_BASIC_INFORMATION
))
4295 return STATUS_INFO_LENGTH_MISMATCH
;
4298 else if (SectionInformationClass
== SectionImageInformation
)
4300 if (SectionInformationLength
< sizeof(SECTION_IMAGE_INFORMATION
))
4302 return STATUS_INFO_LENGTH_MISMATCH
;
4307 return STATUS_INVALID_INFO_CLASS
;
4310 Status
= ObReferenceObjectByHandle(SectionHandle
,
4312 MmSectionObjectType
,
4314 (PVOID
*)(PVOID
)&Section
,
4316 if (!NT_SUCCESS(Status
))
4318 DPRINT1("Failed to reference section: 0x%lx\n", Status
);
4322 if (MiIsRosSectionObject(Section
))
4324 PROS_SECTION_OBJECT RosSection
= (PROS_SECTION_OBJECT
)Section
;
4326 switch (SectionInformationClass
)
4328 case SectionBasicInformation
:
4330 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4334 Sbi
->Attributes
= RosSection
->AllocationAttributes
;
4335 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4337 Sbi
->BaseAddress
= 0;
4338 Sbi
->Size
.QuadPart
= 0;
4342 Sbi
->BaseAddress
= (PVOID
)RosSection
->Segment
->Image
.VirtualAddress
;
4343 Sbi
->Size
.QuadPart
= RosSection
->Segment
->Length
.QuadPart
;
4346 if (ResultLength
!= NULL
)
4348 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4350 Status
= STATUS_SUCCESS
;
4352 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4354 Status
= _SEH2_GetExceptionCode();
4361 case SectionImageInformation
:
4363 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4367 if (RosSection
->AllocationAttributes
& SEC_IMAGE
)
4369 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4370 ImageSectionObject
= RosSection
->ImageSection
;
4372 *Sii
= ImageSectionObject
->ImageInformation
;
4375 if (ResultLength
!= NULL
)
4377 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4379 Status
= STATUS_SUCCESS
;
4381 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4383 Status
= _SEH2_GetExceptionCode();
4393 switch(SectionInformationClass
)
4395 case SectionBasicInformation
:
4397 SECTION_BASIC_INFORMATION Sbi
;
4399 Sbi
.Size
= Section
->SizeOfSection
;
4400 Sbi
.BaseAddress
= (PVOID
)Section
->Address
.StartingVpn
;
4403 if (Section
->u
.Flags
.Image
)
4404 Sbi
.Attributes
|= SEC_IMAGE
;
4405 if (Section
->u
.Flags
.Commit
)
4406 Sbi
.Attributes
|= SEC_COMMIT
;
4407 if (Section
->u
.Flags
.Reserve
)
4408 Sbi
.Attributes
|= SEC_RESERVE
;
4409 if (Section
->u
.Flags
.File
)
4410 Sbi
.Attributes
|= SEC_FILE
;
4411 if (Section
->u
.Flags
.Image
)
4412 Sbi
.Attributes
|= SEC_IMAGE
;
4414 /* FIXME : Complete/test the list of flags passed back from NtCreateSection */
4418 *((SECTION_BASIC_INFORMATION
*)SectionInformation
) = Sbi
;
4420 *ResultLength
= sizeof(Sbi
);
4422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4424 Status
= _SEH2_GetExceptionCode();
4429 case SectionImageInformation
:
4431 if (!Section
->u
.Flags
.Image
)
4433 Status
= STATUS_SECTION_NOT_IMAGE
;
4437 /* Currently not supported */
4445 ObDereferenceObject(Section
);
4450 /**********************************************************************
4452 * MmMapViewOfSection
4455 * Maps a view of a section into the virtual address space of a
4460 * Pointer to the section object.
4463 * Pointer to the process.
4466 * Desired base address (or NULL) on entry;
4467 * Actual base address of the view on exit.
4470 * Number of high order address bits that must be zero.
4473 * Size in bytes of the initially committed section of
4477 * Offset in bytes from the beginning of the section
4478 * to the beginning of the view.
4481 * Desired length of map (or zero to map all) on entry
4482 * Actual length mapped on exit.
4484 * InheritDisposition
4485 * Specified how the view is to be shared with
4489 * Type of allocation for the pages.
4492 * Protection for the committed region of the view.
4500 MmMapViewOfSection(IN PVOID SectionObject
,
4501 IN PEPROCESS Process
,
4502 IN OUT PVOID
*BaseAddress
,
4503 IN ULONG_PTR ZeroBits
,
4504 IN SIZE_T CommitSize
,
4505 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4506 IN OUT PSIZE_T ViewSize
,
4507 IN SECTION_INHERIT InheritDisposition
,
4508 IN ULONG AllocationType
,
4511 PROS_SECTION_OBJECT Section
;
4512 PMMSUPPORT AddressSpace
;
4514 NTSTATUS Status
= STATUS_SUCCESS
;
4515 BOOLEAN NotAtBase
= FALSE
;
4517 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4519 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4520 return MmMapViewOfArm3Section(SectionObject
,
4534 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4536 return STATUS_INVALID_PAGE_PROTECTION
;
4539 /* FIXME: We should keep this, but it would break code checking equality */
4540 Protect
&= ~PAGE_NOCACHE
;
4542 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4543 AddressSpace
= &Process
->Vm
;
4545 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4547 MmLockAddressSpace(AddressSpace
);
4549 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4553 ULONG_PTR ImageBase
;
4555 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4556 PMM_SECTION_SEGMENT SectionSegments
;
4558 ImageSectionObject
= Section
->ImageSection
;
4559 SectionSegments
= ImageSectionObject
->Segments
;
4560 NrSegments
= ImageSectionObject
->NrSegments
;
4562 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4565 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4569 for (i
= 0; i
< NrSegments
; i
++)
4571 ULONG_PTR MaxExtent
;
4572 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4573 SectionSegments
[i
].Length
.QuadPart
);
4574 ImageSize
= max(ImageSize
, MaxExtent
);
4577 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4579 /* Check for an illegal base address */
4580 if (((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
) ||
4581 ((ImageBase
+ ImageSize
) < ImageSize
))
4583 ASSERT(*BaseAddress
== NULL
);
4584 ImageBase
= ALIGN_DOWN_BY((ULONG_PTR
)MmHighestUserAddress
- ImageSize
,
4585 MM_VIRTMEM_GRANULARITY
);
4588 else if (ImageBase
!= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
))
4590 ASSERT(*BaseAddress
== NULL
);
4591 ImageBase
= ALIGN_DOWN_BY(ImageBase
, MM_VIRTMEM_GRANULARITY
);
4595 /* Check there is enough space to map the section at that point. */
4596 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4597 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4599 /* Fail if the user requested a fixed base address. */
4600 if ((*BaseAddress
) != NULL
)
4602 MmUnlockAddressSpace(AddressSpace
);
4603 return(STATUS_CONFLICTING_ADDRESSES
);
4605 /* Otherwise find a gap to map the image. */
4606 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), MM_VIRTMEM_GRANULARITY
, FALSE
);
4609 MmUnlockAddressSpace(AddressSpace
);
4610 return(STATUS_CONFLICTING_ADDRESSES
);
4612 /* Remember that we loaded image at a different base address */
4616 for (i
= 0; i
< NrSegments
; i
++)
4618 PVOID SBaseAddress
= (PVOID
)
4619 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4620 MmLockSectionSegment(&SectionSegments
[i
]);
4621 Status
= MmMapViewOfSegment(AddressSpace
,
4623 &SectionSegments
[i
],
4625 SectionSegments
[i
].Length
.LowPart
,
4626 SectionSegments
[i
].Protection
,
4629 MmUnlockSectionSegment(&SectionSegments
[i
]);
4630 if (!NT_SUCCESS(Status
))
4632 MmUnlockAddressSpace(AddressSpace
);
4637 *BaseAddress
= (PVOID
)ImageBase
;
4638 *ViewSize
= ImageSize
;
4642 /* check for write access */
4643 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4644 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4646 MmUnlockAddressSpace(AddressSpace
);
4647 return STATUS_SECTION_PROTECTION
;
4649 /* check for read access */
4650 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4651 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4653 MmUnlockAddressSpace(AddressSpace
);
4654 return STATUS_SECTION_PROTECTION
;
4656 /* check for execute access */
4657 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4658 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4660 MmUnlockAddressSpace(AddressSpace
);
4661 return STATUS_SECTION_PROTECTION
;
4664 if (SectionOffset
== NULL
)
4670 ViewOffset
= SectionOffset
->u
.LowPart
;
4673 if ((ViewOffset
% PAGE_SIZE
) != 0)
4675 MmUnlockAddressSpace(AddressSpace
);
4676 return(STATUS_MAPPED_ALIGNMENT
);
4679 if ((*ViewSize
) == 0)
4681 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4683 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4685 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4688 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4690 MmLockSectionSegment(Section
->Segment
);
4691 Status
= MmMapViewOfSegment(AddressSpace
,
4698 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4699 MmUnlockSectionSegment(Section
->Segment
);
4700 if (!NT_SUCCESS(Status
))
4702 MmUnlockAddressSpace(AddressSpace
);
4707 MmUnlockAddressSpace(AddressSpace
);
4708 ASSERT(*BaseAddress
== ALIGN_DOWN_POINTER_BY(*BaseAddress
, MM_VIRTMEM_GRANULARITY
));
4711 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4713 Status
= STATUS_SUCCESS
;
4722 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4723 IN PLARGE_INTEGER NewFileSize
)
4725 /* Check whether an ImageSectionObject exists */
4726 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4728 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4732 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4734 PMM_SECTION_SEGMENT Segment
;
4736 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4739 if (Segment
->ReferenceCount
!= 0)
4742 CC_FILE_SIZES FileSizes
;
4744 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4747 /* Check size of file */
4748 if (SectionObjectPointer
->SharedCacheMap
)
4750 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4755 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4764 /* Check size of file */
4765 if (SectionObjectPointer
->SharedCacheMap
)
4767 PROS_SHARED_CACHE_MAP SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
4768 if (NewFileSize
->QuadPart
<= SharedCacheMap
->FileSize
.QuadPart
)
4777 /* Something must gone wrong
4778 * how can we have a Section but no
4780 DPRINT("ERROR: DataSectionObject without reference!\n");
4784 DPRINT("FIXME: didn't check for outstanding write probes\n");
4796 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4797 IN MMFLUSH_TYPE FlushType
)
4799 BOOLEAN Result
= TRUE
;
4801 PMM_SECTION_SEGMENT Segment
;
4806 case MmFlushForDelete
:
4807 if (SectionObjectPointer
->ImageSectionObject
||
4808 SectionObjectPointer
->DataSectionObject
)
4813 CcRosRemoveIfClosed(SectionObjectPointer
);
4816 case MmFlushForWrite
:
4818 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4820 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4823 if (SectionObjectPointer
->ImageSectionObject
)
4825 DPRINT1("SectionObject has ImageSection\n");
4831 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4833 DPRINT("Result %d\n", Result
);
4845 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4846 OUT PVOID
* MappedBase
,
4847 IN OUT PSIZE_T ViewSize
)
4849 PROS_SECTION_OBJECT Section
;
4850 PMMSUPPORT AddressSpace
;
4854 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4856 return MiMapViewInSystemSpace(SectionObject
,
4862 DPRINT("MmMapViewInSystemSpace() called\n");
4864 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4865 AddressSpace
= MmGetKernelAddressSpace();
4867 MmLockAddressSpace(AddressSpace
);
4870 if ((*ViewSize
) == 0)
4872 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4874 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4876 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4879 MmLockSectionSegment(Section
->Segment
);
4882 Status
= MmMapViewOfSegment(AddressSpace
,
4891 MmUnlockSectionSegment(Section
->Segment
);
4892 MmUnlockAddressSpace(AddressSpace
);
4899 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4901 PMMSUPPORT AddressSpace
;
4904 DPRINT("MmUnmapViewInSystemSpace() called\n");
4906 AddressSpace
= MmGetKernelAddressSpace();
4908 MmLockAddressSpace(AddressSpace
);
4910 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4912 MmUnlockAddressSpace(AddressSpace
);
4917 /**********************************************************************
4922 * Creates a section object.
4925 * SectionObject (OUT)
4926 * Caller supplied storage for the resulting pointer
4927 * to a SECTION_OBJECT instance;
4930 * Specifies the desired access to the section can be a
4932 * STANDARD_RIGHTS_REQUIRED |
4934 * SECTION_MAP_WRITE |
4935 * SECTION_MAP_READ |
4936 * SECTION_MAP_EXECUTE
4938 * ObjectAttributes [OPTIONAL]
4939 * Initialized attributes for the object can be used
4940 * to create a named section;
4943 * Maximizes the size of the memory section. Must be
4944 * non-NULL for a page-file backed section.
4945 * If value specified for a mapped file and the file is
4946 * not large enough, file will be extended.
4948 * SectionPageProtection
4949 * Can be a combination of:
4955 * AllocationAttributes
4956 * Can be a combination of:
4961 * Handle to a file to create a section mapped to a file
4962 * instead of a memory backed section;
4973 MmCreateSection (OUT PVOID
* Section
,
4974 IN ACCESS_MASK DesiredAccess
,
4975 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4976 IN PLARGE_INTEGER MaximumSize
,
4977 IN ULONG SectionPageProtection
,
4978 IN ULONG AllocationAttributes
,
4979 IN HANDLE FileHandle OPTIONAL
,
4980 IN PFILE_OBJECT FileObject OPTIONAL
)
4984 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4986 /* Check if an ARM3 section is being created instead */
4987 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4989 if (!(FileObject
) && !(FileHandle
))
4991 return MmCreateArm3Section(Section
,
4995 SectionPageProtection
,
4996 AllocationAttributes
&~ 1,
5002 /* Convert section flag to page flag */
5003 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
5005 /* Check to make sure the protection is correct. Nt* does this already */
5006 Protection
= MiMakeProtectionMask(SectionPageProtection
);
5007 if (Protection
== MM_INVALID_PROTECTION
)
5009 DPRINT1("Page protection is invalid\n");
5010 return STATUS_INVALID_PAGE_PROTECTION
;
5013 /* Check if this is going to be a data or image backed file section */
5014 if ((FileHandle
) || (FileObject
))
5016 /* These cannot be mapped with large pages */
5017 if (AllocationAttributes
& SEC_LARGE_PAGES
)
5019 DPRINT1("Large pages cannot be used with an image mapping\n");
5020 return STATUS_INVALID_PARAMETER_6
;
5023 /* Did the caller pass an object? */
5026 /* Reference the object directly */
5027 ObReferenceObject(FileObject
);
5031 /* Reference the file handle to get the object */
5032 Status
= ObReferenceObjectByHandle(FileHandle
,
5033 MmMakeFileAccess
[Protection
],
5035 ExGetPreviousMode(),
5036 (PVOID
*)&FileObject
,
5038 if (!NT_SUCCESS(Status
))
5040 DPRINT1("Failed to get a handle to the FO: %lx\n", Status
);
5047 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
5048 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
5051 #ifndef NEWCC // A hack for initializing caching.
5052 // This is needed only in the old case.
5055 IO_STATUS_BLOCK Iosb
;
5058 LARGE_INTEGER ByteOffset
;
5059 ByteOffset
.QuadPart
= 0;
5060 Status
= ZwReadFile(FileHandle
,
5069 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5071 DPRINT1("CC failure: %lx\n", Status
);
5073 ObDereferenceObject(FileObject
);
5076 // Caching is initialized...
5078 // Hack of the hack: actually, it might not be initialized if FSD init on effective right and if file is null-size
5079 // In such case, force cache by initiating a write IRP
5080 if (Status
== STATUS_END_OF_FILE
&& !(AllocationAttributes
& SEC_IMAGE
) && FileObject
!= NULL
&&
5081 (FileObject
->SectionObjectPointer
== NULL
|| FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
))
5084 Status
= ZwWriteFile(FileHandle
,
5093 if (NT_SUCCESS(Status
))
5096 Zero
.QuadPart
= 0LL;
5098 Status
= IoSetInformation(FileObject
,
5099 FileEndOfFileInformation
,
5100 sizeof(LARGE_INTEGER
),
5102 ASSERT(NT_SUCCESS(Status
));
5108 if (AllocationAttributes
& SEC_IMAGE
)
5110 Status
= MmCreateImageSection(SectionObject
,
5114 SectionPageProtection
,
5115 AllocationAttributes
,
5119 else if (FileHandle
!= NULL
)
5121 Status
= MmCreateDataFileSection(SectionObject
,
5125 SectionPageProtection
,
5126 AllocationAttributes
,
5130 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5132 Status
= MmCreateCacheSection(SectionObject
,
5136 SectionPageProtection
,
5137 AllocationAttributes
,
5143 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5145 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5147 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5148 Status
= MmCreatePageFileSection(SectionObject
,
5152 SectionPageProtection
,
5153 AllocationAttributes
);
5155 ObDereferenceObject(FileObject
);