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 *****************************************************************/
49 #include "../cache/section/newmm.h"
53 #include <reactos/exeformat.h>
55 #if defined (ALLOC_PRAGMA)
56 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
57 #pragma alloc_text(INIT, MmInitSectionImplementation)
62 MiMapViewInSystemSpace(IN PVOID Section
,
64 OUT PVOID
*MappedBase
,
65 IN OUT PSIZE_T ViewSize
);
69 MmCreateArm3Section(OUT PVOID
*SectionObject
,
70 IN ACCESS_MASK DesiredAccess
,
71 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
72 IN PLARGE_INTEGER InputMaximumSize
,
73 IN ULONG SectionPageProtection
,
74 IN ULONG AllocationAttributes
,
75 IN HANDLE FileHandle OPTIONAL
,
76 IN PFILE_OBJECT FileObject OPTIONAL
);
80 MmMapViewOfArm3Section(IN PVOID SectionObject
,
82 IN OUT PVOID
*BaseAddress
,
83 IN ULONG_PTR ZeroBits
,
85 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
86 IN OUT PSIZE_T ViewSize
,
87 IN SECTION_INHERIT InheritDisposition
,
88 IN ULONG AllocationType
,
92 // PeFmtCreateSection depends on the following:
94 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
95 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
97 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
98 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
99 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
101 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
102 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
103 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
104 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
105 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
106 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
107 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
108 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
109 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
111 /* TYPES *********************************************************************/
115 PROS_SECTION_OBJECT Section
;
116 PMM_SECTION_SEGMENT Segment
;
121 MM_SECTION_PAGEOUT_CONTEXT
;
123 /* GLOBALS *******************************************************************/
125 POBJECT_TYPE MmSectionObjectType
= NULL
;
127 ULONG_PTR MmSubsectionBase
;
129 static ULONG SectionCharacteristicsToProtect
[16] =
131 PAGE_NOACCESS
, /* 0 = NONE */
132 PAGE_NOACCESS
, /* 1 = SHARED */
133 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
134 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
135 PAGE_READONLY
, /* 4 = READABLE */
136 PAGE_READONLY
, /* 5 = READABLE, SHARED */
137 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
138 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
140 * FIXME? do we really need the WriteCopy field in segments? can't we use
141 * PAGE_WRITECOPY here?
143 PAGE_READWRITE
, /* 8 = WRITABLE */
144 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
145 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
146 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
147 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
148 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
149 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
150 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
153 static GENERIC_MAPPING MmpSectionMapping
= {
154 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
155 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
156 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
159 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
160 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
161 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
162 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
163 #define MAX_SHARE_COUNT 0x7FF
164 #define MAKE_SSE(P, C) ((ULONG)(P) | ((C) << 1))
165 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
166 #define MAKE_SWAP_SSE(S) (((ULONG)(S) << 1) | 0x1)
168 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
170 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
171 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
174 /* FUNCTIONS *****************************************************************/
179 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
180 File Format Specification", revision 6.0 (February 1999)
182 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
183 IN SIZE_T FileHeaderSize
,
185 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
187 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
188 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
191 ULONG cbFileHeaderOffsetSize
= 0;
192 ULONG cbSectionHeadersOffset
= 0;
193 ULONG cbSectionHeadersSize
;
194 ULONG cbSectionHeadersOffsetSize
= 0;
195 ULONG cbOptHeaderSize
;
196 ULONG cbHeadersSize
= 0;
197 ULONG nSectionAlignment
;
198 ULONG nFileAlignment
;
199 const IMAGE_DOS_HEADER
* pidhDosHeader
;
200 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
201 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
202 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
203 PMM_SECTION_SEGMENT pssSegments
;
204 LARGE_INTEGER lnOffset
;
206 SIZE_T nPrevVirtualEndOfSegment
= 0;
207 ULONG nFileSizeOfHeaders
= 0;
211 ASSERT(FileHeaderSize
> 0);
213 ASSERT(ImageSectionObject
);
215 ASSERT(AllocateSegmentsCb
);
217 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
219 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
221 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
224 pidhDosHeader
= FileHeader
;
227 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
229 /* image too small to be an MZ executable */
230 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
231 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
233 /* no MZ signature */
234 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
235 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
237 /* not a Windows executable */
238 if(pidhDosHeader
->e_lfanew
<= 0)
239 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
242 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
244 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
245 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
247 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
252 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
253 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
255 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
256 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
260 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
261 * need to read the header from the file
263 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
264 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
266 ULONG cbNtHeaderSize
;
270 l_ReadHeaderFromFile
:
272 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
274 /* read the header from the file */
275 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
277 if(!NT_SUCCESS(nStatus
))
278 DIE(("ReadFile failed, status %08X\n", nStatus
));
282 ASSERT(cbReadSize
> 0);
284 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
286 /* the buffer doesn't contain the file header */
287 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
288 DIE(("The file doesn't contain the PE file header\n"));
290 pinhNtHeader
= pData
;
292 /* object still not aligned: copy it to the beginning of the buffer */
293 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
295 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
296 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
297 pinhNtHeader
= pBuffer
;
300 /* invalid NT header */
301 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
303 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
304 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
306 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
308 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
309 DIE(("The full NT header is too large\n"));
311 /* the buffer doesn't contain the whole NT header */
312 if(cbReadSize
< cbNtHeaderSize
)
313 DIE(("The file doesn't contain the full NT header\n"));
317 ULONG cbOptHeaderOffsetSize
= 0;
319 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
321 /* don't trust an invalid NT header */
322 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
323 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
325 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
326 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
328 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
329 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
331 /* the buffer doesn't contain the whole NT header: read it from the file */
332 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
333 goto l_ReadHeaderFromFile
;
336 /* read information from the NT header */
337 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
338 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
340 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
342 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
343 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
345 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
347 switch(piohOptHeader
->Magic
)
349 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
350 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
354 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
357 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
358 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
360 /* See [1], section 3.4.2 */
361 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
363 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
364 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
366 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
367 DIE(("The section alignment is smaller than the file alignment\n"));
369 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
370 nFileAlignment
= piohOptHeader
->FileAlignment
;
372 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
373 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
377 nSectionAlignment
= PAGE_SIZE
;
378 nFileAlignment
= PAGE_SIZE
;
381 ASSERT(IsPowerOf2(nSectionAlignment
));
382 ASSERT(IsPowerOf2(nFileAlignment
));
384 switch(piohOptHeader
->Magic
)
387 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
389 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
390 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
392 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
393 ImageSectionObject
->ImageSize
= piohOptHeader
->SizeOfImage
;
395 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
396 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
398 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
399 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
405 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
407 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
409 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
411 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
413 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
414 DIE(("ImageBase exceeds the address space\n"));
416 ImageSectionObject
->ImageBase
= (ULONG_PTR
)pioh64OptHeader
->ImageBase
;
419 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
421 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
422 DIE(("SizeOfImage exceeds the address space\n"));
424 ImageSectionObject
->ImageSize
= pioh64OptHeader
->SizeOfImage
;
427 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
429 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
430 DIE(("SizeOfStackReserve exceeds the address space\n"));
432 ImageSectionObject
->StackReserve
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackReserve
;
435 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
437 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
438 DIE(("SizeOfStackCommit exceeds the address space\n"));
440 ImageSectionObject
->StackCommit
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackCommit
;
447 /* [1], section 3.4.2 */
448 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
449 DIE(("ImageBase is not aligned on a 64KB boundary"));
451 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
453 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
455 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
456 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
458 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
459 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
463 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
465 ImageSectionObject
->EntryPoint
= piohOptHeader
->ImageBase
+
466 piohOptHeader
->AddressOfEntryPoint
;
469 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
470 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
472 ImageSectionObject
->Executable
= TRUE
;
474 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
475 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
477 /* SECTION HEADERS */
478 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
480 /* see [1], section 3.3 */
481 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
482 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
485 * the additional segment is for the file's headers. They need to be present for
486 * the benefit of the dynamic loader (to locate exports, defaults for thread
487 * parameters, resources, etc.)
489 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
491 /* file offset for the section headers */
492 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
493 DIE(("Offset overflow\n"));
495 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
496 DIE(("Offset overflow\n"));
498 /* size of the section headers */
499 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
500 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
502 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
503 DIE(("Section headers too large\n"));
505 /* size of the executable's headers */
506 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
508 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
509 // DIE(("SizeOfHeaders is not aligned\n"));
511 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
512 DIE(("The section headers overflow SizeOfHeaders\n"));
514 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
516 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
517 DIE(("Overflow aligning the size of headers\n"));
524 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
525 /* WARNING: piohOptHeader IS NO LONGER USABLE */
526 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
528 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
529 pishSectionHeaders
= NULL
;
533 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
534 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
536 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
537 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
541 * the buffer doesn't contain the section headers, or the alignment is wrong:
542 * read the headers from the file
544 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
545 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
550 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
552 /* read the header from the file */
553 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
555 if(!NT_SUCCESS(nStatus
))
556 DIE(("ReadFile failed with status %08X\n", nStatus
));
560 ASSERT(cbReadSize
> 0);
562 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
564 /* the buffer doesn't contain all the section headers */
565 if(cbReadSize
< cbSectionHeadersSize
)
566 DIE(("The file doesn't contain all of the section headers\n"));
568 pishSectionHeaders
= pData
;
570 /* object still not aligned: copy it to the beginning of the buffer */
571 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
573 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
574 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
575 pishSectionHeaders
= pBuffer
;
580 /* allocate the segments */
581 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
582 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
584 if(ImageSectionObject
->Segments
== NULL
)
585 DIE(("AllocateSegments failed\n"));
587 /* initialize the headers segment */
588 pssSegments
= ImageSectionObject
->Segments
;
590 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
592 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
593 DIE(("Cannot align the size of the section headers\n"));
595 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
596 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
597 DIE(("Cannot align the size of the section headers\n"));
599 pssSegments
[0].FileOffset
= 0;
600 pssSegments
[0].Protection
= PAGE_READONLY
;
601 pssSegments
[0].Length
= nPrevVirtualEndOfSegment
;
602 pssSegments
[0].RawLength
= nFileSizeOfHeaders
;
603 pssSegments
[0].VirtualAddress
= 0;
604 pssSegments
[0].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
605 pssSegments
[0].WriteCopy
= TRUE
;
607 /* skip the headers segment */
610 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
612 /* convert the executable sections into segments. See also [1], section 4 */
613 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
615 ULONG nCharacteristics
;
617 /* validate the alignment */
618 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
619 DIE(("VirtualAddress[%u] is not aligned\n", i
));
621 /* sections must be contiguous, ordered by base address and non-overlapping */
622 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
623 DIE(("Memory gap between section %u and the previous\n", i
));
625 /* ignore explicit BSS sections */
626 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
628 /* validate the alignment */
630 /* Yes, this should be a multiple of FileAlignment, but there's
631 * stuff out there that isn't. We can cope with that
633 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
634 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
637 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
638 // DIE(("PointerToRawData[%u] is not aligned\n", i));
641 pssSegments
[i
].FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
642 pssSegments
[i
].RawLength
= pishSectionHeaders
[i
].SizeOfRawData
;
646 ASSERT(pssSegments
[i
].FileOffset
== 0);
647 ASSERT(pssSegments
[i
].RawLength
== 0);
650 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].FileOffset
, pssSegments
[i
].RawLength
));
652 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
654 /* no explicit protection */
655 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
657 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
658 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
660 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
661 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
663 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
664 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
667 /* see table above */
668 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
669 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
671 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
672 pssSegments
[i
].Length
= pishSectionHeaders
[i
].SizeOfRawData
;
674 pssSegments
[i
].Length
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
676 pssSegments
[i
].Length
= ALIGN_UP_BY(pssSegments
[i
].Length
, nSectionAlignment
);
677 if (pssSegments
[i
].Length
< pssSegments
[i
].Length
)
678 DIE(("Cannot align the virtual size of section %u\n", i
));
680 if(pssSegments
[i
].Length
== 0)
681 DIE(("Virtual size of section %u is null\n", i
));
683 pssSegments
[i
].VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
684 pssSegments
[i
].Characteristics
= pishSectionHeaders
[i
].Characteristics
;
686 /* ensure the memory image is no larger than 4GB */
687 nPrevVirtualEndOfSegment
= pssSegments
[i
].VirtualAddress
+ pssSegments
[i
].Length
;
688 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].VirtualAddress
)
689 DIE(("The image is too large\n"));
692 if(nSectionAlignment
>= PAGE_SIZE
)
693 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
696 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;
705 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
708 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
709 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
710 * RETURNS: Status of the wait.
713 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
715 LARGE_INTEGER Timeout
;
716 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
718 Timeout
.QuadPart
= -100000000LL; // 10 sec
721 Timeout
.QuadPart
= -100000000; // 10 sec
724 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
729 * FUNCTION: Sets the page op completion event and releases the page op.
730 * ARGUMENTS: PMM_PAGEOP.
731 * RETURNS: In shorter time than it takes you to even read this
732 * description, so don't even think about geting a mug of coffee.
735 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
737 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
738 MmReleasePageOp(PageOp
);
743 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
744 * ARGUMENTS: PFILE_OBJECT to wait for.
745 * RETURNS: Status of the wait.
748 MmspWaitForFileLock(PFILE_OBJECT File
)
750 return STATUS_SUCCESS
;
751 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
756 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
759 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
761 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
763 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
765 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
773 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
775 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
777 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
778 PMM_SECTION_SEGMENT SectionSegments
;
782 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
783 NrSegments
= ImageSectionObject
->NrSegments
;
784 SectionSegments
= ImageSectionObject
->Segments
;
785 for (i
= 0; i
< NrSegments
; i
++)
787 if (SectionSegments
[i
].ReferenceCount
!= 0)
789 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
790 SectionSegments
[i
].ReferenceCount
);
791 KeBugCheck(MEMORY_MANAGEMENT
);
793 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
795 ExFreePool(ImageSectionObject
->Segments
);
796 ExFreePool(ImageSectionObject
);
797 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
799 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
801 PMM_SECTION_SEGMENT Segment
;
803 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
806 if (Segment
->ReferenceCount
!= 0)
808 DPRINT1("Data segment still referenced\n");
809 KeBugCheck(MEMORY_MANAGEMENT
);
811 MmFreePageTablesSectionSegment(Segment
);
813 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
819 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
821 ExAcquireFastMutex(&Segment
->Lock
);
826 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
828 ExReleaseFastMutex(&Segment
->Lock
);
833 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
837 PSECTION_PAGE_TABLE Table
;
838 ULONG_PTR DirectoryOffset
;
839 ULONG_PTR TableOffset
;
841 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
843 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
847 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
848 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
852 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
853 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
854 TAG_SECTION_PAGE_TABLE
);
857 KeBugCheck(MEMORY_MANAGEMENT
);
859 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
860 DPRINT("Table %x\n", Table
);
863 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
864 Table
->Entry
[TableOffset
] = (ULONG
)Entry
;
870 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
873 PSECTION_PAGE_TABLE Table
;
875 ULONG_PTR DirectoryOffset
;
876 ULONG_PTR TableOffset
;
878 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
880 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
882 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
886 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
887 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
888 DPRINT("Table %x\n", Table
);
894 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
895 Entry
= Table
->Entry
[TableOffset
];
901 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
906 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
909 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
910 KeBugCheck(MEMORY_MANAGEMENT
);
912 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
914 DPRINT1("Maximum share count reached\n");
915 KeBugCheck(MEMORY_MANAGEMENT
);
917 if (IS_SWAP_FROM_SSE(Entry
))
919 KeBugCheck(MEMORY_MANAGEMENT
);
921 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
922 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
927 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
928 PMM_SECTION_SEGMENT Segment
,
934 BOOLEAN IsDirectMapped
= FALSE
;
936 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
939 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
940 KeBugCheck(MEMORY_MANAGEMENT
);
942 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
944 DPRINT1("Zero share count for unshare\n");
945 KeBugCheck(MEMORY_MANAGEMENT
);
947 if (IS_SWAP_FROM_SSE(Entry
))
949 KeBugCheck(MEMORY_MANAGEMENT
);
951 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
953 * If we reducing the share count of this entry to zero then set the entry
954 * to zero and tell the cache the page is no longer mapped.
956 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
958 PFILE_OBJECT FileObject
;
960 SWAPENTRY SavedSwapEntry
;
962 BOOLEAN IsImageSection
;
965 FileOffset
= Offset
+ Segment
->FileOffset
;
967 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
969 Page
= PFN_FROM_SSE(Entry
);
970 FileObject
= Section
->FileObject
;
971 if (FileObject
!= NULL
&&
972 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
975 if ((FileOffset
% PAGE_SIZE
) == 0 &&
976 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
979 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
980 IsDirectMapped
= TRUE
;
982 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
984 Status
= STATUS_SUCCESS
;
986 if (!NT_SUCCESS(Status
))
988 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
989 KeBugCheck(MEMORY_MANAGEMENT
);
994 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
995 if (SavedSwapEntry
== 0)
998 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
999 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
1003 * Try to page out this page and set the swap entry
1004 * within the section segment. There exist no rmap entry
1005 * for this page. The pager thread can't page out a
1006 * page without a rmap entry.
1008 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1012 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
1013 if (!IsDirectMapped
)
1015 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1021 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1022 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1030 * We hold all locks. Nobody can do something with the current
1031 * process and the current segment (also not within an other process).
1034 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
1035 if (!NT_SUCCESS(Status
))
1037 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
1038 KeBugCheck(MEMORY_MANAGEMENT
);
1041 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
1042 MmSetSavedSwapEntryPage(Page
, 0);
1044 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1048 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1049 KeBugCheck(MEMORY_MANAGEMENT
);
1055 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1057 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1060 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1064 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1067 PCACHE_SEGMENT CacheSeg
;
1068 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1069 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
1072 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
1082 MiCopyFromUserPage(PFN_NUMBER DestPage
, PVOID SourceAddress
)
1088 Process
= PsGetCurrentProcess();
1089 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1090 if (TempAddress
== NULL
)
1092 return(STATUS_NO_MEMORY
);
1094 memcpy(TempAddress
, SourceAddress
, PAGE_SIZE
);
1095 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
1096 return(STATUS_SUCCESS
);
1102 MiReadPage(PMEMORY_AREA MemoryArea
,
1103 ULONG_PTR SegOffset
,
1106 * FUNCTION: Read a page for a section backed memory area.
1108 * MemoryArea - Memory area to read the page for.
1109 * Offset - Offset of the page to read.
1110 * Page - Variable that receives a page contains the read data.
1114 ULONG_PTR FileOffset
;
1117 PCACHE_SEGMENT CacheSeg
;
1118 PFILE_OBJECT FileObject
;
1120 ULONG_PTR RawLength
;
1122 BOOLEAN IsImageSection
;
1125 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1126 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1127 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
1128 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
1129 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1133 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1136 * If the file system is letting us go directly to the cache and the
1137 * memory area was mapped at an offset in the file which is page aligned
1138 * then get the related cache segment.
1140 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1141 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
1142 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1146 * Get the related cache segment; we use a lower level interface than
1147 * filesystems do because it is safe for us to use an offset with a
1148 * alignment less than the file system block size.
1150 Status
= CcRosGetCacheSegment(Bcb
,
1156 if (!NT_SUCCESS(Status
))
1163 * If the cache segment isn't up to date then call the file
1164 * system to read in the data.
1166 Status
= ReadCacheSegment(CacheSeg
);
1167 if (!NT_SUCCESS(Status
))
1169 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1174 * Retrieve the page from the cache segment that we actually want.
1176 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1177 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1179 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1186 ULONG_PTR CacheSegOffset
;
1189 * Allocate a page, this is rather complicated by the possibility
1190 * we might have to move other things out of memory
1192 MI_SET_USAGE(MI_USAGE_SECTION
);
1193 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1194 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1195 if (!NT_SUCCESS(Status
))
1199 Status
= CcRosGetCacheSegment(Bcb
,
1205 if (!NT_SUCCESS(Status
))
1212 * If the cache segment isn't up to date then call the file
1213 * system to read in the data.
1215 Status
= ReadCacheSegment(CacheSeg
);
1216 if (!NT_SUCCESS(Status
))
1218 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1223 Process
= PsGetCurrentProcess();
1224 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1225 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
1226 Length
= RawLength
- SegOffset
;
1227 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1229 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1231 else if (CacheSegOffset
>= PAGE_SIZE
)
1233 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1237 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1238 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1239 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1240 Status
= CcRosGetCacheSegment(Bcb
,
1241 (ULONG
)(FileOffset
+ CacheSegOffset
),
1246 if (!NT_SUCCESS(Status
))
1253 * If the cache segment isn't up to date then call the file
1254 * system to read in the data.
1256 Status
= ReadCacheSegment(CacheSeg
);
1257 if (!NT_SUCCESS(Status
))
1259 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1263 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1264 if (Length
< PAGE_SIZE
)
1266 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1270 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1273 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1274 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1276 return(STATUS_SUCCESS
);
1281 MiReadPage(PMEMORY_AREA MemoryArea
,
1285 * FUNCTION: Read a page for a section backed memory area.
1287 * MemoryArea - Memory area to read the page for.
1288 * Offset - Offset of the page to read.
1289 * Page - Variable that receives a page contains the read data.
1292 MM_REQUIRED_RESOURCES Resources
= { };
1294 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1295 Resources
.FileOffset
.QuadPart
= SegOffset
+
1296 MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
1297 Resources
.Consumer
= MC_USER
;
1298 Resources
.Amount
= PAGE_SIZE
;
1300 DPRINT1("%S, offset %x, len %d, page %x\n", ((PFILE_OBJECT
)Resources
.Context
)->FileName
.Buffer
, Resources
.FileOffset
.LowPart
, Resources
.Amount
, Resources
.Page
[0]);
1302 NTSTATUS Status
= MiReadFilePage(NULL
, NULL
, &Resources
);
1303 *Page
= Resources
.Page
[0];
1310 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1311 MEMORY_AREA
* MemoryArea
,
1317 PROS_SECTION_OBJECT Section
;
1318 PMM_SECTION_SEGMENT Segment
;
1324 BOOLEAN HasSwapEntry
;
1325 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1328 * There is a window between taking the page fault and locking the
1329 * address space when another thread could load the page so we check
1332 if (MmIsPagePresent(Process
, Address
))
1334 return(STATUS_SUCCESS
);
1338 * Check for the virtual memory area being deleted.
1340 if (MemoryArea
->DeleteInProgress
)
1342 return(STATUS_UNSUCCESSFUL
);
1345 Address
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1346 Offset
= (ULONG
)((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1347 + MemoryArea
->Data
.SectionData
.ViewOffset
);
1349 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1350 Section
= MemoryArea
->Data
.SectionData
.Section
;
1351 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1352 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1357 MmLockSectionSegment(Segment
);
1360 * Check if this page needs to be mapped COW
1362 if ((Segment
->WriteCopy
) &&
1363 (Region
->Protect
== PAGE_READWRITE
||
1364 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1366 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1370 Attributes
= Region
->Protect
;
1374 * Get or create a page operation descriptor
1376 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
1379 DPRINT1("MmGetPageOp failed\n");
1380 KeBugCheck(MEMORY_MANAGEMENT
);
1384 * Check if someone else is already handling this fault, if so wait
1387 if (PageOp
->Thread
!= PsGetCurrentThread())
1389 MmUnlockSectionSegment(Segment
);
1390 MmUnlockAddressSpace(AddressSpace
);
1391 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1393 * Check for various strange conditions
1395 if (Status
!= STATUS_SUCCESS
)
1397 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1398 KeBugCheck(MEMORY_MANAGEMENT
);
1400 if (PageOp
->Status
== STATUS_PENDING
)
1402 DPRINT1("Woke for page op before completion\n");
1403 KeBugCheck(MEMORY_MANAGEMENT
);
1405 MmLockAddressSpace(AddressSpace
);
1407 * If this wasn't a pagein then restart the operation
1409 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
1411 MmspCompleteAndReleasePageOp(PageOp
);
1412 DPRINT("Address 0x%.8X\n", Address
);
1413 return(STATUS_MM_RESTART_OPERATION
);
1417 * If the thread handling this fault has failed then we don't retry
1419 if (!NT_SUCCESS(PageOp
->Status
))
1421 Status
= PageOp
->Status
;
1422 MmspCompleteAndReleasePageOp(PageOp
);
1423 DPRINT("Address 0x%.8X\n", Address
);
1426 MmLockSectionSegment(Segment
);
1428 * If the completed fault was for another address space then set the
1431 if (!MmIsPagePresent(Process
, Address
))
1433 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1434 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)Address
);
1436 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
1439 * The page was a private page in another or in our address space
1441 MmUnlockSectionSegment(Segment
);
1442 MmspCompleteAndReleasePageOp(PageOp
);
1443 return(STATUS_MM_RESTART_OPERATION
);
1446 Page
= PFN_FROM_SSE(Entry
);
1448 MmSharePageEntrySectionSegment(Segment
, Offset
);
1450 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
1451 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
1453 Status
= MmCreateVirtualMapping(Process
,
1458 if (!NT_SUCCESS(Status
))
1460 DPRINT1("Unable to create virtual mapping\n");
1461 KeBugCheck(MEMORY_MANAGEMENT
);
1463 MmInsertRmap(Page
, Process
, Address
);
1465 MmUnlockSectionSegment(Segment
);
1466 PageOp
->Status
= STATUS_SUCCESS
;
1467 MmspCompleteAndReleasePageOp(PageOp
);
1468 DPRINT("Address 0x%.8X\n", Address
);
1469 return(STATUS_SUCCESS
);
1472 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1476 * Must be private page we have swapped out.
1478 SWAPENTRY SwapEntry
;
1483 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1485 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1486 KeBugCheck(MEMORY_MANAGEMENT
);
1489 MmUnlockSectionSegment(Segment
);
1490 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1492 MmUnlockAddressSpace(AddressSpace
);
1493 MI_SET_USAGE(MI_USAGE_SECTION
);
1494 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1495 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1496 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1497 if (!NT_SUCCESS(Status
))
1499 KeBugCheck(MEMORY_MANAGEMENT
);
1502 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1503 if (!NT_SUCCESS(Status
))
1505 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1506 KeBugCheck(MEMORY_MANAGEMENT
);
1508 MmLockAddressSpace(AddressSpace
);
1509 Status
= MmCreateVirtualMapping(Process
,
1514 if (!NT_SUCCESS(Status
))
1516 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1517 KeBugCheck(MEMORY_MANAGEMENT
);
1522 * Store the swap entry for later use.
1524 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1527 * Add the page to the process's working set
1529 MmInsertRmap(Page
, Process
, Address
);
1531 * Finish the operation
1533 PageOp
->Status
= STATUS_SUCCESS
;
1534 MmspCompleteAndReleasePageOp(PageOp
);
1535 DPRINT("Address 0x%.8X\n", Address
);
1536 return(STATUS_SUCCESS
);
1540 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1542 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1544 MmUnlockSectionSegment(Segment
);
1546 * Just map the desired physical page
1548 Page
= Offset
>> PAGE_SHIFT
;
1549 Status
= MmCreateVirtualMappingUnsafe(Process
,
1554 if (!NT_SUCCESS(Status
))
1556 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1557 KeBugCheck(MEMORY_MANAGEMENT
);
1562 * Cleanup and release locks
1564 PageOp
->Status
= STATUS_SUCCESS
;
1565 MmspCompleteAndReleasePageOp(PageOp
);
1566 DPRINT("Address 0x%.8X\n", Address
);
1567 return(STATUS_SUCCESS
);
1571 * Map anonymous memory for BSS sections
1573 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1575 MmUnlockSectionSegment(Segment
);
1576 MI_SET_USAGE(MI_USAGE_SECTION
);
1577 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1578 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1579 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1580 if (!NT_SUCCESS(Status
))
1582 MmUnlockAddressSpace(AddressSpace
);
1583 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1584 MmLockAddressSpace(AddressSpace
);
1586 if (!NT_SUCCESS(Status
))
1588 KeBugCheck(MEMORY_MANAGEMENT
);
1590 Status
= MmCreateVirtualMapping(Process
,
1595 if (!NT_SUCCESS(Status
))
1597 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1598 KeBugCheck(MEMORY_MANAGEMENT
);
1601 MmInsertRmap(Page
, Process
, Address
);
1604 * Cleanup and release locks
1606 PageOp
->Status
= STATUS_SUCCESS
;
1607 MmspCompleteAndReleasePageOp(PageOp
);
1608 DPRINT("Address 0x%.8X\n", Address
);
1609 return(STATUS_SUCCESS
);
1613 * Get the entry corresponding to the offset within the section
1615 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1620 * If the entry is zero (and it can't change because we have
1621 * locked the segment) then we need to load the page.
1625 * Release all our locks and read in the page from disk
1627 MmUnlockSectionSegment(Segment
);
1628 MmUnlockAddressSpace(AddressSpace
);
1630 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1631 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1633 MI_SET_USAGE(MI_USAGE_SECTION
);
1634 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1635 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1636 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1637 if (!NT_SUCCESS(Status
))
1639 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1645 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1646 if (!NT_SUCCESS(Status
))
1648 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1651 if (!NT_SUCCESS(Status
))
1654 * FIXME: What do we know in this case?
1657 * Cleanup and release locks
1659 MmLockAddressSpace(AddressSpace
);
1660 PageOp
->Status
= Status
;
1661 MmspCompleteAndReleasePageOp(PageOp
);
1662 DPRINT("Address 0x%.8X\n", Address
);
1666 * Relock the address space and segment
1668 MmLockAddressSpace(AddressSpace
);
1669 MmLockSectionSegment(Segment
);
1672 * Check the entry. No one should change the status of a page
1673 * that has a pending page-in.
1675 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1676 if (Entry
!= Entry1
)
1678 DPRINT1("Someone changed ppte entry while we slept\n");
1679 KeBugCheck(MEMORY_MANAGEMENT
);
1683 * Mark the offset within the section as having valid, in-memory
1686 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1687 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1688 MmUnlockSectionSegment(Segment
);
1690 Status
= MmCreateVirtualMapping(Process
,
1695 if (!NT_SUCCESS(Status
))
1697 DPRINT1("Unable to create virtual mapping\n");
1698 KeBugCheck(MEMORY_MANAGEMENT
);
1700 MmInsertRmap(Page
, Process
, Address
);
1702 PageOp
->Status
= STATUS_SUCCESS
;
1703 MmspCompleteAndReleasePageOp(PageOp
);
1704 DPRINT("Address 0x%.8X\n", Address
);
1705 return(STATUS_SUCCESS
);
1707 else if (IS_SWAP_FROM_SSE(Entry
))
1709 SWAPENTRY SwapEntry
;
1711 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1714 * Release all our locks and read in the page from disk
1716 MmUnlockSectionSegment(Segment
);
1718 MmUnlockAddressSpace(AddressSpace
);
1719 MI_SET_USAGE(MI_USAGE_SECTION
);
1720 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1721 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1722 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1723 if (!NT_SUCCESS(Status
))
1725 KeBugCheck(MEMORY_MANAGEMENT
);
1728 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1729 if (!NT_SUCCESS(Status
))
1731 KeBugCheck(MEMORY_MANAGEMENT
);
1735 * Relock the address space and segment
1737 MmLockAddressSpace(AddressSpace
);
1738 MmLockSectionSegment(Segment
);
1741 * Check the entry. No one should change the status of a page
1742 * that has a pending page-in.
1744 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1745 if (Entry
!= Entry1
)
1747 DPRINT1("Someone changed ppte entry while we slept\n");
1748 KeBugCheck(MEMORY_MANAGEMENT
);
1752 * Mark the offset within the section as having valid, in-memory
1755 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1756 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1757 MmUnlockSectionSegment(Segment
);
1760 * Save the swap entry.
1762 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1763 Status
= MmCreateVirtualMapping(Process
,
1768 if (!NT_SUCCESS(Status
))
1770 DPRINT1("Unable to create virtual mapping\n");
1771 KeBugCheck(MEMORY_MANAGEMENT
);
1773 MmInsertRmap(Page
, Process
, Address
);
1774 PageOp
->Status
= STATUS_SUCCESS
;
1775 MmspCompleteAndReleasePageOp(PageOp
);
1776 DPRINT("Address 0x%.8X\n", Address
);
1777 return(STATUS_SUCCESS
);
1782 * If the section offset is already in-memory and valid then just
1783 * take another reference to the page
1786 Page
= PFN_FROM_SSE(Entry
);
1788 MmSharePageEntrySectionSegment(Segment
, Offset
);
1789 MmUnlockSectionSegment(Segment
);
1791 Status
= MmCreateVirtualMapping(Process
,
1796 if (!NT_SUCCESS(Status
))
1798 DPRINT1("Unable to create virtual mapping\n");
1799 KeBugCheck(MEMORY_MANAGEMENT
);
1801 MmInsertRmap(Page
, Process
, Address
);
1802 PageOp
->Status
= STATUS_SUCCESS
;
1803 MmspCompleteAndReleasePageOp(PageOp
);
1804 DPRINT("Address 0x%.8X\n", Address
);
1805 return(STATUS_SUCCESS
);
1811 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1812 MEMORY_AREA
* MemoryArea
,
1815 PMM_SECTION_SEGMENT Segment
;
1816 PROS_SECTION_OBJECT Section
;
1824 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1826 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
);
1829 * Check if the page has already been set readwrite
1831 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1833 DPRINT("Address 0x%.8X\n", Address
);
1834 return(STATUS_SUCCESS
);
1838 * Find the offset of the page
1840 Address
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1841 Offset
= (ULONG
)((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1842 + MemoryArea
->Data
.SectionData
.ViewOffset
);
1844 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1845 Section
= MemoryArea
->Data
.SectionData
.Section
;
1846 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1847 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1852 MmLockSectionSegment(Segment
);
1854 OldPage
= MmGetPfnForProcess(Process
, Address
);
1855 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1857 MmUnlockSectionSegment(Segment
);
1860 * Check if we are doing COW
1862 if (!((Segment
->WriteCopy
) &&
1863 (Region
->Protect
== PAGE_READWRITE
||
1864 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1866 DPRINT("Address 0x%.8X\n", Address
);
1867 return(STATUS_ACCESS_VIOLATION
);
1870 if (IS_SWAP_FROM_SSE(Entry
) ||
1871 PFN_FROM_SSE(Entry
) != OldPage
)
1873 /* This is a private page. We must only change the page protection. */
1874 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1875 return(STATUS_SUCCESS
);
1879 * Get or create a pageop
1881 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1882 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1885 DPRINT1("MmGetPageOp failed\n");
1886 KeBugCheck(MEMORY_MANAGEMENT
);
1890 * Wait for any other operations to complete
1892 if (PageOp
->Thread
!= PsGetCurrentThread())
1894 MmUnlockAddressSpace(AddressSpace
);
1895 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1897 * Check for various strange conditions
1899 if (Status
== STATUS_TIMEOUT
)
1901 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1902 KeBugCheck(MEMORY_MANAGEMENT
);
1904 if (PageOp
->Status
== STATUS_PENDING
)
1906 DPRINT1("Woke for page op before completion\n");
1907 KeBugCheck(MEMORY_MANAGEMENT
);
1910 * Restart the operation
1912 MmLockAddressSpace(AddressSpace
);
1913 MmspCompleteAndReleasePageOp(PageOp
);
1914 DPRINT("Address 0x%.8X\n", Address
);
1915 return(STATUS_MM_RESTART_OPERATION
);
1919 * Release locks now we have the pageop
1921 MmUnlockAddressSpace(AddressSpace
);
1926 MI_SET_USAGE(MI_USAGE_SECTION
);
1927 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1928 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1929 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1930 if (!NT_SUCCESS(Status
))
1932 KeBugCheck(MEMORY_MANAGEMENT
);
1938 MiCopyFromUserPage(NewPage
, Address
);
1940 MmLockAddressSpace(AddressSpace
);
1942 * Delete the old entry.
1944 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1947 * Set the PTE to point to the new page
1949 Status
= MmCreateVirtualMapping(Process
,
1954 if (!NT_SUCCESS(Status
))
1956 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1957 KeBugCheck(MEMORY_MANAGEMENT
);
1960 if (!NT_SUCCESS(Status
))
1962 DPRINT1("Unable to create virtual mapping\n");
1963 KeBugCheck(MEMORY_MANAGEMENT
);
1967 * Unshare the old page.
1969 MmDeleteRmap(OldPage
, Process
, Address
);
1970 MmInsertRmap(NewPage
, Process
, Address
);
1971 MmLockSectionSegment(Segment
);
1972 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1973 MmUnlockSectionSegment(Segment
);
1975 PageOp
->Status
= STATUS_SUCCESS
;
1976 MmspCompleteAndReleasePageOp(PageOp
);
1977 DPRINT("Address 0x%.8X\n", Address
);
1978 return(STATUS_SUCCESS
);
1982 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1984 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1988 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1991 MmLockAddressSpace(&Process
->Vm
);
1994 MmDeleteVirtualMapping(Process
,
2001 PageOutContext
->WasDirty
= TRUE
;
2003 if (!PageOutContext
->Private
)
2005 MmLockSectionSegment(PageOutContext
->Segment
);
2006 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
2007 PageOutContext
->Segment
,
2008 PageOutContext
->Offset
,
2009 PageOutContext
->WasDirty
,
2011 MmUnlockSectionSegment(PageOutContext
->Segment
);
2015 MmUnlockAddressSpace(&Process
->Vm
);
2018 if (PageOutContext
->Private
)
2020 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2023 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
2028 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
2029 MEMORY_AREA
* MemoryArea
,
2034 MM_SECTION_PAGEOUT_CONTEXT Context
;
2035 SWAPENTRY SwapEntry
;
2039 PFILE_OBJECT FileObject
;
2043 BOOLEAN DirectMapped
;
2044 BOOLEAN IsImageSection
;
2045 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2048 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2051 * Get the segment and section.
2053 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2054 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
2056 Context
.Offset
= (ULONG
)((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2057 + MemoryArea
->Data
.SectionData
.ViewOffset
);
2058 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
2060 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2062 FileObject
= Context
.Section
->FileObject
;
2063 DirectMapped
= FALSE
;
2065 if (FileObject
!= NULL
&&
2066 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2068 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2071 * If the file system is letting us go directly to the cache and the
2072 * memory area was mapped at an offset in the file which is page aligned
2073 * then note this is a direct mapped page.
2075 if ((FileOffset
% PAGE_SIZE
) == 0 &&
2076 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
2078 DirectMapped
= TRUE
;
2085 * This should never happen since mappings of physical memory are never
2086 * placed in the rmap lists.
2088 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2090 DPRINT1("Trying to page out from physical memory section address 0x%X "
2091 "process %d\n", Address
,
2092 Process
? Process
->UniqueProcessId
: 0);
2093 KeBugCheck(MEMORY_MANAGEMENT
);
2097 * Get the section segment entry and the physical address.
2099 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
2100 if (!MmIsPagePresent(Process
, Address
))
2102 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2103 Process
? Process
->UniqueProcessId
: 0, Address
);
2104 KeBugCheck(MEMORY_MANAGEMENT
);
2106 Page
= MmGetPfnForProcess(Process
, Address
);
2107 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2110 * Check the reference count to ensure this page can be paged out
2112 if (MmGetReferenceCountPage(Page
) != 1)
2114 DPRINT("Cannot page out locked section page: 0x%p (RefCount: %d)\n",
2115 Page
, MmGetReferenceCountPage(Page
));
2116 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2117 MmspCompleteAndReleasePageOp(PageOp
);
2118 return STATUS_UNSUCCESSFUL
;
2122 * Prepare the context structure for the rmap delete call.
2124 Context
.WasDirty
= FALSE
;
2125 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2126 IS_SWAP_FROM_SSE(Entry
) ||
2127 PFN_FROM_SSE(Entry
) != Page
)
2129 Context
.Private
= TRUE
;
2133 Context
.Private
= FALSE
;
2137 * Take an additional reference to the page or the cache segment.
2139 if (DirectMapped
&& !Context
.Private
)
2141 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
2143 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2144 KeBugCheck(MEMORY_MANAGEMENT
);
2149 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
2150 MmReferencePage(Page
);
2151 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
2154 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2157 * If this wasn't a private page then we should have reduced the entry to
2158 * zero by deleting all the rmaps.
2160 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
2162 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2163 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2165 KeBugCheck(MEMORY_MANAGEMENT
);
2170 * If the page wasn't dirty then we can just free it as for a readonly page.
2171 * Since we unmapped all the mappings above we know it will not suddenly
2173 * If the page is from a pagefile section and has no swap entry,
2174 * we can't free the page at this point.
2176 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2177 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2179 if (Context
.Private
)
2181 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
2182 Context
.WasDirty
? "dirty" : "clean", Address
);
2183 KeBugCheck(MEMORY_MANAGEMENT
);
2185 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2187 MmSetSavedSwapEntryPage(Page
, 0);
2188 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2189 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2190 PageOp
->Status
= STATUS_SUCCESS
;
2191 MmspCompleteAndReleasePageOp(PageOp
);
2192 return(STATUS_SUCCESS
);
2195 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2197 if (Context
.Private
)
2199 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2200 Context
.WasDirty
? "dirty" : "clean", Address
);
2201 KeBugCheck(MEMORY_MANAGEMENT
);
2203 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2205 MmSetSavedSwapEntryPage(Page
, 0);
2208 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2210 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2211 PageOp
->Status
= STATUS_SUCCESS
;
2212 MmspCompleteAndReleasePageOp(PageOp
);
2213 return(STATUS_SUCCESS
);
2216 else if (!Context
.Private
&& DirectMapped
)
2220 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2222 KeBugCheck(MEMORY_MANAGEMENT
);
2225 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
2227 Status
= STATUS_SUCCESS
;
2229 if (!NT_SUCCESS(Status
))
2231 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2232 KeBugCheck(MEMORY_MANAGEMENT
);
2234 PageOp
->Status
= STATUS_SUCCESS
;
2235 MmspCompleteAndReleasePageOp(PageOp
);
2236 return(STATUS_SUCCESS
);
2238 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2242 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2244 KeBugCheck(MEMORY_MANAGEMENT
);
2246 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2247 PageOp
->Status
= STATUS_SUCCESS
;
2248 MmspCompleteAndReleasePageOp(PageOp
);
2249 return(STATUS_SUCCESS
);
2251 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2253 MmSetSavedSwapEntryPage(Page
, 0);
2254 MmLockAddressSpace(AddressSpace
);
2255 Status
= MmCreatePageFileMapping(Process
,
2258 MmUnlockAddressSpace(AddressSpace
);
2259 if (!NT_SUCCESS(Status
))
2261 KeBugCheck(MEMORY_MANAGEMENT
);
2263 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2264 PageOp
->Status
= STATUS_SUCCESS
;
2265 MmspCompleteAndReleasePageOp(PageOp
);
2266 return(STATUS_SUCCESS
);
2270 * If necessary, allocate an entry in the paging file for this page
2274 SwapEntry
= MmAllocSwapPage();
2277 MmShowOutOfSpaceMessagePagingFile();
2278 MmLockAddressSpace(AddressSpace
);
2280 * For private pages restore the old mappings.
2282 if (Context
.Private
)
2284 Status
= MmCreateVirtualMapping(Process
,
2286 MemoryArea
->Protect
,
2289 MmSetDirtyPage(Process
, Address
);
2297 * For non-private pages if the page wasn't direct mapped then
2298 * set it back into the section segment entry so we don't loose
2299 * our copy. Otherwise it will be handled by the cache manager.
2301 Status
= MmCreateVirtualMapping(Process
,
2303 MemoryArea
->Protect
,
2306 MmSetDirtyPage(Process
, Address
);
2310 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2311 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2313 MmUnlockAddressSpace(AddressSpace
);
2314 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2315 MmspCompleteAndReleasePageOp(PageOp
);
2316 return(STATUS_PAGEFILE_QUOTA
);
2321 * Write the page to the pagefile
2323 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2324 if (!NT_SUCCESS(Status
))
2326 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2329 * As above: undo our actions.
2330 * FIXME: Also free the swap page.
2332 MmLockAddressSpace(AddressSpace
);
2333 if (Context
.Private
)
2335 Status
= MmCreateVirtualMapping(Process
,
2337 MemoryArea
->Protect
,
2340 MmSetDirtyPage(Process
, Address
);
2347 Status
= MmCreateVirtualMapping(Process
,
2349 MemoryArea
->Protect
,
2352 MmSetDirtyPage(Process
, Address
);
2356 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2357 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2359 MmUnlockAddressSpace(AddressSpace
);
2360 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2361 MmspCompleteAndReleasePageOp(PageOp
);
2362 return(STATUS_UNSUCCESSFUL
);
2366 * Otherwise we have succeeded.
2368 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2369 MmSetSavedSwapEntryPage(Page
, 0);
2370 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2371 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2373 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2377 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2380 if (Context
.Private
)
2382 MmLockAddressSpace(AddressSpace
);
2383 Status
= MmCreatePageFileMapping(Process
,
2386 MmUnlockAddressSpace(AddressSpace
);
2387 if (!NT_SUCCESS(Status
))
2389 KeBugCheck(MEMORY_MANAGEMENT
);
2394 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2395 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2398 PageOp
->Status
= STATUS_SUCCESS
;
2399 MmspCompleteAndReleasePageOp(PageOp
);
2400 return(STATUS_SUCCESS
);
2405 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2406 PMEMORY_AREA MemoryArea
,
2411 PROS_SECTION_OBJECT Section
;
2412 PMM_SECTION_SEGMENT Segment
;
2414 SWAPENTRY SwapEntry
;
2418 PFILE_OBJECT FileObject
;
2420 BOOLEAN DirectMapped
;
2421 BOOLEAN IsImageSection
;
2422 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2424 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2426 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2427 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2430 * Get the segment and section.
2432 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2433 Section
= MemoryArea
->Data
.SectionData
.Section
;
2434 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2436 FileObject
= Section
->FileObject
;
2437 DirectMapped
= FALSE
;
2438 if (FileObject
!= NULL
&&
2439 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2441 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2444 * If the file system is letting us go directly to the cache and the
2445 * memory area was mapped at an offset in the file which is page aligned
2446 * then note this is a direct mapped page.
2448 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
2449 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
2451 DirectMapped
= TRUE
;
2456 * This should never happen since mappings of physical memory are never
2457 * placed in the rmap lists.
2459 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2461 DPRINT1("Trying to write back page from physical memory mapped at %X "
2462 "process %d\n", Address
,
2463 Process
? Process
->UniqueProcessId
: 0);
2464 KeBugCheck(MEMORY_MANAGEMENT
);
2468 * Get the section segment entry and the physical address.
2470 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2471 if (!MmIsPagePresent(Process
, Address
))
2473 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2474 Process
? Process
->UniqueProcessId
: 0, Address
);
2475 KeBugCheck(MEMORY_MANAGEMENT
);
2477 Page
= MmGetPfnForProcess(Process
, Address
);
2478 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2481 * Check for a private (COWed) page.
2483 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2484 IS_SWAP_FROM_SSE(Entry
) ||
2485 PFN_FROM_SSE(Entry
) != Page
)
2495 * Speculatively set all mappings of the page to clean.
2497 MmSetCleanAllRmaps(Page
);
2500 * If this page was direct mapped from the cache then the cache manager
2501 * will take care of writing it back to disk.
2503 if (DirectMapped
&& !Private
)
2505 ASSERT(SwapEntry
== 0);
2507 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)Offset
+ Segment
->FileOffset
);
2509 PageOp
->Status
= STATUS_SUCCESS
;
2510 MmspCompleteAndReleasePageOp(PageOp
);
2511 return(STATUS_SUCCESS
);
2515 * If necessary, allocate an entry in the paging file for this page
2519 SwapEntry
= MmAllocSwapPage();
2522 MmSetDirtyAllRmaps(Page
);
2523 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2524 MmspCompleteAndReleasePageOp(PageOp
);
2525 return(STATUS_PAGEFILE_QUOTA
);
2527 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2531 * Write the page to the pagefile
2533 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2534 if (!NT_SUCCESS(Status
))
2536 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2538 MmSetDirtyAllRmaps(Page
);
2539 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2540 MmspCompleteAndReleasePageOp(PageOp
);
2541 return(STATUS_UNSUCCESSFUL
);
2545 * Otherwise we have succeeded.
2547 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2548 PageOp
->Status
= STATUS_SUCCESS
;
2549 MmspCompleteAndReleasePageOp(PageOp
);
2550 return(STATUS_SUCCESS
);
2554 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2562 PMEMORY_AREA MemoryArea
;
2563 PMM_SECTION_SEGMENT Segment
;
2564 BOOLEAN DoCOW
= FALSE
;
2566 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2568 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2570 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2572 if ((Segment
->WriteCopy
) &&
2573 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2578 if (OldProtect
!= NewProtect
)
2580 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2582 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2583 ULONG Protect
= NewProtect
;
2586 * If we doing COW for this segment then check if the page is
2589 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2595 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2596 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2597 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2598 Page
= MmGetPfnForProcess(Process
, Address
);
2600 Protect
= PAGE_READONLY
;
2601 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2602 IS_SWAP_FROM_SSE(Entry
) ||
2603 PFN_FROM_SSE(Entry
) != Page
)
2605 Protect
= NewProtect
;
2609 if (MmIsPagePresent(Process
, Address
))
2611 MmSetPageProtect(Process
, Address
,
2620 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2621 PMEMORY_AREA MemoryArea
,
2629 ULONG_PTR MaxLength
;
2631 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2632 if (Length
> MaxLength
)
2633 Length
= (ULONG
)MaxLength
;
2635 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2636 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2638 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2639 Region
->Protect
!= Protect
)
2641 return STATUS_INVALID_PAGE_PROTECTION
;
2644 *OldProtect
= Region
->Protect
;
2645 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2646 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2647 BaseAddress
, Length
, Region
->Type
, Protect
,
2648 MmAlterViewAttributes
);
2654 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2656 PMEMORY_BASIC_INFORMATION Info
,
2657 PSIZE_T ResultLength
)
2660 PVOID RegionBaseAddress
;
2661 PROS_SECTION_OBJECT Section
;
2662 PMM_SECTION_SEGMENT Segment
;
2664 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2665 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2666 Address
, &RegionBaseAddress
);
2669 return STATUS_UNSUCCESSFUL
;
2672 Section
= MemoryArea
->Data
.SectionData
.Section
;
2673 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2675 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2676 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2677 Info
->Type
= MEM_IMAGE
;
2681 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2682 Info
->Type
= MEM_MAPPED
;
2684 Info
->BaseAddress
= RegionBaseAddress
;
2685 Info
->AllocationProtect
= MemoryArea
->Protect
;
2686 Info
->RegionSize
= Region
->Length
;
2687 Info
->State
= MEM_COMMIT
;
2688 Info
->Protect
= Region
->Protect
;
2690 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2691 return(STATUS_SUCCESS
);
2696 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2701 SWAPENTRY SavedSwapEntry
;
2706 Length
= PAGE_ROUND_UP(Segment
->Length
);
2707 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2709 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2712 if (IS_SWAP_FROM_SSE(Entry
))
2714 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2718 Page
= PFN_FROM_SSE(Entry
);
2719 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2720 if (SavedSwapEntry
!= 0)
2722 MmSetSavedSwapEntryPage(Page
, 0);
2723 MmFreeSwapPage(SavedSwapEntry
);
2725 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2727 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2733 MmpDeleteSection(PVOID ObjectBody
)
2735 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2737 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2738 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2743 PMM_SECTION_SEGMENT SectionSegments
;
2746 * NOTE: Section->ImageSection can be NULL for short time
2747 * during the section creating. If we fail for some reason
2748 * until the image section is properly initialized we shouldn't
2749 * process further here.
2751 if (Section
->ImageSection
== NULL
)
2754 SectionSegments
= Section
->ImageSection
->Segments
;
2755 NrSegments
= Section
->ImageSection
->NrSegments
;
2757 for (i
= 0; i
< NrSegments
; i
++)
2759 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2761 MmLockSectionSegment(&SectionSegments
[i
]);
2763 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2764 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2768 MmpFreePageFileSegment(&SectionSegments
[i
]);
2770 MmUnlockSectionSegment(&SectionSegments
[i
]);
2777 * NOTE: Section->Segment can be NULL for short time
2778 * during the section creating.
2780 if (Section
->Segment
== NULL
)
2783 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2785 MmpFreePageFileSegment(Section
->Segment
);
2786 MmFreePageTablesSectionSegment(Section
->Segment
);
2787 ExFreePool(Section
->Segment
);
2788 Section
->Segment
= NULL
;
2792 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2795 if (Section
->FileObject
!= NULL
)
2798 CcRosDereferenceCache(Section
->FileObject
);
2800 ObDereferenceObject(Section
->FileObject
);
2801 Section
->FileObject
= NULL
;
2806 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2808 IN ACCESS_MASK GrantedAccess
,
2809 IN ULONG ProcessHandleCount
,
2810 IN ULONG SystemHandleCount
)
2812 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2813 Object
, ProcessHandleCount
);
2819 MmCreatePhysicalMemorySection(VOID
)
2821 PROS_SECTION_OBJECT PhysSection
;
2823 OBJECT_ATTRIBUTES Obj
;
2824 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2825 LARGE_INTEGER SectionSize
;
2829 * Create the section mapping physical memory
2831 SectionSize
.QuadPart
= 0xFFFFFFFF;
2832 InitializeObjectAttributes(&Obj
,
2837 Status
= MmCreateSection((PVOID
)&PhysSection
,
2841 PAGE_EXECUTE_READWRITE
,
2845 if (!NT_SUCCESS(Status
))
2847 DPRINT1("Failed to create PhysicalMemory section\n");
2848 KeBugCheck(MEMORY_MANAGEMENT
);
2850 Status
= ObInsertObject(PhysSection
,
2856 if (!NT_SUCCESS(Status
))
2858 ObDereferenceObject(PhysSection
);
2860 ObCloseHandle(Handle
, KernelMode
);
2861 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2862 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2864 return(STATUS_SUCCESS
);
2870 MmInitSectionImplementation(VOID
)
2872 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2873 UNICODE_STRING Name
;
2875 DPRINT("Creating Section Object Type\n");
2877 /* Initialize the Section object type */
2878 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2879 RtlInitUnicodeString(&Name
, L
"Section");
2880 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2881 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2882 ObjectTypeInitializer
.PoolType
= PagedPool
;
2883 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2884 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2885 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2886 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2887 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2888 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2890 MmCreatePhysicalMemorySection();
2892 return(STATUS_SUCCESS
);
2897 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2898 ACCESS_MASK DesiredAccess
,
2899 POBJECT_ATTRIBUTES ObjectAttributes
,
2900 PLARGE_INTEGER UMaximumSize
,
2901 ULONG SectionPageProtection
,
2902 ULONG AllocationAttributes
)
2904 * Create a section which is backed by the pagefile
2907 LARGE_INTEGER MaximumSize
;
2908 PROS_SECTION_OBJECT Section
;
2909 PMM_SECTION_SEGMENT Segment
;
2912 if (UMaximumSize
== NULL
)
2914 return(STATUS_UNSUCCESSFUL
);
2916 MaximumSize
= *UMaximumSize
;
2919 * Create the section
2921 Status
= ObCreateObject(ExGetPreviousMode(),
2922 MmSectionObjectType
,
2924 ExGetPreviousMode(),
2926 sizeof(ROS_SECTION_OBJECT
),
2929 (PVOID
*)(PVOID
)&Section
);
2930 if (!NT_SUCCESS(Status
))
2938 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2939 Section
->SectionPageProtection
= SectionPageProtection
;
2940 Section
->AllocationAttributes
= AllocationAttributes
;
2941 Section
->MaximumSize
= MaximumSize
;
2942 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2943 TAG_MM_SECTION_SEGMENT
);
2944 if (Segment
== NULL
)
2946 ObDereferenceObject(Section
);
2947 return(STATUS_NO_MEMORY
);
2949 Section
->Segment
= Segment
;
2950 Segment
->ReferenceCount
= 1;
2951 ExInitializeFastMutex(&Segment
->Lock
);
2952 Segment
->FileOffset
= 0;
2953 Segment
->Protection
= SectionPageProtection
;
2954 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2955 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2956 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2957 Segment
->WriteCopy
= FALSE
;
2958 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2959 Segment
->VirtualAddress
= 0;
2960 Segment
->Characteristics
= 0;
2961 *SectionObject
= Section
;
2962 return(STATUS_SUCCESS
);
2968 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2969 ACCESS_MASK DesiredAccess
,
2970 POBJECT_ATTRIBUTES ObjectAttributes
,
2971 PLARGE_INTEGER UMaximumSize
,
2972 ULONG SectionPageProtection
,
2973 ULONG AllocationAttributes
,
2976 * Create a section backed by a data file
2979 PROS_SECTION_OBJECT Section
;
2981 LARGE_INTEGER MaximumSize
;
2982 PFILE_OBJECT FileObject
;
2983 PMM_SECTION_SEGMENT Segment
;
2985 IO_STATUS_BLOCK Iosb
;
2986 LARGE_INTEGER Offset
;
2988 FILE_STANDARD_INFORMATION FileInfo
;
2992 * Create the section
2994 Status
= ObCreateObject(ExGetPreviousMode(),
2995 MmSectionObjectType
,
2997 ExGetPreviousMode(),
2999 sizeof(ROS_SECTION_OBJECT
),
3002 (PVOID
*)(PVOID
)&Section
);
3003 if (!NT_SUCCESS(Status
))
3010 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3011 Section
->SectionPageProtection
= SectionPageProtection
;
3012 Section
->AllocationAttributes
= AllocationAttributes
;
3015 * Check file access required
3017 if (SectionPageProtection
& PAGE_READWRITE
||
3018 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3020 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3024 FileAccess
= FILE_READ_DATA
;
3028 * Reference the file handle
3030 Status
= ObReferenceObjectByHandle(FileHandle
,
3033 ExGetPreviousMode(),
3034 (PVOID
*)(PVOID
)&FileObject
,
3036 if (!NT_SUCCESS(Status
))
3038 ObDereferenceObject(Section
);
3043 * FIXME: This is propably not entirely correct. We can't look into
3044 * the standard FCB header because it might not be initialized yet
3045 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
3046 * standard file information is filled on first request).
3048 Status
= IoQueryFileInformation(FileObject
,
3049 FileStandardInformation
,
3050 sizeof(FILE_STANDARD_INFORMATION
),
3053 Iosb
.Information
= Length
;
3054 if (!NT_SUCCESS(Status
))
3056 ObDereferenceObject(Section
);
3057 ObDereferenceObject(FileObject
);
3062 * FIXME: Revise this once a locking order for file size changes is
3065 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
3067 MaximumSize
= *UMaximumSize
;
3071 MaximumSize
= FileInfo
.EndOfFile
;
3072 /* Mapping zero-sized files isn't allowed. */
3073 if (MaximumSize
.QuadPart
== 0)
3075 ObDereferenceObject(Section
);
3076 ObDereferenceObject(FileObject
);
3077 return STATUS_FILE_INVALID
;
3081 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3083 Status
= IoSetInformation(FileObject
,
3084 FileAllocationInformation
,
3085 sizeof(LARGE_INTEGER
),
3087 if (!NT_SUCCESS(Status
))
3089 ObDereferenceObject(Section
);
3090 ObDereferenceObject(FileObject
);
3091 return(STATUS_SECTION_NOT_EXTENDED
);
3095 if (FileObject
->SectionObjectPointer
== NULL
||
3096 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3099 * Read a bit so caching is initiated for the file object.
3100 * This is only needed because MiReadPage currently cannot
3101 * handle non-cached streams.
3103 Offset
.QuadPart
= 0;
3104 Status
= ZwReadFile(FileHandle
,
3113 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3115 ObDereferenceObject(Section
);
3116 ObDereferenceObject(FileObject
);
3119 if (FileObject
->SectionObjectPointer
== NULL
||
3120 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3122 /* FIXME: handle this situation */
3123 ObDereferenceObject(Section
);
3124 ObDereferenceObject(FileObject
);
3125 return STATUS_INVALID_PARAMETER
;
3132 Status
= MmspWaitForFileLock(FileObject
);
3133 if (Status
!= STATUS_SUCCESS
)
3135 ObDereferenceObject(Section
);
3136 ObDereferenceObject(FileObject
);
3141 * If this file hasn't been mapped as a data file before then allocate a
3142 * section segment to describe the data file mapping
3144 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3146 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3147 TAG_MM_SECTION_SEGMENT
);
3148 if (Segment
== NULL
)
3150 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3151 ObDereferenceObject(Section
);
3152 ObDereferenceObject(FileObject
);
3153 return(STATUS_NO_MEMORY
);
3155 Section
->Segment
= Segment
;
3156 Segment
->ReferenceCount
= 1;
3157 ExInitializeFastMutex(&Segment
->Lock
);
3159 * Set the lock before assigning the segment to the file object
3161 ExAcquireFastMutex(&Segment
->Lock
);
3162 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3164 Segment
->FileOffset
= 0;
3165 Segment
->Protection
= SectionPageProtection
;
3166 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3167 Segment
->Characteristics
= 0;
3168 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3169 if (AllocationAttributes
& SEC_RESERVE
)
3171 Segment
->Length
= Segment
->RawLength
= 0;
3175 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3176 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3178 Segment
->VirtualAddress
= 0;
3179 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
3184 * If the file is already mapped as a data file then we may need
3188 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3190 Section
->Segment
= Segment
;
3191 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3192 MmLockSectionSegment(Segment
);
3194 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
3195 !(AllocationAttributes
& SEC_RESERVE
))
3197 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3198 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3201 MmUnlockSectionSegment(Segment
);
3202 Section
->FileObject
= FileObject
;
3203 Section
->MaximumSize
= MaximumSize
;
3205 CcRosReferenceCache(FileObject
);
3207 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3208 *SectionObject
= Section
;
3209 return(STATUS_SUCCESS
);
3213 TODO: not that great (declaring loaders statically, having to declare all of
3214 them, having to keep them extern, etc.), will fix in the future
3216 extern NTSTATUS NTAPI PeFmtCreateSection
3218 IN CONST VOID
* FileHeader
,
3219 IN SIZE_T FileHeaderSize
,
3221 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3223 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3224 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3227 extern NTSTATUS NTAPI ElfFmtCreateSection
3229 IN CONST VOID
* FileHeader
,
3230 IN SIZE_T FileHeaderSize
,
3232 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3234 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3235 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3238 /* TODO: this is a standard DDK/PSDK macro */
3239 #ifndef RTL_NUMBER_OF
3240 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3243 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3254 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3256 SIZE_T SizeOfSegments
;
3257 PMM_SECTION_SEGMENT Segments
;
3259 /* TODO: check for integer overflow */
3260 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3262 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3264 TAG_MM_SECTION_SEGMENT
);
3267 RtlZeroMemory(Segments
, SizeOfSegments
);
3275 ExeFmtpReadFile(IN PVOID File
,
3276 IN PLARGE_INTEGER Offset
,
3279 OUT PVOID
* AllocBase
,
3280 OUT PULONG ReadSize
)
3283 LARGE_INTEGER FileOffset
;
3285 ULONG OffsetAdjustment
;
3290 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3294 KeBugCheck(MEMORY_MANAGEMENT
);
3297 FileOffset
= *Offset
;
3299 /* Negative/special offset: it cannot be used in this context */
3300 if(FileOffset
.u
.HighPart
< 0)
3302 KeBugCheck(MEMORY_MANAGEMENT
);
3305 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3306 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3307 FileOffset
.u
.LowPart
= AdjustOffset
;
3309 BufferSize
= Length
+ OffsetAdjustment
;
3310 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3313 * It's ok to use paged pool, because this is a temporary buffer only used in
3314 * the loading of executables. The assumption is that MmCreateSection is
3315 * always called at low IRQLs and that these buffers don't survive a brief
3316 * initialization phase
3318 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3323 KeBugCheck(MEMORY_MANAGEMENT
);
3329 Status
= MmspPageRead(File
,
3336 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
3337 * nothing will work. But using ZwReadFile is wrong, and using its side effects
3338 * to initialize internal state is even worse. Our cache manager is in need of
3342 IO_STATUS_BLOCK Iosb
;
3344 Status
= ZwReadFile(File
,
3354 if(NT_SUCCESS(Status
))
3356 UsedSize
= (ULONG
)Iosb
.Information
;
3361 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3363 Status
= STATUS_IN_PAGE_ERROR
;
3364 ASSERT(!NT_SUCCESS(Status
));
3367 if(NT_SUCCESS(Status
))
3369 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3370 *AllocBase
= Buffer
;
3371 *ReadSize
= UsedSize
- OffsetAdjustment
;
3375 ExFreePoolWithTag(Buffer
, 'rXmM');
3382 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3383 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3384 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3389 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3393 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3395 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3396 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
3403 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3407 MmspAssertSegmentsSorted(ImageSectionObject
);
3409 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3411 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
3415 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3416 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3417 ImageSectionObject
->Segments
[i
- 1].Length
));
3425 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3429 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3431 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
3432 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
3440 MmspCompareSegments(const void * x
,
3443 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3444 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3447 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
3448 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3452 * Ensures an image section's segments are sorted in memory
3457 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3460 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3462 MmspAssertSegmentsSorted(ImageSectionObject
);
3466 qsort(ImageSectionObject
->Segments
,
3467 ImageSectionObject
->NrSegments
,
3468 sizeof(ImageSectionObject
->Segments
[0]),
3469 MmspCompareSegments
);
3475 * Ensures an image section's segments don't overlap in memory and don't have
3476 * gaps and don't have a null size. We let them map to overlapping file regions,
3477 * though - that's not necessarily an error
3482 MmspCheckSegmentBounds
3484 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3490 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3492 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3496 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3498 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3500 if(ImageSectionObject
->Segments
[i
].Length
== 0)
3508 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3509 * page could be OK (Windows seems to be OK with them), and larger gaps
3510 * could lead to image sections spanning several discontiguous regions
3511 * (NtMapViewOfSection could then refuse to map them, and they could
3512 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3514 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3515 ImageSectionObject
->Segments
[i
- 1].Length
) !=
3516 ImageSectionObject
->Segments
[i
].VirtualAddress
)
3527 * Merges and pads an image section's segments until they all are page-aligned
3528 * and have a size that is a multiple of the page size
3533 MmspPageAlignSegments
3535 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3541 PMM_SECTION_SEGMENT EffectiveSegment
;
3543 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3545 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3550 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3552 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3555 * The first segment requires special handling
3559 ULONG_PTR VirtualAddress
;
3560 ULONG_PTR VirtualOffset
;
3562 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3564 /* Round down the virtual address to the nearest page */
3565 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3567 /* Round up the virtual size to the nearest page */
3568 EffectiveSegment
->Length
= (ULONG
)(PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3569 EffectiveSegment
->VirtualAddress
);
3571 /* Adjust the raw address and size */
3572 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3574 if (EffectiveSegment
->FileOffset
< (LONG_PTR
)VirtualOffset
)
3580 * Garbage in, garbage out: unaligned base addresses make the file
3581 * offset point in curious and odd places, but that's what we were
3584 EffectiveSegment
->FileOffset
-= (ULONG
)VirtualOffset
;
3585 EffectiveSegment
->RawLength
+= (ULONG
)VirtualOffset
;
3589 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3590 ULONG_PTR EndOfEffectiveSegment
;
3592 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3593 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3596 * The current segment begins exactly where the current effective
3597 * segment ended, therefore beginning a new effective segment
3599 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3602 ASSERT(LastSegment
<= i
);
3603 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3605 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3607 if (LastSegment
!= i
)
3610 * Copy the current segment. If necessary, the effective segment
3611 * will be expanded later
3613 *EffectiveSegment
= *Segment
;
3617 * Page-align the virtual size. We know for sure the virtual address
3620 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3621 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3624 * The current segment is still part of the current effective segment:
3625 * extend the effective segment to reflect this
3627 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3629 static const ULONG FlagsToProtection
[16] =
3637 PAGE_EXECUTE_READWRITE
,
3638 PAGE_EXECUTE_READWRITE
,
3643 PAGE_EXECUTE_WRITECOPY
,
3644 PAGE_EXECUTE_WRITECOPY
,
3645 PAGE_EXECUTE_WRITECOPY
,
3646 PAGE_EXECUTE_WRITECOPY
3649 unsigned ProtectionFlags
;
3652 * Extend the file size
3655 /* Unaligned segments must be contiguous within the file */
3656 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3657 EffectiveSegment
->RawLength
))
3662 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3665 * Extend the virtual size
3667 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3669 EffectiveSegment
->Length
= (ULONG
)(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3670 EffectiveSegment
->VirtualAddress
);
3673 * Merge the protection
3675 EffectiveSegment
->Protection
|= Segment
->Protection
;
3677 /* Clean up redundance */
3678 ProtectionFlags
= 0;
3680 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3681 ProtectionFlags
|= 1 << 0;
3683 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3684 ProtectionFlags
|= 1 << 1;
3686 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3687 ProtectionFlags
|= 1 << 2;
3689 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3690 ProtectionFlags
|= 1 << 3;
3692 ASSERT(ProtectionFlags
< 16);
3693 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3695 /* If a segment was required to be shared and cannot, fail */
3696 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3697 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3703 * We assume no holes between segments at this point
3707 KeBugCheck(MEMORY_MANAGEMENT
);
3711 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3717 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3718 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3720 LARGE_INTEGER Offset
;
3722 PVOID FileHeaderBuffer
;
3723 ULONG FileHeaderSize
;
3725 ULONG OldNrSegments
;
3730 * Read the beginning of the file (2 pages). Should be enough to contain
3731 * all (or most) of the headers
3733 Offset
.QuadPart
= 0;
3735 /* FIXME: use FileObject instead of FileHandle */
3736 Status
= ExeFmtpReadFile (FileHandle
,
3743 if (!NT_SUCCESS(Status
))
3746 if (FileHeaderSize
== 0)
3748 ExFreePool(FileHeaderBuffer
);
3749 return STATUS_UNSUCCESSFUL
;
3753 * Look for a loader that can handle this executable
3755 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3757 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3760 /* FIXME: use FileObject instead of FileHandle */
3761 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3767 ExeFmtpAllocateSegments
);
3769 if (!NT_SUCCESS(Status
))
3771 if (ImageSectionObject
->Segments
)
3773 ExFreePool(ImageSectionObject
->Segments
);
3774 ImageSectionObject
->Segments
= NULL
;
3778 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3782 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3785 * No loader handled the format
3787 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3789 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3790 ASSERT(!NT_SUCCESS(Status
));
3793 if (!NT_SUCCESS(Status
))
3796 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3801 /* FIXME? are these values platform-dependent? */
3802 if(ImageSectionObject
->StackReserve
== 0)
3803 ImageSectionObject
->StackReserve
= 0x40000;
3805 if(ImageSectionObject
->StackCommit
== 0)
3806 ImageSectionObject
->StackCommit
= 0x1000;
3808 if(ImageSectionObject
->ImageBase
== 0)
3810 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3811 ImageSectionObject
->ImageBase
= 0x10000000;
3813 ImageSectionObject
->ImageBase
= 0x00400000;
3817 * And now the fun part: fixing the segments
3820 /* Sort them by virtual address */
3821 MmspSortSegments(ImageSectionObject
, Flags
);
3823 /* Ensure they don't overlap in memory */
3824 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3825 return STATUS_INVALID_IMAGE_FORMAT
;
3827 /* Ensure they are aligned */
3828 OldNrSegments
= ImageSectionObject
->NrSegments
;
3830 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3831 return STATUS_INVALID_IMAGE_FORMAT
;
3833 /* Trim them if the alignment phase merged some of them */
3834 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3836 PMM_SECTION_SEGMENT Segments
;
3837 SIZE_T SizeOfSegments
;
3839 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3841 Segments
= ExAllocatePoolWithTag(PagedPool
,
3843 TAG_MM_SECTION_SEGMENT
);
3845 if (Segments
== NULL
)
3846 return STATUS_INSUFFICIENT_RESOURCES
;
3848 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3849 ExFreePool(ImageSectionObject
->Segments
);
3850 ImageSectionObject
->Segments
= Segments
;
3853 /* And finish their initialization */
3854 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3856 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3857 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3859 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3860 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3863 ASSERT(NT_SUCCESS(Status
));
3868 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3869 ACCESS_MASK DesiredAccess
,
3870 POBJECT_ATTRIBUTES ObjectAttributes
,
3871 PLARGE_INTEGER UMaximumSize
,
3872 ULONG SectionPageProtection
,
3873 ULONG AllocationAttributes
,
3876 PROS_SECTION_OBJECT Section
;
3878 PFILE_OBJECT FileObject
;
3879 PMM_SECTION_SEGMENT SectionSegments
;
3880 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3882 ULONG FileAccess
= 0;
3885 * Check file access required
3887 if (SectionPageProtection
& PAGE_READWRITE
||
3888 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3890 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3894 FileAccess
= FILE_READ_DATA
;
3898 * Reference the file handle
3900 Status
= ObReferenceObjectByHandle(FileHandle
,
3903 ExGetPreviousMode(),
3904 (PVOID
*)(PVOID
)&FileObject
,
3907 if (!NT_SUCCESS(Status
))
3913 * Create the section
3915 Status
= ObCreateObject (ExGetPreviousMode(),
3916 MmSectionObjectType
,
3918 ExGetPreviousMode(),
3920 sizeof(ROS_SECTION_OBJECT
),
3923 (PVOID
*)(PVOID
)&Section
);
3924 if (!NT_SUCCESS(Status
))
3926 ObDereferenceObject(FileObject
);
3933 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3934 Section
->SectionPageProtection
= SectionPageProtection
;
3935 Section
->AllocationAttributes
= AllocationAttributes
;
3939 * Initialized caching for this file object if previously caching
3940 * was initialized for the same on disk file
3942 Status
= CcTryToInitializeFileCache(FileObject
);
3944 Status
= STATUS_SUCCESS
;
3947 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3949 NTSTATUS StatusExeFmt
;
3951 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3952 if (ImageSectionObject
== NULL
)
3954 ObDereferenceObject(FileObject
);
3955 ObDereferenceObject(Section
);
3956 return(STATUS_NO_MEMORY
);
3959 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3961 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3963 if (!NT_SUCCESS(StatusExeFmt
))
3965 if(ImageSectionObject
->Segments
!= NULL
)
3966 ExFreePool(ImageSectionObject
->Segments
);
3968 ExFreePool(ImageSectionObject
);
3969 ObDereferenceObject(Section
);
3970 ObDereferenceObject(FileObject
);
3971 return(StatusExeFmt
);
3974 Section
->ImageSection
= ImageSectionObject
;
3975 ASSERT(ImageSectionObject
->Segments
);
3980 Status
= MmspWaitForFileLock(FileObject
);
3981 if (!NT_SUCCESS(Status
))
3983 ExFreePool(ImageSectionObject
->Segments
);
3984 ExFreePool(ImageSectionObject
);
3985 ObDereferenceObject(Section
);
3986 ObDereferenceObject(FileObject
);
3990 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3991 ImageSectionObject
, NULL
))
3994 * An other thread has initialized the same image in the background
3996 ExFreePool(ImageSectionObject
->Segments
);
3997 ExFreePool(ImageSectionObject
);
3998 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3999 Section
->ImageSection
= ImageSectionObject
;
4000 SectionSegments
= ImageSectionObject
->Segments
;
4002 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
4004 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
4008 Status
= StatusExeFmt
;
4015 Status
= MmspWaitForFileLock(FileObject
);
4016 if (Status
!= STATUS_SUCCESS
)
4018 ObDereferenceObject(Section
);
4019 ObDereferenceObject(FileObject
);
4023 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
4024 Section
->ImageSection
= ImageSectionObject
;
4025 SectionSegments
= ImageSectionObject
->Segments
;
4028 * Otherwise just reference all the section segments
4030 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
4032 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
4035 Status
= STATUS_SUCCESS
;
4037 Section
->FileObject
= FileObject
;
4039 CcRosReferenceCache(FileObject
);
4041 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
4042 *SectionObject
= Section
;
4049 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
4050 PROS_SECTION_OBJECT Section
,
4051 PMM_SECTION_SEGMENT Segment
,
4056 ULONG AllocationType
)
4060 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4062 if (Segment
->WriteCopy
)
4064 /* We have to do this because the not present fault
4065 * and access fault handlers depend on the protection
4066 * that should be granted AFTER the COW fault takes
4067 * place to be in Region->Protect. The not present fault
4068 * handler changes this to the correct protection for COW when
4069 * mapping the pages into the process's address space. If a COW
4070 * fault takes place, the access fault handler sets the page protection
4071 * to these values for the newly copied pages
4073 if (Protect
== PAGE_WRITECOPY
)
4074 Protect
= PAGE_READWRITE
;
4075 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
4076 Protect
= PAGE_EXECUTE_READWRITE
;
4079 BoundaryAddressMultiple
.QuadPart
= 0;
4081 Status
= MmCreateMemoryArea(AddressSpace
,
4082 MEMORY_AREA_SECTION_VIEW
,
4089 BoundaryAddressMultiple
);
4090 if (!NT_SUCCESS(Status
))
4092 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
4093 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
4097 ObReferenceObject((PVOID
)Section
);
4099 MArea
->Data
.SectionData
.Segment
= Segment
;
4100 MArea
->Data
.SectionData
.Section
= Section
;
4101 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
4102 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
4103 ViewSize
, 0, Protect
);
4105 return(STATUS_SUCCESS
);
4111 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
4112 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4115 PFILE_OBJECT FileObject
;
4118 SWAPENTRY SavedSwapEntry
;
4121 PROS_SECTION_OBJECT Section
;
4122 PMM_SECTION_SEGMENT Segment
;
4123 PMMSUPPORT AddressSpace
;
4126 AddressSpace
= (PMMSUPPORT
)Context
;
4127 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4129 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4131 Offset
= (ULONG
)(((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
4132 MemoryArea
->Data
.SectionData
.ViewOffset
);
4134 Section
= MemoryArea
->Data
.SectionData
.Section
;
4135 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4137 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4141 MmUnlockSectionSegment(Segment
);
4142 MmUnlockAddressSpace(AddressSpace
);
4144 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4145 if (Status
!= STATUS_SUCCESS
)
4147 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4148 KeBugCheck(MEMORY_MANAGEMENT
);
4151 MmLockAddressSpace(AddressSpace
);
4152 MmLockSectionSegment(Segment
);
4153 MmspCompleteAndReleasePageOp(PageOp
);
4154 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4157 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
4160 * For a dirty, datafile, non-private page mark it as dirty in the
4163 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4165 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4167 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4168 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4170 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
4172 ASSERT(SwapEntry
== 0);
4181 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4183 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4184 KeBugCheck(MEMORY_MANAGEMENT
);
4186 MmFreeSwapPage(SwapEntry
);
4190 if (IS_SWAP_FROM_SSE(Entry
) ||
4191 Page
!= PFN_FROM_SSE(Entry
))
4196 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4198 DPRINT1("Found a private page in a pagefile section.\n");
4199 KeBugCheck(MEMORY_MANAGEMENT
);
4202 * Just dereference private pages
4204 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4205 if (SavedSwapEntry
!= 0)
4207 MmFreeSwapPage(SavedSwapEntry
);
4208 MmSetSavedSwapEntryPage(Page
, 0);
4210 MmDeleteRmap(Page
, Process
, Address
);
4211 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4215 MmDeleteRmap(Page
, Process
, Address
);
4216 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4222 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4226 PMEMORY_AREA MemoryArea
;
4227 PROS_SECTION_OBJECT Section
;
4228 PMM_SECTION_SEGMENT Segment
;
4229 PLIST_ENTRY CurrentEntry
;
4230 PMM_REGION CurrentRegion
;
4231 PLIST_ENTRY RegionListHead
;
4233 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4235 if (MemoryArea
== NULL
)
4237 return(STATUS_UNSUCCESSFUL
);
4240 MemoryArea
->DeleteInProgress
= TRUE
;
4241 Section
= MemoryArea
->Data
.SectionData
.Section
;
4242 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4244 MmLockSectionSegment(Segment
);
4246 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4247 while (!IsListEmpty(RegionListHead
))
4249 CurrentEntry
= RemoveHeadList(RegionListHead
);
4250 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4251 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4254 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4256 Status
= MmFreeMemoryArea(AddressSpace
,
4263 Status
= MmFreeMemoryArea(AddressSpace
,
4268 MmUnlockSectionSegment(Segment
);
4269 ObDereferenceObject(Section
);
4277 MmUnmapViewOfSection(PEPROCESS Process
,
4281 PMEMORY_AREA MemoryArea
;
4282 PMMSUPPORT AddressSpace
;
4283 PROS_SECTION_OBJECT Section
;
4286 PVOID ImageBaseAddress
= 0;
4288 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4289 Process
, BaseAddress
);
4293 AddressSpace
= &Process
->Vm
;
4295 MmLockAddressSpace(AddressSpace
);
4296 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4298 if (MemoryArea
== NULL
||
4299 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4300 MemoryArea
->DeleteInProgress
)
4302 MmUnlockAddressSpace(AddressSpace
);
4303 return STATUS_NOT_MAPPED_VIEW
;
4306 MemoryArea
->DeleteInProgress
= TRUE
;
4308 while (MemoryArea
->PageOpCount
)
4310 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4314 Offset
-= PAGE_SIZE
;
4315 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4316 MemoryArea
->Data
.SectionData
.Segment
,
4317 (ULONG
)Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4320 MmUnlockAddressSpace(AddressSpace
);
4321 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4322 if (Status
!= STATUS_SUCCESS
)
4324 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4325 KeBugCheck(MEMORY_MANAGEMENT
);
4327 MmLockAddressSpace(AddressSpace
);
4328 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4330 if (MemoryArea
== NULL
||
4331 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4333 MmUnlockAddressSpace(AddressSpace
);
4334 return STATUS_NOT_MAPPED_VIEW
;
4341 Section
= MemoryArea
->Data
.SectionData
.Section
;
4343 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4347 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4348 PMM_SECTION_SEGMENT SectionSegments
;
4349 PMM_SECTION_SEGMENT Segment
;
4351 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4352 ImageSectionObject
= Section
->ImageSection
;
4353 SectionSegments
= ImageSectionObject
->Segments
;
4354 NrSegments
= ImageSectionObject
->NrSegments
;
4356 /* Search for the current segment within the section segments
4357 * and calculate the image base address */
4358 for (i
= 0; i
< NrSegments
; i
++)
4360 if (Segment
== &SectionSegments
[i
])
4362 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4366 if (i
>= NrSegments
)
4368 KeBugCheck(MEMORY_MANAGEMENT
);
4371 for (i
= 0; i
< NrSegments
; i
++)
4373 PVOID SBaseAddress
= (PVOID
)
4374 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4376 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4381 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4384 MmUnlockAddressSpace(AddressSpace
);
4386 /* Notify debugger */
4387 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4389 return(STATUS_SUCCESS
);
4396 * Queries the information of a section object.
4398 * @param SectionHandle
4399 * Handle to the section object. It must be opened with SECTION_QUERY
4401 * @param SectionInformationClass
4402 * Index to a certain information structure. Can be either
4403 * SectionBasicInformation or SectionImageInformation. The latter
4404 * is valid only for sections that were created with the SEC_IMAGE
4406 * @param SectionInformation
4407 * Caller supplies storage for resulting information.
4409 * Size of the supplied storage.
4410 * @param ResultLength
4418 NtQuerySection(IN HANDLE SectionHandle
,
4419 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4420 OUT PVOID SectionInformation
,
4421 IN SIZE_T SectionInformationLength
,
4422 OUT PSIZE_T ResultLength OPTIONAL
)
4424 PROS_SECTION_OBJECT Section
;
4425 KPROCESSOR_MODE PreviousMode
;
4429 PreviousMode
= ExGetPreviousMode();
4431 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4433 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4435 (ULONG
)SectionInformationLength
,
4440 if(!NT_SUCCESS(Status
))
4442 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4446 Status
= ObReferenceObjectByHandle(SectionHandle
,
4448 MmSectionObjectType
,
4450 (PVOID
*)(PVOID
)&Section
,
4452 if (NT_SUCCESS(Status
))
4454 switch (SectionInformationClass
)
4456 case SectionBasicInformation
:
4458 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4462 Sbi
->Attributes
= Section
->AllocationAttributes
;
4463 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4465 Sbi
->BaseAddress
= 0;
4466 Sbi
->Size
.QuadPart
= 0;
4470 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4471 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4474 if (ResultLength
!= NULL
)
4476 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4478 Status
= STATUS_SUCCESS
;
4480 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4482 Status
= _SEH2_GetExceptionCode();
4489 case SectionImageInformation
:
4491 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4495 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4496 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4498 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4499 ImageSectionObject
= Section
->ImageSection
;
4501 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4502 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4503 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4504 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4505 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4506 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4507 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4508 Sii
->Machine
= ImageSectionObject
->Machine
;
4509 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4512 if (ResultLength
!= NULL
)
4514 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4516 Status
= STATUS_SUCCESS
;
4518 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4520 Status
= _SEH2_GetExceptionCode();
4528 ObDereferenceObject(Section
);
4534 /**********************************************************************
4536 * MmMapViewOfSection
4539 * Maps a view of a section into the virtual address space of a
4544 * Pointer to the section object.
4547 * Pointer to the process.
4550 * Desired base address (or NULL) on entry;
4551 * Actual base address of the view on exit.
4554 * Number of high order address bits that must be zero.
4557 * Size in bytes of the initially committed section of
4561 * Offset in bytes from the beginning of the section
4562 * to the beginning of the view.
4565 * Desired length of map (or zero to map all) on entry
4566 * Actual length mapped on exit.
4568 * InheritDisposition
4569 * Specified how the view is to be shared with
4573 * Type of allocation for the pages.
4576 * Protection for the committed region of the view.
4584 MmMapViewOfSection(IN PVOID SectionObject
,
4585 IN PEPROCESS Process
,
4586 IN OUT PVOID
*BaseAddress
,
4587 IN ULONG_PTR ZeroBits
,
4588 IN SIZE_T CommitSize
,
4589 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4590 IN OUT PSIZE_T ViewSize
,
4591 IN SECTION_INHERIT InheritDisposition
,
4592 IN ULONG AllocationType
,
4595 PROS_SECTION_OBJECT Section
;
4596 PMMSUPPORT AddressSpace
;
4598 NTSTATUS Status
= STATUS_SUCCESS
;
4599 BOOLEAN NotAtBase
= FALSE
;
4601 if ((ULONG_PTR
)SectionObject
& 1)
4603 return MmMapViewOfArm3Section((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4617 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4619 return STATUS_INVALID_PAGE_PROTECTION
;
4623 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4624 AddressSpace
= &Process
->Vm
;
4626 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4628 MmLockAddressSpace(AddressSpace
);
4630 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4634 ULONG_PTR ImageBase
;
4636 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4637 PMM_SECTION_SEGMENT SectionSegments
;
4639 ImageSectionObject
= Section
->ImageSection
;
4640 SectionSegments
= ImageSectionObject
->Segments
;
4641 NrSegments
= ImageSectionObject
->NrSegments
;
4644 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4647 ImageBase
= ImageSectionObject
->ImageBase
;
4651 for (i
= 0; i
< NrSegments
; i
++)
4653 ULONG_PTR MaxExtent
;
4654 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4655 SectionSegments
[i
].Length
;
4656 ImageSize
= max(ImageSize
, MaxExtent
);
4659 ImageSectionObject
->ImageSize
= (ULONG
)ImageSize
;
4661 /* Check for an illegal base address */
4662 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4664 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4667 /* Check there is enough space to map the section at that point. */
4668 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4669 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4671 /* Fail if the user requested a fixed base address. */
4672 if ((*BaseAddress
) != NULL
)
4674 MmUnlockAddressSpace(AddressSpace
);
4675 return(STATUS_UNSUCCESSFUL
);
4677 /* Otherwise find a gap to map the image. */
4678 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4681 MmUnlockAddressSpace(AddressSpace
);
4682 return(STATUS_UNSUCCESSFUL
);
4684 /* Remember that we loaded image at a different base address */
4688 for (i
= 0; i
< NrSegments
; i
++)
4690 PVOID SBaseAddress
= (PVOID
)
4691 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4692 MmLockSectionSegment(&SectionSegments
[i
]);
4693 Status
= MmMapViewOfSegment(AddressSpace
,
4695 &SectionSegments
[i
],
4697 SectionSegments
[i
].Length
,
4698 SectionSegments
[i
].Protection
,
4701 MmUnlockSectionSegment(&SectionSegments
[i
]);
4702 if (!NT_SUCCESS(Status
))
4704 MmUnlockAddressSpace(AddressSpace
);
4709 *BaseAddress
= (PVOID
)ImageBase
;
4710 *ViewSize
= ImageSize
;
4714 /* check for write access */
4715 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4716 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4718 MmUnlockAddressSpace(AddressSpace
);
4719 return STATUS_SECTION_PROTECTION
;
4721 /* check for read access */
4722 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4723 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4725 MmUnlockAddressSpace(AddressSpace
);
4726 return STATUS_SECTION_PROTECTION
;
4728 /* check for execute access */
4729 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4730 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4732 MmUnlockAddressSpace(AddressSpace
);
4733 return STATUS_SECTION_PROTECTION
;
4736 if (ViewSize
== NULL
)
4738 /* Following this pointer would lead to us to the dark side */
4739 /* What to do? Bugcheck? Return status? Do the mambo? */
4740 KeBugCheck(MEMORY_MANAGEMENT
);
4743 if (SectionOffset
== NULL
)
4749 ViewOffset
= SectionOffset
->u
.LowPart
;
4752 if ((ViewOffset
% PAGE_SIZE
) != 0)
4754 MmUnlockAddressSpace(AddressSpace
);
4755 return(STATUS_MAPPED_ALIGNMENT
);
4758 if ((*ViewSize
) == 0)
4760 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4762 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4764 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4767 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4769 MmLockSectionSegment(Section
->Segment
);
4770 Status
= MmMapViewOfSegment(AddressSpace
,
4777 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4778 MmUnlockSectionSegment(Section
->Segment
);
4779 if (!NT_SUCCESS(Status
))
4781 MmUnlockAddressSpace(AddressSpace
);
4786 MmUnlockAddressSpace(AddressSpace
);
4789 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4791 Status
= STATUS_SUCCESS
;
4800 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4801 IN PLARGE_INTEGER NewFileSize
)
4803 /* Check whether an ImageSectionObject exists */
4804 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4806 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4810 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4812 PMM_SECTION_SEGMENT Segment
;
4814 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4817 if (Segment
->ReferenceCount
!= 0)
4819 /* Check size of file */
4820 if (SectionObjectPointer
->SharedCacheMap
)
4822 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4823 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4831 /* Something must gone wrong
4832 * how can we have a Section but no
4834 DPRINT("ERROR: DataSectionObject without reference!\n");
4838 DPRINT("FIXME: didn't check for outstanding write probes\n");
4850 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4851 IN MMFLUSH_TYPE FlushType
)
4855 case MmFlushForDelete
:
4856 if (SectionObjectPointer
->ImageSectionObject
||
4857 SectionObjectPointer
->DataSectionObject
)
4862 CcRosSetRemoveOnClose(SectionObjectPointer
);
4865 case MmFlushForWrite
:
4875 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4876 OUT PVOID
* MappedBase
,
4877 IN OUT PSIZE_T ViewSize
)
4879 PROS_SECTION_OBJECT Section
;
4880 PMMSUPPORT AddressSpace
;
4884 if ((ULONG_PTR
)SectionObject
& 1)
4886 extern PVOID MmSession
;
4887 return MiMapViewInSystemSpace((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4893 DPRINT("MmMapViewInSystemSpace() called\n");
4895 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4896 AddressSpace
= MmGetKernelAddressSpace();
4898 MmLockAddressSpace(AddressSpace
);
4901 if ((*ViewSize
) == 0)
4903 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4905 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4907 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4910 MmLockSectionSegment(Section
->Segment
);
4913 Status
= MmMapViewOfSegment(AddressSpace
,
4922 MmUnlockSectionSegment(Section
->Segment
);
4923 MmUnlockAddressSpace(AddressSpace
);
4932 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4934 PMMSUPPORT AddressSpace
;
4937 DPRINT("MmUnmapViewInSystemSpace() called\n");
4939 AddressSpace
= MmGetKernelAddressSpace();
4941 MmLockAddressSpace(AddressSpace
);
4943 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4945 MmUnlockAddressSpace(AddressSpace
);
4951 /**********************************************************************
4956 * Creates a section object.
4959 * SectionObject (OUT)
4960 * Caller supplied storage for the resulting pointer
4961 * to a SECTION_OBJECT instance;
4964 * Specifies the desired access to the section can be a
4966 * STANDARD_RIGHTS_REQUIRED |
4968 * SECTION_MAP_WRITE |
4969 * SECTION_MAP_READ |
4970 * SECTION_MAP_EXECUTE
4972 * ObjectAttributes [OPTIONAL]
4973 * Initialized attributes for the object can be used
4974 * to create a named section;
4977 * Maximizes the size of the memory section. Must be
4978 * non-NULL for a page-file backed section.
4979 * If value specified for a mapped file and the file is
4980 * not large enough, file will be extended.
4982 * SectionPageProtection
4983 * Can be a combination of:
4989 * AllocationAttributes
4990 * Can be a combination of:
4995 * Handle to a file to create a section mapped to a file
4996 * instead of a memory backed section;
5007 MmCreateSection (OUT PVOID
* Section
,
5008 IN ACCESS_MASK DesiredAccess
,
5009 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
5010 IN PLARGE_INTEGER MaximumSize
,
5011 IN ULONG SectionPageProtection
,
5012 IN ULONG AllocationAttributes
,
5013 IN HANDLE FileHandle OPTIONAL
,
5014 IN PFILE_OBJECT File OPTIONAL
)
5017 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
5019 /* Check if an ARM3 section is being created instead */
5020 if (AllocationAttributes
& 1)
5022 DPRINT1("arm 3 path\n");
5023 return MmCreateArm3Section(Section
,
5027 SectionPageProtection
,
5028 AllocationAttributes
&~ 1,
5034 * Check the protection
5036 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
5037 if (Protection
!= PAGE_READONLY
&&
5038 Protection
!= PAGE_READWRITE
&&
5039 Protection
!= PAGE_WRITECOPY
&&
5040 Protection
!= PAGE_EXECUTE
&&
5041 Protection
!= PAGE_EXECUTE_READ
&&
5042 Protection
!= PAGE_EXECUTE_READWRITE
&&
5043 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5045 return STATUS_INVALID_PAGE_PROTECTION
;
5048 if (AllocationAttributes
& SEC_IMAGE
)
5050 return(MmCreateImageSection(SectionObject
,
5054 SectionPageProtection
,
5055 AllocationAttributes
,
5059 if (FileHandle
!= NULL
)
5061 return(MmCreateDataFileSection(SectionObject
,
5065 SectionPageProtection
,
5066 AllocationAttributes
,
5070 return(MmCreatePageFileSection(SectionObject
,
5074 SectionPageProtection
,
5075 AllocationAttributes
));