2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
49 #include "../cache/section/newmm.h"
53 #include <reactos/exeformat.h>
55 #if defined (ALLOC_PRAGMA)
56 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
57 #pragma alloc_text(INIT, MmInitSectionImplementation)
62 MiMapViewInSystemSpace(IN PVOID Section
,
64 OUT PVOID
*MappedBase
,
65 IN OUT PSIZE_T ViewSize
);
69 MmCreateArm3Section(OUT PVOID
*SectionObject
,
70 IN ACCESS_MASK DesiredAccess
,
71 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
72 IN PLARGE_INTEGER InputMaximumSize
,
73 IN ULONG SectionPageProtection
,
74 IN ULONG AllocationAttributes
,
75 IN HANDLE FileHandle OPTIONAL
,
76 IN PFILE_OBJECT FileObject OPTIONAL
);
80 MmMapViewOfArm3Section(IN PVOID SectionObject
,
82 IN OUT PVOID
*BaseAddress
,
83 IN ULONG_PTR ZeroBits
,
85 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
86 IN OUT PSIZE_T ViewSize
,
87 IN SECTION_INHERIT InheritDisposition
,
88 IN ULONG AllocationType
,
92 // PeFmtCreateSection depends on the following:
94 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
95 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
97 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
98 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
99 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
101 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
102 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
103 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
104 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
105 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
106 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
107 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
108 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
109 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
111 /* TYPES *********************************************************************/
115 PROS_SECTION_OBJECT Section
;
116 PMM_SECTION_SEGMENT Segment
;
121 MM_SECTION_PAGEOUT_CONTEXT
;
123 /* GLOBALS *******************************************************************/
125 POBJECT_TYPE MmSectionObjectType
= NULL
;
127 ULONG_PTR MmSubsectionBase
;
129 static ULONG SectionCharacteristicsToProtect
[16] =
131 PAGE_NOACCESS
, /* 0 = NONE */
132 PAGE_NOACCESS
, /* 1 = SHARED */
133 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
134 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
135 PAGE_READONLY
, /* 4 = READABLE */
136 PAGE_READONLY
, /* 5 = READABLE, SHARED */
137 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
138 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
140 * FIXME? do we really need the WriteCopy field in segments? can't we use
141 * PAGE_WRITECOPY here?
143 PAGE_READWRITE
, /* 8 = WRITABLE */
144 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
145 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
146 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
147 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
148 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
149 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
150 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
153 static GENERIC_MAPPING MmpSectionMapping
= {
154 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
155 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
156 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
159 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
160 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
161 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
162 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
163 #define MAX_SHARE_COUNT 0x7FF
164 #define MAKE_SSE(P, C) ((ULONG)(P) | ((C) << 1))
165 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
166 #define MAKE_SWAP_SSE(S) (((ULONG)(S) << 1) | 0x1)
168 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
170 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
171 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
174 /* FUNCTIONS *****************************************************************/
179 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
180 File Format Specification", revision 6.0 (February 1999)
182 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
183 IN SIZE_T FileHeaderSize
,
185 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
187 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
188 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
191 ULONG cbFileHeaderOffsetSize
= 0;
192 ULONG cbSectionHeadersOffset
= 0;
193 ULONG cbSectionHeadersSize
;
194 ULONG cbSectionHeadersOffsetSize
= 0;
195 ULONG cbOptHeaderSize
;
196 ULONG cbHeadersSize
= 0;
197 ULONG nSectionAlignment
;
198 ULONG nFileAlignment
;
199 const IMAGE_DOS_HEADER
* pidhDosHeader
;
200 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
201 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
202 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
203 PMM_SECTION_SEGMENT pssSegments
;
204 LARGE_INTEGER lnOffset
;
206 SIZE_T nPrevVirtualEndOfSegment
= 0;
207 ULONG nFileSizeOfHeaders
= 0;
211 ASSERT(FileHeaderSize
> 0);
213 ASSERT(ImageSectionObject
);
215 ASSERT(AllocateSegmentsCb
);
217 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
219 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
221 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
224 pidhDosHeader
= FileHeader
;
227 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
229 /* image too small to be an MZ executable */
230 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
231 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
233 /* no MZ signature */
234 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
235 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
237 /* not a Windows executable */
238 if(pidhDosHeader
->e_lfanew
<= 0)
239 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
242 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
244 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
245 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
247 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
252 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
253 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
255 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
256 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
260 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
261 * need to read the header from the file
263 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
264 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
266 ULONG cbNtHeaderSize
;
270 l_ReadHeaderFromFile
:
272 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
274 /* read the header from the file */
275 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
277 if(!NT_SUCCESS(nStatus
))
278 DIE(("ReadFile failed, status %08X\n", nStatus
));
282 ASSERT(cbReadSize
> 0);
284 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
286 /* the buffer doesn't contain the file header */
287 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
288 DIE(("The file doesn't contain the PE file header\n"));
290 pinhNtHeader
= pData
;
292 /* object still not aligned: copy it to the beginning of the buffer */
293 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
295 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
296 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
297 pinhNtHeader
= pBuffer
;
300 /* invalid NT header */
301 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
303 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
304 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
306 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
308 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
309 DIE(("The full NT header is too large\n"));
311 /* the buffer doesn't contain the whole NT header */
312 if(cbReadSize
< cbNtHeaderSize
)
313 DIE(("The file doesn't contain the full NT header\n"));
317 ULONG cbOptHeaderOffsetSize
= 0;
319 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
321 /* don't trust an invalid NT header */
322 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
323 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
325 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
326 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
328 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
329 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
331 /* the buffer doesn't contain the whole NT header: read it from the file */
332 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
333 goto l_ReadHeaderFromFile
;
336 /* read information from the NT header */
337 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
338 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
340 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
342 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
343 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
345 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
347 switch(piohOptHeader
->Magic
)
349 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
350 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
354 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
357 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
358 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
360 /* See [1], section 3.4.2 */
361 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
363 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
364 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
366 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
367 DIE(("The section alignment is smaller than the file alignment\n"));
369 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
370 nFileAlignment
= piohOptHeader
->FileAlignment
;
372 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
373 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
377 nSectionAlignment
= PAGE_SIZE
;
378 nFileAlignment
= PAGE_SIZE
;
381 ASSERT(IsPowerOf2(nSectionAlignment
));
382 ASSERT(IsPowerOf2(nFileAlignment
));
384 switch(piohOptHeader
->Magic
)
387 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
389 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
390 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
392 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
393 ImageSectionObject
->ImageSize
= piohOptHeader
->SizeOfImage
;
395 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
396 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
398 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
399 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
405 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
407 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
409 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
411 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
413 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
414 DIE(("ImageBase exceeds the address space\n"));
416 ImageSectionObject
->ImageBase
= (ULONG_PTR
)pioh64OptHeader
->ImageBase
;
419 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
421 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
422 DIE(("SizeOfImage exceeds the address space\n"));
424 ImageSectionObject
->ImageSize
= pioh64OptHeader
->SizeOfImage
;
427 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
429 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
430 DIE(("SizeOfStackReserve exceeds the address space\n"));
432 ImageSectionObject
->StackReserve
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackReserve
;
435 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
437 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
438 DIE(("SizeOfStackCommit exceeds the address space\n"));
440 ImageSectionObject
->StackCommit
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackCommit
;
447 /* [1], section 3.4.2 */
448 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
449 DIE(("ImageBase is not aligned on a 64KB boundary"));
451 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
453 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
455 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
456 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
458 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
459 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
463 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
465 ImageSectionObject
->EntryPoint
= piohOptHeader
->ImageBase
+
466 piohOptHeader
->AddressOfEntryPoint
;
469 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
470 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
472 ImageSectionObject
->Executable
= TRUE
;
474 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
475 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
477 /* SECTION HEADERS */
478 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
480 /* see [1], section 3.3 */
481 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
482 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
485 * the additional segment is for the file's headers. They need to be present for
486 * the benefit of the dynamic loader (to locate exports, defaults for thread
487 * parameters, resources, etc.)
489 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
491 /* file offset for the section headers */
492 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
493 DIE(("Offset overflow\n"));
495 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
496 DIE(("Offset overflow\n"));
498 /* size of the section headers */
499 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
500 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
502 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
503 DIE(("Section headers too large\n"));
505 /* size of the executable's headers */
506 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
508 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
509 // DIE(("SizeOfHeaders is not aligned\n"));
511 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
512 DIE(("The section headers overflow SizeOfHeaders\n"));
514 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
516 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
517 DIE(("Overflow aligning the size of headers\n"));
524 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
525 /* WARNING: piohOptHeader IS NO LONGER USABLE */
526 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
528 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
529 pishSectionHeaders
= NULL
;
533 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
534 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
536 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
537 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
541 * the buffer doesn't contain the section headers, or the alignment is wrong:
542 * read the headers from the file
544 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
545 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
550 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
552 /* read the header from the file */
553 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
555 if(!NT_SUCCESS(nStatus
))
556 DIE(("ReadFile failed with status %08X\n", nStatus
));
560 ASSERT(cbReadSize
> 0);
562 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
564 /* the buffer doesn't contain all the section headers */
565 if(cbReadSize
< cbSectionHeadersSize
)
566 DIE(("The file doesn't contain all of the section headers\n"));
568 pishSectionHeaders
= pData
;
570 /* object still not aligned: copy it to the beginning of the buffer */
571 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
573 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
574 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
575 pishSectionHeaders
= pBuffer
;
580 /* allocate the segments */
581 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
582 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
584 if(ImageSectionObject
->Segments
== NULL
)
585 DIE(("AllocateSegments failed\n"));
587 /* initialize the headers segment */
588 pssSegments
= ImageSectionObject
->Segments
;
590 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
592 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
593 DIE(("Cannot align the size of the section headers\n"));
595 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
596 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
597 DIE(("Cannot align the size of the section headers\n"));
599 pssSegments
[0].FileOffset
= 0;
600 pssSegments
[0].Protection
= PAGE_READONLY
;
601 pssSegments
[0].Length
= nPrevVirtualEndOfSegment
;
602 pssSegments
[0].RawLength
= nFileSizeOfHeaders
;
603 pssSegments
[0].VirtualAddress
= 0;
604 pssSegments
[0].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
605 pssSegments
[0].WriteCopy
= TRUE
;
607 /* skip the headers segment */
610 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
612 /* convert the executable sections into segments. See also [1], section 4 */
613 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
615 ULONG nCharacteristics
;
617 /* validate the alignment */
618 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
619 DIE(("VirtualAddress[%u] is not aligned\n", i
));
621 /* sections must be contiguous, ordered by base address and non-overlapping */
622 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
623 DIE(("Memory gap between section %u and the previous\n", i
));
625 /* ignore explicit BSS sections */
626 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
628 /* validate the alignment */
630 /* Yes, this should be a multiple of FileAlignment, but there's
631 * stuff out there that isn't. We can cope with that
633 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
634 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
637 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
638 // DIE(("PointerToRawData[%u] is not aligned\n", i));
641 pssSegments
[i
].FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
642 pssSegments
[i
].RawLength
= pishSectionHeaders
[i
].SizeOfRawData
;
646 ASSERT(pssSegments
[i
].FileOffset
== 0);
647 ASSERT(pssSegments
[i
].RawLength
== 0);
650 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].FileOffset
, pssSegments
[i
].RawLength
));
652 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
654 /* no explicit protection */
655 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
657 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
658 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
660 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
661 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
663 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
664 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
667 /* see table above */
668 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
669 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
671 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
672 pssSegments
[i
].Length
= pishSectionHeaders
[i
].SizeOfRawData
;
674 pssSegments
[i
].Length
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
676 pssSegments
[i
].Length
= ALIGN_UP_BY(pssSegments
[i
].Length
, nSectionAlignment
);
677 if (pssSegments
[i
].Length
< pssSegments
[i
].Length
)
678 DIE(("Cannot align the virtual size of section %u\n", i
));
680 if(pssSegments
[i
].Length
== 0)
681 DIE(("Virtual size of section %u is null\n", i
));
683 pssSegments
[i
].VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
684 pssSegments
[i
].Characteristics
= pishSectionHeaders
[i
].Characteristics
;
686 /* ensure the memory image is no larger than 4GB */
687 nPrevVirtualEndOfSegment
= pssSegments
[i
].VirtualAddress
+ pssSegments
[i
].Length
;
688 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].VirtualAddress
)
689 DIE(("The image is too large\n"));
692 if(nSectionAlignment
>= PAGE_SIZE
)
693 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
696 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;
705 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
708 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
709 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
710 * RETURNS: Status of the wait.
713 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
715 LARGE_INTEGER Timeout
;
716 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
718 Timeout
.QuadPart
= -100000000LL; // 10 sec
721 Timeout
.QuadPart
= -100000000; // 10 sec
724 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
729 * FUNCTION: Sets the page op completion event and releases the page op.
730 * ARGUMENTS: PMM_PAGEOP.
731 * RETURNS: In shorter time than it takes you to even read this
732 * description, so don't even think about geting a mug of coffee.
735 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
737 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
738 MmReleasePageOp(PageOp
);
743 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
744 * ARGUMENTS: PFILE_OBJECT to wait for.
745 * RETURNS: Status of the wait.
748 MmspWaitForFileLock(PFILE_OBJECT File
)
750 return STATUS_SUCCESS
;
751 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
756 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
759 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
761 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
763 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
765 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
773 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
775 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
777 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
778 PMM_SECTION_SEGMENT SectionSegments
;
782 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
783 NrSegments
= ImageSectionObject
->NrSegments
;
784 SectionSegments
= ImageSectionObject
->Segments
;
785 for (i
= 0; i
< NrSegments
; i
++)
787 if (SectionSegments
[i
].ReferenceCount
!= 0)
789 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
790 SectionSegments
[i
].ReferenceCount
);
791 KeBugCheck(MEMORY_MANAGEMENT
);
793 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
795 ExFreePool(ImageSectionObject
->Segments
);
796 ExFreePool(ImageSectionObject
);
797 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
799 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
801 PMM_SECTION_SEGMENT Segment
;
803 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
806 if (Segment
->ReferenceCount
!= 0)
808 DPRINT1("Data segment still referenced\n");
809 KeBugCheck(MEMORY_MANAGEMENT
);
811 MmFreePageTablesSectionSegment(Segment
);
813 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
819 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
821 ExAcquireFastMutex(&Segment
->Lock
);
826 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
828 ExReleaseFastMutex(&Segment
->Lock
);
833 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
837 PSECTION_PAGE_TABLE Table
;
838 ULONG_PTR DirectoryOffset
;
839 ULONG_PTR TableOffset
;
841 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
843 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
847 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
848 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
852 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
853 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
854 TAG_SECTION_PAGE_TABLE
);
857 KeBugCheck(MEMORY_MANAGEMENT
);
859 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
860 DPRINT("Table %x\n", Table
);
863 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
864 Table
->Entry
[TableOffset
] = (ULONG
)Entry
;
870 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
873 PSECTION_PAGE_TABLE Table
;
875 ULONG_PTR DirectoryOffset
;
876 ULONG_PTR TableOffset
;
878 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
880 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
882 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
886 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
887 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
888 DPRINT("Table %x\n", Table
);
894 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
895 Entry
= Table
->Entry
[TableOffset
];
901 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
906 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
909 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
910 KeBugCheck(MEMORY_MANAGEMENT
);
912 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
914 DPRINT1("Maximum share count reached\n");
915 KeBugCheck(MEMORY_MANAGEMENT
);
917 if (IS_SWAP_FROM_SSE(Entry
))
919 KeBugCheck(MEMORY_MANAGEMENT
);
921 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
922 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
927 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
928 PMM_SECTION_SEGMENT Segment
,
934 BOOLEAN IsDirectMapped
= FALSE
;
936 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
939 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
940 KeBugCheck(MEMORY_MANAGEMENT
);
942 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
944 DPRINT1("Zero share count for unshare\n");
945 KeBugCheck(MEMORY_MANAGEMENT
);
947 if (IS_SWAP_FROM_SSE(Entry
))
949 KeBugCheck(MEMORY_MANAGEMENT
);
951 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
953 * If we reducing the share count of this entry to zero then set the entry
954 * to zero and tell the cache the page is no longer mapped.
956 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
958 PFILE_OBJECT FileObject
;
960 SWAPENTRY SavedSwapEntry
;
962 BOOLEAN IsImageSection
;
965 FileOffset
= Offset
+ Segment
->FileOffset
;
967 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
969 Page
= PFN_FROM_SSE(Entry
);
970 FileObject
= Section
->FileObject
;
971 if (FileObject
!= NULL
&&
972 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
975 if ((FileOffset
% PAGE_SIZE
) == 0 &&
976 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
979 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
980 IsDirectMapped
= TRUE
;
982 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
984 Status
= STATUS_SUCCESS
;
986 if (!NT_SUCCESS(Status
))
988 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
989 KeBugCheck(MEMORY_MANAGEMENT
);
994 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
995 if (SavedSwapEntry
== 0)
998 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
999 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
1003 * Try to page out this page and set the swap entry
1004 * within the section segment. There exist no rmap entry
1005 * for this page. The pager thread can't page out a
1006 * page without a rmap entry.
1008 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1012 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
1013 if (!IsDirectMapped
)
1015 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1021 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1022 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1030 * We hold all locks. Nobody can do something with the current
1031 * process and the current segment (also not within an other process).
1034 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
1035 if (!NT_SUCCESS(Status
))
1037 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
1038 KeBugCheck(MEMORY_MANAGEMENT
);
1041 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
1042 MmSetSavedSwapEntryPage(Page
, 0);
1044 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1048 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1049 KeBugCheck(MEMORY_MANAGEMENT
);
1055 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1057 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1060 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1064 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1067 PCACHE_SEGMENT CacheSeg
;
1068 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1069 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
1072 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
1082 MiCopyFromUserPage(PFN_NUMBER DestPage
, PVOID SourceAddress
)
1088 Process
= PsGetCurrentProcess();
1089 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1090 if (TempAddress
== NULL
)
1092 return(STATUS_NO_MEMORY
);
1094 memcpy(TempAddress
, SourceAddress
, PAGE_SIZE
);
1095 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
1096 return(STATUS_SUCCESS
);
1102 MiReadPage(PMEMORY_AREA MemoryArea
,
1103 ULONG_PTR SegOffset
,
1106 * FUNCTION: Read a page for a section backed memory area.
1108 * MemoryArea - Memory area to read the page for.
1109 * Offset - Offset of the page to read.
1110 * Page - Variable that receives a page contains the read data.
1114 ULONG_PTR FileOffset
;
1117 PCACHE_SEGMENT CacheSeg
;
1118 PFILE_OBJECT FileObject
;
1120 ULONG_PTR RawLength
;
1122 BOOLEAN IsImageSection
;
1125 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1126 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1127 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
1128 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
1129 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1133 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1136 * If the file system is letting us go directly to the cache and the
1137 * memory area was mapped at an offset in the file which is page aligned
1138 * then get the related cache segment.
1140 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1141 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
1142 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1146 * Get the related cache segment; we use a lower level interface than
1147 * filesystems do because it is safe for us to use an offset with a
1148 * alignment less than the file system block size.
1150 Status
= CcRosGetCacheSegment(Bcb
,
1156 if (!NT_SUCCESS(Status
))
1163 * If the cache segment isn't up to date then call the file
1164 * system to read in the data.
1166 Status
= ReadCacheSegment(CacheSeg
);
1167 if (!NT_SUCCESS(Status
))
1169 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1174 * Retrieve the page from the cache segment that we actually want.
1176 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1177 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1179 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1186 ULONG_PTR CacheSegOffset
;
1189 * Allocate a page, this is rather complicated by the possibility
1190 * we might have to move other things out of memory
1192 MI_SET_USAGE(MI_USAGE_SECTION
);
1193 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1194 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1195 if (!NT_SUCCESS(Status
))
1199 Status
= CcRosGetCacheSegment(Bcb
,
1205 if (!NT_SUCCESS(Status
))
1212 * If the cache segment isn't up to date then call the file
1213 * system to read in the data.
1215 Status
= ReadCacheSegment(CacheSeg
);
1216 if (!NT_SUCCESS(Status
))
1218 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1223 Process
= PsGetCurrentProcess();
1224 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1225 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
1226 Length
= RawLength
- SegOffset
;
1227 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1229 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1231 else if (CacheSegOffset
>= PAGE_SIZE
)
1233 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1237 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1238 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1239 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1240 Status
= CcRosGetCacheSegment(Bcb
,
1241 (ULONG
)(FileOffset
+ CacheSegOffset
),
1246 if (!NT_SUCCESS(Status
))
1253 * If the cache segment isn't up to date then call the file
1254 * system to read in the data.
1256 Status
= ReadCacheSegment(CacheSeg
);
1257 if (!NT_SUCCESS(Status
))
1259 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1263 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1264 if (Length
< PAGE_SIZE
)
1266 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1270 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1273 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1274 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1276 return(STATUS_SUCCESS
);
1281 MiReadPage(PMEMORY_AREA MemoryArea
,
1285 * FUNCTION: Read a page for a section backed memory area.
1287 * MemoryArea - Memory area to read the page for.
1288 * Offset - Offset of the page to read.
1289 * Page - Variable that receives a page contains the read data.
1292 MM_REQUIRED_RESOURCES Resources
= { };
1294 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1295 Resources
.FileOffset
.QuadPart
= SegOffset
+
1296 MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
1297 Resources
.Consumer
= MC_USER
;
1298 Resources
.Amount
= PAGE_SIZE
;
1300 DPRINT1("%S, offset %x, len %d, page %x\n", ((PFILE_OBJECT
)Resources
.Context
)->FileName
.Buffer
, Resources
.FileOffset
.LowPart
, Resources
.Amount
, Resources
.Page
[0]);
1302 NTSTATUS Status
= MiReadFilePage(NULL
, NULL
, &Resources
);
1303 *Page
= Resources
.Page
[0];
1310 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1311 MEMORY_AREA
* MemoryArea
,
1318 PROS_SECTION_OBJECT Section
;
1319 PMM_SECTION_SEGMENT Segment
;
1325 BOOLEAN HasSwapEntry
;
1326 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1329 * There is a window between taking the page fault and locking the
1330 * address space when another thread could load the page so we check
1333 if (MmIsPagePresent(Process
, Address
))
1335 return(STATUS_SUCCESS
);
1339 * Check for the virtual memory area being deleted.
1341 if (MemoryArea
->DeleteInProgress
)
1343 return(STATUS_UNSUCCESSFUL
);
1346 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1347 Offset
= (ULONG
)((ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1348 + MemoryArea
->Data
.SectionData
.ViewOffset
);
1350 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1351 Section
= MemoryArea
->Data
.SectionData
.Section
;
1352 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1353 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1358 MmLockSectionSegment(Segment
);
1361 * Check if this page needs to be mapped COW
1363 if ((Segment
->WriteCopy
) &&
1364 (Region
->Protect
== PAGE_READWRITE
||
1365 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1367 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1371 Attributes
= Region
->Protect
;
1375 * Get or create a page operation descriptor
1377 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
1380 DPRINT1("MmGetPageOp failed\n");
1381 KeBugCheck(MEMORY_MANAGEMENT
);
1385 * Check if someone else is already handling this fault, if so wait
1388 if (PageOp
->Thread
!= PsGetCurrentThread())
1390 MmUnlockSectionSegment(Segment
);
1391 MmUnlockAddressSpace(AddressSpace
);
1392 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1394 * Check for various strange conditions
1396 if (Status
!= STATUS_SUCCESS
)
1398 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1399 KeBugCheck(MEMORY_MANAGEMENT
);
1401 if (PageOp
->Status
== STATUS_PENDING
)
1403 DPRINT1("Woke for page op before completion\n");
1404 KeBugCheck(MEMORY_MANAGEMENT
);
1406 MmLockAddressSpace(AddressSpace
);
1408 * If this wasn't a pagein then restart the operation
1410 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
1412 MmspCompleteAndReleasePageOp(PageOp
);
1413 DPRINT("Address 0x%.8X\n", Address
);
1414 return(STATUS_MM_RESTART_OPERATION
);
1418 * If the thread handling this fault has failed then we don't retry
1420 if (!NT_SUCCESS(PageOp
->Status
))
1422 Status
= PageOp
->Status
;
1423 MmspCompleteAndReleasePageOp(PageOp
);
1424 DPRINT("Address 0x%.8X\n", Address
);
1427 MmLockSectionSegment(Segment
);
1429 * If the completed fault was for another address space then set the
1432 if (!MmIsPagePresent(Process
, Address
))
1434 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1435 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1437 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
1440 * The page was a private page in another or in our address space
1442 MmUnlockSectionSegment(Segment
);
1443 MmspCompleteAndReleasePageOp(PageOp
);
1444 return(STATUS_MM_RESTART_OPERATION
);
1447 Page
= PFN_FROM_SSE(Entry
);
1449 MmSharePageEntrySectionSegment(Segment
, Offset
);
1451 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
1452 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
1454 Status
= MmCreateVirtualMapping(Process
,
1459 if (!NT_SUCCESS(Status
))
1461 DPRINT1("Unable to create virtual mapping\n");
1462 KeBugCheck(MEMORY_MANAGEMENT
);
1464 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1466 MmUnlockSectionSegment(Segment
);
1467 PageOp
->Status
= STATUS_SUCCESS
;
1468 MmspCompleteAndReleasePageOp(PageOp
);
1469 DPRINT("Address 0x%.8X\n", Address
);
1470 return(STATUS_SUCCESS
);
1473 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1477 * Must be private page we have swapped out.
1479 SWAPENTRY SwapEntry
;
1484 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1486 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1487 KeBugCheck(MEMORY_MANAGEMENT
);
1490 MmUnlockSectionSegment(Segment
);
1491 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
1493 MmUnlockAddressSpace(AddressSpace
);
1494 MI_SET_USAGE(MI_USAGE_SECTION
);
1495 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1496 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1497 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1498 if (!NT_SUCCESS(Status
))
1500 KeBugCheck(MEMORY_MANAGEMENT
);
1503 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1504 if (!NT_SUCCESS(Status
))
1506 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1507 KeBugCheck(MEMORY_MANAGEMENT
);
1509 MmLockAddressSpace(AddressSpace
);
1510 Status
= MmCreateVirtualMapping(Process
,
1515 if (!NT_SUCCESS(Status
))
1517 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1518 KeBugCheck(MEMORY_MANAGEMENT
);
1523 * Store the swap entry for later use.
1525 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1528 * Add the page to the process's working set
1530 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1533 * Finish the operation
1535 PageOp
->Status
= STATUS_SUCCESS
;
1536 MmspCompleteAndReleasePageOp(PageOp
);
1537 DPRINT("Address 0x%.8X\n", Address
);
1538 return(STATUS_SUCCESS
);
1542 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1544 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1546 MmUnlockSectionSegment(Segment
);
1548 * Just map the desired physical page
1550 Page
= Offset
>> PAGE_SHIFT
;
1551 Status
= MmCreateVirtualMappingUnsafe(Process
,
1556 if (!NT_SUCCESS(Status
))
1558 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1559 KeBugCheck(MEMORY_MANAGEMENT
);
1564 * Cleanup and release locks
1566 PageOp
->Status
= STATUS_SUCCESS
;
1567 MmspCompleteAndReleasePageOp(PageOp
);
1568 DPRINT("Address 0x%.8X\n", Address
);
1569 return(STATUS_SUCCESS
);
1573 * Map anonymous memory for BSS sections
1575 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1577 MmUnlockSectionSegment(Segment
);
1578 MI_SET_USAGE(MI_USAGE_SECTION
);
1579 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1580 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1581 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1582 if (!NT_SUCCESS(Status
))
1584 MmUnlockAddressSpace(AddressSpace
);
1585 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1586 MmLockAddressSpace(AddressSpace
);
1588 if (!NT_SUCCESS(Status
))
1590 KeBugCheck(MEMORY_MANAGEMENT
);
1592 Status
= MmCreateVirtualMapping(Process
,
1597 if (!NT_SUCCESS(Status
))
1599 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1600 KeBugCheck(MEMORY_MANAGEMENT
);
1603 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1606 * Cleanup and release locks
1608 PageOp
->Status
= STATUS_SUCCESS
;
1609 MmspCompleteAndReleasePageOp(PageOp
);
1610 DPRINT("Address 0x%.8X\n", Address
);
1611 return(STATUS_SUCCESS
);
1615 * Get the entry corresponding to the offset within the section
1617 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1622 * If the entry is zero (and it can't change because we have
1623 * locked the segment) then we need to load the page.
1627 * Release all our locks and read in the page from disk
1629 MmUnlockSectionSegment(Segment
);
1630 MmUnlockAddressSpace(AddressSpace
);
1632 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1633 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1635 MI_SET_USAGE(MI_USAGE_SECTION
);
1636 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1637 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1638 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1639 if (!NT_SUCCESS(Status
))
1641 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1647 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1648 if (!NT_SUCCESS(Status
))
1650 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1653 if (!NT_SUCCESS(Status
))
1656 * FIXME: What do we know in this case?
1659 * Cleanup and release locks
1661 MmLockAddressSpace(AddressSpace
);
1662 PageOp
->Status
= Status
;
1663 MmspCompleteAndReleasePageOp(PageOp
);
1664 DPRINT("Address 0x%.8X\n", Address
);
1668 * Relock the address space and segment
1670 MmLockAddressSpace(AddressSpace
);
1671 MmLockSectionSegment(Segment
);
1674 * Check the entry. No one should change the status of a page
1675 * that has a pending page-in.
1677 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1678 if (Entry
!= Entry1
)
1680 DPRINT1("Someone changed ppte entry while we slept\n");
1681 KeBugCheck(MEMORY_MANAGEMENT
);
1685 * Mark the offset within the section as having valid, in-memory
1688 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1689 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1690 MmUnlockSectionSegment(Segment
);
1692 Status
= MmCreateVirtualMapping(Process
,
1697 if (!NT_SUCCESS(Status
))
1699 DPRINT1("Unable to create virtual mapping\n");
1700 KeBugCheck(MEMORY_MANAGEMENT
);
1702 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1704 PageOp
->Status
= STATUS_SUCCESS
;
1705 MmspCompleteAndReleasePageOp(PageOp
);
1706 DPRINT("Address 0x%.8X\n", Address
);
1707 return(STATUS_SUCCESS
);
1709 else if (IS_SWAP_FROM_SSE(Entry
))
1711 SWAPENTRY SwapEntry
;
1713 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1716 * Release all our locks and read in the page from disk
1718 MmUnlockSectionSegment(Segment
);
1720 MmUnlockAddressSpace(AddressSpace
);
1721 MI_SET_USAGE(MI_USAGE_SECTION
);
1722 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1723 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1724 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1725 if (!NT_SUCCESS(Status
))
1727 KeBugCheck(MEMORY_MANAGEMENT
);
1730 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1731 if (!NT_SUCCESS(Status
))
1733 KeBugCheck(MEMORY_MANAGEMENT
);
1737 * Relock the address space and segment
1739 MmLockAddressSpace(AddressSpace
);
1740 MmLockSectionSegment(Segment
);
1743 * Check the entry. No one should change the status of a page
1744 * that has a pending page-in.
1746 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1747 if (Entry
!= Entry1
)
1749 DPRINT1("Someone changed ppte entry while we slept\n");
1750 KeBugCheck(MEMORY_MANAGEMENT
);
1754 * Mark the offset within the section as having valid, in-memory
1757 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1758 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1759 MmUnlockSectionSegment(Segment
);
1762 * Save the swap entry.
1764 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1765 Status
= MmCreateVirtualMapping(Process
,
1770 if (!NT_SUCCESS(Status
))
1772 DPRINT1("Unable to create virtual mapping\n");
1773 KeBugCheck(MEMORY_MANAGEMENT
);
1775 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1776 PageOp
->Status
= STATUS_SUCCESS
;
1777 MmspCompleteAndReleasePageOp(PageOp
);
1778 DPRINT("Address 0x%.8X\n", Address
);
1779 return(STATUS_SUCCESS
);
1784 * If the section offset is already in-memory and valid then just
1785 * take another reference to the page
1788 Page
= PFN_FROM_SSE(Entry
);
1790 MmSharePageEntrySectionSegment(Segment
, Offset
);
1791 MmUnlockSectionSegment(Segment
);
1793 Status
= MmCreateVirtualMapping(Process
,
1798 if (!NT_SUCCESS(Status
))
1800 DPRINT1("Unable to create virtual mapping\n");
1801 KeBugCheck(MEMORY_MANAGEMENT
);
1803 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1804 PageOp
->Status
= STATUS_SUCCESS
;
1805 MmspCompleteAndReleasePageOp(PageOp
);
1806 DPRINT("Address 0x%.8X\n", Address
);
1807 return(STATUS_SUCCESS
);
1813 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1814 MEMORY_AREA
* MemoryArea
,
1817 PMM_SECTION_SEGMENT Segment
;
1818 PROS_SECTION_OBJECT Section
;
1827 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1829 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
);
1832 * Check if the page has been paged out or has already been set readwrite
1834 if (!MmIsPagePresent(Process
, Address
) ||
1835 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1837 DPRINT("Address 0x%.8X\n", Address
);
1838 return(STATUS_SUCCESS
);
1842 * Find the offset of the page
1844 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1845 Offset
= (ULONG
)((ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1846 + MemoryArea
->Data
.SectionData
.ViewOffset
);
1848 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1849 Section
= MemoryArea
->Data
.SectionData
.Section
;
1850 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1851 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1856 MmLockSectionSegment(Segment
);
1858 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1859 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1861 MmUnlockSectionSegment(Segment
);
1864 * Check if we are doing COW
1866 if (!((Segment
->WriteCopy
) &&
1867 (Region
->Protect
== PAGE_READWRITE
||
1868 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1870 DPRINT("Address 0x%.8X\n", Address
);
1871 return(STATUS_ACCESS_VIOLATION
);
1874 if (IS_SWAP_FROM_SSE(Entry
) ||
1875 PFN_FROM_SSE(Entry
) != OldPage
)
1877 /* This is a private page. We must only change the page protection. */
1878 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1879 return(STATUS_SUCCESS
);
1883 * Get or create a pageop
1885 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1886 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1889 DPRINT1("MmGetPageOp failed\n");
1890 KeBugCheck(MEMORY_MANAGEMENT
);
1894 * Wait for any other operations to complete
1896 if (PageOp
->Thread
!= PsGetCurrentThread())
1898 MmUnlockAddressSpace(AddressSpace
);
1899 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1901 * Check for various strange conditions
1903 if (Status
== STATUS_TIMEOUT
)
1905 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1906 KeBugCheck(MEMORY_MANAGEMENT
);
1908 if (PageOp
->Status
== STATUS_PENDING
)
1910 DPRINT1("Woke for page op before completion\n");
1911 KeBugCheck(MEMORY_MANAGEMENT
);
1914 * Restart the operation
1916 MmLockAddressSpace(AddressSpace
);
1917 MmspCompleteAndReleasePageOp(PageOp
);
1918 DPRINT("Address 0x%.8X\n", Address
);
1919 return(STATUS_MM_RESTART_OPERATION
);
1923 * Release locks now we have the pageop
1925 MmUnlockAddressSpace(AddressSpace
);
1930 MI_SET_USAGE(MI_USAGE_SECTION
);
1931 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1932 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1933 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1934 if (!NT_SUCCESS(Status
))
1936 KeBugCheck(MEMORY_MANAGEMENT
);
1942 MiCopyFromUserPage(NewPage
, PAddress
);
1944 MmLockAddressSpace(AddressSpace
);
1946 * Delete the old entry.
1948 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1951 * Set the PTE to point to the new page
1953 Status
= MmCreateVirtualMapping(Process
,
1958 if (!NT_SUCCESS(Status
))
1960 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1961 KeBugCheck(MEMORY_MANAGEMENT
);
1964 if (!NT_SUCCESS(Status
))
1966 DPRINT1("Unable to create virtual mapping\n");
1967 KeBugCheck(MEMORY_MANAGEMENT
);
1971 * Unshare the old page.
1973 MmDeleteRmap(OldPage
, Process
, PAddress
);
1974 MmInsertRmap(NewPage
, Process
, PAddress
);
1975 MmLockSectionSegment(Segment
);
1976 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1977 MmUnlockSectionSegment(Segment
);
1979 PageOp
->Status
= STATUS_SUCCESS
;
1980 MmspCompleteAndReleasePageOp(PageOp
);
1981 DPRINT("Address 0x%.8X\n", Address
);
1982 return(STATUS_SUCCESS
);
1986 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1988 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1992 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1995 MmLockAddressSpace(&Process
->Vm
);
1998 MmDeleteVirtualMapping(Process
,
2005 PageOutContext
->WasDirty
= TRUE
;
2007 if (!PageOutContext
->Private
)
2009 MmLockSectionSegment(PageOutContext
->Segment
);
2010 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
2011 PageOutContext
->Segment
,
2012 PageOutContext
->Offset
,
2013 PageOutContext
->WasDirty
,
2015 MmUnlockSectionSegment(PageOutContext
->Segment
);
2019 MmUnlockAddressSpace(&Process
->Vm
);
2022 if (PageOutContext
->Private
)
2024 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2027 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
2032 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
2033 MEMORY_AREA
* MemoryArea
,
2038 MM_SECTION_PAGEOUT_CONTEXT Context
;
2039 SWAPENTRY SwapEntry
;
2043 PFILE_OBJECT FileObject
;
2047 BOOLEAN DirectMapped
;
2048 BOOLEAN IsImageSection
;
2049 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2052 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2055 * Get the segment and section.
2057 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2058 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
2060 Context
.Offset
= (ULONG
)((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2061 + MemoryArea
->Data
.SectionData
.ViewOffset
);
2062 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
2064 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2066 FileObject
= Context
.Section
->FileObject
;
2067 DirectMapped
= FALSE
;
2069 if (FileObject
!= NULL
&&
2070 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2072 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2075 * If the file system is letting us go directly to the cache and the
2076 * memory area was mapped at an offset in the file which is page aligned
2077 * then note this is a direct mapped page.
2079 if ((FileOffset
% PAGE_SIZE
) == 0 &&
2080 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
2082 DirectMapped
= TRUE
;
2089 * This should never happen since mappings of physical memory are never
2090 * placed in the rmap lists.
2092 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2094 DPRINT1("Trying to page out from physical memory section address 0x%X "
2095 "process %d\n", Address
,
2096 Process
? Process
->UniqueProcessId
: 0);
2097 KeBugCheck(MEMORY_MANAGEMENT
);
2101 * Get the section segment entry and the physical address.
2103 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
2104 if (!MmIsPagePresent(Process
, Address
))
2106 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2107 Process
? Process
->UniqueProcessId
: 0, Address
);
2108 KeBugCheck(MEMORY_MANAGEMENT
);
2110 Page
= MmGetPfnForProcess(Process
, Address
);
2111 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2114 * Prepare the context structure for the rmap delete call.
2116 Context
.WasDirty
= FALSE
;
2117 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2118 IS_SWAP_FROM_SSE(Entry
) ||
2119 PFN_FROM_SSE(Entry
) != Page
)
2121 Context
.Private
= TRUE
;
2125 Context
.Private
= FALSE
;
2129 * Take an additional reference to the page or the cache segment.
2131 if (DirectMapped
&& !Context
.Private
)
2133 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
2135 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2136 KeBugCheck(MEMORY_MANAGEMENT
);
2141 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
2142 MmReferencePage(Page
);
2143 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
2146 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2149 * If this wasn't a private page then we should have reduced the entry to
2150 * zero by deleting all the rmaps.
2152 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
2154 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2155 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2157 KeBugCheck(MEMORY_MANAGEMENT
);
2162 * If the page wasn't dirty then we can just free it as for a readonly page.
2163 * Since we unmapped all the mappings above we know it will not suddenly
2165 * If the page is from a pagefile section and has no swap entry,
2166 * we can't free the page at this point.
2168 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2169 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2171 if (Context
.Private
)
2173 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
2174 Context
.WasDirty
? "dirty" : "clean", Address
);
2175 KeBugCheck(MEMORY_MANAGEMENT
);
2177 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2179 MmSetSavedSwapEntryPage(Page
, 0);
2180 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2181 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2182 PageOp
->Status
= STATUS_SUCCESS
;
2183 MmspCompleteAndReleasePageOp(PageOp
);
2184 return(STATUS_SUCCESS
);
2187 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2189 if (Context
.Private
)
2191 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2192 Context
.WasDirty
? "dirty" : "clean", Address
);
2193 KeBugCheck(MEMORY_MANAGEMENT
);
2195 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2197 MmSetSavedSwapEntryPage(Page
, 0);
2200 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2202 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2203 PageOp
->Status
= STATUS_SUCCESS
;
2204 MmspCompleteAndReleasePageOp(PageOp
);
2205 return(STATUS_SUCCESS
);
2208 else if (!Context
.Private
&& DirectMapped
)
2212 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2214 KeBugCheck(MEMORY_MANAGEMENT
);
2217 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
2219 Status
= STATUS_SUCCESS
;
2221 if (!NT_SUCCESS(Status
))
2223 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2224 KeBugCheck(MEMORY_MANAGEMENT
);
2226 PageOp
->Status
= STATUS_SUCCESS
;
2227 MmspCompleteAndReleasePageOp(PageOp
);
2228 return(STATUS_SUCCESS
);
2230 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2234 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2236 KeBugCheck(MEMORY_MANAGEMENT
);
2238 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2239 PageOp
->Status
= STATUS_SUCCESS
;
2240 MmspCompleteAndReleasePageOp(PageOp
);
2241 return(STATUS_SUCCESS
);
2243 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2245 MmSetSavedSwapEntryPage(Page
, 0);
2246 MmLockAddressSpace(AddressSpace
);
2247 Status
= MmCreatePageFileMapping(Process
,
2250 MmUnlockAddressSpace(AddressSpace
);
2251 if (!NT_SUCCESS(Status
))
2253 KeBugCheck(MEMORY_MANAGEMENT
);
2255 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2256 PageOp
->Status
= STATUS_SUCCESS
;
2257 MmspCompleteAndReleasePageOp(PageOp
);
2258 return(STATUS_SUCCESS
);
2262 * If necessary, allocate an entry in the paging file for this page
2266 SwapEntry
= MmAllocSwapPage();
2269 MmShowOutOfSpaceMessagePagingFile();
2270 MmLockAddressSpace(AddressSpace
);
2272 * For private pages restore the old mappings.
2274 if (Context
.Private
)
2276 Status
= MmCreateVirtualMapping(Process
,
2278 MemoryArea
->Protect
,
2281 MmSetDirtyPage(Process
, Address
);
2289 * For non-private pages if the page wasn't direct mapped then
2290 * set it back into the section segment entry so we don't loose
2291 * our copy. Otherwise it will be handled by the cache manager.
2293 Status
= MmCreateVirtualMapping(Process
,
2295 MemoryArea
->Protect
,
2298 MmSetDirtyPage(Process
, Address
);
2302 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2303 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2305 MmUnlockAddressSpace(AddressSpace
);
2306 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2307 MmspCompleteAndReleasePageOp(PageOp
);
2308 return(STATUS_PAGEFILE_QUOTA
);
2313 * Write the page to the pagefile
2315 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2316 if (!NT_SUCCESS(Status
))
2318 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2321 * As above: undo our actions.
2322 * FIXME: Also free the swap page.
2324 MmLockAddressSpace(AddressSpace
);
2325 if (Context
.Private
)
2327 Status
= MmCreateVirtualMapping(Process
,
2329 MemoryArea
->Protect
,
2332 MmSetDirtyPage(Process
, Address
);
2339 Status
= MmCreateVirtualMapping(Process
,
2341 MemoryArea
->Protect
,
2344 MmSetDirtyPage(Process
, Address
);
2348 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2349 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2351 MmUnlockAddressSpace(AddressSpace
);
2352 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2353 MmspCompleteAndReleasePageOp(PageOp
);
2354 return(STATUS_UNSUCCESSFUL
);
2358 * Otherwise we have succeeded.
2360 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2361 MmSetSavedSwapEntryPage(Page
, 0);
2362 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2363 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2365 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2369 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2372 if (Context
.Private
)
2374 MmLockAddressSpace(AddressSpace
);
2375 Status
= MmCreatePageFileMapping(Process
,
2378 MmUnlockAddressSpace(AddressSpace
);
2379 if (!NT_SUCCESS(Status
))
2381 KeBugCheck(MEMORY_MANAGEMENT
);
2386 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2387 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2390 PageOp
->Status
= STATUS_SUCCESS
;
2391 MmspCompleteAndReleasePageOp(PageOp
);
2392 return(STATUS_SUCCESS
);
2397 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2398 PMEMORY_AREA MemoryArea
,
2403 PROS_SECTION_OBJECT Section
;
2404 PMM_SECTION_SEGMENT Segment
;
2406 SWAPENTRY SwapEntry
;
2410 PFILE_OBJECT FileObject
;
2412 BOOLEAN DirectMapped
;
2413 BOOLEAN IsImageSection
;
2414 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2416 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2418 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2419 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2422 * Get the segment and section.
2424 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2425 Section
= MemoryArea
->Data
.SectionData
.Section
;
2426 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2428 FileObject
= Section
->FileObject
;
2429 DirectMapped
= FALSE
;
2430 if (FileObject
!= NULL
&&
2431 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2433 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2436 * If the file system is letting us go directly to the cache and the
2437 * memory area was mapped at an offset in the file which is page aligned
2438 * then note this is a direct mapped page.
2440 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
2441 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
2443 DirectMapped
= TRUE
;
2448 * This should never happen since mappings of physical memory are never
2449 * placed in the rmap lists.
2451 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2453 DPRINT1("Trying to write back page from physical memory mapped at %X "
2454 "process %d\n", Address
,
2455 Process
? Process
->UniqueProcessId
: 0);
2456 KeBugCheck(MEMORY_MANAGEMENT
);
2460 * Get the section segment entry and the physical address.
2462 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2463 if (!MmIsPagePresent(Process
, Address
))
2465 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2466 Process
? Process
->UniqueProcessId
: 0, Address
);
2467 KeBugCheck(MEMORY_MANAGEMENT
);
2469 Page
= MmGetPfnForProcess(Process
, Address
);
2470 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2473 * Check for a private (COWed) page.
2475 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2476 IS_SWAP_FROM_SSE(Entry
) ||
2477 PFN_FROM_SSE(Entry
) != Page
)
2487 * Speculatively set all mappings of the page to clean.
2489 MmSetCleanAllRmaps(Page
);
2492 * If this page was direct mapped from the cache then the cache manager
2493 * will take care of writing it back to disk.
2495 if (DirectMapped
&& !Private
)
2497 ASSERT(SwapEntry
== 0);
2499 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)Offset
+ Segment
->FileOffset
);
2501 PageOp
->Status
= STATUS_SUCCESS
;
2502 MmspCompleteAndReleasePageOp(PageOp
);
2503 return(STATUS_SUCCESS
);
2507 * If necessary, allocate an entry in the paging file for this page
2511 SwapEntry
= MmAllocSwapPage();
2514 MmSetDirtyAllRmaps(Page
);
2515 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2516 MmspCompleteAndReleasePageOp(PageOp
);
2517 return(STATUS_PAGEFILE_QUOTA
);
2519 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2523 * Write the page to the pagefile
2525 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2526 if (!NT_SUCCESS(Status
))
2528 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2530 MmSetDirtyAllRmaps(Page
);
2531 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2532 MmspCompleteAndReleasePageOp(PageOp
);
2533 return(STATUS_UNSUCCESSFUL
);
2537 * Otherwise we have succeeded.
2539 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2540 PageOp
->Status
= STATUS_SUCCESS
;
2541 MmspCompleteAndReleasePageOp(PageOp
);
2542 return(STATUS_SUCCESS
);
2546 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2554 PMEMORY_AREA MemoryArea
;
2555 PMM_SECTION_SEGMENT Segment
;
2556 BOOLEAN DoCOW
= FALSE
;
2558 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2560 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2561 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2563 if ((Segment
->WriteCopy
) &&
2564 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2569 if (OldProtect
!= NewProtect
)
2571 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2573 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2574 ULONG Protect
= NewProtect
;
2577 * If we doing COW for this segment then check if the page is
2580 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2586 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2587 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2588 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2589 Page
= MmGetPfnForProcess(Process
, Address
);
2591 Protect
= PAGE_READONLY
;
2592 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2593 IS_SWAP_FROM_SSE(Entry
) ||
2594 PFN_FROM_SSE(Entry
) != Page
)
2596 Protect
= NewProtect
;
2600 if (MmIsPagePresent(Process
, Address
))
2602 MmSetPageProtect(Process
, Address
,
2611 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2612 PMEMORY_AREA MemoryArea
,
2620 ULONG_PTR MaxLength
;
2622 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2623 if (Length
> MaxLength
)
2624 Length
= (ULONG
)MaxLength
;
2626 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2627 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2629 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2630 Region
->Protect
!= Protect
)
2632 return STATUS_INVALID_PAGE_PROTECTION
;
2635 *OldProtect
= Region
->Protect
;
2636 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2637 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2638 BaseAddress
, Length
, Region
->Type
, Protect
,
2639 MmAlterViewAttributes
);
2645 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2647 PMEMORY_BASIC_INFORMATION Info
,
2648 PSIZE_T ResultLength
)
2651 PVOID RegionBaseAddress
;
2652 PROS_SECTION_OBJECT Section
;
2653 PMM_SECTION_SEGMENT Segment
;
2655 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2656 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2657 Address
, &RegionBaseAddress
);
2660 return STATUS_UNSUCCESSFUL
;
2663 Section
= MemoryArea
->Data
.SectionData
.Section
;
2664 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2666 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2667 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2668 Info
->Type
= MEM_IMAGE
;
2672 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2673 Info
->Type
= MEM_MAPPED
;
2675 Info
->BaseAddress
= RegionBaseAddress
;
2676 Info
->AllocationProtect
= MemoryArea
->Protect
;
2677 Info
->RegionSize
= Region
->Length
;
2678 Info
->State
= MEM_COMMIT
;
2679 Info
->Protect
= Region
->Protect
;
2681 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2682 return(STATUS_SUCCESS
);
2687 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2692 SWAPENTRY SavedSwapEntry
;
2697 Length
= PAGE_ROUND_UP(Segment
->Length
);
2698 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2700 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2703 if (IS_SWAP_FROM_SSE(Entry
))
2705 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2709 Page
= PFN_FROM_SSE(Entry
);
2710 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2711 if (SavedSwapEntry
!= 0)
2713 MmSetSavedSwapEntryPage(Page
, 0);
2714 MmFreeSwapPage(SavedSwapEntry
);
2716 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2718 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2724 MmpDeleteSection(PVOID ObjectBody
)
2726 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2728 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2729 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2734 PMM_SECTION_SEGMENT SectionSegments
;
2737 * NOTE: Section->ImageSection can be NULL for short time
2738 * during the section creating. If we fail for some reason
2739 * until the image section is properly initialized we shouldn't
2740 * process further here.
2742 if (Section
->ImageSection
== NULL
)
2745 SectionSegments
= Section
->ImageSection
->Segments
;
2746 NrSegments
= Section
->ImageSection
->NrSegments
;
2748 for (i
= 0; i
< NrSegments
; i
++)
2750 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2752 MmLockSectionSegment(&SectionSegments
[i
]);
2754 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2755 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2759 MmpFreePageFileSegment(&SectionSegments
[i
]);
2761 MmUnlockSectionSegment(&SectionSegments
[i
]);
2768 * NOTE: Section->Segment can be NULL for short time
2769 * during the section creating.
2771 if (Section
->Segment
== NULL
)
2774 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2776 MmpFreePageFileSegment(Section
->Segment
);
2777 MmFreePageTablesSectionSegment(Section
->Segment
);
2778 ExFreePool(Section
->Segment
);
2779 Section
->Segment
= NULL
;
2783 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2786 if (Section
->FileObject
!= NULL
)
2789 CcRosDereferenceCache(Section
->FileObject
);
2791 ObDereferenceObject(Section
->FileObject
);
2792 Section
->FileObject
= NULL
;
2797 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2799 IN ACCESS_MASK GrantedAccess
,
2800 IN ULONG ProcessHandleCount
,
2801 IN ULONG SystemHandleCount
)
2803 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2804 Object
, ProcessHandleCount
);
2810 MmCreatePhysicalMemorySection(VOID
)
2812 PROS_SECTION_OBJECT PhysSection
;
2814 OBJECT_ATTRIBUTES Obj
;
2815 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2816 LARGE_INTEGER SectionSize
;
2820 * Create the section mapping physical memory
2822 SectionSize
.QuadPart
= 0xFFFFFFFF;
2823 InitializeObjectAttributes(&Obj
,
2828 Status
= MmCreateSection((PVOID
)&PhysSection
,
2832 PAGE_EXECUTE_READWRITE
,
2836 if (!NT_SUCCESS(Status
))
2838 DPRINT1("Failed to create PhysicalMemory section\n");
2839 KeBugCheck(MEMORY_MANAGEMENT
);
2841 Status
= ObInsertObject(PhysSection
,
2847 if (!NT_SUCCESS(Status
))
2849 ObDereferenceObject(PhysSection
);
2851 ObCloseHandle(Handle
, KernelMode
);
2852 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2853 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2855 return(STATUS_SUCCESS
);
2861 MmInitSectionImplementation(VOID
)
2863 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2864 UNICODE_STRING Name
;
2866 DPRINT("Creating Section Object Type\n");
2868 /* Initialize the Section object type */
2869 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2870 RtlInitUnicodeString(&Name
, L
"Section");
2871 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2872 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2873 ObjectTypeInitializer
.PoolType
= PagedPool
;
2874 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2875 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2876 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2877 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2878 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2879 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2881 MmCreatePhysicalMemorySection();
2883 return(STATUS_SUCCESS
);
2888 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2889 ACCESS_MASK DesiredAccess
,
2890 POBJECT_ATTRIBUTES ObjectAttributes
,
2891 PLARGE_INTEGER UMaximumSize
,
2892 ULONG SectionPageProtection
,
2893 ULONG AllocationAttributes
)
2895 * Create a section which is backed by the pagefile
2898 LARGE_INTEGER MaximumSize
;
2899 PROS_SECTION_OBJECT Section
;
2900 PMM_SECTION_SEGMENT Segment
;
2903 if (UMaximumSize
== NULL
)
2905 return(STATUS_UNSUCCESSFUL
);
2907 MaximumSize
= *UMaximumSize
;
2910 * Create the section
2912 Status
= ObCreateObject(ExGetPreviousMode(),
2913 MmSectionObjectType
,
2915 ExGetPreviousMode(),
2917 sizeof(ROS_SECTION_OBJECT
),
2920 (PVOID
*)(PVOID
)&Section
);
2921 if (!NT_SUCCESS(Status
))
2929 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2930 Section
->SectionPageProtection
= SectionPageProtection
;
2931 Section
->AllocationAttributes
= AllocationAttributes
;
2932 Section
->MaximumSize
= MaximumSize
;
2933 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2934 TAG_MM_SECTION_SEGMENT
);
2935 if (Segment
== NULL
)
2937 ObDereferenceObject(Section
);
2938 return(STATUS_NO_MEMORY
);
2940 Section
->Segment
= Segment
;
2941 Segment
->ReferenceCount
= 1;
2942 ExInitializeFastMutex(&Segment
->Lock
);
2943 Segment
->FileOffset
= 0;
2944 Segment
->Protection
= SectionPageProtection
;
2945 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2946 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2947 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2948 Segment
->WriteCopy
= FALSE
;
2949 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2950 Segment
->VirtualAddress
= 0;
2951 Segment
->Characteristics
= 0;
2952 *SectionObject
= Section
;
2953 return(STATUS_SUCCESS
);
2959 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2960 ACCESS_MASK DesiredAccess
,
2961 POBJECT_ATTRIBUTES ObjectAttributes
,
2962 PLARGE_INTEGER UMaximumSize
,
2963 ULONG SectionPageProtection
,
2964 ULONG AllocationAttributes
,
2967 * Create a section backed by a data file
2970 PROS_SECTION_OBJECT Section
;
2972 LARGE_INTEGER MaximumSize
;
2973 PFILE_OBJECT FileObject
;
2974 PMM_SECTION_SEGMENT Segment
;
2976 IO_STATUS_BLOCK Iosb
;
2977 LARGE_INTEGER Offset
;
2979 FILE_STANDARD_INFORMATION FileInfo
;
2983 * Create the section
2985 Status
= ObCreateObject(ExGetPreviousMode(),
2986 MmSectionObjectType
,
2988 ExGetPreviousMode(),
2990 sizeof(ROS_SECTION_OBJECT
),
2993 (PVOID
*)(PVOID
)&Section
);
2994 if (!NT_SUCCESS(Status
))
3001 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3002 Section
->SectionPageProtection
= SectionPageProtection
;
3003 Section
->AllocationAttributes
= AllocationAttributes
;
3006 * Check file access required
3008 if (SectionPageProtection
& PAGE_READWRITE
||
3009 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3011 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3015 FileAccess
= FILE_READ_DATA
;
3019 * Reference the file handle
3021 Status
= ObReferenceObjectByHandle(FileHandle
,
3024 ExGetPreviousMode(),
3025 (PVOID
*)(PVOID
)&FileObject
,
3027 if (!NT_SUCCESS(Status
))
3029 ObDereferenceObject(Section
);
3034 * FIXME: This is propably not entirely correct. We can't look into
3035 * the standard FCB header because it might not be initialized yet
3036 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
3037 * standard file information is filled on first request).
3039 Status
= IoQueryFileInformation(FileObject
,
3040 FileStandardInformation
,
3041 sizeof(FILE_STANDARD_INFORMATION
),
3044 Iosb
.Information
= Length
;
3045 if (!NT_SUCCESS(Status
))
3047 ObDereferenceObject(Section
);
3048 ObDereferenceObject(FileObject
);
3053 * FIXME: Revise this once a locking order for file size changes is
3056 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
3058 MaximumSize
= *UMaximumSize
;
3062 MaximumSize
= FileInfo
.EndOfFile
;
3063 /* Mapping zero-sized files isn't allowed. */
3064 if (MaximumSize
.QuadPart
== 0)
3066 ObDereferenceObject(Section
);
3067 ObDereferenceObject(FileObject
);
3068 return STATUS_FILE_INVALID
;
3072 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3074 Status
= IoSetInformation(FileObject
,
3075 FileAllocationInformation
,
3076 sizeof(LARGE_INTEGER
),
3078 if (!NT_SUCCESS(Status
))
3080 ObDereferenceObject(Section
);
3081 ObDereferenceObject(FileObject
);
3082 return(STATUS_SECTION_NOT_EXTENDED
);
3086 if (FileObject
->SectionObjectPointer
== NULL
||
3087 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3090 * Read a bit so caching is initiated for the file object.
3091 * This is only needed because MiReadPage currently cannot
3092 * handle non-cached streams.
3094 Offset
.QuadPart
= 0;
3095 Status
= ZwReadFile(FileHandle
,
3104 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3106 ObDereferenceObject(Section
);
3107 ObDereferenceObject(FileObject
);
3110 if (FileObject
->SectionObjectPointer
== NULL
||
3111 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3113 /* FIXME: handle this situation */
3114 ObDereferenceObject(Section
);
3115 ObDereferenceObject(FileObject
);
3116 return STATUS_INVALID_PARAMETER
;
3123 Status
= MmspWaitForFileLock(FileObject
);
3124 if (Status
!= STATUS_SUCCESS
)
3126 ObDereferenceObject(Section
);
3127 ObDereferenceObject(FileObject
);
3132 * If this file hasn't been mapped as a data file before then allocate a
3133 * section segment to describe the data file mapping
3135 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3137 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3138 TAG_MM_SECTION_SEGMENT
);
3139 if (Segment
== NULL
)
3141 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3142 ObDereferenceObject(Section
);
3143 ObDereferenceObject(FileObject
);
3144 return(STATUS_NO_MEMORY
);
3146 Section
->Segment
= Segment
;
3147 Segment
->ReferenceCount
= 1;
3148 ExInitializeFastMutex(&Segment
->Lock
);
3150 * Set the lock before assigning the segment to the file object
3152 ExAcquireFastMutex(&Segment
->Lock
);
3153 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3155 Segment
->FileOffset
= 0;
3156 Segment
->Protection
= SectionPageProtection
;
3157 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3158 Segment
->Characteristics
= 0;
3159 Segment
->WriteCopy
= FALSE
;
3160 if (AllocationAttributes
& SEC_RESERVE
)
3162 Segment
->Length
= Segment
->RawLength
= 0;
3166 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3167 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3169 Segment
->VirtualAddress
= 0;
3170 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
3175 * If the file is already mapped as a data file then we may need
3179 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3181 Section
->Segment
= Segment
;
3182 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3183 MmLockSectionSegment(Segment
);
3185 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
3186 !(AllocationAttributes
& SEC_RESERVE
))
3188 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3189 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3192 MmUnlockSectionSegment(Segment
);
3193 Section
->FileObject
= FileObject
;
3194 Section
->MaximumSize
= MaximumSize
;
3196 CcRosReferenceCache(FileObject
);
3198 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3199 *SectionObject
= Section
;
3200 return(STATUS_SUCCESS
);
3204 TODO: not that great (declaring loaders statically, having to declare all of
3205 them, having to keep them extern, etc.), will fix in the future
3207 extern NTSTATUS NTAPI PeFmtCreateSection
3209 IN CONST VOID
* FileHeader
,
3210 IN SIZE_T FileHeaderSize
,
3212 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3214 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3215 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3218 extern NTSTATUS NTAPI ElfFmtCreateSection
3220 IN CONST VOID
* FileHeader
,
3221 IN SIZE_T FileHeaderSize
,
3223 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3225 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3226 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3229 /* TODO: this is a standard DDK/PSDK macro */
3230 #ifndef RTL_NUMBER_OF
3231 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3234 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3245 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3247 SIZE_T SizeOfSegments
;
3248 PMM_SECTION_SEGMENT Segments
;
3250 /* TODO: check for integer overflow */
3251 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3253 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3255 TAG_MM_SECTION_SEGMENT
);
3258 RtlZeroMemory(Segments
, SizeOfSegments
);
3266 ExeFmtpReadFile(IN PVOID File
,
3267 IN PLARGE_INTEGER Offset
,
3270 OUT PVOID
* AllocBase
,
3271 OUT PULONG ReadSize
)
3274 LARGE_INTEGER FileOffset
;
3276 ULONG OffsetAdjustment
;
3281 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3285 KeBugCheck(MEMORY_MANAGEMENT
);
3288 FileOffset
= *Offset
;
3290 /* Negative/special offset: it cannot be used in this context */
3291 if(FileOffset
.u
.HighPart
< 0)
3293 KeBugCheck(MEMORY_MANAGEMENT
);
3296 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3297 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3298 FileOffset
.u
.LowPart
= AdjustOffset
;
3300 BufferSize
= Length
+ OffsetAdjustment
;
3301 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3304 * It's ok to use paged pool, because this is a temporary buffer only used in
3305 * the loading of executables. The assumption is that MmCreateSection is
3306 * always called at low IRQLs and that these buffers don't survive a brief
3307 * initialization phase
3309 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3314 KeBugCheck(MEMORY_MANAGEMENT
);
3320 Status
= MmspPageRead(File
,
3327 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
3328 * nothing will work. But using ZwReadFile is wrong, and using its side effects
3329 * to initialize internal state is even worse. Our cache manager is in need of
3333 IO_STATUS_BLOCK Iosb
;
3335 Status
= ZwReadFile(File
,
3345 if(NT_SUCCESS(Status
))
3347 UsedSize
= (ULONG
)Iosb
.Information
;
3352 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3354 Status
= STATUS_IN_PAGE_ERROR
;
3355 ASSERT(!NT_SUCCESS(Status
));
3358 if(NT_SUCCESS(Status
))
3360 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3361 *AllocBase
= Buffer
;
3362 *ReadSize
= UsedSize
- OffsetAdjustment
;
3366 ExFreePoolWithTag(Buffer
, 'rXmM');
3373 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3374 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3375 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3380 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3384 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3386 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3387 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
3394 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3398 MmspAssertSegmentsSorted(ImageSectionObject
);
3400 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3402 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
3406 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3407 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3408 ImageSectionObject
->Segments
[i
- 1].Length
));
3416 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3420 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3422 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
3423 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
3431 MmspCompareSegments(const void * x
,
3434 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3435 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3438 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
3439 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3443 * Ensures an image section's segments are sorted in memory
3448 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3451 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3453 MmspAssertSegmentsSorted(ImageSectionObject
);
3457 qsort(ImageSectionObject
->Segments
,
3458 ImageSectionObject
->NrSegments
,
3459 sizeof(ImageSectionObject
->Segments
[0]),
3460 MmspCompareSegments
);
3466 * Ensures an image section's segments don't overlap in memory and don't have
3467 * gaps and don't have a null size. We let them map to overlapping file regions,
3468 * though - that's not necessarily an error
3473 MmspCheckSegmentBounds
3475 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3481 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3483 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3487 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3489 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3491 if(ImageSectionObject
->Segments
[i
].Length
== 0)
3499 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3500 * page could be OK (Windows seems to be OK with them), and larger gaps
3501 * could lead to image sections spanning several discontiguous regions
3502 * (NtMapViewOfSection could then refuse to map them, and they could
3503 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3505 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3506 ImageSectionObject
->Segments
[i
- 1].Length
) !=
3507 ImageSectionObject
->Segments
[i
].VirtualAddress
)
3518 * Merges and pads an image section's segments until they all are page-aligned
3519 * and have a size that is a multiple of the page size
3524 MmspPageAlignSegments
3526 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3532 PMM_SECTION_SEGMENT EffectiveSegment
;
3534 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3536 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3541 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3543 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3546 * The first segment requires special handling
3550 ULONG_PTR VirtualAddress
;
3551 ULONG_PTR VirtualOffset
;
3553 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3555 /* Round down the virtual address to the nearest page */
3556 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3558 /* Round up the virtual size to the nearest page */
3559 EffectiveSegment
->Length
= (ULONG
)(PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3560 EffectiveSegment
->VirtualAddress
);
3562 /* Adjust the raw address and size */
3563 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3565 if (EffectiveSegment
->FileOffset
< (LONG_PTR
)VirtualOffset
)
3571 * Garbage in, garbage out: unaligned base addresses make the file
3572 * offset point in curious and odd places, but that's what we were
3575 EffectiveSegment
->FileOffset
-= (ULONG
)VirtualOffset
;
3576 EffectiveSegment
->RawLength
+= (ULONG
)VirtualOffset
;
3580 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3581 ULONG_PTR EndOfEffectiveSegment
;
3583 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3584 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3587 * The current segment begins exactly where the current effective
3588 * segment ended, therefore beginning a new effective segment
3590 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3593 ASSERT(LastSegment
<= i
);
3594 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3596 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3598 if (LastSegment
!= i
)
3601 * Copy the current segment. If necessary, the effective segment
3602 * will be expanded later
3604 *EffectiveSegment
= *Segment
;
3608 * Page-align the virtual size. We know for sure the virtual address
3611 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3612 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3615 * The current segment is still part of the current effective segment:
3616 * extend the effective segment to reflect this
3618 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3620 static const ULONG FlagsToProtection
[16] =
3628 PAGE_EXECUTE_READWRITE
,
3629 PAGE_EXECUTE_READWRITE
,
3634 PAGE_EXECUTE_WRITECOPY
,
3635 PAGE_EXECUTE_WRITECOPY
,
3636 PAGE_EXECUTE_WRITECOPY
,
3637 PAGE_EXECUTE_WRITECOPY
3640 unsigned ProtectionFlags
;
3643 * Extend the file size
3646 /* Unaligned segments must be contiguous within the file */
3647 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3648 EffectiveSegment
->RawLength
))
3653 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3656 * Extend the virtual size
3658 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3660 EffectiveSegment
->Length
= (ULONG
)(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3661 EffectiveSegment
->VirtualAddress
);
3664 * Merge the protection
3666 EffectiveSegment
->Protection
|= Segment
->Protection
;
3668 /* Clean up redundance */
3669 ProtectionFlags
= 0;
3671 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3672 ProtectionFlags
|= 1 << 0;
3674 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3675 ProtectionFlags
|= 1 << 1;
3677 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3678 ProtectionFlags
|= 1 << 2;
3680 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3681 ProtectionFlags
|= 1 << 3;
3683 ASSERT(ProtectionFlags
< 16);
3684 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3686 /* If a segment was required to be shared and cannot, fail */
3687 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3688 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3694 * We assume no holes between segments at this point
3698 KeBugCheck(MEMORY_MANAGEMENT
);
3702 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3708 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3709 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3711 LARGE_INTEGER Offset
;
3713 PVOID FileHeaderBuffer
;
3714 ULONG FileHeaderSize
;
3716 ULONG OldNrSegments
;
3721 * Read the beginning of the file (2 pages). Should be enough to contain
3722 * all (or most) of the headers
3724 Offset
.QuadPart
= 0;
3726 /* FIXME: use FileObject instead of FileHandle */
3727 Status
= ExeFmtpReadFile (FileHandle
,
3734 if (!NT_SUCCESS(Status
))
3737 if (FileHeaderSize
== 0)
3739 ExFreePool(FileHeaderBuffer
);
3740 return STATUS_UNSUCCESSFUL
;
3744 * Look for a loader that can handle this executable
3746 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3748 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3751 /* FIXME: use FileObject instead of FileHandle */
3752 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3758 ExeFmtpAllocateSegments
);
3760 if (!NT_SUCCESS(Status
))
3762 if (ImageSectionObject
->Segments
)
3764 ExFreePool(ImageSectionObject
->Segments
);
3765 ImageSectionObject
->Segments
= NULL
;
3769 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3773 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3776 * No loader handled the format
3778 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3780 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3781 ASSERT(!NT_SUCCESS(Status
));
3784 if (!NT_SUCCESS(Status
))
3787 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3792 /* FIXME? are these values platform-dependent? */
3793 if(ImageSectionObject
->StackReserve
== 0)
3794 ImageSectionObject
->StackReserve
= 0x40000;
3796 if(ImageSectionObject
->StackCommit
== 0)
3797 ImageSectionObject
->StackCommit
= 0x1000;
3799 if(ImageSectionObject
->ImageBase
== 0)
3801 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3802 ImageSectionObject
->ImageBase
= 0x10000000;
3804 ImageSectionObject
->ImageBase
= 0x00400000;
3808 * And now the fun part: fixing the segments
3811 /* Sort them by virtual address */
3812 MmspSortSegments(ImageSectionObject
, Flags
);
3814 /* Ensure they don't overlap in memory */
3815 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3816 return STATUS_INVALID_IMAGE_FORMAT
;
3818 /* Ensure they are aligned */
3819 OldNrSegments
= ImageSectionObject
->NrSegments
;
3821 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3822 return STATUS_INVALID_IMAGE_FORMAT
;
3824 /* Trim them if the alignment phase merged some of them */
3825 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3827 PMM_SECTION_SEGMENT Segments
;
3828 SIZE_T SizeOfSegments
;
3830 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3832 Segments
= ExAllocatePoolWithTag(PagedPool
,
3834 TAG_MM_SECTION_SEGMENT
);
3836 if (Segments
== NULL
)
3837 return STATUS_INSUFFICIENT_RESOURCES
;
3839 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3840 ExFreePool(ImageSectionObject
->Segments
);
3841 ImageSectionObject
->Segments
= Segments
;
3844 /* And finish their initialization */
3845 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3847 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3848 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3850 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3851 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3854 ASSERT(NT_SUCCESS(Status
));
3859 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3860 ACCESS_MASK DesiredAccess
,
3861 POBJECT_ATTRIBUTES ObjectAttributes
,
3862 PLARGE_INTEGER UMaximumSize
,
3863 ULONG SectionPageProtection
,
3864 ULONG AllocationAttributes
,
3867 PROS_SECTION_OBJECT Section
;
3869 PFILE_OBJECT FileObject
;
3870 PMM_SECTION_SEGMENT SectionSegments
;
3871 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3873 ULONG FileAccess
= 0;
3876 * Check file access required
3878 if (SectionPageProtection
& PAGE_READWRITE
||
3879 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3881 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3885 FileAccess
= FILE_READ_DATA
;
3889 * Reference the file handle
3891 Status
= ObReferenceObjectByHandle(FileHandle
,
3894 ExGetPreviousMode(),
3895 (PVOID
*)(PVOID
)&FileObject
,
3898 if (!NT_SUCCESS(Status
))
3904 * Create the section
3906 Status
= ObCreateObject (ExGetPreviousMode(),
3907 MmSectionObjectType
,
3909 ExGetPreviousMode(),
3911 sizeof(ROS_SECTION_OBJECT
),
3914 (PVOID
*)(PVOID
)&Section
);
3915 if (!NT_SUCCESS(Status
))
3917 ObDereferenceObject(FileObject
);
3924 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3925 Section
->SectionPageProtection
= SectionPageProtection
;
3926 Section
->AllocationAttributes
= AllocationAttributes
;
3930 * Initialized caching for this file object if previously caching
3931 * was initialized for the same on disk file
3933 Status
= CcTryToInitializeFileCache(FileObject
);
3935 Status
= STATUS_SUCCESS
;
3938 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3940 NTSTATUS StatusExeFmt
;
3942 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3943 if (ImageSectionObject
== NULL
)
3945 ObDereferenceObject(FileObject
);
3946 ObDereferenceObject(Section
);
3947 return(STATUS_NO_MEMORY
);
3950 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3952 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3954 if (!NT_SUCCESS(StatusExeFmt
))
3956 if(ImageSectionObject
->Segments
!= NULL
)
3957 ExFreePool(ImageSectionObject
->Segments
);
3959 ExFreePool(ImageSectionObject
);
3960 ObDereferenceObject(Section
);
3961 ObDereferenceObject(FileObject
);
3962 return(StatusExeFmt
);
3965 Section
->ImageSection
= ImageSectionObject
;
3966 ASSERT(ImageSectionObject
->Segments
);
3971 Status
= MmspWaitForFileLock(FileObject
);
3972 if (!NT_SUCCESS(Status
))
3974 ExFreePool(ImageSectionObject
->Segments
);
3975 ExFreePool(ImageSectionObject
);
3976 ObDereferenceObject(Section
);
3977 ObDereferenceObject(FileObject
);
3981 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3982 ImageSectionObject
, NULL
))
3985 * An other thread has initialized the same image in the background
3987 ExFreePool(ImageSectionObject
->Segments
);
3988 ExFreePool(ImageSectionObject
);
3989 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3990 Section
->ImageSection
= ImageSectionObject
;
3991 SectionSegments
= ImageSectionObject
->Segments
;
3993 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3995 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3999 Status
= StatusExeFmt
;
4006 Status
= MmspWaitForFileLock(FileObject
);
4007 if (Status
!= STATUS_SUCCESS
)
4009 ObDereferenceObject(Section
);
4010 ObDereferenceObject(FileObject
);
4014 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
4015 Section
->ImageSection
= ImageSectionObject
;
4016 SectionSegments
= ImageSectionObject
->Segments
;
4019 * Otherwise just reference all the section segments
4021 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
4023 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
4026 Status
= STATUS_SUCCESS
;
4028 Section
->FileObject
= FileObject
;
4030 CcRosReferenceCache(FileObject
);
4032 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
4033 *SectionObject
= Section
;
4040 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
4041 PROS_SECTION_OBJECT Section
,
4042 PMM_SECTION_SEGMENT Segment
,
4047 ULONG AllocationType
)
4051 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4053 BoundaryAddressMultiple
.QuadPart
= 0;
4055 Status
= MmCreateMemoryArea(AddressSpace
,
4056 MEMORY_AREA_SECTION_VIEW
,
4063 BoundaryAddressMultiple
);
4064 if (!NT_SUCCESS(Status
))
4066 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
4067 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
4071 ObReferenceObject((PVOID
)Section
);
4073 MArea
->Data
.SectionData
.Segment
= Segment
;
4074 MArea
->Data
.SectionData
.Section
= Section
;
4075 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
4076 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
4077 ViewSize
, 0, Protect
);
4079 return(STATUS_SUCCESS
);
4085 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
4086 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4089 PFILE_OBJECT FileObject
;
4092 SWAPENTRY SavedSwapEntry
;
4095 PROS_SECTION_OBJECT Section
;
4096 PMM_SECTION_SEGMENT Segment
;
4097 PMMSUPPORT AddressSpace
;
4100 AddressSpace
= (PMMSUPPORT
)Context
;
4101 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4103 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4105 Offset
= (ULONG
)(((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
4106 MemoryArea
->Data
.SectionData
.ViewOffset
);
4108 Section
= MemoryArea
->Data
.SectionData
.Section
;
4109 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4111 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4115 MmUnlockSectionSegment(Segment
);
4116 MmUnlockAddressSpace(AddressSpace
);
4118 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4119 if (Status
!= STATUS_SUCCESS
)
4121 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4122 KeBugCheck(MEMORY_MANAGEMENT
);
4125 MmLockAddressSpace(AddressSpace
);
4126 MmLockSectionSegment(Segment
);
4127 MmspCompleteAndReleasePageOp(PageOp
);
4128 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4131 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
4134 * For a dirty, datafile, non-private page mark it as dirty in the
4137 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4139 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4141 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4142 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4144 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
4146 ASSERT(SwapEntry
== 0);
4155 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4157 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4158 KeBugCheck(MEMORY_MANAGEMENT
);
4160 MmFreeSwapPage(SwapEntry
);
4164 if (IS_SWAP_FROM_SSE(Entry
) ||
4165 Page
!= PFN_FROM_SSE(Entry
))
4170 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4172 DPRINT1("Found a private page in a pagefile section.\n");
4173 KeBugCheck(MEMORY_MANAGEMENT
);
4176 * Just dereference private pages
4178 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4179 if (SavedSwapEntry
!= 0)
4181 MmFreeSwapPage(SavedSwapEntry
);
4182 MmSetSavedSwapEntryPage(Page
, 0);
4184 MmDeleteRmap(Page
, Process
, Address
);
4185 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4189 MmDeleteRmap(Page
, Process
, Address
);
4190 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4196 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4200 PMEMORY_AREA MemoryArea
;
4201 PROS_SECTION_OBJECT Section
;
4202 PMM_SECTION_SEGMENT Segment
;
4203 PLIST_ENTRY CurrentEntry
;
4204 PMM_REGION CurrentRegion
;
4205 PLIST_ENTRY RegionListHead
;
4207 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4209 if (MemoryArea
== NULL
)
4211 return(STATUS_UNSUCCESSFUL
);
4214 MemoryArea
->DeleteInProgress
= TRUE
;
4215 Section
= MemoryArea
->Data
.SectionData
.Section
;
4216 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4218 MmLockSectionSegment(Segment
);
4220 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4221 while (!IsListEmpty(RegionListHead
))
4223 CurrentEntry
= RemoveHeadList(RegionListHead
);
4224 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4225 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4228 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4230 Status
= MmFreeMemoryArea(AddressSpace
,
4237 Status
= MmFreeMemoryArea(AddressSpace
,
4242 MmUnlockSectionSegment(Segment
);
4243 ObDereferenceObject(Section
);
4251 MmUnmapViewOfSection(PEPROCESS Process
,
4255 PMEMORY_AREA MemoryArea
;
4256 PMMSUPPORT AddressSpace
;
4257 PROS_SECTION_OBJECT Section
;
4260 PVOID ImageBaseAddress
= 0;
4262 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4263 Process
, BaseAddress
);
4267 AddressSpace
= &Process
->Vm
;
4269 MmLockAddressSpace(AddressSpace
);
4270 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4272 if (MemoryArea
== NULL
||
4273 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4274 MemoryArea
->DeleteInProgress
)
4276 MmUnlockAddressSpace(AddressSpace
);
4277 return STATUS_NOT_MAPPED_VIEW
;
4280 MemoryArea
->DeleteInProgress
= TRUE
;
4282 while (MemoryArea
->PageOpCount
)
4284 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4288 Offset
-= PAGE_SIZE
;
4289 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4290 MemoryArea
->Data
.SectionData
.Segment
,
4291 (ULONG
)Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4294 MmUnlockAddressSpace(AddressSpace
);
4295 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4296 if (Status
!= STATUS_SUCCESS
)
4298 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4299 KeBugCheck(MEMORY_MANAGEMENT
);
4301 MmLockAddressSpace(AddressSpace
);
4302 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4304 if (MemoryArea
== NULL
||
4305 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4307 MmUnlockAddressSpace(AddressSpace
);
4308 return STATUS_NOT_MAPPED_VIEW
;
4315 Section
= MemoryArea
->Data
.SectionData
.Section
;
4317 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4321 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4322 PMM_SECTION_SEGMENT SectionSegments
;
4323 PMM_SECTION_SEGMENT Segment
;
4325 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4326 ImageSectionObject
= Section
->ImageSection
;
4327 SectionSegments
= ImageSectionObject
->Segments
;
4328 NrSegments
= ImageSectionObject
->NrSegments
;
4330 /* Search for the current segment within the section segments
4331 * and calculate the image base address */
4332 for (i
= 0; i
< NrSegments
; i
++)
4334 if (Segment
== &SectionSegments
[i
])
4336 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4340 if (i
>= NrSegments
)
4342 KeBugCheck(MEMORY_MANAGEMENT
);
4345 for (i
= 0; i
< NrSegments
; i
++)
4347 PVOID SBaseAddress
= (PVOID
)
4348 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4350 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4355 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4358 MmUnlockAddressSpace(AddressSpace
);
4360 /* Notify debugger */
4361 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4363 return(STATUS_SUCCESS
);
4370 * Queries the information of a section object.
4372 * @param SectionHandle
4373 * Handle to the section object. It must be opened with SECTION_QUERY
4375 * @param SectionInformationClass
4376 * Index to a certain information structure. Can be either
4377 * SectionBasicInformation or SectionImageInformation. The latter
4378 * is valid only for sections that were created with the SEC_IMAGE
4380 * @param SectionInformation
4381 * Caller supplies storage for resulting information.
4383 * Size of the supplied storage.
4384 * @param ResultLength
4392 NtQuerySection(IN HANDLE SectionHandle
,
4393 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4394 OUT PVOID SectionInformation
,
4395 IN SIZE_T SectionInformationLength
,
4396 OUT PSIZE_T ResultLength OPTIONAL
)
4398 PROS_SECTION_OBJECT Section
;
4399 KPROCESSOR_MODE PreviousMode
;
4403 PreviousMode
= ExGetPreviousMode();
4405 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4407 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4409 (ULONG
)SectionInformationLength
,
4414 if(!NT_SUCCESS(Status
))
4416 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4420 Status
= ObReferenceObjectByHandle(SectionHandle
,
4422 MmSectionObjectType
,
4424 (PVOID
*)(PVOID
)&Section
,
4426 if (NT_SUCCESS(Status
))
4428 switch (SectionInformationClass
)
4430 case SectionBasicInformation
:
4432 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4436 Sbi
->Attributes
= Section
->AllocationAttributes
;
4437 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4439 Sbi
->BaseAddress
= 0;
4440 Sbi
->Size
.QuadPart
= 0;
4444 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4445 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4448 if (ResultLength
!= NULL
)
4450 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4452 Status
= STATUS_SUCCESS
;
4454 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4456 Status
= _SEH2_GetExceptionCode();
4463 case SectionImageInformation
:
4465 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4469 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4470 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4472 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4473 ImageSectionObject
= Section
->ImageSection
;
4475 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4476 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4477 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4478 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4479 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4480 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4481 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4482 Sii
->Machine
= ImageSectionObject
->Machine
;
4483 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4486 if (ResultLength
!= NULL
)
4488 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4490 Status
= STATUS_SUCCESS
;
4492 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4494 Status
= _SEH2_GetExceptionCode();
4502 ObDereferenceObject(Section
);
4508 /**********************************************************************
4510 * MmMapViewOfSection
4513 * Maps a view of a section into the virtual address space of a
4518 * Pointer to the section object.
4521 * Pointer to the process.
4524 * Desired base address (or NULL) on entry;
4525 * Actual base address of the view on exit.
4528 * Number of high order address bits that must be zero.
4531 * Size in bytes of the initially committed section of
4535 * Offset in bytes from the beginning of the section
4536 * to the beginning of the view.
4539 * Desired length of map (or zero to map all) on entry
4540 * Actual length mapped on exit.
4542 * InheritDisposition
4543 * Specified how the view is to be shared with
4547 * Type of allocation for the pages.
4550 * Protection for the committed region of the view.
4558 MmMapViewOfSection(IN PVOID SectionObject
,
4559 IN PEPROCESS Process
,
4560 IN OUT PVOID
*BaseAddress
,
4561 IN ULONG_PTR ZeroBits
,
4562 IN SIZE_T CommitSize
,
4563 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4564 IN OUT PSIZE_T ViewSize
,
4565 IN SECTION_INHERIT InheritDisposition
,
4566 IN ULONG AllocationType
,
4569 PROS_SECTION_OBJECT Section
;
4570 PMMSUPPORT AddressSpace
;
4572 NTSTATUS Status
= STATUS_SUCCESS
;
4573 BOOLEAN NotAtBase
= FALSE
;
4575 if ((ULONG_PTR
)SectionObject
& 1)
4577 return MmMapViewOfArm3Section((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4591 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4593 return STATUS_INVALID_PAGE_PROTECTION
;
4597 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4598 AddressSpace
= &Process
->Vm
;
4600 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4602 MmLockAddressSpace(AddressSpace
);
4604 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4608 ULONG_PTR ImageBase
;
4610 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4611 PMM_SECTION_SEGMENT SectionSegments
;
4613 ImageSectionObject
= Section
->ImageSection
;
4614 SectionSegments
= ImageSectionObject
->Segments
;
4615 NrSegments
= ImageSectionObject
->NrSegments
;
4618 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4621 ImageBase
= ImageSectionObject
->ImageBase
;
4625 for (i
= 0; i
< NrSegments
; i
++)
4627 ULONG_PTR MaxExtent
;
4628 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4629 SectionSegments
[i
].Length
;
4630 ImageSize
= max(ImageSize
, MaxExtent
);
4633 ImageSectionObject
->ImageSize
= (ULONG
)ImageSize
;
4635 /* Check for an illegal base address */
4636 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4638 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4641 /* Check there is enough space to map the section at that point. */
4642 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4643 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4645 /* Fail if the user requested a fixed base address. */
4646 if ((*BaseAddress
) != NULL
)
4648 MmUnlockAddressSpace(AddressSpace
);
4649 return(STATUS_UNSUCCESSFUL
);
4651 /* Otherwise find a gap to map the image. */
4652 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4655 MmUnlockAddressSpace(AddressSpace
);
4656 return(STATUS_UNSUCCESSFUL
);
4658 /* Remember that we loaded image at a different base address */
4662 for (i
= 0; i
< NrSegments
; i
++)
4664 PVOID SBaseAddress
= (PVOID
)
4665 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4666 MmLockSectionSegment(&SectionSegments
[i
]);
4667 Status
= MmMapViewOfSegment(AddressSpace
,
4669 &SectionSegments
[i
],
4671 SectionSegments
[i
].Length
,
4672 SectionSegments
[i
].Protection
,
4675 MmUnlockSectionSegment(&SectionSegments
[i
]);
4676 if (!NT_SUCCESS(Status
))
4678 MmUnlockAddressSpace(AddressSpace
);
4683 *BaseAddress
= (PVOID
)ImageBase
;
4684 *ViewSize
= ImageSize
;
4688 /* check for write access */
4689 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4690 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4692 MmUnlockAddressSpace(AddressSpace
);
4693 return STATUS_SECTION_PROTECTION
;
4695 /* check for read access */
4696 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4697 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4699 MmUnlockAddressSpace(AddressSpace
);
4700 return STATUS_SECTION_PROTECTION
;
4702 /* check for execute access */
4703 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4704 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4706 MmUnlockAddressSpace(AddressSpace
);
4707 return STATUS_SECTION_PROTECTION
;
4710 if (ViewSize
== NULL
)
4712 /* Following this pointer would lead to us to the dark side */
4713 /* What to do? Bugcheck? Return status? Do the mambo? */
4714 KeBugCheck(MEMORY_MANAGEMENT
);
4717 if (SectionOffset
== NULL
)
4723 ViewOffset
= SectionOffset
->u
.LowPart
;
4726 if ((ViewOffset
% PAGE_SIZE
) != 0)
4728 MmUnlockAddressSpace(AddressSpace
);
4729 return(STATUS_MAPPED_ALIGNMENT
);
4732 if ((*ViewSize
) == 0)
4734 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4736 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4738 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4741 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4743 MmLockSectionSegment(Section
->Segment
);
4744 Status
= MmMapViewOfSegment(AddressSpace
,
4751 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4752 MmUnlockSectionSegment(Section
->Segment
);
4753 if (!NT_SUCCESS(Status
))
4755 MmUnlockAddressSpace(AddressSpace
);
4760 MmUnlockAddressSpace(AddressSpace
);
4763 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4765 Status
= STATUS_SUCCESS
;
4774 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4775 IN PLARGE_INTEGER NewFileSize
)
4777 /* Check whether an ImageSectionObject exists */
4778 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4780 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4784 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4786 PMM_SECTION_SEGMENT Segment
;
4788 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4791 if (Segment
->ReferenceCount
!= 0)
4793 /* Check size of file */
4794 if (SectionObjectPointer
->SharedCacheMap
)
4796 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4797 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4805 /* Something must gone wrong
4806 * how can we have a Section but no
4808 DPRINT("ERROR: DataSectionObject without reference!\n");
4812 DPRINT("FIXME: didn't check for outstanding write probes\n");
4824 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4825 IN MMFLUSH_TYPE FlushType
)
4829 case MmFlushForDelete
:
4830 if (SectionObjectPointer
->ImageSectionObject
||
4831 SectionObjectPointer
->DataSectionObject
)
4836 CcRosSetRemoveOnClose(SectionObjectPointer
);
4839 case MmFlushForWrite
:
4849 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4850 OUT PVOID
* MappedBase
,
4851 IN OUT PSIZE_T ViewSize
)
4853 PROS_SECTION_OBJECT Section
;
4854 PMMSUPPORT AddressSpace
;
4858 if ((ULONG_PTR
)SectionObject
& 1)
4860 extern PVOID MmSession
;
4861 return MiMapViewInSystemSpace((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4867 DPRINT("MmMapViewInSystemSpace() called\n");
4869 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4870 AddressSpace
= MmGetKernelAddressSpace();
4872 MmLockAddressSpace(AddressSpace
);
4875 if ((*ViewSize
) == 0)
4877 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4879 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4881 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4884 MmLockSectionSegment(Section
->Segment
);
4887 Status
= MmMapViewOfSegment(AddressSpace
,
4896 MmUnlockSectionSegment(Section
->Segment
);
4897 MmUnlockAddressSpace(AddressSpace
);
4906 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4908 PMMSUPPORT AddressSpace
;
4911 DPRINT("MmUnmapViewInSystemSpace() called\n");
4913 AddressSpace
= MmGetKernelAddressSpace();
4915 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4921 /**********************************************************************
4926 * Creates a section object.
4929 * SectionObject (OUT)
4930 * Caller supplied storage for the resulting pointer
4931 * to a SECTION_OBJECT instance;
4934 * Specifies the desired access to the section can be a
4936 * STANDARD_RIGHTS_REQUIRED |
4938 * SECTION_MAP_WRITE |
4939 * SECTION_MAP_READ |
4940 * SECTION_MAP_EXECUTE
4942 * ObjectAttributes [OPTIONAL]
4943 * Initialized attributes for the object can be used
4944 * to create a named section;
4947 * Maximizes the size of the memory section. Must be
4948 * non-NULL for a page-file backed section.
4949 * If value specified for a mapped file and the file is
4950 * not large enough, file will be extended.
4952 * SectionPageProtection
4953 * Can be a combination of:
4959 * AllocationAttributes
4960 * Can be a combination of:
4965 * Handle to a file to create a section mapped to a file
4966 * instead of a memory backed section;
4977 MmCreateSection (OUT PVOID
* Section
,
4978 IN ACCESS_MASK DesiredAccess
,
4979 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4980 IN PLARGE_INTEGER MaximumSize
,
4981 IN ULONG SectionPageProtection
,
4982 IN ULONG AllocationAttributes
,
4983 IN HANDLE FileHandle OPTIONAL
,
4984 IN PFILE_OBJECT File OPTIONAL
)
4987 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4989 /* Check if an ARM3 section is being created instead */
4990 if (AllocationAttributes
& 1)
4992 DPRINT1("arm 3 path\n");
4993 return MmCreateArm3Section(Section
,
4997 SectionPageProtection
,
4998 AllocationAttributes
&~ 1,
5004 * Check the protection
5006 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
5007 if (Protection
!= PAGE_READONLY
&&
5008 Protection
!= PAGE_READWRITE
&&
5009 Protection
!= PAGE_WRITECOPY
&&
5010 Protection
!= PAGE_EXECUTE
&&
5011 Protection
!= PAGE_EXECUTE_READ
&&
5012 Protection
!= PAGE_EXECUTE_READWRITE
&&
5013 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5015 return STATUS_INVALID_PAGE_PROTECTION
;
5018 if (AllocationAttributes
& SEC_IMAGE
)
5020 return(MmCreateImageSection(SectionObject
,
5024 SectionPageProtection
,
5025 AllocationAttributes
,
5029 if (FileHandle
!= NULL
)
5031 return(MmCreateDataFileSection(SectionObject
,
5035 SectionPageProtection
,
5036 AllocationAttributes
,
5040 return(MmCreatePageFileSection(SectionObject
,
5044 SectionPageProtection
,
5045 AllocationAttributes
));