2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
49 #include "../cache/section/newmm.h"
53 #include <reactos/exeformat.h>
55 #if defined (ALLOC_PRAGMA)
56 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
57 #pragma alloc_text(INIT, MmInitSectionImplementation)
62 MiMapViewInSystemSpace(IN PVOID Section
,
64 OUT PVOID
*MappedBase
,
65 IN OUT PSIZE_T ViewSize
);
69 MmCreateArm3Section(OUT PVOID
*SectionObject
,
70 IN ACCESS_MASK DesiredAccess
,
71 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
72 IN PLARGE_INTEGER InputMaximumSize
,
73 IN ULONG SectionPageProtection
,
74 IN ULONG AllocationAttributes
,
75 IN HANDLE FileHandle OPTIONAL
,
76 IN PFILE_OBJECT FileObject OPTIONAL
);
80 MmMapViewOfArm3Section(IN PVOID SectionObject
,
82 IN OUT PVOID
*BaseAddress
,
83 IN ULONG_PTR ZeroBits
,
85 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
86 IN OUT PSIZE_T ViewSize
,
87 IN SECTION_INHERIT InheritDisposition
,
88 IN ULONG AllocationType
,
92 // PeFmtCreateSection depends on the following:
94 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
95 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
97 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
98 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
99 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
101 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
102 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
103 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
104 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
105 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
106 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
107 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
108 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
109 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
111 /* TYPES *********************************************************************/
115 PROS_SECTION_OBJECT Section
;
116 PMM_SECTION_SEGMENT Segment
;
121 MM_SECTION_PAGEOUT_CONTEXT
;
123 /* GLOBALS *******************************************************************/
125 POBJECT_TYPE MmSectionObjectType
= NULL
;
127 ULONG_PTR MmSubsectionBase
;
129 static ULONG SectionCharacteristicsToProtect
[16] =
131 PAGE_NOACCESS
, /* 0 = NONE */
132 PAGE_NOACCESS
, /* 1 = SHARED */
133 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
134 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
135 PAGE_READONLY
, /* 4 = READABLE */
136 PAGE_READONLY
, /* 5 = READABLE, SHARED */
137 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
138 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
140 * FIXME? do we really need the WriteCopy field in segments? can't we use
141 * PAGE_WRITECOPY here?
143 PAGE_READWRITE
, /* 8 = WRITABLE */
144 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
145 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
146 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
147 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
148 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
149 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
150 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
153 static GENERIC_MAPPING MmpSectionMapping
= {
154 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
155 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
156 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
159 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
160 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
161 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
162 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
163 #define MAX_SHARE_COUNT 0x7FF
164 #define MAKE_SSE(P, C) ((ULONG)(P) | ((C) << 1))
165 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
166 #define MAKE_SWAP_SSE(S) (((ULONG)(S) << 1) | 0x1)
168 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
170 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
171 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
174 /* FUNCTIONS *****************************************************************/
179 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
180 File Format Specification", revision 6.0 (February 1999)
182 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
183 IN SIZE_T FileHeaderSize
,
185 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
187 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
188 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
191 ULONG cbFileHeaderOffsetSize
= 0;
192 ULONG cbSectionHeadersOffset
= 0;
193 ULONG cbSectionHeadersSize
;
194 ULONG cbSectionHeadersOffsetSize
= 0;
195 ULONG cbOptHeaderSize
;
196 ULONG cbHeadersSize
= 0;
197 ULONG nSectionAlignment
;
198 ULONG nFileAlignment
;
199 const IMAGE_DOS_HEADER
* pidhDosHeader
;
200 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
201 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
202 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
203 PMM_SECTION_SEGMENT pssSegments
;
204 LARGE_INTEGER lnOffset
;
206 SIZE_T nPrevVirtualEndOfSegment
= 0;
207 ULONG nFileSizeOfHeaders
= 0;
211 ASSERT(FileHeaderSize
> 0);
213 ASSERT(ImageSectionObject
);
215 ASSERT(AllocateSegmentsCb
);
217 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
219 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
221 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
224 pidhDosHeader
= FileHeader
;
227 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
229 /* image too small to be an MZ executable */
230 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
231 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
233 /* no MZ signature */
234 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
235 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
237 /* not a Windows executable */
238 if(pidhDosHeader
->e_lfanew
<= 0)
239 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
242 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
244 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
245 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
247 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
252 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
253 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
255 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
256 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
260 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
261 * need to read the header from the file
263 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
264 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
266 ULONG cbNtHeaderSize
;
270 l_ReadHeaderFromFile
:
272 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
274 /* read the header from the file */
275 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
277 if(!NT_SUCCESS(nStatus
))
278 DIE(("ReadFile failed, status %08X\n", nStatus
));
282 ASSERT(cbReadSize
> 0);
284 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
286 /* the buffer doesn't contain the file header */
287 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
288 DIE(("The file doesn't contain the PE file header\n"));
290 pinhNtHeader
= pData
;
292 /* object still not aligned: copy it to the beginning of the buffer */
293 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
295 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
296 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
297 pinhNtHeader
= pBuffer
;
300 /* invalid NT header */
301 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
303 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
304 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
306 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
308 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
309 DIE(("The full NT header is too large\n"));
311 /* the buffer doesn't contain the whole NT header */
312 if(cbReadSize
< cbNtHeaderSize
)
313 DIE(("The file doesn't contain the full NT header\n"));
317 ULONG cbOptHeaderOffsetSize
= 0;
319 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
321 /* don't trust an invalid NT header */
322 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
323 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
325 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
326 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
328 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
329 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
331 /* the buffer doesn't contain the whole NT header: read it from the file */
332 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
333 goto l_ReadHeaderFromFile
;
336 /* read information from the NT header */
337 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
338 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
340 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
342 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
343 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
345 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
347 switch(piohOptHeader
->Magic
)
349 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
350 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
354 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
357 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
358 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
360 /* See [1], section 3.4.2 */
361 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
363 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
364 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
366 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
367 DIE(("The section alignment is smaller than the file alignment\n"));
369 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
370 nFileAlignment
= piohOptHeader
->FileAlignment
;
372 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
373 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
377 nSectionAlignment
= PAGE_SIZE
;
378 nFileAlignment
= PAGE_SIZE
;
381 ASSERT(IsPowerOf2(nSectionAlignment
));
382 ASSERT(IsPowerOf2(nFileAlignment
));
384 switch(piohOptHeader
->Magic
)
387 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
389 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
390 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
392 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
393 ImageSectionObject
->ImageSize
= piohOptHeader
->SizeOfImage
;
395 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
396 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
398 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
399 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
405 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
407 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
409 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
411 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
413 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
414 DIE(("ImageBase exceeds the address space\n"));
416 ImageSectionObject
->ImageBase
= (ULONG_PTR
)pioh64OptHeader
->ImageBase
;
419 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
421 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
422 DIE(("SizeOfImage exceeds the address space\n"));
424 ImageSectionObject
->ImageSize
= pioh64OptHeader
->SizeOfImage
;
427 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
429 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
430 DIE(("SizeOfStackReserve exceeds the address space\n"));
432 ImageSectionObject
->StackReserve
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackReserve
;
435 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
437 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
438 DIE(("SizeOfStackCommit exceeds the address space\n"));
440 ImageSectionObject
->StackCommit
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackCommit
;
447 /* [1], section 3.4.2 */
448 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
449 DIE(("ImageBase is not aligned on a 64KB boundary"));
451 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
453 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
455 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
456 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
458 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
459 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
463 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
465 ImageSectionObject
->EntryPoint
= piohOptHeader
->ImageBase
+
466 piohOptHeader
->AddressOfEntryPoint
;
469 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
470 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
472 ImageSectionObject
->Executable
= TRUE
;
474 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
475 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
477 /* SECTION HEADERS */
478 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
480 /* see [1], section 3.3 */
481 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
482 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
485 * the additional segment is for the file's headers. They need to be present for
486 * the benefit of the dynamic loader (to locate exports, defaults for thread
487 * parameters, resources, etc.)
489 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
491 /* file offset for the section headers */
492 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
493 DIE(("Offset overflow\n"));
495 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
496 DIE(("Offset overflow\n"));
498 /* size of the section headers */
499 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
500 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
502 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
503 DIE(("Section headers too large\n"));
505 /* size of the executable's headers */
506 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
508 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
509 // DIE(("SizeOfHeaders is not aligned\n"));
511 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
512 DIE(("The section headers overflow SizeOfHeaders\n"));
514 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
516 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
517 DIE(("Overflow aligning the size of headers\n"));
524 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
525 /* WARNING: piohOptHeader IS NO LONGER USABLE */
526 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
528 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
529 pishSectionHeaders
= NULL
;
533 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
534 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
536 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
537 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
541 * the buffer doesn't contain the section headers, or the alignment is wrong:
542 * read the headers from the file
544 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
545 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
550 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
552 /* read the header from the file */
553 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
555 if(!NT_SUCCESS(nStatus
))
556 DIE(("ReadFile failed with status %08X\n", nStatus
));
560 ASSERT(cbReadSize
> 0);
562 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
564 /* the buffer doesn't contain all the section headers */
565 if(cbReadSize
< cbSectionHeadersSize
)
566 DIE(("The file doesn't contain all of the section headers\n"));
568 pishSectionHeaders
= pData
;
570 /* object still not aligned: copy it to the beginning of the buffer */
571 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
573 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
574 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
575 pishSectionHeaders
= pBuffer
;
580 /* allocate the segments */
581 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
582 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
584 if(ImageSectionObject
->Segments
== NULL
)
585 DIE(("AllocateSegments failed\n"));
587 /* initialize the headers segment */
588 pssSegments
= ImageSectionObject
->Segments
;
590 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
592 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
593 DIE(("Cannot align the size of the section headers\n"));
595 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
596 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
597 DIE(("Cannot align the size of the section headers\n"));
599 pssSegments
[0].FileOffset
= 0;
600 pssSegments
[0].Protection
= PAGE_READONLY
;
601 pssSegments
[0].Length
= nPrevVirtualEndOfSegment
;
602 pssSegments
[0].RawLength
= nFileSizeOfHeaders
;
603 pssSegments
[0].VirtualAddress
= 0;
604 pssSegments
[0].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
605 pssSegments
[0].WriteCopy
= TRUE
;
607 /* skip the headers segment */
610 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
612 /* convert the executable sections into segments. See also [1], section 4 */
613 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
615 ULONG nCharacteristics
;
617 /* validate the alignment */
618 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
619 DIE(("VirtualAddress[%u] is not aligned\n", i
));
621 /* sections must be contiguous, ordered by base address and non-overlapping */
622 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
623 DIE(("Memory gap between section %u and the previous\n", i
));
625 /* ignore explicit BSS sections */
626 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
628 /* validate the alignment */
630 /* Yes, this should be a multiple of FileAlignment, but there's
631 * stuff out there that isn't. We can cope with that
633 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
634 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
637 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
638 // DIE(("PointerToRawData[%u] is not aligned\n", i));
641 pssSegments
[i
].FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
642 pssSegments
[i
].RawLength
= pishSectionHeaders
[i
].SizeOfRawData
;
646 ASSERT(pssSegments
[i
].FileOffset
== 0);
647 ASSERT(pssSegments
[i
].RawLength
== 0);
650 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].FileOffset
, pssSegments
[i
].RawLength
));
652 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
654 /* no explicit protection */
655 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
657 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
658 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
660 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
661 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
663 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
664 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
667 /* see table above */
668 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
669 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
671 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
672 pssSegments
[i
].Length
= pishSectionHeaders
[i
].SizeOfRawData
;
674 pssSegments
[i
].Length
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
676 pssSegments
[i
].Length
= ALIGN_UP_BY(pssSegments
[i
].Length
, nSectionAlignment
);
677 if (pssSegments
[i
].Length
< pssSegments
[i
].Length
)
678 DIE(("Cannot align the virtual size of section %u\n", i
));
680 if(pssSegments
[i
].Length
== 0)
681 DIE(("Virtual size of section %u is null\n", i
));
683 pssSegments
[i
].VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
684 pssSegments
[i
].Characteristics
= pishSectionHeaders
[i
].Characteristics
;
686 /* ensure the memory image is no larger than 4GB */
687 nPrevVirtualEndOfSegment
= pssSegments
[i
].VirtualAddress
+ pssSegments
[i
].Length
;
688 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].VirtualAddress
)
689 DIE(("The image is too large\n"));
692 if(nSectionAlignment
>= PAGE_SIZE
)
693 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
696 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;
705 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
708 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
709 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
710 * RETURNS: Status of the wait.
713 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
715 LARGE_INTEGER Timeout
;
716 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
718 Timeout
.QuadPart
= -100000000LL; // 10 sec
721 Timeout
.QuadPart
= -100000000; // 10 sec
724 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
729 * FUNCTION: Sets the page op completion event and releases the page op.
730 * ARGUMENTS: PMM_PAGEOP.
731 * RETURNS: In shorter time than it takes you to even read this
732 * description, so don't even think about geting a mug of coffee.
735 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
737 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
738 MmReleasePageOp(PageOp
);
743 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
744 * ARGUMENTS: PFILE_OBJECT to wait for.
745 * RETURNS: Status of the wait.
748 MmspWaitForFileLock(PFILE_OBJECT File
)
750 return STATUS_SUCCESS
;
751 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
756 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
759 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
761 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
763 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
765 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
773 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
775 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
777 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
778 PMM_SECTION_SEGMENT SectionSegments
;
782 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
783 NrSegments
= ImageSectionObject
->NrSegments
;
784 SectionSegments
= ImageSectionObject
->Segments
;
785 for (i
= 0; i
< NrSegments
; i
++)
787 if (SectionSegments
[i
].ReferenceCount
!= 0)
789 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
790 SectionSegments
[i
].ReferenceCount
);
791 KeBugCheck(MEMORY_MANAGEMENT
);
793 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
795 ExFreePool(ImageSectionObject
->Segments
);
796 ExFreePool(ImageSectionObject
);
797 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
799 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
801 PMM_SECTION_SEGMENT Segment
;
803 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
806 if (Segment
->ReferenceCount
!= 0)
808 DPRINT1("Data segment still referenced\n");
809 KeBugCheck(MEMORY_MANAGEMENT
);
811 MmFreePageTablesSectionSegment(Segment
);
813 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
819 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
821 ExAcquireFastMutex(&Segment
->Lock
);
826 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
828 ExReleaseFastMutex(&Segment
->Lock
);
833 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
837 PSECTION_PAGE_TABLE Table
;
838 ULONG_PTR DirectoryOffset
;
839 ULONG_PTR TableOffset
;
841 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
843 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
847 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
848 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
852 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
853 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
854 TAG_SECTION_PAGE_TABLE
);
857 KeBugCheck(MEMORY_MANAGEMENT
);
859 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
860 DPRINT("Table %x\n", Table
);
863 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
864 Table
->Entry
[TableOffset
] = (ULONG
)Entry
;
870 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
873 PSECTION_PAGE_TABLE Table
;
875 ULONG_PTR DirectoryOffset
;
876 ULONG_PTR TableOffset
;
878 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
880 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
882 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
886 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
887 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
888 DPRINT("Table %x\n", Table
);
894 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
895 Entry
= Table
->Entry
[TableOffset
];
901 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
906 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
909 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
910 KeBugCheck(MEMORY_MANAGEMENT
);
912 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
914 DPRINT1("Maximum share count reached\n");
915 KeBugCheck(MEMORY_MANAGEMENT
);
917 if (IS_SWAP_FROM_SSE(Entry
))
919 KeBugCheck(MEMORY_MANAGEMENT
);
921 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
922 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
927 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
928 PMM_SECTION_SEGMENT Segment
,
934 BOOLEAN IsDirectMapped
= FALSE
;
936 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
939 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
940 KeBugCheck(MEMORY_MANAGEMENT
);
942 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
944 DPRINT1("Zero share count for unshare\n");
945 KeBugCheck(MEMORY_MANAGEMENT
);
947 if (IS_SWAP_FROM_SSE(Entry
))
949 KeBugCheck(MEMORY_MANAGEMENT
);
951 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
953 * If we reducing the share count of this entry to zero then set the entry
954 * to zero and tell the cache the page is no longer mapped.
956 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
958 PFILE_OBJECT FileObject
;
960 SWAPENTRY SavedSwapEntry
;
962 BOOLEAN IsImageSection
;
965 FileOffset
= Offset
+ Segment
->FileOffset
;
967 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
969 Page
= PFN_FROM_SSE(Entry
);
970 FileObject
= Section
->FileObject
;
971 if (FileObject
!= NULL
&&
972 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
975 if ((FileOffset
% PAGE_SIZE
) == 0 &&
976 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
979 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
980 IsDirectMapped
= TRUE
;
982 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
984 Status
= STATUS_SUCCESS
;
986 if (!NT_SUCCESS(Status
))
988 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
989 KeBugCheck(MEMORY_MANAGEMENT
);
994 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
995 if (SavedSwapEntry
== 0)
998 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
999 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
1003 * Try to page out this page and set the swap entry
1004 * within the section segment. There exist no rmap entry
1005 * for this page. The pager thread can't page out a
1006 * page without a rmap entry.
1008 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1012 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
1013 if (!IsDirectMapped
)
1015 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1021 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1022 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1030 * We hold all locks. Nobody can do something with the current
1031 * process and the current segment (also not within an other process).
1034 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
1035 if (!NT_SUCCESS(Status
))
1037 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
1038 KeBugCheck(MEMORY_MANAGEMENT
);
1041 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
1042 MmSetSavedSwapEntryPage(Page
, 0);
1044 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1048 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1049 KeBugCheck(MEMORY_MANAGEMENT
);
1055 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1057 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1060 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1064 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1067 PCACHE_SEGMENT CacheSeg
;
1068 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1069 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
1072 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
1082 MiCopyFromUserPage(PFN_NUMBER DestPage
, PVOID SourceAddress
)
1088 Process
= PsGetCurrentProcess();
1089 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1090 if (TempAddress
== NULL
)
1092 return(STATUS_NO_MEMORY
);
1094 memcpy(TempAddress
, SourceAddress
, PAGE_SIZE
);
1095 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
1096 return(STATUS_SUCCESS
);
1102 MiReadPage(PMEMORY_AREA MemoryArea
,
1103 ULONG_PTR SegOffset
,
1106 * FUNCTION: Read a page for a section backed memory area.
1108 * MemoryArea - Memory area to read the page for.
1109 * Offset - Offset of the page to read.
1110 * Page - Variable that receives a page contains the read data.
1114 ULONG_PTR FileOffset
;
1117 PCACHE_SEGMENT CacheSeg
;
1118 PFILE_OBJECT FileObject
;
1120 ULONG_PTR RawLength
;
1122 BOOLEAN IsImageSection
;
1125 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1126 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1127 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
1128 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
1129 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1133 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1136 * If the file system is letting us go directly to the cache and the
1137 * memory area was mapped at an offset in the file which is page aligned
1138 * then get the related cache segment.
1140 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1141 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
1142 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1146 * Get the related cache segment; we use a lower level interface than
1147 * filesystems do because it is safe for us to use an offset with a
1148 * alignment less than the file system block size.
1150 Status
= CcRosGetCacheSegment(Bcb
,
1156 if (!NT_SUCCESS(Status
))
1163 * If the cache segment isn't up to date then call the file
1164 * system to read in the data.
1166 Status
= ReadCacheSegment(CacheSeg
);
1167 if (!NT_SUCCESS(Status
))
1169 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1174 * Retrieve the page from the cache segment that we actually want.
1176 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1177 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1179 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1186 ULONG_PTR CacheSegOffset
;
1189 * Allocate a page, this is rather complicated by the possibility
1190 * we might have to move other things out of memory
1192 MI_SET_USAGE(MI_USAGE_SECTION
);
1193 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1194 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1195 if (!NT_SUCCESS(Status
))
1199 Status
= CcRosGetCacheSegment(Bcb
,
1205 if (!NT_SUCCESS(Status
))
1212 * If the cache segment isn't up to date then call the file
1213 * system to read in the data.
1215 Status
= ReadCacheSegment(CacheSeg
);
1216 if (!NT_SUCCESS(Status
))
1218 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1223 Process
= PsGetCurrentProcess();
1224 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1225 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
1226 Length
= RawLength
- SegOffset
;
1227 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1229 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1231 else if (CacheSegOffset
>= PAGE_SIZE
)
1233 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1237 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1238 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1239 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1240 Status
= CcRosGetCacheSegment(Bcb
,
1241 (ULONG
)(FileOffset
+ CacheSegOffset
),
1246 if (!NT_SUCCESS(Status
))
1253 * If the cache segment isn't up to date then call the file
1254 * system to read in the data.
1256 Status
= ReadCacheSegment(CacheSeg
);
1257 if (!NT_SUCCESS(Status
))
1259 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1263 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1264 if (Length
< PAGE_SIZE
)
1266 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1270 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1273 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1274 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1276 return(STATUS_SUCCESS
);
1281 MiReadPage(PMEMORY_AREA MemoryArea
,
1285 * FUNCTION: Read a page for a section backed memory area.
1287 * MemoryArea - Memory area to read the page for.
1288 * Offset - Offset of the page to read.
1289 * Page - Variable that receives a page contains the read data.
1292 MM_REQUIRED_RESOURCES Resources
= { };
1294 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1295 Resources
.FileOffset
.QuadPart
= SegOffset
+
1296 MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
1297 Resources
.Consumer
= MC_USER
;
1298 Resources
.Amount
= PAGE_SIZE
;
1300 DPRINT1("%S, offset %x, len %d, page %x\n", ((PFILE_OBJECT
)Resources
.Context
)->FileName
.Buffer
, Resources
.FileOffset
.LowPart
, Resources
.Amount
, Resources
.Page
[0]);
1302 NTSTATUS Status
= MiReadFilePage(NULL
, NULL
, &Resources
);
1303 *Page
= Resources
.Page
[0];
1310 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1311 MEMORY_AREA
* MemoryArea
,
1317 PROS_SECTION_OBJECT Section
;
1318 PMM_SECTION_SEGMENT Segment
;
1324 BOOLEAN HasSwapEntry
;
1325 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1328 * There is a window between taking the page fault and locking the
1329 * address space when another thread could load the page so we check
1332 if (MmIsPagePresent(Process
, Address
))
1334 return(STATUS_SUCCESS
);
1338 * Check for the virtual memory area being deleted.
1340 if (MemoryArea
->DeleteInProgress
)
1342 return(STATUS_UNSUCCESSFUL
);
1345 Address
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1346 Offset
= (ULONG
)((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1347 + MemoryArea
->Data
.SectionData
.ViewOffset
);
1349 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1350 Section
= MemoryArea
->Data
.SectionData
.Section
;
1351 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1352 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1357 MmLockSectionSegment(Segment
);
1360 * Check if this page needs to be mapped COW
1362 if ((Segment
->WriteCopy
) &&
1363 (Region
->Protect
== PAGE_READWRITE
||
1364 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1366 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1370 Attributes
= Region
->Protect
;
1374 * Get or create a page operation descriptor
1376 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
1379 DPRINT1("MmGetPageOp failed\n");
1380 KeBugCheck(MEMORY_MANAGEMENT
);
1384 * Check if someone else is already handling this fault, if so wait
1387 if (PageOp
->Thread
!= PsGetCurrentThread())
1389 MmUnlockSectionSegment(Segment
);
1390 MmUnlockAddressSpace(AddressSpace
);
1391 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1393 * Check for various strange conditions
1395 if (Status
!= STATUS_SUCCESS
)
1397 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1398 KeBugCheck(MEMORY_MANAGEMENT
);
1400 if (PageOp
->Status
== STATUS_PENDING
)
1402 DPRINT1("Woke for page op before completion\n");
1403 KeBugCheck(MEMORY_MANAGEMENT
);
1405 MmLockAddressSpace(AddressSpace
);
1407 * If this wasn't a pagein then restart the operation
1409 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
1411 MmspCompleteAndReleasePageOp(PageOp
);
1412 DPRINT("Address 0x%.8X\n", Address
);
1413 return(STATUS_MM_RESTART_OPERATION
);
1417 * If the thread handling this fault has failed then we don't retry
1419 if (!NT_SUCCESS(PageOp
->Status
))
1421 Status
= PageOp
->Status
;
1422 MmspCompleteAndReleasePageOp(PageOp
);
1423 DPRINT("Address 0x%.8X\n", Address
);
1426 MmLockSectionSegment(Segment
);
1428 * If the completed fault was for another address space then set the
1431 if (!MmIsPagePresent(Process
, Address
))
1433 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1434 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)Address
);
1436 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
1439 * The page was a private page in another or in our address space
1441 MmUnlockSectionSegment(Segment
);
1442 MmspCompleteAndReleasePageOp(PageOp
);
1443 return(STATUS_MM_RESTART_OPERATION
);
1446 Page
= PFN_FROM_SSE(Entry
);
1448 MmSharePageEntrySectionSegment(Segment
, Offset
);
1450 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
1451 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
1453 Status
= MmCreateVirtualMapping(Process
,
1458 if (!NT_SUCCESS(Status
))
1460 DPRINT1("Unable to create virtual mapping\n");
1461 KeBugCheck(MEMORY_MANAGEMENT
);
1463 MmInsertRmap(Page
, Process
, Address
);
1465 MmUnlockSectionSegment(Segment
);
1466 PageOp
->Status
= STATUS_SUCCESS
;
1467 MmspCompleteAndReleasePageOp(PageOp
);
1468 DPRINT("Address 0x%.8X\n", Address
);
1469 return(STATUS_SUCCESS
);
1472 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1476 * Must be private page we have swapped out.
1478 SWAPENTRY SwapEntry
;
1483 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1485 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1486 KeBugCheck(MEMORY_MANAGEMENT
);
1489 MmUnlockSectionSegment(Segment
);
1490 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1492 MmUnlockAddressSpace(AddressSpace
);
1493 MI_SET_USAGE(MI_USAGE_SECTION
);
1494 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1495 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1496 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1497 if (!NT_SUCCESS(Status
))
1499 KeBugCheck(MEMORY_MANAGEMENT
);
1502 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1503 if (!NT_SUCCESS(Status
))
1505 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1506 KeBugCheck(MEMORY_MANAGEMENT
);
1508 MmLockAddressSpace(AddressSpace
);
1509 Status
= MmCreateVirtualMapping(Process
,
1514 if (!NT_SUCCESS(Status
))
1516 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1517 KeBugCheck(MEMORY_MANAGEMENT
);
1522 * Store the swap entry for later use.
1524 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1527 * Add the page to the process's working set
1529 MmInsertRmap(Page
, Process
, Address
);
1531 * Finish the operation
1533 PageOp
->Status
= STATUS_SUCCESS
;
1534 MmspCompleteAndReleasePageOp(PageOp
);
1535 DPRINT("Address 0x%.8X\n", Address
);
1536 return(STATUS_SUCCESS
);
1540 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1542 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1544 MmUnlockSectionSegment(Segment
);
1546 * Just map the desired physical page
1548 Page
= Offset
>> PAGE_SHIFT
;
1549 Status
= MmCreateVirtualMappingUnsafe(Process
,
1554 if (!NT_SUCCESS(Status
))
1556 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1557 KeBugCheck(MEMORY_MANAGEMENT
);
1562 * Cleanup and release locks
1564 PageOp
->Status
= STATUS_SUCCESS
;
1565 MmspCompleteAndReleasePageOp(PageOp
);
1566 DPRINT("Address 0x%.8X\n", Address
);
1567 return(STATUS_SUCCESS
);
1571 * Map anonymous memory for BSS sections
1573 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1575 MmUnlockSectionSegment(Segment
);
1576 MI_SET_USAGE(MI_USAGE_SECTION
);
1577 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1578 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1579 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1580 if (!NT_SUCCESS(Status
))
1582 MmUnlockAddressSpace(AddressSpace
);
1583 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1584 MmLockAddressSpace(AddressSpace
);
1586 if (!NT_SUCCESS(Status
))
1588 KeBugCheck(MEMORY_MANAGEMENT
);
1590 Status
= MmCreateVirtualMapping(Process
,
1595 if (!NT_SUCCESS(Status
))
1597 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1598 KeBugCheck(MEMORY_MANAGEMENT
);
1601 MmInsertRmap(Page
, Process
, Address
);
1604 * Cleanup and release locks
1606 PageOp
->Status
= STATUS_SUCCESS
;
1607 MmspCompleteAndReleasePageOp(PageOp
);
1608 DPRINT("Address 0x%.8X\n", Address
);
1609 return(STATUS_SUCCESS
);
1613 * Get the entry corresponding to the offset within the section
1615 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1620 * If the entry is zero (and it can't change because we have
1621 * locked the segment) then we need to load the page.
1625 * Release all our locks and read in the page from disk
1627 MmUnlockSectionSegment(Segment
);
1628 MmUnlockAddressSpace(AddressSpace
);
1630 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1631 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1633 MI_SET_USAGE(MI_USAGE_SECTION
);
1634 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1635 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1636 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1637 if (!NT_SUCCESS(Status
))
1639 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1645 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1646 if (!NT_SUCCESS(Status
))
1648 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1651 if (!NT_SUCCESS(Status
))
1654 * FIXME: What do we know in this case?
1657 * Cleanup and release locks
1659 MmLockAddressSpace(AddressSpace
);
1660 PageOp
->Status
= Status
;
1661 MmspCompleteAndReleasePageOp(PageOp
);
1662 DPRINT("Address 0x%.8X\n", Address
);
1666 * Relock the address space and segment
1668 MmLockAddressSpace(AddressSpace
);
1669 MmLockSectionSegment(Segment
);
1672 * Check the entry. No one should change the status of a page
1673 * that has a pending page-in.
1675 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1676 if (Entry
!= Entry1
)
1678 DPRINT1("Someone changed ppte entry while we slept\n");
1679 KeBugCheck(MEMORY_MANAGEMENT
);
1683 * Mark the offset within the section as having valid, in-memory
1686 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1687 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1688 MmUnlockSectionSegment(Segment
);
1690 Status
= MmCreateVirtualMapping(Process
,
1695 if (!NT_SUCCESS(Status
))
1697 DPRINT1("Unable to create virtual mapping\n");
1698 KeBugCheck(MEMORY_MANAGEMENT
);
1700 MmInsertRmap(Page
, Process
, Address
);
1702 PageOp
->Status
= STATUS_SUCCESS
;
1703 MmspCompleteAndReleasePageOp(PageOp
);
1704 DPRINT("Address 0x%.8X\n", Address
);
1705 return(STATUS_SUCCESS
);
1707 else if (IS_SWAP_FROM_SSE(Entry
))
1709 SWAPENTRY SwapEntry
;
1711 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1714 * Release all our locks and read in the page from disk
1716 MmUnlockSectionSegment(Segment
);
1718 MmUnlockAddressSpace(AddressSpace
);
1719 MI_SET_USAGE(MI_USAGE_SECTION
);
1720 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1721 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1722 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1723 if (!NT_SUCCESS(Status
))
1725 KeBugCheck(MEMORY_MANAGEMENT
);
1728 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1729 if (!NT_SUCCESS(Status
))
1731 KeBugCheck(MEMORY_MANAGEMENT
);
1735 * Relock the address space and segment
1737 MmLockAddressSpace(AddressSpace
);
1738 MmLockSectionSegment(Segment
);
1741 * Check the entry. No one should change the status of a page
1742 * that has a pending page-in.
1744 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1745 if (Entry
!= Entry1
)
1747 DPRINT1("Someone changed ppte entry while we slept\n");
1748 KeBugCheck(MEMORY_MANAGEMENT
);
1752 * Mark the offset within the section as having valid, in-memory
1755 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1756 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1757 MmUnlockSectionSegment(Segment
);
1760 * Save the swap entry.
1762 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1763 Status
= MmCreateVirtualMapping(Process
,
1768 if (!NT_SUCCESS(Status
))
1770 DPRINT1("Unable to create virtual mapping\n");
1771 KeBugCheck(MEMORY_MANAGEMENT
);
1773 MmInsertRmap(Page
, Process
, Address
);
1774 PageOp
->Status
= STATUS_SUCCESS
;
1775 MmspCompleteAndReleasePageOp(PageOp
);
1776 DPRINT("Address 0x%.8X\n", Address
);
1777 return(STATUS_SUCCESS
);
1782 * If the section offset is already in-memory and valid then just
1783 * take another reference to the page
1786 Page
= PFN_FROM_SSE(Entry
);
1788 MmSharePageEntrySectionSegment(Segment
, Offset
);
1789 MmUnlockSectionSegment(Segment
);
1791 Status
= MmCreateVirtualMapping(Process
,
1796 if (!NT_SUCCESS(Status
))
1798 DPRINT1("Unable to create virtual mapping\n");
1799 KeBugCheck(MEMORY_MANAGEMENT
);
1801 MmInsertRmap(Page
, Process
, Address
);
1802 PageOp
->Status
= STATUS_SUCCESS
;
1803 MmspCompleteAndReleasePageOp(PageOp
);
1804 DPRINT("Address 0x%.8X\n", Address
);
1805 return(STATUS_SUCCESS
);
1811 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1812 MEMORY_AREA
* MemoryArea
,
1815 PMM_SECTION_SEGMENT Segment
;
1816 PROS_SECTION_OBJECT Section
;
1824 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1826 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
);
1829 * Check if the page has already been set readwrite
1831 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1833 DPRINT("Address 0x%.8X\n", Address
);
1834 return(STATUS_SUCCESS
);
1838 * Find the offset of the page
1840 Address
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1841 Offset
= (ULONG
)((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1842 + MemoryArea
->Data
.SectionData
.ViewOffset
);
1844 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1845 Section
= MemoryArea
->Data
.SectionData
.Section
;
1846 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1847 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1852 MmLockSectionSegment(Segment
);
1854 OldPage
= MmGetPfnForProcess(Process
, Address
);
1855 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1857 MmUnlockSectionSegment(Segment
);
1860 * Check if we are doing COW
1862 if (!((Segment
->WriteCopy
) &&
1863 (Region
->Protect
== PAGE_READWRITE
||
1864 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1866 DPRINT("Address 0x%.8X\n", Address
);
1867 return(STATUS_ACCESS_VIOLATION
);
1870 if (IS_SWAP_FROM_SSE(Entry
) ||
1871 PFN_FROM_SSE(Entry
) != OldPage
)
1873 /* This is a private page. We must only change the page protection. */
1874 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1875 return(STATUS_SUCCESS
);
1879 * Get or create a pageop
1881 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1882 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1885 DPRINT1("MmGetPageOp failed\n");
1886 KeBugCheck(MEMORY_MANAGEMENT
);
1890 * Wait for any other operations to complete
1892 if (PageOp
->Thread
!= PsGetCurrentThread())
1894 MmUnlockAddressSpace(AddressSpace
);
1895 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1897 * Check for various strange conditions
1899 if (Status
== STATUS_TIMEOUT
)
1901 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1902 KeBugCheck(MEMORY_MANAGEMENT
);
1904 if (PageOp
->Status
== STATUS_PENDING
)
1906 DPRINT1("Woke for page op before completion\n");
1907 KeBugCheck(MEMORY_MANAGEMENT
);
1910 * Restart the operation
1912 MmLockAddressSpace(AddressSpace
);
1913 MmspCompleteAndReleasePageOp(PageOp
);
1914 DPRINT("Address 0x%.8X\n", Address
);
1915 return(STATUS_MM_RESTART_OPERATION
);
1919 * Release locks now we have the pageop
1921 MmUnlockAddressSpace(AddressSpace
);
1926 MI_SET_USAGE(MI_USAGE_SECTION
);
1927 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1928 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1929 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1930 if (!NT_SUCCESS(Status
))
1932 KeBugCheck(MEMORY_MANAGEMENT
);
1938 MiCopyFromUserPage(NewPage
, Address
);
1940 MmLockAddressSpace(AddressSpace
);
1942 * Delete the old entry.
1944 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1947 * Set the PTE to point to the new page
1949 Status
= MmCreateVirtualMapping(Process
,
1954 if (!NT_SUCCESS(Status
))
1956 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1957 KeBugCheck(MEMORY_MANAGEMENT
);
1960 if (!NT_SUCCESS(Status
))
1962 DPRINT1("Unable to create virtual mapping\n");
1963 KeBugCheck(MEMORY_MANAGEMENT
);
1967 * Unshare the old page.
1969 MmDeleteRmap(OldPage
, Process
, Address
);
1970 MmInsertRmap(NewPage
, Process
, Address
);
1971 MmLockSectionSegment(Segment
);
1972 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1973 MmUnlockSectionSegment(Segment
);
1975 PageOp
->Status
= STATUS_SUCCESS
;
1976 MmspCompleteAndReleasePageOp(PageOp
);
1977 DPRINT("Address 0x%.8X\n", Address
);
1978 return(STATUS_SUCCESS
);
1982 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1984 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1988 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1991 MmLockAddressSpace(&Process
->Vm
);
1994 MmDeleteVirtualMapping(Process
,
2001 PageOutContext
->WasDirty
= TRUE
;
2003 if (!PageOutContext
->Private
)
2005 MmLockSectionSegment(PageOutContext
->Segment
);
2006 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
2007 PageOutContext
->Segment
,
2008 PageOutContext
->Offset
,
2009 PageOutContext
->WasDirty
,
2011 MmUnlockSectionSegment(PageOutContext
->Segment
);
2015 MmUnlockAddressSpace(&Process
->Vm
);
2018 if (PageOutContext
->Private
)
2020 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2023 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
2028 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
2029 MEMORY_AREA
* MemoryArea
,
2034 MM_SECTION_PAGEOUT_CONTEXT Context
;
2035 SWAPENTRY SwapEntry
;
2039 PFILE_OBJECT FileObject
;
2043 BOOLEAN DirectMapped
;
2044 BOOLEAN IsImageSection
;
2045 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2048 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2051 * Get the segment and section.
2053 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2054 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
2056 Context
.Offset
= (ULONG
)((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2057 + MemoryArea
->Data
.SectionData
.ViewOffset
);
2058 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
2060 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2062 FileObject
= Context
.Section
->FileObject
;
2063 DirectMapped
= FALSE
;
2065 if (FileObject
!= NULL
&&
2066 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2068 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2071 * If the file system is letting us go directly to the cache and the
2072 * memory area was mapped at an offset in the file which is page aligned
2073 * then note this is a direct mapped page.
2075 if ((FileOffset
% PAGE_SIZE
) == 0 &&
2076 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
2078 DirectMapped
= TRUE
;
2085 * This should never happen since mappings of physical memory are never
2086 * placed in the rmap lists.
2088 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2090 DPRINT1("Trying to page out from physical memory section address 0x%X "
2091 "process %d\n", Address
,
2092 Process
? Process
->UniqueProcessId
: 0);
2093 KeBugCheck(MEMORY_MANAGEMENT
);
2097 * Get the section segment entry and the physical address.
2099 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
2100 if (!MmIsPagePresent(Process
, Address
))
2102 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2103 Process
? Process
->UniqueProcessId
: 0, Address
);
2104 KeBugCheck(MEMORY_MANAGEMENT
);
2106 Page
= MmGetPfnForProcess(Process
, Address
);
2107 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2110 * Prepare the context structure for the rmap delete call.
2112 Context
.WasDirty
= FALSE
;
2113 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2114 IS_SWAP_FROM_SSE(Entry
) ||
2115 PFN_FROM_SSE(Entry
) != Page
)
2117 Context
.Private
= TRUE
;
2121 Context
.Private
= FALSE
;
2125 * Take an additional reference to the page or the cache segment.
2127 if (DirectMapped
&& !Context
.Private
)
2129 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
2131 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2132 KeBugCheck(MEMORY_MANAGEMENT
);
2137 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
2138 MmReferencePage(Page
);
2139 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
2142 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2145 * If this wasn't a private page then we should have reduced the entry to
2146 * zero by deleting all the rmaps.
2148 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
2150 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2151 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2153 KeBugCheck(MEMORY_MANAGEMENT
);
2158 * If the page wasn't dirty then we can just free it as for a readonly page.
2159 * Since we unmapped all the mappings above we know it will not suddenly
2161 * If the page is from a pagefile section and has no swap entry,
2162 * we can't free the page at this point.
2164 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2165 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2167 if (Context
.Private
)
2169 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
2170 Context
.WasDirty
? "dirty" : "clean", Address
);
2171 KeBugCheck(MEMORY_MANAGEMENT
);
2173 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2175 MmSetSavedSwapEntryPage(Page
, 0);
2176 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2177 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2178 PageOp
->Status
= STATUS_SUCCESS
;
2179 MmspCompleteAndReleasePageOp(PageOp
);
2180 return(STATUS_SUCCESS
);
2183 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2185 if (Context
.Private
)
2187 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2188 Context
.WasDirty
? "dirty" : "clean", Address
);
2189 KeBugCheck(MEMORY_MANAGEMENT
);
2191 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2193 MmSetSavedSwapEntryPage(Page
, 0);
2196 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2198 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2199 PageOp
->Status
= STATUS_SUCCESS
;
2200 MmspCompleteAndReleasePageOp(PageOp
);
2201 return(STATUS_SUCCESS
);
2204 else if (!Context
.Private
&& DirectMapped
)
2208 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2210 KeBugCheck(MEMORY_MANAGEMENT
);
2213 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
2215 Status
= STATUS_SUCCESS
;
2217 if (!NT_SUCCESS(Status
))
2219 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2220 KeBugCheck(MEMORY_MANAGEMENT
);
2222 PageOp
->Status
= STATUS_SUCCESS
;
2223 MmspCompleteAndReleasePageOp(PageOp
);
2224 return(STATUS_SUCCESS
);
2226 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2230 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2232 KeBugCheck(MEMORY_MANAGEMENT
);
2234 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2235 PageOp
->Status
= STATUS_SUCCESS
;
2236 MmspCompleteAndReleasePageOp(PageOp
);
2237 return(STATUS_SUCCESS
);
2239 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2241 MmSetSavedSwapEntryPage(Page
, 0);
2242 MmLockAddressSpace(AddressSpace
);
2243 Status
= MmCreatePageFileMapping(Process
,
2246 MmUnlockAddressSpace(AddressSpace
);
2247 if (!NT_SUCCESS(Status
))
2249 KeBugCheck(MEMORY_MANAGEMENT
);
2251 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2252 PageOp
->Status
= STATUS_SUCCESS
;
2253 MmspCompleteAndReleasePageOp(PageOp
);
2254 return(STATUS_SUCCESS
);
2258 * If necessary, allocate an entry in the paging file for this page
2262 SwapEntry
= MmAllocSwapPage();
2265 MmShowOutOfSpaceMessagePagingFile();
2266 MmLockAddressSpace(AddressSpace
);
2268 * For private pages restore the old mappings.
2270 if (Context
.Private
)
2272 Status
= MmCreateVirtualMapping(Process
,
2274 MemoryArea
->Protect
,
2277 MmSetDirtyPage(Process
, Address
);
2285 * For non-private pages if the page wasn't direct mapped then
2286 * set it back into the section segment entry so we don't loose
2287 * our copy. Otherwise it will be handled by the cache manager.
2289 Status
= MmCreateVirtualMapping(Process
,
2291 MemoryArea
->Protect
,
2294 MmSetDirtyPage(Process
, Address
);
2298 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2299 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2301 MmUnlockAddressSpace(AddressSpace
);
2302 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2303 MmspCompleteAndReleasePageOp(PageOp
);
2304 return(STATUS_PAGEFILE_QUOTA
);
2309 * Write the page to the pagefile
2311 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2312 if (!NT_SUCCESS(Status
))
2314 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2317 * As above: undo our actions.
2318 * FIXME: Also free the swap page.
2320 MmLockAddressSpace(AddressSpace
);
2321 if (Context
.Private
)
2323 Status
= MmCreateVirtualMapping(Process
,
2325 MemoryArea
->Protect
,
2328 MmSetDirtyPage(Process
, Address
);
2335 Status
= MmCreateVirtualMapping(Process
,
2337 MemoryArea
->Protect
,
2340 MmSetDirtyPage(Process
, Address
);
2344 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2345 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2347 MmUnlockAddressSpace(AddressSpace
);
2348 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2349 MmspCompleteAndReleasePageOp(PageOp
);
2350 return(STATUS_UNSUCCESSFUL
);
2354 * Otherwise we have succeeded.
2356 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2357 MmSetSavedSwapEntryPage(Page
, 0);
2358 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2359 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2361 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2365 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2368 if (Context
.Private
)
2370 MmLockAddressSpace(AddressSpace
);
2371 Status
= MmCreatePageFileMapping(Process
,
2374 MmUnlockAddressSpace(AddressSpace
);
2375 if (!NT_SUCCESS(Status
))
2377 KeBugCheck(MEMORY_MANAGEMENT
);
2382 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2383 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2386 PageOp
->Status
= STATUS_SUCCESS
;
2387 MmspCompleteAndReleasePageOp(PageOp
);
2388 return(STATUS_SUCCESS
);
2393 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2394 PMEMORY_AREA MemoryArea
,
2399 PROS_SECTION_OBJECT Section
;
2400 PMM_SECTION_SEGMENT Segment
;
2402 SWAPENTRY SwapEntry
;
2406 PFILE_OBJECT FileObject
;
2408 BOOLEAN DirectMapped
;
2409 BOOLEAN IsImageSection
;
2410 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2412 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2414 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2415 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2418 * Get the segment and section.
2420 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2421 Section
= MemoryArea
->Data
.SectionData
.Section
;
2422 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2424 FileObject
= Section
->FileObject
;
2425 DirectMapped
= FALSE
;
2426 if (FileObject
!= NULL
&&
2427 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2429 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2432 * If the file system is letting us go directly to the cache and the
2433 * memory area was mapped at an offset in the file which is page aligned
2434 * then note this is a direct mapped page.
2436 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
2437 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
2439 DirectMapped
= TRUE
;
2444 * This should never happen since mappings of physical memory are never
2445 * placed in the rmap lists.
2447 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2449 DPRINT1("Trying to write back page from physical memory mapped at %X "
2450 "process %d\n", Address
,
2451 Process
? Process
->UniqueProcessId
: 0);
2452 KeBugCheck(MEMORY_MANAGEMENT
);
2456 * Get the section segment entry and the physical address.
2458 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2459 if (!MmIsPagePresent(Process
, Address
))
2461 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2462 Process
? Process
->UniqueProcessId
: 0, Address
);
2463 KeBugCheck(MEMORY_MANAGEMENT
);
2465 Page
= MmGetPfnForProcess(Process
, Address
);
2466 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2469 * Check for a private (COWed) page.
2471 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2472 IS_SWAP_FROM_SSE(Entry
) ||
2473 PFN_FROM_SSE(Entry
) != Page
)
2483 * Speculatively set all mappings of the page to clean.
2485 MmSetCleanAllRmaps(Page
);
2488 * If this page was direct mapped from the cache then the cache manager
2489 * will take care of writing it back to disk.
2491 if (DirectMapped
&& !Private
)
2493 ASSERT(SwapEntry
== 0);
2495 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)Offset
+ Segment
->FileOffset
);
2497 PageOp
->Status
= STATUS_SUCCESS
;
2498 MmspCompleteAndReleasePageOp(PageOp
);
2499 return(STATUS_SUCCESS
);
2503 * If necessary, allocate an entry in the paging file for this page
2507 SwapEntry
= MmAllocSwapPage();
2510 MmSetDirtyAllRmaps(Page
);
2511 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2512 MmspCompleteAndReleasePageOp(PageOp
);
2513 return(STATUS_PAGEFILE_QUOTA
);
2515 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2519 * Write the page to the pagefile
2521 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2522 if (!NT_SUCCESS(Status
))
2524 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2526 MmSetDirtyAllRmaps(Page
);
2527 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2528 MmspCompleteAndReleasePageOp(PageOp
);
2529 return(STATUS_UNSUCCESSFUL
);
2533 * Otherwise we have succeeded.
2535 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2536 PageOp
->Status
= STATUS_SUCCESS
;
2537 MmspCompleteAndReleasePageOp(PageOp
);
2538 return(STATUS_SUCCESS
);
2542 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2550 PMEMORY_AREA MemoryArea
;
2551 PMM_SECTION_SEGMENT Segment
;
2552 BOOLEAN DoCOW
= FALSE
;
2554 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2556 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2557 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2559 if ((Segment
->WriteCopy
) &&
2560 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2565 if (OldProtect
!= NewProtect
)
2567 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2569 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2570 ULONG Protect
= NewProtect
;
2573 * If we doing COW for this segment then check if the page is
2576 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2582 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2583 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2584 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2585 Page
= MmGetPfnForProcess(Process
, Address
);
2587 Protect
= PAGE_READONLY
;
2588 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2589 IS_SWAP_FROM_SSE(Entry
) ||
2590 PFN_FROM_SSE(Entry
) != Page
)
2592 Protect
= NewProtect
;
2596 if (MmIsPagePresent(Process
, Address
))
2598 MmSetPageProtect(Process
, Address
,
2607 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2608 PMEMORY_AREA MemoryArea
,
2616 ULONG_PTR MaxLength
;
2618 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2619 if (Length
> MaxLength
)
2620 Length
= (ULONG
)MaxLength
;
2622 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2623 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2625 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2626 Region
->Protect
!= Protect
)
2628 return STATUS_INVALID_PAGE_PROTECTION
;
2631 *OldProtect
= Region
->Protect
;
2632 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2633 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2634 BaseAddress
, Length
, Region
->Type
, Protect
,
2635 MmAlterViewAttributes
);
2641 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2643 PMEMORY_BASIC_INFORMATION Info
,
2644 PSIZE_T ResultLength
)
2647 PVOID RegionBaseAddress
;
2648 PROS_SECTION_OBJECT Section
;
2649 PMM_SECTION_SEGMENT Segment
;
2651 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2652 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2653 Address
, &RegionBaseAddress
);
2656 return STATUS_UNSUCCESSFUL
;
2659 Section
= MemoryArea
->Data
.SectionData
.Section
;
2660 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2662 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2663 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2664 Info
->Type
= MEM_IMAGE
;
2668 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2669 Info
->Type
= MEM_MAPPED
;
2671 Info
->BaseAddress
= RegionBaseAddress
;
2672 Info
->AllocationProtect
= MemoryArea
->Protect
;
2673 Info
->RegionSize
= Region
->Length
;
2674 Info
->State
= MEM_COMMIT
;
2675 Info
->Protect
= Region
->Protect
;
2677 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2678 return(STATUS_SUCCESS
);
2683 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2688 SWAPENTRY SavedSwapEntry
;
2693 Length
= PAGE_ROUND_UP(Segment
->Length
);
2694 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2696 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2699 if (IS_SWAP_FROM_SSE(Entry
))
2701 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2705 Page
= PFN_FROM_SSE(Entry
);
2706 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2707 if (SavedSwapEntry
!= 0)
2709 MmSetSavedSwapEntryPage(Page
, 0);
2710 MmFreeSwapPage(SavedSwapEntry
);
2712 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2714 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2720 MmpDeleteSection(PVOID ObjectBody
)
2722 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2724 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2725 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2730 PMM_SECTION_SEGMENT SectionSegments
;
2733 * NOTE: Section->ImageSection can be NULL for short time
2734 * during the section creating. If we fail for some reason
2735 * until the image section is properly initialized we shouldn't
2736 * process further here.
2738 if (Section
->ImageSection
== NULL
)
2741 SectionSegments
= Section
->ImageSection
->Segments
;
2742 NrSegments
= Section
->ImageSection
->NrSegments
;
2744 for (i
= 0; i
< NrSegments
; i
++)
2746 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2748 MmLockSectionSegment(&SectionSegments
[i
]);
2750 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2751 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2755 MmpFreePageFileSegment(&SectionSegments
[i
]);
2757 MmUnlockSectionSegment(&SectionSegments
[i
]);
2764 * NOTE: Section->Segment can be NULL for short time
2765 * during the section creating.
2767 if (Section
->Segment
== NULL
)
2770 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2772 MmpFreePageFileSegment(Section
->Segment
);
2773 MmFreePageTablesSectionSegment(Section
->Segment
);
2774 ExFreePool(Section
->Segment
);
2775 Section
->Segment
= NULL
;
2779 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2782 if (Section
->FileObject
!= NULL
)
2785 CcRosDereferenceCache(Section
->FileObject
);
2787 ObDereferenceObject(Section
->FileObject
);
2788 Section
->FileObject
= NULL
;
2793 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2795 IN ACCESS_MASK GrantedAccess
,
2796 IN ULONG ProcessHandleCount
,
2797 IN ULONG SystemHandleCount
)
2799 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2800 Object
, ProcessHandleCount
);
2806 MmCreatePhysicalMemorySection(VOID
)
2808 PROS_SECTION_OBJECT PhysSection
;
2810 OBJECT_ATTRIBUTES Obj
;
2811 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2812 LARGE_INTEGER SectionSize
;
2816 * Create the section mapping physical memory
2818 SectionSize
.QuadPart
= 0xFFFFFFFF;
2819 InitializeObjectAttributes(&Obj
,
2824 Status
= MmCreateSection((PVOID
)&PhysSection
,
2828 PAGE_EXECUTE_READWRITE
,
2832 if (!NT_SUCCESS(Status
))
2834 DPRINT1("Failed to create PhysicalMemory section\n");
2835 KeBugCheck(MEMORY_MANAGEMENT
);
2837 Status
= ObInsertObject(PhysSection
,
2843 if (!NT_SUCCESS(Status
))
2845 ObDereferenceObject(PhysSection
);
2847 ObCloseHandle(Handle
, KernelMode
);
2848 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2849 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2851 return(STATUS_SUCCESS
);
2857 MmInitSectionImplementation(VOID
)
2859 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2860 UNICODE_STRING Name
;
2862 DPRINT("Creating Section Object Type\n");
2864 /* Initialize the Section object type */
2865 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2866 RtlInitUnicodeString(&Name
, L
"Section");
2867 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2868 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2869 ObjectTypeInitializer
.PoolType
= PagedPool
;
2870 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2871 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2872 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2873 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2874 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2875 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2877 MmCreatePhysicalMemorySection();
2879 return(STATUS_SUCCESS
);
2884 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2885 ACCESS_MASK DesiredAccess
,
2886 POBJECT_ATTRIBUTES ObjectAttributes
,
2887 PLARGE_INTEGER UMaximumSize
,
2888 ULONG SectionPageProtection
,
2889 ULONG AllocationAttributes
)
2891 * Create a section which is backed by the pagefile
2894 LARGE_INTEGER MaximumSize
;
2895 PROS_SECTION_OBJECT Section
;
2896 PMM_SECTION_SEGMENT Segment
;
2899 if (UMaximumSize
== NULL
)
2901 return(STATUS_UNSUCCESSFUL
);
2903 MaximumSize
= *UMaximumSize
;
2906 * Create the section
2908 Status
= ObCreateObject(ExGetPreviousMode(),
2909 MmSectionObjectType
,
2911 ExGetPreviousMode(),
2913 sizeof(ROS_SECTION_OBJECT
),
2916 (PVOID
*)(PVOID
)&Section
);
2917 if (!NT_SUCCESS(Status
))
2925 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2926 Section
->SectionPageProtection
= SectionPageProtection
;
2927 Section
->AllocationAttributes
= AllocationAttributes
;
2928 Section
->MaximumSize
= MaximumSize
;
2929 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2930 TAG_MM_SECTION_SEGMENT
);
2931 if (Segment
== NULL
)
2933 ObDereferenceObject(Section
);
2934 return(STATUS_NO_MEMORY
);
2936 Section
->Segment
= Segment
;
2937 Segment
->ReferenceCount
= 1;
2938 ExInitializeFastMutex(&Segment
->Lock
);
2939 Segment
->FileOffset
= 0;
2940 Segment
->Protection
= SectionPageProtection
;
2941 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2942 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2943 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2944 Segment
->WriteCopy
= FALSE
;
2945 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2946 Segment
->VirtualAddress
= 0;
2947 Segment
->Characteristics
= 0;
2948 *SectionObject
= Section
;
2949 return(STATUS_SUCCESS
);
2955 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2956 ACCESS_MASK DesiredAccess
,
2957 POBJECT_ATTRIBUTES ObjectAttributes
,
2958 PLARGE_INTEGER UMaximumSize
,
2959 ULONG SectionPageProtection
,
2960 ULONG AllocationAttributes
,
2963 * Create a section backed by a data file
2966 PROS_SECTION_OBJECT Section
;
2968 LARGE_INTEGER MaximumSize
;
2969 PFILE_OBJECT FileObject
;
2970 PMM_SECTION_SEGMENT Segment
;
2972 IO_STATUS_BLOCK Iosb
;
2973 LARGE_INTEGER Offset
;
2975 FILE_STANDARD_INFORMATION FileInfo
;
2979 * Create the section
2981 Status
= ObCreateObject(ExGetPreviousMode(),
2982 MmSectionObjectType
,
2984 ExGetPreviousMode(),
2986 sizeof(ROS_SECTION_OBJECT
),
2989 (PVOID
*)(PVOID
)&Section
);
2990 if (!NT_SUCCESS(Status
))
2997 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2998 Section
->SectionPageProtection
= SectionPageProtection
;
2999 Section
->AllocationAttributes
= AllocationAttributes
;
3002 * Check file access required
3004 if (SectionPageProtection
& PAGE_READWRITE
||
3005 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3007 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3011 FileAccess
= FILE_READ_DATA
;
3015 * Reference the file handle
3017 Status
= ObReferenceObjectByHandle(FileHandle
,
3020 ExGetPreviousMode(),
3021 (PVOID
*)(PVOID
)&FileObject
,
3023 if (!NT_SUCCESS(Status
))
3025 ObDereferenceObject(Section
);
3030 * FIXME: This is propably not entirely correct. We can't look into
3031 * the standard FCB header because it might not be initialized yet
3032 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
3033 * standard file information is filled on first request).
3035 Status
= IoQueryFileInformation(FileObject
,
3036 FileStandardInformation
,
3037 sizeof(FILE_STANDARD_INFORMATION
),
3040 Iosb
.Information
= Length
;
3041 if (!NT_SUCCESS(Status
))
3043 ObDereferenceObject(Section
);
3044 ObDereferenceObject(FileObject
);
3049 * FIXME: Revise this once a locking order for file size changes is
3052 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
3054 MaximumSize
= *UMaximumSize
;
3058 MaximumSize
= FileInfo
.EndOfFile
;
3059 /* Mapping zero-sized files isn't allowed. */
3060 if (MaximumSize
.QuadPart
== 0)
3062 ObDereferenceObject(Section
);
3063 ObDereferenceObject(FileObject
);
3064 return STATUS_FILE_INVALID
;
3068 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3070 Status
= IoSetInformation(FileObject
,
3071 FileAllocationInformation
,
3072 sizeof(LARGE_INTEGER
),
3074 if (!NT_SUCCESS(Status
))
3076 ObDereferenceObject(Section
);
3077 ObDereferenceObject(FileObject
);
3078 return(STATUS_SECTION_NOT_EXTENDED
);
3082 if (FileObject
->SectionObjectPointer
== NULL
||
3083 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3086 * Read a bit so caching is initiated for the file object.
3087 * This is only needed because MiReadPage currently cannot
3088 * handle non-cached streams.
3090 Offset
.QuadPart
= 0;
3091 Status
= ZwReadFile(FileHandle
,
3100 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3102 ObDereferenceObject(Section
);
3103 ObDereferenceObject(FileObject
);
3106 if (FileObject
->SectionObjectPointer
== NULL
||
3107 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3109 /* FIXME: handle this situation */
3110 ObDereferenceObject(Section
);
3111 ObDereferenceObject(FileObject
);
3112 return STATUS_INVALID_PARAMETER
;
3119 Status
= MmspWaitForFileLock(FileObject
);
3120 if (Status
!= STATUS_SUCCESS
)
3122 ObDereferenceObject(Section
);
3123 ObDereferenceObject(FileObject
);
3128 * If this file hasn't been mapped as a data file before then allocate a
3129 * section segment to describe the data file mapping
3131 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3133 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3134 TAG_MM_SECTION_SEGMENT
);
3135 if (Segment
== NULL
)
3137 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3138 ObDereferenceObject(Section
);
3139 ObDereferenceObject(FileObject
);
3140 return(STATUS_NO_MEMORY
);
3142 Section
->Segment
= Segment
;
3143 Segment
->ReferenceCount
= 1;
3144 ExInitializeFastMutex(&Segment
->Lock
);
3146 * Set the lock before assigning the segment to the file object
3148 ExAcquireFastMutex(&Segment
->Lock
);
3149 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3151 Segment
->FileOffset
= 0;
3152 Segment
->Protection
= SectionPageProtection
;
3153 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3154 Segment
->Characteristics
= 0;
3155 Segment
->WriteCopy
= FALSE
;
3156 if (AllocationAttributes
& SEC_RESERVE
)
3158 Segment
->Length
= Segment
->RawLength
= 0;
3162 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3163 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3165 Segment
->VirtualAddress
= 0;
3166 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
3171 * If the file is already mapped as a data file then we may need
3175 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3177 Section
->Segment
= Segment
;
3178 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3179 MmLockSectionSegment(Segment
);
3181 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
3182 !(AllocationAttributes
& SEC_RESERVE
))
3184 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3185 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3188 MmUnlockSectionSegment(Segment
);
3189 Section
->FileObject
= FileObject
;
3190 Section
->MaximumSize
= MaximumSize
;
3192 CcRosReferenceCache(FileObject
);
3194 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3195 *SectionObject
= Section
;
3196 return(STATUS_SUCCESS
);
3200 TODO: not that great (declaring loaders statically, having to declare all of
3201 them, having to keep them extern, etc.), will fix in the future
3203 extern NTSTATUS NTAPI PeFmtCreateSection
3205 IN CONST VOID
* FileHeader
,
3206 IN SIZE_T FileHeaderSize
,
3208 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3210 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3211 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3214 extern NTSTATUS NTAPI ElfFmtCreateSection
3216 IN CONST VOID
* FileHeader
,
3217 IN SIZE_T FileHeaderSize
,
3219 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3221 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3222 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3225 /* TODO: this is a standard DDK/PSDK macro */
3226 #ifndef RTL_NUMBER_OF
3227 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3230 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3241 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3243 SIZE_T SizeOfSegments
;
3244 PMM_SECTION_SEGMENT Segments
;
3246 /* TODO: check for integer overflow */
3247 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3249 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3251 TAG_MM_SECTION_SEGMENT
);
3254 RtlZeroMemory(Segments
, SizeOfSegments
);
3262 ExeFmtpReadFile(IN PVOID File
,
3263 IN PLARGE_INTEGER Offset
,
3266 OUT PVOID
* AllocBase
,
3267 OUT PULONG ReadSize
)
3270 LARGE_INTEGER FileOffset
;
3272 ULONG OffsetAdjustment
;
3277 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3281 KeBugCheck(MEMORY_MANAGEMENT
);
3284 FileOffset
= *Offset
;
3286 /* Negative/special offset: it cannot be used in this context */
3287 if(FileOffset
.u
.HighPart
< 0)
3289 KeBugCheck(MEMORY_MANAGEMENT
);
3292 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3293 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3294 FileOffset
.u
.LowPart
= AdjustOffset
;
3296 BufferSize
= Length
+ OffsetAdjustment
;
3297 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3300 * It's ok to use paged pool, because this is a temporary buffer only used in
3301 * the loading of executables. The assumption is that MmCreateSection is
3302 * always called at low IRQLs and that these buffers don't survive a brief
3303 * initialization phase
3305 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3310 KeBugCheck(MEMORY_MANAGEMENT
);
3316 Status
= MmspPageRead(File
,
3323 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
3324 * nothing will work. But using ZwReadFile is wrong, and using its side effects
3325 * to initialize internal state is even worse. Our cache manager is in need of
3329 IO_STATUS_BLOCK Iosb
;
3331 Status
= ZwReadFile(File
,
3341 if(NT_SUCCESS(Status
))
3343 UsedSize
= (ULONG
)Iosb
.Information
;
3348 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3350 Status
= STATUS_IN_PAGE_ERROR
;
3351 ASSERT(!NT_SUCCESS(Status
));
3354 if(NT_SUCCESS(Status
))
3356 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3357 *AllocBase
= Buffer
;
3358 *ReadSize
= UsedSize
- OffsetAdjustment
;
3362 ExFreePoolWithTag(Buffer
, 'rXmM');
3369 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3370 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3371 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3376 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3380 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3382 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3383 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
3390 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3394 MmspAssertSegmentsSorted(ImageSectionObject
);
3396 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3398 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
3402 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3403 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3404 ImageSectionObject
->Segments
[i
- 1].Length
));
3412 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3416 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3418 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
3419 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
3427 MmspCompareSegments(const void * x
,
3430 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3431 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3434 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
3435 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3439 * Ensures an image section's segments are sorted in memory
3444 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3447 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3449 MmspAssertSegmentsSorted(ImageSectionObject
);
3453 qsort(ImageSectionObject
->Segments
,
3454 ImageSectionObject
->NrSegments
,
3455 sizeof(ImageSectionObject
->Segments
[0]),
3456 MmspCompareSegments
);
3462 * Ensures an image section's segments don't overlap in memory and don't have
3463 * gaps and don't have a null size. We let them map to overlapping file regions,
3464 * though - that's not necessarily an error
3469 MmspCheckSegmentBounds
3471 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3477 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3479 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3483 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3485 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3487 if(ImageSectionObject
->Segments
[i
].Length
== 0)
3495 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3496 * page could be OK (Windows seems to be OK with them), and larger gaps
3497 * could lead to image sections spanning several discontiguous regions
3498 * (NtMapViewOfSection could then refuse to map them, and they could
3499 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3501 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3502 ImageSectionObject
->Segments
[i
- 1].Length
) !=
3503 ImageSectionObject
->Segments
[i
].VirtualAddress
)
3514 * Merges and pads an image section's segments until they all are page-aligned
3515 * and have a size that is a multiple of the page size
3520 MmspPageAlignSegments
3522 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3528 PMM_SECTION_SEGMENT EffectiveSegment
;
3530 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3532 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3537 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3539 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3542 * The first segment requires special handling
3546 ULONG_PTR VirtualAddress
;
3547 ULONG_PTR VirtualOffset
;
3549 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3551 /* Round down the virtual address to the nearest page */
3552 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3554 /* Round up the virtual size to the nearest page */
3555 EffectiveSegment
->Length
= (ULONG
)(PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3556 EffectiveSegment
->VirtualAddress
);
3558 /* Adjust the raw address and size */
3559 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3561 if (EffectiveSegment
->FileOffset
< (LONG_PTR
)VirtualOffset
)
3567 * Garbage in, garbage out: unaligned base addresses make the file
3568 * offset point in curious and odd places, but that's what we were
3571 EffectiveSegment
->FileOffset
-= (ULONG
)VirtualOffset
;
3572 EffectiveSegment
->RawLength
+= (ULONG
)VirtualOffset
;
3576 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3577 ULONG_PTR EndOfEffectiveSegment
;
3579 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3580 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3583 * The current segment begins exactly where the current effective
3584 * segment ended, therefore beginning a new effective segment
3586 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3589 ASSERT(LastSegment
<= i
);
3590 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3592 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3594 if (LastSegment
!= i
)
3597 * Copy the current segment. If necessary, the effective segment
3598 * will be expanded later
3600 *EffectiveSegment
= *Segment
;
3604 * Page-align the virtual size. We know for sure the virtual address
3607 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3608 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3611 * The current segment is still part of the current effective segment:
3612 * extend the effective segment to reflect this
3614 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3616 static const ULONG FlagsToProtection
[16] =
3624 PAGE_EXECUTE_READWRITE
,
3625 PAGE_EXECUTE_READWRITE
,
3630 PAGE_EXECUTE_WRITECOPY
,
3631 PAGE_EXECUTE_WRITECOPY
,
3632 PAGE_EXECUTE_WRITECOPY
,
3633 PAGE_EXECUTE_WRITECOPY
3636 unsigned ProtectionFlags
;
3639 * Extend the file size
3642 /* Unaligned segments must be contiguous within the file */
3643 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3644 EffectiveSegment
->RawLength
))
3649 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3652 * Extend the virtual size
3654 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3656 EffectiveSegment
->Length
= (ULONG
)(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3657 EffectiveSegment
->VirtualAddress
);
3660 * Merge the protection
3662 EffectiveSegment
->Protection
|= Segment
->Protection
;
3664 /* Clean up redundance */
3665 ProtectionFlags
= 0;
3667 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3668 ProtectionFlags
|= 1 << 0;
3670 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3671 ProtectionFlags
|= 1 << 1;
3673 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3674 ProtectionFlags
|= 1 << 2;
3676 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3677 ProtectionFlags
|= 1 << 3;
3679 ASSERT(ProtectionFlags
< 16);
3680 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3682 /* If a segment was required to be shared and cannot, fail */
3683 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3684 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3690 * We assume no holes between segments at this point
3694 KeBugCheck(MEMORY_MANAGEMENT
);
3698 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3704 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3705 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3707 LARGE_INTEGER Offset
;
3709 PVOID FileHeaderBuffer
;
3710 ULONG FileHeaderSize
;
3712 ULONG OldNrSegments
;
3717 * Read the beginning of the file (2 pages). Should be enough to contain
3718 * all (or most) of the headers
3720 Offset
.QuadPart
= 0;
3722 /* FIXME: use FileObject instead of FileHandle */
3723 Status
= ExeFmtpReadFile (FileHandle
,
3730 if (!NT_SUCCESS(Status
))
3733 if (FileHeaderSize
== 0)
3735 ExFreePool(FileHeaderBuffer
);
3736 return STATUS_UNSUCCESSFUL
;
3740 * Look for a loader that can handle this executable
3742 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3744 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3747 /* FIXME: use FileObject instead of FileHandle */
3748 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3754 ExeFmtpAllocateSegments
);
3756 if (!NT_SUCCESS(Status
))
3758 if (ImageSectionObject
->Segments
)
3760 ExFreePool(ImageSectionObject
->Segments
);
3761 ImageSectionObject
->Segments
= NULL
;
3765 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3769 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3772 * No loader handled the format
3774 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3776 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3777 ASSERT(!NT_SUCCESS(Status
));
3780 if (!NT_SUCCESS(Status
))
3783 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3788 /* FIXME? are these values platform-dependent? */
3789 if(ImageSectionObject
->StackReserve
== 0)
3790 ImageSectionObject
->StackReserve
= 0x40000;
3792 if(ImageSectionObject
->StackCommit
== 0)
3793 ImageSectionObject
->StackCommit
= 0x1000;
3795 if(ImageSectionObject
->ImageBase
== 0)
3797 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3798 ImageSectionObject
->ImageBase
= 0x10000000;
3800 ImageSectionObject
->ImageBase
= 0x00400000;
3804 * And now the fun part: fixing the segments
3807 /* Sort them by virtual address */
3808 MmspSortSegments(ImageSectionObject
, Flags
);
3810 /* Ensure they don't overlap in memory */
3811 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3812 return STATUS_INVALID_IMAGE_FORMAT
;
3814 /* Ensure they are aligned */
3815 OldNrSegments
= ImageSectionObject
->NrSegments
;
3817 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3818 return STATUS_INVALID_IMAGE_FORMAT
;
3820 /* Trim them if the alignment phase merged some of them */
3821 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3823 PMM_SECTION_SEGMENT Segments
;
3824 SIZE_T SizeOfSegments
;
3826 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3828 Segments
= ExAllocatePoolWithTag(PagedPool
,
3830 TAG_MM_SECTION_SEGMENT
);
3832 if (Segments
== NULL
)
3833 return STATUS_INSUFFICIENT_RESOURCES
;
3835 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3836 ExFreePool(ImageSectionObject
->Segments
);
3837 ImageSectionObject
->Segments
= Segments
;
3840 /* And finish their initialization */
3841 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3843 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3844 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3846 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3847 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3850 ASSERT(NT_SUCCESS(Status
));
3855 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3856 ACCESS_MASK DesiredAccess
,
3857 POBJECT_ATTRIBUTES ObjectAttributes
,
3858 PLARGE_INTEGER UMaximumSize
,
3859 ULONG SectionPageProtection
,
3860 ULONG AllocationAttributes
,
3863 PROS_SECTION_OBJECT Section
;
3865 PFILE_OBJECT FileObject
;
3866 PMM_SECTION_SEGMENT SectionSegments
;
3867 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3869 ULONG FileAccess
= 0;
3872 * Check file access required
3874 if (SectionPageProtection
& PAGE_READWRITE
||
3875 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3877 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3881 FileAccess
= FILE_READ_DATA
;
3885 * Reference the file handle
3887 Status
= ObReferenceObjectByHandle(FileHandle
,
3890 ExGetPreviousMode(),
3891 (PVOID
*)(PVOID
)&FileObject
,
3894 if (!NT_SUCCESS(Status
))
3900 * Create the section
3902 Status
= ObCreateObject (ExGetPreviousMode(),
3903 MmSectionObjectType
,
3905 ExGetPreviousMode(),
3907 sizeof(ROS_SECTION_OBJECT
),
3910 (PVOID
*)(PVOID
)&Section
);
3911 if (!NT_SUCCESS(Status
))
3913 ObDereferenceObject(FileObject
);
3920 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3921 Section
->SectionPageProtection
= SectionPageProtection
;
3922 Section
->AllocationAttributes
= AllocationAttributes
;
3926 * Initialized caching for this file object if previously caching
3927 * was initialized for the same on disk file
3929 Status
= CcTryToInitializeFileCache(FileObject
);
3931 Status
= STATUS_SUCCESS
;
3934 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3936 NTSTATUS StatusExeFmt
;
3938 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3939 if (ImageSectionObject
== NULL
)
3941 ObDereferenceObject(FileObject
);
3942 ObDereferenceObject(Section
);
3943 return(STATUS_NO_MEMORY
);
3946 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3948 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3950 if (!NT_SUCCESS(StatusExeFmt
))
3952 if(ImageSectionObject
->Segments
!= NULL
)
3953 ExFreePool(ImageSectionObject
->Segments
);
3955 ExFreePool(ImageSectionObject
);
3956 ObDereferenceObject(Section
);
3957 ObDereferenceObject(FileObject
);
3958 return(StatusExeFmt
);
3961 Section
->ImageSection
= ImageSectionObject
;
3962 ASSERT(ImageSectionObject
->Segments
);
3967 Status
= MmspWaitForFileLock(FileObject
);
3968 if (!NT_SUCCESS(Status
))
3970 ExFreePool(ImageSectionObject
->Segments
);
3971 ExFreePool(ImageSectionObject
);
3972 ObDereferenceObject(Section
);
3973 ObDereferenceObject(FileObject
);
3977 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3978 ImageSectionObject
, NULL
))
3981 * An other thread has initialized the same image in the background
3983 ExFreePool(ImageSectionObject
->Segments
);
3984 ExFreePool(ImageSectionObject
);
3985 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3986 Section
->ImageSection
= ImageSectionObject
;
3987 SectionSegments
= ImageSectionObject
->Segments
;
3989 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3991 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3995 Status
= StatusExeFmt
;
4002 Status
= MmspWaitForFileLock(FileObject
);
4003 if (Status
!= STATUS_SUCCESS
)
4005 ObDereferenceObject(Section
);
4006 ObDereferenceObject(FileObject
);
4010 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
4011 Section
->ImageSection
= ImageSectionObject
;
4012 SectionSegments
= ImageSectionObject
->Segments
;
4015 * Otherwise just reference all the section segments
4017 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
4019 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
4022 Status
= STATUS_SUCCESS
;
4024 Section
->FileObject
= FileObject
;
4026 CcRosReferenceCache(FileObject
);
4028 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
4029 *SectionObject
= Section
;
4036 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
4037 PROS_SECTION_OBJECT Section
,
4038 PMM_SECTION_SEGMENT Segment
,
4043 ULONG AllocationType
)
4047 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4049 BoundaryAddressMultiple
.QuadPart
= 0;
4051 Status
= MmCreateMemoryArea(AddressSpace
,
4052 MEMORY_AREA_SECTION_VIEW
,
4059 BoundaryAddressMultiple
);
4060 if (!NT_SUCCESS(Status
))
4062 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
4063 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
4067 ObReferenceObject((PVOID
)Section
);
4069 MArea
->Data
.SectionData
.Segment
= Segment
;
4070 MArea
->Data
.SectionData
.Section
= Section
;
4071 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
4072 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
4073 ViewSize
, 0, Protect
);
4075 return(STATUS_SUCCESS
);
4081 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
4082 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4085 PFILE_OBJECT FileObject
;
4088 SWAPENTRY SavedSwapEntry
;
4091 PROS_SECTION_OBJECT Section
;
4092 PMM_SECTION_SEGMENT Segment
;
4093 PMMSUPPORT AddressSpace
;
4096 AddressSpace
= (PMMSUPPORT
)Context
;
4097 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4099 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4101 Offset
= (ULONG
)(((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
4102 MemoryArea
->Data
.SectionData
.ViewOffset
);
4104 Section
= MemoryArea
->Data
.SectionData
.Section
;
4105 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4107 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4111 MmUnlockSectionSegment(Segment
);
4112 MmUnlockAddressSpace(AddressSpace
);
4114 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4115 if (Status
!= STATUS_SUCCESS
)
4117 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4118 KeBugCheck(MEMORY_MANAGEMENT
);
4121 MmLockAddressSpace(AddressSpace
);
4122 MmLockSectionSegment(Segment
);
4123 MmspCompleteAndReleasePageOp(PageOp
);
4124 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4127 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
4130 * For a dirty, datafile, non-private page mark it as dirty in the
4133 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4135 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4137 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4138 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4140 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
4142 ASSERT(SwapEntry
== 0);
4151 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4153 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4154 KeBugCheck(MEMORY_MANAGEMENT
);
4156 MmFreeSwapPage(SwapEntry
);
4160 if (IS_SWAP_FROM_SSE(Entry
) ||
4161 Page
!= PFN_FROM_SSE(Entry
))
4166 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4168 DPRINT1("Found a private page in a pagefile section.\n");
4169 KeBugCheck(MEMORY_MANAGEMENT
);
4172 * Just dereference private pages
4174 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4175 if (SavedSwapEntry
!= 0)
4177 MmFreeSwapPage(SavedSwapEntry
);
4178 MmSetSavedSwapEntryPage(Page
, 0);
4180 MmDeleteRmap(Page
, Process
, Address
);
4181 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4185 MmDeleteRmap(Page
, Process
, Address
);
4186 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4192 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4196 PMEMORY_AREA MemoryArea
;
4197 PROS_SECTION_OBJECT Section
;
4198 PMM_SECTION_SEGMENT Segment
;
4199 PLIST_ENTRY CurrentEntry
;
4200 PMM_REGION CurrentRegion
;
4201 PLIST_ENTRY RegionListHead
;
4203 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4205 if (MemoryArea
== NULL
)
4207 return(STATUS_UNSUCCESSFUL
);
4210 MemoryArea
->DeleteInProgress
= TRUE
;
4211 Section
= MemoryArea
->Data
.SectionData
.Section
;
4212 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4214 MmLockSectionSegment(Segment
);
4216 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4217 while (!IsListEmpty(RegionListHead
))
4219 CurrentEntry
= RemoveHeadList(RegionListHead
);
4220 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4221 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4224 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4226 Status
= MmFreeMemoryArea(AddressSpace
,
4233 Status
= MmFreeMemoryArea(AddressSpace
,
4238 MmUnlockSectionSegment(Segment
);
4239 ObDereferenceObject(Section
);
4247 MmUnmapViewOfSection(PEPROCESS Process
,
4251 PMEMORY_AREA MemoryArea
;
4252 PMMSUPPORT AddressSpace
;
4253 PROS_SECTION_OBJECT Section
;
4256 PVOID ImageBaseAddress
= 0;
4258 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4259 Process
, BaseAddress
);
4263 AddressSpace
= &Process
->Vm
;
4265 MmLockAddressSpace(AddressSpace
);
4266 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4268 if (MemoryArea
== NULL
||
4269 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4270 MemoryArea
->DeleteInProgress
)
4272 MmUnlockAddressSpace(AddressSpace
);
4273 return STATUS_NOT_MAPPED_VIEW
;
4276 MemoryArea
->DeleteInProgress
= TRUE
;
4278 while (MemoryArea
->PageOpCount
)
4280 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4284 Offset
-= PAGE_SIZE
;
4285 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4286 MemoryArea
->Data
.SectionData
.Segment
,
4287 (ULONG
)Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4290 MmUnlockAddressSpace(AddressSpace
);
4291 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4292 if (Status
!= STATUS_SUCCESS
)
4294 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4295 KeBugCheck(MEMORY_MANAGEMENT
);
4297 MmLockAddressSpace(AddressSpace
);
4298 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4300 if (MemoryArea
== NULL
||
4301 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4303 MmUnlockAddressSpace(AddressSpace
);
4304 return STATUS_NOT_MAPPED_VIEW
;
4311 Section
= MemoryArea
->Data
.SectionData
.Section
;
4313 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4317 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4318 PMM_SECTION_SEGMENT SectionSegments
;
4319 PMM_SECTION_SEGMENT Segment
;
4321 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4322 ImageSectionObject
= Section
->ImageSection
;
4323 SectionSegments
= ImageSectionObject
->Segments
;
4324 NrSegments
= ImageSectionObject
->NrSegments
;
4326 /* Search for the current segment within the section segments
4327 * and calculate the image base address */
4328 for (i
= 0; i
< NrSegments
; i
++)
4330 if (Segment
== &SectionSegments
[i
])
4332 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4336 if (i
>= NrSegments
)
4338 KeBugCheck(MEMORY_MANAGEMENT
);
4341 for (i
= 0; i
< NrSegments
; i
++)
4343 PVOID SBaseAddress
= (PVOID
)
4344 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4346 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4351 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4354 MmUnlockAddressSpace(AddressSpace
);
4356 /* Notify debugger */
4357 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4359 return(STATUS_SUCCESS
);
4366 * Queries the information of a section object.
4368 * @param SectionHandle
4369 * Handle to the section object. It must be opened with SECTION_QUERY
4371 * @param SectionInformationClass
4372 * Index to a certain information structure. Can be either
4373 * SectionBasicInformation or SectionImageInformation. The latter
4374 * is valid only for sections that were created with the SEC_IMAGE
4376 * @param SectionInformation
4377 * Caller supplies storage for resulting information.
4379 * Size of the supplied storage.
4380 * @param ResultLength
4388 NtQuerySection(IN HANDLE SectionHandle
,
4389 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4390 OUT PVOID SectionInformation
,
4391 IN SIZE_T SectionInformationLength
,
4392 OUT PSIZE_T ResultLength OPTIONAL
)
4394 PROS_SECTION_OBJECT Section
;
4395 KPROCESSOR_MODE PreviousMode
;
4399 PreviousMode
= ExGetPreviousMode();
4401 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4403 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4405 (ULONG
)SectionInformationLength
,
4410 if(!NT_SUCCESS(Status
))
4412 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4416 Status
= ObReferenceObjectByHandle(SectionHandle
,
4418 MmSectionObjectType
,
4420 (PVOID
*)(PVOID
)&Section
,
4422 if (NT_SUCCESS(Status
))
4424 switch (SectionInformationClass
)
4426 case SectionBasicInformation
:
4428 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4432 Sbi
->Attributes
= Section
->AllocationAttributes
;
4433 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4435 Sbi
->BaseAddress
= 0;
4436 Sbi
->Size
.QuadPart
= 0;
4440 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4441 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4444 if (ResultLength
!= NULL
)
4446 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4448 Status
= STATUS_SUCCESS
;
4450 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4452 Status
= _SEH2_GetExceptionCode();
4459 case SectionImageInformation
:
4461 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4465 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4466 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4468 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4469 ImageSectionObject
= Section
->ImageSection
;
4471 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4472 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4473 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4474 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4475 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4476 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4477 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4478 Sii
->Machine
= ImageSectionObject
->Machine
;
4479 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4482 if (ResultLength
!= NULL
)
4484 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4486 Status
= STATUS_SUCCESS
;
4488 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4490 Status
= _SEH2_GetExceptionCode();
4498 ObDereferenceObject(Section
);
4504 /**********************************************************************
4506 * MmMapViewOfSection
4509 * Maps a view of a section into the virtual address space of a
4514 * Pointer to the section object.
4517 * Pointer to the process.
4520 * Desired base address (or NULL) on entry;
4521 * Actual base address of the view on exit.
4524 * Number of high order address bits that must be zero.
4527 * Size in bytes of the initially committed section of
4531 * Offset in bytes from the beginning of the section
4532 * to the beginning of the view.
4535 * Desired length of map (or zero to map all) on entry
4536 * Actual length mapped on exit.
4538 * InheritDisposition
4539 * Specified how the view is to be shared with
4543 * Type of allocation for the pages.
4546 * Protection for the committed region of the view.
4554 MmMapViewOfSection(IN PVOID SectionObject
,
4555 IN PEPROCESS Process
,
4556 IN OUT PVOID
*BaseAddress
,
4557 IN ULONG_PTR ZeroBits
,
4558 IN SIZE_T CommitSize
,
4559 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4560 IN OUT PSIZE_T ViewSize
,
4561 IN SECTION_INHERIT InheritDisposition
,
4562 IN ULONG AllocationType
,
4565 PROS_SECTION_OBJECT Section
;
4566 PMMSUPPORT AddressSpace
;
4568 NTSTATUS Status
= STATUS_SUCCESS
;
4569 BOOLEAN NotAtBase
= FALSE
;
4571 if ((ULONG_PTR
)SectionObject
& 1)
4573 return MmMapViewOfArm3Section((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4587 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4589 return STATUS_INVALID_PAGE_PROTECTION
;
4593 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4594 AddressSpace
= &Process
->Vm
;
4596 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4598 MmLockAddressSpace(AddressSpace
);
4600 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4604 ULONG_PTR ImageBase
;
4606 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4607 PMM_SECTION_SEGMENT SectionSegments
;
4609 ImageSectionObject
= Section
->ImageSection
;
4610 SectionSegments
= ImageSectionObject
->Segments
;
4611 NrSegments
= ImageSectionObject
->NrSegments
;
4614 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4617 ImageBase
= ImageSectionObject
->ImageBase
;
4621 for (i
= 0; i
< NrSegments
; i
++)
4623 ULONG_PTR MaxExtent
;
4624 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4625 SectionSegments
[i
].Length
;
4626 ImageSize
= max(ImageSize
, MaxExtent
);
4629 ImageSectionObject
->ImageSize
= (ULONG
)ImageSize
;
4631 /* Check for an illegal base address */
4632 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4634 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4637 /* Check there is enough space to map the section at that point. */
4638 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4639 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4641 /* Fail if the user requested a fixed base address. */
4642 if ((*BaseAddress
) != NULL
)
4644 MmUnlockAddressSpace(AddressSpace
);
4645 return(STATUS_UNSUCCESSFUL
);
4647 /* Otherwise find a gap to map the image. */
4648 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4651 MmUnlockAddressSpace(AddressSpace
);
4652 return(STATUS_UNSUCCESSFUL
);
4654 /* Remember that we loaded image at a different base address */
4658 for (i
= 0; i
< NrSegments
; i
++)
4660 PVOID SBaseAddress
= (PVOID
)
4661 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4662 MmLockSectionSegment(&SectionSegments
[i
]);
4663 Status
= MmMapViewOfSegment(AddressSpace
,
4665 &SectionSegments
[i
],
4667 SectionSegments
[i
].Length
,
4668 SectionSegments
[i
].Protection
,
4671 MmUnlockSectionSegment(&SectionSegments
[i
]);
4672 if (!NT_SUCCESS(Status
))
4674 MmUnlockAddressSpace(AddressSpace
);
4679 *BaseAddress
= (PVOID
)ImageBase
;
4680 *ViewSize
= ImageSize
;
4684 /* check for write access */
4685 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4686 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4688 MmUnlockAddressSpace(AddressSpace
);
4689 return STATUS_SECTION_PROTECTION
;
4691 /* check for read access */
4692 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4693 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4695 MmUnlockAddressSpace(AddressSpace
);
4696 return STATUS_SECTION_PROTECTION
;
4698 /* check for execute access */
4699 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4700 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4702 MmUnlockAddressSpace(AddressSpace
);
4703 return STATUS_SECTION_PROTECTION
;
4706 if (ViewSize
== NULL
)
4708 /* Following this pointer would lead to us to the dark side */
4709 /* What to do? Bugcheck? Return status? Do the mambo? */
4710 KeBugCheck(MEMORY_MANAGEMENT
);
4713 if (SectionOffset
== NULL
)
4719 ViewOffset
= SectionOffset
->u
.LowPart
;
4722 if ((ViewOffset
% PAGE_SIZE
) != 0)
4724 MmUnlockAddressSpace(AddressSpace
);
4725 return(STATUS_MAPPED_ALIGNMENT
);
4728 if ((*ViewSize
) == 0)
4730 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4732 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4734 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4737 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4739 MmLockSectionSegment(Section
->Segment
);
4740 Status
= MmMapViewOfSegment(AddressSpace
,
4747 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4748 MmUnlockSectionSegment(Section
->Segment
);
4749 if (!NT_SUCCESS(Status
))
4751 MmUnlockAddressSpace(AddressSpace
);
4756 MmUnlockAddressSpace(AddressSpace
);
4759 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4761 Status
= STATUS_SUCCESS
;
4770 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4771 IN PLARGE_INTEGER NewFileSize
)
4773 /* Check whether an ImageSectionObject exists */
4774 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4776 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4780 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4782 PMM_SECTION_SEGMENT Segment
;
4784 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4787 if (Segment
->ReferenceCount
!= 0)
4789 /* Check size of file */
4790 if (SectionObjectPointer
->SharedCacheMap
)
4792 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4793 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4801 /* Something must gone wrong
4802 * how can we have a Section but no
4804 DPRINT("ERROR: DataSectionObject without reference!\n");
4808 DPRINT("FIXME: didn't check for outstanding write probes\n");
4820 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4821 IN MMFLUSH_TYPE FlushType
)
4825 case MmFlushForDelete
:
4826 if (SectionObjectPointer
->ImageSectionObject
||
4827 SectionObjectPointer
->DataSectionObject
)
4832 CcRosSetRemoveOnClose(SectionObjectPointer
);
4835 case MmFlushForWrite
:
4845 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4846 OUT PVOID
* MappedBase
,
4847 IN OUT PSIZE_T ViewSize
)
4849 PROS_SECTION_OBJECT Section
;
4850 PMMSUPPORT AddressSpace
;
4854 if ((ULONG_PTR
)SectionObject
& 1)
4856 extern PVOID MmSession
;
4857 return MiMapViewInSystemSpace((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4863 DPRINT("MmMapViewInSystemSpace() called\n");
4865 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4866 AddressSpace
= MmGetKernelAddressSpace();
4868 MmLockAddressSpace(AddressSpace
);
4871 if ((*ViewSize
) == 0)
4873 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4875 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4877 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4880 MmLockSectionSegment(Section
->Segment
);
4883 Status
= MmMapViewOfSegment(AddressSpace
,
4892 MmUnlockSectionSegment(Section
->Segment
);
4893 MmUnlockAddressSpace(AddressSpace
);
4902 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4904 PMMSUPPORT AddressSpace
;
4907 DPRINT("MmUnmapViewInSystemSpace() called\n");
4909 AddressSpace
= MmGetKernelAddressSpace();
4911 MmLockAddressSpace(AddressSpace
);
4913 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4915 MmUnlockAddressSpace(AddressSpace
);
4921 /**********************************************************************
4926 * Creates a section object.
4929 * SectionObject (OUT)
4930 * Caller supplied storage for the resulting pointer
4931 * to a SECTION_OBJECT instance;
4934 * Specifies the desired access to the section can be a
4936 * STANDARD_RIGHTS_REQUIRED |
4938 * SECTION_MAP_WRITE |
4939 * SECTION_MAP_READ |
4940 * SECTION_MAP_EXECUTE
4942 * ObjectAttributes [OPTIONAL]
4943 * Initialized attributes for the object can be used
4944 * to create a named section;
4947 * Maximizes the size of the memory section. Must be
4948 * non-NULL for a page-file backed section.
4949 * If value specified for a mapped file and the file is
4950 * not large enough, file will be extended.
4952 * SectionPageProtection
4953 * Can be a combination of:
4959 * AllocationAttributes
4960 * Can be a combination of:
4965 * Handle to a file to create a section mapped to a file
4966 * instead of a memory backed section;
4977 MmCreateSection (OUT PVOID
* Section
,
4978 IN ACCESS_MASK DesiredAccess
,
4979 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4980 IN PLARGE_INTEGER MaximumSize
,
4981 IN ULONG SectionPageProtection
,
4982 IN ULONG AllocationAttributes
,
4983 IN HANDLE FileHandle OPTIONAL
,
4984 IN PFILE_OBJECT File OPTIONAL
)
4987 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4989 /* Check if an ARM3 section is being created instead */
4990 if (AllocationAttributes
& 1)
4992 DPRINT1("arm 3 path\n");
4993 return MmCreateArm3Section(Section
,
4997 SectionPageProtection
,
4998 AllocationAttributes
&~ 1,
5004 * Check the protection
5006 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
5007 if (Protection
!= PAGE_READONLY
&&
5008 Protection
!= PAGE_READWRITE
&&
5009 Protection
!= PAGE_WRITECOPY
&&
5010 Protection
!= PAGE_EXECUTE
&&
5011 Protection
!= PAGE_EXECUTE_READ
&&
5012 Protection
!= PAGE_EXECUTE_READWRITE
&&
5013 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5015 return STATUS_INVALID_PAGE_PROTECTION
;
5018 if (AllocationAttributes
& SEC_IMAGE
)
5020 return(MmCreateImageSection(SectionObject
,
5024 SectionPageProtection
,
5025 AllocationAttributes
,
5029 if (FileHandle
!= NULL
)
5031 return(MmCreateDataFileSection(SectionObject
,
5035 SectionPageProtection
,
5036 AllocationAttributes
,
5040 return(MmCreatePageFileSection(SectionObject
,
5044 SectionPageProtection
,
5045 AllocationAttributes
));