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,%x,%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
;
131 MM_SECTION_PAGEOUT_CONTEXT
;
133 /* GLOBALS *******************************************************************/
135 POBJECT_TYPE MmSectionObjectType
= NULL
;
137 ULONG_PTR MmSubsectionBase
;
139 static ULONG SectionCharacteristicsToProtect
[16] =
141 PAGE_NOACCESS
, /* 0 = NONE */
142 PAGE_NOACCESS
, /* 1 = SHARED */
143 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
144 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
145 PAGE_READONLY
, /* 4 = READABLE */
146 PAGE_READONLY
, /* 5 = READABLE, SHARED */
147 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
148 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
150 * FIXME? do we really need the WriteCopy field in segments? can't we use
151 * PAGE_WRITECOPY here?
153 PAGE_READWRITE
, /* 8 = WRITABLE */
154 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
155 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
156 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
157 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
158 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
159 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
160 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
163 ACCESS_MASK NTAPI
MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection
);
164 static GENERIC_MAPPING MmpSectionMapping
= {
165 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
166 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
167 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
170 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
171 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
172 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFC) >> 2)
173 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
174 #define MAX_SHARE_COUNT 0x3FF
175 #define MAKE_SSE(P, C) ((P) | ((C) << 2))
176 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
177 #define MAKE_SWAP_SSE(S) (((ULONG)(S) << 1) | 0x1)
179 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
181 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
182 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
185 /* FUNCTIONS *****************************************************************/
190 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
191 File Format Specification", revision 6.0 (February 1999)
193 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
194 IN SIZE_T FileHeaderSize
,
196 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
198 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
199 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
202 ULONG cbFileHeaderOffsetSize
= 0;
203 ULONG cbSectionHeadersOffset
= 0;
204 ULONG cbSectionHeadersSize
;
205 ULONG cbSectionHeadersOffsetSize
= 0;
206 ULONG cbOptHeaderSize
;
207 ULONG cbHeadersSize
= 0;
208 ULONG nSectionAlignment
;
209 ULONG nFileAlignment
;
210 const IMAGE_DOS_HEADER
* pidhDosHeader
;
211 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
212 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
213 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
214 PMM_SECTION_SEGMENT pssSegments
;
215 LARGE_INTEGER lnOffset
;
217 SIZE_T nPrevVirtualEndOfSegment
= 0;
218 ULONG nFileSizeOfHeaders
= 0;
222 ASSERT(FileHeaderSize
> 0);
224 ASSERT(ImageSectionObject
);
226 ASSERT(AllocateSegmentsCb
);
228 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
230 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
232 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
235 pidhDosHeader
= FileHeader
;
238 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
240 /* image too small to be an MZ executable */
241 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
242 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
244 /* no MZ signature */
245 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
246 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
248 /* not a Windows executable */
249 if(pidhDosHeader
->e_lfanew
<= 0)
250 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
253 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
255 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
256 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
258 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
263 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
264 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
266 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
267 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
271 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
272 * need to read the header from the file
274 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
275 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
277 ULONG cbNtHeaderSize
;
281 l_ReadHeaderFromFile
:
283 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
285 /* read the header from the file */
286 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
288 if(!NT_SUCCESS(nStatus
))
289 DIE(("ReadFile failed, status %08X\n", nStatus
));
293 ASSERT(cbReadSize
> 0);
295 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
297 /* the buffer doesn't contain the file header */
298 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
299 DIE(("The file doesn't contain the PE file header\n"));
301 pinhNtHeader
= pData
;
303 /* object still not aligned: copy it to the beginning of the buffer */
304 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
306 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
307 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
308 pinhNtHeader
= pBuffer
;
311 /* invalid NT header */
312 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
314 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
315 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
317 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
319 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
320 DIE(("The full NT header is too large\n"));
322 /* the buffer doesn't contain the whole NT header */
323 if(cbReadSize
< cbNtHeaderSize
)
324 DIE(("The file doesn't contain the full NT header\n"));
328 ULONG cbOptHeaderOffsetSize
= 0;
330 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
332 /* don't trust an invalid NT header */
333 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
334 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
336 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
337 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
339 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
340 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
342 /* the buffer doesn't contain the whole NT header: read it from the file */
343 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
344 goto l_ReadHeaderFromFile
;
347 /* read information from the NT header */
348 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
349 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
351 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
353 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
354 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
356 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
358 switch(piohOptHeader
->Magic
)
360 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
361 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
365 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
368 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
369 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
371 /* See [1], section 3.4.2 */
372 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
374 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
375 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
377 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
378 DIE(("The section alignment is smaller than the file alignment\n"));
380 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
381 nFileAlignment
= piohOptHeader
->FileAlignment
;
383 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
384 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
388 nSectionAlignment
= PAGE_SIZE
;
389 nFileAlignment
= PAGE_SIZE
;
392 ASSERT(IsPowerOf2(nSectionAlignment
));
393 ASSERT(IsPowerOf2(nFileAlignment
));
395 switch(piohOptHeader
->Magic
)
398 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
400 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
401 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
403 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
404 ImageSectionObject
->ImageSize
= piohOptHeader
->SizeOfImage
;
406 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
407 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
409 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
410 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
416 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
418 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
420 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
422 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
424 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
425 DIE(("ImageBase exceeds the address space\n"));
427 ImageSectionObject
->ImageBase
= (ULONG_PTR
)pioh64OptHeader
->ImageBase
;
430 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
432 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
433 DIE(("SizeOfImage exceeds the address space\n"));
435 ImageSectionObject
->ImageSize
= pioh64OptHeader
->SizeOfImage
;
438 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
440 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
441 DIE(("SizeOfStackReserve exceeds the address space\n"));
443 ImageSectionObject
->StackReserve
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackReserve
;
446 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
448 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
449 DIE(("SizeOfStackCommit exceeds the address space\n"));
451 ImageSectionObject
->StackCommit
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackCommit
;
458 /* [1], section 3.4.2 */
459 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
460 DIE(("ImageBase is not aligned on a 64KB boundary"));
462 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
464 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
466 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
467 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
469 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
470 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
474 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
476 ImageSectionObject
->EntryPoint
= ImageSectionObject
->ImageBase
+
477 piohOptHeader
->AddressOfEntryPoint
;
480 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
481 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
483 ImageSectionObject
->Executable
= TRUE
;
485 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
486 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
488 /* SECTION HEADERS */
489 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
491 /* see [1], section 3.3 */
492 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
493 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
496 * the additional segment is for the file's headers. They need to be present for
497 * the benefit of the dynamic loader (to locate exports, defaults for thread
498 * parameters, resources, etc.)
500 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
502 /* file offset for the section headers */
503 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
504 DIE(("Offset overflow\n"));
506 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
507 DIE(("Offset overflow\n"));
509 /* size of the section headers */
510 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
511 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
513 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
514 DIE(("Section headers too large\n"));
516 /* size of the executable's headers */
517 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
519 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
520 // DIE(("SizeOfHeaders is not aligned\n"));
522 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
523 DIE(("The section headers overflow SizeOfHeaders\n"));
525 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
527 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
528 DIE(("Overflow aligning the size of headers\n"));
535 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
536 /* WARNING: piohOptHeader IS NO LONGER USABLE */
537 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
539 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
540 pishSectionHeaders
= NULL
;
544 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
545 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
547 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
548 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
552 * the buffer doesn't contain the section headers, or the alignment is wrong:
553 * read the headers from the file
555 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
556 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
561 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
563 /* read the header from the file */
564 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
566 if(!NT_SUCCESS(nStatus
))
567 DIE(("ReadFile failed with status %08X\n", nStatus
));
571 ASSERT(cbReadSize
> 0);
573 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
575 /* the buffer doesn't contain all the section headers */
576 if(cbReadSize
< cbSectionHeadersSize
)
577 DIE(("The file doesn't contain all of the section headers\n"));
579 pishSectionHeaders
= pData
;
581 /* object still not aligned: copy it to the beginning of the buffer */
582 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
584 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
585 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
586 pishSectionHeaders
= pBuffer
;
591 /* allocate the segments */
592 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
593 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
595 if(ImageSectionObject
->Segments
== NULL
)
596 DIE(("AllocateSegments failed\n"));
598 /* initialize the headers segment */
599 pssSegments
= ImageSectionObject
->Segments
;
601 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
603 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
604 DIE(("Cannot align the size of the section headers\n"));
606 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
607 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
608 DIE(("Cannot align the size of the section headers\n"));
610 pssSegments
[0].Image
.FileOffset
= 0;
611 pssSegments
[0].Protection
= PAGE_READONLY
;
612 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
613 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
614 pssSegments
[0].Image
.VirtualAddress
= 0;
615 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
616 pssSegments
[0].WriteCopy
= TRUE
;
618 /* skip the headers segment */
621 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
623 /* convert the executable sections into segments. See also [1], section 4 */
624 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
626 ULONG nCharacteristics
;
628 /* validate the alignment */
629 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
630 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
632 /* sections must be contiguous, ordered by base address and non-overlapping */
633 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
634 DIE(("Memory gap between section %u and the previous\n", i
));
636 /* ignore explicit BSS sections */
637 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
639 /* validate the alignment */
641 /* Yes, this should be a multiple of FileAlignment, but there's
642 * stuff out there that isn't. We can cope with that
644 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
645 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
648 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
649 // DIE(("PointerToRawData[%u] is not aligned\n", i));
652 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
653 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
657 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
658 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
661 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
663 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
665 /* no explicit protection */
666 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
668 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
669 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
671 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
672 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
674 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
675 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
678 /* see table above */
679 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
680 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
682 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
683 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
685 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
687 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
688 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
689 DIE(("Cannot align the virtual size of section %u\n", i
));
691 if(pssSegments
[i
].Length
.QuadPart
== 0)
692 DIE(("Virtual size of section %u is null\n", i
));
694 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
695 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
697 /* ensure the memory image is no larger than 4GB */
698 nPrevVirtualEndOfSegment
= pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
;
699 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
700 DIE(("The image is too large\n"));
703 if(nSectionAlignment
>= PAGE_SIZE
)
704 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
707 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;
716 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
719 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
720 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
721 * RETURNS: Status of the wait.
724 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
726 LARGE_INTEGER Timeout
;
727 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
729 Timeout
.QuadPart
= -100000000LL; // 10 sec
732 Timeout
.QuadPart
= -100000000; // 10 sec
735 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
740 * FUNCTION: Sets the page op completion event and releases the page op.
741 * ARGUMENTS: PMM_PAGEOP.
742 * RETURNS: In shorter time than it takes you to even read this
743 * description, so don't even think about geting a mug of coffee.
746 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
748 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
749 MmReleasePageOp(PageOp
);
754 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
755 * ARGUMENTS: PFILE_OBJECT to wait for.
756 * RETURNS: Status of the wait.
759 MmspWaitForFileLock(PFILE_OBJECT File
)
761 return STATUS_SUCCESS
;
762 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
767 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
769 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
771 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
772 PMM_SECTION_SEGMENT SectionSegments
;
776 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
777 NrSegments
= ImageSectionObject
->NrSegments
;
778 SectionSegments
= ImageSectionObject
->Segments
;
779 for (i
= 0; i
< NrSegments
; i
++)
781 if (SectionSegments
[i
].ReferenceCount
!= 0)
783 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
784 SectionSegments
[i
].ReferenceCount
);
785 KeBugCheck(MEMORY_MANAGEMENT
);
787 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
789 ExFreePool(ImageSectionObject
->Segments
);
790 ExFreePool(ImageSectionObject
);
791 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
793 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
795 PMM_SECTION_SEGMENT Segment
;
797 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
800 if (Segment
->ReferenceCount
!= 0)
802 DPRINT1("Data segment still referenced\n");
803 KeBugCheck(MEMORY_MANAGEMENT
);
805 MmFreePageTablesSectionSegment(Segment
, NULL
);
807 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
813 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
814 PLARGE_INTEGER Offset
)
818 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
821 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
822 KeBugCheck(MEMORY_MANAGEMENT
);
824 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
826 DPRINT1("Maximum share count reached\n");
827 KeBugCheck(MEMORY_MANAGEMENT
);
829 if (IS_SWAP_FROM_SSE(Entry
))
831 KeBugCheck(MEMORY_MANAGEMENT
);
833 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
834 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
839 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
840 PMM_SECTION_SEGMENT Segment
,
841 PLARGE_INTEGER Offset
,
846 BOOLEAN IsDirectMapped
= FALSE
;
848 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
851 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
852 KeBugCheck(MEMORY_MANAGEMENT
);
854 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
856 DPRINT1("Zero share count for unshare\n");
857 KeBugCheck(MEMORY_MANAGEMENT
);
859 if (IS_SWAP_FROM_SSE(Entry
))
861 KeBugCheck(MEMORY_MANAGEMENT
);
863 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
865 * If we reducing the share count of this entry to zero then set the entry
866 * to zero and tell the cache the page is no longer mapped.
868 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
870 PFILE_OBJECT FileObject
;
874 SWAPENTRY SavedSwapEntry
;
876 BOOLEAN IsImageSection
;
877 LARGE_INTEGER FileOffset
;
879 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
881 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
883 Page
= PFN_FROM_SSE(Entry
);
884 FileObject
= Section
->FileObject
;
885 if (FileObject
!= NULL
&&
886 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
890 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
891 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
894 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
895 IsDirectMapped
= TRUE
;
897 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
.LowPart
, Dirty
);
899 Status
= STATUS_SUCCESS
;
901 if (!NT_SUCCESS(Status
))
903 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
904 KeBugCheck(MEMORY_MANAGEMENT
);
910 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
911 if (SavedSwapEntry
== 0)
914 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
915 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
919 * Try to page out this page and set the swap entry
920 * within the section segment. There exist no rmap entry
921 * for this page. The pager thread can't page out a
922 * page without a rmap entry.
924 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
928 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
931 MmReleasePageMemoryConsumer(MC_USER
, Page
);
937 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
938 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
946 * We hold all locks. Nobody can do something with the current
947 * process and the current segment (also not within an other process).
950 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
951 if (!NT_SUCCESS(Status
))
953 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
954 KeBugCheck(MEMORY_MANAGEMENT
);
957 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
958 MmSetSavedSwapEntryPage(Page
, 0);
960 MmReleasePageMemoryConsumer(MC_USER
, Page
);
964 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
965 KeBugCheck(MEMORY_MANAGEMENT
);
971 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
973 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
976 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
980 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
983 PCACHE_SEGMENT CacheSeg
;
984 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
985 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
);
988 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
998 MiCopyFromUserPage(PFN_NUMBER DestPage
, PVOID SourceAddress
)
1004 ASSERT((ULONG_PTR
)SourceAddress
% PAGE_SIZE
== 0);
1005 Process
= PsGetCurrentProcess();
1006 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1007 if (TempAddress
== NULL
)
1009 return(STATUS_NO_MEMORY
);
1011 ASSERT((ULONG_PTR
)TempAddress
% PAGE_SIZE
== 0);
1012 RtlCopyMemory(TempAddress
, SourceAddress
, PAGE_SIZE
);
1013 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
1014 return(STATUS_SUCCESS
);
1020 MiReadPage(PMEMORY_AREA MemoryArea
,
1021 ULONG_PTR SegOffset
,
1024 * FUNCTION: Read a page for a section backed memory area.
1026 * MemoryArea - Memory area to read the page for.
1027 * Offset - Offset of the page to read.
1028 * Page - Variable that receives a page contains the read data.
1032 ULONG_PTR FileOffset
;
1035 PCACHE_SEGMENT CacheSeg
;
1036 PFILE_OBJECT FileObject
;
1038 ULONG_PTR RawLength
;
1040 BOOLEAN IsImageSection
;
1043 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1044 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1045 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
;
1046 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1047 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1051 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1054 * If the file system is letting us go directly to the cache and the
1055 * memory area was mapped at an offset in the file which is page aligned
1056 * then get the related cache segment.
1058 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1059 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
1060 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1064 * Get the related cache segment; we use a lower level interface than
1065 * filesystems do because it is safe for us to use an offset with a
1066 * alignment less than the file system block size.
1068 Status
= CcRosGetCacheSegment(Bcb
,
1074 if (!NT_SUCCESS(Status
))
1081 * If the cache segment isn't up to date then call the file
1082 * system to read in the data.
1084 Status
= ReadCacheSegment(CacheSeg
);
1085 if (!NT_SUCCESS(Status
))
1087 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1092 * Retrieve the page from the cache segment that we actually want.
1094 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1095 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1097 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1104 ULONG_PTR CacheSegOffset
;
1107 * Allocate a page, this is rather complicated by the possibility
1108 * we might have to move other things out of memory
1110 MI_SET_USAGE(MI_USAGE_SECTION
);
1111 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1112 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1113 if (!NT_SUCCESS(Status
))
1117 Status
= CcRosGetCacheSegment(Bcb
,
1123 if (!NT_SUCCESS(Status
))
1130 * If the cache segment isn't up to date then call the file
1131 * system to read in the data.
1133 Status
= ReadCacheSegment(CacheSeg
);
1134 if (!NT_SUCCESS(Status
))
1136 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1141 Process
= PsGetCurrentProcess();
1142 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1143 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
1144 Length
= RawLength
- SegOffset
;
1145 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1147 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1149 else if (CacheSegOffset
>= PAGE_SIZE
)
1151 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1155 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1156 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1157 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1158 Status
= CcRosGetCacheSegment(Bcb
,
1159 (ULONG
)(FileOffset
+ CacheSegOffset
),
1164 if (!NT_SUCCESS(Status
))
1171 * If the cache segment isn't up to date then call the file
1172 * system to read in the data.
1174 Status
= ReadCacheSegment(CacheSeg
);
1175 if (!NT_SUCCESS(Status
))
1177 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1181 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1182 if (Length
< PAGE_SIZE
)
1184 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1188 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1191 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1192 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1194 return(STATUS_SUCCESS
);
1199 MiReadPage(PMEMORY_AREA MemoryArea
,
1203 * FUNCTION: Read a page for a section backed memory area.
1205 * MemoryArea - Memory area to read the page for.
1206 * Offset - Offset of the page to read.
1207 * Page - Variable that receives a page contains the read data.
1210 MM_REQUIRED_RESOURCES Resources
;
1213 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1215 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1216 Resources
.FileOffset
.QuadPart
= SegOffset
+
1217 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1218 Resources
.Consumer
= MC_USER
;
1219 Resources
.Amount
= PAGE_SIZE
;
1221 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]);
1223 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1224 *Page
= Resources
.Page
[0];
1231 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1232 MEMORY_AREA
* MemoryArea
,
1236 LARGE_INTEGER Offset
;
1239 PROS_SECTION_OBJECT Section
;
1240 PMM_SECTION_SEGMENT Segment
;
1246 BOOLEAN HasSwapEntry
;
1248 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1251 * There is a window between taking the page fault and locking the
1252 * address space when another thread could load the page so we check
1255 if (MmIsPagePresent(Process
, Address
))
1257 return(STATUS_SUCCESS
);
1261 * Check for the virtual memory area being deleted.
1263 if (MemoryArea
->DeleteInProgress
)
1265 return(STATUS_UNSUCCESSFUL
);
1268 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1269 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1270 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1272 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1273 Section
= MemoryArea
->Data
.SectionData
.Section
;
1274 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1275 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1277 ASSERT(Region
!= NULL
);
1281 MmLockSectionSegment(Segment
);
1284 * Check if this page needs to be mapped COW
1286 if ((Segment
->WriteCopy
) &&
1287 (Region
->Protect
== PAGE_READWRITE
||
1288 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1290 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1294 Attributes
= Region
->Protect
;
1298 * Get or create a page operation descriptor
1300 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
.LowPart
, MM_PAGEOP_PAGEIN
, FALSE
);
1303 DPRINT1("MmGetPageOp failed\n");
1304 KeBugCheck(MEMORY_MANAGEMENT
);
1308 * Check if someone else is already handling this fault, if so wait
1311 if (PageOp
->Thread
!= PsGetCurrentThread())
1313 MmUnlockSectionSegment(Segment
);
1314 MmUnlockAddressSpace(AddressSpace
);
1315 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1317 * Check for various strange conditions
1319 if (Status
!= STATUS_SUCCESS
)
1321 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1322 KeBugCheck(MEMORY_MANAGEMENT
);
1324 if (PageOp
->Status
== STATUS_PENDING
)
1326 DPRINT1("Woke for page op before completion\n");
1327 KeBugCheck(MEMORY_MANAGEMENT
);
1329 MmLockAddressSpace(AddressSpace
);
1331 * If this wasn't a pagein then restart the operation
1333 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
1335 MmspCompleteAndReleasePageOp(PageOp
);
1336 DPRINT("Address 0x%.8X\n", Address
);
1337 return(STATUS_MM_RESTART_OPERATION
);
1341 * If the thread handling this fault has failed then we don't retry
1343 if (!NT_SUCCESS(PageOp
->Status
))
1345 Status
= PageOp
->Status
;
1346 MmspCompleteAndReleasePageOp(PageOp
);
1347 DPRINT("Address 0x%.8X\n", Address
);
1350 MmLockSectionSegment(Segment
);
1352 * If the completed fault was for another address space then set the
1355 if (!MmIsPagePresent(Process
, Address
))
1357 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1358 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1360 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
1363 * The page was a private page in another or in our address space
1365 MmUnlockSectionSegment(Segment
);
1366 MmspCompleteAndReleasePageOp(PageOp
);
1367 return(STATUS_MM_RESTART_OPERATION
);
1370 Page
= PFN_FROM_SSE(Entry
);
1372 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1374 #if (_MI_PAGING_LEVELS == 2)
1375 /* Reference Page Directory Entry */
1376 if(Address
< MmSystemRangeStart
)
1378 MmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)]++;
1379 ASSERT(MmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)] <= PTE_COUNT
);
1383 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
1384 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
1386 Status
= MmCreateVirtualMapping(Process
,
1391 if (!NT_SUCCESS(Status
))
1393 DPRINT1("Unable to create virtual mapping\n");
1394 KeBugCheck(MEMORY_MANAGEMENT
);
1396 MmInsertRmap(Page
, Process
, Address
);
1398 MmUnlockSectionSegment(Segment
);
1399 PageOp
->Status
= STATUS_SUCCESS
;
1400 MmspCompleteAndReleasePageOp(PageOp
);
1401 DPRINT("Address 0x%.8X\n", Address
);
1402 return(STATUS_SUCCESS
);
1405 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1409 * Must be private page we have swapped out.
1411 SWAPENTRY SwapEntry
;
1416 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1418 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1419 KeBugCheck(MEMORY_MANAGEMENT
);
1422 MmUnlockSectionSegment(Segment
);
1423 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1425 MmUnlockAddressSpace(AddressSpace
);
1426 MI_SET_USAGE(MI_USAGE_SECTION
);
1427 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1428 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1429 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1430 if (!NT_SUCCESS(Status
))
1432 KeBugCheck(MEMORY_MANAGEMENT
);
1435 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1436 if (!NT_SUCCESS(Status
))
1438 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1439 KeBugCheck(MEMORY_MANAGEMENT
);
1441 MmLockAddressSpace(AddressSpace
);
1442 Status
= MmCreateVirtualMapping(Process
,
1447 if (!NT_SUCCESS(Status
))
1449 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1450 KeBugCheck(MEMORY_MANAGEMENT
);
1455 * Store the swap entry for later use.
1457 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1460 * Add the page to the process's working set
1462 MmInsertRmap(Page
, Process
, Address
);
1464 * Finish the operation
1466 PageOp
->Status
= STATUS_SUCCESS
;
1467 MmspCompleteAndReleasePageOp(PageOp
);
1468 DPRINT("Address 0x%.8X\n", Address
);
1469 return(STATUS_SUCCESS
);
1472 #if (_MI_PAGING_LEVELS == 2)
1473 /* Reference Page Directory Entry */
1474 if(Address
< MmSystemRangeStart
)
1476 MmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)]++;
1477 ASSERT(MmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)] <= PTE_COUNT
);
1482 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1484 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1486 MmUnlockSectionSegment(Segment
);
1488 * Just map the desired physical page
1490 Page
= Offset
.QuadPart
>> PAGE_SHIFT
;
1491 Status
= MmCreateVirtualMappingUnsafe(Process
,
1496 if (!NT_SUCCESS(Status
))
1498 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1499 KeBugCheck(MEMORY_MANAGEMENT
);
1504 * Cleanup and release locks
1506 PageOp
->Status
= STATUS_SUCCESS
;
1507 MmspCompleteAndReleasePageOp(PageOp
);
1508 DPRINT("Address 0x%.8X\n", Address
);
1509 return(STATUS_SUCCESS
);
1513 * Map anonymous memory for BSS sections
1515 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1517 MmUnlockSectionSegment(Segment
);
1518 MI_SET_USAGE(MI_USAGE_SECTION
);
1519 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1520 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1521 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1522 if (!NT_SUCCESS(Status
))
1524 MmUnlockAddressSpace(AddressSpace
);
1525 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1526 MmLockAddressSpace(AddressSpace
);
1528 if (!NT_SUCCESS(Status
))
1530 KeBugCheck(MEMORY_MANAGEMENT
);
1532 Status
= MmCreateVirtualMapping(Process
,
1537 if (!NT_SUCCESS(Status
))
1539 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1540 KeBugCheck(MEMORY_MANAGEMENT
);
1543 MmInsertRmap(Page
, Process
, Address
);
1546 * Cleanup and release locks
1548 PageOp
->Status
= STATUS_SUCCESS
;
1549 MmspCompleteAndReleasePageOp(PageOp
);
1550 DPRINT("Address 0x%.8X\n", Address
);
1551 return(STATUS_SUCCESS
);
1555 * Get the entry corresponding to the offset within the section
1557 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1562 * If the entry is zero (and it can't change because we have
1563 * locked the segment) then we need to load the page.
1567 * Release all our locks and read in the page from disk
1569 MmUnlockSectionSegment(Segment
);
1570 MmUnlockAddressSpace(AddressSpace
);
1572 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1573 (Offset
.QuadPart
>= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1575 MI_SET_USAGE(MI_USAGE_SECTION
);
1576 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1577 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1578 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1579 if (!NT_SUCCESS(Status
))
1581 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1587 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1588 if (!NT_SUCCESS(Status
))
1590 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1593 if (!NT_SUCCESS(Status
))
1596 * FIXME: What do we know in this case?
1599 * Cleanup and release locks
1601 #if (_MI_PAGING_LEVELS == 2)
1602 if(Address
< MmSystemRangeStart
)
1604 MmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)]--;
1607 MmLockAddressSpace(AddressSpace
);
1608 PageOp
->Status
= Status
;
1609 MmspCompleteAndReleasePageOp(PageOp
);
1610 DPRINT("Address 0x%.8X\n", Address
);
1614 * Relock the address space and segment
1616 MmLockAddressSpace(AddressSpace
);
1617 MmLockSectionSegment(Segment
);
1620 * Check the entry. No one should change the status of a page
1621 * that has a pending page-in.
1623 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1624 if (Entry
!= Entry1
)
1626 DPRINT1("Someone changed ppte entry while we slept\n");
1627 KeBugCheck(MEMORY_MANAGEMENT
);
1631 * Mark the offset within the section as having valid, in-memory
1634 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1635 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1636 MmUnlockSectionSegment(Segment
);
1638 Status
= MmCreateVirtualMapping(Process
,
1643 if (!NT_SUCCESS(Status
))
1645 DPRINT1("Unable to create virtual mapping\n");
1646 KeBugCheck(MEMORY_MANAGEMENT
);
1648 MmInsertRmap(Page
, Process
, Address
);
1650 PageOp
->Status
= STATUS_SUCCESS
;
1651 MmspCompleteAndReleasePageOp(PageOp
);
1652 DPRINT("Address 0x%.8X\n", Address
);
1653 return(STATUS_SUCCESS
);
1655 else if (IS_SWAP_FROM_SSE(Entry
))
1657 SWAPENTRY SwapEntry
;
1659 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1662 * Release all our locks and read in the page from disk
1664 MmUnlockSectionSegment(Segment
);
1666 MmUnlockAddressSpace(AddressSpace
);
1667 MI_SET_USAGE(MI_USAGE_SECTION
);
1668 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1669 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1670 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1671 if (!NT_SUCCESS(Status
))
1673 KeBugCheck(MEMORY_MANAGEMENT
);
1676 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1677 if (!NT_SUCCESS(Status
))
1679 KeBugCheck(MEMORY_MANAGEMENT
);
1683 * Relock the address space and segment
1685 MmLockAddressSpace(AddressSpace
);
1686 MmLockSectionSegment(Segment
);
1689 * Check the entry. No one should change the status of a page
1690 * that has a pending page-in.
1692 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1693 if (Entry
!= Entry1
)
1695 DPRINT1("Someone changed ppte entry while we slept\n");
1696 KeBugCheck(MEMORY_MANAGEMENT
);
1700 * Mark the offset within the section as having valid, in-memory
1703 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1704 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1705 MmUnlockSectionSegment(Segment
);
1708 * Save the swap entry.
1710 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1711 Status
= MmCreateVirtualMapping(Process
,
1716 if (!NT_SUCCESS(Status
))
1718 DPRINT1("Unable to create virtual mapping\n");
1719 KeBugCheck(MEMORY_MANAGEMENT
);
1721 MmInsertRmap(Page
, Process
, Address
);
1722 PageOp
->Status
= STATUS_SUCCESS
;
1723 MmspCompleteAndReleasePageOp(PageOp
);
1724 DPRINT("Address 0x%.8X\n", Address
);
1725 return(STATUS_SUCCESS
);
1730 * If the section offset is already in-memory and valid then just
1731 * take another reference to the page
1734 Page
= PFN_FROM_SSE(Entry
);
1736 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1737 MmUnlockSectionSegment(Segment
);
1739 Status
= MmCreateVirtualMapping(Process
,
1744 if (!NT_SUCCESS(Status
))
1746 DPRINT1("Unable to create virtual mapping\n");
1747 KeBugCheck(MEMORY_MANAGEMENT
);
1749 MmInsertRmap(Page
, Process
, Address
);
1750 PageOp
->Status
= STATUS_SUCCESS
;
1751 MmspCompleteAndReleasePageOp(PageOp
);
1752 DPRINT("Address 0x%.8X\n", Address
);
1753 return(STATUS_SUCCESS
);
1759 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1760 MEMORY_AREA
* MemoryArea
,
1763 PMM_SECTION_SEGMENT Segment
;
1764 PROS_SECTION_OBJECT Section
;
1769 LARGE_INTEGER Offset
;
1773 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1775 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
);
1778 * Check if the page has already been set readwrite
1780 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1782 DPRINT("Address 0x%.8X\n", Address
);
1783 return(STATUS_SUCCESS
);
1787 * Find the offset of the page
1789 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1790 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1791 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1793 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1794 Section
= MemoryArea
->Data
.SectionData
.Section
;
1795 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1796 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1798 ASSERT(Region
!= NULL
);
1802 MmLockSectionSegment(Segment
);
1804 OldPage
= MmGetPfnForProcess(Process
, Address
);
1805 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1807 MmUnlockSectionSegment(Segment
);
1810 * Check if we are doing COW
1812 if (!((Segment
->WriteCopy
) &&
1813 (Region
->Protect
== PAGE_READWRITE
||
1814 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1816 DPRINT("Address 0x%.8X\n", Address
);
1817 return(STATUS_ACCESS_VIOLATION
);
1820 if (IS_SWAP_FROM_SSE(Entry
) ||
1821 PFN_FROM_SSE(Entry
) != OldPage
)
1823 /* This is a private page. We must only change the page protection. */
1824 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1825 return(STATUS_SUCCESS
);
1829 DPRINT("OldPage == 0!\n");
1832 * Get or create a pageop
1834 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
.LowPart
,
1835 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1838 DPRINT1("MmGetPageOp failed\n");
1839 KeBugCheck(MEMORY_MANAGEMENT
);
1843 * Wait for any other operations to complete
1845 if (PageOp
->Thread
!= PsGetCurrentThread())
1847 MmUnlockAddressSpace(AddressSpace
);
1848 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1850 * Check for various strange conditions
1852 if (Status
== STATUS_TIMEOUT
)
1854 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1855 KeBugCheck(MEMORY_MANAGEMENT
);
1857 if (PageOp
->Status
== STATUS_PENDING
)
1859 DPRINT1("Woke for page op before completion\n");
1860 KeBugCheck(MEMORY_MANAGEMENT
);
1863 * Restart the operation
1865 MmLockAddressSpace(AddressSpace
);
1866 MmspCompleteAndReleasePageOp(PageOp
);
1867 DPRINT("Address 0x%.8X\n", Address
);
1868 return(STATUS_MM_RESTART_OPERATION
);
1872 * Release locks now we have the pageop
1874 MmUnlockAddressSpace(AddressSpace
);
1879 MI_SET_USAGE(MI_USAGE_SECTION
);
1880 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1881 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1882 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1883 if (!NT_SUCCESS(Status
))
1885 KeBugCheck(MEMORY_MANAGEMENT
);
1891 MiCopyFromUserPage(NewPage
, PAddress
);
1893 MmLockAddressSpace(AddressSpace
);
1895 * Delete the old entry.
1897 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1900 * Set the PTE to point to the new page
1902 Status
= MmCreateVirtualMapping(Process
,
1907 if (!NT_SUCCESS(Status
))
1909 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1910 KeBugCheck(MEMORY_MANAGEMENT
);
1913 if (!NT_SUCCESS(Status
))
1915 DPRINT1("Unable to create virtual mapping\n");
1916 KeBugCheck(MEMORY_MANAGEMENT
);
1920 * Unshare the old page.
1922 MmDeleteRmap(OldPage
, Process
, PAddress
);
1923 MmInsertRmap(NewPage
, Process
, PAddress
);
1924 MmLockSectionSegment(Segment
);
1925 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
);
1926 MmUnlockSectionSegment(Segment
);
1928 PageOp
->Status
= STATUS_SUCCESS
;
1929 MmspCompleteAndReleasePageOp(PageOp
);
1930 DPRINT("Address 0x%.8X\n", Address
);
1931 return(STATUS_SUCCESS
);
1935 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1937 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1941 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1944 MmLockAddressSpace(&Process
->Vm
);
1947 MmDeleteVirtualMapping(Process
,
1954 PageOutContext
->WasDirty
= TRUE
;
1956 if (!PageOutContext
->Private
)
1958 MmLockSectionSegment(PageOutContext
->Segment
);
1959 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1960 PageOutContext
->Segment
,
1961 &PageOutContext
->Offset
,
1962 PageOutContext
->WasDirty
,
1964 MmUnlockSectionSegment(PageOutContext
->Segment
);
1968 MmUnlockAddressSpace(&Process
->Vm
);
1971 if (PageOutContext
->Private
)
1973 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1976 #if (_MI_PAGING_LEVELS == 2)
1977 /* If this is for the calling process, we take care of te reference in the main function */
1978 if((Address
< MmSystemRangeStart
) && (Process
!= PageOutContext
->CallingProcess
))
1980 Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)]--;
1981 ASSERT(Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)] < PTE_COUNT
);
1985 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1990 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1991 MEMORY_AREA
* MemoryArea
,
1996 MM_SECTION_PAGEOUT_CONTEXT Context
;
1997 SWAPENTRY SwapEntry
;
2001 PFILE_OBJECT FileObject
;
2005 BOOLEAN DirectMapped
;
2006 BOOLEAN IsImageSection
;
2007 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2010 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2013 * Get the segment and section.
2015 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2016 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
2017 Context
.CallingProcess
= Process
;
2019 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2020 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2021 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
2023 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2025 FileObject
= Context
.Section
->FileObject
;
2026 DirectMapped
= FALSE
;
2029 if (FileObject
!= NULL
&&
2030 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2032 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2035 * If the file system is letting us go directly to the cache and the
2036 * memory area was mapped at an offset in the file which is page aligned
2037 * then note this is a direct mapped page.
2039 if ((FileOffset
% PAGE_SIZE
) == 0 &&
2040 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2042 DirectMapped
= TRUE
;
2049 * This should never happen since mappings of physical memory are never
2050 * placed in the rmap lists.
2052 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2054 DPRINT1("Trying to page out from physical memory section address 0x%X "
2055 "process %d\n", Address
,
2056 Process
? Process
->UniqueProcessId
: 0);
2057 KeBugCheck(MEMORY_MANAGEMENT
);
2061 * Get the section segment entry and the physical address.
2063 if (!MmIsPagePresent(Process
, Address
))
2065 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2066 Process
? Process
->UniqueProcessId
: 0, Address
);
2067 KeBugCheck(MEMORY_MANAGEMENT
);
2069 Page
= MmGetPfnForProcess(Process
, Address
);
2070 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2073 * Check the reference count to ensure this page can be paged out
2075 if (MmGetReferenceCountPage(Page
) != 1)
2077 DPRINT("Cannot page out locked section page: 0x%p (RefCount: %d)\n",
2078 Page
, MmGetReferenceCountPage(Page
));
2079 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2080 MmspCompleteAndReleasePageOp(PageOp
);
2081 return STATUS_UNSUCCESSFUL
;
2085 * Prepare the context structure for the rmap delete call.
2087 MmLockSectionSegment(Context
.Segment
);
2088 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2089 MmUnlockSectionSegment(Context
.Segment
);
2090 Context
.WasDirty
= FALSE
;
2091 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2092 IS_SWAP_FROM_SSE(Entry
) ||
2093 PFN_FROM_SSE(Entry
) != Page
)
2095 Context
.Private
= TRUE
;
2099 Context
.Private
= FALSE
;
2103 * Take an additional reference to the page or the cache segment.
2105 if (DirectMapped
&& !Context
.Private
)
2107 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
2109 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2110 KeBugCheck(MEMORY_MANAGEMENT
);
2115 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
2116 MmReferencePage(Page
);
2117 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
2120 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2121 MmLockSectionSegment(Context
.Segment
);
2122 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2123 MmUnlockSectionSegment(Context
.Segment
);
2126 * If this wasn't a private page then we should have reduced the entry to
2127 * zero by deleting all the rmaps.
2129 if (!Context
.Private
&& Entry
!= 0)
2131 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2132 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2134 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2139 * If the page wasn't dirty then we can just free it as for a readonly page.
2140 * Since we unmapped all the mappings above we know it will not suddenly
2142 * If the page is from a pagefile section and has no swap entry,
2143 * we can't free the page at this point.
2145 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2146 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2148 if (Context
.Private
)
2150 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
2151 Context
.WasDirty
? "dirty" : "clean", Address
);
2152 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2154 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2156 #if (_MI_PAGING_LEVELS == 2)
2157 /* We keep the pagefile index global to the segment, not in the PTE */
2158 if(Address
< MmSystemRangeStart
)
2160 Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)]--;
2161 ASSERT(Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)] < PTE_COUNT
);
2164 MmSetSavedSwapEntryPage(Page
, 0);
2165 MmLockSectionSegment(Context
.Segment
);
2166 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2167 MmUnlockSectionSegment(Context
.Segment
);
2168 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2169 PageOp
->Status
= STATUS_SUCCESS
;
2170 MmspCompleteAndReleasePageOp(PageOp
);
2171 return(STATUS_SUCCESS
);
2174 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2176 if (Context
.Private
)
2178 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2179 Context
.WasDirty
? "dirty" : "clean", Address
);
2180 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2182 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2184 #if (_MI_PAGING_LEVELS == 2)
2185 /* We keep the pagefile index global to the segment, not in the PTE */
2186 if(Address
< MmSystemRangeStart
)
2188 Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)]--;
2189 ASSERT(Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)] < PTE_COUNT
);
2192 MmSetSavedSwapEntryPage(Page
, 0);
2195 MmLockSectionSegment(Context
.Segment
);
2196 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2197 MmUnlockSectionSegment(Context
.Segment
);
2199 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2200 PageOp
->Status
= STATUS_SUCCESS
;
2201 MmspCompleteAndReleasePageOp(PageOp
);
2202 return(STATUS_SUCCESS
);
2205 else if (!Context
.Private
&& DirectMapped
)
2207 #if (_MI_PAGING_LEVELS == 2)
2208 /* Read only page, no need for a pagefile entry -> PDE-- */
2209 if(Address
< MmSystemRangeStart
)
2211 Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)]--;
2212 ASSERT(Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)] < PTE_COUNT
);
2217 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2219 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2222 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
2224 Status
= STATUS_SUCCESS
;
2227 if (!NT_SUCCESS(Status
))
2229 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2230 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Bcb
, FileOffset
, (ULONG_PTR
)Address
);
2233 PageOp
->Status
= STATUS_SUCCESS
;
2234 MmspCompleteAndReleasePageOp(PageOp
);
2235 return(STATUS_SUCCESS
);
2237 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2241 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2243 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2245 #if (_MI_PAGING_LEVELS == 2)
2246 /* Non dirty, non private, non direct-mapped -> PDE-- */
2247 if(Address
< MmSystemRangeStart
)
2249 Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)]--;
2250 ASSERT(Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)] < PTE_COUNT
);
2253 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2254 PageOp
->Status
= STATUS_SUCCESS
;
2255 MmspCompleteAndReleasePageOp(PageOp
);
2256 return(STATUS_SUCCESS
);
2258 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2260 DPRINT1("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2261 MmSetSavedSwapEntryPage(Page
, 0);
2262 MmLockAddressSpace(AddressSpace
);
2263 Status
= MmCreatePageFileMapping(Process
,
2266 MmUnlockAddressSpace(AddressSpace
);
2267 if (!NT_SUCCESS(Status
))
2269 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2270 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2272 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2273 PageOp
->Status
= STATUS_SUCCESS
;
2274 MmspCompleteAndReleasePageOp(PageOp
);
2275 return(STATUS_SUCCESS
);
2279 * If necessary, allocate an entry in the paging file for this page
2283 SwapEntry
= MmAllocSwapPage();
2286 MmShowOutOfSpaceMessagePagingFile();
2287 MmLockAddressSpace(AddressSpace
);
2289 * For private pages restore the old mappings.
2291 if (Context
.Private
)
2293 Status
= MmCreateVirtualMapping(Process
,
2295 MemoryArea
->Protect
,
2298 MmSetDirtyPage(Process
, Address
);
2307 * For non-private pages if the page wasn't direct mapped then
2308 * set it back into the section segment entry so we don't loose
2309 * our copy. Otherwise it will be handled by the cache manager.
2311 Status
= MmCreateVirtualMapping(Process
,
2313 MemoryArea
->Protect
,
2316 MmSetDirtyPage(Process
, Address
);
2320 // If we got here, the previous entry should have been a wait
2321 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2322 MmLockSectionSegment(Context
.Segment
);
2323 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2324 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2325 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2326 MmUnlockSectionSegment(Context
.Segment
);
2328 MmUnlockAddressSpace(AddressSpace
);
2329 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2330 MmspCompleteAndReleasePageOp(PageOp
);
2331 return(STATUS_PAGEFILE_QUOTA
);
2336 * Write the page to the pagefile
2338 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2339 if (!NT_SUCCESS(Status
))
2341 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2344 * As above: undo our actions.
2345 * FIXME: Also free the swap page.
2347 MmLockAddressSpace(AddressSpace
);
2348 if (Context
.Private
)
2350 Status
= MmCreateVirtualMapping(Process
,
2352 MemoryArea
->Protect
,
2355 MmSetDirtyPage(Process
, Address
);
2362 Status
= MmCreateVirtualMapping(Process
,
2364 MemoryArea
->Protect
,
2367 MmSetDirtyPage(Process
, Address
);
2371 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2372 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2374 MmUnlockAddressSpace(AddressSpace
);
2375 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2376 MmspCompleteAndReleasePageOp(PageOp
);
2377 return(STATUS_UNSUCCESSFUL
);
2381 * Otherwise we have succeeded.
2383 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2384 MmLockSectionSegment(Context
.Segment
);
2385 MmSetSavedSwapEntryPage(Page
, 0);
2386 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2387 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2389 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2393 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2396 if (Context
.Private
)
2398 MmLockAddressSpace(AddressSpace
);
2399 Status
= MmCreatePageFileMapping(Process
,
2402 MmUnlockAddressSpace(AddressSpace
);
2403 if (!NT_SUCCESS(Status
))
2405 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2406 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2411 #if (_MI_PAGING_LEVELS == 2)
2412 /* We keep the pagefile index global to the segment, not in the PTE */
2413 if(Address
< MmSystemRangeStart
)
2415 Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)]--;
2416 ASSERT(Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)] < PTE_COUNT
);
2419 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2420 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2423 MmUnlockSectionSegment(Context
.Segment
);
2424 PageOp
->Status
= STATUS_SUCCESS
;
2425 MmspCompleteAndReleasePageOp(PageOp
);
2426 return(STATUS_SUCCESS
);
2431 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2432 PMEMORY_AREA MemoryArea
,
2436 LARGE_INTEGER Offset
;
2437 PROS_SECTION_OBJECT Section
;
2438 PMM_SECTION_SEGMENT Segment
;
2440 SWAPENTRY SwapEntry
;
2444 PFILE_OBJECT FileObject
;
2446 BOOLEAN DirectMapped
;
2447 BOOLEAN IsImageSection
;
2448 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2450 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2452 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2453 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2456 * Get the segment and section.
2458 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2459 Section
= MemoryArea
->Data
.SectionData
.Section
;
2460 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2462 FileObject
= Section
->FileObject
;
2463 DirectMapped
= FALSE
;
2464 if (FileObject
!= NULL
&&
2465 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2467 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2470 * If the file system is letting us go directly to the cache and the
2471 * memory area was mapped at an offset in the file which is page aligned
2472 * then note this is a direct mapped page.
2474 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2475 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2477 DirectMapped
= TRUE
;
2482 * This should never happen since mappings of physical memory are never
2483 * placed in the rmap lists.
2485 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2487 DPRINT1("Trying to write back page from physical memory mapped at %X "
2488 "process %d\n", Address
,
2489 Process
? Process
->UniqueProcessId
: 0);
2490 KeBugCheck(MEMORY_MANAGEMENT
);
2494 * Get the section segment entry and the physical address.
2496 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2497 if (!MmIsPagePresent(Process
, Address
))
2499 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2500 Process
? Process
->UniqueProcessId
: 0, Address
);
2501 KeBugCheck(MEMORY_MANAGEMENT
);
2503 Page
= MmGetPfnForProcess(Process
, Address
);
2504 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2507 * Check for a private (COWed) page.
2509 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2510 IS_SWAP_FROM_SSE(Entry
) ||
2511 PFN_FROM_SSE(Entry
) != Page
)
2521 * Speculatively set all mappings of the page to clean.
2523 MmSetCleanAllRmaps(Page
);
2526 * If this page was direct mapped from the cache then the cache manager
2527 * will take care of writing it back to disk.
2529 if (DirectMapped
&& !Private
)
2531 ASSERT(SwapEntry
== 0);
2533 CcRosMarkDirtyCacheSegment(Bcb
, Offset
.LowPart
+ Segment
->Image
.FileOffset
);
2535 PageOp
->Status
= STATUS_SUCCESS
;
2536 MmspCompleteAndReleasePageOp(PageOp
);
2537 return(STATUS_SUCCESS
);
2541 * If necessary, allocate an entry in the paging file for this page
2545 SwapEntry
= MmAllocSwapPage();
2548 MmSetDirtyAllRmaps(Page
);
2549 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2550 MmspCompleteAndReleasePageOp(PageOp
);
2551 return(STATUS_PAGEFILE_QUOTA
);
2553 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2557 * Write the page to the pagefile
2559 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2560 if (!NT_SUCCESS(Status
))
2562 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2564 MmSetDirtyAllRmaps(Page
);
2565 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2566 MmspCompleteAndReleasePageOp(PageOp
);
2567 return(STATUS_UNSUCCESSFUL
);
2571 * Otherwise we have succeeded.
2573 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2574 PageOp
->Status
= STATUS_SUCCESS
;
2575 MmspCompleteAndReleasePageOp(PageOp
);
2576 return(STATUS_SUCCESS
);
2580 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2588 PMEMORY_AREA MemoryArea
;
2589 PMM_SECTION_SEGMENT Segment
;
2590 BOOLEAN DoCOW
= FALSE
;
2592 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2594 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2595 ASSERT(MemoryArea
!= NULL
);
2596 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2597 MmLockSectionSegment(Segment
);
2599 if ((Segment
->WriteCopy
) &&
2600 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2605 if (OldProtect
!= NewProtect
)
2607 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2609 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2610 ULONG Protect
= NewProtect
;
2613 * If we doing COW for this segment then check if the page is
2616 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2618 LARGE_INTEGER Offset
;
2622 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2623 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2624 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2625 Page
= MmGetPfnForProcess(Process
, Address
);
2627 Protect
= PAGE_READONLY
;
2628 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2629 IS_SWAP_FROM_SSE(Entry
) ||
2630 PFN_FROM_SSE(Entry
) != Page
)
2632 Protect
= NewProtect
;
2636 if (MmIsPagePresent(Process
, Address
))
2638 MmSetPageProtect(Process
, Address
,
2644 MmUnlockSectionSegment(Segment
);
2649 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2650 PMEMORY_AREA MemoryArea
,
2658 ULONG_PTR MaxLength
;
2660 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2661 if (Length
> MaxLength
)
2662 Length
= (ULONG
)MaxLength
;
2664 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2665 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2667 ASSERT(Region
!= NULL
);
2669 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2670 Region
->Protect
!= Protect
)
2672 return STATUS_INVALID_PAGE_PROTECTION
;
2675 *OldProtect
= Region
->Protect
;
2676 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2677 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2678 BaseAddress
, Length
, Region
->Type
, Protect
,
2679 MmAlterViewAttributes
);
2685 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2687 PMEMORY_BASIC_INFORMATION Info
,
2688 PSIZE_T ResultLength
)
2691 PVOID RegionBaseAddress
;
2692 PROS_SECTION_OBJECT Section
;
2693 PMM_SECTION_SEGMENT Segment
;
2695 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2696 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2697 Address
, &RegionBaseAddress
);
2700 return STATUS_UNSUCCESSFUL
;
2703 Section
= MemoryArea
->Data
.SectionData
.Section
;
2704 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2706 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2707 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2708 Info
->Type
= MEM_IMAGE
;
2712 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2713 Info
->Type
= MEM_MAPPED
;
2715 Info
->BaseAddress
= RegionBaseAddress
;
2716 Info
->AllocationProtect
= MemoryArea
->Protect
;
2717 Info
->RegionSize
= Region
->Length
;
2718 Info
->State
= MEM_COMMIT
;
2719 Info
->Protect
= Region
->Protect
;
2721 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2722 return(STATUS_SUCCESS
);
2727 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2730 LARGE_INTEGER Offset
;
2732 SWAPENTRY SavedSwapEntry
;
2737 MmLockSectionSegment(Segment
);
2739 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2740 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2742 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2745 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2746 if (IS_SWAP_FROM_SSE(Entry
))
2748 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2752 Page
= PFN_FROM_SSE(Entry
);
2753 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2754 if (SavedSwapEntry
!= 0)
2756 MmSetSavedSwapEntryPage(Page
, 0);
2757 MmFreeSwapPage(SavedSwapEntry
);
2759 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2764 MmUnlockSectionSegment(Segment
);
2768 MmpDeleteSection(PVOID ObjectBody
)
2770 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2772 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2773 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2778 PMM_SECTION_SEGMENT SectionSegments
;
2781 * NOTE: Section->ImageSection can be NULL for short time
2782 * during the section creating. If we fail for some reason
2783 * until the image section is properly initialized we shouldn't
2784 * process further here.
2786 if (Section
->ImageSection
== NULL
)
2789 SectionSegments
= Section
->ImageSection
->Segments
;
2790 NrSegments
= Section
->ImageSection
->NrSegments
;
2792 for (i
= 0; i
< NrSegments
; i
++)
2794 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2796 MmLockSectionSegment(&SectionSegments
[i
]);
2798 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2799 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2801 MmUnlockSectionSegment(&SectionSegments
[i
]);
2804 MmpFreePageFileSegment(&SectionSegments
[i
]);
2810 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2813 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2816 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2818 DPRINT("Freeing section segment\n");
2819 Section
->Segment
= NULL
;
2820 MmFinalizeSegment(Segment
);
2824 DPRINT("RefCount %d\n", RefCount
);
2831 * NOTE: Section->Segment can be NULL for short time
2832 * during the section creating.
2834 if (Section
->Segment
== NULL
)
2837 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2839 MmpFreePageFileSegment(Section
->Segment
);
2840 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2841 ExFreePool(Section
->Segment
);
2842 Section
->Segment
= NULL
;
2846 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2849 if (Section
->FileObject
!= NULL
)
2852 CcRosDereferenceCache(Section
->FileObject
);
2854 ObDereferenceObject(Section
->FileObject
);
2855 Section
->FileObject
= NULL
;
2860 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2862 IN ACCESS_MASK GrantedAccess
,
2863 IN ULONG ProcessHandleCount
,
2864 IN ULONG SystemHandleCount
)
2866 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2867 Object
, ProcessHandleCount
);
2873 MmCreatePhysicalMemorySection(VOID
)
2875 PROS_SECTION_OBJECT PhysSection
;
2877 OBJECT_ATTRIBUTES Obj
;
2878 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2879 LARGE_INTEGER SectionSize
;
2883 * Create the section mapping physical memory
2885 SectionSize
.QuadPart
= 0xFFFFFFFF;
2886 InitializeObjectAttributes(&Obj
,
2891 Status
= MmCreateSection((PVOID
)&PhysSection
,
2895 PAGE_EXECUTE_READWRITE
,
2899 if (!NT_SUCCESS(Status
))
2901 DPRINT1("Failed to create PhysicalMemory section\n");
2902 KeBugCheck(MEMORY_MANAGEMENT
);
2904 Status
= ObInsertObject(PhysSection
,
2910 if (!NT_SUCCESS(Status
))
2912 ObDereferenceObject(PhysSection
);
2914 ObCloseHandle(Handle
, KernelMode
);
2915 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2916 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2918 return(STATUS_SUCCESS
);
2924 MmInitSectionImplementation(VOID
)
2926 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2927 UNICODE_STRING Name
;
2929 DPRINT("Creating Section Object Type\n");
2931 /* Initialize the Section object type */
2932 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2933 RtlInitUnicodeString(&Name
, L
"Section");
2934 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2935 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2936 ObjectTypeInitializer
.PoolType
= PagedPool
;
2937 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2938 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2939 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2940 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2941 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2942 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2944 MmCreatePhysicalMemorySection();
2946 return(STATUS_SUCCESS
);
2951 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2952 ACCESS_MASK DesiredAccess
,
2953 POBJECT_ATTRIBUTES ObjectAttributes
,
2954 PLARGE_INTEGER UMaximumSize
,
2955 ULONG SectionPageProtection
,
2956 ULONG AllocationAttributes
)
2958 * Create a section which is backed by the pagefile
2961 LARGE_INTEGER MaximumSize
;
2962 PROS_SECTION_OBJECT Section
;
2963 PMM_SECTION_SEGMENT Segment
;
2966 if (UMaximumSize
== NULL
)
2968 return(STATUS_UNSUCCESSFUL
);
2970 MaximumSize
= *UMaximumSize
;
2973 * Create the section
2975 Status
= ObCreateObject(ExGetPreviousMode(),
2976 MmSectionObjectType
,
2978 ExGetPreviousMode(),
2980 sizeof(ROS_SECTION_OBJECT
),
2983 (PVOID
*)(PVOID
)&Section
);
2984 if (!NT_SUCCESS(Status
))
2992 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2993 Section
->SectionPageProtection
= SectionPageProtection
;
2994 Section
->AllocationAttributes
= AllocationAttributes
;
2995 Section
->MaximumSize
= MaximumSize
;
2996 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2997 TAG_MM_SECTION_SEGMENT
);
2998 if (Segment
== NULL
)
3000 ObDereferenceObject(Section
);
3001 return(STATUS_NO_MEMORY
);
3003 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
3004 Section
->Segment
= Segment
;
3005 Segment
->ReferenceCount
= 1;
3006 ExInitializeFastMutex(&Segment
->Lock
);
3007 Segment
->Image
.FileOffset
= 0;
3008 Segment
->Protection
= SectionPageProtection
;
3009 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
3010 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
3011 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
3012 Segment
->WriteCopy
= FALSE
;
3013 Segment
->Image
.VirtualAddress
= 0;
3014 Segment
->Image
.Characteristics
= 0;
3015 *SectionObject
= Section
;
3016 MiInitializeSectionPageTable(Segment
);
3017 return(STATUS_SUCCESS
);
3022 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
3023 ACCESS_MASK DesiredAccess
,
3024 POBJECT_ATTRIBUTES ObjectAttributes
,
3025 PLARGE_INTEGER UMaximumSize
,
3026 ULONG SectionPageProtection
,
3027 ULONG AllocationAttributes
,
3030 * Create a section backed by a data file
3033 PROS_SECTION_OBJECT Section
;
3035 LARGE_INTEGER MaximumSize
;
3036 PFILE_OBJECT FileObject
;
3037 PMM_SECTION_SEGMENT Segment
;
3039 IO_STATUS_BLOCK Iosb
;
3040 LARGE_INTEGER Offset
;
3042 FILE_STANDARD_INFORMATION FileInfo
;
3046 * Create the section
3048 Status
= ObCreateObject(ExGetPreviousMode(),
3049 MmSectionObjectType
,
3051 ExGetPreviousMode(),
3053 sizeof(ROS_SECTION_OBJECT
),
3057 if (!NT_SUCCESS(Status
))
3064 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3065 Section
->SectionPageProtection
= SectionPageProtection
;
3066 Section
->AllocationAttributes
= AllocationAttributes
;
3069 * Reference the file handle
3071 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
3072 Status
= ObReferenceObjectByHandle(FileHandle
,
3075 ExGetPreviousMode(),
3076 (PVOID
*)(PVOID
)&FileObject
,
3078 if (!NT_SUCCESS(Status
))
3080 ObDereferenceObject(Section
);
3085 * FIXME: This is propably not entirely correct. We can't look into
3086 * the standard FCB header because it might not be initialized yet
3087 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
3088 * standard file information is filled on first request).
3090 Status
= IoQueryFileInformation(FileObject
,
3091 FileStandardInformation
,
3092 sizeof(FILE_STANDARD_INFORMATION
),
3095 Iosb
.Information
= Length
;
3096 if (!NT_SUCCESS(Status
))
3098 ObDereferenceObject(Section
);
3099 ObDereferenceObject(FileObject
);
3104 * FIXME: Revise this once a locking order for file size changes is
3107 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
3109 MaximumSize
= *UMaximumSize
;
3113 MaximumSize
= FileInfo
.EndOfFile
;
3114 /* Mapping zero-sized files isn't allowed. */
3115 if (MaximumSize
.QuadPart
== 0)
3117 ObDereferenceObject(Section
);
3118 ObDereferenceObject(FileObject
);
3119 return STATUS_FILE_INVALID
;
3123 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3125 Status
= IoSetInformation(FileObject
,
3126 FileAllocationInformation
,
3127 sizeof(LARGE_INTEGER
),
3129 if (!NT_SUCCESS(Status
))
3131 ObDereferenceObject(Section
);
3132 ObDereferenceObject(FileObject
);
3133 return(STATUS_SECTION_NOT_EXTENDED
);
3137 if (FileObject
->SectionObjectPointer
== NULL
||
3138 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3141 * Read a bit so caching is initiated for the file object.
3142 * This is only needed because MiReadPage currently cannot
3143 * handle non-cached streams.
3145 Offset
.QuadPart
= 0;
3146 Status
= ZwReadFile(FileHandle
,
3155 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3157 ObDereferenceObject(Section
);
3158 ObDereferenceObject(FileObject
);
3161 if (FileObject
->SectionObjectPointer
== NULL
||
3162 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3164 /* FIXME: handle this situation */
3165 ObDereferenceObject(Section
);
3166 ObDereferenceObject(FileObject
);
3167 return STATUS_INVALID_PARAMETER
;
3174 Status
= MmspWaitForFileLock(FileObject
);
3175 if (Status
!= STATUS_SUCCESS
)
3177 ObDereferenceObject(Section
);
3178 ObDereferenceObject(FileObject
);
3183 * If this file hasn't been mapped as a data file before then allocate a
3184 * section segment to describe the data file mapping
3186 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3188 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3189 TAG_MM_SECTION_SEGMENT
);
3190 if (Segment
== NULL
)
3192 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3193 ObDereferenceObject(Section
);
3194 ObDereferenceObject(FileObject
);
3195 return(STATUS_NO_MEMORY
);
3197 Section
->Segment
= Segment
;
3198 Segment
->ReferenceCount
= 1;
3199 ExInitializeFastMutex(&Segment
->Lock
);
3201 * Set the lock before assigning the segment to the file object
3203 ExAcquireFastMutex(&Segment
->Lock
);
3204 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3206 Segment
->Image
.FileOffset
= 0;
3207 Segment
->Protection
= SectionPageProtection
;
3208 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3209 Segment
->Image
.Characteristics
= 0;
3210 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3211 if (AllocationAttributes
& SEC_RESERVE
)
3213 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3217 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3218 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3220 Segment
->Image
.VirtualAddress
= 0;
3221 Segment
->Locked
= TRUE
;
3222 MiInitializeSectionPageTable(Segment
);
3227 * If the file is already mapped as a data file then we may need
3231 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3233 Section
->Segment
= Segment
;
3234 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3235 MmLockSectionSegment(Segment
);
3237 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3238 !(AllocationAttributes
& SEC_RESERVE
))
3240 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3241 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3244 MmUnlockSectionSegment(Segment
);
3245 Section
->FileObject
= FileObject
;
3246 Section
->MaximumSize
= MaximumSize
;
3248 CcRosReferenceCache(FileObject
);
3250 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3251 *SectionObject
= Section
;
3252 return(STATUS_SUCCESS
);
3256 TODO: not that great (declaring loaders statically, having to declare all of
3257 them, having to keep them extern, etc.), will fix in the future
3259 extern NTSTATUS NTAPI PeFmtCreateSection
3261 IN CONST VOID
* FileHeader
,
3262 IN SIZE_T FileHeaderSize
,
3264 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3266 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3267 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3270 extern NTSTATUS NTAPI ElfFmtCreateSection
3272 IN CONST VOID
* FileHeader
,
3273 IN SIZE_T FileHeaderSize
,
3275 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3277 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3278 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3281 /* TODO: this is a standard DDK/PSDK macro */
3282 #ifndef RTL_NUMBER_OF
3283 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3286 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3297 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3299 SIZE_T SizeOfSegments
;
3300 PMM_SECTION_SEGMENT Segments
;
3302 /* TODO: check for integer overflow */
3303 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3305 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3307 TAG_MM_SECTION_SEGMENT
);
3310 RtlZeroMemory(Segments
, SizeOfSegments
);
3318 ExeFmtpReadFile(IN PVOID File
,
3319 IN PLARGE_INTEGER Offset
,
3322 OUT PVOID
* AllocBase
,
3323 OUT PULONG ReadSize
)
3326 LARGE_INTEGER FileOffset
;
3328 ULONG OffsetAdjustment
;
3332 PFILE_OBJECT FileObject
= File
;
3333 IO_STATUS_BLOCK Iosb
;
3335 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3339 KeBugCheck(MEMORY_MANAGEMENT
);
3342 FileOffset
= *Offset
;
3344 /* Negative/special offset: it cannot be used in this context */
3345 if(FileOffset
.u
.HighPart
< 0)
3347 KeBugCheck(MEMORY_MANAGEMENT
);
3350 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3351 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3352 FileOffset
.u
.LowPart
= AdjustOffset
;
3354 BufferSize
= Length
+ OffsetAdjustment
;
3355 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3358 * It's ok to use paged pool, because this is a temporary buffer only used in
3359 * the loading of executables. The assumption is that MmCreateSection is
3360 * always called at low IRQLs and that these buffers don't survive a brief
3361 * initialization phase
3363 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3368 KeBugCheck(MEMORY_MANAGEMENT
);
3373 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3375 UsedSize
= Iosb
.Information
;
3377 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3379 Status
= STATUS_IN_PAGE_ERROR
;
3380 ASSERT(!NT_SUCCESS(Status
));
3383 if(NT_SUCCESS(Status
))
3385 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3386 *AllocBase
= Buffer
;
3387 *ReadSize
= UsedSize
- OffsetAdjustment
;
3391 ExFreePoolWithTag(Buffer
, 'rXmM');
3398 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3399 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3400 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3405 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3409 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3411 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3412 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3419 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3423 MmspAssertSegmentsSorted(ImageSectionObject
);
3425 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3427 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3431 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3432 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3433 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3441 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3445 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3447 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3448 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3456 MmspCompareSegments(const void * x
,
3459 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3460 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3463 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3464 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3468 * Ensures an image section's segments are sorted in memory
3473 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3476 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3478 MmspAssertSegmentsSorted(ImageSectionObject
);
3482 qsort(ImageSectionObject
->Segments
,
3483 ImageSectionObject
->NrSegments
,
3484 sizeof(ImageSectionObject
->Segments
[0]),
3485 MmspCompareSegments
);
3491 * Ensures an image section's segments don't overlap in memory and don't have
3492 * gaps and don't have a null size. We let them map to overlapping file regions,
3493 * though - that's not necessarily an error
3498 MmspCheckSegmentBounds
3500 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3506 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3508 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3512 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3514 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3516 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3524 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3525 * page could be OK (Windows seems to be OK with them), and larger gaps
3526 * could lead to image sections spanning several discontiguous regions
3527 * (NtMapViewOfSection could then refuse to map them, and they could
3528 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3530 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3531 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3532 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3543 * Merges and pads an image section's segments until they all are page-aligned
3544 * and have a size that is a multiple of the page size
3549 MmspPageAlignSegments
3551 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3557 PMM_SECTION_SEGMENT EffectiveSegment
;
3559 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3561 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3566 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3568 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3571 * The first segment requires special handling
3575 ULONG_PTR VirtualAddress
;
3576 ULONG_PTR VirtualOffset
;
3578 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3580 /* Round down the virtual address to the nearest page */
3581 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3583 /* Round up the virtual size to the nearest page */
3584 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3585 EffectiveSegment
->Image
.VirtualAddress
;
3587 /* Adjust the raw address and size */
3588 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3590 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3596 * Garbage in, garbage out: unaligned base addresses make the file
3597 * offset point in curious and odd places, but that's what we were
3600 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3601 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3605 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3606 ULONG_PTR EndOfEffectiveSegment
;
3608 EndOfEffectiveSegment
= EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
;
3609 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3612 * The current segment begins exactly where the current effective
3613 * segment ended, therefore beginning a new effective segment
3615 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3618 ASSERT(LastSegment
<= i
);
3619 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3621 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3623 if (LastSegment
!= i
)
3626 * Copy the current segment. If necessary, the effective segment
3627 * will be expanded later
3629 *EffectiveSegment
= *Segment
;
3633 * Page-align the virtual size. We know for sure the virtual address
3636 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3637 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3640 * The current segment is still part of the current effective segment:
3641 * extend the effective segment to reflect this
3643 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3645 static const ULONG FlagsToProtection
[16] =
3653 PAGE_EXECUTE_READWRITE
,
3654 PAGE_EXECUTE_READWRITE
,
3659 PAGE_EXECUTE_WRITECOPY
,
3660 PAGE_EXECUTE_WRITECOPY
,
3661 PAGE_EXECUTE_WRITECOPY
,
3662 PAGE_EXECUTE_WRITECOPY
3665 unsigned ProtectionFlags
;
3668 * Extend the file size
3671 /* Unaligned segments must be contiguous within the file */
3672 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3673 EffectiveSegment
->RawLength
.QuadPart
))
3678 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3681 * Extend the virtual size
3683 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3685 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3686 EffectiveSegment
->Image
.VirtualAddress
;
3689 * Merge the protection
3691 EffectiveSegment
->Protection
|= Segment
->Protection
;
3693 /* Clean up redundance */
3694 ProtectionFlags
= 0;
3696 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3697 ProtectionFlags
|= 1 << 0;
3699 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3700 ProtectionFlags
|= 1 << 1;
3702 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3703 ProtectionFlags
|= 1 << 2;
3705 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3706 ProtectionFlags
|= 1 << 3;
3708 ASSERT(ProtectionFlags
< 16);
3709 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3711 /* If a segment was required to be shared and cannot, fail */
3712 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3713 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3719 * We assume no holes between segments at this point
3723 KeBugCheck(MEMORY_MANAGEMENT
);
3727 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3733 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3734 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3736 LARGE_INTEGER Offset
;
3738 PVOID FileHeaderBuffer
;
3739 ULONG FileHeaderSize
;
3741 ULONG OldNrSegments
;
3746 * Read the beginning of the file (2 pages). Should be enough to contain
3747 * all (or most) of the headers
3749 Offset
.QuadPart
= 0;
3751 /* FIXME: use FileObject instead of FileHandle */
3752 Status
= ExeFmtpReadFile (FileHandle
,
3759 if (!NT_SUCCESS(Status
))
3762 if (FileHeaderSize
== 0)
3764 ExFreePool(FileHeaderBuffer
);
3765 return STATUS_UNSUCCESSFUL
;
3769 * Look for a loader that can handle this executable
3771 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3773 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3776 /* FIXME: use FileObject instead of FileHandle */
3777 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3783 ExeFmtpAllocateSegments
);
3785 if (!NT_SUCCESS(Status
))
3787 if (ImageSectionObject
->Segments
)
3789 ExFreePool(ImageSectionObject
->Segments
);
3790 ImageSectionObject
->Segments
= NULL
;
3794 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3798 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3801 * No loader handled the format
3803 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3805 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3806 ASSERT(!NT_SUCCESS(Status
));
3809 if (!NT_SUCCESS(Status
))
3812 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3817 /* FIXME? are these values platform-dependent? */
3818 if(ImageSectionObject
->StackReserve
== 0)
3819 ImageSectionObject
->StackReserve
= 0x40000;
3821 if(ImageSectionObject
->StackCommit
== 0)
3822 ImageSectionObject
->StackCommit
= 0x1000;
3824 if(ImageSectionObject
->ImageBase
== 0)
3826 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3827 ImageSectionObject
->ImageBase
= 0x10000000;
3829 ImageSectionObject
->ImageBase
= 0x00400000;
3833 * And now the fun part: fixing the segments
3836 /* Sort them by virtual address */
3837 MmspSortSegments(ImageSectionObject
, Flags
);
3839 /* Ensure they don't overlap in memory */
3840 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3841 return STATUS_INVALID_IMAGE_FORMAT
;
3843 /* Ensure they are aligned */
3844 OldNrSegments
= ImageSectionObject
->NrSegments
;
3846 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3847 return STATUS_INVALID_IMAGE_FORMAT
;
3849 /* Trim them if the alignment phase merged some of them */
3850 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3852 PMM_SECTION_SEGMENT Segments
;
3853 SIZE_T SizeOfSegments
;
3855 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3857 Segments
= ExAllocatePoolWithTag(PagedPool
,
3859 TAG_MM_SECTION_SEGMENT
);
3861 if (Segments
== NULL
)
3862 return STATUS_INSUFFICIENT_RESOURCES
;
3864 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3865 ExFreePool(ImageSectionObject
->Segments
);
3866 ImageSectionObject
->Segments
= Segments
;
3869 /* And finish their initialization */
3870 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3872 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3873 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3874 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3877 ASSERT(NT_SUCCESS(Status
));
3882 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3883 ACCESS_MASK DesiredAccess
,
3884 POBJECT_ATTRIBUTES ObjectAttributes
,
3885 PLARGE_INTEGER UMaximumSize
,
3886 ULONG SectionPageProtection
,
3887 ULONG AllocationAttributes
,
3888 PFILE_OBJECT FileObject
)
3890 PROS_SECTION_OBJECT Section
;
3892 PMM_SECTION_SEGMENT SectionSegments
;
3893 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3896 if (FileObject
== NULL
)
3897 return STATUS_INVALID_FILE_FOR_SECTION
;
3900 * Create the section
3902 Status
= ObCreateObject (ExGetPreviousMode(),
3903 MmSectionObjectType
,
3905 ExGetPreviousMode(),
3907 sizeof(ROS_SECTION_OBJECT
),
3910 (PVOID
*)(PVOID
)&Section
);
3911 if (!NT_SUCCESS(Status
))
3913 ObDereferenceObject(FileObject
);
3920 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3921 Section
->SectionPageProtection
= SectionPageProtection
;
3922 Section
->AllocationAttributes
= AllocationAttributes
;
3926 * Initialized caching for this file object if previously caching
3927 * was initialized for the same on disk file
3929 Status
= CcTryToInitializeFileCache(FileObject
);
3931 Status
= STATUS_SUCCESS
;
3934 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3936 NTSTATUS StatusExeFmt
;
3938 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3939 if (ImageSectionObject
== NULL
)
3941 ObDereferenceObject(FileObject
);
3942 ObDereferenceObject(Section
);
3943 return(STATUS_NO_MEMORY
);
3946 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3948 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3950 if (!NT_SUCCESS(StatusExeFmt
))
3952 if(ImageSectionObject
->Segments
!= NULL
)
3953 ExFreePool(ImageSectionObject
->Segments
);
3955 ExFreePool(ImageSectionObject
);
3956 ObDereferenceObject(Section
);
3957 ObDereferenceObject(FileObject
);
3958 return(StatusExeFmt
);
3961 Section
->ImageSection
= ImageSectionObject
;
3962 ASSERT(ImageSectionObject
->Segments
);
3967 Status
= MmspWaitForFileLock(FileObject
);
3968 if (!NT_SUCCESS(Status
))
3970 ExFreePool(ImageSectionObject
->Segments
);
3971 ExFreePool(ImageSectionObject
);
3972 ObDereferenceObject(Section
);
3973 ObDereferenceObject(FileObject
);
3977 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3978 ImageSectionObject
, NULL
))
3981 * An other thread has initialized the same image in the background
3983 ExFreePool(ImageSectionObject
->Segments
);
3984 ExFreePool(ImageSectionObject
);
3985 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3986 Section
->ImageSection
= ImageSectionObject
;
3987 SectionSegments
= ImageSectionObject
->Segments
;
3989 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3991 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3995 Status
= StatusExeFmt
;
4002 Status
= MmspWaitForFileLock(FileObject
);
4003 if (Status
!= STATUS_SUCCESS
)
4005 ObDereferenceObject(Section
);
4006 ObDereferenceObject(FileObject
);
4010 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
4011 Section
->ImageSection
= ImageSectionObject
;
4012 SectionSegments
= ImageSectionObject
->Segments
;
4015 * Otherwise just reference all the section segments
4017 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
4019 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
4022 Status
= STATUS_SUCCESS
;
4024 Section
->FileObject
= FileObject
;
4026 CcRosReferenceCache(FileObject
);
4028 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
4029 *SectionObject
= Section
;
4036 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
4037 PROS_SECTION_OBJECT Section
,
4038 PMM_SECTION_SEGMENT Segment
,
4043 ULONG AllocationType
)
4047 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4049 if (Segment
->WriteCopy
)
4051 /* We have to do this because the not present fault
4052 * and access fault handlers depend on the protection
4053 * that should be granted AFTER the COW fault takes
4054 * place to be in Region->Protect. The not present fault
4055 * handler changes this to the correct protection for COW when
4056 * mapping the pages into the process's address space. If a COW
4057 * fault takes place, the access fault handler sets the page protection
4058 * to these values for the newly copied pages
4060 if (Protect
== PAGE_WRITECOPY
)
4061 Protect
= PAGE_READWRITE
;
4062 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
4063 Protect
= PAGE_EXECUTE_READWRITE
;
4066 BoundaryAddressMultiple
.QuadPart
= 0;
4069 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
4070 LARGE_INTEGER FileOffset
;
4071 FileOffset
.QuadPart
= ViewOffset
;
4072 ObReferenceObject(Section
);
4073 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
4076 Status
= MmCreateMemoryArea(AddressSpace
,
4077 MEMORY_AREA_SECTION_VIEW
,
4084 BoundaryAddressMultiple
);
4085 if (!NT_SUCCESS(Status
))
4087 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
4088 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
4092 ObReferenceObject((PVOID
)Section
);
4094 MArea
->Data
.SectionData
.Segment
= Segment
;
4095 MArea
->Data
.SectionData
.Section
= Section
;
4096 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
4097 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
4098 ViewSize
, 0, Protect
);
4100 return(STATUS_SUCCESS
);
4105 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
4106 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4109 PFILE_OBJECT FileObject
;
4111 LARGE_INTEGER Offset
;
4112 SWAPENTRY SavedSwapEntry
;
4115 PROS_SECTION_OBJECT Section
;
4116 PMM_SECTION_SEGMENT Segment
;
4117 PMMSUPPORT AddressSpace
;
4120 AddressSpace
= (PMMSUPPORT
)Context
;
4121 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4123 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4125 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
4126 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
4128 Section
= MemoryArea
->Data
.SectionData
.Section
;
4129 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4131 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
.LowPart
);
4135 MmUnlockSectionSegment(Segment
);
4136 MmUnlockAddressSpace(AddressSpace
);
4138 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4139 if (Status
!= STATUS_SUCCESS
)
4141 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4142 KeBugCheck(MEMORY_MANAGEMENT
);
4145 MmLockAddressSpace(AddressSpace
);
4146 MmLockSectionSegment(Segment
);
4147 MmspCompleteAndReleasePageOp(PageOp
);
4148 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
.LowPart
);
4151 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4154 * For a dirty, datafile, non-private page mark it as dirty in the
4157 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4159 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4161 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4162 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4164 CcRosMarkDirtyCacheSegment(Bcb
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4166 ASSERT(SwapEntry
== 0);
4175 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4177 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4178 KeBugCheck(MEMORY_MANAGEMENT
);
4180 MmFreeSwapPage(SwapEntry
);
4184 if (IS_SWAP_FROM_SSE(Entry
) ||
4185 Page
!= PFN_FROM_SSE(Entry
))
4190 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4192 DPRINT1("Found a private page in a pagefile section.\n");
4193 KeBugCheck(MEMORY_MANAGEMENT
);
4196 * Just dereference private pages
4198 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4199 if (SavedSwapEntry
!= 0)
4201 MmFreeSwapPage(SavedSwapEntry
);
4202 MmSetSavedSwapEntryPage(Page
, 0);
4204 MmDeleteRmap(Page
, Process
, Address
);
4205 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4209 MmDeleteRmap(Page
, Process
, Address
);
4210 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
);
4216 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4220 PMEMORY_AREA MemoryArea
;
4221 PROS_SECTION_OBJECT Section
;
4222 PMM_SECTION_SEGMENT Segment
;
4223 PLIST_ENTRY CurrentEntry
;
4224 PMM_REGION CurrentRegion
;
4225 PLIST_ENTRY RegionListHead
;
4227 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4229 if (MemoryArea
== NULL
)
4231 return(STATUS_UNSUCCESSFUL
);
4234 MemoryArea
->DeleteInProgress
= TRUE
;
4235 Section
= MemoryArea
->Data
.SectionData
.Section
;
4236 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4239 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4240 return MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4243 MmLockSectionSegment(Segment
);
4245 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4246 while (!IsListEmpty(RegionListHead
))
4248 CurrentEntry
= RemoveHeadList(RegionListHead
);
4249 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4250 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4253 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4255 Status
= MmFreeMemoryArea(AddressSpace
,
4262 Status
= MmFreeMemoryArea(AddressSpace
,
4267 MmUnlockSectionSegment(Segment
);
4268 ObDereferenceObject(Section
);
4276 MmUnmapViewOfSection(PEPROCESS Process
,
4280 PMEMORY_AREA MemoryArea
;
4281 PMMSUPPORT AddressSpace
;
4282 PROS_SECTION_OBJECT Section
;
4285 PVOID ImageBaseAddress
= 0;
4287 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4288 Process
, BaseAddress
);
4292 AddressSpace
= &Process
->Vm
;
4294 MmLockAddressSpace(AddressSpace
);
4295 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4297 if (MemoryArea
== NULL
||
4298 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4299 MemoryArea
->DeleteInProgress
)
4301 MmUnlockAddressSpace(AddressSpace
);
4302 return STATUS_NOT_MAPPED_VIEW
;
4305 MemoryArea
->DeleteInProgress
= TRUE
;
4307 while (MemoryArea
->PageOpCount
)
4309 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4313 Offset
-= PAGE_SIZE
;
4314 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4315 MemoryArea
->Data
.SectionData
.Segment
,
4316 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
);
4319 MmUnlockAddressSpace(AddressSpace
);
4320 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4321 if (Status
!= STATUS_SUCCESS
)
4323 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4324 KeBugCheck(MEMORY_MANAGEMENT
);
4326 MmLockAddressSpace(AddressSpace
);
4327 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4329 if (MemoryArea
== NULL
||
4330 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4332 MmUnlockAddressSpace(AddressSpace
);
4333 return STATUS_NOT_MAPPED_VIEW
;
4340 Section
= MemoryArea
->Data
.SectionData
.Section
;
4342 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4346 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4347 PMM_SECTION_SEGMENT SectionSegments
;
4348 PMM_SECTION_SEGMENT Segment
;
4350 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4351 ImageSectionObject
= Section
->ImageSection
;
4352 SectionSegments
= ImageSectionObject
->Segments
;
4353 NrSegments
= ImageSectionObject
->NrSegments
;
4355 /* Search for the current segment within the section segments
4356 * and calculate the image base address */
4357 for (i
= 0; i
< NrSegments
; i
++)
4359 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4361 if (Segment
== &SectionSegments
[i
])
4363 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4368 if (i
>= NrSegments
)
4370 KeBugCheck(MEMORY_MANAGEMENT
);
4373 for (i
= 0; i
< NrSegments
; i
++)
4375 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4377 PVOID SBaseAddress
= (PVOID
)
4378 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4380 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4386 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4389 MmUnlockAddressSpace(AddressSpace
);
4391 /* Notify debugger */
4392 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4394 return(STATUS_SUCCESS
);
4401 * Queries the information of a section object.
4403 * @param SectionHandle
4404 * Handle to the section object. It must be opened with SECTION_QUERY
4406 * @param SectionInformationClass
4407 * Index to a certain information structure. Can be either
4408 * SectionBasicInformation or SectionImageInformation. The latter
4409 * is valid only for sections that were created with the SEC_IMAGE
4411 * @param SectionInformation
4412 * Caller supplies storage for resulting information.
4414 * Size of the supplied storage.
4415 * @param ResultLength
4423 NtQuerySection(IN HANDLE SectionHandle
,
4424 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4425 OUT PVOID SectionInformation
,
4426 IN SIZE_T SectionInformationLength
,
4427 OUT PSIZE_T ResultLength OPTIONAL
)
4429 PROS_SECTION_OBJECT Section
;
4430 KPROCESSOR_MODE PreviousMode
;
4434 PreviousMode
= ExGetPreviousMode();
4436 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4438 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4440 (ULONG
)SectionInformationLength
,
4445 if(!NT_SUCCESS(Status
))
4447 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4451 Status
= ObReferenceObjectByHandle(SectionHandle
,
4453 MmSectionObjectType
,
4455 (PVOID
*)(PVOID
)&Section
,
4457 if (NT_SUCCESS(Status
))
4459 switch (SectionInformationClass
)
4461 case SectionBasicInformation
:
4463 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4467 Sbi
->Attributes
= Section
->AllocationAttributes
;
4468 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4470 Sbi
->BaseAddress
= 0;
4471 Sbi
->Size
.QuadPart
= 0;
4475 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4476 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4479 if (ResultLength
!= NULL
)
4481 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4483 Status
= STATUS_SUCCESS
;
4485 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4487 Status
= _SEH2_GetExceptionCode();
4494 case SectionImageInformation
:
4496 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4500 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4501 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4503 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4504 ImageSectionObject
= Section
->ImageSection
;
4506 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4507 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4508 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4509 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4510 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4511 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4512 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4513 Sii
->Machine
= ImageSectionObject
->Machine
;
4514 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4517 if (ResultLength
!= NULL
)
4519 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4521 Status
= STATUS_SUCCESS
;
4523 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4525 Status
= _SEH2_GetExceptionCode();
4533 ObDereferenceObject(Section
);
4539 /**********************************************************************
4541 * MmMapViewOfSection
4544 * Maps a view of a section into the virtual address space of a
4549 * Pointer to the section object.
4552 * Pointer to the process.
4555 * Desired base address (or NULL) on entry;
4556 * Actual base address of the view on exit.
4559 * Number of high order address bits that must be zero.
4562 * Size in bytes of the initially committed section of
4566 * Offset in bytes from the beginning of the section
4567 * to the beginning of the view.
4570 * Desired length of map (or zero to map all) on entry
4571 * Actual length mapped on exit.
4573 * InheritDisposition
4574 * Specified how the view is to be shared with
4578 * Type of allocation for the pages.
4581 * Protection for the committed region of the view.
4589 MmMapViewOfSection(IN PVOID SectionObject
,
4590 IN PEPROCESS Process
,
4591 IN OUT PVOID
*BaseAddress
,
4592 IN ULONG_PTR ZeroBits
,
4593 IN SIZE_T CommitSize
,
4594 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4595 IN OUT PSIZE_T ViewSize
,
4596 IN SECTION_INHERIT InheritDisposition
,
4597 IN ULONG AllocationType
,
4600 PROS_SECTION_OBJECT Section
;
4601 PMMSUPPORT AddressSpace
;
4603 NTSTATUS Status
= STATUS_SUCCESS
;
4604 BOOLEAN NotAtBase
= FALSE
;
4606 if ((ULONG_PTR
)SectionObject
& 1)
4608 return MmMapViewOfArm3Section((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4622 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4624 return STATUS_INVALID_PAGE_PROTECTION
;
4628 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4629 AddressSpace
= &Process
->Vm
;
4631 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4633 MmLockAddressSpace(AddressSpace
);
4635 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4639 ULONG_PTR ImageBase
;
4641 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4642 PMM_SECTION_SEGMENT SectionSegments
;
4644 ImageSectionObject
= Section
->ImageSection
;
4645 SectionSegments
= ImageSectionObject
->Segments
;
4646 NrSegments
= ImageSectionObject
->NrSegments
;
4649 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4652 ImageBase
= ImageSectionObject
->ImageBase
;
4656 for (i
= 0; i
< NrSegments
; i
++)
4658 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4660 ULONG_PTR MaxExtent
;
4661 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
+
4662 SectionSegments
[i
].Length
.QuadPart
;
4663 ImageSize
= max(ImageSize
, MaxExtent
);
4667 ImageSectionObject
->ImageSize
= (ULONG
)ImageSize
;
4669 /* Check for an illegal base address */
4670 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4672 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4675 /* Check there is enough space to map the section at that point. */
4676 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4677 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4679 /* Fail if the user requested a fixed base address. */
4680 if ((*BaseAddress
) != NULL
)
4682 MmUnlockAddressSpace(AddressSpace
);
4683 return(STATUS_UNSUCCESSFUL
);
4685 /* Otherwise find a gap to map the image. */
4686 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4689 MmUnlockAddressSpace(AddressSpace
);
4690 return(STATUS_UNSUCCESSFUL
);
4692 /* Remember that we loaded image at a different base address */
4696 for (i
= 0; i
< NrSegments
; i
++)
4698 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4700 PVOID SBaseAddress
= (PVOID
)
4701 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4702 MmLockSectionSegment(&SectionSegments
[i
]);
4703 Status
= MmMapViewOfSegment(AddressSpace
,
4705 &SectionSegments
[i
],
4707 SectionSegments
[i
].Length
.LowPart
,
4708 SectionSegments
[i
].Protection
,
4711 MmUnlockSectionSegment(&SectionSegments
[i
]);
4712 if (!NT_SUCCESS(Status
))
4714 MmUnlockAddressSpace(AddressSpace
);
4720 *BaseAddress
= (PVOID
)ImageBase
;
4721 *ViewSize
= ImageSize
;
4725 /* check for write access */
4726 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4727 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4729 MmUnlockAddressSpace(AddressSpace
);
4730 return STATUS_SECTION_PROTECTION
;
4732 /* check for read access */
4733 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4734 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4736 MmUnlockAddressSpace(AddressSpace
);
4737 return STATUS_SECTION_PROTECTION
;
4739 /* check for execute access */
4740 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4741 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4743 MmUnlockAddressSpace(AddressSpace
);
4744 return STATUS_SECTION_PROTECTION
;
4747 if (ViewSize
== NULL
)
4749 /* Following this pointer would lead to us to the dark side */
4750 /* What to do? Bugcheck? Return status? Do the mambo? */
4751 KeBugCheck(MEMORY_MANAGEMENT
);
4754 if (SectionOffset
== NULL
)
4760 ViewOffset
= SectionOffset
->u
.LowPart
;
4763 if ((ViewOffset
% PAGE_SIZE
) != 0)
4765 MmUnlockAddressSpace(AddressSpace
);
4766 return(STATUS_MAPPED_ALIGNMENT
);
4769 if ((*ViewSize
) == 0)
4771 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4773 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4775 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4778 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4780 MmLockSectionSegment(Section
->Segment
);
4781 Status
= MmMapViewOfSegment(AddressSpace
,
4788 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4789 MmUnlockSectionSegment(Section
->Segment
);
4790 if (!NT_SUCCESS(Status
))
4792 MmUnlockAddressSpace(AddressSpace
);
4797 MmUnlockAddressSpace(AddressSpace
);
4800 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4802 Status
= STATUS_SUCCESS
;
4811 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4812 IN PLARGE_INTEGER NewFileSize
)
4814 /* Check whether an ImageSectionObject exists */
4815 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4817 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4821 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4823 PMM_SECTION_SEGMENT Segment
;
4825 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4828 if (Segment
->ReferenceCount
!= 0)
4831 CC_FILE_SIZES FileSizes
;
4833 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4836 /* Check size of file */
4837 if (SectionObjectPointer
->SharedCacheMap
)
4839 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4844 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4853 /* Check size of file */
4854 if (SectionObjectPointer
->SharedCacheMap
)
4856 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4857 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4866 /* Something must gone wrong
4867 * how can we have a Section but no
4869 DPRINT("ERROR: DataSectionObject without reference!\n");
4873 DPRINT("FIXME: didn't check for outstanding write probes\n");
4885 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4886 IN MMFLUSH_TYPE FlushType
)
4888 BOOLEAN Result
= TRUE
;
4890 PMM_SECTION_SEGMENT Segment
;
4895 case MmFlushForDelete
:
4896 if (SectionObjectPointer
->ImageSectionObject
||
4897 SectionObjectPointer
->DataSectionObject
)
4902 CcRosSetRemoveOnClose(SectionObjectPointer
);
4905 case MmFlushForWrite
:
4907 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4909 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4912 if (SectionObjectPointer
->ImageSectionObject
) {
4913 DPRINT1("SectionObject has ImageSection\n");
4919 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4921 DPRINT("Result %d\n", Result
);
4933 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4934 OUT PVOID
* MappedBase
,
4935 IN OUT PSIZE_T ViewSize
)
4937 PROS_SECTION_OBJECT Section
;
4938 PMMSUPPORT AddressSpace
;
4942 if ((ULONG_PTR
)SectionObject
& 1)
4944 return MiMapViewInSystemSpace((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4950 DPRINT("MmMapViewInSystemSpace() called\n");
4952 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4953 AddressSpace
= MmGetKernelAddressSpace();
4955 MmLockAddressSpace(AddressSpace
);
4958 if ((*ViewSize
) == 0)
4960 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4962 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4964 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4967 MmLockSectionSegment(Section
->Segment
);
4970 Status
= MmMapViewOfSegment(AddressSpace
,
4979 MmUnlockSectionSegment(Section
->Segment
);
4980 MmUnlockAddressSpace(AddressSpace
);
4989 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4991 PMMSUPPORT AddressSpace
;
4994 DPRINT("MmUnmapViewInSystemSpace() called\n");
4996 AddressSpace
= MmGetKernelAddressSpace();
4998 MmLockAddressSpace(AddressSpace
);
5000 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
5002 MmUnlockAddressSpace(AddressSpace
);
5008 /**********************************************************************
5013 * Creates a section object.
5016 * SectionObject (OUT)
5017 * Caller supplied storage for the resulting pointer
5018 * to a SECTION_OBJECT instance;
5021 * Specifies the desired access to the section can be a
5023 * STANDARD_RIGHTS_REQUIRED |
5025 * SECTION_MAP_WRITE |
5026 * SECTION_MAP_READ |
5027 * SECTION_MAP_EXECUTE
5029 * ObjectAttributes [OPTIONAL]
5030 * Initialized attributes for the object can be used
5031 * to create a named section;
5034 * Maximizes the size of the memory section. Must be
5035 * non-NULL for a page-file backed section.
5036 * If value specified for a mapped file and the file is
5037 * not large enough, file will be extended.
5039 * SectionPageProtection
5040 * Can be a combination of:
5046 * AllocationAttributes
5047 * Can be a combination of:
5052 * Handle to a file to create a section mapped to a file
5053 * instead of a memory backed section;
5064 MmCreateSection (OUT PVOID
* Section
,
5065 IN ACCESS_MASK DesiredAccess
,
5066 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
5067 IN PLARGE_INTEGER MaximumSize
,
5068 IN ULONG SectionPageProtection
,
5069 IN ULONG AllocationAttributes
,
5070 IN HANDLE FileHandle OPTIONAL
,
5071 IN PFILE_OBJECT FileObject OPTIONAL
)
5074 ULONG Protection
, FileAccess
;
5075 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
5077 /* Check if an ARM3 section is being created instead */
5078 if (AllocationAttributes
& 1)
5080 DPRINT1("arm 3 path\n");
5081 return MmCreateArm3Section(Section
,
5085 SectionPageProtection
,
5086 AllocationAttributes
&~ 1,
5092 * Check the protection
5094 Protection
= SectionPageProtection
& ~(PAGE_GUARD
| PAGE_NOCACHE
);
5095 if (Protection
!= PAGE_READONLY
&&
5096 Protection
!= PAGE_READWRITE
&&
5097 Protection
!= PAGE_WRITECOPY
&&
5098 Protection
!= PAGE_EXECUTE
&&
5099 Protection
!= PAGE_EXECUTE_READ
&&
5100 Protection
!= PAGE_EXECUTE_READWRITE
&&
5101 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5103 return STATUS_INVALID_PAGE_PROTECTION
;
5106 if ((DesiredAccess
& SECTION_MAP_WRITE
) &&
5107 (Protection
== PAGE_READWRITE
||
5108 Protection
== PAGE_EXECUTE_READWRITE
) &&
5109 !(AllocationAttributes
& SEC_IMAGE
))
5111 DPRINT("Creating a section with WRITE access\n");
5112 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
| SYNCHRONIZE
;
5116 DPRINT("Creating a section with READ access\n");
5117 FileAccess
= FILE_READ_DATA
| SYNCHRONIZE
;
5120 /* FIXME: somehow combine this with the above checks */
5121 if (AllocationAttributes
& SEC_IMAGE
)
5122 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
5124 if (!FileObject
&& FileHandle
)
5126 Status
= ObReferenceObjectByHandle(FileHandle
,
5129 ExGetPreviousMode(),
5130 (PVOID
*)&FileObject
,
5132 if (!NT_SUCCESS(Status
))
5134 DPRINT("Failed: 0x%08lx\n", Status
);
5138 else if (FileObject
)
5139 ObReferenceObject(FileObject
);
5141 #ifndef NEWCC // A hack for initializing caching.
5142 // This is needed only in the old case.
5145 IO_STATUS_BLOCK Iosb
;
5148 LARGE_INTEGER ByteOffset
;
5149 ByteOffset
.QuadPart
= 0;
5150 Status
= ZwReadFile(FileHandle
,
5159 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5161 // Caching is initialized...
5165 if (AllocationAttributes
& SEC_IMAGE
)
5167 Status
= MmCreateImageSection(SectionObject
,
5171 SectionPageProtection
,
5172 AllocationAttributes
,
5176 else if (FileHandle
!= NULL
)
5178 Status
= MmCreateDataFileSection(SectionObject
,
5182 SectionPageProtection
,
5183 AllocationAttributes
,
5186 ObDereferenceObject(FileObject
);
5189 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5191 Status
= MmCreateCacheSection(SectionObject
,
5195 SectionPageProtection
,
5196 AllocationAttributes
,
5202 Status
= MmCreatePageFileSection(SectionObject
,
5206 SectionPageProtection
,
5207 AllocationAttributes
);