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
,
1318 PROS_SECTION_OBJECT Section
;
1319 PMM_SECTION_SEGMENT Segment
;
1325 BOOLEAN HasSwapEntry
;
1326 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1329 * There is a window between taking the page fault and locking the
1330 * address space when another thread could load the page so we check
1333 if (MmIsPagePresent(Process
, Address
))
1335 return(STATUS_SUCCESS
);
1339 * Check for the virtual memory area being deleted.
1341 if (MemoryArea
->DeleteInProgress
)
1343 return(STATUS_UNSUCCESSFUL
);
1346 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1347 Offset
= (ULONG
)((ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1348 + MemoryArea
->Data
.SectionData
.ViewOffset
);
1350 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1351 Section
= MemoryArea
->Data
.SectionData
.Section
;
1352 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1353 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1358 MmLockSectionSegment(Segment
);
1361 * Check if this page needs to be mapped COW
1363 if ((Segment
->WriteCopy
) &&
1364 (Region
->Protect
== PAGE_READWRITE
||
1365 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1367 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1371 Attributes
= Region
->Protect
;
1375 * Get or create a page operation descriptor
1377 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
1380 DPRINT1("MmGetPageOp failed\n");
1381 KeBugCheck(MEMORY_MANAGEMENT
);
1385 * Check if someone else is already handling this fault, if so wait
1388 if (PageOp
->Thread
!= PsGetCurrentThread())
1390 MmUnlockSectionSegment(Segment
);
1391 MmUnlockAddressSpace(AddressSpace
);
1392 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1394 * Check for various strange conditions
1396 if (Status
!= STATUS_SUCCESS
)
1398 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1399 KeBugCheck(MEMORY_MANAGEMENT
);
1401 if (PageOp
->Status
== STATUS_PENDING
)
1403 DPRINT1("Woke for page op before completion\n");
1404 KeBugCheck(MEMORY_MANAGEMENT
);
1406 MmLockAddressSpace(AddressSpace
);
1408 * If this wasn't a pagein then restart the operation
1410 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
1412 MmspCompleteAndReleasePageOp(PageOp
);
1413 DPRINT("Address 0x%.8X\n", Address
);
1414 return(STATUS_MM_RESTART_OPERATION
);
1418 * If the thread handling this fault has failed then we don't retry
1420 if (!NT_SUCCESS(PageOp
->Status
))
1422 Status
= PageOp
->Status
;
1423 MmspCompleteAndReleasePageOp(PageOp
);
1424 DPRINT("Address 0x%.8X\n", Address
);
1427 MmLockSectionSegment(Segment
);
1429 * If the completed fault was for another address space then set the
1432 if (!MmIsPagePresent(Process
, Address
))
1434 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1435 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1437 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
1440 * The page was a private page in another or in our address space
1442 MmUnlockSectionSegment(Segment
);
1443 MmspCompleteAndReleasePageOp(PageOp
);
1444 return(STATUS_MM_RESTART_OPERATION
);
1447 Page
= PFN_FROM_SSE(Entry
);
1449 MmSharePageEntrySectionSegment(Segment
, Offset
);
1451 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
1452 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
1454 Status
= MmCreateVirtualMapping(Process
,
1459 if (!NT_SUCCESS(Status
))
1461 DPRINT1("Unable to create virtual mapping\n");
1462 KeBugCheck(MEMORY_MANAGEMENT
);
1464 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1466 MmUnlockSectionSegment(Segment
);
1467 PageOp
->Status
= STATUS_SUCCESS
;
1468 MmspCompleteAndReleasePageOp(PageOp
);
1469 DPRINT("Address 0x%.8X\n", Address
);
1470 return(STATUS_SUCCESS
);
1473 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1477 * Must be private page we have swapped out.
1479 SWAPENTRY SwapEntry
;
1484 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1486 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1487 KeBugCheck(MEMORY_MANAGEMENT
);
1490 MmUnlockSectionSegment(Segment
);
1491 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
1493 MmUnlockAddressSpace(AddressSpace
);
1494 MI_SET_USAGE(MI_USAGE_SECTION
);
1495 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1496 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1497 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1498 if (!NT_SUCCESS(Status
))
1500 KeBugCheck(MEMORY_MANAGEMENT
);
1503 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1504 if (!NT_SUCCESS(Status
))
1506 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1507 KeBugCheck(MEMORY_MANAGEMENT
);
1509 MmLockAddressSpace(AddressSpace
);
1510 Status
= MmCreateVirtualMapping(Process
,
1515 if (!NT_SUCCESS(Status
))
1517 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1518 KeBugCheck(MEMORY_MANAGEMENT
);
1523 * Store the swap entry for later use.
1525 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1528 * Add the page to the process's working set
1530 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1533 * Finish the operation
1535 PageOp
->Status
= STATUS_SUCCESS
;
1536 MmspCompleteAndReleasePageOp(PageOp
);
1537 DPRINT("Address 0x%.8X\n", Address
);
1538 return(STATUS_SUCCESS
);
1542 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1544 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1546 MmUnlockSectionSegment(Segment
);
1548 * Just map the desired physical page
1550 Page
= Offset
>> PAGE_SHIFT
;
1551 Status
= MmCreateVirtualMappingUnsafe(Process
,
1556 if (!NT_SUCCESS(Status
))
1558 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1559 KeBugCheck(MEMORY_MANAGEMENT
);
1564 * Cleanup and release locks
1566 PageOp
->Status
= STATUS_SUCCESS
;
1567 MmspCompleteAndReleasePageOp(PageOp
);
1568 DPRINT("Address 0x%.8X\n", Address
);
1569 return(STATUS_SUCCESS
);
1573 * Map anonymous memory for BSS sections
1575 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1577 MmUnlockSectionSegment(Segment
);
1578 MI_SET_USAGE(MI_USAGE_SECTION
);
1579 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1580 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1581 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1582 if (!NT_SUCCESS(Status
))
1584 MmUnlockAddressSpace(AddressSpace
);
1585 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1586 MmLockAddressSpace(AddressSpace
);
1588 if (!NT_SUCCESS(Status
))
1590 KeBugCheck(MEMORY_MANAGEMENT
);
1592 Status
= MmCreateVirtualMapping(Process
,
1597 if (!NT_SUCCESS(Status
))
1599 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1600 KeBugCheck(MEMORY_MANAGEMENT
);
1603 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1606 * Cleanup and release locks
1608 PageOp
->Status
= STATUS_SUCCESS
;
1609 MmspCompleteAndReleasePageOp(PageOp
);
1610 DPRINT("Address 0x%.8X\n", Address
);
1611 return(STATUS_SUCCESS
);
1615 * Get the entry corresponding to the offset within the section
1617 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1622 * If the entry is zero (and it can't change because we have
1623 * locked the segment) then we need to load the page.
1627 * Release all our locks and read in the page from disk
1629 MmUnlockSectionSegment(Segment
);
1630 MmUnlockAddressSpace(AddressSpace
);
1632 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1633 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1635 MI_SET_USAGE(MI_USAGE_SECTION
);
1636 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1637 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1638 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1639 if (!NT_SUCCESS(Status
))
1641 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1647 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1648 if (!NT_SUCCESS(Status
))
1650 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1653 if (!NT_SUCCESS(Status
))
1656 * FIXME: What do we know in this case?
1659 * Cleanup and release locks
1661 MmLockAddressSpace(AddressSpace
);
1662 PageOp
->Status
= Status
;
1663 MmspCompleteAndReleasePageOp(PageOp
);
1664 DPRINT("Address 0x%.8X\n", Address
);
1668 * Relock the address space and segment
1670 MmLockAddressSpace(AddressSpace
);
1671 MmLockSectionSegment(Segment
);
1674 * Check the entry. No one should change the status of a page
1675 * that has a pending page-in.
1677 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1678 if (Entry
!= Entry1
)
1680 DPRINT1("Someone changed ppte entry while we slept\n");
1681 KeBugCheck(MEMORY_MANAGEMENT
);
1685 * Mark the offset within the section as having valid, in-memory
1688 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1689 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1690 MmUnlockSectionSegment(Segment
);
1692 Status
= MmCreateVirtualMapping(Process
,
1697 if (!NT_SUCCESS(Status
))
1699 DPRINT1("Unable to create virtual mapping\n");
1700 KeBugCheck(MEMORY_MANAGEMENT
);
1702 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1704 PageOp
->Status
= STATUS_SUCCESS
;
1705 MmspCompleteAndReleasePageOp(PageOp
);
1706 DPRINT("Address 0x%.8X\n", Address
);
1707 return(STATUS_SUCCESS
);
1709 else if (IS_SWAP_FROM_SSE(Entry
))
1711 SWAPENTRY SwapEntry
;
1713 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1716 * Release all our locks and read in the page from disk
1718 MmUnlockSectionSegment(Segment
);
1720 MmUnlockAddressSpace(AddressSpace
);
1721 MI_SET_USAGE(MI_USAGE_SECTION
);
1722 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1723 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1724 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1725 if (!NT_SUCCESS(Status
))
1727 KeBugCheck(MEMORY_MANAGEMENT
);
1730 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1731 if (!NT_SUCCESS(Status
))
1733 KeBugCheck(MEMORY_MANAGEMENT
);
1737 * Relock the address space and segment
1739 MmLockAddressSpace(AddressSpace
);
1740 MmLockSectionSegment(Segment
);
1743 * Check the entry. No one should change the status of a page
1744 * that has a pending page-in.
1746 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1747 if (Entry
!= Entry1
)
1749 DPRINT1("Someone changed ppte entry while we slept\n");
1750 KeBugCheck(MEMORY_MANAGEMENT
);
1754 * Mark the offset within the section as having valid, in-memory
1757 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1758 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1759 MmUnlockSectionSegment(Segment
);
1762 * Save the swap entry.
1764 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1765 Status
= MmCreateVirtualMapping(Process
,
1770 if (!NT_SUCCESS(Status
))
1772 DPRINT1("Unable to create virtual mapping\n");
1773 KeBugCheck(MEMORY_MANAGEMENT
);
1775 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1776 PageOp
->Status
= STATUS_SUCCESS
;
1777 MmspCompleteAndReleasePageOp(PageOp
);
1778 DPRINT("Address 0x%.8X\n", Address
);
1779 return(STATUS_SUCCESS
);
1784 * If the section offset is already in-memory and valid then just
1785 * take another reference to the page
1788 Page
= PFN_FROM_SSE(Entry
);
1790 MmSharePageEntrySectionSegment(Segment
, Offset
);
1791 MmUnlockSectionSegment(Segment
);
1793 Status
= MmCreateVirtualMapping(Process
,
1798 if (!NT_SUCCESS(Status
))
1800 DPRINT1("Unable to create virtual mapping\n");
1801 KeBugCheck(MEMORY_MANAGEMENT
);
1803 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1804 PageOp
->Status
= STATUS_SUCCESS
;
1805 MmspCompleteAndReleasePageOp(PageOp
);
1806 DPRINT("Address 0x%.8X\n", Address
);
1807 return(STATUS_SUCCESS
);
1813 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1814 MEMORY_AREA
* MemoryArea
,
1817 PMM_SECTION_SEGMENT Segment
;
1818 PROS_SECTION_OBJECT Section
;
1827 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1829 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
);
1832 * Check if the page has already been set readwrite
1834 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1836 DPRINT("Address 0x%.8X\n", Address
);
1837 return(STATUS_SUCCESS
);
1841 * Find the offset of the page
1843 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1844 Offset
= (ULONG
)((ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1845 + MemoryArea
->Data
.SectionData
.ViewOffset
);
1847 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1848 Section
= MemoryArea
->Data
.SectionData
.Section
;
1849 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1850 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1855 MmLockSectionSegment(Segment
);
1857 OldPage
= MmGetPfnForProcess(Process
, Address
);
1858 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1860 MmUnlockSectionSegment(Segment
);
1863 * Check if we are doing COW
1865 if (!((Segment
->WriteCopy
) &&
1866 (Region
->Protect
== PAGE_READWRITE
||
1867 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1869 DPRINT("Address 0x%.8X\n", Address
);
1870 return(STATUS_ACCESS_VIOLATION
);
1873 if (IS_SWAP_FROM_SSE(Entry
) ||
1874 PFN_FROM_SSE(Entry
) != OldPage
)
1876 /* This is a private page. We must only change the page protection. */
1877 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1878 return(STATUS_SUCCESS
);
1882 * Get or create a pageop
1884 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1885 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1888 DPRINT1("MmGetPageOp failed\n");
1889 KeBugCheck(MEMORY_MANAGEMENT
);
1893 * Wait for any other operations to complete
1895 if (PageOp
->Thread
!= PsGetCurrentThread())
1897 MmUnlockAddressSpace(AddressSpace
);
1898 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1900 * Check for various strange conditions
1902 if (Status
== STATUS_TIMEOUT
)
1904 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1905 KeBugCheck(MEMORY_MANAGEMENT
);
1907 if (PageOp
->Status
== STATUS_PENDING
)
1909 DPRINT1("Woke for page op before completion\n");
1910 KeBugCheck(MEMORY_MANAGEMENT
);
1913 * Restart the operation
1915 MmLockAddressSpace(AddressSpace
);
1916 MmspCompleteAndReleasePageOp(PageOp
);
1917 DPRINT("Address 0x%.8X\n", Address
);
1918 return(STATUS_MM_RESTART_OPERATION
);
1922 * Release locks now we have the pageop
1924 MmUnlockAddressSpace(AddressSpace
);
1929 MI_SET_USAGE(MI_USAGE_SECTION
);
1930 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1931 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1932 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1933 if (!NT_SUCCESS(Status
))
1935 KeBugCheck(MEMORY_MANAGEMENT
);
1941 MiCopyFromUserPage(NewPage
, PAddress
);
1943 MmLockAddressSpace(AddressSpace
);
1945 * Delete the old entry.
1947 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1950 * Set the PTE to point to the new page
1952 Status
= MmCreateVirtualMapping(Process
,
1957 if (!NT_SUCCESS(Status
))
1959 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1960 KeBugCheck(MEMORY_MANAGEMENT
);
1963 if (!NT_SUCCESS(Status
))
1965 DPRINT1("Unable to create virtual mapping\n");
1966 KeBugCheck(MEMORY_MANAGEMENT
);
1970 * Unshare the old page.
1972 MmDeleteRmap(OldPage
, Process
, PAddress
);
1973 MmInsertRmap(NewPage
, Process
, PAddress
);
1974 MmLockSectionSegment(Segment
);
1975 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1976 MmUnlockSectionSegment(Segment
);
1978 PageOp
->Status
= STATUS_SUCCESS
;
1979 MmspCompleteAndReleasePageOp(PageOp
);
1980 DPRINT("Address 0x%.8X\n", Address
);
1981 return(STATUS_SUCCESS
);
1985 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1987 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1991 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1994 MmLockAddressSpace(&Process
->Vm
);
1997 MmDeleteVirtualMapping(Process
,
2004 PageOutContext
->WasDirty
= TRUE
;
2006 if (!PageOutContext
->Private
)
2008 MmLockSectionSegment(PageOutContext
->Segment
);
2009 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
2010 PageOutContext
->Segment
,
2011 PageOutContext
->Offset
,
2012 PageOutContext
->WasDirty
,
2014 MmUnlockSectionSegment(PageOutContext
->Segment
);
2018 MmUnlockAddressSpace(&Process
->Vm
);
2021 if (PageOutContext
->Private
)
2023 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2026 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
2031 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
2032 MEMORY_AREA
* MemoryArea
,
2037 MM_SECTION_PAGEOUT_CONTEXT Context
;
2038 SWAPENTRY SwapEntry
;
2042 PFILE_OBJECT FileObject
;
2046 BOOLEAN DirectMapped
;
2047 BOOLEAN IsImageSection
;
2048 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2051 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2054 * Get the segment and section.
2056 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2057 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
2059 Context
.Offset
= (ULONG
)((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2060 + MemoryArea
->Data
.SectionData
.ViewOffset
);
2061 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
2063 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2065 FileObject
= Context
.Section
->FileObject
;
2066 DirectMapped
= FALSE
;
2068 if (FileObject
!= NULL
&&
2069 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2071 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2074 * If the file system is letting us go directly to the cache and the
2075 * memory area was mapped at an offset in the file which is page aligned
2076 * then note this is a direct mapped page.
2078 if ((FileOffset
% PAGE_SIZE
) == 0 &&
2079 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
2081 DirectMapped
= TRUE
;
2088 * This should never happen since mappings of physical memory are never
2089 * placed in the rmap lists.
2091 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2093 DPRINT1("Trying to page out from physical memory section address 0x%X "
2094 "process %d\n", Address
,
2095 Process
? Process
->UniqueProcessId
: 0);
2096 KeBugCheck(MEMORY_MANAGEMENT
);
2100 * Get the section segment entry and the physical address.
2102 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
2103 if (!MmIsPagePresent(Process
, Address
))
2105 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2106 Process
? Process
->UniqueProcessId
: 0, Address
);
2107 KeBugCheck(MEMORY_MANAGEMENT
);
2109 Page
= MmGetPfnForProcess(Process
, Address
);
2110 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2113 * Prepare the context structure for the rmap delete call.
2115 Context
.WasDirty
= FALSE
;
2116 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2117 IS_SWAP_FROM_SSE(Entry
) ||
2118 PFN_FROM_SSE(Entry
) != Page
)
2120 Context
.Private
= TRUE
;
2124 Context
.Private
= FALSE
;
2128 * Take an additional reference to the page or the cache segment.
2130 if (DirectMapped
&& !Context
.Private
)
2132 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
2134 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2135 KeBugCheck(MEMORY_MANAGEMENT
);
2140 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
2141 MmReferencePage(Page
);
2142 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
2145 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2148 * If this wasn't a private page then we should have reduced the entry to
2149 * zero by deleting all the rmaps.
2151 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
2153 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2154 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2156 KeBugCheck(MEMORY_MANAGEMENT
);
2161 * If the page wasn't dirty then we can just free it as for a readonly page.
2162 * Since we unmapped all the mappings above we know it will not suddenly
2164 * If the page is from a pagefile section and has no swap entry,
2165 * we can't free the page at this point.
2167 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2168 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2170 if (Context
.Private
)
2172 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
2173 Context
.WasDirty
? "dirty" : "clean", Address
);
2174 KeBugCheck(MEMORY_MANAGEMENT
);
2176 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2178 MmSetSavedSwapEntryPage(Page
, 0);
2179 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2180 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2181 PageOp
->Status
= STATUS_SUCCESS
;
2182 MmspCompleteAndReleasePageOp(PageOp
);
2183 return(STATUS_SUCCESS
);
2186 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2188 if (Context
.Private
)
2190 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2191 Context
.WasDirty
? "dirty" : "clean", Address
);
2192 KeBugCheck(MEMORY_MANAGEMENT
);
2194 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2196 MmSetSavedSwapEntryPage(Page
, 0);
2199 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2201 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2202 PageOp
->Status
= STATUS_SUCCESS
;
2203 MmspCompleteAndReleasePageOp(PageOp
);
2204 return(STATUS_SUCCESS
);
2207 else if (!Context
.Private
&& DirectMapped
)
2211 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2213 KeBugCheck(MEMORY_MANAGEMENT
);
2216 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
2218 Status
= STATUS_SUCCESS
;
2220 if (!NT_SUCCESS(Status
))
2222 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2223 KeBugCheck(MEMORY_MANAGEMENT
);
2225 PageOp
->Status
= STATUS_SUCCESS
;
2226 MmspCompleteAndReleasePageOp(PageOp
);
2227 return(STATUS_SUCCESS
);
2229 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2233 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2235 KeBugCheck(MEMORY_MANAGEMENT
);
2237 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2238 PageOp
->Status
= STATUS_SUCCESS
;
2239 MmspCompleteAndReleasePageOp(PageOp
);
2240 return(STATUS_SUCCESS
);
2242 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2244 MmSetSavedSwapEntryPage(Page
, 0);
2245 MmLockAddressSpace(AddressSpace
);
2246 Status
= MmCreatePageFileMapping(Process
,
2249 MmUnlockAddressSpace(AddressSpace
);
2250 if (!NT_SUCCESS(Status
))
2252 KeBugCheck(MEMORY_MANAGEMENT
);
2254 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2255 PageOp
->Status
= STATUS_SUCCESS
;
2256 MmspCompleteAndReleasePageOp(PageOp
);
2257 return(STATUS_SUCCESS
);
2261 * If necessary, allocate an entry in the paging file for this page
2265 SwapEntry
= MmAllocSwapPage();
2268 MmShowOutOfSpaceMessagePagingFile();
2269 MmLockAddressSpace(AddressSpace
);
2271 * For private pages restore the old mappings.
2273 if (Context
.Private
)
2275 Status
= MmCreateVirtualMapping(Process
,
2277 MemoryArea
->Protect
,
2280 MmSetDirtyPage(Process
, Address
);
2288 * For non-private pages if the page wasn't direct mapped then
2289 * set it back into the section segment entry so we don't loose
2290 * our copy. Otherwise it will be handled by the cache manager.
2292 Status
= MmCreateVirtualMapping(Process
,
2294 MemoryArea
->Protect
,
2297 MmSetDirtyPage(Process
, Address
);
2301 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2302 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2304 MmUnlockAddressSpace(AddressSpace
);
2305 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2306 MmspCompleteAndReleasePageOp(PageOp
);
2307 return(STATUS_PAGEFILE_QUOTA
);
2312 * Write the page to the pagefile
2314 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2315 if (!NT_SUCCESS(Status
))
2317 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2320 * As above: undo our actions.
2321 * FIXME: Also free the swap page.
2323 MmLockAddressSpace(AddressSpace
);
2324 if (Context
.Private
)
2326 Status
= MmCreateVirtualMapping(Process
,
2328 MemoryArea
->Protect
,
2331 MmSetDirtyPage(Process
, Address
);
2338 Status
= MmCreateVirtualMapping(Process
,
2340 MemoryArea
->Protect
,
2343 MmSetDirtyPage(Process
, Address
);
2347 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2348 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2350 MmUnlockAddressSpace(AddressSpace
);
2351 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2352 MmspCompleteAndReleasePageOp(PageOp
);
2353 return(STATUS_UNSUCCESSFUL
);
2357 * Otherwise we have succeeded.
2359 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2360 MmSetSavedSwapEntryPage(Page
, 0);
2361 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2362 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2364 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2368 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2371 if (Context
.Private
)
2373 MmLockAddressSpace(AddressSpace
);
2374 Status
= MmCreatePageFileMapping(Process
,
2377 MmUnlockAddressSpace(AddressSpace
);
2378 if (!NT_SUCCESS(Status
))
2380 KeBugCheck(MEMORY_MANAGEMENT
);
2385 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2386 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2389 PageOp
->Status
= STATUS_SUCCESS
;
2390 MmspCompleteAndReleasePageOp(PageOp
);
2391 return(STATUS_SUCCESS
);
2396 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2397 PMEMORY_AREA MemoryArea
,
2402 PROS_SECTION_OBJECT Section
;
2403 PMM_SECTION_SEGMENT Segment
;
2405 SWAPENTRY SwapEntry
;
2409 PFILE_OBJECT FileObject
;
2411 BOOLEAN DirectMapped
;
2412 BOOLEAN IsImageSection
;
2413 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2415 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2417 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2418 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2421 * Get the segment and section.
2423 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2424 Section
= MemoryArea
->Data
.SectionData
.Section
;
2425 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2427 FileObject
= Section
->FileObject
;
2428 DirectMapped
= FALSE
;
2429 if (FileObject
!= NULL
&&
2430 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2432 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2435 * If the file system is letting us go directly to the cache and the
2436 * memory area was mapped at an offset in the file which is page aligned
2437 * then note this is a direct mapped page.
2439 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
2440 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
2442 DirectMapped
= TRUE
;
2447 * This should never happen since mappings of physical memory are never
2448 * placed in the rmap lists.
2450 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2452 DPRINT1("Trying to write back page from physical memory mapped at %X "
2453 "process %d\n", Address
,
2454 Process
? Process
->UniqueProcessId
: 0);
2455 KeBugCheck(MEMORY_MANAGEMENT
);
2459 * Get the section segment entry and the physical address.
2461 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2462 if (!MmIsPagePresent(Process
, Address
))
2464 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2465 Process
? Process
->UniqueProcessId
: 0, Address
);
2466 KeBugCheck(MEMORY_MANAGEMENT
);
2468 Page
= MmGetPfnForProcess(Process
, Address
);
2469 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2472 * Check for a private (COWed) page.
2474 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2475 IS_SWAP_FROM_SSE(Entry
) ||
2476 PFN_FROM_SSE(Entry
) != Page
)
2486 * Speculatively set all mappings of the page to clean.
2488 MmSetCleanAllRmaps(Page
);
2491 * If this page was direct mapped from the cache then the cache manager
2492 * will take care of writing it back to disk.
2494 if (DirectMapped
&& !Private
)
2496 ASSERT(SwapEntry
== 0);
2498 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)Offset
+ Segment
->FileOffset
);
2500 PageOp
->Status
= STATUS_SUCCESS
;
2501 MmspCompleteAndReleasePageOp(PageOp
);
2502 return(STATUS_SUCCESS
);
2506 * If necessary, allocate an entry in the paging file for this page
2510 SwapEntry
= MmAllocSwapPage();
2513 MmSetDirtyAllRmaps(Page
);
2514 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2515 MmspCompleteAndReleasePageOp(PageOp
);
2516 return(STATUS_PAGEFILE_QUOTA
);
2518 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2522 * Write the page to the pagefile
2524 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2525 if (!NT_SUCCESS(Status
))
2527 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2529 MmSetDirtyAllRmaps(Page
);
2530 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2531 MmspCompleteAndReleasePageOp(PageOp
);
2532 return(STATUS_UNSUCCESSFUL
);
2536 * Otherwise we have succeeded.
2538 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2539 PageOp
->Status
= STATUS_SUCCESS
;
2540 MmspCompleteAndReleasePageOp(PageOp
);
2541 return(STATUS_SUCCESS
);
2545 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2553 PMEMORY_AREA MemoryArea
;
2554 PMM_SECTION_SEGMENT Segment
;
2555 BOOLEAN DoCOW
= FALSE
;
2557 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2559 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2560 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2562 if ((Segment
->WriteCopy
) &&
2563 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2568 if (OldProtect
!= NewProtect
)
2570 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2572 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2573 ULONG Protect
= NewProtect
;
2576 * If we doing COW for this segment then check if the page is
2579 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2585 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2586 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2587 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2588 Page
= MmGetPfnForProcess(Process
, Address
);
2590 Protect
= PAGE_READONLY
;
2591 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2592 IS_SWAP_FROM_SSE(Entry
) ||
2593 PFN_FROM_SSE(Entry
) != Page
)
2595 Protect
= NewProtect
;
2599 if (MmIsPagePresent(Process
, Address
))
2601 MmSetPageProtect(Process
, Address
,
2610 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2611 PMEMORY_AREA MemoryArea
,
2619 ULONG_PTR MaxLength
;
2621 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2622 if (Length
> MaxLength
)
2623 Length
= (ULONG
)MaxLength
;
2625 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2626 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2628 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2629 Region
->Protect
!= Protect
)
2631 return STATUS_INVALID_PAGE_PROTECTION
;
2634 *OldProtect
= Region
->Protect
;
2635 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2636 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2637 BaseAddress
, Length
, Region
->Type
, Protect
,
2638 MmAlterViewAttributes
);
2644 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2646 PMEMORY_BASIC_INFORMATION Info
,
2647 PSIZE_T ResultLength
)
2650 PVOID RegionBaseAddress
;
2651 PROS_SECTION_OBJECT Section
;
2652 PMM_SECTION_SEGMENT Segment
;
2654 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2655 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2656 Address
, &RegionBaseAddress
);
2659 return STATUS_UNSUCCESSFUL
;
2662 Section
= MemoryArea
->Data
.SectionData
.Section
;
2663 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2665 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2666 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2667 Info
->Type
= MEM_IMAGE
;
2671 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2672 Info
->Type
= MEM_MAPPED
;
2674 Info
->BaseAddress
= RegionBaseAddress
;
2675 Info
->AllocationProtect
= MemoryArea
->Protect
;
2676 Info
->RegionSize
= Region
->Length
;
2677 Info
->State
= MEM_COMMIT
;
2678 Info
->Protect
= Region
->Protect
;
2680 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2681 return(STATUS_SUCCESS
);
2686 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2691 SWAPENTRY SavedSwapEntry
;
2696 Length
= PAGE_ROUND_UP(Segment
->Length
);
2697 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2699 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2702 if (IS_SWAP_FROM_SSE(Entry
))
2704 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2708 Page
= PFN_FROM_SSE(Entry
);
2709 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2710 if (SavedSwapEntry
!= 0)
2712 MmSetSavedSwapEntryPage(Page
, 0);
2713 MmFreeSwapPage(SavedSwapEntry
);
2715 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2717 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2723 MmpDeleteSection(PVOID ObjectBody
)
2725 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2727 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2728 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2733 PMM_SECTION_SEGMENT SectionSegments
;
2736 * NOTE: Section->ImageSection can be NULL for short time
2737 * during the section creating. If we fail for some reason
2738 * until the image section is properly initialized we shouldn't
2739 * process further here.
2741 if (Section
->ImageSection
== NULL
)
2744 SectionSegments
= Section
->ImageSection
->Segments
;
2745 NrSegments
= Section
->ImageSection
->NrSegments
;
2747 for (i
= 0; i
< NrSegments
; i
++)
2749 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2751 MmLockSectionSegment(&SectionSegments
[i
]);
2753 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2754 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2758 MmpFreePageFileSegment(&SectionSegments
[i
]);
2760 MmUnlockSectionSegment(&SectionSegments
[i
]);
2767 * NOTE: Section->Segment can be NULL for short time
2768 * during the section creating.
2770 if (Section
->Segment
== NULL
)
2773 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2775 MmpFreePageFileSegment(Section
->Segment
);
2776 MmFreePageTablesSectionSegment(Section
->Segment
);
2777 ExFreePool(Section
->Segment
);
2778 Section
->Segment
= NULL
;
2782 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2785 if (Section
->FileObject
!= NULL
)
2788 CcRosDereferenceCache(Section
->FileObject
);
2790 ObDereferenceObject(Section
->FileObject
);
2791 Section
->FileObject
= NULL
;
2796 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2798 IN ACCESS_MASK GrantedAccess
,
2799 IN ULONG ProcessHandleCount
,
2800 IN ULONG SystemHandleCount
)
2802 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2803 Object
, ProcessHandleCount
);
2809 MmCreatePhysicalMemorySection(VOID
)
2811 PROS_SECTION_OBJECT PhysSection
;
2813 OBJECT_ATTRIBUTES Obj
;
2814 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2815 LARGE_INTEGER SectionSize
;
2819 * Create the section mapping physical memory
2821 SectionSize
.QuadPart
= 0xFFFFFFFF;
2822 InitializeObjectAttributes(&Obj
,
2827 Status
= MmCreateSection((PVOID
)&PhysSection
,
2831 PAGE_EXECUTE_READWRITE
,
2835 if (!NT_SUCCESS(Status
))
2837 DPRINT1("Failed to create PhysicalMemory section\n");
2838 KeBugCheck(MEMORY_MANAGEMENT
);
2840 Status
= ObInsertObject(PhysSection
,
2846 if (!NT_SUCCESS(Status
))
2848 ObDereferenceObject(PhysSection
);
2850 ObCloseHandle(Handle
, KernelMode
);
2851 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2852 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2854 return(STATUS_SUCCESS
);
2860 MmInitSectionImplementation(VOID
)
2862 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2863 UNICODE_STRING Name
;
2865 DPRINT("Creating Section Object Type\n");
2867 /* Initialize the Section object type */
2868 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2869 RtlInitUnicodeString(&Name
, L
"Section");
2870 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2871 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2872 ObjectTypeInitializer
.PoolType
= PagedPool
;
2873 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2874 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2875 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2876 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2877 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2878 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2880 MmCreatePhysicalMemorySection();
2882 return(STATUS_SUCCESS
);
2887 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2888 ACCESS_MASK DesiredAccess
,
2889 POBJECT_ATTRIBUTES ObjectAttributes
,
2890 PLARGE_INTEGER UMaximumSize
,
2891 ULONG SectionPageProtection
,
2892 ULONG AllocationAttributes
)
2894 * Create a section which is backed by the pagefile
2897 LARGE_INTEGER MaximumSize
;
2898 PROS_SECTION_OBJECT Section
;
2899 PMM_SECTION_SEGMENT Segment
;
2902 if (UMaximumSize
== NULL
)
2904 return(STATUS_UNSUCCESSFUL
);
2906 MaximumSize
= *UMaximumSize
;
2909 * Create the section
2911 Status
= ObCreateObject(ExGetPreviousMode(),
2912 MmSectionObjectType
,
2914 ExGetPreviousMode(),
2916 sizeof(ROS_SECTION_OBJECT
),
2919 (PVOID
*)(PVOID
)&Section
);
2920 if (!NT_SUCCESS(Status
))
2928 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2929 Section
->SectionPageProtection
= SectionPageProtection
;
2930 Section
->AllocationAttributes
= AllocationAttributes
;
2931 Section
->MaximumSize
= MaximumSize
;
2932 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2933 TAG_MM_SECTION_SEGMENT
);
2934 if (Segment
== NULL
)
2936 ObDereferenceObject(Section
);
2937 return(STATUS_NO_MEMORY
);
2939 Section
->Segment
= Segment
;
2940 Segment
->ReferenceCount
= 1;
2941 ExInitializeFastMutex(&Segment
->Lock
);
2942 Segment
->FileOffset
= 0;
2943 Segment
->Protection
= SectionPageProtection
;
2944 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2945 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2946 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2947 Segment
->WriteCopy
= FALSE
;
2948 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2949 Segment
->VirtualAddress
= 0;
2950 Segment
->Characteristics
= 0;
2951 *SectionObject
= Section
;
2952 return(STATUS_SUCCESS
);
2958 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2959 ACCESS_MASK DesiredAccess
,
2960 POBJECT_ATTRIBUTES ObjectAttributes
,
2961 PLARGE_INTEGER UMaximumSize
,
2962 ULONG SectionPageProtection
,
2963 ULONG AllocationAttributes
,
2966 * Create a section backed by a data file
2969 PROS_SECTION_OBJECT Section
;
2971 LARGE_INTEGER MaximumSize
;
2972 PFILE_OBJECT FileObject
;
2973 PMM_SECTION_SEGMENT Segment
;
2975 IO_STATUS_BLOCK Iosb
;
2976 LARGE_INTEGER Offset
;
2978 FILE_STANDARD_INFORMATION FileInfo
;
2982 * Create the section
2984 Status
= ObCreateObject(ExGetPreviousMode(),
2985 MmSectionObjectType
,
2987 ExGetPreviousMode(),
2989 sizeof(ROS_SECTION_OBJECT
),
2992 (PVOID
*)(PVOID
)&Section
);
2993 if (!NT_SUCCESS(Status
))
3000 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3001 Section
->SectionPageProtection
= SectionPageProtection
;
3002 Section
->AllocationAttributes
= AllocationAttributes
;
3005 * Check file access required
3007 if (SectionPageProtection
& PAGE_READWRITE
||
3008 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3010 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3014 FileAccess
= FILE_READ_DATA
;
3018 * Reference the file handle
3020 Status
= ObReferenceObjectByHandle(FileHandle
,
3023 ExGetPreviousMode(),
3024 (PVOID
*)(PVOID
)&FileObject
,
3026 if (!NT_SUCCESS(Status
))
3028 ObDereferenceObject(Section
);
3033 * FIXME: This is propably not entirely correct. We can't look into
3034 * the standard FCB header because it might not be initialized yet
3035 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
3036 * standard file information is filled on first request).
3038 Status
= IoQueryFileInformation(FileObject
,
3039 FileStandardInformation
,
3040 sizeof(FILE_STANDARD_INFORMATION
),
3043 Iosb
.Information
= Length
;
3044 if (!NT_SUCCESS(Status
))
3046 ObDereferenceObject(Section
);
3047 ObDereferenceObject(FileObject
);
3052 * FIXME: Revise this once a locking order for file size changes is
3055 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
3057 MaximumSize
= *UMaximumSize
;
3061 MaximumSize
= FileInfo
.EndOfFile
;
3062 /* Mapping zero-sized files isn't allowed. */
3063 if (MaximumSize
.QuadPart
== 0)
3065 ObDereferenceObject(Section
);
3066 ObDereferenceObject(FileObject
);
3067 return STATUS_FILE_INVALID
;
3071 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3073 Status
= IoSetInformation(FileObject
,
3074 FileAllocationInformation
,
3075 sizeof(LARGE_INTEGER
),
3077 if (!NT_SUCCESS(Status
))
3079 ObDereferenceObject(Section
);
3080 ObDereferenceObject(FileObject
);
3081 return(STATUS_SECTION_NOT_EXTENDED
);
3085 if (FileObject
->SectionObjectPointer
== NULL
||
3086 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3089 * Read a bit so caching is initiated for the file object.
3090 * This is only needed because MiReadPage currently cannot
3091 * handle non-cached streams.
3093 Offset
.QuadPart
= 0;
3094 Status
= ZwReadFile(FileHandle
,
3103 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3105 ObDereferenceObject(Section
);
3106 ObDereferenceObject(FileObject
);
3109 if (FileObject
->SectionObjectPointer
== NULL
||
3110 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3112 /* FIXME: handle this situation */
3113 ObDereferenceObject(Section
);
3114 ObDereferenceObject(FileObject
);
3115 return STATUS_INVALID_PARAMETER
;
3122 Status
= MmspWaitForFileLock(FileObject
);
3123 if (Status
!= STATUS_SUCCESS
)
3125 ObDereferenceObject(Section
);
3126 ObDereferenceObject(FileObject
);
3131 * If this file hasn't been mapped as a data file before then allocate a
3132 * section segment to describe the data file mapping
3134 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3136 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3137 TAG_MM_SECTION_SEGMENT
);
3138 if (Segment
== NULL
)
3140 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3141 ObDereferenceObject(Section
);
3142 ObDereferenceObject(FileObject
);
3143 return(STATUS_NO_MEMORY
);
3145 Section
->Segment
= Segment
;
3146 Segment
->ReferenceCount
= 1;
3147 ExInitializeFastMutex(&Segment
->Lock
);
3149 * Set the lock before assigning the segment to the file object
3151 ExAcquireFastMutex(&Segment
->Lock
);
3152 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3154 Segment
->FileOffset
= 0;
3155 Segment
->Protection
= SectionPageProtection
;
3156 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3157 Segment
->Characteristics
= 0;
3158 Segment
->WriteCopy
= FALSE
;
3159 if (AllocationAttributes
& SEC_RESERVE
)
3161 Segment
->Length
= Segment
->RawLength
= 0;
3165 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3166 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3168 Segment
->VirtualAddress
= 0;
3169 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
3174 * If the file is already mapped as a data file then we may need
3178 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3180 Section
->Segment
= Segment
;
3181 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3182 MmLockSectionSegment(Segment
);
3184 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
3185 !(AllocationAttributes
& SEC_RESERVE
))
3187 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3188 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3191 MmUnlockSectionSegment(Segment
);
3192 Section
->FileObject
= FileObject
;
3193 Section
->MaximumSize
= MaximumSize
;
3195 CcRosReferenceCache(FileObject
);
3197 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3198 *SectionObject
= Section
;
3199 return(STATUS_SUCCESS
);
3203 TODO: not that great (declaring loaders statically, having to declare all of
3204 them, having to keep them extern, etc.), will fix in the future
3206 extern NTSTATUS NTAPI PeFmtCreateSection
3208 IN CONST VOID
* FileHeader
,
3209 IN SIZE_T FileHeaderSize
,
3211 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3213 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3214 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3217 extern NTSTATUS NTAPI ElfFmtCreateSection
3219 IN CONST VOID
* FileHeader
,
3220 IN SIZE_T FileHeaderSize
,
3222 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3224 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3225 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3228 /* TODO: this is a standard DDK/PSDK macro */
3229 #ifndef RTL_NUMBER_OF
3230 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3233 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3244 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3246 SIZE_T SizeOfSegments
;
3247 PMM_SECTION_SEGMENT Segments
;
3249 /* TODO: check for integer overflow */
3250 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3252 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3254 TAG_MM_SECTION_SEGMENT
);
3257 RtlZeroMemory(Segments
, SizeOfSegments
);
3265 ExeFmtpReadFile(IN PVOID File
,
3266 IN PLARGE_INTEGER Offset
,
3269 OUT PVOID
* AllocBase
,
3270 OUT PULONG ReadSize
)
3273 LARGE_INTEGER FileOffset
;
3275 ULONG OffsetAdjustment
;
3280 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3284 KeBugCheck(MEMORY_MANAGEMENT
);
3287 FileOffset
= *Offset
;
3289 /* Negative/special offset: it cannot be used in this context */
3290 if(FileOffset
.u
.HighPart
< 0)
3292 KeBugCheck(MEMORY_MANAGEMENT
);
3295 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3296 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3297 FileOffset
.u
.LowPart
= AdjustOffset
;
3299 BufferSize
= Length
+ OffsetAdjustment
;
3300 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3303 * It's ok to use paged pool, because this is a temporary buffer only used in
3304 * the loading of executables. The assumption is that MmCreateSection is
3305 * always called at low IRQLs and that these buffers don't survive a brief
3306 * initialization phase
3308 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3313 KeBugCheck(MEMORY_MANAGEMENT
);
3319 Status
= MmspPageRead(File
,
3326 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
3327 * nothing will work. But using ZwReadFile is wrong, and using its side effects
3328 * to initialize internal state is even worse. Our cache manager is in need of
3332 IO_STATUS_BLOCK Iosb
;
3334 Status
= ZwReadFile(File
,
3344 if(NT_SUCCESS(Status
))
3346 UsedSize
= (ULONG
)Iosb
.Information
;
3351 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3353 Status
= STATUS_IN_PAGE_ERROR
;
3354 ASSERT(!NT_SUCCESS(Status
));
3357 if(NT_SUCCESS(Status
))
3359 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3360 *AllocBase
= Buffer
;
3361 *ReadSize
= UsedSize
- OffsetAdjustment
;
3365 ExFreePoolWithTag(Buffer
, 'rXmM');
3372 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3373 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3374 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3379 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3383 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3385 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3386 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
3393 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3397 MmspAssertSegmentsSorted(ImageSectionObject
);
3399 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3401 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
3405 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3406 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3407 ImageSectionObject
->Segments
[i
- 1].Length
));
3415 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3419 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3421 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
3422 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
3430 MmspCompareSegments(const void * x
,
3433 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3434 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3437 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
3438 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3442 * Ensures an image section's segments are sorted in memory
3447 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3450 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3452 MmspAssertSegmentsSorted(ImageSectionObject
);
3456 qsort(ImageSectionObject
->Segments
,
3457 ImageSectionObject
->NrSegments
,
3458 sizeof(ImageSectionObject
->Segments
[0]),
3459 MmspCompareSegments
);
3465 * Ensures an image section's segments don't overlap in memory and don't have
3466 * gaps and don't have a null size. We let them map to overlapping file regions,
3467 * though - that's not necessarily an error
3472 MmspCheckSegmentBounds
3474 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3480 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3482 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3486 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3488 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3490 if(ImageSectionObject
->Segments
[i
].Length
== 0)
3498 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3499 * page could be OK (Windows seems to be OK with them), and larger gaps
3500 * could lead to image sections spanning several discontiguous regions
3501 * (NtMapViewOfSection could then refuse to map them, and they could
3502 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3504 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3505 ImageSectionObject
->Segments
[i
- 1].Length
) !=
3506 ImageSectionObject
->Segments
[i
].VirtualAddress
)
3517 * Merges and pads an image section's segments until they all are page-aligned
3518 * and have a size that is a multiple of the page size
3523 MmspPageAlignSegments
3525 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3531 PMM_SECTION_SEGMENT EffectiveSegment
;
3533 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3535 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3540 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3542 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3545 * The first segment requires special handling
3549 ULONG_PTR VirtualAddress
;
3550 ULONG_PTR VirtualOffset
;
3552 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3554 /* Round down the virtual address to the nearest page */
3555 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3557 /* Round up the virtual size to the nearest page */
3558 EffectiveSegment
->Length
= (ULONG
)(PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3559 EffectiveSegment
->VirtualAddress
);
3561 /* Adjust the raw address and size */
3562 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3564 if (EffectiveSegment
->FileOffset
< (LONG_PTR
)VirtualOffset
)
3570 * Garbage in, garbage out: unaligned base addresses make the file
3571 * offset point in curious and odd places, but that's what we were
3574 EffectiveSegment
->FileOffset
-= (ULONG
)VirtualOffset
;
3575 EffectiveSegment
->RawLength
+= (ULONG
)VirtualOffset
;
3579 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3580 ULONG_PTR EndOfEffectiveSegment
;
3582 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3583 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3586 * The current segment begins exactly where the current effective
3587 * segment ended, therefore beginning a new effective segment
3589 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3592 ASSERT(LastSegment
<= i
);
3593 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3595 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3597 if (LastSegment
!= i
)
3600 * Copy the current segment. If necessary, the effective segment
3601 * will be expanded later
3603 *EffectiveSegment
= *Segment
;
3607 * Page-align the virtual size. We know for sure the virtual address
3610 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3611 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3614 * The current segment is still part of the current effective segment:
3615 * extend the effective segment to reflect this
3617 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3619 static const ULONG FlagsToProtection
[16] =
3627 PAGE_EXECUTE_READWRITE
,
3628 PAGE_EXECUTE_READWRITE
,
3633 PAGE_EXECUTE_WRITECOPY
,
3634 PAGE_EXECUTE_WRITECOPY
,
3635 PAGE_EXECUTE_WRITECOPY
,
3636 PAGE_EXECUTE_WRITECOPY
3639 unsigned ProtectionFlags
;
3642 * Extend the file size
3645 /* Unaligned segments must be contiguous within the file */
3646 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3647 EffectiveSegment
->RawLength
))
3652 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3655 * Extend the virtual size
3657 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3659 EffectiveSegment
->Length
= (ULONG
)(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3660 EffectiveSegment
->VirtualAddress
);
3663 * Merge the protection
3665 EffectiveSegment
->Protection
|= Segment
->Protection
;
3667 /* Clean up redundance */
3668 ProtectionFlags
= 0;
3670 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3671 ProtectionFlags
|= 1 << 0;
3673 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3674 ProtectionFlags
|= 1 << 1;
3676 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3677 ProtectionFlags
|= 1 << 2;
3679 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3680 ProtectionFlags
|= 1 << 3;
3682 ASSERT(ProtectionFlags
< 16);
3683 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3685 /* If a segment was required to be shared and cannot, fail */
3686 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3687 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3693 * We assume no holes between segments at this point
3697 KeBugCheck(MEMORY_MANAGEMENT
);
3701 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3707 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3708 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3710 LARGE_INTEGER Offset
;
3712 PVOID FileHeaderBuffer
;
3713 ULONG FileHeaderSize
;
3715 ULONG OldNrSegments
;
3720 * Read the beginning of the file (2 pages). Should be enough to contain
3721 * all (or most) of the headers
3723 Offset
.QuadPart
= 0;
3725 /* FIXME: use FileObject instead of FileHandle */
3726 Status
= ExeFmtpReadFile (FileHandle
,
3733 if (!NT_SUCCESS(Status
))
3736 if (FileHeaderSize
== 0)
3738 ExFreePool(FileHeaderBuffer
);
3739 return STATUS_UNSUCCESSFUL
;
3743 * Look for a loader that can handle this executable
3745 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3747 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3750 /* FIXME: use FileObject instead of FileHandle */
3751 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3757 ExeFmtpAllocateSegments
);
3759 if (!NT_SUCCESS(Status
))
3761 if (ImageSectionObject
->Segments
)
3763 ExFreePool(ImageSectionObject
->Segments
);
3764 ImageSectionObject
->Segments
= NULL
;
3768 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3772 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3775 * No loader handled the format
3777 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3779 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3780 ASSERT(!NT_SUCCESS(Status
));
3783 if (!NT_SUCCESS(Status
))
3786 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3791 /* FIXME? are these values platform-dependent? */
3792 if(ImageSectionObject
->StackReserve
== 0)
3793 ImageSectionObject
->StackReserve
= 0x40000;
3795 if(ImageSectionObject
->StackCommit
== 0)
3796 ImageSectionObject
->StackCommit
= 0x1000;
3798 if(ImageSectionObject
->ImageBase
== 0)
3800 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3801 ImageSectionObject
->ImageBase
= 0x10000000;
3803 ImageSectionObject
->ImageBase
= 0x00400000;
3807 * And now the fun part: fixing the segments
3810 /* Sort them by virtual address */
3811 MmspSortSegments(ImageSectionObject
, Flags
);
3813 /* Ensure they don't overlap in memory */
3814 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3815 return STATUS_INVALID_IMAGE_FORMAT
;
3817 /* Ensure they are aligned */
3818 OldNrSegments
= ImageSectionObject
->NrSegments
;
3820 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3821 return STATUS_INVALID_IMAGE_FORMAT
;
3823 /* Trim them if the alignment phase merged some of them */
3824 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3826 PMM_SECTION_SEGMENT Segments
;
3827 SIZE_T SizeOfSegments
;
3829 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3831 Segments
= ExAllocatePoolWithTag(PagedPool
,
3833 TAG_MM_SECTION_SEGMENT
);
3835 if (Segments
== NULL
)
3836 return STATUS_INSUFFICIENT_RESOURCES
;
3838 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3839 ExFreePool(ImageSectionObject
->Segments
);
3840 ImageSectionObject
->Segments
= Segments
;
3843 /* And finish their initialization */
3844 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3846 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3847 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3849 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3850 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3853 ASSERT(NT_SUCCESS(Status
));
3858 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3859 ACCESS_MASK DesiredAccess
,
3860 POBJECT_ATTRIBUTES ObjectAttributes
,
3861 PLARGE_INTEGER UMaximumSize
,
3862 ULONG SectionPageProtection
,
3863 ULONG AllocationAttributes
,
3866 PROS_SECTION_OBJECT Section
;
3868 PFILE_OBJECT FileObject
;
3869 PMM_SECTION_SEGMENT SectionSegments
;
3870 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3872 ULONG FileAccess
= 0;
3875 * Check file access required
3877 if (SectionPageProtection
& PAGE_READWRITE
||
3878 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3880 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3884 FileAccess
= FILE_READ_DATA
;
3888 * Reference the file handle
3890 Status
= ObReferenceObjectByHandle(FileHandle
,
3893 ExGetPreviousMode(),
3894 (PVOID
*)(PVOID
)&FileObject
,
3897 if (!NT_SUCCESS(Status
))
3903 * Create the section
3905 Status
= ObCreateObject (ExGetPreviousMode(),
3906 MmSectionObjectType
,
3908 ExGetPreviousMode(),
3910 sizeof(ROS_SECTION_OBJECT
),
3913 (PVOID
*)(PVOID
)&Section
);
3914 if (!NT_SUCCESS(Status
))
3916 ObDereferenceObject(FileObject
);
3923 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3924 Section
->SectionPageProtection
= SectionPageProtection
;
3925 Section
->AllocationAttributes
= AllocationAttributes
;
3929 * Initialized caching for this file object if previously caching
3930 * was initialized for the same on disk file
3932 Status
= CcTryToInitializeFileCache(FileObject
);
3934 Status
= STATUS_SUCCESS
;
3937 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3939 NTSTATUS StatusExeFmt
;
3941 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3942 if (ImageSectionObject
== NULL
)
3944 ObDereferenceObject(FileObject
);
3945 ObDereferenceObject(Section
);
3946 return(STATUS_NO_MEMORY
);
3949 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3951 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3953 if (!NT_SUCCESS(StatusExeFmt
))
3955 if(ImageSectionObject
->Segments
!= NULL
)
3956 ExFreePool(ImageSectionObject
->Segments
);
3958 ExFreePool(ImageSectionObject
);
3959 ObDereferenceObject(Section
);
3960 ObDereferenceObject(FileObject
);
3961 return(StatusExeFmt
);
3964 Section
->ImageSection
= ImageSectionObject
;
3965 ASSERT(ImageSectionObject
->Segments
);
3970 Status
= MmspWaitForFileLock(FileObject
);
3971 if (!NT_SUCCESS(Status
))
3973 ExFreePool(ImageSectionObject
->Segments
);
3974 ExFreePool(ImageSectionObject
);
3975 ObDereferenceObject(Section
);
3976 ObDereferenceObject(FileObject
);
3980 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3981 ImageSectionObject
, NULL
))
3984 * An other thread has initialized the same image in the background
3986 ExFreePool(ImageSectionObject
->Segments
);
3987 ExFreePool(ImageSectionObject
);
3988 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3989 Section
->ImageSection
= ImageSectionObject
;
3990 SectionSegments
= ImageSectionObject
->Segments
;
3992 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3994 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3998 Status
= StatusExeFmt
;
4005 Status
= MmspWaitForFileLock(FileObject
);
4006 if (Status
!= STATUS_SUCCESS
)
4008 ObDereferenceObject(Section
);
4009 ObDereferenceObject(FileObject
);
4013 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
4014 Section
->ImageSection
= ImageSectionObject
;
4015 SectionSegments
= ImageSectionObject
->Segments
;
4018 * Otherwise just reference all the section segments
4020 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
4022 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
4025 Status
= STATUS_SUCCESS
;
4027 Section
->FileObject
= FileObject
;
4029 CcRosReferenceCache(FileObject
);
4031 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
4032 *SectionObject
= Section
;
4039 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
4040 PROS_SECTION_OBJECT Section
,
4041 PMM_SECTION_SEGMENT Segment
,
4046 ULONG AllocationType
)
4050 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4052 BoundaryAddressMultiple
.QuadPart
= 0;
4054 Status
= MmCreateMemoryArea(AddressSpace
,
4055 MEMORY_AREA_SECTION_VIEW
,
4062 BoundaryAddressMultiple
);
4063 if (!NT_SUCCESS(Status
))
4065 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
4066 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
4070 ObReferenceObject((PVOID
)Section
);
4072 MArea
->Data
.SectionData
.Segment
= Segment
;
4073 MArea
->Data
.SectionData
.Section
= Section
;
4074 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
4075 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
4076 ViewSize
, 0, Protect
);
4078 return(STATUS_SUCCESS
);
4084 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
4085 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4088 PFILE_OBJECT FileObject
;
4091 SWAPENTRY SavedSwapEntry
;
4094 PROS_SECTION_OBJECT Section
;
4095 PMM_SECTION_SEGMENT Segment
;
4096 PMMSUPPORT AddressSpace
;
4099 AddressSpace
= (PMMSUPPORT
)Context
;
4100 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4102 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4104 Offset
= (ULONG
)(((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
4105 MemoryArea
->Data
.SectionData
.ViewOffset
);
4107 Section
= MemoryArea
->Data
.SectionData
.Section
;
4108 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4110 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4114 MmUnlockSectionSegment(Segment
);
4115 MmUnlockAddressSpace(AddressSpace
);
4117 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4118 if (Status
!= STATUS_SUCCESS
)
4120 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4121 KeBugCheck(MEMORY_MANAGEMENT
);
4124 MmLockAddressSpace(AddressSpace
);
4125 MmLockSectionSegment(Segment
);
4126 MmspCompleteAndReleasePageOp(PageOp
);
4127 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4130 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
4133 * For a dirty, datafile, non-private page mark it as dirty in the
4136 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4138 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4140 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4141 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4143 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
4145 ASSERT(SwapEntry
== 0);
4154 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4156 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4157 KeBugCheck(MEMORY_MANAGEMENT
);
4159 MmFreeSwapPage(SwapEntry
);
4163 if (IS_SWAP_FROM_SSE(Entry
) ||
4164 Page
!= PFN_FROM_SSE(Entry
))
4169 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4171 DPRINT1("Found a private page in a pagefile section.\n");
4172 KeBugCheck(MEMORY_MANAGEMENT
);
4175 * Just dereference private pages
4177 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4178 if (SavedSwapEntry
!= 0)
4180 MmFreeSwapPage(SavedSwapEntry
);
4181 MmSetSavedSwapEntryPage(Page
, 0);
4183 MmDeleteRmap(Page
, Process
, Address
);
4184 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4188 MmDeleteRmap(Page
, Process
, Address
);
4189 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4195 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4199 PMEMORY_AREA MemoryArea
;
4200 PROS_SECTION_OBJECT Section
;
4201 PMM_SECTION_SEGMENT Segment
;
4202 PLIST_ENTRY CurrentEntry
;
4203 PMM_REGION CurrentRegion
;
4204 PLIST_ENTRY RegionListHead
;
4206 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4208 if (MemoryArea
== NULL
)
4210 return(STATUS_UNSUCCESSFUL
);
4213 MemoryArea
->DeleteInProgress
= TRUE
;
4214 Section
= MemoryArea
->Data
.SectionData
.Section
;
4215 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4217 MmLockSectionSegment(Segment
);
4219 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4220 while (!IsListEmpty(RegionListHead
))
4222 CurrentEntry
= RemoveHeadList(RegionListHead
);
4223 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4224 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4227 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4229 Status
= MmFreeMemoryArea(AddressSpace
,
4236 Status
= MmFreeMemoryArea(AddressSpace
,
4241 MmUnlockSectionSegment(Segment
);
4242 ObDereferenceObject(Section
);
4250 MmUnmapViewOfSection(PEPROCESS Process
,
4254 PMEMORY_AREA MemoryArea
;
4255 PMMSUPPORT AddressSpace
;
4256 PROS_SECTION_OBJECT Section
;
4259 PVOID ImageBaseAddress
= 0;
4261 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4262 Process
, BaseAddress
);
4266 AddressSpace
= &Process
->Vm
;
4268 MmLockAddressSpace(AddressSpace
);
4269 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4271 if (MemoryArea
== NULL
||
4272 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4273 MemoryArea
->DeleteInProgress
)
4275 MmUnlockAddressSpace(AddressSpace
);
4276 return STATUS_NOT_MAPPED_VIEW
;
4279 MemoryArea
->DeleteInProgress
= TRUE
;
4281 while (MemoryArea
->PageOpCount
)
4283 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4287 Offset
-= PAGE_SIZE
;
4288 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4289 MemoryArea
->Data
.SectionData
.Segment
,
4290 (ULONG
)Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4293 MmUnlockAddressSpace(AddressSpace
);
4294 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4295 if (Status
!= STATUS_SUCCESS
)
4297 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4298 KeBugCheck(MEMORY_MANAGEMENT
);
4300 MmLockAddressSpace(AddressSpace
);
4301 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4303 if (MemoryArea
== NULL
||
4304 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4306 MmUnlockAddressSpace(AddressSpace
);
4307 return STATUS_NOT_MAPPED_VIEW
;
4314 Section
= MemoryArea
->Data
.SectionData
.Section
;
4316 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4320 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4321 PMM_SECTION_SEGMENT SectionSegments
;
4322 PMM_SECTION_SEGMENT Segment
;
4324 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4325 ImageSectionObject
= Section
->ImageSection
;
4326 SectionSegments
= ImageSectionObject
->Segments
;
4327 NrSegments
= ImageSectionObject
->NrSegments
;
4329 /* Search for the current segment within the section segments
4330 * and calculate the image base address */
4331 for (i
= 0; i
< NrSegments
; i
++)
4333 if (Segment
== &SectionSegments
[i
])
4335 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4339 if (i
>= NrSegments
)
4341 KeBugCheck(MEMORY_MANAGEMENT
);
4344 for (i
= 0; i
< NrSegments
; i
++)
4346 PVOID SBaseAddress
= (PVOID
)
4347 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4349 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4354 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4357 MmUnlockAddressSpace(AddressSpace
);
4359 /* Notify debugger */
4360 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4362 return(STATUS_SUCCESS
);
4369 * Queries the information of a section object.
4371 * @param SectionHandle
4372 * Handle to the section object. It must be opened with SECTION_QUERY
4374 * @param SectionInformationClass
4375 * Index to a certain information structure. Can be either
4376 * SectionBasicInformation or SectionImageInformation. The latter
4377 * is valid only for sections that were created with the SEC_IMAGE
4379 * @param SectionInformation
4380 * Caller supplies storage for resulting information.
4382 * Size of the supplied storage.
4383 * @param ResultLength
4391 NtQuerySection(IN HANDLE SectionHandle
,
4392 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4393 OUT PVOID SectionInformation
,
4394 IN SIZE_T SectionInformationLength
,
4395 OUT PSIZE_T ResultLength OPTIONAL
)
4397 PROS_SECTION_OBJECT Section
;
4398 KPROCESSOR_MODE PreviousMode
;
4402 PreviousMode
= ExGetPreviousMode();
4404 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4406 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4408 (ULONG
)SectionInformationLength
,
4413 if(!NT_SUCCESS(Status
))
4415 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4419 Status
= ObReferenceObjectByHandle(SectionHandle
,
4421 MmSectionObjectType
,
4423 (PVOID
*)(PVOID
)&Section
,
4425 if (NT_SUCCESS(Status
))
4427 switch (SectionInformationClass
)
4429 case SectionBasicInformation
:
4431 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4435 Sbi
->Attributes
= Section
->AllocationAttributes
;
4436 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4438 Sbi
->BaseAddress
= 0;
4439 Sbi
->Size
.QuadPart
= 0;
4443 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4444 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4447 if (ResultLength
!= NULL
)
4449 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4451 Status
= STATUS_SUCCESS
;
4453 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4455 Status
= _SEH2_GetExceptionCode();
4462 case SectionImageInformation
:
4464 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4468 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4469 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4471 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4472 ImageSectionObject
= Section
->ImageSection
;
4474 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4475 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4476 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4477 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4478 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4479 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4480 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4481 Sii
->Machine
= ImageSectionObject
->Machine
;
4482 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4485 if (ResultLength
!= NULL
)
4487 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4489 Status
= STATUS_SUCCESS
;
4491 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4493 Status
= _SEH2_GetExceptionCode();
4501 ObDereferenceObject(Section
);
4507 /**********************************************************************
4509 * MmMapViewOfSection
4512 * Maps a view of a section into the virtual address space of a
4517 * Pointer to the section object.
4520 * Pointer to the process.
4523 * Desired base address (or NULL) on entry;
4524 * Actual base address of the view on exit.
4527 * Number of high order address bits that must be zero.
4530 * Size in bytes of the initially committed section of
4534 * Offset in bytes from the beginning of the section
4535 * to the beginning of the view.
4538 * Desired length of map (or zero to map all) on entry
4539 * Actual length mapped on exit.
4541 * InheritDisposition
4542 * Specified how the view is to be shared with
4546 * Type of allocation for the pages.
4549 * Protection for the committed region of the view.
4557 MmMapViewOfSection(IN PVOID SectionObject
,
4558 IN PEPROCESS Process
,
4559 IN OUT PVOID
*BaseAddress
,
4560 IN ULONG_PTR ZeroBits
,
4561 IN SIZE_T CommitSize
,
4562 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4563 IN OUT PSIZE_T ViewSize
,
4564 IN SECTION_INHERIT InheritDisposition
,
4565 IN ULONG AllocationType
,
4568 PROS_SECTION_OBJECT Section
;
4569 PMMSUPPORT AddressSpace
;
4571 NTSTATUS Status
= STATUS_SUCCESS
;
4572 BOOLEAN NotAtBase
= FALSE
;
4574 if ((ULONG_PTR
)SectionObject
& 1)
4576 return MmMapViewOfArm3Section((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4590 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4592 return STATUS_INVALID_PAGE_PROTECTION
;
4596 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4597 AddressSpace
= &Process
->Vm
;
4599 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4601 MmLockAddressSpace(AddressSpace
);
4603 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4607 ULONG_PTR ImageBase
;
4609 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4610 PMM_SECTION_SEGMENT SectionSegments
;
4612 ImageSectionObject
= Section
->ImageSection
;
4613 SectionSegments
= ImageSectionObject
->Segments
;
4614 NrSegments
= ImageSectionObject
->NrSegments
;
4617 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4620 ImageBase
= ImageSectionObject
->ImageBase
;
4624 for (i
= 0; i
< NrSegments
; i
++)
4626 ULONG_PTR MaxExtent
;
4627 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4628 SectionSegments
[i
].Length
;
4629 ImageSize
= max(ImageSize
, MaxExtent
);
4632 ImageSectionObject
->ImageSize
= (ULONG
)ImageSize
;
4634 /* Check for an illegal base address */
4635 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4637 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4640 /* Check there is enough space to map the section at that point. */
4641 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4642 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4644 /* Fail if the user requested a fixed base address. */
4645 if ((*BaseAddress
) != NULL
)
4647 MmUnlockAddressSpace(AddressSpace
);
4648 return(STATUS_UNSUCCESSFUL
);
4650 /* Otherwise find a gap to map the image. */
4651 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4654 MmUnlockAddressSpace(AddressSpace
);
4655 return(STATUS_UNSUCCESSFUL
);
4657 /* Remember that we loaded image at a different base address */
4661 for (i
= 0; i
< NrSegments
; i
++)
4663 PVOID SBaseAddress
= (PVOID
)
4664 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4665 MmLockSectionSegment(&SectionSegments
[i
]);
4666 Status
= MmMapViewOfSegment(AddressSpace
,
4668 &SectionSegments
[i
],
4670 SectionSegments
[i
].Length
,
4671 SectionSegments
[i
].Protection
,
4674 MmUnlockSectionSegment(&SectionSegments
[i
]);
4675 if (!NT_SUCCESS(Status
))
4677 MmUnlockAddressSpace(AddressSpace
);
4682 *BaseAddress
= (PVOID
)ImageBase
;
4683 *ViewSize
= ImageSize
;
4687 /* check for write access */
4688 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4689 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4691 MmUnlockAddressSpace(AddressSpace
);
4692 return STATUS_SECTION_PROTECTION
;
4694 /* check for read access */
4695 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4696 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4698 MmUnlockAddressSpace(AddressSpace
);
4699 return STATUS_SECTION_PROTECTION
;
4701 /* check for execute access */
4702 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4703 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4705 MmUnlockAddressSpace(AddressSpace
);
4706 return STATUS_SECTION_PROTECTION
;
4709 if (ViewSize
== NULL
)
4711 /* Following this pointer would lead to us to the dark side */
4712 /* What to do? Bugcheck? Return status? Do the mambo? */
4713 KeBugCheck(MEMORY_MANAGEMENT
);
4716 if (SectionOffset
== NULL
)
4722 ViewOffset
= SectionOffset
->u
.LowPart
;
4725 if ((ViewOffset
% PAGE_SIZE
) != 0)
4727 MmUnlockAddressSpace(AddressSpace
);
4728 return(STATUS_MAPPED_ALIGNMENT
);
4731 if ((*ViewSize
) == 0)
4733 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4735 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4737 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4740 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4742 MmLockSectionSegment(Section
->Segment
);
4743 Status
= MmMapViewOfSegment(AddressSpace
,
4750 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4751 MmUnlockSectionSegment(Section
->Segment
);
4752 if (!NT_SUCCESS(Status
))
4754 MmUnlockAddressSpace(AddressSpace
);
4759 MmUnlockAddressSpace(AddressSpace
);
4762 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4764 Status
= STATUS_SUCCESS
;
4773 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4774 IN PLARGE_INTEGER NewFileSize
)
4776 /* Check whether an ImageSectionObject exists */
4777 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4779 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4783 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4785 PMM_SECTION_SEGMENT Segment
;
4787 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4790 if (Segment
->ReferenceCount
!= 0)
4792 /* Check size of file */
4793 if (SectionObjectPointer
->SharedCacheMap
)
4795 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4796 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4804 /* Something must gone wrong
4805 * how can we have a Section but no
4807 DPRINT("ERROR: DataSectionObject without reference!\n");
4811 DPRINT("FIXME: didn't check for outstanding write probes\n");
4823 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4824 IN MMFLUSH_TYPE FlushType
)
4828 case MmFlushForDelete
:
4829 if (SectionObjectPointer
->ImageSectionObject
||
4830 SectionObjectPointer
->DataSectionObject
)
4835 CcRosSetRemoveOnClose(SectionObjectPointer
);
4838 case MmFlushForWrite
:
4848 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4849 OUT PVOID
* MappedBase
,
4850 IN OUT PSIZE_T ViewSize
)
4852 PROS_SECTION_OBJECT Section
;
4853 PMMSUPPORT AddressSpace
;
4857 if ((ULONG_PTR
)SectionObject
& 1)
4859 extern PVOID MmSession
;
4860 return MiMapViewInSystemSpace((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4866 DPRINT("MmMapViewInSystemSpace() called\n");
4868 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4869 AddressSpace
= MmGetKernelAddressSpace();
4871 MmLockAddressSpace(AddressSpace
);
4874 if ((*ViewSize
) == 0)
4876 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4878 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4880 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4883 MmLockSectionSegment(Section
->Segment
);
4886 Status
= MmMapViewOfSegment(AddressSpace
,
4895 MmUnlockSectionSegment(Section
->Segment
);
4896 MmUnlockAddressSpace(AddressSpace
);
4905 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4907 PMMSUPPORT AddressSpace
;
4910 DPRINT("MmUnmapViewInSystemSpace() called\n");
4912 AddressSpace
= MmGetKernelAddressSpace();
4914 MmLockAddressSpace(AddressSpace
);
4916 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4918 MmUnlockAddressSpace(AddressSpace
);
4924 /**********************************************************************
4929 * Creates a section object.
4932 * SectionObject (OUT)
4933 * Caller supplied storage for the resulting pointer
4934 * to a SECTION_OBJECT instance;
4937 * Specifies the desired access to the section can be a
4939 * STANDARD_RIGHTS_REQUIRED |
4941 * SECTION_MAP_WRITE |
4942 * SECTION_MAP_READ |
4943 * SECTION_MAP_EXECUTE
4945 * ObjectAttributes [OPTIONAL]
4946 * Initialized attributes for the object can be used
4947 * to create a named section;
4950 * Maximizes the size of the memory section. Must be
4951 * non-NULL for a page-file backed section.
4952 * If value specified for a mapped file and the file is
4953 * not large enough, file will be extended.
4955 * SectionPageProtection
4956 * Can be a combination of:
4962 * AllocationAttributes
4963 * Can be a combination of:
4968 * Handle to a file to create a section mapped to a file
4969 * instead of a memory backed section;
4980 MmCreateSection (OUT PVOID
* Section
,
4981 IN ACCESS_MASK DesiredAccess
,
4982 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4983 IN PLARGE_INTEGER MaximumSize
,
4984 IN ULONG SectionPageProtection
,
4985 IN ULONG AllocationAttributes
,
4986 IN HANDLE FileHandle OPTIONAL
,
4987 IN PFILE_OBJECT File OPTIONAL
)
4990 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4992 /* Check if an ARM3 section is being created instead */
4993 if (AllocationAttributes
& 1)
4995 DPRINT1("arm 3 path\n");
4996 return MmCreateArm3Section(Section
,
5000 SectionPageProtection
,
5001 AllocationAttributes
&~ 1,
5007 * Check the protection
5009 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
5010 if (Protection
!= PAGE_READONLY
&&
5011 Protection
!= PAGE_READWRITE
&&
5012 Protection
!= PAGE_WRITECOPY
&&
5013 Protection
!= PAGE_EXECUTE
&&
5014 Protection
!= PAGE_EXECUTE_READ
&&
5015 Protection
!= PAGE_EXECUTE_READWRITE
&&
5016 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5018 return STATUS_INVALID_PAGE_PROTECTION
;
5021 if (AllocationAttributes
& SEC_IMAGE
)
5023 return(MmCreateImageSection(SectionObject
,
5027 SectionPageProtection
,
5028 AllocationAttributes
,
5032 if (FileHandle
!= NULL
)
5034 return(MmCreateDataFileSection(SectionObject
,
5038 SectionPageProtection
,
5039 AllocationAttributes
,
5043 return(MmCreatePageFileSection(SectionObject
,
5047 SectionPageProtection
,
5048 AllocationAttributes
));