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 ACCESS_MASK NTAPI
MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection
);
165 static GENERIC_MAPPING MmpSectionMapping
= {
166 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
167 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
168 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
171 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
173 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
174 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
177 /* FUNCTIONS *****************************************************************/
182 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
183 File Format Specification", revision 6.0 (February 1999)
185 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
186 IN SIZE_T FileHeaderSize
,
188 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
190 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
191 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
194 ULONG cbFileHeaderOffsetSize
= 0;
195 ULONG cbSectionHeadersOffset
= 0;
196 ULONG cbSectionHeadersSize
;
197 ULONG cbSectionHeadersOffsetSize
= 0;
198 ULONG cbOptHeaderSize
;
199 ULONG cbHeadersSize
= 0;
200 ULONG nSectionAlignment
;
201 ULONG nFileAlignment
;
203 const IMAGE_DOS_HEADER
* pidhDosHeader
;
204 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
205 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
206 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
207 PMM_SECTION_SEGMENT pssSegments
;
208 LARGE_INTEGER lnOffset
;
210 SIZE_T nPrevVirtualEndOfSegment
= 0;
211 ULONG nFileSizeOfHeaders
= 0;
215 ASSERT(FileHeaderSize
> 0);
217 ASSERT(ImageSectionObject
);
219 ASSERT(AllocateSegmentsCb
);
221 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
223 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
225 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
228 pidhDosHeader
= FileHeader
;
231 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
233 /* image too small to be an MZ executable */
234 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
235 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
237 /* no MZ signature */
238 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
239 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
241 /* not a Windows executable */
242 if(pidhDosHeader
->e_lfanew
<= 0)
243 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
246 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
248 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
249 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
251 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
256 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
257 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
259 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
260 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
264 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
265 * need to read the header from the file
267 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
268 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
270 ULONG cbNtHeaderSize
;
274 l_ReadHeaderFromFile
:
276 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
278 /* read the header from the file */
279 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
281 if(!NT_SUCCESS(nStatus
))
282 DIE(("ReadFile failed, status %08X\n", nStatus
));
286 ASSERT(cbReadSize
> 0);
288 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
290 /* the buffer doesn't contain the file header */
291 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
292 DIE(("The file doesn't contain the PE file header\n"));
294 pinhNtHeader
= pData
;
296 /* object still not aligned: copy it to the beginning of the buffer */
297 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
299 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
300 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
301 pinhNtHeader
= pBuffer
;
304 /* invalid NT header */
305 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
307 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
308 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
310 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
312 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
313 DIE(("The full NT header is too large\n"));
315 /* the buffer doesn't contain the whole NT header */
316 if(cbReadSize
< cbNtHeaderSize
)
317 DIE(("The file doesn't contain the full NT header\n"));
321 ULONG cbOptHeaderOffsetSize
= 0;
323 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
325 /* don't trust an invalid NT header */
326 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
327 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
329 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
330 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
332 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
333 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
335 /* the buffer doesn't contain the whole NT header: read it from the file */
336 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
337 goto l_ReadHeaderFromFile
;
340 /* read information from the NT header */
341 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
342 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
344 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
346 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
347 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
349 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
351 switch(piohOptHeader
->Magic
)
353 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
354 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
358 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
361 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
362 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
364 /* See [1], section 3.4.2 */
365 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
367 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
368 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
370 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
371 DIE(("The section alignment is smaller than the file alignment\n"));
373 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
374 nFileAlignment
= piohOptHeader
->FileAlignment
;
376 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
377 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
381 nSectionAlignment
= PAGE_SIZE
;
382 nFileAlignment
= PAGE_SIZE
;
385 ASSERT(IsPowerOf2(nSectionAlignment
));
386 ASSERT(IsPowerOf2(nFileAlignment
));
388 switch(piohOptHeader
->Magic
)
391 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
393 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
394 ImageBase
= piohOptHeader
->ImageBase
;
396 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
397 ImageSectionObject
->ImageInformation
.ImageFileSize
= piohOptHeader
->SizeOfImage
;
399 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
400 ImageSectionObject
->ImageInformation
.MaximumStackSize
= piohOptHeader
->SizeOfStackReserve
;
402 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
403 ImageSectionObject
->ImageInformation
.CommittedStackSize
= piohOptHeader
->SizeOfStackCommit
;
405 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
407 ImageSectionObject
->ImageInformation
.SubSystemType
= piohOptHeader
->Subsystem
;
409 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
410 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
412 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= piohOptHeader
->MinorSubsystemVersion
;
413 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= piohOptHeader
->MajorSubsystemVersion
;
417 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
419 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
420 piohOptHeader
->AddressOfEntryPoint
);
423 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
424 ImageSectionObject
->ImageInformation
.ImageContainsCode
= piohOptHeader
->SizeOfCode
!= 0;
426 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
428 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
430 if (piohOptHeader
->AddressOfEntryPoint
== 0)
432 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
436 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, LoaderFlags
))
437 ImageSectionObject
->ImageInformation
.LoaderFlags
= piohOptHeader
->LoaderFlags
;
439 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, DllCharacteristics
))
441 ImageSectionObject
->ImageInformation
.DllCharacteristics
= piohOptHeader
->DllCharacteristics
;
444 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
445 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
446 * magic to any binary.
448 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
449 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
450 * the SxS support -- at which point, duh, this should be removed.
452 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
454 ImageSectionObject
->ImageInformation
.DllCharacteristics
|= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
;
461 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
463 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
465 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
467 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
469 ImageBase
= pioh64OptHeader
->ImageBase
;
470 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
471 DIE(("ImageBase exceeds the address space\n"));
474 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
476 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
477 DIE(("SizeOfImage exceeds the address space\n"));
479 ImageSectionObject
->ImageInformation
.ImageFileSize
= pioh64OptHeader
->SizeOfImage
;
482 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
484 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
485 DIE(("SizeOfStackReserve exceeds the address space\n"));
487 ImageSectionObject
->ImageInformation
.MaximumStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackReserve
;
490 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
492 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
493 DIE(("SizeOfStackCommit exceeds the address space\n"));
495 ImageSectionObject
->ImageInformation
.CommittedStackSize
= (ULONG_PTR
) pioh64OptHeader
->SizeOfStackCommit
;
498 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, Subsystem
))
500 ImageSectionObject
->ImageInformation
.SubSystemType
= pioh64OptHeader
->Subsystem
;
502 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
503 RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
505 ImageSectionObject
->ImageInformation
.SubSystemMinorVersion
= pioh64OptHeader
->MinorSubsystemVersion
;
506 ImageSectionObject
->ImageInformation
.SubSystemMajorVersion
= pioh64OptHeader
->MajorSubsystemVersion
;
510 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
512 ImageSectionObject
->ImageInformation
.TransferAddress
= (PVOID
) (ImageBase
+
513 pioh64OptHeader
->AddressOfEntryPoint
);
516 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfCode
))
517 ImageSectionObject
->ImageInformation
.ImageContainsCode
= pioh64OptHeader
->SizeOfCode
!= 0;
519 ImageSectionObject
->ImageInformation
.ImageContainsCode
= TRUE
;
521 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
523 if (pioh64OptHeader
->AddressOfEntryPoint
== 0)
525 ImageSectionObject
->ImageInformation
.ImageContainsCode
= FALSE
;
529 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, LoaderFlags
))
530 ImageSectionObject
->ImageInformation
.LoaderFlags
= pioh64OptHeader
->LoaderFlags
;
532 if (RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, DllCharacteristics
))
533 ImageSectionObject
->ImageInformation
.DllCharacteristics
= pioh64OptHeader
->DllCharacteristics
;
539 /* [1], section 3.4.2 */
540 if((ULONG_PTR
)ImageBase
% 0x10000)
541 DIE(("ImageBase is not aligned on a 64KB boundary"));
543 ImageSectionObject
->ImageInformation
.ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
544 ImageSectionObject
->ImageInformation
.Machine
= pinhNtHeader
->FileHeader
.Machine
;
545 ImageSectionObject
->ImageInformation
.GpValue
= 0;
546 ImageSectionObject
->ImageInformation
.ZeroBits
= 0;
547 ImageSectionObject
->BasedAddress
= (PVOID
)ImageBase
;
549 /* SECTION HEADERS */
550 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
552 /* see [1], section 3.3 */
553 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
554 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
557 * the additional segment is for the file's headers. They need to be present for
558 * the benefit of the dynamic loader (to locate exports, defaults for thread
559 * parameters, resources, etc.)
561 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
563 /* file offset for the section headers */
564 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
565 DIE(("Offset overflow\n"));
567 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
568 DIE(("Offset overflow\n"));
570 /* size of the section headers */
571 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
572 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
574 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
575 DIE(("Section headers too large\n"));
577 /* size of the executable's headers */
578 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
580 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
581 // DIE(("SizeOfHeaders is not aligned\n"));
583 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
584 DIE(("The section headers overflow SizeOfHeaders\n"));
586 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
588 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
589 DIE(("Overflow aligning the size of headers\n"));
596 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
597 /* WARNING: piohOptHeader IS NO LONGER USABLE */
598 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
600 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
601 pishSectionHeaders
= NULL
;
605 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
606 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
608 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
609 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
613 * the buffer doesn't contain the section headers, or the alignment is wrong:
614 * read the headers from the file
616 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
617 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
622 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
624 /* read the header from the file */
625 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
627 if(!NT_SUCCESS(nStatus
))
628 DIE(("ReadFile failed with status %08X\n", nStatus
));
632 ASSERT(cbReadSize
> 0);
634 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
636 /* the buffer doesn't contain all the section headers */
637 if(cbReadSize
< cbSectionHeadersSize
)
638 DIE(("The file doesn't contain all of the section headers\n"));
640 pishSectionHeaders
= pData
;
642 /* object still not aligned: copy it to the beginning of the buffer */
643 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
645 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
646 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
647 pishSectionHeaders
= pBuffer
;
652 /* allocate the segments */
653 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
654 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
656 if(ImageSectionObject
->Segments
== NULL
)
657 DIE(("AllocateSegments failed\n"));
659 /* initialize the headers segment */
660 pssSegments
= ImageSectionObject
->Segments
;
662 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
664 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
665 DIE(("Cannot align the size of the section headers\n"));
667 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
668 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
669 DIE(("Cannot align the size of the section headers\n"));
671 pssSegments
[0].Image
.FileOffset
= 0;
672 pssSegments
[0].Protection
= PAGE_READONLY
;
673 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
674 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
675 pssSegments
[0].Image
.VirtualAddress
= 0;
676 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
677 pssSegments
[0].WriteCopy
= TRUE
;
679 /* skip the headers segment */
682 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
684 /* convert the executable sections into segments. See also [1], section 4 */
685 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
687 ULONG nCharacteristics
;
689 /* validate the alignment */
690 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
691 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
693 /* sections must be contiguous, ordered by base address and non-overlapping */
694 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
695 DIE(("Memory gap between section %u and the previous\n", i
));
697 /* ignore explicit BSS sections */
698 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
700 /* validate the alignment */
702 /* Yes, this should be a multiple of FileAlignment, but there's
703 * stuff out there that isn't. We can cope with that
705 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
706 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
709 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
710 // DIE(("PointerToRawData[%u] is not aligned\n", i));
713 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
714 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
718 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
719 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
722 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
724 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
726 /* no explicit protection */
727 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
729 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
730 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
732 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
733 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
735 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
736 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
739 /* see table above */
740 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
741 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
743 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
744 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
746 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
748 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
749 /* FIXME: always false */
750 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
751 DIE(("Cannot align the virtual size of section %u\n", i
));
753 if(pssSegments
[i
].Length
.QuadPart
== 0)
754 DIE(("Virtual size of section %u is null\n", i
));
756 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
757 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
759 /* ensure the memory image is no larger than 4GB */
760 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
761 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
762 DIE(("The image is too large\n"));
765 if(nSectionAlignment
>= PAGE_SIZE
)
766 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
769 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;
779 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
780 * ARGUMENTS: PFILE_OBJECT to wait for.
781 * RETURNS: Status of the wait.
784 MmspWaitForFileLock(PFILE_OBJECT File
)
786 return STATUS_SUCCESS
;
787 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
792 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
794 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
796 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
797 PMM_SECTION_SEGMENT SectionSegments
;
801 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
802 NrSegments
= ImageSectionObject
->NrSegments
;
803 SectionSegments
= ImageSectionObject
->Segments
;
804 for (i
= 0; i
< NrSegments
; i
++)
806 if (SectionSegments
[i
].ReferenceCount
!= 0)
808 DPRINT1("Image segment %lu still referenced (was %lu)\n", i
,
809 SectionSegments
[i
].ReferenceCount
);
810 KeBugCheck(MEMORY_MANAGEMENT
);
812 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
814 ExFreePool(ImageSectionObject
->Segments
);
815 ExFreePool(ImageSectionObject
);
816 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
818 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
820 PMM_SECTION_SEGMENT Segment
;
822 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
825 if (Segment
->ReferenceCount
!= 0)
827 DPRINT1("Data segment still referenced\n");
828 KeBugCheck(MEMORY_MANAGEMENT
);
830 MmFreePageTablesSectionSegment(Segment
, NULL
);
832 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
838 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
839 PLARGE_INTEGER Offset
)
843 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
846 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
847 KeBugCheck(MEMORY_MANAGEMENT
);
849 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
851 DPRINT1("Maximum share count reached\n");
852 KeBugCheck(MEMORY_MANAGEMENT
);
854 if (IS_SWAP_FROM_SSE(Entry
))
856 KeBugCheck(MEMORY_MANAGEMENT
);
858 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
859 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
864 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
865 PMM_SECTION_SEGMENT Segment
,
866 PLARGE_INTEGER Offset
,
871 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
872 BOOLEAN IsDirectMapped
= FALSE
;
876 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
877 KeBugCheck(MEMORY_MANAGEMENT
);
879 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
881 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
882 KeBugCheck(MEMORY_MANAGEMENT
);
884 if (IS_SWAP_FROM_SSE(Entry
))
886 KeBugCheck(MEMORY_MANAGEMENT
);
888 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
890 * If we reducing the share count of this entry to zero then set the entry
891 * to zero and tell the cache the page is no longer mapped.
893 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
895 PFILE_OBJECT FileObject
;
899 SWAPENTRY SavedSwapEntry
;
901 BOOLEAN IsImageSection
;
902 LARGE_INTEGER FileOffset
;
904 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
906 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
908 Page
= PFN_FROM_SSE(Entry
);
909 FileObject
= Section
->FileObject
;
910 if (FileObject
!= NULL
&&
911 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
915 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
916 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
919 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
920 IsDirectMapped
= TRUE
;
922 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
.LowPart
, Dirty
);
924 Status
= STATUS_SUCCESS
;
926 if (!NT_SUCCESS(Status
))
928 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
929 KeBugCheck(MEMORY_MANAGEMENT
);
935 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
936 if (SavedSwapEntry
== 0)
939 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
940 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
944 * Try to page out this page and set the swap entry
945 * within the section segment. There exist no rmap entry
946 * for this page. The pager thread can't page out a
947 * page without a rmap entry.
949 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
950 if (InEntry
) *InEntry
= Entry
;
951 MiSetPageEvent(NULL
, NULL
);
955 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
956 if (InEntry
) *InEntry
= 0;
957 MiSetPageEvent(NULL
, NULL
);
960 MmReleasePageMemoryConsumer(MC_USER
, Page
);
966 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
967 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
975 * We hold all locks. Nobody can do something with the current
976 * process and the current segment (also not within an other process).
979 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
980 if (!NT_SUCCESS(Status
))
982 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
983 KeBugCheck(MEMORY_MANAGEMENT
);
986 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
987 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
988 MmSetSavedSwapEntryPage(Page
, 0);
989 MiSetPageEvent(NULL
, NULL
);
991 MmReleasePageMemoryConsumer(MC_USER
, Page
);
995 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
996 KeBugCheck(MEMORY_MANAGEMENT
);
1005 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1007 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1010 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1014 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1017 PCACHE_SEGMENT CacheSeg
;
1018 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1019 CacheSeg
= CcRosLookupCacheSegment(Bcb
, (ULONG
)(SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
));
1022 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
1032 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
1036 PVOID DestAddress
, SrcAddress
;
1038 Process
= PsGetCurrentProcess();
1039 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1040 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
1041 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
1043 return(STATUS_NO_MEMORY
);
1045 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
1046 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
1047 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
1048 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
1049 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
1050 return(STATUS_SUCCESS
);
1056 MiReadPage(PMEMORY_AREA MemoryArea
,
1057 ULONG_PTR SegOffset
,
1060 * FUNCTION: Read a page for a section backed memory area.
1062 * MemoryArea - Memory area to read the page for.
1063 * Offset - Offset of the page to read.
1064 * Page - Variable that receives a page contains the read data.
1068 ULONGLONG FileOffset
;
1071 PCACHE_SEGMENT CacheSeg
;
1072 PFILE_OBJECT FileObject
;
1074 ULONG_PTR RawLength
;
1076 BOOLEAN IsImageSection
;
1079 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1080 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1081 RawLength
= (ULONG_PTR
)(MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
);
1082 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1083 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1087 DPRINT("%S %I64x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1090 * If the file system is letting us go directly to the cache and the
1091 * memory area was mapped at an offset in the file which is page aligned
1092 * then get the related cache segment.
1094 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1095 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1096 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1100 * Get the related cache segment; we use a lower level interface than
1101 * filesystems do because it is safe for us to use an offset with a
1102 * alignment less than the file system block size.
1104 Status
= CcRosGetCacheSegment(Bcb
,
1110 if (!NT_SUCCESS(Status
))
1117 * If the cache segment isn't up to date then call the file
1118 * system to read in the data.
1120 Status
= ReadCacheSegment(CacheSeg
);
1121 if (!NT_SUCCESS(Status
))
1123 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1128 * Retrieve the page from the cache segment that we actually want.
1130 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1131 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1133 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1140 ULONG_PTR CacheSegOffset
;
1143 * Allocate a page, this is rather complicated by the possibility
1144 * we might have to move other things out of memory
1146 MI_SET_USAGE(MI_USAGE_SECTION
);
1147 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1148 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1149 if (!NT_SUCCESS(Status
))
1153 Status
= CcRosGetCacheSegment(Bcb
,
1159 if (!NT_SUCCESS(Status
))
1166 * If the cache segment isn't up to date then call the file
1167 * system to read in the data.
1169 Status
= ReadCacheSegment(CacheSeg
);
1170 if (!NT_SUCCESS(Status
))
1172 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1177 Process
= PsGetCurrentProcess();
1178 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1179 CacheSegOffset
= (ULONG_PTR
)(BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
);
1180 Length
= RawLength
- SegOffset
;
1181 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1183 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1185 else if (CacheSegOffset
>= PAGE_SIZE
)
1187 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1191 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1192 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1193 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1194 Status
= CcRosGetCacheSegment(Bcb
,
1195 (ULONG
)(FileOffset
+ CacheSegOffset
),
1200 if (!NT_SUCCESS(Status
))
1207 * If the cache segment isn't up to date then call the file
1208 * system to read in the data.
1210 Status
= ReadCacheSegment(CacheSeg
);
1211 if (!NT_SUCCESS(Status
))
1213 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1217 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1218 if (Length
< PAGE_SIZE
)
1220 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1224 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1227 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1228 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1230 return(STATUS_SUCCESS
);
1235 MiReadPage(PMEMORY_AREA MemoryArea
,
1236 ULONG_PTR SegOffset
,
1239 * FUNCTION: Read a page for a section backed memory area.
1241 * MemoryArea - Memory area to read the page for.
1242 * Offset - Offset of the page to read.
1243 * Page - Variable that receives a page contains the read data.
1246 MM_REQUIRED_RESOURCES Resources
;
1249 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1251 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1252 Resources
.FileOffset
.QuadPart
= SegOffset
+
1253 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1254 Resources
.Consumer
= MC_USER
;
1255 Resources
.Amount
= PAGE_SIZE
;
1257 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]);
1259 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1260 *Page
= Resources
.Page
[0];
1267 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1268 MEMORY_AREA
* MemoryArea
,
1272 LARGE_INTEGER Offset
;
1275 PROS_SECTION_OBJECT Section
;
1276 PMM_SECTION_SEGMENT Segment
;
1281 BOOLEAN HasSwapEntry
;
1283 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1284 SWAPENTRY SwapEntry
;
1287 * There is a window between taking the page fault and locking the
1288 * address space when another thread could load the page so we check
1291 if (MmIsPagePresent(Process
, Address
))
1293 return(STATUS_SUCCESS
);
1296 if (MmIsDisabledPage(Process
, Address
))
1298 return(STATUS_ACCESS_VIOLATION
);
1302 * Check for the virtual memory area being deleted.
1304 if (MemoryArea
->DeleteInProgress
)
1306 return(STATUS_UNSUCCESSFUL
);
1309 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1310 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1311 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1313 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1314 Section
= MemoryArea
->Data
.SectionData
.Section
;
1315 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1316 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1318 ASSERT(Region
!= NULL
);
1322 MmLockSectionSegment(Segment
);
1323 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1325 * Check if this page needs to be mapped COW
1327 if ((Segment
->WriteCopy
) &&
1328 (Region
->Protect
== PAGE_READWRITE
||
1329 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1331 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1335 Attributes
= Region
->Protect
;
1339 * Check if someone else is already handling this fault, if so wait
1342 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1344 MmUnlockSectionSegment(Segment
);
1345 MmUnlockAddressSpace(AddressSpace
);
1346 MiWaitForPageEvent(NULL
, NULL
);
1347 MmLockAddressSpace(AddressSpace
);
1348 DPRINT("Address 0x%p\n", Address
);
1349 return(STATUS_MM_RESTART_OPERATION
);
1352 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1356 SWAPENTRY DummyEntry
;
1359 * Is it a wait entry?
1361 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1363 if (SwapEntry
== MM_WAIT_ENTRY
)
1365 MmUnlockSectionSegment(Segment
);
1366 MmUnlockAddressSpace(AddressSpace
);
1367 MiWaitForPageEvent(NULL
, NULL
);
1368 MmLockAddressSpace(AddressSpace
);
1369 return STATUS_MM_RESTART_OPERATION
;
1373 * Must be private page we have swapped out.
1379 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1381 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1382 KeBugCheck(MEMORY_MANAGEMENT
);
1385 MmUnlockSectionSegment(Segment
);
1386 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1387 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1389 MmUnlockAddressSpace(AddressSpace
);
1390 MI_SET_USAGE(MI_USAGE_SECTION
);
1391 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1392 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1393 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1394 if (!NT_SUCCESS(Status
))
1396 KeBugCheck(MEMORY_MANAGEMENT
);
1399 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1400 if (!NT_SUCCESS(Status
))
1402 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1403 KeBugCheck(MEMORY_MANAGEMENT
);
1405 MmLockAddressSpace(AddressSpace
);
1406 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1407 Status
= MmCreateVirtualMapping(Process
,
1412 if (!NT_SUCCESS(Status
))
1414 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1415 KeBugCheck(MEMORY_MANAGEMENT
);
1420 * Store the swap entry for later use.
1422 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1425 * Add the page to the process's working set
1427 MmInsertRmap(Page
, Process
, Address
);
1429 * Finish the operation
1431 MiSetPageEvent(Process
, Address
);
1432 DPRINT("Address 0x%p\n", Address
);
1433 return(STATUS_SUCCESS
);
1437 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1439 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1441 MmUnlockSectionSegment(Segment
);
1443 * Just map the desired physical page
1445 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1446 Status
= MmCreateVirtualMappingUnsafe(Process
,
1451 if (!NT_SUCCESS(Status
))
1453 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1454 KeBugCheck(MEMORY_MANAGEMENT
);
1459 * Cleanup and release locks
1461 MiSetPageEvent(Process
, Address
);
1462 DPRINT("Address 0x%p\n", Address
);
1463 return(STATUS_SUCCESS
);
1467 * Get the entry corresponding to the offset within the section
1469 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1473 SWAPENTRY FakeSwapEntry
;
1476 * If the entry is zero (and it can't change because we have
1477 * locked the segment) then we need to load the page.
1481 * Release all our locks and read in the page from disk
1483 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1484 MmUnlockSectionSegment(Segment
);
1485 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1486 MmUnlockAddressSpace(AddressSpace
);
1488 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1489 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1490 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1492 MI_SET_USAGE(MI_USAGE_SECTION
);
1493 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1494 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1495 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1496 if (!NT_SUCCESS(Status
))
1498 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1504 Status
= MiReadPage(MemoryArea
, (ULONG_PTR
)Offset
.QuadPart
, &Page
);
1505 if (!NT_SUCCESS(Status
))
1507 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1510 if (!NT_SUCCESS(Status
))
1513 * FIXME: What do we know in this case?
1516 * Cleanup and release locks
1518 MmLockAddressSpace(AddressSpace
);
1519 MiSetPageEvent(Process
, Address
);
1520 DPRINT("Address 0x%p\n", Address
);
1525 * Mark the offset within the section as having valid, in-memory
1528 MmLockAddressSpace(AddressSpace
);
1529 MmLockSectionSegment(Segment
);
1530 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1531 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1532 MmUnlockSectionSegment(Segment
);
1534 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1535 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1536 Page
, Process
, PAddress
, Attributes
);
1537 Status
= MmCreateVirtualMapping(Process
,
1542 if (!NT_SUCCESS(Status
))
1544 DPRINT1("Unable to create virtual mapping\n");
1545 KeBugCheck(MEMORY_MANAGEMENT
);
1547 ASSERT(MmIsPagePresent(Process
, PAddress
));
1548 MmInsertRmap(Page
, Process
, Address
);
1550 MiSetPageEvent(Process
, Address
);
1551 DPRINT("Address 0x%p\n", Address
);
1552 return(STATUS_SUCCESS
);
1554 else if (IS_SWAP_FROM_SSE(Entry
))
1556 SWAPENTRY SwapEntry
;
1558 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1561 * Release all our locks and read in the page from disk
1563 MmUnlockSectionSegment(Segment
);
1565 MmUnlockAddressSpace(AddressSpace
);
1566 MI_SET_USAGE(MI_USAGE_SECTION
);
1567 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1568 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1569 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1570 if (!NT_SUCCESS(Status
))
1572 KeBugCheck(MEMORY_MANAGEMENT
);
1575 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1576 if (!NT_SUCCESS(Status
))
1578 KeBugCheck(MEMORY_MANAGEMENT
);
1582 * Relock the address space and segment
1584 MmLockAddressSpace(AddressSpace
);
1585 MmLockSectionSegment(Segment
);
1588 * Check the entry. No one should change the status of a page
1589 * that has a pending page-in.
1591 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1592 if (Entry
!= Entry1
)
1594 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1595 KeBugCheck(MEMORY_MANAGEMENT
);
1599 * Mark the offset within the section as having valid, in-memory
1602 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1603 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1604 MmUnlockSectionSegment(Segment
);
1607 * Save the swap entry.
1609 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1610 Status
= MmCreateVirtualMapping(Process
,
1615 if (!NT_SUCCESS(Status
))
1617 DPRINT1("Unable to create virtual mapping\n");
1618 KeBugCheck(MEMORY_MANAGEMENT
);
1620 MmInsertRmap(Page
, Process
, Address
);
1621 MiSetPageEvent(Process
, Address
);
1622 DPRINT("Address 0x%p\n", Address
);
1623 return(STATUS_SUCCESS
);
1628 * If the section offset is already in-memory and valid then just
1629 * take another reference to the page
1632 Page
= PFN_FROM_SSE(Entry
);
1634 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1635 MmUnlockSectionSegment(Segment
);
1637 Status
= MmCreateVirtualMapping(Process
,
1642 if (!NT_SUCCESS(Status
))
1644 DPRINT1("Unable to create virtual mapping\n");
1645 KeBugCheck(MEMORY_MANAGEMENT
);
1647 MmInsertRmap(Page
, Process
, Address
);
1648 MiSetPageEvent(Process
, Address
);
1649 DPRINT("Address 0x%p\n", Address
);
1650 return(STATUS_SUCCESS
);
1656 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1657 MEMORY_AREA
* MemoryArea
,
1660 PMM_SECTION_SEGMENT Segment
;
1661 PROS_SECTION_OBJECT Section
;
1666 LARGE_INTEGER Offset
;
1669 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1670 SWAPENTRY SwapEntry
;
1672 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace
, MemoryArea
, Address
);
1675 * Check if the page has already been set readwrite
1677 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1679 DPRINT("Address 0x%p\n", Address
);
1680 return(STATUS_SUCCESS
);
1684 * Find the offset of the page
1686 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1687 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1688 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1690 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1691 Section
= MemoryArea
->Data
.SectionData
.Section
;
1692 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1693 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1695 ASSERT(Region
!= NULL
);
1699 MmLockSectionSegment(Segment
);
1701 OldPage
= MmGetPfnForProcess(Process
, Address
);
1702 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1704 MmUnlockSectionSegment(Segment
);
1707 * Check if we are doing COW
1709 if (!((Segment
->WriteCopy
) &&
1710 (Region
->Protect
== PAGE_READWRITE
||
1711 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1713 DPRINT("Address 0x%p\n", Address
);
1714 return(STATUS_ACCESS_VIOLATION
);
1717 if (IS_SWAP_FROM_SSE(Entry
) ||
1718 PFN_FROM_SSE(Entry
) != OldPage
)
1720 /* This is a private page. We must only change the page protection. */
1721 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1722 return(STATUS_SUCCESS
);
1726 DPRINT("OldPage == 0!\n");
1729 * Get or create a pageop
1731 MmLockSectionSegment(Segment
);
1732 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1735 * Wait for any other operations to complete
1737 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1739 MmUnlockSectionSegment(Segment
);
1740 MmUnlockAddressSpace(AddressSpace
);
1741 MiWaitForPageEvent(NULL
, NULL
);
1743 * Restart the operation
1745 MmLockAddressSpace(AddressSpace
);
1746 DPRINT("Address 0x%p\n", Address
);
1747 return(STATUS_MM_RESTART_OPERATION
);
1750 MmDeleteRmap(OldPage
, Process
, PAddress
);
1751 MmDeleteVirtualMapping(Process
, PAddress
, FALSE
, NULL
, NULL
);
1752 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1755 * Release locks now we have the pageop
1757 MmUnlockSectionSegment(Segment
);
1758 MmUnlockAddressSpace(AddressSpace
);
1763 MI_SET_USAGE(MI_USAGE_SECTION
);
1764 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1765 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1766 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1767 if (!NT_SUCCESS(Status
))
1769 KeBugCheck(MEMORY_MANAGEMENT
);
1775 MiCopyFromUserPage(NewPage
, OldPage
);
1777 MmLockAddressSpace(AddressSpace
);
1780 * Set the PTE to point to the new page
1782 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1783 Status
= MmCreateVirtualMapping(Process
,
1788 if (!NT_SUCCESS(Status
))
1790 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1791 KeBugCheck(MEMORY_MANAGEMENT
);
1796 * Unshare the old page.
1798 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1799 MmInsertRmap(NewPage
, Process
, PAddress
);
1800 MmLockSectionSegment(Segment
);
1801 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1802 MmUnlockSectionSegment(Segment
);
1804 MiSetPageEvent(Process
, Address
);
1805 DPRINT("Address 0x%p\n", Address
);
1806 return(STATUS_SUCCESS
);
1810 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1812 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1814 PFN_NUMBER Page
= 0;
1816 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1819 MmLockAddressSpace(&Process
->Vm
);
1822 MmDeleteVirtualMapping(Process
,
1829 PageOutContext
->WasDirty
= TRUE
;
1831 if (!PageOutContext
->Private
)
1833 MmLockSectionSegment(PageOutContext
->Segment
);
1834 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1835 PageOutContext
->Segment
,
1836 &PageOutContext
->Offset
,
1837 PageOutContext
->WasDirty
,
1839 &PageOutContext
->SectionEntry
);
1840 MmUnlockSectionSegment(PageOutContext
->Segment
);
1844 MmUnlockAddressSpace(&Process
->Vm
);
1847 if (PageOutContext
->Private
)
1849 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1855 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1856 MEMORY_AREA
* MemoryArea
,
1857 PVOID Address
, ULONG_PTR Entry
)
1860 MM_SECTION_PAGEOUT_CONTEXT Context
;
1861 SWAPENTRY SwapEntry
;
1862 ULONGLONG FileOffset
;
1864 PFILE_OBJECT FileObject
;
1868 BOOLEAN DirectMapped
;
1869 BOOLEAN IsImageSection
;
1870 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1873 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1876 * Get the segment and section.
1878 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1879 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1880 Context
.SectionEntry
= Entry
;
1881 Context
.CallingProcess
= Process
;
1883 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1884 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1885 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1887 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1889 FileObject
= Context
.Section
->FileObject
;
1890 DirectMapped
= FALSE
;
1892 MmLockSectionSegment(Context
.Segment
);
1895 if (FileObject
!= NULL
&&
1896 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1898 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1901 * If the file system is letting us go directly to the cache and the
1902 * memory area was mapped at an offset in the file which is page aligned
1903 * then note this is a direct mapped page.
1905 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1906 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1908 DirectMapped
= TRUE
;
1915 * This should never happen since mappings of physical memory are never
1916 * placed in the rmap lists.
1918 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1920 DPRINT1("Trying to page out from physical memory section address 0x%p "
1921 "process %p\n", Address
,
1922 Process
? Process
->UniqueProcessId
: 0);
1923 KeBugCheck(MEMORY_MANAGEMENT
);
1927 * Get the section segment entry and the physical address.
1929 if (!MmIsPagePresent(Process
, Address
))
1931 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
1932 Process
? Process
->UniqueProcessId
: 0, Address
);
1933 KeBugCheck(MEMORY_MANAGEMENT
);
1935 Page
= MmGetPfnForProcess(Process
, Address
);
1936 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1939 * Check the reference count to ensure this page can be paged out
1941 if (MmGetReferenceCountPage(Page
) != 1)
1943 DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
1944 Page
, MmGetReferenceCountPage(Page
));
1945 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1946 MmUnlockSectionSegment(Context
.Segment
);
1947 return STATUS_UNSUCCESSFUL
;
1951 * Prepare the context structure for the rmap delete call.
1953 MmUnlockSectionSegment(Context
.Segment
);
1954 Context
.WasDirty
= FALSE
;
1955 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1956 IS_SWAP_FROM_SSE(Entry
) ||
1957 PFN_FROM_SSE(Entry
) != Page
)
1959 Context
.Private
= TRUE
;
1963 Context
.Private
= FALSE
;
1967 * Take an additional reference to the page or the cache segment.
1969 if (DirectMapped
&& !Context
.Private
)
1971 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
1973 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1974 KeBugCheck(MEMORY_MANAGEMENT
);
1979 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1980 MmReferencePage(Page
);
1981 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1984 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1986 /* Since we passed in a surrogate, we'll get back the page entry
1987 * state in our context. This is intended to make intermediate
1988 * decrements of share count not release the wait entry.
1990 Entry
= Context
.SectionEntry
;
1993 * If this wasn't a private page then we should have reduced the entry to
1994 * zero by deleting all the rmaps.
1996 if (!Context
.Private
&& Entry
!= 0)
1998 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1999 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2001 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2006 * If the page wasn't dirty then we can just free it as for a readonly page.
2007 * Since we unmapped all the mappings above we know it will not suddenly
2009 * If the page is from a pagefile section and has no swap entry,
2010 * we can't free the page at this point.
2012 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2013 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2015 if (Context
.Private
)
2017 DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
2018 Context
.WasDirty
? "dirty" : "clean", Address
);
2019 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2021 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2023 MmSetSavedSwapEntryPage(Page
, 0);
2024 MmLockSectionSegment(Context
.Segment
);
2025 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2026 MmUnlockSectionSegment(Context
.Segment
);
2027 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2028 MiSetPageEvent(NULL
, NULL
);
2029 return(STATUS_SUCCESS
);
2032 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2034 if (Context
.Private
)
2036 DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
2037 Context
.WasDirty
? "dirty" : "clean", Address
);
2038 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2040 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2042 MmSetSavedSwapEntryPage(Page
, 0);
2045 MmLockSectionSegment(Context
.Segment
);
2046 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2047 MmUnlockSectionSegment(Context
.Segment
);
2049 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2050 MiSetPageEvent(NULL
, NULL
);
2051 return(STATUS_SUCCESS
);
2054 else if (!Context
.Private
&& DirectMapped
)
2058 DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
2060 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2063 Status
= CcRosUnmapCacheSegment(Bcb
, (ULONG
)FileOffset
, FALSE
);
2065 Status
= STATUS_SUCCESS
;
2068 if (!NT_SUCCESS(Status
))
2070 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2071 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Bcb
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2074 MiSetPageEvent(NULL
, NULL
);
2075 return(STATUS_SUCCESS
);
2077 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2081 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
2083 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2085 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2086 MiSetPageEvent(NULL
, NULL
);
2087 return(STATUS_SUCCESS
);
2089 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2091 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2092 MmSetSavedSwapEntryPage(Page
, 0);
2093 MmLockAddressSpace(AddressSpace
);
2094 Status
= MmCreatePageFileMapping(Process
,
2097 MmUnlockAddressSpace(AddressSpace
);
2098 if (!NT_SUCCESS(Status
))
2100 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2101 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2103 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2104 MiSetPageEvent(NULL
, NULL
);
2105 return(STATUS_SUCCESS
);
2109 * If necessary, allocate an entry in the paging file for this page
2113 SwapEntry
= MmAllocSwapPage();
2116 MmShowOutOfSpaceMessagePagingFile();
2117 MmLockAddressSpace(AddressSpace
);
2119 * For private pages restore the old mappings.
2121 if (Context
.Private
)
2123 Status
= MmCreateVirtualMapping(Process
,
2125 MemoryArea
->Protect
,
2128 MmSetDirtyPage(Process
, Address
);
2137 * For non-private pages if the page wasn't direct mapped then
2138 * set it back into the section segment entry so we don't loose
2139 * our copy. Otherwise it will be handled by the cache manager.
2141 Status
= MmCreateVirtualMapping(Process
,
2143 MemoryArea
->Protect
,
2146 MmSetDirtyPage(Process
, Address
);
2150 // If we got here, the previous entry should have been a wait
2151 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2152 MmLockSectionSegment(Context
.Segment
);
2153 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2154 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2155 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2156 MmUnlockSectionSegment(Context
.Segment
);
2158 MmUnlockAddressSpace(AddressSpace
);
2159 MiSetPageEvent(NULL
, NULL
);
2160 return(STATUS_PAGEFILE_QUOTA
);
2165 * Write the page to the pagefile
2167 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2168 if (!NT_SUCCESS(Status
))
2170 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2173 * As above: undo our actions.
2174 * FIXME: Also free the swap page.
2176 MmLockAddressSpace(AddressSpace
);
2177 if (Context
.Private
)
2179 Status
= MmCreateVirtualMapping(Process
,
2181 MemoryArea
->Protect
,
2184 MmSetDirtyPage(Process
, Address
);
2191 Status
= MmCreateVirtualMapping(Process
,
2193 MemoryArea
->Protect
,
2196 MmSetDirtyPage(Process
, Address
);
2200 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2201 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2203 MmUnlockAddressSpace(AddressSpace
);
2204 MiSetPageEvent(NULL
, NULL
);
2205 return(STATUS_UNSUCCESSFUL
);
2209 * Otherwise we have succeeded.
2211 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2212 MmSetSavedSwapEntryPage(Page
, 0);
2213 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2214 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2216 MmLockSectionSegment(Context
.Segment
);
2217 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2218 MmUnlockSectionSegment(Context
.Segment
);
2222 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2225 if (Context
.Private
)
2227 MmLockAddressSpace(AddressSpace
);
2228 MmLockSectionSegment(Context
.Segment
);
2229 Status
= MmCreatePageFileMapping(Process
,
2232 /* We had placed a wait entry upon entry ... replace it before leaving */
2233 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2234 MmUnlockSectionSegment(Context
.Segment
);
2235 MmUnlockAddressSpace(AddressSpace
);
2236 if (!NT_SUCCESS(Status
))
2238 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2239 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2244 MmLockAddressSpace(AddressSpace
);
2245 MmLockSectionSegment(Context
.Segment
);
2246 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2247 /* We had placed a wait entry upon entry ... replace it before leaving */
2248 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2249 MmUnlockSectionSegment(Context
.Segment
);
2250 MmUnlockAddressSpace(AddressSpace
);
2253 MiSetPageEvent(NULL
, NULL
);
2254 return(STATUS_SUCCESS
);
2259 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2260 PMEMORY_AREA MemoryArea
,
2264 LARGE_INTEGER Offset
;
2265 PROS_SECTION_OBJECT Section
;
2266 PMM_SECTION_SEGMENT Segment
;
2268 SWAPENTRY SwapEntry
;
2272 PFILE_OBJECT FileObject
;
2274 BOOLEAN DirectMapped
;
2275 BOOLEAN IsImageSection
;
2276 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2278 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2280 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2281 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2284 * Get the segment and section.
2286 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2287 Section
= MemoryArea
->Data
.SectionData
.Section
;
2288 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2290 FileObject
= Section
->FileObject
;
2291 DirectMapped
= FALSE
;
2292 if (FileObject
!= NULL
&&
2293 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2295 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2298 * If the file system is letting us go directly to the cache and the
2299 * memory area was mapped at an offset in the file which is page aligned
2300 * then note this is a direct mapped page.
2302 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2303 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2305 DirectMapped
= TRUE
;
2310 * This should never happen since mappings of physical memory are never
2311 * placed in the rmap lists.
2313 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2315 DPRINT1("Trying to write back page from physical memory mapped at %p "
2316 "process %p\n", Address
,
2317 Process
? Process
->UniqueProcessId
: 0);
2318 KeBugCheck(MEMORY_MANAGEMENT
);
2322 * Get the section segment entry and the physical address.
2324 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2325 if (!MmIsPagePresent(Process
, Address
))
2327 DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
2328 Process
? Process
->UniqueProcessId
: 0, Address
);
2329 KeBugCheck(MEMORY_MANAGEMENT
);
2331 Page
= MmGetPfnForProcess(Process
, Address
);
2332 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2335 * Check for a private (COWed) page.
2337 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2338 IS_SWAP_FROM_SSE(Entry
) ||
2339 PFN_FROM_SSE(Entry
) != Page
)
2349 * Speculatively set all mappings of the page to clean.
2351 MmSetCleanAllRmaps(Page
);
2354 * If this page was direct mapped from the cache then the cache manager
2355 * will take care of writing it back to disk.
2357 if (DirectMapped
&& !Private
)
2359 //LARGE_INTEGER SOffset;
2360 ASSERT(SwapEntry
== 0);
2361 //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
2363 CcRosMarkDirtyCacheSegment(Bcb
, Offset
.LowPart
);
2365 MmLockSectionSegment(Segment
);
2366 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2367 MmUnlockSectionSegment(Segment
);
2368 MiSetPageEvent(NULL
, NULL
);
2369 return(STATUS_SUCCESS
);
2373 * If necessary, allocate an entry in the paging file for this page
2377 SwapEntry
= MmAllocSwapPage();
2380 MmSetDirtyAllRmaps(Page
);
2381 MiSetPageEvent(NULL
, NULL
);
2382 return(STATUS_PAGEFILE_QUOTA
);
2384 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2388 * Write the page to the pagefile
2390 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2391 if (!NT_SUCCESS(Status
))
2393 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2395 MmSetDirtyAllRmaps(Page
);
2396 MiSetPageEvent(NULL
, NULL
);
2397 return(STATUS_UNSUCCESSFUL
);
2401 * Otherwise we have succeeded.
2403 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2404 MiSetPageEvent(NULL
, NULL
);
2405 return(STATUS_SUCCESS
);
2409 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2417 PMEMORY_AREA MemoryArea
;
2418 PMM_SECTION_SEGMENT Segment
;
2419 BOOLEAN DoCOW
= FALSE
;
2421 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2423 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2424 ASSERT(MemoryArea
!= NULL
);
2425 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2426 MmLockSectionSegment(Segment
);
2428 if ((Segment
->WriteCopy
) &&
2429 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2434 if (OldProtect
!= NewProtect
)
2436 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2438 SWAPENTRY SwapEntry
;
2439 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2440 ULONG Protect
= NewProtect
;
2442 /* Wait for a wait entry to disappear */
2444 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2445 if (SwapEntry
!= MM_WAIT_ENTRY
)
2447 MiWaitForPageEvent(Process
, Address
);
2451 * If we doing COW for this segment then check if the page is
2454 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2456 LARGE_INTEGER Offset
;
2460 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2461 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2462 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2464 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2465 * IS_SWAP_FROM_SSE and we'll do the right thing.
2467 Page
= MmGetPfnForProcess(Process
, Address
);
2469 Protect
= PAGE_READONLY
;
2470 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2471 IS_SWAP_FROM_SSE(Entry
) ||
2472 PFN_FROM_SSE(Entry
) != Page
)
2474 Protect
= NewProtect
;
2478 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2480 MmSetPageProtect(Process
, Address
,
2486 MmUnlockSectionSegment(Segment
);
2491 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2492 PMEMORY_AREA MemoryArea
,
2500 ULONG_PTR MaxLength
;
2502 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2503 if (Length
> MaxLength
)
2504 Length
= (ULONG
)MaxLength
;
2506 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2507 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2509 ASSERT(Region
!= NULL
);
2511 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2512 Region
->Protect
!= Protect
)
2514 return STATUS_INVALID_PAGE_PROTECTION
;
2517 *OldProtect
= Region
->Protect
;
2518 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2519 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2520 BaseAddress
, Length
, Region
->Type
, Protect
,
2521 MmAlterViewAttributes
);
2527 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2529 PMEMORY_BASIC_INFORMATION Info
,
2530 PSIZE_T ResultLength
)
2533 PVOID RegionBaseAddress
;
2534 PROS_SECTION_OBJECT Section
;
2535 PMM_SECTION_SEGMENT Segment
;
2537 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2538 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2539 Address
, &RegionBaseAddress
);
2542 return STATUS_UNSUCCESSFUL
;
2545 Section
= MemoryArea
->Data
.SectionData
.Section
;
2546 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2548 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2549 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2550 Info
->Type
= MEM_IMAGE
;
2554 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2555 Info
->Type
= MEM_MAPPED
;
2557 Info
->BaseAddress
= RegionBaseAddress
;
2558 Info
->AllocationProtect
= MemoryArea
->Protect
;
2559 Info
->RegionSize
= Region
->Length
;
2560 Info
->State
= MEM_COMMIT
;
2561 Info
->Protect
= Region
->Protect
;
2563 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2564 return(STATUS_SUCCESS
);
2569 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2572 LARGE_INTEGER Offset
;
2574 SWAPENTRY SavedSwapEntry
;
2579 MmLockSectionSegment(Segment
);
2581 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2582 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2584 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2587 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2588 if (IS_SWAP_FROM_SSE(Entry
))
2590 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2594 Page
= PFN_FROM_SSE(Entry
);
2595 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2596 if (SavedSwapEntry
!= 0)
2598 MmSetSavedSwapEntryPage(Page
, 0);
2599 MmFreeSwapPage(SavedSwapEntry
);
2601 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2606 MmUnlockSectionSegment(Segment
);
2610 MmpDeleteSection(PVOID ObjectBody
)
2612 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2614 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2615 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2620 PMM_SECTION_SEGMENT SectionSegments
;
2623 * NOTE: Section->ImageSection can be NULL for short time
2624 * during the section creating. If we fail for some reason
2625 * until the image section is properly initialized we shouldn't
2626 * process further here.
2628 if (Section
->ImageSection
== NULL
)
2631 SectionSegments
= Section
->ImageSection
->Segments
;
2632 NrSegments
= Section
->ImageSection
->NrSegments
;
2634 for (i
= 0; i
< NrSegments
; i
++)
2636 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2638 MmLockSectionSegment(&SectionSegments
[i
]);
2640 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2641 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2643 MmUnlockSectionSegment(&SectionSegments
[i
]);
2646 MmpFreePageFileSegment(&SectionSegments
[i
]);
2652 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2655 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2658 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2660 DPRINT("Freeing section segment\n");
2661 Section
->Segment
= NULL
;
2662 MmFinalizeSegment(Segment
);
2666 DPRINT("RefCount %d\n", RefCount
);
2673 * NOTE: Section->Segment can be NULL for short time
2674 * during the section creating.
2676 if (Section
->Segment
== NULL
)
2679 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2681 MmpFreePageFileSegment(Section
->Segment
);
2682 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2683 ExFreePool(Section
->Segment
);
2684 Section
->Segment
= NULL
;
2688 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2691 if (Section
->FileObject
!= NULL
)
2694 CcRosDereferenceCache(Section
->FileObject
);
2696 ObDereferenceObject(Section
->FileObject
);
2697 Section
->FileObject
= NULL
;
2702 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2704 IN ACCESS_MASK GrantedAccess
,
2705 IN ULONG ProcessHandleCount
,
2706 IN ULONG SystemHandleCount
)
2708 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object
, ProcessHandleCount
);
2714 MmCreatePhysicalMemorySection(VOID
)
2716 PROS_SECTION_OBJECT PhysSection
;
2718 OBJECT_ATTRIBUTES Obj
;
2719 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2720 LARGE_INTEGER SectionSize
;
2724 * Create the section mapping physical memory
2726 SectionSize
.QuadPart
= 0xFFFFFFFF;
2727 InitializeObjectAttributes(&Obj
,
2732 Status
= MmCreateSection((PVOID
)&PhysSection
,
2736 PAGE_EXECUTE_READWRITE
,
2740 if (!NT_SUCCESS(Status
))
2742 DPRINT1("Failed to create PhysicalMemory section\n");
2743 KeBugCheck(MEMORY_MANAGEMENT
);
2745 Status
= ObInsertObject(PhysSection
,
2751 if (!NT_SUCCESS(Status
))
2753 ObDereferenceObject(PhysSection
);
2755 ObCloseHandle(Handle
, KernelMode
);
2756 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2757 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2759 return(STATUS_SUCCESS
);
2765 MmInitSectionImplementation(VOID
)
2767 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2768 UNICODE_STRING Name
;
2770 DPRINT("Creating Section Object Type\n");
2772 /* Initialize the section based root */
2773 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2774 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2776 /* Initialize the Section object type */
2777 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2778 RtlInitUnicodeString(&Name
, L
"Section");
2779 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2780 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2781 ObjectTypeInitializer
.PoolType
= PagedPool
;
2782 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2783 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2784 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2785 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2786 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2787 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2788 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2790 MmCreatePhysicalMemorySection();
2792 return(STATUS_SUCCESS
);
2797 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2798 ACCESS_MASK DesiredAccess
,
2799 POBJECT_ATTRIBUTES ObjectAttributes
,
2800 PLARGE_INTEGER UMaximumSize
,
2801 ULONG SectionPageProtection
,
2802 ULONG AllocationAttributes
)
2804 * Create a section which is backed by the pagefile
2807 LARGE_INTEGER MaximumSize
;
2808 PROS_SECTION_OBJECT Section
;
2809 PMM_SECTION_SEGMENT Segment
;
2812 if (UMaximumSize
== NULL
)
2814 return(STATUS_UNSUCCESSFUL
);
2816 MaximumSize
= *UMaximumSize
;
2819 * Create the section
2821 Status
= ObCreateObject(ExGetPreviousMode(),
2822 MmSectionObjectType
,
2824 ExGetPreviousMode(),
2826 sizeof(ROS_SECTION_OBJECT
),
2829 (PVOID
*)(PVOID
)&Section
);
2830 if (!NT_SUCCESS(Status
))
2838 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2839 Section
->Type
= 'SC';
2840 Section
->Size
= 'TN';
2841 Section
->SectionPageProtection
= SectionPageProtection
;
2842 Section
->AllocationAttributes
= AllocationAttributes
;
2843 Section
->MaximumSize
= MaximumSize
;
2844 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2845 TAG_MM_SECTION_SEGMENT
);
2846 if (Segment
== NULL
)
2848 ObDereferenceObject(Section
);
2849 return(STATUS_NO_MEMORY
);
2851 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2852 Section
->Segment
= Segment
;
2853 Segment
->ReferenceCount
= 1;
2854 ExInitializeFastMutex(&Segment
->Lock
);
2855 Segment
->Image
.FileOffset
= 0;
2856 Segment
->Protection
= SectionPageProtection
;
2857 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2858 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2859 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2860 Segment
->WriteCopy
= FALSE
;
2861 Segment
->Image
.VirtualAddress
= 0;
2862 Segment
->Image
.Characteristics
= 0;
2863 *SectionObject
= Section
;
2864 MiInitializeSectionPageTable(Segment
);
2865 return(STATUS_SUCCESS
);
2870 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2871 ACCESS_MASK DesiredAccess
,
2872 POBJECT_ATTRIBUTES ObjectAttributes
,
2873 PLARGE_INTEGER UMaximumSize
,
2874 ULONG SectionPageProtection
,
2875 ULONG AllocationAttributes
,
2878 * Create a section backed by a data file
2881 PROS_SECTION_OBJECT Section
;
2883 LARGE_INTEGER MaximumSize
;
2884 PFILE_OBJECT FileObject
;
2885 PMM_SECTION_SEGMENT Segment
;
2887 IO_STATUS_BLOCK Iosb
;
2888 LARGE_INTEGER Offset
;
2890 FILE_STANDARD_INFORMATION FileInfo
;
2894 * Create the section
2896 Status
= ObCreateObject(ExGetPreviousMode(),
2897 MmSectionObjectType
,
2899 ExGetPreviousMode(),
2901 sizeof(ROS_SECTION_OBJECT
),
2905 if (!NT_SUCCESS(Status
))
2912 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2913 Section
->Type
= 'SC';
2914 Section
->Size
= 'TN';
2915 Section
->SectionPageProtection
= SectionPageProtection
;
2916 Section
->AllocationAttributes
= AllocationAttributes
;
2919 * Reference the file handle
2921 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2922 Status
= ObReferenceObjectByHandle(FileHandle
,
2925 ExGetPreviousMode(),
2926 (PVOID
*)(PVOID
)&FileObject
,
2928 if (!NT_SUCCESS(Status
))
2930 ObDereferenceObject(Section
);
2935 * FIXME: This is propably not entirely correct. We can't look into
2936 * the standard FCB header because it might not be initialized yet
2937 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2938 * standard file information is filled on first request).
2940 Status
= IoQueryFileInformation(FileObject
,
2941 FileStandardInformation
,
2942 sizeof(FILE_STANDARD_INFORMATION
),
2945 Iosb
.Information
= Length
;
2946 if (!NT_SUCCESS(Status
))
2948 ObDereferenceObject(Section
);
2949 ObDereferenceObject(FileObject
);
2954 * FIXME: Revise this once a locking order for file size changes is
2957 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2959 MaximumSize
= *UMaximumSize
;
2963 MaximumSize
= FileInfo
.EndOfFile
;
2964 /* Mapping zero-sized files isn't allowed. */
2965 if (MaximumSize
.QuadPart
== 0)
2967 ObDereferenceObject(Section
);
2968 ObDereferenceObject(FileObject
);
2969 return STATUS_FILE_INVALID
;
2973 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2975 Status
= IoSetInformation(FileObject
,
2976 FileAllocationInformation
,
2977 sizeof(LARGE_INTEGER
),
2979 if (!NT_SUCCESS(Status
))
2981 ObDereferenceObject(Section
);
2982 ObDereferenceObject(FileObject
);
2983 return(STATUS_SECTION_NOT_EXTENDED
);
2987 if (FileObject
->SectionObjectPointer
== NULL
||
2988 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2991 * Read a bit so caching is initiated for the file object.
2992 * This is only needed because MiReadPage currently cannot
2993 * handle non-cached streams.
2995 Offset
.QuadPart
= 0;
2996 Status
= ZwReadFile(FileHandle
,
3005 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3007 ObDereferenceObject(Section
);
3008 ObDereferenceObject(FileObject
);
3011 if (FileObject
->SectionObjectPointer
== NULL
||
3012 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3014 /* FIXME: handle this situation */
3015 ObDereferenceObject(Section
);
3016 ObDereferenceObject(FileObject
);
3017 return STATUS_INVALID_PARAMETER
;
3024 Status
= MmspWaitForFileLock(FileObject
);
3025 if (Status
!= STATUS_SUCCESS
)
3027 ObDereferenceObject(Section
);
3028 ObDereferenceObject(FileObject
);
3033 * If this file hasn't been mapped as a data file before then allocate a
3034 * section segment to describe the data file mapping
3036 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3038 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3039 TAG_MM_SECTION_SEGMENT
);
3040 if (Segment
== NULL
)
3042 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3043 ObDereferenceObject(Section
);
3044 ObDereferenceObject(FileObject
);
3045 return(STATUS_NO_MEMORY
);
3047 Section
->Segment
= Segment
;
3048 Segment
->ReferenceCount
= 1;
3049 ExInitializeFastMutex(&Segment
->Lock
);
3051 * Set the lock before assigning the segment to the file object
3053 ExAcquireFastMutex(&Segment
->Lock
);
3054 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3056 Segment
->Image
.FileOffset
= 0;
3057 Segment
->Protection
= SectionPageProtection
;
3058 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3059 Segment
->Image
.Characteristics
= 0;
3060 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3061 if (AllocationAttributes
& SEC_RESERVE
)
3063 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3067 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3068 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3070 Segment
->Image
.VirtualAddress
= 0;
3071 Segment
->Locked
= TRUE
;
3072 MiInitializeSectionPageTable(Segment
);
3077 * If the file is already mapped as a data file then we may need
3081 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3083 Section
->Segment
= Segment
;
3084 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3085 MmLockSectionSegment(Segment
);
3087 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3088 !(AllocationAttributes
& SEC_RESERVE
))
3090 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3091 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3094 MmUnlockSectionSegment(Segment
);
3095 Section
->FileObject
= FileObject
;
3096 Section
->MaximumSize
= MaximumSize
;
3098 CcRosReferenceCache(FileObject
);
3100 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3101 *SectionObject
= Section
;
3102 return(STATUS_SUCCESS
);
3106 TODO: not that great (declaring loaders statically, having to declare all of
3107 them, having to keep them extern, etc.), will fix in the future
3109 extern NTSTATUS NTAPI PeFmtCreateSection
3111 IN CONST VOID
* FileHeader
,
3112 IN SIZE_T FileHeaderSize
,
3114 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3116 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3117 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3120 extern NTSTATUS NTAPI ElfFmtCreateSection
3122 IN CONST VOID
* FileHeader
,
3123 IN SIZE_T FileHeaderSize
,
3125 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3127 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3128 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3131 /* TODO: this is a standard DDK/PSDK macro */
3132 #ifndef RTL_NUMBER_OF
3133 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3136 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3147 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3149 SIZE_T SizeOfSegments
;
3150 PMM_SECTION_SEGMENT Segments
;
3152 /* TODO: check for integer overflow */
3153 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3155 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3157 TAG_MM_SECTION_SEGMENT
);
3160 RtlZeroMemory(Segments
, SizeOfSegments
);
3168 ExeFmtpReadFile(IN PVOID File
,
3169 IN PLARGE_INTEGER Offset
,
3172 OUT PVOID
* AllocBase
,
3173 OUT PULONG ReadSize
)
3176 LARGE_INTEGER FileOffset
;
3178 ULONG OffsetAdjustment
;
3182 PFILE_OBJECT FileObject
= File
;
3183 IO_STATUS_BLOCK Iosb
;
3185 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3189 KeBugCheck(MEMORY_MANAGEMENT
);
3192 FileOffset
= *Offset
;
3194 /* Negative/special offset: it cannot be used in this context */
3195 if(FileOffset
.u
.HighPart
< 0)
3197 KeBugCheck(MEMORY_MANAGEMENT
);
3200 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3201 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3202 FileOffset
.u
.LowPart
= AdjustOffset
;
3204 BufferSize
= Length
+ OffsetAdjustment
;
3205 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3208 * It's ok to use paged pool, because this is a temporary buffer only used in
3209 * the loading of executables. The assumption is that MmCreateSection is
3210 * always called at low IRQLs and that these buffers don't survive a brief
3211 * initialization phase
3213 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3218 KeBugCheck(MEMORY_MANAGEMENT
);
3223 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3225 UsedSize
= (ULONG
)Iosb
.Information
;
3227 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3229 Status
= STATUS_IN_PAGE_ERROR
;
3230 ASSERT(!NT_SUCCESS(Status
));
3233 if(NT_SUCCESS(Status
))
3235 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3236 *AllocBase
= Buffer
;
3237 *ReadSize
= UsedSize
- OffsetAdjustment
;
3241 ExFreePoolWithTag(Buffer
, 'rXmM');
3248 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3249 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3250 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3255 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3259 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3261 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3262 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3269 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3273 MmspAssertSegmentsSorted(ImageSectionObject
);
3275 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3277 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3281 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3282 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3283 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3291 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3295 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3297 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3298 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3306 MmspCompareSegments(const void * x
,
3309 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3310 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3313 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3314 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3318 * Ensures an image section's segments are sorted in memory
3323 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3326 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3328 MmspAssertSegmentsSorted(ImageSectionObject
);
3332 qsort(ImageSectionObject
->Segments
,
3333 ImageSectionObject
->NrSegments
,
3334 sizeof(ImageSectionObject
->Segments
[0]),
3335 MmspCompareSegments
);
3341 * Ensures an image section's segments don't overlap in memory and don't have
3342 * gaps and don't have a null size. We let them map to overlapping file regions,
3343 * though - that's not necessarily an error
3348 MmspCheckSegmentBounds
3350 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3356 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3358 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3362 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3364 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3366 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3374 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3375 * page could be OK (Windows seems to be OK with them), and larger gaps
3376 * could lead to image sections spanning several discontiguous regions
3377 * (NtMapViewOfSection could then refuse to map them, and they could
3378 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3380 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3381 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3382 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3393 * Merges and pads an image section's segments until they all are page-aligned
3394 * and have a size that is a multiple of the page size
3399 MmspPageAlignSegments
3401 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3407 PMM_SECTION_SEGMENT EffectiveSegment
;
3409 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3411 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3416 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3418 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3421 * The first segment requires special handling
3425 ULONG_PTR VirtualAddress
;
3426 ULONG_PTR VirtualOffset
;
3428 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3430 /* Round down the virtual address to the nearest page */
3431 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3433 /* Round up the virtual size to the nearest page */
3434 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3435 EffectiveSegment
->Image
.VirtualAddress
;
3437 /* Adjust the raw address and size */
3438 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3440 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3446 * Garbage in, garbage out: unaligned base addresses make the file
3447 * offset point in curious and odd places, but that's what we were
3450 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3451 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3455 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3456 ULONG_PTR EndOfEffectiveSegment
;
3458 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3459 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3462 * The current segment begins exactly where the current effective
3463 * segment ended, therefore beginning a new effective segment
3465 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3468 ASSERT(LastSegment
<= i
);
3469 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3471 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3473 if (LastSegment
!= i
)
3476 * Copy the current segment. If necessary, the effective segment
3477 * will be expanded later
3479 *EffectiveSegment
= *Segment
;
3483 * Page-align the virtual size. We know for sure the virtual address
3486 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3487 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3490 * The current segment is still part of the current effective segment:
3491 * extend the effective segment to reflect this
3493 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3495 static const ULONG FlagsToProtection
[16] =
3503 PAGE_EXECUTE_READWRITE
,
3504 PAGE_EXECUTE_READWRITE
,
3509 PAGE_EXECUTE_WRITECOPY
,
3510 PAGE_EXECUTE_WRITECOPY
,
3511 PAGE_EXECUTE_WRITECOPY
,
3512 PAGE_EXECUTE_WRITECOPY
3515 unsigned ProtectionFlags
;
3518 * Extend the file size
3521 /* Unaligned segments must be contiguous within the file */
3522 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3523 EffectiveSegment
->RawLength
.QuadPart
))
3528 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3531 * Extend the virtual size
3533 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3535 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3536 EffectiveSegment
->Image
.VirtualAddress
;
3539 * Merge the protection
3541 EffectiveSegment
->Protection
|= Segment
->Protection
;
3543 /* Clean up redundance */
3544 ProtectionFlags
= 0;
3546 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3547 ProtectionFlags
|= 1 << 0;
3549 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3550 ProtectionFlags
|= 1 << 1;
3552 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3553 ProtectionFlags
|= 1 << 2;
3555 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3556 ProtectionFlags
|= 1 << 3;
3558 ASSERT(ProtectionFlags
< 16);
3559 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3561 /* If a segment was required to be shared and cannot, fail */
3562 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3563 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3569 * We assume no holes between segments at this point
3573 KeBugCheck(MEMORY_MANAGEMENT
);
3577 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3583 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3584 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3586 LARGE_INTEGER Offset
;
3588 PVOID FileHeaderBuffer
;
3589 ULONG FileHeaderSize
;
3591 ULONG OldNrSegments
;
3596 * Read the beginning of the file (2 pages). Should be enough to contain
3597 * all (or most) of the headers
3599 Offset
.QuadPart
= 0;
3601 /* FIXME: use FileObject instead of FileHandle */
3602 Status
= ExeFmtpReadFile (FileHandle
,
3609 if (!NT_SUCCESS(Status
))
3612 if (FileHeaderSize
== 0)
3614 ExFreePool(FileHeaderBuffer
);
3615 return STATUS_UNSUCCESSFUL
;
3619 * Look for a loader that can handle this executable
3621 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3623 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3626 /* FIXME: use FileObject instead of FileHandle */
3627 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3633 ExeFmtpAllocateSegments
);
3635 if (!NT_SUCCESS(Status
))
3637 if (ImageSectionObject
->Segments
)
3639 ExFreePool(ImageSectionObject
->Segments
);
3640 ImageSectionObject
->Segments
= NULL
;
3644 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3648 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3651 * No loader handled the format
3653 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3655 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3656 ASSERT(!NT_SUCCESS(Status
));
3659 if (!NT_SUCCESS(Status
))
3662 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3667 /* FIXME? are these values platform-dependent? */
3668 if (ImageSectionObject
->ImageInformation
.MaximumStackSize
== 0)
3669 ImageSectionObject
->ImageInformation
.MaximumStackSize
= 0x40000;
3671 if(ImageSectionObject
->ImageInformation
.CommittedStackSize
== 0)
3672 ImageSectionObject
->ImageInformation
.CommittedStackSize
= 0x1000;
3674 if(ImageSectionObject
->BasedAddress
== NULL
)
3676 if(ImageSectionObject
->ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3677 ImageSectionObject
->BasedAddress
= (PVOID
)0x10000000;
3679 ImageSectionObject
->BasedAddress
= (PVOID
)0x00400000;
3683 * And now the fun part: fixing the segments
3686 /* Sort them by virtual address */
3687 MmspSortSegments(ImageSectionObject
, Flags
);
3689 /* Ensure they don't overlap in memory */
3690 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3691 return STATUS_INVALID_IMAGE_FORMAT
;
3693 /* Ensure they are aligned */
3694 OldNrSegments
= ImageSectionObject
->NrSegments
;
3696 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3697 return STATUS_INVALID_IMAGE_FORMAT
;
3699 /* Trim them if the alignment phase merged some of them */
3700 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3702 PMM_SECTION_SEGMENT Segments
;
3703 SIZE_T SizeOfSegments
;
3705 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3707 Segments
= ExAllocatePoolWithTag(PagedPool
,
3709 TAG_MM_SECTION_SEGMENT
);
3711 if (Segments
== NULL
)
3712 return STATUS_INSUFFICIENT_RESOURCES
;
3714 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3715 ExFreePool(ImageSectionObject
->Segments
);
3716 ImageSectionObject
->Segments
= Segments
;
3719 /* And finish their initialization */
3720 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3722 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3723 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3724 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3727 ASSERT(NT_SUCCESS(Status
));
3732 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3733 ACCESS_MASK DesiredAccess
,
3734 POBJECT_ATTRIBUTES ObjectAttributes
,
3735 PLARGE_INTEGER UMaximumSize
,
3736 ULONG SectionPageProtection
,
3737 ULONG AllocationAttributes
,
3738 PFILE_OBJECT FileObject
)
3740 PROS_SECTION_OBJECT Section
;
3742 PMM_SECTION_SEGMENT SectionSegments
;
3743 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3746 if (FileObject
== NULL
)
3747 return STATUS_INVALID_FILE_FOR_SECTION
;
3750 * Create the section
3752 Status
= ObCreateObject (ExGetPreviousMode(),
3753 MmSectionObjectType
,
3755 ExGetPreviousMode(),
3757 sizeof(ROS_SECTION_OBJECT
),
3760 (PVOID
*)(PVOID
)&Section
);
3761 if (!NT_SUCCESS(Status
))
3763 ObDereferenceObject(FileObject
);
3770 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3771 Section
->Type
= 'SC';
3772 Section
->Size
= 'TN';
3773 Section
->SectionPageProtection
= SectionPageProtection
;
3774 Section
->AllocationAttributes
= AllocationAttributes
;
3778 * Initialized caching for this file object if previously caching
3779 * was initialized for the same on disk file
3781 Status
= CcTryToInitializeFileCache(FileObject
);
3783 Status
= STATUS_SUCCESS
;
3786 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3788 NTSTATUS StatusExeFmt
;
3790 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3791 if (ImageSectionObject
== NULL
)
3793 ObDereferenceObject(FileObject
);
3794 ObDereferenceObject(Section
);
3795 return(STATUS_NO_MEMORY
);
3798 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3800 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3802 if (!NT_SUCCESS(StatusExeFmt
))
3804 if(ImageSectionObject
->Segments
!= NULL
)
3805 ExFreePool(ImageSectionObject
->Segments
);
3807 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3808 ObDereferenceObject(Section
);
3809 ObDereferenceObject(FileObject
);
3810 return(StatusExeFmt
);
3813 Section
->ImageSection
= ImageSectionObject
;
3814 ASSERT(ImageSectionObject
->Segments
);
3819 Status
= MmspWaitForFileLock(FileObject
);
3820 if (!NT_SUCCESS(Status
))
3822 ExFreePool(ImageSectionObject
->Segments
);
3823 ExFreePool(ImageSectionObject
);
3824 ObDereferenceObject(Section
);
3825 ObDereferenceObject(FileObject
);
3829 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3830 ImageSectionObject
, NULL
))
3833 * An other thread has initialized the same image in the background
3835 ExFreePool(ImageSectionObject
->Segments
);
3836 ExFreePool(ImageSectionObject
);
3837 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3838 Section
->ImageSection
= ImageSectionObject
;
3839 SectionSegments
= ImageSectionObject
->Segments
;
3841 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3843 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3847 Status
= StatusExeFmt
;
3854 Status
= MmspWaitForFileLock(FileObject
);
3855 if (Status
!= STATUS_SUCCESS
)
3857 ObDereferenceObject(Section
);
3858 ObDereferenceObject(FileObject
);
3862 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3863 Section
->ImageSection
= ImageSectionObject
;
3864 SectionSegments
= ImageSectionObject
->Segments
;
3867 * Otherwise just reference all the section segments
3869 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3871 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3874 Status
= STATUS_SUCCESS
;
3876 Section
->FileObject
= FileObject
;
3878 CcRosReferenceCache(FileObject
);
3880 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3881 *SectionObject
= Section
;
3888 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3889 PROS_SECTION_OBJECT Section
,
3890 PMM_SECTION_SEGMENT Segment
,
3895 ULONG AllocationType
)
3899 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3901 if (Segment
->WriteCopy
)
3903 /* We have to do this because the not present fault
3904 * and access fault handlers depend on the protection
3905 * that should be granted AFTER the COW fault takes
3906 * place to be in Region->Protect. The not present fault
3907 * handler changes this to the correct protection for COW when
3908 * mapping the pages into the process's address space. If a COW
3909 * fault takes place, the access fault handler sets the page protection
3910 * to these values for the newly copied pages
3912 if (Protect
== PAGE_WRITECOPY
)
3913 Protect
= PAGE_READWRITE
;
3914 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3915 Protect
= PAGE_EXECUTE_READWRITE
;
3918 BoundaryAddressMultiple
.QuadPart
= 0;
3921 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
3922 LARGE_INTEGER FileOffset
;
3923 FileOffset
.QuadPart
= ViewOffset
;
3924 ObReferenceObject(Section
);
3925 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3928 Status
= MmCreateMemoryArea(AddressSpace
,
3929 MEMORY_AREA_SECTION_VIEW
,
3936 BoundaryAddressMultiple
);
3937 if (!NT_SUCCESS(Status
))
3939 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3940 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3944 ObReferenceObject((PVOID
)Section
);
3946 MArea
->Data
.SectionData
.Segment
= Segment
;
3947 MArea
->Data
.SectionData
.Section
= Section
;
3948 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3949 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3950 ViewSize
, 0, Protect
);
3952 return(STATUS_SUCCESS
);
3957 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3958 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3961 PFILE_OBJECT FileObject
;
3963 LARGE_INTEGER Offset
;
3964 SWAPENTRY SavedSwapEntry
;
3965 PROS_SECTION_OBJECT Section
;
3966 PMM_SECTION_SEGMENT Segment
;
3967 PMMSUPPORT AddressSpace
;
3970 AddressSpace
= (PMMSUPPORT
)Context
;
3971 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3973 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3975 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3976 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3978 Section
= MemoryArea
->Data
.SectionData
.Section
;
3979 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3981 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3982 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
3984 MmUnlockSectionSegment(Segment
);
3985 MmUnlockAddressSpace(AddressSpace
);
3987 MiWaitForPageEvent(NULL
, NULL
);
3989 MmLockAddressSpace(AddressSpace
);
3990 MmLockSectionSegment(Segment
);
3991 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3995 * For a dirty, datafile, non-private page mark it as dirty in the
3998 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4000 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4002 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4003 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4005 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)(Offset
.QuadPart
+ Segment
->Image
.FileOffset
));
4007 ASSERT(SwapEntry
== 0);
4016 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4018 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4019 KeBugCheck(MEMORY_MANAGEMENT
);
4021 MmFreeSwapPage(SwapEntry
);
4025 if (IS_SWAP_FROM_SSE(Entry
) ||
4026 Page
!= PFN_FROM_SSE(Entry
))
4031 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4033 DPRINT1("Found a private page in a pagefile section.\n");
4034 KeBugCheck(MEMORY_MANAGEMENT
);
4037 * Just dereference private pages
4039 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4040 if (SavedSwapEntry
!= 0)
4042 MmFreeSwapPage(SavedSwapEntry
);
4043 MmSetSavedSwapEntryPage(Page
, 0);
4045 MmDeleteRmap(Page
, Process
, Address
);
4046 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4050 MmDeleteRmap(Page
, Process
, Address
);
4051 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4057 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4061 PMEMORY_AREA MemoryArea
;
4062 PROS_SECTION_OBJECT Section
;
4063 PMM_SECTION_SEGMENT Segment
;
4064 PLIST_ENTRY CurrentEntry
;
4065 PMM_REGION CurrentRegion
;
4066 PLIST_ENTRY RegionListHead
;
4068 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4070 if (MemoryArea
== NULL
)
4072 return(STATUS_UNSUCCESSFUL
);
4075 MemoryArea
->DeleteInProgress
= TRUE
;
4076 Section
= MemoryArea
->Data
.SectionData
.Section
;
4077 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4080 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4081 return MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4084 MmLockSectionSegment(Segment
);
4086 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4087 while (!IsListEmpty(RegionListHead
))
4089 CurrentEntry
= RemoveHeadList(RegionListHead
);
4090 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4091 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4094 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4096 Status
= MmFreeMemoryArea(AddressSpace
,
4103 Status
= MmFreeMemoryArea(AddressSpace
,
4108 MmUnlockSectionSegment(Segment
);
4109 ObDereferenceObject(Section
);
4115 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4116 IN PVOID BaseAddress
,
4120 PMEMORY_AREA MemoryArea
;
4121 PMMSUPPORT AddressSpace
;
4122 PROS_SECTION_OBJECT Section
;
4123 PVOID ImageBaseAddress
= 0;
4125 DPRINT("Opening memory area Process %p BaseAddress %p\n",
4126 Process
, BaseAddress
);
4130 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4132 MmLockAddressSpace(AddressSpace
);
4133 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4135 if (MemoryArea
== NULL
||
4136 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4137 MemoryArea
->DeleteInProgress
)
4139 ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4140 MmUnlockAddressSpace(AddressSpace
);
4141 return STATUS_NOT_MAPPED_VIEW
;
4144 MemoryArea
->DeleteInProgress
= TRUE
;
4146 Section
= MemoryArea
->Data
.SectionData
.Section
;
4148 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4152 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4153 PMM_SECTION_SEGMENT SectionSegments
;
4154 PMM_SECTION_SEGMENT Segment
;
4156 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4157 ImageSectionObject
= Section
->ImageSection
;
4158 SectionSegments
= ImageSectionObject
->Segments
;
4159 NrSegments
= ImageSectionObject
->NrSegments
;
4161 /* Search for the current segment within the section segments
4162 * and calculate the image base address */
4163 for (i
= 0; i
< NrSegments
; i
++)
4165 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4167 if (Segment
== &SectionSegments
[i
])
4169 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4174 if (i
>= NrSegments
)
4176 KeBugCheck(MEMORY_MANAGEMENT
);
4179 for (i
= 0; i
< NrSegments
; i
++)
4181 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4183 PVOID SBaseAddress
= (PVOID
)
4184 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4186 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4187 NT_ASSERT(NT_SUCCESS(Status
));
4193 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4194 NT_ASSERT(NT_SUCCESS(Status
));
4197 MmUnlockAddressSpace(AddressSpace
);
4199 /* Notify debugger */
4200 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4202 return(STATUS_SUCCESS
);
4209 * Queries the information of a section object.
4211 * @param SectionHandle
4212 * Handle to the section object. It must be opened with SECTION_QUERY
4214 * @param SectionInformationClass
4215 * Index to a certain information structure. Can be either
4216 * SectionBasicInformation or SectionImageInformation. The latter
4217 * is valid only for sections that were created with the SEC_IMAGE
4219 * @param SectionInformation
4220 * Caller supplies storage for resulting information.
4222 * Size of the supplied storage.
4223 * @param ResultLength
4231 NtQuerySection(IN HANDLE SectionHandle
,
4232 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4233 OUT PVOID SectionInformation
,
4234 IN SIZE_T SectionInformationLength
,
4235 OUT PSIZE_T ResultLength OPTIONAL
)
4237 PROS_SECTION_OBJECT Section
;
4238 KPROCESSOR_MODE PreviousMode
;
4242 PreviousMode
= ExGetPreviousMode();
4244 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4246 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4248 (ULONG
)SectionInformationLength
,
4253 if(!NT_SUCCESS(Status
))
4255 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4259 Status
= ObReferenceObjectByHandle(SectionHandle
,
4261 MmSectionObjectType
,
4263 (PVOID
*)(PVOID
)&Section
,
4265 if (NT_SUCCESS(Status
))
4267 switch (SectionInformationClass
)
4269 case SectionBasicInformation
:
4271 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4275 Sbi
->Attributes
= Section
->AllocationAttributes
;
4276 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4278 Sbi
->BaseAddress
= 0;
4279 Sbi
->Size
.QuadPart
= 0;
4283 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4284 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4287 if (ResultLength
!= NULL
)
4289 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4291 Status
= STATUS_SUCCESS
;
4293 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4295 Status
= _SEH2_GetExceptionCode();
4302 case SectionImageInformation
:
4304 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4308 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4310 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4311 ImageSectionObject
= Section
->ImageSection
;
4313 *Sii
= ImageSectionObject
->ImageInformation
;
4316 if (ResultLength
!= NULL
)
4318 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4320 Status
= STATUS_SUCCESS
;
4322 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4324 Status
= _SEH2_GetExceptionCode();
4332 ObDereferenceObject(Section
);
4338 /**********************************************************************
4340 * MmMapViewOfSection
4343 * Maps a view of a section into the virtual address space of a
4348 * Pointer to the section object.
4351 * Pointer to the process.
4354 * Desired base address (or NULL) on entry;
4355 * Actual base address of the view on exit.
4358 * Number of high order address bits that must be zero.
4361 * Size in bytes of the initially committed section of
4365 * Offset in bytes from the beginning of the section
4366 * to the beginning of the view.
4369 * Desired length of map (or zero to map all) on entry
4370 * Actual length mapped on exit.
4372 * InheritDisposition
4373 * Specified how the view is to be shared with
4377 * Type of allocation for the pages.
4380 * Protection for the committed region of the view.
4388 MmMapViewOfSection(IN PVOID SectionObject
,
4389 IN PEPROCESS Process
,
4390 IN OUT PVOID
*BaseAddress
,
4391 IN ULONG_PTR ZeroBits
,
4392 IN SIZE_T CommitSize
,
4393 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4394 IN OUT PSIZE_T ViewSize
,
4395 IN SECTION_INHERIT InheritDisposition
,
4396 IN ULONG AllocationType
,
4399 PROS_SECTION_OBJECT Section
;
4400 PMMSUPPORT AddressSpace
;
4402 NTSTATUS Status
= STATUS_SUCCESS
;
4403 BOOLEAN NotAtBase
= FALSE
;
4405 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4407 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4408 return MmMapViewOfArm3Section(SectionObject
,
4422 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4424 return STATUS_INVALID_PAGE_PROTECTION
;
4428 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4429 AddressSpace
= &Process
->Vm
;
4431 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4433 MmLockAddressSpace(AddressSpace
);
4435 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4439 ULONG_PTR ImageBase
;
4441 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4442 PMM_SECTION_SEGMENT SectionSegments
;
4444 ImageSectionObject
= Section
->ImageSection
;
4445 SectionSegments
= ImageSectionObject
->Segments
;
4446 NrSegments
= ImageSectionObject
->NrSegments
;
4448 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4451 ImageBase
= (ULONG_PTR
)ImageSectionObject
->BasedAddress
;
4455 for (i
= 0; i
< NrSegments
; i
++)
4457 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4459 ULONG_PTR MaxExtent
;
4460 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4461 SectionSegments
[i
].Length
.QuadPart
);
4462 ImageSize
= max(ImageSize
, MaxExtent
);
4466 ImageSectionObject
->ImageInformation
.ImageFileSize
= (ULONG
)ImageSize
;
4468 /* Check for an illegal base address */
4469 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4471 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4474 /* Check there is enough space to map the section at that point. */
4475 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4476 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4478 /* Fail if the user requested a fixed base address. */
4479 if ((*BaseAddress
) != NULL
)
4481 MmUnlockAddressSpace(AddressSpace
);
4482 return(STATUS_UNSUCCESSFUL
);
4484 /* Otherwise find a gap to map the image. */
4485 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4488 MmUnlockAddressSpace(AddressSpace
);
4489 return(STATUS_UNSUCCESSFUL
);
4491 /* Remember that we loaded image at a different base address */
4495 for (i
= 0; i
< NrSegments
; i
++)
4497 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4499 PVOID SBaseAddress
= (PVOID
)
4500 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4501 MmLockSectionSegment(&SectionSegments
[i
]);
4502 Status
= MmMapViewOfSegment(AddressSpace
,
4504 &SectionSegments
[i
],
4506 SectionSegments
[i
].Length
.LowPart
,
4507 SectionSegments
[i
].Protection
,
4510 MmUnlockSectionSegment(&SectionSegments
[i
]);
4511 if (!NT_SUCCESS(Status
))
4513 MmUnlockAddressSpace(AddressSpace
);
4519 *BaseAddress
= (PVOID
)ImageBase
;
4520 *ViewSize
= ImageSize
;
4524 /* check for write access */
4525 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4526 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4528 MmUnlockAddressSpace(AddressSpace
);
4529 return STATUS_SECTION_PROTECTION
;
4531 /* check for read access */
4532 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4533 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4535 MmUnlockAddressSpace(AddressSpace
);
4536 return STATUS_SECTION_PROTECTION
;
4538 /* check for execute access */
4539 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4540 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4542 MmUnlockAddressSpace(AddressSpace
);
4543 return STATUS_SECTION_PROTECTION
;
4546 if (ViewSize
== NULL
)
4548 /* Following this pointer would lead to us to the dark side */
4549 /* What to do? Bugcheck? Return status? Do the mambo? */
4550 KeBugCheck(MEMORY_MANAGEMENT
);
4553 if (SectionOffset
== NULL
)
4559 ViewOffset
= SectionOffset
->u
.LowPart
;
4562 if ((ViewOffset
% PAGE_SIZE
) != 0)
4564 MmUnlockAddressSpace(AddressSpace
);
4565 return(STATUS_MAPPED_ALIGNMENT
);
4568 if ((*ViewSize
) == 0)
4570 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4572 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4574 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4577 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4579 MmLockSectionSegment(Section
->Segment
);
4580 Status
= MmMapViewOfSegment(AddressSpace
,
4587 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4588 MmUnlockSectionSegment(Section
->Segment
);
4589 if (!NT_SUCCESS(Status
))
4591 MmUnlockAddressSpace(AddressSpace
);
4596 MmUnlockAddressSpace(AddressSpace
);
4599 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4601 Status
= STATUS_SUCCESS
;
4610 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4611 IN PLARGE_INTEGER NewFileSize
)
4613 /* Check whether an ImageSectionObject exists */
4614 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4616 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4620 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4622 PMM_SECTION_SEGMENT Segment
;
4624 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4627 if (Segment
->ReferenceCount
!= 0)
4630 CC_FILE_SIZES FileSizes
;
4632 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4635 /* Check size of file */
4636 if (SectionObjectPointer
->SharedCacheMap
)
4638 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4643 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4652 /* Check size of file */
4653 if (SectionObjectPointer
->SharedCacheMap
)
4655 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4656 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4665 /* Something must gone wrong
4666 * how can we have a Section but no
4668 DPRINT("ERROR: DataSectionObject without reference!\n");
4672 DPRINT("FIXME: didn't check for outstanding write probes\n");
4684 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4685 IN MMFLUSH_TYPE FlushType
)
4687 BOOLEAN Result
= TRUE
;
4689 PMM_SECTION_SEGMENT Segment
;
4694 case MmFlushForDelete
:
4695 if (SectionObjectPointer
->ImageSectionObject
||
4696 SectionObjectPointer
->DataSectionObject
)
4701 CcRosSetRemoveOnClose(SectionObjectPointer
);
4704 case MmFlushForWrite
:
4706 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4708 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4711 if (SectionObjectPointer
->ImageSectionObject
) {
4712 DPRINT1("SectionObject has ImageSection\n");
4718 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4720 DPRINT("Result %d\n", Result
);
4732 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4733 OUT PVOID
* MappedBase
,
4734 IN OUT PSIZE_T ViewSize
)
4736 PROS_SECTION_OBJECT Section
;
4737 PMMSUPPORT AddressSpace
;
4741 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4743 return MiMapViewInSystemSpace(SectionObject
,
4749 DPRINT("MmMapViewInSystemSpace() called\n");
4751 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4752 AddressSpace
= MmGetKernelAddressSpace();
4754 MmLockAddressSpace(AddressSpace
);
4757 if ((*ViewSize
) == 0)
4759 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4761 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4763 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4766 MmLockSectionSegment(Section
->Segment
);
4769 Status
= MmMapViewOfSegment(AddressSpace
,
4778 MmUnlockSectionSegment(Section
->Segment
);
4779 MmUnlockAddressSpace(AddressSpace
);
4786 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4788 PMMSUPPORT AddressSpace
;
4791 DPRINT("MmUnmapViewInSystemSpace() called\n");
4793 AddressSpace
= MmGetKernelAddressSpace();
4795 MmLockAddressSpace(AddressSpace
);
4797 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4799 MmUnlockAddressSpace(AddressSpace
);
4804 /**********************************************************************
4809 * Creates a section object.
4812 * SectionObject (OUT)
4813 * Caller supplied storage for the resulting pointer
4814 * to a SECTION_OBJECT instance;
4817 * Specifies the desired access to the section can be a
4819 * STANDARD_RIGHTS_REQUIRED |
4821 * SECTION_MAP_WRITE |
4822 * SECTION_MAP_READ |
4823 * SECTION_MAP_EXECUTE
4825 * ObjectAttributes [OPTIONAL]
4826 * Initialized attributes for the object can be used
4827 * to create a named section;
4830 * Maximizes the size of the memory section. Must be
4831 * non-NULL for a page-file backed section.
4832 * If value specified for a mapped file and the file is
4833 * not large enough, file will be extended.
4835 * SectionPageProtection
4836 * Can be a combination of:
4842 * AllocationAttributes
4843 * Can be a combination of:
4848 * Handle to a file to create a section mapped to a file
4849 * instead of a memory backed section;
4860 MmCreateSection (OUT PVOID
* Section
,
4861 IN ACCESS_MASK DesiredAccess
,
4862 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4863 IN PLARGE_INTEGER MaximumSize
,
4864 IN ULONG SectionPageProtection
,
4865 IN ULONG AllocationAttributes
,
4866 IN HANDLE FileHandle OPTIONAL
,
4867 IN PFILE_OBJECT FileObject OPTIONAL
)
4870 ULONG Protection
, FileAccess
;
4871 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4873 /* Check if an ARM3 section is being created instead */
4874 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4876 if (!(FileObject
) && !(FileHandle
))
4878 return MmCreateArm3Section(Section
,
4882 SectionPageProtection
,
4883 AllocationAttributes
&~ 1,
4890 * Check the protection
4892 Protection
= SectionPageProtection
& ~(PAGE_GUARD
| PAGE_NOCACHE
);
4893 if (Protection
!= PAGE_READONLY
&&
4894 Protection
!= PAGE_READWRITE
&&
4895 Protection
!= PAGE_WRITECOPY
&&
4896 Protection
!= PAGE_EXECUTE
&&
4897 Protection
!= PAGE_EXECUTE_READ
&&
4898 Protection
!= PAGE_EXECUTE_READWRITE
&&
4899 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4901 return STATUS_INVALID_PAGE_PROTECTION
;
4904 if ((DesiredAccess
& SECTION_MAP_WRITE
) &&
4905 (Protection
== PAGE_READWRITE
||
4906 Protection
== PAGE_EXECUTE_READWRITE
) &&
4907 !(AllocationAttributes
& SEC_IMAGE
))
4909 DPRINT("Creating a section with WRITE access\n");
4910 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
| SYNCHRONIZE
;
4914 DPRINT("Creating a section with READ access\n");
4915 FileAccess
= FILE_READ_DATA
| SYNCHRONIZE
;
4918 /* FIXME: somehow combine this with the above checks */
4919 if (AllocationAttributes
& SEC_IMAGE
)
4920 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
4922 if (!FileObject
&& FileHandle
)
4924 Status
= ObReferenceObjectByHandle(FileHandle
,
4927 ExGetPreviousMode(),
4928 (PVOID
*)&FileObject
,
4930 if (!NT_SUCCESS(Status
))
4932 DPRINT("Failed: 0x%08lx\n", Status
);
4936 else if (FileObject
)
4937 ObReferenceObject(FileObject
);
4939 #ifndef NEWCC // A hack for initializing caching.
4940 // This is needed only in the old case.
4943 IO_STATUS_BLOCK Iosb
;
4946 LARGE_INTEGER ByteOffset
;
4947 ByteOffset
.QuadPart
= 0;
4948 Status
= ZwReadFile(FileHandle
,
4957 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
4959 // Caching is initialized...
4963 if (AllocationAttributes
& SEC_IMAGE
)
4965 Status
= MmCreateImageSection(SectionObject
,
4969 SectionPageProtection
,
4970 AllocationAttributes
,
4974 else if (FileHandle
!= NULL
)
4976 Status
= MmCreateDataFileSection(SectionObject
,
4980 SectionPageProtection
,
4981 AllocationAttributes
,
4984 ObDereferenceObject(FileObject
);
4987 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
4989 Status
= MmCreateCacheSection(SectionObject
,
4993 SectionPageProtection
,
4994 AllocationAttributes
,
5000 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
5002 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
5004 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
5005 Status
= MmCreatePageFileSection(SectionObject
,
5009 SectionPageProtection
,
5010 AllocationAttributes
);