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) ((P) | ((C) << 1))
165 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
166 #define MAKE_SWAP_SSE(S) (((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 ULONG 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
= 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
= 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 if(!AlignUp(&nPrevVirtualEndOfSegment
, cbHeadersSize
, nSectionAlignment
))
596 DIE(("Cannot align the size of the section headers\n"));
598 pssSegments
[0].FileOffset
= 0;
599 pssSegments
[0].Protection
= PAGE_READONLY
;
600 pssSegments
[0].Length
= nPrevVirtualEndOfSegment
;
601 pssSegments
[0].RawLength
= nFileSizeOfHeaders
;
602 pssSegments
[0].VirtualAddress
= 0;
603 pssSegments
[0].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
604 pssSegments
[0].WriteCopy
= TRUE
;
606 /* skip the headers segment */
609 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
611 /* convert the executable sections into segments. See also [1], section 4 */
612 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
614 ULONG nCharacteristics
;
616 /* validate the alignment */
617 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
618 DIE(("VirtualAddress[%u] is not aligned\n", i
));
620 /* sections must be contiguous, ordered by base address and non-overlapping */
621 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
622 DIE(("Memory gap between section %u and the previous\n", i
));
624 /* ignore explicit BSS sections */
625 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
627 /* validate the alignment */
629 /* Yes, this should be a multiple of FileAlignment, but there's
630 * stuff out there that isn't. We can cope with that
632 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
633 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
636 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
637 // DIE(("PointerToRawData[%u] is not aligned\n", i));
640 pssSegments
[i
].FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
641 pssSegments
[i
].RawLength
= pishSectionHeaders
[i
].SizeOfRawData
;
645 ASSERT(pssSegments
[i
].FileOffset
== 0);
646 ASSERT(pssSegments
[i
].RawLength
== 0);
649 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].FileOffset
, pssSegments
[i
].RawLength
));
651 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
653 /* no explicit protection */
654 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
656 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
657 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
659 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
660 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
662 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
663 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
666 /* see table above */
667 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
668 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
670 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
671 pssSegments
[i
].Length
= pishSectionHeaders
[i
].SizeOfRawData
;
673 pssSegments
[i
].Length
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
675 if(!AlignUp(&pssSegments
[i
].Length
, pssSegments
[i
].Length
, nSectionAlignment
))
676 DIE(("Cannot align the virtual size of section %u\n", i
));
678 ASSERT(IsAligned(pssSegments
[i
].Length
, nSectionAlignment
));
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 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment
, pssSegments
[i
].VirtualAddress
, pssSegments
[i
].Length
))
688 DIE(("The image is larger than 4GB\n"));
691 if(nSectionAlignment
>= PAGE_SIZE
)
692 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
695 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;
704 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
707 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
708 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
709 * RETURNS: Status of the wait.
712 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
714 LARGE_INTEGER Timeout
;
715 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
717 Timeout
.QuadPart
= -100000000LL; // 10 sec
720 Timeout
.QuadPart
= -100000000; // 10 sec
723 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
728 * FUNCTION: Sets the page op completion event and releases the page op.
729 * ARGUMENTS: PMM_PAGEOP.
730 * RETURNS: In shorter time than it takes you to even read this
731 * description, so don't even think about geting a mug of coffee.
734 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
736 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
737 MmReleasePageOp(PageOp
);
742 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
743 * ARGUMENTS: PFILE_OBJECT to wait for.
744 * RETURNS: Status of the wait.
747 MmspWaitForFileLock(PFILE_OBJECT File
)
749 return STATUS_SUCCESS
;
750 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
755 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
758 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
760 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
762 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
764 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
772 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
774 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
776 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
777 PMM_SECTION_SEGMENT SectionSegments
;
781 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
782 NrSegments
= ImageSectionObject
->NrSegments
;
783 SectionSegments
= ImageSectionObject
->Segments
;
784 for (i
= 0; i
< NrSegments
; i
++)
786 if (SectionSegments
[i
].ReferenceCount
!= 0)
788 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
789 SectionSegments
[i
].ReferenceCount
);
790 KeBugCheck(MEMORY_MANAGEMENT
);
792 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
794 ExFreePool(ImageSectionObject
->Segments
);
795 ExFreePool(ImageSectionObject
);
796 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
798 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
800 PMM_SECTION_SEGMENT Segment
;
802 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
805 if (Segment
->ReferenceCount
!= 0)
807 DPRINT1("Data segment still referenced\n");
808 KeBugCheck(MEMORY_MANAGEMENT
);
810 MmFreePageTablesSectionSegment(Segment
);
812 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
818 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
820 ExAcquireFastMutex(&Segment
->Lock
);
825 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
827 ExReleaseFastMutex(&Segment
->Lock
);
832 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
836 PSECTION_PAGE_TABLE Table
;
837 ULONG DirectoryOffset
;
840 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
842 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
846 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
847 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
851 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
852 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
853 TAG_SECTION_PAGE_TABLE
);
856 KeBugCheck(MEMORY_MANAGEMENT
);
858 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
859 DPRINT("Table %x\n", Table
);
862 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
863 Table
->Entry
[TableOffset
] = Entry
;
869 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
872 PSECTION_PAGE_TABLE Table
;
874 ULONG DirectoryOffset
;
877 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
879 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
881 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
885 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
886 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
887 DPRINT("Table %x\n", Table
);
893 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
894 Entry
= Table
->Entry
[TableOffset
];
900 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
905 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
908 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
909 KeBugCheck(MEMORY_MANAGEMENT
);
911 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
913 DPRINT1("Maximum share count reached\n");
914 KeBugCheck(MEMORY_MANAGEMENT
);
916 if (IS_SWAP_FROM_SSE(Entry
))
918 KeBugCheck(MEMORY_MANAGEMENT
);
920 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
921 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
926 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
927 PMM_SECTION_SEGMENT Segment
,
933 BOOLEAN IsDirectMapped
= FALSE
;
935 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
938 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
939 KeBugCheck(MEMORY_MANAGEMENT
);
941 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
943 DPRINT1("Zero share count for unshare\n");
944 KeBugCheck(MEMORY_MANAGEMENT
);
946 if (IS_SWAP_FROM_SSE(Entry
))
948 KeBugCheck(MEMORY_MANAGEMENT
);
950 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
952 * If we reducing the share count of this entry to zero then set the entry
953 * to zero and tell the cache the page is no longer mapped.
955 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
957 PFILE_OBJECT FileObject
;
959 SWAPENTRY SavedSwapEntry
;
961 BOOLEAN IsImageSection
;
964 FileOffset
= Offset
+ Segment
->FileOffset
;
966 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
968 Page
= PFN_FROM_SSE(Entry
);
969 FileObject
= Section
->FileObject
;
970 if (FileObject
!= NULL
&&
971 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
974 if ((FileOffset
% PAGE_SIZE
) == 0 &&
975 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
978 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
979 IsDirectMapped
= TRUE
;
981 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
983 Status
= STATUS_SUCCESS
;
985 if (!NT_SUCCESS(Status
))
987 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
988 KeBugCheck(MEMORY_MANAGEMENT
);
993 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
994 if (SavedSwapEntry
== 0)
997 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
998 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
1002 * Try to page out this page and set the swap entry
1003 * within the section segment. There exist no rmap entry
1004 * for this page. The pager thread can't page out a
1005 * page without a rmap entry.
1007 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1011 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
1012 if (!IsDirectMapped
)
1014 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1020 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1021 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1029 * We hold all locks. Nobody can do something with the current
1030 * process and the current segment (also not within an other process).
1033 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
1034 if (!NT_SUCCESS(Status
))
1036 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
1037 KeBugCheck(MEMORY_MANAGEMENT
);
1040 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
1041 MmSetSavedSwapEntryPage(Page
, 0);
1043 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1047 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1048 KeBugCheck(MEMORY_MANAGEMENT
);
1054 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1056 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1059 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1063 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1066 PCACHE_SEGMENT CacheSeg
;
1067 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1068 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
1071 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
1081 MiCopyFromUserPage(PFN_NUMBER DestPage
, PVOID SourceAddress
)
1087 Process
= PsGetCurrentProcess();
1088 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1089 if (TempAddress
== NULL
)
1091 return(STATUS_NO_MEMORY
);
1093 memcpy(TempAddress
, SourceAddress
, PAGE_SIZE
);
1094 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
1095 return(STATUS_SUCCESS
);
1101 MiReadPage(PMEMORY_AREA MemoryArea
,
1105 * FUNCTION: Read a page for a section backed memory area.
1107 * MemoryArea - Memory area to read the page for.
1108 * Offset - Offset of the page to read.
1109 * Page - Variable that receives a page contains the read data.
1116 PCACHE_SEGMENT CacheSeg
;
1117 PFILE_OBJECT FileObject
;
1121 BOOLEAN IsImageSection
;
1124 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1125 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1126 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
1127 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
1128 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1132 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1135 * If the file system is letting us go directly to the cache and the
1136 * memory area was mapped at an offset in the file which is page aligned
1137 * then get the related cache segment.
1139 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1140 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
1141 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1145 * Get the related cache segment; we use a lower level interface than
1146 * filesystems do because it is safe for us to use an offset with a
1147 * alignment less than the file system block size.
1149 Status
= CcRosGetCacheSegment(Bcb
,
1155 if (!NT_SUCCESS(Status
))
1162 * If the cache segment isn't up to date then call the file
1163 * system to read in the data.
1165 Status
= ReadCacheSegment(CacheSeg
);
1166 if (!NT_SUCCESS(Status
))
1168 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1173 * Retrieve the page from the cache segment that we actually want.
1175 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1176 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1178 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1185 ULONG CacheSegOffset
;
1188 * Allocate a page, this is rather complicated by the possibility
1189 * we might have to move other things out of memory
1191 MI_SET_USAGE(MI_USAGE_SECTION
);
1192 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1193 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1194 if (!NT_SUCCESS(Status
))
1198 Status
= CcRosGetCacheSegment(Bcb
,
1204 if (!NT_SUCCESS(Status
))
1211 * If the cache segment isn't up to date then call the file
1212 * system to read in the data.
1214 Status
= ReadCacheSegment(CacheSeg
);
1215 if (!NT_SUCCESS(Status
))
1217 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1222 Process
= PsGetCurrentProcess();
1223 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1224 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
1225 Length
= RawLength
- SegOffset
;
1226 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1228 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1230 else if (CacheSegOffset
>= PAGE_SIZE
)
1232 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1236 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1237 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1238 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1239 Status
= CcRosGetCacheSegment(Bcb
,
1240 FileOffset
+ CacheSegOffset
,
1245 if (!NT_SUCCESS(Status
))
1252 * If the cache segment isn't up to date then call the file
1253 * system to read in the data.
1255 Status
= ReadCacheSegment(CacheSeg
);
1256 if (!NT_SUCCESS(Status
))
1258 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1262 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1263 if (Length
< PAGE_SIZE
)
1265 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1269 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1272 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1273 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1275 return(STATUS_SUCCESS
);
1280 MiReadPage(PMEMORY_AREA MemoryArea
,
1284 * FUNCTION: Read a page for a section backed memory area.
1286 * MemoryArea - Memory area to read the page for.
1287 * Offset - Offset of the page to read.
1288 * Page - Variable that receives a page contains the read data.
1291 MM_REQUIRED_RESOURCES Resources
= { };
1293 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1294 Resources
.FileOffset
.QuadPart
= SegOffset
+
1295 MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
1296 Resources
.Consumer
= MC_USER
;
1297 Resources
.Amount
= PAGE_SIZE
;
1299 DPRINT1("%S, offset %x, len %d, page %x\n", ((PFILE_OBJECT
)Resources
.Context
)->FileName
.Buffer
, Resources
.FileOffset
.LowPart
, Resources
.Amount
, Resources
.Page
[0]);
1301 NTSTATUS Status
= MiReadFilePage(NULL
, NULL
, &Resources
);
1302 *Page
= Resources
.Page
[0];
1309 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1310 MEMORY_AREA
* MemoryArea
,
1318 PROS_SECTION_OBJECT Section
;
1319 PMM_SECTION_SEGMENT Segment
;
1325 BOOLEAN HasSwapEntry
;
1326 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1329 * There is a window between taking the page fault and locking the
1330 * address space when another thread could load the page so we check
1333 if (MmIsPagePresent(Process
, Address
))
1335 return(STATUS_SUCCESS
);
1338 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1339 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1340 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1342 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1343 Section
= MemoryArea
->Data
.SectionData
.Section
;
1344 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1345 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1350 MmLockSectionSegment(Segment
);
1353 * Check if this page needs to be mapped COW
1355 if ((Segment
->WriteCopy
) &&
1356 (Region
->Protect
== PAGE_READWRITE
||
1357 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1359 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1363 Attributes
= Region
->Protect
;
1367 * Get or create a page operation descriptor
1369 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
1372 DPRINT1("MmGetPageOp failed\n");
1373 KeBugCheck(MEMORY_MANAGEMENT
);
1377 * Check if someone else is already handling this fault, if so wait
1380 if (PageOp
->Thread
!= PsGetCurrentThread())
1382 MmUnlockSectionSegment(Segment
);
1383 MmUnlockAddressSpace(AddressSpace
);
1384 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1386 * Check for various strange conditions
1388 if (Status
!= STATUS_SUCCESS
)
1390 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1391 KeBugCheck(MEMORY_MANAGEMENT
);
1393 if (PageOp
->Status
== STATUS_PENDING
)
1395 DPRINT1("Woke for page op before completion\n");
1396 KeBugCheck(MEMORY_MANAGEMENT
);
1398 MmLockAddressSpace(AddressSpace
);
1400 * If this wasn't a pagein then restart the operation
1402 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
1404 MmspCompleteAndReleasePageOp(PageOp
);
1405 DPRINT("Address 0x%.8X\n", Address
);
1406 return(STATUS_MM_RESTART_OPERATION
);
1410 * If the thread handling this fault has failed then we don't retry
1412 if (!NT_SUCCESS(PageOp
->Status
))
1414 Status
= PageOp
->Status
;
1415 MmspCompleteAndReleasePageOp(PageOp
);
1416 DPRINT("Address 0x%.8X\n", Address
);
1419 MmLockSectionSegment(Segment
);
1421 * If the completed fault was for another address space then set the
1424 if (!MmIsPagePresent(Process
, Address
))
1426 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1427 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1429 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
1432 * The page was a private page in another or in our address space
1434 MmUnlockSectionSegment(Segment
);
1435 MmspCompleteAndReleasePageOp(PageOp
);
1436 return(STATUS_MM_RESTART_OPERATION
);
1439 Page
= PFN_FROM_SSE(Entry
);
1441 MmSharePageEntrySectionSegment(Segment
, Offset
);
1443 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
1444 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
1446 Status
= MmCreateVirtualMapping(Process
,
1451 if (!NT_SUCCESS(Status
))
1453 DPRINT1("Unable to create virtual mapping\n");
1454 KeBugCheck(MEMORY_MANAGEMENT
);
1456 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1458 MmUnlockSectionSegment(Segment
);
1459 PageOp
->Status
= STATUS_SUCCESS
;
1460 MmspCompleteAndReleasePageOp(PageOp
);
1461 DPRINT("Address 0x%.8X\n", Address
);
1462 return(STATUS_SUCCESS
);
1465 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1469 * Must be private page we have swapped out.
1471 SWAPENTRY SwapEntry
;
1476 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1478 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1479 KeBugCheck(MEMORY_MANAGEMENT
);
1482 MmUnlockSectionSegment(Segment
);
1483 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
1485 MmUnlockAddressSpace(AddressSpace
);
1486 MI_SET_USAGE(MI_USAGE_SECTION
);
1487 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1488 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1489 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1490 if (!NT_SUCCESS(Status
))
1492 KeBugCheck(MEMORY_MANAGEMENT
);
1495 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1496 if (!NT_SUCCESS(Status
))
1498 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1499 KeBugCheck(MEMORY_MANAGEMENT
);
1501 MmLockAddressSpace(AddressSpace
);
1502 Status
= MmCreateVirtualMapping(Process
,
1507 if (!NT_SUCCESS(Status
))
1509 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1510 KeBugCheck(MEMORY_MANAGEMENT
);
1515 * Store the swap entry for later use.
1517 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1520 * Add the page to the process's working set
1522 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1525 * Finish the operation
1527 PageOp
->Status
= STATUS_SUCCESS
;
1528 MmspCompleteAndReleasePageOp(PageOp
);
1529 DPRINT("Address 0x%.8X\n", Address
);
1530 return(STATUS_SUCCESS
);
1534 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1536 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1538 MmUnlockSectionSegment(Segment
);
1540 * Just map the desired physical page
1542 Page
= Offset
>> PAGE_SHIFT
;
1543 Status
= MmCreateVirtualMappingUnsafe(Process
,
1548 if (!NT_SUCCESS(Status
))
1550 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1551 KeBugCheck(MEMORY_MANAGEMENT
);
1556 * Cleanup and release locks
1558 PageOp
->Status
= STATUS_SUCCESS
;
1559 MmspCompleteAndReleasePageOp(PageOp
);
1560 DPRINT("Address 0x%.8X\n", Address
);
1561 return(STATUS_SUCCESS
);
1565 * Map anonymous memory for BSS sections
1567 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1569 MmUnlockSectionSegment(Segment
);
1570 MI_SET_USAGE(MI_USAGE_SECTION
);
1571 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1572 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1573 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1574 if (!NT_SUCCESS(Status
))
1576 MmUnlockAddressSpace(AddressSpace
);
1577 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1578 MmLockAddressSpace(AddressSpace
);
1580 if (!NT_SUCCESS(Status
))
1582 KeBugCheck(MEMORY_MANAGEMENT
);
1584 Status
= MmCreateVirtualMapping(Process
,
1589 if (!NT_SUCCESS(Status
))
1591 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1592 KeBugCheck(MEMORY_MANAGEMENT
);
1595 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1598 * Cleanup and release locks
1600 PageOp
->Status
= STATUS_SUCCESS
;
1601 MmspCompleteAndReleasePageOp(PageOp
);
1602 DPRINT("Address 0x%.8X\n", Address
);
1603 return(STATUS_SUCCESS
);
1607 * Get the entry corresponding to the offset within the section
1609 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1614 * If the entry is zero (and it can't change because we have
1615 * locked the segment) then we need to load the page.
1619 * Release all our locks and read in the page from disk
1621 MmUnlockSectionSegment(Segment
);
1622 MmUnlockAddressSpace(AddressSpace
);
1624 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1625 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1627 MI_SET_USAGE(MI_USAGE_SECTION
);
1628 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1629 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1630 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1631 if (!NT_SUCCESS(Status
))
1633 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1639 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1640 if (!NT_SUCCESS(Status
))
1642 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1645 if (!NT_SUCCESS(Status
))
1648 * FIXME: What do we know in this case?
1651 * Cleanup and release locks
1653 MmLockAddressSpace(AddressSpace
);
1654 PageOp
->Status
= Status
;
1655 MmspCompleteAndReleasePageOp(PageOp
);
1656 DPRINT("Address 0x%.8X\n", Address
);
1660 * Relock the address space and segment
1662 MmLockAddressSpace(AddressSpace
);
1663 MmLockSectionSegment(Segment
);
1666 * Check the entry. No one should change the status of a page
1667 * that has a pending page-in.
1669 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1670 if (Entry
!= Entry1
)
1672 DPRINT1("Someone changed ppte entry while we slept\n");
1673 KeBugCheck(MEMORY_MANAGEMENT
);
1677 * Mark the offset within the section as having valid, in-memory
1680 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1681 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1682 MmUnlockSectionSegment(Segment
);
1684 Status
= MmCreateVirtualMapping(Process
,
1689 if (!NT_SUCCESS(Status
))
1691 DPRINT1("Unable to create virtual mapping\n");
1692 KeBugCheck(MEMORY_MANAGEMENT
);
1694 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1696 PageOp
->Status
= STATUS_SUCCESS
;
1697 MmspCompleteAndReleasePageOp(PageOp
);
1698 DPRINT("Address 0x%.8X\n", Address
);
1699 return(STATUS_SUCCESS
);
1701 else if (IS_SWAP_FROM_SSE(Entry
))
1703 SWAPENTRY SwapEntry
;
1705 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1708 * Release all our locks and read in the page from disk
1710 MmUnlockSectionSegment(Segment
);
1712 MmUnlockAddressSpace(AddressSpace
);
1713 MI_SET_USAGE(MI_USAGE_SECTION
);
1714 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1715 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1716 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1717 if (!NT_SUCCESS(Status
))
1719 KeBugCheck(MEMORY_MANAGEMENT
);
1722 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1723 if (!NT_SUCCESS(Status
))
1725 KeBugCheck(MEMORY_MANAGEMENT
);
1729 * Relock the address space and segment
1731 MmLockAddressSpace(AddressSpace
);
1732 MmLockSectionSegment(Segment
);
1735 * Check the entry. No one should change the status of a page
1736 * that has a pending page-in.
1738 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1739 if (Entry
!= Entry1
)
1741 DPRINT1("Someone changed ppte entry while we slept\n");
1742 KeBugCheck(MEMORY_MANAGEMENT
);
1746 * Mark the offset within the section as having valid, in-memory
1749 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1750 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1751 MmUnlockSectionSegment(Segment
);
1754 * Save the swap entry.
1756 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1757 Status
= MmCreateVirtualMapping(Process
,
1762 if (!NT_SUCCESS(Status
))
1764 DPRINT1("Unable to create virtual mapping\n");
1765 KeBugCheck(MEMORY_MANAGEMENT
);
1767 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1768 PageOp
->Status
= STATUS_SUCCESS
;
1769 MmspCompleteAndReleasePageOp(PageOp
);
1770 DPRINT("Address 0x%.8X\n", Address
);
1771 return(STATUS_SUCCESS
);
1776 * If the section offset is already in-memory and valid then just
1777 * take another reference to the page
1780 Page
= PFN_FROM_SSE(Entry
);
1782 MmSharePageEntrySectionSegment(Segment
, Offset
);
1783 MmUnlockSectionSegment(Segment
);
1785 Status
= MmCreateVirtualMapping(Process
,
1790 if (!NT_SUCCESS(Status
))
1792 DPRINT1("Unable to create virtual mapping\n");
1793 KeBugCheck(MEMORY_MANAGEMENT
);
1795 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1796 PageOp
->Status
= STATUS_SUCCESS
;
1797 MmspCompleteAndReleasePageOp(PageOp
);
1798 DPRINT("Address 0x%.8X\n", Address
);
1799 return(STATUS_SUCCESS
);
1805 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1806 MEMORY_AREA
* MemoryArea
,
1810 PMM_SECTION_SEGMENT Segment
;
1811 PROS_SECTION_OBJECT Section
;
1820 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1822 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1825 * Check if the page has been paged out or has already been set readwrite
1827 if (!MmIsPagePresent(Process
, Address
) ||
1828 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1830 DPRINT("Address 0x%.8X\n", Address
);
1831 return(STATUS_SUCCESS
);
1835 * Find the offset of the page
1837 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1838 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1839 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1841 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1842 Section
= MemoryArea
->Data
.SectionData
.Section
;
1843 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1844 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1849 MmLockSectionSegment(Segment
);
1851 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1852 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1854 MmUnlockSectionSegment(Segment
);
1857 * Check if we are doing COW
1859 if (!((Segment
->WriteCopy
) &&
1860 (Region
->Protect
== PAGE_READWRITE
||
1861 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1863 DPRINT("Address 0x%.8X\n", Address
);
1864 return(STATUS_ACCESS_VIOLATION
);
1867 if (IS_SWAP_FROM_SSE(Entry
) ||
1868 PFN_FROM_SSE(Entry
) != OldPage
)
1870 /* This is a private page. We must only change the page protection. */
1871 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1872 return(STATUS_SUCCESS
);
1876 * Get or create a pageop
1878 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1879 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1882 DPRINT1("MmGetPageOp failed\n");
1883 KeBugCheck(MEMORY_MANAGEMENT
);
1887 * Wait for any other operations to complete
1889 if (PageOp
->Thread
!= PsGetCurrentThread())
1891 MmUnlockAddressSpace(AddressSpace
);
1892 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1894 * Check for various strange conditions
1896 if (Status
== STATUS_TIMEOUT
)
1898 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1899 KeBugCheck(MEMORY_MANAGEMENT
);
1901 if (PageOp
->Status
== STATUS_PENDING
)
1903 DPRINT1("Woke for page op before completion\n");
1904 KeBugCheck(MEMORY_MANAGEMENT
);
1907 * Restart the operation
1909 MmLockAddressSpace(AddressSpace
);
1910 MmspCompleteAndReleasePageOp(PageOp
);
1911 DPRINT("Address 0x%.8X\n", Address
);
1912 return(STATUS_MM_RESTART_OPERATION
);
1916 * Release locks now we have the pageop
1918 MmUnlockAddressSpace(AddressSpace
);
1923 MI_SET_USAGE(MI_USAGE_SECTION
);
1924 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1925 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1926 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1927 if (!NT_SUCCESS(Status
))
1929 KeBugCheck(MEMORY_MANAGEMENT
);
1935 MiCopyFromUserPage(NewPage
, PAddress
);
1937 MmLockAddressSpace(AddressSpace
);
1939 * Delete the old entry.
1941 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1944 * Set the PTE to point to the new page
1946 Status
= MmCreateVirtualMapping(Process
,
1951 if (!NT_SUCCESS(Status
))
1953 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1954 KeBugCheck(MEMORY_MANAGEMENT
);
1957 if (!NT_SUCCESS(Status
))
1959 DPRINT1("Unable to create virtual mapping\n");
1960 KeBugCheck(MEMORY_MANAGEMENT
);
1964 * Unshare the old page.
1966 MmDeleteRmap(OldPage
, Process
, PAddress
);
1967 MmInsertRmap(NewPage
, Process
, PAddress
);
1968 MmLockSectionSegment(Segment
);
1969 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1970 MmUnlockSectionSegment(Segment
);
1972 PageOp
->Status
= STATUS_SUCCESS
;
1973 MmspCompleteAndReleasePageOp(PageOp
);
1974 DPRINT("Address 0x%.8X\n", Address
);
1975 return(STATUS_SUCCESS
);
1979 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1981 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1985 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1988 MmLockAddressSpace(&Process
->Vm
);
1991 MmDeleteVirtualMapping(Process
,
1998 PageOutContext
->WasDirty
= TRUE
;
2000 if (!PageOutContext
->Private
)
2002 MmLockSectionSegment(PageOutContext
->Segment
);
2003 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
2004 PageOutContext
->Segment
,
2005 PageOutContext
->Offset
,
2006 PageOutContext
->WasDirty
,
2008 MmUnlockSectionSegment(PageOutContext
->Segment
);
2012 MmUnlockAddressSpace(&Process
->Vm
);
2015 if (PageOutContext
->Private
)
2017 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2020 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
2025 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
2026 MEMORY_AREA
* MemoryArea
,
2031 MM_SECTION_PAGEOUT_CONTEXT Context
;
2032 SWAPENTRY SwapEntry
;
2036 PFILE_OBJECT FileObject
;
2040 BOOLEAN DirectMapped
;
2041 BOOLEAN IsImageSection
;
2042 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2045 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2048 * Get the segment and section.
2050 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2051 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
2053 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2054 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2055 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
2057 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2059 FileObject
= Context
.Section
->FileObject
;
2060 DirectMapped
= FALSE
;
2062 if (FileObject
!= NULL
&&
2063 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2065 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2068 * If the file system is letting us go directly to the cache and the
2069 * memory area was mapped at an offset in the file which is page aligned
2070 * then note this is a direct mapped page.
2072 if ((FileOffset
% PAGE_SIZE
) == 0 &&
2073 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
2075 DirectMapped
= TRUE
;
2082 * This should never happen since mappings of physical memory are never
2083 * placed in the rmap lists.
2085 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2087 DPRINT1("Trying to page out from physical memory section address 0x%X "
2088 "process %d\n", Address
,
2089 Process
? Process
->UniqueProcessId
: 0);
2090 KeBugCheck(MEMORY_MANAGEMENT
);
2094 * Get the section segment entry and the physical address.
2096 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
2097 if (!MmIsPagePresent(Process
, Address
))
2099 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2100 Process
? Process
->UniqueProcessId
: 0, Address
);
2101 KeBugCheck(MEMORY_MANAGEMENT
);
2103 Page
= MmGetPfnForProcess(Process
, Address
);
2104 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2107 * Prepare the context structure for the rmap delete call.
2109 Context
.WasDirty
= FALSE
;
2110 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2111 IS_SWAP_FROM_SSE(Entry
) ||
2112 PFN_FROM_SSE(Entry
) != Page
)
2114 Context
.Private
= TRUE
;
2118 Context
.Private
= FALSE
;
2122 * Take an additional reference to the page or the cache segment.
2124 if (DirectMapped
&& !Context
.Private
)
2126 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
2128 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2129 KeBugCheck(MEMORY_MANAGEMENT
);
2134 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
2135 MmReferencePage(Page
);
2136 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
2139 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2142 * If this wasn't a private page then we should have reduced the entry to
2143 * zero by deleting all the rmaps.
2145 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
2147 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2148 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2150 KeBugCheck(MEMORY_MANAGEMENT
);
2155 * If the page wasn't dirty then we can just free it as for a readonly page.
2156 * Since we unmapped all the mappings above we know it will not suddenly
2158 * If the page is from a pagefile section and has no swap entry,
2159 * we can't free the page at this point.
2161 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2162 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2164 if (Context
.Private
)
2166 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
2167 Context
.WasDirty
? "dirty" : "clean", Address
);
2168 KeBugCheck(MEMORY_MANAGEMENT
);
2170 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2172 MmSetSavedSwapEntryPage(Page
, 0);
2173 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2174 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2175 PageOp
->Status
= STATUS_SUCCESS
;
2176 MmspCompleteAndReleasePageOp(PageOp
);
2177 return(STATUS_SUCCESS
);
2180 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2182 if (Context
.Private
)
2184 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2185 Context
.WasDirty
? "dirty" : "clean", Address
);
2186 KeBugCheck(MEMORY_MANAGEMENT
);
2188 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2190 MmSetSavedSwapEntryPage(Page
, 0);
2193 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2195 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2196 PageOp
->Status
= STATUS_SUCCESS
;
2197 MmspCompleteAndReleasePageOp(PageOp
);
2198 return(STATUS_SUCCESS
);
2201 else if (!Context
.Private
&& DirectMapped
)
2205 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2207 KeBugCheck(MEMORY_MANAGEMENT
);
2210 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
2212 Status
= STATUS_SUCCESS
;
2214 if (!NT_SUCCESS(Status
))
2216 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2217 KeBugCheck(MEMORY_MANAGEMENT
);
2219 PageOp
->Status
= STATUS_SUCCESS
;
2220 MmspCompleteAndReleasePageOp(PageOp
);
2221 return(STATUS_SUCCESS
);
2223 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2227 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2229 KeBugCheck(MEMORY_MANAGEMENT
);
2231 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2232 PageOp
->Status
= STATUS_SUCCESS
;
2233 MmspCompleteAndReleasePageOp(PageOp
);
2234 return(STATUS_SUCCESS
);
2236 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2238 MmSetSavedSwapEntryPage(Page
, 0);
2239 MmLockAddressSpace(AddressSpace
);
2240 Status
= MmCreatePageFileMapping(Process
,
2243 MmUnlockAddressSpace(AddressSpace
);
2244 if (!NT_SUCCESS(Status
))
2246 KeBugCheck(MEMORY_MANAGEMENT
);
2248 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2249 PageOp
->Status
= STATUS_SUCCESS
;
2250 MmspCompleteAndReleasePageOp(PageOp
);
2251 return(STATUS_SUCCESS
);
2255 * If necessary, allocate an entry in the paging file for this page
2259 SwapEntry
= MmAllocSwapPage();
2262 MmShowOutOfSpaceMessagePagingFile();
2263 MmLockAddressSpace(AddressSpace
);
2265 * For private pages restore the old mappings.
2267 if (Context
.Private
)
2269 Status
= MmCreateVirtualMapping(Process
,
2271 MemoryArea
->Protect
,
2274 MmSetDirtyPage(Process
, Address
);
2282 * For non-private pages if the page wasn't direct mapped then
2283 * set it back into the section segment entry so we don't loose
2284 * our copy. Otherwise it will be handled by the cache manager.
2286 Status
= MmCreateVirtualMapping(Process
,
2288 MemoryArea
->Protect
,
2291 MmSetDirtyPage(Process
, Address
);
2295 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2296 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2298 MmUnlockAddressSpace(AddressSpace
);
2299 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2300 MmspCompleteAndReleasePageOp(PageOp
);
2301 return(STATUS_PAGEFILE_QUOTA
);
2306 * Write the page to the pagefile
2308 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2309 if (!NT_SUCCESS(Status
))
2311 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2314 * As above: undo our actions.
2315 * FIXME: Also free the swap page.
2317 MmLockAddressSpace(AddressSpace
);
2318 if (Context
.Private
)
2320 Status
= MmCreateVirtualMapping(Process
,
2322 MemoryArea
->Protect
,
2325 MmSetDirtyPage(Process
, Address
);
2332 Status
= MmCreateVirtualMapping(Process
,
2334 MemoryArea
->Protect
,
2337 MmSetDirtyPage(Process
, Address
);
2341 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2342 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2344 MmUnlockAddressSpace(AddressSpace
);
2345 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2346 MmspCompleteAndReleasePageOp(PageOp
);
2347 return(STATUS_UNSUCCESSFUL
);
2351 * Otherwise we have succeeded.
2353 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2354 MmSetSavedSwapEntryPage(Page
, 0);
2355 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2356 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2358 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2362 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2365 if (Context
.Private
)
2367 MmLockAddressSpace(AddressSpace
);
2368 Status
= MmCreatePageFileMapping(Process
,
2371 MmUnlockAddressSpace(AddressSpace
);
2372 if (!NT_SUCCESS(Status
))
2374 KeBugCheck(MEMORY_MANAGEMENT
);
2379 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2380 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2383 PageOp
->Status
= STATUS_SUCCESS
;
2384 MmspCompleteAndReleasePageOp(PageOp
);
2385 return(STATUS_SUCCESS
);
2390 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2391 PMEMORY_AREA MemoryArea
,
2396 PROS_SECTION_OBJECT Section
;
2397 PMM_SECTION_SEGMENT Segment
;
2399 SWAPENTRY SwapEntry
;
2403 PFILE_OBJECT FileObject
;
2405 BOOLEAN DirectMapped
;
2406 BOOLEAN IsImageSection
;
2407 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2409 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2411 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2412 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2415 * Get the segment and section.
2417 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2418 Section
= MemoryArea
->Data
.SectionData
.Section
;
2419 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2421 FileObject
= Section
->FileObject
;
2422 DirectMapped
= FALSE
;
2423 if (FileObject
!= NULL
&&
2424 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2426 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2429 * If the file system is letting us go directly to the cache and the
2430 * memory area was mapped at an offset in the file which is page aligned
2431 * then note this is a direct mapped page.
2433 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
2434 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
2436 DirectMapped
= TRUE
;
2441 * This should never happen since mappings of physical memory are never
2442 * placed in the rmap lists.
2444 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2446 DPRINT1("Trying to write back page from physical memory mapped at %X "
2447 "process %d\n", Address
,
2448 Process
? Process
->UniqueProcessId
: 0);
2449 KeBugCheck(MEMORY_MANAGEMENT
);
2453 * Get the section segment entry and the physical address.
2455 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2456 if (!MmIsPagePresent(Process
, Address
))
2458 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2459 Process
? Process
->UniqueProcessId
: 0, Address
);
2460 KeBugCheck(MEMORY_MANAGEMENT
);
2462 Page
= MmGetPfnForProcess(Process
, Address
);
2463 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2466 * Check for a private (COWed) page.
2468 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2469 IS_SWAP_FROM_SSE(Entry
) ||
2470 PFN_FROM_SSE(Entry
) != Page
)
2480 * Speculatively set all mappings of the page to clean.
2482 MmSetCleanAllRmaps(Page
);
2485 * If this page was direct mapped from the cache then the cache manager
2486 * will take care of writing it back to disk.
2488 if (DirectMapped
&& !Private
)
2490 ASSERT(SwapEntry
== 0);
2492 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
2494 PageOp
->Status
= STATUS_SUCCESS
;
2495 MmspCompleteAndReleasePageOp(PageOp
);
2496 return(STATUS_SUCCESS
);
2500 * If necessary, allocate an entry in the paging file for this page
2504 SwapEntry
= MmAllocSwapPage();
2507 MmSetDirtyAllRmaps(Page
);
2508 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2509 MmspCompleteAndReleasePageOp(PageOp
);
2510 return(STATUS_PAGEFILE_QUOTA
);
2512 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2516 * Write the page to the pagefile
2518 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2519 if (!NT_SUCCESS(Status
))
2521 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2523 MmSetDirtyAllRmaps(Page
);
2524 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2525 MmspCompleteAndReleasePageOp(PageOp
);
2526 return(STATUS_UNSUCCESSFUL
);
2530 * Otherwise we have succeeded.
2532 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2533 PageOp
->Status
= STATUS_SUCCESS
;
2534 MmspCompleteAndReleasePageOp(PageOp
);
2535 return(STATUS_SUCCESS
);
2539 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2547 PMEMORY_AREA MemoryArea
;
2548 PMM_SECTION_SEGMENT Segment
;
2549 BOOLEAN DoCOW
= FALSE
;
2551 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2553 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2554 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2556 if ((Segment
->WriteCopy
) &&
2557 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2562 if (OldProtect
!= NewProtect
)
2564 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2566 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2567 ULONG Protect
= NewProtect
;
2570 * If we doing COW for this segment then check if the page is
2573 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2579 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2580 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2581 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2582 Page
= MmGetPfnForProcess(Process
, Address
);
2584 Protect
= PAGE_READONLY
;
2585 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2586 IS_SWAP_FROM_SSE(Entry
) ||
2587 PFN_FROM_SSE(Entry
) != Page
)
2589 Protect
= NewProtect
;
2593 if (MmIsPagePresent(Process
, Address
))
2595 MmSetPageProtect(Process
, Address
,
2604 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2605 PMEMORY_AREA MemoryArea
,
2613 ULONG_PTR MaxLength
;
2615 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2616 if (Length
> MaxLength
)
2619 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2620 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2622 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2623 Region
->Protect
!= Protect
)
2625 return STATUS_INVALID_PAGE_PROTECTION
;
2628 *OldProtect
= Region
->Protect
;
2629 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2630 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2631 BaseAddress
, Length
, Region
->Type
, Protect
,
2632 MmAlterViewAttributes
);
2638 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2640 PMEMORY_BASIC_INFORMATION Info
,
2641 PSIZE_T ResultLength
)
2644 PVOID RegionBaseAddress
;
2645 PROS_SECTION_OBJECT Section
;
2646 PMM_SECTION_SEGMENT Segment
;
2648 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2649 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2650 Address
, &RegionBaseAddress
);
2653 return STATUS_UNSUCCESSFUL
;
2656 Section
= MemoryArea
->Data
.SectionData
.Section
;
2657 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2659 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2660 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2661 Info
->Type
= MEM_IMAGE
;
2665 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2666 Info
->Type
= MEM_MAPPED
;
2668 Info
->BaseAddress
= RegionBaseAddress
;
2669 Info
->AllocationProtect
= MemoryArea
->Protect
;
2670 Info
->RegionSize
= Region
->Length
;
2671 Info
->State
= MEM_COMMIT
;
2672 Info
->Protect
= Region
->Protect
;
2674 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2675 return(STATUS_SUCCESS
);
2680 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2685 ULONG SavedSwapEntry
;
2690 Length
= PAGE_ROUND_UP(Segment
->Length
);
2691 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2693 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2696 if (IS_SWAP_FROM_SSE(Entry
))
2698 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2702 Page
= PFN_FROM_SSE(Entry
);
2703 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2704 if (SavedSwapEntry
!= 0)
2706 MmSetSavedSwapEntryPage(Page
, 0);
2707 MmFreeSwapPage(SavedSwapEntry
);
2709 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2711 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2717 MmpDeleteSection(PVOID ObjectBody
)
2719 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2721 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2722 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2727 PMM_SECTION_SEGMENT SectionSegments
;
2730 * NOTE: Section->ImageSection can be NULL for short time
2731 * during the section creating. If we fail for some reason
2732 * until the image section is properly initialized we shouldn't
2733 * process further here.
2735 if (Section
->ImageSection
== NULL
)
2738 SectionSegments
= Section
->ImageSection
->Segments
;
2739 NrSegments
= Section
->ImageSection
->NrSegments
;
2741 for (i
= 0; i
< NrSegments
; i
++)
2743 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2745 MmLockSectionSegment(&SectionSegments
[i
]);
2747 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2748 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2752 MmpFreePageFileSegment(&SectionSegments
[i
]);
2754 MmUnlockSectionSegment(&SectionSegments
[i
]);
2761 * NOTE: Section->Segment can be NULL for short time
2762 * during the section creating.
2764 if (Section
->Segment
== NULL
)
2767 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2769 MmpFreePageFileSegment(Section
->Segment
);
2770 MmFreePageTablesSectionSegment(Section
->Segment
);
2771 ExFreePool(Section
->Segment
);
2772 Section
->Segment
= NULL
;
2776 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2779 if (Section
->FileObject
!= NULL
)
2782 CcRosDereferenceCache(Section
->FileObject
);
2784 ObDereferenceObject(Section
->FileObject
);
2785 Section
->FileObject
= NULL
;
2790 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2792 IN ACCESS_MASK GrantedAccess
,
2793 IN ULONG ProcessHandleCount
,
2794 IN ULONG SystemHandleCount
)
2796 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2797 Object
, ProcessHandleCount
);
2803 MmCreatePhysicalMemorySection(VOID
)
2805 PROS_SECTION_OBJECT PhysSection
;
2807 OBJECT_ATTRIBUTES Obj
;
2808 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2809 LARGE_INTEGER SectionSize
;
2813 * Create the section mapping physical memory
2815 SectionSize
.QuadPart
= 0xFFFFFFFF;
2816 InitializeObjectAttributes(&Obj
,
2821 Status
= MmCreateSection((PVOID
)&PhysSection
,
2825 PAGE_EXECUTE_READWRITE
,
2829 if (!NT_SUCCESS(Status
))
2831 DPRINT1("Failed to create PhysicalMemory section\n");
2832 KeBugCheck(MEMORY_MANAGEMENT
);
2834 Status
= ObInsertObject(PhysSection
,
2840 if (!NT_SUCCESS(Status
))
2842 ObDereferenceObject(PhysSection
);
2844 ObCloseHandle(Handle
, KernelMode
);
2845 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2846 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2848 return(STATUS_SUCCESS
);
2854 MmInitSectionImplementation(VOID
)
2856 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2857 UNICODE_STRING Name
;
2859 DPRINT("Creating Section Object Type\n");
2861 /* Initialize the Section object type */
2862 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2863 RtlInitUnicodeString(&Name
, L
"Section");
2864 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2865 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2866 ObjectTypeInitializer
.PoolType
= PagedPool
;
2867 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2868 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2869 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2870 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2871 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2872 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2874 MmCreatePhysicalMemorySection();
2876 return(STATUS_SUCCESS
);
2881 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2882 ACCESS_MASK DesiredAccess
,
2883 POBJECT_ATTRIBUTES ObjectAttributes
,
2884 PLARGE_INTEGER UMaximumSize
,
2885 ULONG SectionPageProtection
,
2886 ULONG AllocationAttributes
)
2888 * Create a section which is backed by the pagefile
2891 LARGE_INTEGER MaximumSize
;
2892 PROS_SECTION_OBJECT Section
;
2893 PMM_SECTION_SEGMENT Segment
;
2896 if (UMaximumSize
== NULL
)
2898 return(STATUS_UNSUCCESSFUL
);
2900 MaximumSize
= *UMaximumSize
;
2903 * Create the section
2905 Status
= ObCreateObject(ExGetPreviousMode(),
2906 MmSectionObjectType
,
2908 ExGetPreviousMode(),
2910 sizeof(ROS_SECTION_OBJECT
),
2913 (PVOID
*)(PVOID
)&Section
);
2914 if (!NT_SUCCESS(Status
))
2922 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2923 Section
->SectionPageProtection
= SectionPageProtection
;
2924 Section
->AllocationAttributes
= AllocationAttributes
;
2925 Section
->MaximumSize
= MaximumSize
;
2926 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2927 TAG_MM_SECTION_SEGMENT
);
2928 if (Segment
== NULL
)
2930 ObDereferenceObject(Section
);
2931 return(STATUS_NO_MEMORY
);
2933 Section
->Segment
= Segment
;
2934 Segment
->ReferenceCount
= 1;
2935 ExInitializeFastMutex(&Segment
->Lock
);
2936 Segment
->FileOffset
= 0;
2937 Segment
->Protection
= SectionPageProtection
;
2938 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2939 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2940 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2941 Segment
->WriteCopy
= FALSE
;
2942 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2943 Segment
->VirtualAddress
= 0;
2944 Segment
->Characteristics
= 0;
2945 *SectionObject
= Section
;
2946 return(STATUS_SUCCESS
);
2952 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2953 ACCESS_MASK DesiredAccess
,
2954 POBJECT_ATTRIBUTES ObjectAttributes
,
2955 PLARGE_INTEGER UMaximumSize
,
2956 ULONG SectionPageProtection
,
2957 ULONG AllocationAttributes
,
2960 * Create a section backed by a data file
2963 PROS_SECTION_OBJECT Section
;
2965 LARGE_INTEGER MaximumSize
;
2966 PFILE_OBJECT FileObject
;
2967 PMM_SECTION_SEGMENT Segment
;
2969 IO_STATUS_BLOCK Iosb
;
2970 LARGE_INTEGER Offset
;
2972 FILE_STANDARD_INFORMATION FileInfo
;
2976 * Create the section
2978 Status
= ObCreateObject(ExGetPreviousMode(),
2979 MmSectionObjectType
,
2981 ExGetPreviousMode(),
2983 sizeof(ROS_SECTION_OBJECT
),
2986 (PVOID
*)(PVOID
)&Section
);
2987 if (!NT_SUCCESS(Status
))
2994 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2995 Section
->SectionPageProtection
= SectionPageProtection
;
2996 Section
->AllocationAttributes
= AllocationAttributes
;
2999 * Check file access required
3001 if (SectionPageProtection
& PAGE_READWRITE
||
3002 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3004 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3008 FileAccess
= FILE_READ_DATA
;
3012 * Reference the file handle
3014 Status
= ObReferenceObjectByHandle(FileHandle
,
3017 ExGetPreviousMode(),
3018 (PVOID
*)(PVOID
)&FileObject
,
3020 if (!NT_SUCCESS(Status
))
3022 ObDereferenceObject(Section
);
3027 * FIXME: This is propably not entirely correct. We can't look into
3028 * the standard FCB header because it might not be initialized yet
3029 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
3030 * standard file information is filled on first request).
3032 Status
= IoQueryFileInformation(FileObject
,
3033 FileStandardInformation
,
3034 sizeof(FILE_STANDARD_INFORMATION
),
3037 Iosb
.Information
= Length
;
3038 if (!NT_SUCCESS(Status
))
3040 ObDereferenceObject(Section
);
3041 ObDereferenceObject(FileObject
);
3046 * FIXME: Revise this once a locking order for file size changes is
3049 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
3051 MaximumSize
= *UMaximumSize
;
3055 MaximumSize
= FileInfo
.EndOfFile
;
3056 /* Mapping zero-sized files isn't allowed. */
3057 if (MaximumSize
.QuadPart
== 0)
3059 ObDereferenceObject(Section
);
3060 ObDereferenceObject(FileObject
);
3061 return STATUS_FILE_INVALID
;
3065 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3067 Status
= IoSetInformation(FileObject
,
3068 FileAllocationInformation
,
3069 sizeof(LARGE_INTEGER
),
3071 if (!NT_SUCCESS(Status
))
3073 ObDereferenceObject(Section
);
3074 ObDereferenceObject(FileObject
);
3075 return(STATUS_SECTION_NOT_EXTENDED
);
3079 if (FileObject
->SectionObjectPointer
== NULL
||
3080 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3083 * Read a bit so caching is initiated for the file object.
3084 * This is only needed because MiReadPage currently cannot
3085 * handle non-cached streams.
3087 Offset
.QuadPart
= 0;
3088 Status
= ZwReadFile(FileHandle
,
3097 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3099 ObDereferenceObject(Section
);
3100 ObDereferenceObject(FileObject
);
3103 if (FileObject
->SectionObjectPointer
== NULL
||
3104 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3106 /* FIXME: handle this situation */
3107 ObDereferenceObject(Section
);
3108 ObDereferenceObject(FileObject
);
3109 return STATUS_INVALID_PARAMETER
;
3116 Status
= MmspWaitForFileLock(FileObject
);
3117 if (Status
!= STATUS_SUCCESS
)
3119 ObDereferenceObject(Section
);
3120 ObDereferenceObject(FileObject
);
3125 * If this file hasn't been mapped as a data file before then allocate a
3126 * section segment to describe the data file mapping
3128 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3130 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3131 TAG_MM_SECTION_SEGMENT
);
3132 if (Segment
== NULL
)
3134 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3135 ObDereferenceObject(Section
);
3136 ObDereferenceObject(FileObject
);
3137 return(STATUS_NO_MEMORY
);
3139 Section
->Segment
= Segment
;
3140 Segment
->ReferenceCount
= 1;
3141 ExInitializeFastMutex(&Segment
->Lock
);
3143 * Set the lock before assigning the segment to the file object
3145 ExAcquireFastMutex(&Segment
->Lock
);
3146 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3148 Segment
->FileOffset
= 0;
3149 Segment
->Protection
= SectionPageProtection
;
3150 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3151 Segment
->Characteristics
= 0;
3152 Segment
->WriteCopy
= FALSE
;
3153 if (AllocationAttributes
& SEC_RESERVE
)
3155 Segment
->Length
= Segment
->RawLength
= 0;
3159 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3160 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3162 Segment
->VirtualAddress
= 0;
3163 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
3168 * If the file is already mapped as a data file then we may need
3172 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3174 Section
->Segment
= Segment
;
3175 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3176 MmLockSectionSegment(Segment
);
3178 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
3179 !(AllocationAttributes
& SEC_RESERVE
))
3181 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3182 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3185 MmUnlockSectionSegment(Segment
);
3186 Section
->FileObject
= FileObject
;
3187 Section
->MaximumSize
= MaximumSize
;
3189 CcRosReferenceCache(FileObject
);
3191 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3192 *SectionObject
= Section
;
3193 return(STATUS_SUCCESS
);
3197 TODO: not that great (declaring loaders statically, having to declare all of
3198 them, having to keep them extern, etc.), will fix in the future
3200 extern NTSTATUS NTAPI PeFmtCreateSection
3202 IN CONST VOID
* FileHeader
,
3203 IN SIZE_T FileHeaderSize
,
3205 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3207 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3208 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3211 extern NTSTATUS NTAPI ElfFmtCreateSection
3213 IN CONST VOID
* FileHeader
,
3214 IN SIZE_T FileHeaderSize
,
3216 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3218 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3219 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3222 /* TODO: this is a standard DDK/PSDK macro */
3223 #ifndef RTL_NUMBER_OF
3224 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3227 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3238 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3240 SIZE_T SizeOfSegments
;
3241 PMM_SECTION_SEGMENT Segments
;
3243 /* TODO: check for integer overflow */
3244 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3246 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3248 TAG_MM_SECTION_SEGMENT
);
3251 RtlZeroMemory(Segments
, SizeOfSegments
);
3259 ExeFmtpReadFile(IN PVOID File
,
3260 IN PLARGE_INTEGER Offset
,
3263 OUT PVOID
* AllocBase
,
3264 OUT PULONG ReadSize
)
3267 LARGE_INTEGER FileOffset
;
3269 ULONG OffsetAdjustment
;
3274 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3278 KeBugCheck(MEMORY_MANAGEMENT
);
3281 FileOffset
= *Offset
;
3283 /* Negative/special offset: it cannot be used in this context */
3284 if(FileOffset
.u
.HighPart
< 0)
3286 KeBugCheck(MEMORY_MANAGEMENT
);
3289 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3290 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3291 FileOffset
.u
.LowPart
= AdjustOffset
;
3293 BufferSize
= Length
+ OffsetAdjustment
;
3294 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3297 * It's ok to use paged pool, because this is a temporary buffer only used in
3298 * the loading of executables. The assumption is that MmCreateSection is
3299 * always called at low IRQLs and that these buffers don't survive a brief
3300 * initialization phase
3302 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3307 KeBugCheck(MEMORY_MANAGEMENT
);
3313 Status
= MmspPageRead(File
,
3320 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
3321 * nothing will work. But using ZwReadFile is wrong, and using its side effects
3322 * to initialize internal state is even worse. Our cache manager is in need of
3326 IO_STATUS_BLOCK Iosb
;
3328 Status
= ZwReadFile(File
,
3338 if(NT_SUCCESS(Status
))
3340 UsedSize
= Iosb
.Information
;
3345 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3347 Status
= STATUS_IN_PAGE_ERROR
;
3348 ASSERT(!NT_SUCCESS(Status
));
3351 if(NT_SUCCESS(Status
))
3353 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3354 *AllocBase
= Buffer
;
3355 *ReadSize
= UsedSize
- OffsetAdjustment
;
3359 ExFreePoolWithTag(Buffer
, 'rXmM');
3366 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3367 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3368 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3373 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3377 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3379 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3380 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
3387 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3391 MmspAssertSegmentsSorted(ImageSectionObject
);
3393 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3395 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
3399 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3400 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3401 ImageSectionObject
->Segments
[i
- 1].Length
));
3409 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3413 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3415 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
3416 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
3424 MmspCompareSegments(const void * x
,
3427 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3428 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3431 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
3432 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3436 * Ensures an image section's segments are sorted in memory
3441 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3444 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3446 MmspAssertSegmentsSorted(ImageSectionObject
);
3450 qsort(ImageSectionObject
->Segments
,
3451 ImageSectionObject
->NrSegments
,
3452 sizeof(ImageSectionObject
->Segments
[0]),
3453 MmspCompareSegments
);
3459 * Ensures an image section's segments don't overlap in memory and don't have
3460 * gaps and don't have a null size. We let them map to overlapping file regions,
3461 * though - that's not necessarily an error
3466 MmspCheckSegmentBounds
3468 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3474 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3476 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3480 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3482 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3484 if(ImageSectionObject
->Segments
[i
].Length
== 0)
3492 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3493 * page could be OK (Windows seems to be OK with them), and larger gaps
3494 * could lead to image sections spanning several discontiguous regions
3495 * (NtMapViewOfSection could then refuse to map them, and they could
3496 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3498 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3499 ImageSectionObject
->Segments
[i
- 1].Length
) !=
3500 ImageSectionObject
->Segments
[i
].VirtualAddress
)
3511 * Merges and pads an image section's segments until they all are page-aligned
3512 * and have a size that is a multiple of the page size
3517 MmspPageAlignSegments
3519 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3525 PMM_SECTION_SEGMENT EffectiveSegment
;
3527 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3529 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3534 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3536 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3539 * The first segment requires special handling
3543 ULONG_PTR VirtualAddress
;
3544 ULONG_PTR VirtualOffset
;
3546 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3548 /* Round down the virtual address to the nearest page */
3549 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3551 /* Round up the virtual size to the nearest page */
3552 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3553 EffectiveSegment
->VirtualAddress
;
3555 /* Adjust the raw address and size */
3556 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3558 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3564 * Garbage in, garbage out: unaligned base addresses make the file
3565 * offset point in curious and odd places, but that's what we were
3568 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3569 EffectiveSegment
->RawLength
+= VirtualOffset
;
3573 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3574 ULONG_PTR EndOfEffectiveSegment
;
3576 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3577 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3580 * The current segment begins exactly where the current effective
3581 * segment ended, therefore beginning a new effective segment
3583 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3586 ASSERT(LastSegment
<= i
);
3587 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3589 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3591 if (LastSegment
!= i
)
3594 * Copy the current segment. If necessary, the effective segment
3595 * will be expanded later
3597 *EffectiveSegment
= *Segment
;
3601 * Page-align the virtual size. We know for sure the virtual address
3604 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3605 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3608 * The current segment is still part of the current effective segment:
3609 * extend the effective segment to reflect this
3611 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3613 static const ULONG FlagsToProtection
[16] =
3621 PAGE_EXECUTE_READWRITE
,
3622 PAGE_EXECUTE_READWRITE
,
3627 PAGE_EXECUTE_WRITECOPY
,
3628 PAGE_EXECUTE_WRITECOPY
,
3629 PAGE_EXECUTE_WRITECOPY
,
3630 PAGE_EXECUTE_WRITECOPY
3633 unsigned ProtectionFlags
;
3636 * Extend the file size
3639 /* Unaligned segments must be contiguous within the file */
3640 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3641 EffectiveSegment
->RawLength
))
3646 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3649 * Extend the virtual size
3651 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3653 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3654 EffectiveSegment
->VirtualAddress
;
3657 * Merge the protection
3659 EffectiveSegment
->Protection
|= Segment
->Protection
;
3661 /* Clean up redundance */
3662 ProtectionFlags
= 0;
3664 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3665 ProtectionFlags
|= 1 << 0;
3667 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3668 ProtectionFlags
|= 1 << 1;
3670 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3671 ProtectionFlags
|= 1 << 2;
3673 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3674 ProtectionFlags
|= 1 << 3;
3676 ASSERT(ProtectionFlags
< 16);
3677 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3679 /* If a segment was required to be shared and cannot, fail */
3680 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3681 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3687 * We assume no holes between segments at this point
3691 KeBugCheck(MEMORY_MANAGEMENT
);
3695 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3701 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3702 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3704 LARGE_INTEGER Offset
;
3706 PVOID FileHeaderBuffer
;
3707 ULONG FileHeaderSize
;
3709 ULONG OldNrSegments
;
3714 * Read the beginning of the file (2 pages). Should be enough to contain
3715 * all (or most) of the headers
3717 Offset
.QuadPart
= 0;
3719 /* FIXME: use FileObject instead of FileHandle */
3720 Status
= ExeFmtpReadFile (FileHandle
,
3727 if (!NT_SUCCESS(Status
))
3730 if (FileHeaderSize
== 0)
3732 ExFreePool(FileHeaderBuffer
);
3733 return STATUS_UNSUCCESSFUL
;
3737 * Look for a loader that can handle this executable
3739 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3741 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3744 /* FIXME: use FileObject instead of FileHandle */
3745 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3751 ExeFmtpAllocateSegments
);
3753 if (!NT_SUCCESS(Status
))
3755 if (ImageSectionObject
->Segments
)
3757 ExFreePool(ImageSectionObject
->Segments
);
3758 ImageSectionObject
->Segments
= NULL
;
3762 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3766 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3769 * No loader handled the format
3771 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3773 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3774 ASSERT(!NT_SUCCESS(Status
));
3777 if (!NT_SUCCESS(Status
))
3780 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3785 /* FIXME? are these values platform-dependent? */
3786 if(ImageSectionObject
->StackReserve
== 0)
3787 ImageSectionObject
->StackReserve
= 0x40000;
3789 if(ImageSectionObject
->StackCommit
== 0)
3790 ImageSectionObject
->StackCommit
= 0x1000;
3792 if(ImageSectionObject
->ImageBase
== 0)
3794 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3795 ImageSectionObject
->ImageBase
= 0x10000000;
3797 ImageSectionObject
->ImageBase
= 0x00400000;
3801 * And now the fun part: fixing the segments
3804 /* Sort them by virtual address */
3805 MmspSortSegments(ImageSectionObject
, Flags
);
3807 /* Ensure they don't overlap in memory */
3808 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3809 return STATUS_INVALID_IMAGE_FORMAT
;
3811 /* Ensure they are aligned */
3812 OldNrSegments
= ImageSectionObject
->NrSegments
;
3814 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3815 return STATUS_INVALID_IMAGE_FORMAT
;
3817 /* Trim them if the alignment phase merged some of them */
3818 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3820 PMM_SECTION_SEGMENT Segments
;
3821 SIZE_T SizeOfSegments
;
3823 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3825 Segments
= ExAllocatePoolWithTag(PagedPool
,
3827 TAG_MM_SECTION_SEGMENT
);
3829 if (Segments
== NULL
)
3830 return STATUS_INSUFFICIENT_RESOURCES
;
3832 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3833 ExFreePool(ImageSectionObject
->Segments
);
3834 ImageSectionObject
->Segments
= Segments
;
3837 /* And finish their initialization */
3838 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3840 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3841 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3843 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3844 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3847 ASSERT(NT_SUCCESS(Status
));
3852 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3853 ACCESS_MASK DesiredAccess
,
3854 POBJECT_ATTRIBUTES ObjectAttributes
,
3855 PLARGE_INTEGER UMaximumSize
,
3856 ULONG SectionPageProtection
,
3857 ULONG AllocationAttributes
,
3860 PROS_SECTION_OBJECT Section
;
3862 PFILE_OBJECT FileObject
;
3863 PMM_SECTION_SEGMENT SectionSegments
;
3864 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3866 ULONG FileAccess
= 0;
3869 * Check file access required
3871 if (SectionPageProtection
& PAGE_READWRITE
||
3872 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3874 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3878 FileAccess
= FILE_READ_DATA
;
3882 * Reference the file handle
3884 Status
= ObReferenceObjectByHandle(FileHandle
,
3887 ExGetPreviousMode(),
3888 (PVOID
*)(PVOID
)&FileObject
,
3891 if (!NT_SUCCESS(Status
))
3897 * Create the section
3899 Status
= ObCreateObject (ExGetPreviousMode(),
3900 MmSectionObjectType
,
3902 ExGetPreviousMode(),
3904 sizeof(ROS_SECTION_OBJECT
),
3907 (PVOID
*)(PVOID
)&Section
);
3908 if (!NT_SUCCESS(Status
))
3910 ObDereferenceObject(FileObject
);
3917 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3918 Section
->SectionPageProtection
= SectionPageProtection
;
3919 Section
->AllocationAttributes
= AllocationAttributes
;
3923 * Initialized caching for this file object if previously caching
3924 * was initialized for the same on disk file
3926 Status
= CcTryToInitializeFileCache(FileObject
);
3928 Status
= STATUS_SUCCESS
;
3931 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3933 NTSTATUS StatusExeFmt
;
3935 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3936 if (ImageSectionObject
== NULL
)
3938 ObDereferenceObject(FileObject
);
3939 ObDereferenceObject(Section
);
3940 return(STATUS_NO_MEMORY
);
3943 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3945 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3947 if (!NT_SUCCESS(StatusExeFmt
))
3949 if(ImageSectionObject
->Segments
!= NULL
)
3950 ExFreePool(ImageSectionObject
->Segments
);
3952 ExFreePool(ImageSectionObject
);
3953 ObDereferenceObject(Section
);
3954 ObDereferenceObject(FileObject
);
3955 return(StatusExeFmt
);
3958 Section
->ImageSection
= ImageSectionObject
;
3959 ASSERT(ImageSectionObject
->Segments
);
3964 Status
= MmspWaitForFileLock(FileObject
);
3965 if (!NT_SUCCESS(Status
))
3967 ExFreePool(ImageSectionObject
->Segments
);
3968 ExFreePool(ImageSectionObject
);
3969 ObDereferenceObject(Section
);
3970 ObDereferenceObject(FileObject
);
3974 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3975 ImageSectionObject
, NULL
))
3978 * An other thread has initialized the same image in the background
3980 ExFreePool(ImageSectionObject
->Segments
);
3981 ExFreePool(ImageSectionObject
);
3982 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3983 Section
->ImageSection
= ImageSectionObject
;
3984 SectionSegments
= ImageSectionObject
->Segments
;
3986 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3988 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3992 Status
= StatusExeFmt
;
3999 Status
= MmspWaitForFileLock(FileObject
);
4000 if (Status
!= STATUS_SUCCESS
)
4002 ObDereferenceObject(Section
);
4003 ObDereferenceObject(FileObject
);
4007 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
4008 Section
->ImageSection
= ImageSectionObject
;
4009 SectionSegments
= ImageSectionObject
->Segments
;
4012 * Otherwise just reference all the section segments
4014 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
4016 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
4019 Status
= STATUS_SUCCESS
;
4021 Section
->FileObject
= FileObject
;
4023 CcRosReferenceCache(FileObject
);
4025 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
4026 *SectionObject
= Section
;
4033 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
4034 PROS_SECTION_OBJECT Section
,
4035 PMM_SECTION_SEGMENT Segment
,
4040 ULONG AllocationType
)
4044 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4046 BoundaryAddressMultiple
.QuadPart
= 0;
4048 Status
= MmCreateMemoryArea(AddressSpace
,
4049 MEMORY_AREA_SECTION_VIEW
,
4056 BoundaryAddressMultiple
);
4057 if (!NT_SUCCESS(Status
))
4059 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
4060 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
4064 ObReferenceObject((PVOID
)Section
);
4066 MArea
->Data
.SectionData
.Segment
= Segment
;
4067 MArea
->Data
.SectionData
.Section
= Section
;
4068 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
4069 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
4070 ViewSize
, 0, Protect
);
4072 return(STATUS_SUCCESS
);
4078 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
4079 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4082 PFILE_OBJECT FileObject
;
4085 SWAPENTRY SavedSwapEntry
;
4088 PROS_SECTION_OBJECT Section
;
4089 PMM_SECTION_SEGMENT Segment
;
4090 PMMSUPPORT AddressSpace
;
4093 AddressSpace
= (PMMSUPPORT
)Context
;
4094 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4096 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4098 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
4099 MemoryArea
->Data
.SectionData
.ViewOffset
;
4101 Section
= MemoryArea
->Data
.SectionData
.Section
;
4102 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4104 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4108 MmUnlockSectionSegment(Segment
);
4109 MmUnlockAddressSpace(AddressSpace
);
4111 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4112 if (Status
!= STATUS_SUCCESS
)
4114 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4115 KeBugCheck(MEMORY_MANAGEMENT
);
4118 MmLockAddressSpace(AddressSpace
);
4119 MmLockSectionSegment(Segment
);
4120 MmspCompleteAndReleasePageOp(PageOp
);
4121 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4124 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
4127 * For a dirty, datafile, non-private page mark it as dirty in the
4130 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4132 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4134 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4135 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4137 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
4139 ASSERT(SwapEntry
== 0);
4148 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4150 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4151 KeBugCheck(MEMORY_MANAGEMENT
);
4153 MmFreeSwapPage(SwapEntry
);
4157 if (IS_SWAP_FROM_SSE(Entry
) ||
4158 Page
!= PFN_FROM_SSE(Entry
))
4163 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4165 DPRINT1("Found a private page in a pagefile section.\n");
4166 KeBugCheck(MEMORY_MANAGEMENT
);
4169 * Just dereference private pages
4171 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4172 if (SavedSwapEntry
!= 0)
4174 MmFreeSwapPage(SavedSwapEntry
);
4175 MmSetSavedSwapEntryPage(Page
, 0);
4177 MmDeleteRmap(Page
, Process
, Address
);
4178 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4182 MmDeleteRmap(Page
, Process
, Address
);
4183 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4189 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4193 PMEMORY_AREA MemoryArea
;
4194 PROS_SECTION_OBJECT Section
;
4195 PMM_SECTION_SEGMENT Segment
;
4196 PLIST_ENTRY CurrentEntry
;
4197 PMM_REGION CurrentRegion
;
4198 PLIST_ENTRY RegionListHead
;
4200 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4202 if (MemoryArea
== NULL
)
4204 return(STATUS_UNSUCCESSFUL
);
4207 MemoryArea
->DeleteInProgress
= TRUE
;
4208 Section
= MemoryArea
->Data
.SectionData
.Section
;
4209 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4211 MmLockSectionSegment(Segment
);
4213 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4214 while (!IsListEmpty(RegionListHead
))
4216 CurrentEntry
= RemoveHeadList(RegionListHead
);
4217 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4218 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4221 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4223 Status
= MmFreeMemoryArea(AddressSpace
,
4230 Status
= MmFreeMemoryArea(AddressSpace
,
4235 MmUnlockSectionSegment(Segment
);
4236 ObDereferenceObject(Section
);
4244 MmUnmapViewOfSection(PEPROCESS Process
,
4248 PMEMORY_AREA MemoryArea
;
4249 PMMSUPPORT AddressSpace
;
4250 PROS_SECTION_OBJECT Section
;
4253 PVOID ImageBaseAddress
= 0;
4255 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4256 Process
, BaseAddress
);
4260 AddressSpace
= &Process
->Vm
;
4262 MmLockAddressSpace(AddressSpace
);
4263 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4265 if (MemoryArea
== NULL
||
4266 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4267 MemoryArea
->DeleteInProgress
)
4269 MmUnlockAddressSpace(AddressSpace
);
4270 return STATUS_NOT_MAPPED_VIEW
;
4273 MemoryArea
->DeleteInProgress
= TRUE
;
4275 while (MemoryArea
->PageOpCount
)
4277 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4281 Offset
-= PAGE_SIZE
;
4282 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4283 MemoryArea
->Data
.SectionData
.Segment
,
4284 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4287 MmUnlockAddressSpace(AddressSpace
);
4288 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4289 if (Status
!= STATUS_SUCCESS
)
4291 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4292 KeBugCheck(MEMORY_MANAGEMENT
);
4294 MmLockAddressSpace(AddressSpace
);
4295 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4297 if (MemoryArea
== NULL
||
4298 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4300 MmUnlockAddressSpace(AddressSpace
);
4301 return STATUS_NOT_MAPPED_VIEW
;
4308 Section
= MemoryArea
->Data
.SectionData
.Section
;
4310 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4314 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4315 PMM_SECTION_SEGMENT SectionSegments
;
4316 PMM_SECTION_SEGMENT Segment
;
4318 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4319 ImageSectionObject
= Section
->ImageSection
;
4320 SectionSegments
= ImageSectionObject
->Segments
;
4321 NrSegments
= ImageSectionObject
->NrSegments
;
4323 /* Search for the current segment within the section segments
4324 * and calculate the image base address */
4325 for (i
= 0; i
< NrSegments
; i
++)
4327 if (Segment
== &SectionSegments
[i
])
4329 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4333 if (i
>= NrSegments
)
4335 KeBugCheck(MEMORY_MANAGEMENT
);
4338 for (i
= 0; i
< NrSegments
; i
++)
4340 PVOID SBaseAddress
= (PVOID
)
4341 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4343 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4348 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4351 MmUnlockAddressSpace(AddressSpace
);
4353 /* Notify debugger */
4354 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4356 return(STATUS_SUCCESS
);
4363 * Queries the information of a section object.
4365 * @param SectionHandle
4366 * Handle to the section object. It must be opened with SECTION_QUERY
4368 * @param SectionInformationClass
4369 * Index to a certain information structure. Can be either
4370 * SectionBasicInformation or SectionImageInformation. The latter
4371 * is valid only for sections that were created with the SEC_IMAGE
4373 * @param SectionInformation
4374 * Caller supplies storage for resulting information.
4376 * Size of the supplied storage.
4377 * @param ResultLength
4385 NtQuerySection(IN HANDLE SectionHandle
,
4386 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4387 OUT PVOID SectionInformation
,
4388 IN SIZE_T SectionInformationLength
,
4389 OUT PSIZE_T ResultLength OPTIONAL
)
4391 PROS_SECTION_OBJECT Section
;
4392 KPROCESSOR_MODE PreviousMode
;
4396 PreviousMode
= ExGetPreviousMode();
4398 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4400 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4402 SectionInformationLength
,
4407 if(!NT_SUCCESS(Status
))
4409 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4413 Status
= ObReferenceObjectByHandle(SectionHandle
,
4415 MmSectionObjectType
,
4417 (PVOID
*)(PVOID
)&Section
,
4419 if (NT_SUCCESS(Status
))
4421 switch (SectionInformationClass
)
4423 case SectionBasicInformation
:
4425 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4429 Sbi
->Attributes
= Section
->AllocationAttributes
;
4430 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4432 Sbi
->BaseAddress
= 0;
4433 Sbi
->Size
.QuadPart
= 0;
4437 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4438 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4441 if (ResultLength
!= NULL
)
4443 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4445 Status
= STATUS_SUCCESS
;
4447 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4449 Status
= _SEH2_GetExceptionCode();
4456 case SectionImageInformation
:
4458 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4462 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4463 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4465 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4466 ImageSectionObject
= Section
->ImageSection
;
4468 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4469 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4470 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4471 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4472 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4473 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4474 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4475 Sii
->Machine
= ImageSectionObject
->Machine
;
4476 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4479 if (ResultLength
!= NULL
)
4481 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4483 Status
= STATUS_SUCCESS
;
4485 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4487 Status
= _SEH2_GetExceptionCode();
4495 ObDereferenceObject(Section
);
4501 /**********************************************************************
4503 * MmMapViewOfSection
4506 * Maps a view of a section into the virtual address space of a
4511 * Pointer to the section object.
4514 * Pointer to the process.
4517 * Desired base address (or NULL) on entry;
4518 * Actual base address of the view on exit.
4521 * Number of high order address bits that must be zero.
4524 * Size in bytes of the initially committed section of
4528 * Offset in bytes from the beginning of the section
4529 * to the beginning of the view.
4532 * Desired length of map (or zero to map all) on entry
4533 * Actual length mapped on exit.
4535 * InheritDisposition
4536 * Specified how the view is to be shared with
4540 * Type of allocation for the pages.
4543 * Protection for the committed region of the view.
4551 MmMapViewOfSection(IN PVOID SectionObject
,
4552 IN PEPROCESS Process
,
4553 IN OUT PVOID
*BaseAddress
,
4554 IN ULONG_PTR ZeroBits
,
4555 IN SIZE_T CommitSize
,
4556 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4557 IN OUT PSIZE_T ViewSize
,
4558 IN SECTION_INHERIT InheritDisposition
,
4559 IN ULONG AllocationType
,
4562 PROS_SECTION_OBJECT Section
;
4563 PMMSUPPORT AddressSpace
;
4565 NTSTATUS Status
= STATUS_SUCCESS
;
4566 BOOLEAN NotAtBase
= FALSE
;
4568 if ((ULONG_PTR
)SectionObject
& 1)
4570 return MmMapViewOfArm3Section((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4584 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4586 return STATUS_INVALID_PAGE_PROTECTION
;
4590 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4591 AddressSpace
= &Process
->Vm
;
4593 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4595 MmLockAddressSpace(AddressSpace
);
4597 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4601 ULONG_PTR ImageBase
;
4603 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4604 PMM_SECTION_SEGMENT SectionSegments
;
4606 ImageSectionObject
= Section
->ImageSection
;
4607 SectionSegments
= ImageSectionObject
->Segments
;
4608 NrSegments
= ImageSectionObject
->NrSegments
;
4611 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4614 ImageBase
= ImageSectionObject
->ImageBase
;
4618 for (i
= 0; i
< NrSegments
; i
++)
4620 ULONG_PTR MaxExtent
;
4621 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4622 SectionSegments
[i
].Length
;
4623 ImageSize
= max(ImageSize
, MaxExtent
);
4626 ImageSectionObject
->ImageSize
= ImageSize
;
4628 /* Check there is enough space to map the section at that point. */
4629 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4630 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4632 /* Fail if the user requested a fixed base address. */
4633 if ((*BaseAddress
) != NULL
)
4635 MmUnlockAddressSpace(AddressSpace
);
4636 return(STATUS_UNSUCCESSFUL
);
4638 /* Otherwise find a gap to map the image. */
4639 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4642 MmUnlockAddressSpace(AddressSpace
);
4643 return(STATUS_UNSUCCESSFUL
);
4645 /* Remember that we loaded image at a different base address */
4649 for (i
= 0; i
< NrSegments
; i
++)
4651 PVOID SBaseAddress
= (PVOID
)
4652 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4653 MmLockSectionSegment(&SectionSegments
[i
]);
4654 Status
= MmMapViewOfSegment(AddressSpace
,
4656 &SectionSegments
[i
],
4658 SectionSegments
[i
].Length
,
4659 SectionSegments
[i
].Protection
,
4662 MmUnlockSectionSegment(&SectionSegments
[i
]);
4663 if (!NT_SUCCESS(Status
))
4665 MmUnlockAddressSpace(AddressSpace
);
4670 *BaseAddress
= (PVOID
)ImageBase
;
4671 *ViewSize
= ImageSize
;
4675 /* check for write access */
4676 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4677 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4679 MmUnlockAddressSpace(AddressSpace
);
4680 return STATUS_SECTION_PROTECTION
;
4682 /* check for read access */
4683 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4684 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4686 MmUnlockAddressSpace(AddressSpace
);
4687 return STATUS_SECTION_PROTECTION
;
4689 /* check for execute access */
4690 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4691 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4693 MmUnlockAddressSpace(AddressSpace
);
4694 return STATUS_SECTION_PROTECTION
;
4697 if (ViewSize
== NULL
)
4699 /* Following this pointer would lead to us to the dark side */
4700 /* What to do? Bugcheck? Return status? Do the mambo? */
4701 KeBugCheck(MEMORY_MANAGEMENT
);
4704 if (SectionOffset
== NULL
)
4710 ViewOffset
= SectionOffset
->u
.LowPart
;
4713 if ((ViewOffset
% PAGE_SIZE
) != 0)
4715 MmUnlockAddressSpace(AddressSpace
);
4716 return(STATUS_MAPPED_ALIGNMENT
);
4719 if ((*ViewSize
) == 0)
4721 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4723 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4725 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4728 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4730 MmLockSectionSegment(Section
->Segment
);
4731 Status
= MmMapViewOfSegment(AddressSpace
,
4738 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4739 MmUnlockSectionSegment(Section
->Segment
);
4740 if (!NT_SUCCESS(Status
))
4742 MmUnlockAddressSpace(AddressSpace
);
4747 MmUnlockAddressSpace(AddressSpace
);
4750 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4752 Status
= STATUS_SUCCESS
;
4761 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4762 IN PLARGE_INTEGER NewFileSize
)
4764 /* Check whether an ImageSectionObject exists */
4765 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4767 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4771 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4773 PMM_SECTION_SEGMENT Segment
;
4775 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4778 if (Segment
->ReferenceCount
!= 0)
4780 /* Check size of file */
4781 if (SectionObjectPointer
->SharedCacheMap
)
4783 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4784 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4792 /* Something must gone wrong
4793 * how can we have a Section but no
4795 DPRINT("ERROR: DataSectionObject without reference!\n");
4799 DPRINT("FIXME: didn't check for outstanding write probes\n");
4811 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4812 IN MMFLUSH_TYPE FlushType
)
4816 case MmFlushForDelete
:
4817 if (SectionObjectPointer
->ImageSectionObject
||
4818 SectionObjectPointer
->DataSectionObject
)
4823 CcRosSetRemoveOnClose(SectionObjectPointer
);
4826 case MmFlushForWrite
:
4836 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4837 OUT PVOID
* MappedBase
,
4838 IN OUT PSIZE_T ViewSize
)
4840 PROS_SECTION_OBJECT Section
;
4841 PMMSUPPORT AddressSpace
;
4845 if ((ULONG_PTR
)SectionObject
& 1)
4847 extern PVOID MmSession
;
4848 return MiMapViewInSystemSpace((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4854 DPRINT("MmMapViewInSystemSpace() called\n");
4856 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4857 AddressSpace
= MmGetKernelAddressSpace();
4859 MmLockAddressSpace(AddressSpace
);
4862 if ((*ViewSize
) == 0)
4864 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4866 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4868 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4871 MmLockSectionSegment(Section
->Segment
);
4874 Status
= MmMapViewOfSegment(AddressSpace
,
4883 MmUnlockSectionSegment(Section
->Segment
);
4884 MmUnlockAddressSpace(AddressSpace
);
4893 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4895 PMMSUPPORT AddressSpace
;
4898 DPRINT("MmUnmapViewInSystemSpace() called\n");
4900 AddressSpace
= MmGetKernelAddressSpace();
4902 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4908 /**********************************************************************
4913 * Creates a section object.
4916 * SectionObject (OUT)
4917 * Caller supplied storage for the resulting pointer
4918 * to a SECTION_OBJECT instance;
4921 * Specifies the desired access to the section can be a
4923 * STANDARD_RIGHTS_REQUIRED |
4925 * SECTION_MAP_WRITE |
4926 * SECTION_MAP_READ |
4927 * SECTION_MAP_EXECUTE
4929 * ObjectAttributes [OPTIONAL]
4930 * Initialized attributes for the object can be used
4931 * to create a named section;
4934 * Maximizes the size of the memory section. Must be
4935 * non-NULL for a page-file backed section.
4936 * If value specified for a mapped file and the file is
4937 * not large enough, file will be extended.
4939 * SectionPageProtection
4940 * Can be a combination of:
4946 * AllocationAttributes
4947 * Can be a combination of:
4952 * Handle to a file to create a section mapped to a file
4953 * instead of a memory backed section;
4964 MmCreateSection (OUT PVOID
* Section
,
4965 IN ACCESS_MASK DesiredAccess
,
4966 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4967 IN PLARGE_INTEGER MaximumSize
,
4968 IN ULONG SectionPageProtection
,
4969 IN ULONG AllocationAttributes
,
4970 IN HANDLE FileHandle OPTIONAL
,
4971 IN PFILE_OBJECT File OPTIONAL
)
4974 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4976 /* Check if an ARM3 section is being created instead */
4977 if (AllocationAttributes
& 1)
4979 DPRINT1("arm 3 path\n");
4980 return MmCreateArm3Section(Section
,
4984 SectionPageProtection
,
4985 AllocationAttributes
&~ 1,
4991 * Check the protection
4993 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4994 if (Protection
!= PAGE_READONLY
&&
4995 Protection
!= PAGE_READWRITE
&&
4996 Protection
!= PAGE_WRITECOPY
&&
4997 Protection
!= PAGE_EXECUTE
&&
4998 Protection
!= PAGE_EXECUTE_READ
&&
4999 Protection
!= PAGE_EXECUTE_READWRITE
&&
5000 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5002 return STATUS_INVALID_PAGE_PROTECTION
;
5005 if (AllocationAttributes
& SEC_IMAGE
)
5007 return(MmCreateImageSection(SectionObject
,
5011 SectionPageProtection
,
5012 AllocationAttributes
,
5016 if (FileHandle
!= NULL
)
5018 return(MmCreateDataFileSection(SectionObject
,
5022 SectionPageProtection
,
5023 AllocationAttributes
,
5027 return(MmCreatePageFileSection(SectionObject
,
5031 SectionPageProtection
,
5032 AllocationAttributes
));