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 DPRINT1("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
= FALSE
;
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