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 *****************************************************************/
50 #include <reactos/exeformat.h>
52 #if defined (ALLOC_PRAGMA)
53 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
54 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 MiMapViewInSystemSpace(IN PVOID Section
,
61 OUT PVOID
*MappedBase
,
62 IN OUT PSIZE_T ViewSize
);
66 MmCreateArm3Section(OUT PVOID
*SectionObject
,
67 IN ACCESS_MASK DesiredAccess
,
68 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
69 IN PLARGE_INTEGER InputMaximumSize
,
70 IN ULONG SectionPageProtection
,
71 IN ULONG AllocationAttributes
,
72 IN HANDLE FileHandle OPTIONAL
,
73 IN PFILE_OBJECT FileObject OPTIONAL
);
77 MmMapViewOfArm3Section(IN PVOID SectionObject
,
79 IN OUT PVOID
*BaseAddress
,
80 IN ULONG_PTR ZeroBits
,
82 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
83 IN OUT PSIZE_T ViewSize
,
84 IN SECTION_INHERIT InheritDisposition
,
85 IN ULONG AllocationType
,
89 // PeFmtCreateSection depends on the following:
91 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
92 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
94 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
95 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
96 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
98 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
99 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
100 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
101 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
102 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
103 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
104 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
105 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
106 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
108 /* TYPES *********************************************************************/
112 PROS_SECTION_OBJECT Section
;
113 PMM_SECTION_SEGMENT Segment
;
118 MM_SECTION_PAGEOUT_CONTEXT
;
120 /* GLOBALS *******************************************************************/
122 POBJECT_TYPE MmSectionObjectType
= NULL
;
124 SIZE_T MmAllocationFragment
;
126 ULONG_PTR MmSubsectionBase
;
128 static ULONG SectionCharacteristicsToProtect
[16] =
130 PAGE_NOACCESS
, /* 0 = NONE */
131 PAGE_NOACCESS
, /* 1 = SHARED */
132 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
133 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
134 PAGE_READONLY
, /* 4 = READABLE */
135 PAGE_READONLY
, /* 5 = READABLE, SHARED */
136 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
137 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
139 * FIXME? do we really need the WriteCopy field in segments? can't we use
140 * PAGE_WRITECOPY here?
142 PAGE_READWRITE
, /* 8 = WRITABLE */
143 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
144 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
145 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
146 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
147 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
148 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
149 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
152 static GENERIC_MAPPING MmpSectionMapping
= {
153 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
154 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
155 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
158 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
159 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
160 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
161 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
162 #define MAX_SHARE_COUNT 0x7FF
163 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
164 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
165 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
167 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
169 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
170 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
173 /* FUNCTIONS *****************************************************************/
178 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
179 File Format Specification", revision 6.0 (February 1999)
181 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
182 IN SIZE_T FileHeaderSize
,
184 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
186 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
187 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
190 ULONG cbFileHeaderOffsetSize
= 0;
191 ULONG cbSectionHeadersOffset
= 0;
192 ULONG cbSectionHeadersSize
;
193 ULONG cbSectionHeadersOffsetSize
= 0;
194 ULONG cbOptHeaderSize
;
195 ULONG cbHeadersSize
= 0;
196 ULONG nSectionAlignment
;
197 ULONG nFileAlignment
;
198 const IMAGE_DOS_HEADER
* pidhDosHeader
;
199 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
200 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
201 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
202 PMM_SECTION_SEGMENT pssSegments
;
203 LARGE_INTEGER lnOffset
;
205 ULONG nPrevVirtualEndOfSegment
= 0;
206 ULONG nFileSizeOfHeaders
= 0;
210 ASSERT(FileHeaderSize
> 0);
212 ASSERT(ImageSectionObject
);
214 ASSERT(AllocateSegmentsCb
);
216 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
218 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
220 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
223 pidhDosHeader
= FileHeader
;
226 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
228 /* image too small to be an MZ executable */
229 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
230 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
232 /* no MZ signature */
233 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
234 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
236 /* not a Windows executable */
237 if(pidhDosHeader
->e_lfanew
<= 0)
238 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
241 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
243 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
244 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
246 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
251 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
252 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
254 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
255 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
259 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
260 * need to read the header from the file
262 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
263 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
265 ULONG cbNtHeaderSize
;
269 l_ReadHeaderFromFile
:
271 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
273 /* read the header from the file */
274 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
276 if(!NT_SUCCESS(nStatus
))
277 DIE(("ReadFile failed, status %08X\n", nStatus
));
281 ASSERT(cbReadSize
> 0);
283 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
285 /* the buffer doesn't contain the file header */
286 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
287 DIE(("The file doesn't contain the PE file header\n"));
289 pinhNtHeader
= pData
;
291 /* object still not aligned: copy it to the beginning of the buffer */
292 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
294 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
295 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
296 pinhNtHeader
= pBuffer
;
299 /* invalid NT header */
300 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
302 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
303 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
305 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
307 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
308 DIE(("The full NT header is too large\n"));
310 /* the buffer doesn't contain the whole NT header */
311 if(cbReadSize
< cbNtHeaderSize
)
312 DIE(("The file doesn't contain the full NT header\n"));
316 ULONG cbOptHeaderOffsetSize
= 0;
318 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
320 /* don't trust an invalid NT header */
321 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
322 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
324 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
325 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
327 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
328 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
330 /* the buffer doesn't contain the whole NT header: read it from the file */
331 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
332 goto l_ReadHeaderFromFile
;
335 /* read information from the NT header */
336 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
337 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
339 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
341 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
342 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
344 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
346 switch(piohOptHeader
->Magic
)
348 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
349 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
353 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
356 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
357 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
359 /* See [1], section 3.4.2 */
360 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
362 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
363 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
365 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
366 DIE(("The section alignment is smaller than the file alignment\n"));
368 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
369 nFileAlignment
= piohOptHeader
->FileAlignment
;
371 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
372 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
376 nSectionAlignment
= PAGE_SIZE
;
377 nFileAlignment
= PAGE_SIZE
;
380 ASSERT(IsPowerOf2(nSectionAlignment
));
381 ASSERT(IsPowerOf2(nFileAlignment
));
383 switch(piohOptHeader
->Magic
)
386 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
388 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
389 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
391 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
392 ImageSectionObject
->ImageSize
= piohOptHeader
->SizeOfImage
;
394 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
395 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
397 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
398 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
404 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
406 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
408 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
410 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
412 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
413 DIE(("ImageBase exceeds the address space\n"));
415 ImageSectionObject
->ImageBase
= (ULONG_PTR
)pioh64OptHeader
->ImageBase
;
418 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
420 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
421 DIE(("SizeOfImage exceeds the address space\n"));
423 ImageSectionObject
->ImageSize
= pioh64OptHeader
->SizeOfImage
;
426 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
428 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
429 DIE(("SizeOfStackReserve exceeds the address space\n"));
431 ImageSectionObject
->StackReserve
= pioh64OptHeader
->SizeOfStackReserve
;
434 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
436 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
437 DIE(("SizeOfStackCommit exceeds the address space\n"));
439 ImageSectionObject
->StackCommit
= pioh64OptHeader
->SizeOfStackCommit
;
446 /* [1], section 3.4.2 */
447 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
448 DIE(("ImageBase is not aligned on a 64KB boundary"));
450 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
452 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
454 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
455 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
457 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
458 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
462 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
464 ImageSectionObject
->EntryPoint
= piohOptHeader
->ImageBase
+
465 piohOptHeader
->AddressOfEntryPoint
;
468 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
469 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
471 ImageSectionObject
->Executable
= TRUE
;
473 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
474 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
476 /* SECTION HEADERS */
477 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
479 /* see [1], section 3.3 */
480 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
481 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
484 * the additional segment is for the file's headers. They need to be present for
485 * the benefit of the dynamic loader (to locate exports, defaults for thread
486 * parameters, resources, etc.)
488 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
490 /* file offset for the section headers */
491 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
492 DIE(("Offset overflow\n"));
494 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
495 DIE(("Offset overflow\n"));
497 /* size of the section headers */
498 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
499 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
501 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
502 DIE(("Section headers too large\n"));
504 /* size of the executable's headers */
505 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
507 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
508 // DIE(("SizeOfHeaders is not aligned\n"));
510 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
511 DIE(("The section headers overflow SizeOfHeaders\n"));
513 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
515 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
516 DIE(("Overflow aligning the size of headers\n"));
523 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
524 /* WARNING: piohOptHeader IS NO LONGER USABLE */
525 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
527 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
528 pishSectionHeaders
= NULL
;
532 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
533 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
535 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
536 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
540 * the buffer doesn't contain the section headers, or the alignment is wrong:
541 * read the headers from the file
543 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
544 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
549 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
551 /* read the header from the file */
552 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
554 if(!NT_SUCCESS(nStatus
))
555 DIE(("ReadFile failed with status %08X\n", nStatus
));
559 ASSERT(cbReadSize
> 0);
561 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
563 /* the buffer doesn't contain all the section headers */
564 if(cbReadSize
< cbSectionHeadersSize
)
565 DIE(("The file doesn't contain all of the section headers\n"));
567 pishSectionHeaders
= pData
;
569 /* object still not aligned: copy it to the beginning of the buffer */
570 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
572 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
573 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
574 pishSectionHeaders
= pBuffer
;
579 /* allocate the segments */
580 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
581 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
583 if(ImageSectionObject
->Segments
== NULL
)
584 DIE(("AllocateSegments failed\n"));
586 /* initialize the headers segment */
587 pssSegments
= ImageSectionObject
->Segments
;
589 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
591 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
592 DIE(("Cannot align the size of the section headers\n"));
594 if(!AlignUp(&nPrevVirtualEndOfSegment
, cbHeadersSize
, nSectionAlignment
))
595 DIE(("Cannot align the size of the section headers\n"));
597 pssSegments
[0].FileOffset
= 0;
598 pssSegments
[0].Protection
= PAGE_READONLY
;
599 pssSegments
[0].Length
= nPrevVirtualEndOfSegment
;
600 pssSegments
[0].RawLength
= nFileSizeOfHeaders
;
601 pssSegments
[0].VirtualAddress
= 0;
602 pssSegments
[0].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
603 pssSegments
[0].WriteCopy
= TRUE
;
605 /* skip the headers segment */
608 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
610 /* convert the executable sections into segments. See also [1], section 4 */
611 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
613 ULONG nCharacteristics
;
615 /* validate the alignment */
616 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
617 DIE(("VirtualAddress[%u] is not aligned\n", i
));
619 /* sections must be contiguous, ordered by base address and non-overlapping */
620 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
621 DIE(("Memory gap between section %u and the previous\n", i
));
623 /* ignore explicit BSS sections */
624 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
626 /* validate the alignment */
628 /* Yes, this should be a multiple of FileAlignment, but there's
629 * stuff out there that isn't. We can cope with that
631 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
632 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
635 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
636 // DIE(("PointerToRawData[%u] is not aligned\n", i));
639 pssSegments
[i
].FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
640 pssSegments
[i
].RawLength
= pishSectionHeaders
[i
].SizeOfRawData
;
644 ASSERT(pssSegments
[i
].FileOffset
== 0);
645 ASSERT(pssSegments
[i
].RawLength
== 0);
648 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].FileOffset
, pssSegments
[i
].RawLength
));
650 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
652 /* no explicit protection */
653 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
655 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
656 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
658 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
659 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
661 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
662 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
665 /* see table above */
666 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
667 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
669 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
670 pssSegments
[i
].Length
= pishSectionHeaders
[i
].SizeOfRawData
;
672 pssSegments
[i
].Length
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
674 if(!AlignUp(&pssSegments
[i
].Length
, pssSegments
[i
].Length
, nSectionAlignment
))
675 DIE(("Cannot align the virtual size of section %u\n", i
));
677 ASSERT(IsAligned(pssSegments
[i
].Length
, nSectionAlignment
));
679 if(pssSegments
[i
].Length
== 0)
680 DIE(("Virtual size of section %u is null\n", i
));
682 pssSegments
[i
].VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
683 pssSegments
[i
].Characteristics
= pishSectionHeaders
[i
].Characteristics
;
685 /* ensure the memory image is no larger than 4GB */
686 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment
, pssSegments
[i
].VirtualAddress
, pssSegments
[i
].Length
))
687 DIE(("The image is larger than 4GB\n"));
690 /* spare our caller some work in validating the segments */
691 *Flags
= EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
| EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
;
693 if(nSectionAlignment
>= PAGE_SIZE
)
694 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
697 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;
706 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
709 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
710 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
711 * RETURNS: Status of the wait.
714 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
716 LARGE_INTEGER Timeout
;
717 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
719 Timeout
.QuadPart
= -100000000LL; // 10 sec
722 Timeout
.QuadPart
= -100000000; // 10 sec
725 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
730 * FUNCTION: Sets the page op completion event and releases the page op.
731 * ARGUMENTS: PMM_PAGEOP.
732 * RETURNS: In shorter time than it takes you to even read this
733 * description, so don't even think about geting a mug of coffee.
736 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
738 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
739 MmReleasePageOp(PageOp
);
744 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
745 * ARGUMENTS: PFILE_OBJECT to wait for.
746 * RETURNS: Status of the wait.
749 MmspWaitForFileLock(PFILE_OBJECT File
)
751 return STATUS_SUCCESS
;
752 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
757 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
760 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
762 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
764 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
766 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
774 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
776 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
778 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
779 PMM_SECTION_SEGMENT SectionSegments
;
783 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
784 NrSegments
= ImageSectionObject
->NrSegments
;
785 SectionSegments
= ImageSectionObject
->Segments
;
786 for (i
= 0; i
< NrSegments
; i
++)
788 if (SectionSegments
[i
].ReferenceCount
!= 0)
790 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
791 SectionSegments
[i
].ReferenceCount
);
792 KeBugCheck(MEMORY_MANAGEMENT
);
794 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
796 ExFreePool(ImageSectionObject
->Segments
);
797 ExFreePool(ImageSectionObject
);
798 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
800 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
802 PMM_SECTION_SEGMENT Segment
;
804 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
807 if (Segment
->ReferenceCount
!= 0)
809 DPRINT1("Data segment still referenced\n");
810 KeBugCheck(MEMORY_MANAGEMENT
);
812 MmFreePageTablesSectionSegment(Segment
);
814 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
820 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
822 ExAcquireFastMutex(&Segment
->Lock
);
827 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
829 ExReleaseFastMutex(&Segment
->Lock
);
834 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
838 PSECTION_PAGE_TABLE Table
;
839 ULONG DirectoryOffset
;
842 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
844 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
848 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
849 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
853 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
854 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
855 TAG_SECTION_PAGE_TABLE
);
858 KeBugCheck(MEMORY_MANAGEMENT
);
860 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
861 DPRINT("Table %x\n", Table
);
864 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
865 Table
->Entry
[TableOffset
] = Entry
;
871 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
874 PSECTION_PAGE_TABLE Table
;
876 ULONG DirectoryOffset
;
879 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
881 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
883 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
887 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
888 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
889 DPRINT("Table %x\n", Table
);
895 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
896 Entry
= Table
->Entry
[TableOffset
];
902 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
907 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
910 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
911 KeBugCheck(MEMORY_MANAGEMENT
);
913 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
915 DPRINT1("Maximum share count reached\n");
916 KeBugCheck(MEMORY_MANAGEMENT
);
918 if (IS_SWAP_FROM_SSE(Entry
))
920 KeBugCheck(MEMORY_MANAGEMENT
);
922 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
923 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
928 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
929 PMM_SECTION_SEGMENT Segment
,
935 BOOLEAN IsDirectMapped
= FALSE
;
937 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
940 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
941 KeBugCheck(MEMORY_MANAGEMENT
);
943 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
945 DPRINT1("Zero share count for unshare\n");
946 KeBugCheck(MEMORY_MANAGEMENT
);
948 if (IS_SWAP_FROM_SSE(Entry
))
950 KeBugCheck(MEMORY_MANAGEMENT
);
952 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
954 * If we reducing the share count of this entry to zero then set the entry
955 * to zero and tell the cache the page is no longer mapped.
957 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
959 PFILE_OBJECT FileObject
;
961 SWAPENTRY SavedSwapEntry
;
963 BOOLEAN IsImageSection
;
966 FileOffset
= Offset
+ Segment
->FileOffset
;
968 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
970 Page
= PFN_FROM_SSE(Entry
);
971 FileObject
= Section
->FileObject
;
972 if (FileObject
!= NULL
&&
973 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
976 if ((FileOffset
% PAGE_SIZE
) == 0 &&
977 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
980 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
981 IsDirectMapped
= TRUE
;
982 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
983 if (!NT_SUCCESS(Status
))
985 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
986 KeBugCheck(MEMORY_MANAGEMENT
);
991 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
992 if (SavedSwapEntry
== 0)
995 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
996 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
1000 * Try to page out this page and set the swap entry
1001 * within the section segment. There exist no rmap entry
1002 * for this page. The pager thread can't page out a
1003 * page without a rmap entry.
1005 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1009 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
1010 if (!IsDirectMapped
)
1012 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1018 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1019 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1027 * We hold all locks. Nobody can do something with the current
1028 * process and the current segment (also not within an other process).
1031 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
1032 if (!NT_SUCCESS(Status
))
1034 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
1035 KeBugCheck(MEMORY_MANAGEMENT
);
1038 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
1039 MmSetSavedSwapEntryPage(Page
, 0);
1041 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1045 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1046 KeBugCheck(MEMORY_MANAGEMENT
);
1052 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1054 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1057 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1060 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1063 PCACHE_SEGMENT CacheSeg
;
1064 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1065 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
1068 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
1077 MiCopyFromUserPage(PFN_NUMBER DestPage
, PVOID SourceAddress
)
1083 Process
= PsGetCurrentProcess();
1084 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1085 if (TempAddress
== NULL
)
1087 return(STATUS_NO_MEMORY
);
1089 memcpy(TempAddress
, SourceAddress
, PAGE_SIZE
);
1090 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
1091 return(STATUS_SUCCESS
);
1096 MiReadPage(PMEMORY_AREA MemoryArea
,
1100 * FUNCTION: Read a page for a section backed memory area.
1102 * MemoryArea - Memory area to read the page for.
1103 * Offset - Offset of the page to read.
1104 * Page - Variable that receives a page contains the read data.
1111 PCACHE_SEGMENT CacheSeg
;
1112 PFILE_OBJECT FileObject
;
1116 BOOLEAN IsImageSection
;
1119 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1120 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1121 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
1122 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
1123 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1127 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1130 * If the file system is letting us go directly to the cache and the
1131 * memory area was mapped at an offset in the file which is page aligned
1132 * then get the related cache segment.
1134 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1135 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
1136 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1140 * Get the related cache segment; we use a lower level interface than
1141 * filesystems do because it is safe for us to use an offset with a
1142 * alignment less than the file system block size.
1144 Status
= CcRosGetCacheSegment(Bcb
,
1150 if (!NT_SUCCESS(Status
))
1157 * If the cache segment isn't up to date then call the file
1158 * system to read in the data.
1160 Status
= ReadCacheSegment(CacheSeg
);
1161 if (!NT_SUCCESS(Status
))
1163 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1168 * Retrieve the page from the cache segment that we actually want.
1170 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1171 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1173 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1180 ULONG CacheSegOffset
;
1183 * Allocate a page, this is rather complicated by the possibility
1184 * we might have to move other things out of memory
1186 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1187 if (!NT_SUCCESS(Status
))
1191 Status
= CcRosGetCacheSegment(Bcb
,
1197 if (!NT_SUCCESS(Status
))
1204 * If the cache segment isn't up to date then call the file
1205 * system to read in the data.
1207 Status
= ReadCacheSegment(CacheSeg
);
1208 if (!NT_SUCCESS(Status
))
1210 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1215 Process
= PsGetCurrentProcess();
1216 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1217 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
1218 Length
= RawLength
- SegOffset
;
1219 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1221 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1223 else if (CacheSegOffset
>= PAGE_SIZE
)
1225 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1229 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1230 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1231 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1232 Status
= CcRosGetCacheSegment(Bcb
,
1233 FileOffset
+ CacheSegOffset
,
1238 if (!NT_SUCCESS(Status
))
1245 * If the cache segment isn't up to date then call the file
1246 * system to read in the data.
1248 Status
= ReadCacheSegment(CacheSeg
);
1249 if (!NT_SUCCESS(Status
))
1251 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1255 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1256 if (Length
< PAGE_SIZE
)
1258 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1262 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1265 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1266 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1268 return(STATUS_SUCCESS
);
1273 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1274 MEMORY_AREA
* MemoryArea
,
1282 PROS_SECTION_OBJECT Section
;
1283 PMM_SECTION_SEGMENT Segment
;
1289 BOOLEAN HasSwapEntry
;
1290 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1293 * There is a window between taking the page fault and locking the
1294 * address space when another thread could load the page so we check
1297 if (MmIsPagePresent(Process
, Address
))
1299 return(STATUS_SUCCESS
);
1302 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1303 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1304 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1306 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1307 Section
= MemoryArea
->Data
.SectionData
.Section
;
1308 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1309 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1314 MmLockSectionSegment(Segment
);
1317 * Check if this page needs to be mapped COW
1319 if ((Segment
->WriteCopy
) &&
1320 (Region
->Protect
== PAGE_READWRITE
||
1321 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1323 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1327 Attributes
= Region
->Protect
;
1331 * Get or create a page operation descriptor
1333 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
1336 DPRINT1("MmGetPageOp failed\n");
1337 KeBugCheck(MEMORY_MANAGEMENT
);
1341 * Check if someone else is already handling this fault, if so wait
1344 if (PageOp
->Thread
!= PsGetCurrentThread())
1346 MmUnlockSectionSegment(Segment
);
1347 MmUnlockAddressSpace(AddressSpace
);
1348 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1350 * Check for various strange conditions
1352 if (Status
!= STATUS_SUCCESS
)
1354 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1355 KeBugCheck(MEMORY_MANAGEMENT
);
1357 if (PageOp
->Status
== STATUS_PENDING
)
1359 DPRINT1("Woke for page op before completion\n");
1360 KeBugCheck(MEMORY_MANAGEMENT
);
1362 MmLockAddressSpace(AddressSpace
);
1364 * If this wasn't a pagein then restart the operation
1366 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
1368 MmspCompleteAndReleasePageOp(PageOp
);
1369 DPRINT("Address 0x%.8X\n", Address
);
1370 return(STATUS_MM_RESTART_OPERATION
);
1374 * If the thread handling this fault has failed then we don't retry
1376 if (!NT_SUCCESS(PageOp
->Status
))
1378 Status
= PageOp
->Status
;
1379 MmspCompleteAndReleasePageOp(PageOp
);
1380 DPRINT("Address 0x%.8X\n", Address
);
1383 MmLockSectionSegment(Segment
);
1385 * If the completed fault was for another address space then set the
1388 if (!MmIsPagePresent(Process
, Address
))
1390 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1391 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1393 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
1396 * The page was a private page in another or in our address space
1398 MmUnlockSectionSegment(Segment
);
1399 MmspCompleteAndReleasePageOp(PageOp
);
1400 return(STATUS_MM_RESTART_OPERATION
);
1403 Page
= PFN_FROM_SSE(Entry
);
1405 MmSharePageEntrySectionSegment(Segment
, Offset
);
1407 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
1408 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
1410 Status
= MmCreateVirtualMapping(Process
,
1415 if (!NT_SUCCESS(Status
))
1417 DPRINT1("Unable to create virtual mapping\n");
1418 KeBugCheck(MEMORY_MANAGEMENT
);
1420 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1422 MmUnlockSectionSegment(Segment
);
1423 PageOp
->Status
= STATUS_SUCCESS
;
1424 MmspCompleteAndReleasePageOp(PageOp
);
1425 DPRINT("Address 0x%.8X\n", Address
);
1426 return(STATUS_SUCCESS
);
1429 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1433 * Must be private page we have swapped out.
1435 SWAPENTRY SwapEntry
;
1440 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1442 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1443 KeBugCheck(MEMORY_MANAGEMENT
);
1446 MmUnlockSectionSegment(Segment
);
1447 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
1449 MmUnlockAddressSpace(AddressSpace
);
1450 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1451 if (!NT_SUCCESS(Status
))
1453 KeBugCheck(MEMORY_MANAGEMENT
);
1456 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1457 if (!NT_SUCCESS(Status
))
1459 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1460 KeBugCheck(MEMORY_MANAGEMENT
);
1462 MmLockAddressSpace(AddressSpace
);
1463 Status
= MmCreateVirtualMapping(Process
,
1468 if (!NT_SUCCESS(Status
))
1470 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1471 KeBugCheck(MEMORY_MANAGEMENT
);
1476 * Store the swap entry for later use.
1478 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1481 * Add the page to the process's working set
1483 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1486 * Finish the operation
1488 PageOp
->Status
= STATUS_SUCCESS
;
1489 MmspCompleteAndReleasePageOp(PageOp
);
1490 DPRINT("Address 0x%.8X\n", Address
);
1491 return(STATUS_SUCCESS
);
1495 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1497 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1499 MmUnlockSectionSegment(Segment
);
1501 * Just map the desired physical page
1503 Page
= Offset
>> PAGE_SHIFT
;
1504 Status
= MmCreateVirtualMappingUnsafe(Process
,
1509 if (!NT_SUCCESS(Status
))
1511 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1512 KeBugCheck(MEMORY_MANAGEMENT
);
1517 * Cleanup and release locks
1519 PageOp
->Status
= STATUS_SUCCESS
;
1520 MmspCompleteAndReleasePageOp(PageOp
);
1521 DPRINT("Address 0x%.8X\n", Address
);
1522 return(STATUS_SUCCESS
);
1526 * Map anonymous memory for BSS sections
1528 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1530 MmUnlockSectionSegment(Segment
);
1531 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1532 if (!NT_SUCCESS(Status
))
1534 MmUnlockAddressSpace(AddressSpace
);
1535 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1536 MmLockAddressSpace(AddressSpace
);
1538 if (!NT_SUCCESS(Status
))
1540 KeBugCheck(MEMORY_MANAGEMENT
);
1542 Status
= MmCreateVirtualMapping(Process
,
1547 if (!NT_SUCCESS(Status
))
1549 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1550 KeBugCheck(MEMORY_MANAGEMENT
);
1553 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1556 * Cleanup and release locks
1558 PageOp
->Status
= STATUS_SUCCESS
;
1559 MmspCompleteAndReleasePageOp(PageOp
);
1560 DPRINT("Address 0x%.8X\n", Address
);
1561 return(STATUS_SUCCESS
);
1565 * Get the entry corresponding to the offset within the section
1567 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1572 * If the entry is zero (and it can't change because we have
1573 * locked the segment) then we need to load the page.
1577 * Release all our locks and read in the page from disk
1579 MmUnlockSectionSegment(Segment
);
1580 MmUnlockAddressSpace(AddressSpace
);
1582 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1583 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1585 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1586 if (!NT_SUCCESS(Status
))
1588 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1593 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1594 if (!NT_SUCCESS(Status
))
1596 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1599 if (!NT_SUCCESS(Status
))
1602 * FIXME: What do we know in this case?
1605 * Cleanup and release locks
1607 MmLockAddressSpace(AddressSpace
);
1608 PageOp
->Status
= Status
;
1609 MmspCompleteAndReleasePageOp(PageOp
);
1610 DPRINT("Address 0x%.8X\n", Address
);
1614 * Relock the address space and segment
1616 MmLockAddressSpace(AddressSpace
);
1617 MmLockSectionSegment(Segment
);
1620 * Check the entry. No one should change the status of a page
1621 * that has a pending page-in.
1623 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1624 if (Entry
!= Entry1
)
1626 DPRINT1("Someone changed ppte entry while we slept\n");
1627 KeBugCheck(MEMORY_MANAGEMENT
);
1631 * Mark the offset within the section as having valid, in-memory
1634 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1635 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1636 MmUnlockSectionSegment(Segment
);
1638 Status
= MmCreateVirtualMapping(Process
,
1643 if (!NT_SUCCESS(Status
))
1645 DPRINT1("Unable to create virtual mapping\n");
1646 KeBugCheck(MEMORY_MANAGEMENT
);
1648 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1650 PageOp
->Status
= STATUS_SUCCESS
;
1651 MmspCompleteAndReleasePageOp(PageOp
);
1652 DPRINT("Address 0x%.8X\n", Address
);
1653 return(STATUS_SUCCESS
);
1655 else if (IS_SWAP_FROM_SSE(Entry
))
1657 SWAPENTRY SwapEntry
;
1659 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1662 * Release all our locks and read in the page from disk
1664 MmUnlockSectionSegment(Segment
);
1666 MmUnlockAddressSpace(AddressSpace
);
1668 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1669 if (!NT_SUCCESS(Status
))
1671 KeBugCheck(MEMORY_MANAGEMENT
);
1674 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1675 if (!NT_SUCCESS(Status
))
1677 KeBugCheck(MEMORY_MANAGEMENT
);
1681 * Relock the address space and segment
1683 MmLockAddressSpace(AddressSpace
);
1684 MmLockSectionSegment(Segment
);
1687 * Check the entry. No one should change the status of a page
1688 * that has a pending page-in.
1690 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1691 if (Entry
!= Entry1
)
1693 DPRINT1("Someone changed ppte entry while we slept\n");
1694 KeBugCheck(MEMORY_MANAGEMENT
);
1698 * Mark the offset within the section as having valid, in-memory
1701 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1702 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1703 MmUnlockSectionSegment(Segment
);
1706 * Save the swap entry.
1708 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1709 Status
= MmCreateVirtualMapping(Process
,
1714 if (!NT_SUCCESS(Status
))
1716 DPRINT1("Unable to create virtual mapping\n");
1717 KeBugCheck(MEMORY_MANAGEMENT
);
1719 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1720 PageOp
->Status
= STATUS_SUCCESS
;
1721 MmspCompleteAndReleasePageOp(PageOp
);
1722 DPRINT("Address 0x%.8X\n", Address
);
1723 return(STATUS_SUCCESS
);
1728 * If the section offset is already in-memory and valid then just
1729 * take another reference to the page
1732 Page
= PFN_FROM_SSE(Entry
);
1734 MmSharePageEntrySectionSegment(Segment
, Offset
);
1735 MmUnlockSectionSegment(Segment
);
1737 Status
= MmCreateVirtualMapping(Process
,
1742 if (!NT_SUCCESS(Status
))
1744 DPRINT1("Unable to create virtual mapping\n");
1745 KeBugCheck(MEMORY_MANAGEMENT
);
1747 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1748 PageOp
->Status
= STATUS_SUCCESS
;
1749 MmspCompleteAndReleasePageOp(PageOp
);
1750 DPRINT("Address 0x%.8X\n", Address
);
1751 return(STATUS_SUCCESS
);
1757 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1758 MEMORY_AREA
* MemoryArea
,
1762 PMM_SECTION_SEGMENT Segment
;
1763 PROS_SECTION_OBJECT Section
;
1772 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1774 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1777 * Check if the page has been paged out or has already been set readwrite
1779 if (!MmIsPagePresent(Process
, Address
) ||
1780 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1782 DPRINT("Address 0x%.8X\n", Address
);
1783 return(STATUS_SUCCESS
);
1787 * Find the offset of the page
1789 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1790 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1791 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1793 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1794 Section
= MemoryArea
->Data
.SectionData
.Section
;
1795 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1796 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1801 MmLockSectionSegment(Segment
);
1803 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1804 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1806 MmUnlockSectionSegment(Segment
);
1809 * Check if we are doing COW
1811 if (!((Segment
->WriteCopy
) &&
1812 (Region
->Protect
== PAGE_READWRITE
||
1813 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1815 DPRINT("Address 0x%.8X\n", Address
);
1816 return(STATUS_ACCESS_VIOLATION
);
1819 if (IS_SWAP_FROM_SSE(Entry
) ||
1820 PFN_FROM_SSE(Entry
) != OldPage
)
1822 /* This is a private page. We must only change the page protection. */
1823 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1824 return(STATUS_SUCCESS
);
1828 * Get or create a pageop
1830 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1831 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1834 DPRINT1("MmGetPageOp failed\n");
1835 KeBugCheck(MEMORY_MANAGEMENT
);
1839 * Wait for any other operations to complete
1841 if (PageOp
->Thread
!= PsGetCurrentThread())
1843 MmUnlockAddressSpace(AddressSpace
);
1844 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1846 * Check for various strange conditions
1848 if (Status
== STATUS_TIMEOUT
)
1850 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1851 KeBugCheck(MEMORY_MANAGEMENT
);
1853 if (PageOp
->Status
== STATUS_PENDING
)
1855 DPRINT1("Woke for page op before completion\n");
1856 KeBugCheck(MEMORY_MANAGEMENT
);
1859 * Restart the operation
1861 MmLockAddressSpace(AddressSpace
);
1862 MmspCompleteAndReleasePageOp(PageOp
);
1863 DPRINT("Address 0x%.8X\n", Address
);
1864 return(STATUS_MM_RESTART_OPERATION
);
1868 * Release locks now we have the pageop
1870 MmUnlockAddressSpace(AddressSpace
);
1875 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1876 if (!NT_SUCCESS(Status
))
1878 KeBugCheck(MEMORY_MANAGEMENT
);
1884 MiCopyFromUserPage(NewPage
, PAddress
);
1886 MmLockAddressSpace(AddressSpace
);
1888 * Delete the old entry.
1890 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1893 * Set the PTE to point to the new page
1895 Status
= MmCreateVirtualMapping(Process
,
1900 if (!NT_SUCCESS(Status
))
1902 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1903 KeBugCheck(MEMORY_MANAGEMENT
);
1906 if (!NT_SUCCESS(Status
))
1908 DPRINT1("Unable to create virtual mapping\n");
1909 KeBugCheck(MEMORY_MANAGEMENT
);
1913 * Unshare the old page.
1915 MmDeleteRmap(OldPage
, Process
, PAddress
);
1916 MmInsertRmap(NewPage
, Process
, PAddress
);
1917 MmLockSectionSegment(Segment
);
1918 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1919 MmUnlockSectionSegment(Segment
);
1921 PageOp
->Status
= STATUS_SUCCESS
;
1922 MmspCompleteAndReleasePageOp(PageOp
);
1923 DPRINT("Address 0x%.8X\n", Address
);
1924 return(STATUS_SUCCESS
);
1928 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1930 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1934 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1937 MmLockAddressSpace(&Process
->Vm
);
1940 MmDeleteVirtualMapping(Process
,
1947 PageOutContext
->WasDirty
= TRUE
;
1949 if (!PageOutContext
->Private
)
1951 MmLockSectionSegment(PageOutContext
->Segment
);
1952 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1953 PageOutContext
->Segment
,
1954 PageOutContext
->Offset
,
1955 PageOutContext
->WasDirty
,
1957 MmUnlockSectionSegment(PageOutContext
->Segment
);
1961 MmUnlockAddressSpace(&Process
->Vm
);
1964 if (PageOutContext
->Private
)
1966 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1969 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1974 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1975 MEMORY_AREA
* MemoryArea
,
1980 MM_SECTION_PAGEOUT_CONTEXT Context
;
1981 SWAPENTRY SwapEntry
;
1985 PFILE_OBJECT FileObject
;
1987 BOOLEAN DirectMapped
;
1988 BOOLEAN IsImageSection
;
1989 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1992 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1995 * Get the segment and section.
1997 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1998 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
2000 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2001 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2002 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
2004 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2006 FileObject
= Context
.Section
->FileObject
;
2007 DirectMapped
= FALSE
;
2008 if (FileObject
!= NULL
&&
2009 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2011 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2014 * If the file system is letting us go directly to the cache and the
2015 * memory area was mapped at an offset in the file which is page aligned
2016 * then note this is a direct mapped page.
2018 if ((FileOffset
% PAGE_SIZE
) == 0 &&
2019 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
2021 DirectMapped
= TRUE
;
2027 * This should never happen since mappings of physical memory are never
2028 * placed in the rmap lists.
2030 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2032 DPRINT1("Trying to page out from physical memory section address 0x%X "
2033 "process %d\n", Address
,
2034 Process
? Process
->UniqueProcessId
: 0);
2035 KeBugCheck(MEMORY_MANAGEMENT
);
2039 * Get the section segment entry and the physical address.
2041 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
2042 if (!MmIsPagePresent(Process
, Address
))
2044 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2045 Process
? Process
->UniqueProcessId
: 0, Address
);
2046 KeBugCheck(MEMORY_MANAGEMENT
);
2048 Page
= MmGetPfnForProcess(Process
, Address
);
2049 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2052 * Prepare the context structure for the rmap delete call.
2054 Context
.WasDirty
= FALSE
;
2055 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2056 IS_SWAP_FROM_SSE(Entry
) ||
2057 PFN_FROM_SSE(Entry
) != Page
)
2059 Context
.Private
= TRUE
;
2063 Context
.Private
= FALSE
;
2067 * Take an additional reference to the page or the cache segment.
2069 if (DirectMapped
&& !Context
.Private
)
2071 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
2073 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2074 KeBugCheck(MEMORY_MANAGEMENT
);
2079 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
2080 MmReferencePage(Page
);
2081 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
2084 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2087 * If this wasn't a private page then we should have reduced the entry to
2088 * zero by deleting all the rmaps.
2090 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
2092 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2093 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2095 KeBugCheck(MEMORY_MANAGEMENT
);
2100 * If the page wasn't dirty then we can just free it as for a readonly page.
2101 * Since we unmapped all the mappings above we know it will not suddenly
2103 * If the page is from a pagefile section and has no swap entry,
2104 * we can't free the page at this point.
2106 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2107 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2109 if (Context
.Private
)
2111 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
2112 Context
.WasDirty
? "dirty" : "clean", Address
);
2113 KeBugCheck(MEMORY_MANAGEMENT
);
2115 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2117 MmSetSavedSwapEntryPage(Page
, 0);
2118 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2119 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2120 PageOp
->Status
= STATUS_SUCCESS
;
2121 MmspCompleteAndReleasePageOp(PageOp
);
2122 return(STATUS_SUCCESS
);
2125 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2127 if (Context
.Private
)
2129 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2130 Context
.WasDirty
? "dirty" : "clean", Address
);
2131 KeBugCheck(MEMORY_MANAGEMENT
);
2133 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2135 MmSetSavedSwapEntryPage(Page
, 0);
2138 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2140 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2141 PageOp
->Status
= STATUS_SUCCESS
;
2142 MmspCompleteAndReleasePageOp(PageOp
);
2143 return(STATUS_SUCCESS
);
2146 else if (!Context
.Private
&& DirectMapped
)
2150 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2152 KeBugCheck(MEMORY_MANAGEMENT
);
2154 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
2155 if (!NT_SUCCESS(Status
))
2157 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2158 KeBugCheck(MEMORY_MANAGEMENT
);
2160 PageOp
->Status
= STATUS_SUCCESS
;
2161 MmspCompleteAndReleasePageOp(PageOp
);
2162 return(STATUS_SUCCESS
);
2164 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2168 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2170 KeBugCheck(MEMORY_MANAGEMENT
);
2172 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2173 PageOp
->Status
= STATUS_SUCCESS
;
2174 MmspCompleteAndReleasePageOp(PageOp
);
2175 return(STATUS_SUCCESS
);
2177 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2179 MmSetSavedSwapEntryPage(Page
, 0);
2180 MmLockAddressSpace(AddressSpace
);
2181 Status
= MmCreatePageFileMapping(Process
,
2184 MmUnlockAddressSpace(AddressSpace
);
2185 if (!NT_SUCCESS(Status
))
2187 KeBugCheck(MEMORY_MANAGEMENT
);
2189 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2190 PageOp
->Status
= STATUS_SUCCESS
;
2191 MmspCompleteAndReleasePageOp(PageOp
);
2192 return(STATUS_SUCCESS
);
2196 * If necessary, allocate an entry in the paging file for this page
2200 SwapEntry
= MmAllocSwapPage();
2203 MmShowOutOfSpaceMessagePagingFile();
2204 MmLockAddressSpace(AddressSpace
);
2206 * For private pages restore the old mappings.
2208 if (Context
.Private
)
2210 Status
= MmCreateVirtualMapping(Process
,
2212 MemoryArea
->Protect
,
2215 MmSetDirtyPage(Process
, Address
);
2223 * For non-private pages if the page wasn't direct mapped then
2224 * set it back into the section segment entry so we don't loose
2225 * our copy. Otherwise it will be handled by the cache manager.
2227 Status
= MmCreateVirtualMapping(Process
,
2229 MemoryArea
->Protect
,
2232 MmSetDirtyPage(Process
, Address
);
2236 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2237 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2239 MmUnlockAddressSpace(AddressSpace
);
2240 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2241 MmspCompleteAndReleasePageOp(PageOp
);
2242 return(STATUS_PAGEFILE_QUOTA
);
2247 * Write the page to the pagefile
2249 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2250 if (!NT_SUCCESS(Status
))
2252 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2255 * As above: undo our actions.
2256 * FIXME: Also free the swap page.
2258 MmLockAddressSpace(AddressSpace
);
2259 if (Context
.Private
)
2261 Status
= MmCreateVirtualMapping(Process
,
2263 MemoryArea
->Protect
,
2266 MmSetDirtyPage(Process
, Address
);
2273 Status
= MmCreateVirtualMapping(Process
,
2275 MemoryArea
->Protect
,
2278 MmSetDirtyPage(Process
, Address
);
2282 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2283 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2285 MmUnlockAddressSpace(AddressSpace
);
2286 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2287 MmspCompleteAndReleasePageOp(PageOp
);
2288 return(STATUS_UNSUCCESSFUL
);
2292 * Otherwise we have succeeded.
2294 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2295 MmSetSavedSwapEntryPage(Page
, 0);
2296 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2297 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2299 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2303 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2306 if (Context
.Private
)
2308 MmLockAddressSpace(AddressSpace
);
2309 Status
= MmCreatePageFileMapping(Process
,
2312 MmUnlockAddressSpace(AddressSpace
);
2313 if (!NT_SUCCESS(Status
))
2315 KeBugCheck(MEMORY_MANAGEMENT
);
2320 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2321 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2324 PageOp
->Status
= STATUS_SUCCESS
;
2325 MmspCompleteAndReleasePageOp(PageOp
);
2326 return(STATUS_SUCCESS
);
2331 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2332 PMEMORY_AREA MemoryArea
,
2337 PROS_SECTION_OBJECT Section
;
2338 PMM_SECTION_SEGMENT Segment
;
2340 SWAPENTRY SwapEntry
;
2344 PFILE_OBJECT FileObject
;
2346 BOOLEAN DirectMapped
;
2347 BOOLEAN IsImageSection
;
2348 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2350 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2352 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2353 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2356 * Get the segment and section.
2358 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2359 Section
= MemoryArea
->Data
.SectionData
.Section
;
2360 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2362 FileObject
= Section
->FileObject
;
2363 DirectMapped
= FALSE
;
2364 if (FileObject
!= NULL
&&
2365 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2367 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2370 * If the file system is letting us go directly to the cache and the
2371 * memory area was mapped at an offset in the file which is page aligned
2372 * then note this is a direct mapped page.
2374 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
2375 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
2377 DirectMapped
= TRUE
;
2382 * This should never happen since mappings of physical memory are never
2383 * placed in the rmap lists.
2385 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2387 DPRINT1("Trying to write back page from physical memory mapped at %X "
2388 "process %d\n", Address
,
2389 Process
? Process
->UniqueProcessId
: 0);
2390 KeBugCheck(MEMORY_MANAGEMENT
);
2394 * Get the section segment entry and the physical address.
2396 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2397 if (!MmIsPagePresent(Process
, Address
))
2399 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2400 Process
? Process
->UniqueProcessId
: 0, Address
);
2401 KeBugCheck(MEMORY_MANAGEMENT
);
2403 Page
= MmGetPfnForProcess(Process
, Address
);
2404 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2407 * Check for a private (COWed) page.
2409 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2410 IS_SWAP_FROM_SSE(Entry
) ||
2411 PFN_FROM_SSE(Entry
) != Page
)
2421 * Speculatively set all mappings of the page to clean.
2423 MmSetCleanAllRmaps(Page
);
2426 * If this page was direct mapped from the cache then the cache manager
2427 * will take care of writing it back to disk.
2429 if (DirectMapped
&& !Private
)
2431 ASSERT(SwapEntry
== 0);
2432 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
2433 PageOp
->Status
= STATUS_SUCCESS
;
2434 MmspCompleteAndReleasePageOp(PageOp
);
2435 return(STATUS_SUCCESS
);
2439 * If necessary, allocate an entry in the paging file for this page
2443 SwapEntry
= MmAllocSwapPage();
2446 MmSetDirtyAllRmaps(Page
);
2447 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2448 MmspCompleteAndReleasePageOp(PageOp
);
2449 return(STATUS_PAGEFILE_QUOTA
);
2451 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2455 * Write the page to the pagefile
2457 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2458 if (!NT_SUCCESS(Status
))
2460 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2462 MmSetDirtyAllRmaps(Page
);
2463 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2464 MmspCompleteAndReleasePageOp(PageOp
);
2465 return(STATUS_UNSUCCESSFUL
);
2469 * Otherwise we have succeeded.
2471 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2472 PageOp
->Status
= STATUS_SUCCESS
;
2473 MmspCompleteAndReleasePageOp(PageOp
);
2474 return(STATUS_SUCCESS
);
2478 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2486 PMEMORY_AREA MemoryArea
;
2487 PMM_SECTION_SEGMENT Segment
;
2488 BOOLEAN DoCOW
= FALSE
;
2490 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2492 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2493 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2495 if ((Segment
->WriteCopy
) &&
2496 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2501 if (OldProtect
!= NewProtect
)
2503 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2505 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2506 ULONG Protect
= NewProtect
;
2509 * If we doing COW for this segment then check if the page is
2512 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2518 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2519 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2520 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2521 Page
= MmGetPfnForProcess(Process
, Address
);
2523 Protect
= PAGE_READONLY
;
2524 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2525 IS_SWAP_FROM_SSE(Entry
) ||
2526 PFN_FROM_SSE(Entry
) != Page
)
2528 Protect
= NewProtect
;
2532 if (MmIsPagePresent(Process
, Address
))
2534 MmSetPageProtect(Process
, Address
,
2543 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2544 PMEMORY_AREA MemoryArea
,
2552 ULONG_PTR MaxLength
;
2554 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2555 if (Length
> MaxLength
)
2558 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2559 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2561 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2562 Region
->Protect
!= Protect
)
2564 return STATUS_INVALID_PAGE_PROTECTION
;
2567 *OldProtect
= Region
->Protect
;
2568 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2569 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2570 BaseAddress
, Length
, Region
->Type
, Protect
,
2571 MmAlterViewAttributes
);
2577 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2579 PMEMORY_BASIC_INFORMATION Info
,
2580 PSIZE_T ResultLength
)
2583 PVOID RegionBaseAddress
;
2584 PROS_SECTION_OBJECT Section
;
2585 PMM_SECTION_SEGMENT Segment
;
2587 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2588 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2589 Address
, &RegionBaseAddress
);
2592 return STATUS_UNSUCCESSFUL
;
2595 Section
= MemoryArea
->Data
.SectionData
.Section
;
2596 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2598 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2599 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2600 Info
->Type
= MEM_IMAGE
;
2604 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2605 Info
->Type
= MEM_MAPPED
;
2607 Info
->BaseAddress
= RegionBaseAddress
;
2608 Info
->AllocationProtect
= MemoryArea
->Protect
;
2609 Info
->RegionSize
= Region
->Length
;
2610 Info
->State
= MEM_COMMIT
;
2611 Info
->Protect
= Region
->Protect
;
2613 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2614 return(STATUS_SUCCESS
);
2619 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2624 ULONG SavedSwapEntry
;
2629 Length
= PAGE_ROUND_UP(Segment
->Length
);
2630 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2632 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2635 if (IS_SWAP_FROM_SSE(Entry
))
2637 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2641 Page
= PFN_FROM_SSE(Entry
);
2642 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2643 if (SavedSwapEntry
!= 0)
2645 MmSetSavedSwapEntryPage(Page
, 0);
2646 MmFreeSwapPage(SavedSwapEntry
);
2648 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2650 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2656 MmpDeleteSection(PVOID ObjectBody
)
2658 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2660 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2661 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2666 PMM_SECTION_SEGMENT SectionSegments
;
2669 * NOTE: Section->ImageSection can be NULL for short time
2670 * during the section creating. If we fail for some reason
2671 * until the image section is properly initialized we shouldn't
2672 * process further here.
2674 if (Section
->ImageSection
== NULL
)
2677 SectionSegments
= Section
->ImageSection
->Segments
;
2678 NrSegments
= Section
->ImageSection
->NrSegments
;
2680 for (i
= 0; i
< NrSegments
; i
++)
2682 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2684 MmLockSectionSegment(&SectionSegments
[i
]);
2686 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2687 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2691 MmpFreePageFileSegment(&SectionSegments
[i
]);
2693 MmUnlockSectionSegment(&SectionSegments
[i
]);
2700 * NOTE: Section->Segment can be NULL for short time
2701 * during the section creating.
2703 if (Section
->Segment
== NULL
)
2706 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2708 MmpFreePageFileSegment(Section
->Segment
);
2709 MmFreePageTablesSectionSegment(Section
->Segment
);
2710 ExFreePool(Section
->Segment
);
2711 Section
->Segment
= NULL
;
2715 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2718 if (Section
->FileObject
!= NULL
)
2720 CcRosDereferenceCache(Section
->FileObject
);
2721 ObDereferenceObject(Section
->FileObject
);
2722 Section
->FileObject
= NULL
;
2727 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2729 IN ACCESS_MASK GrantedAccess
,
2730 IN ULONG ProcessHandleCount
,
2731 IN ULONG SystemHandleCount
)
2733 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2734 Object
, ProcessHandleCount
);
2740 MmCreatePhysicalMemorySection(VOID
)
2742 PROS_SECTION_OBJECT PhysSection
;
2744 OBJECT_ATTRIBUTES Obj
;
2745 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2746 LARGE_INTEGER SectionSize
;
2750 * Create the section mapping physical memory
2752 SectionSize
.QuadPart
= 0xFFFFFFFF;
2753 InitializeObjectAttributes(&Obj
,
2758 Status
= MmCreateSection((PVOID
)&PhysSection
,
2762 PAGE_EXECUTE_READWRITE
,
2766 if (!NT_SUCCESS(Status
))
2768 DPRINT1("Failed to create PhysicalMemory section\n");
2769 KeBugCheck(MEMORY_MANAGEMENT
);
2771 Status
= ObInsertObject(PhysSection
,
2777 if (!NT_SUCCESS(Status
))
2779 ObDereferenceObject(PhysSection
);
2781 ObCloseHandle(Handle
, KernelMode
);
2782 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2783 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2785 return(STATUS_SUCCESS
);
2791 MmInitSectionImplementation(VOID
)
2793 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2794 UNICODE_STRING Name
;
2796 DPRINT("Creating Section Object Type\n");
2798 /* Initialize the Section object type */
2799 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2800 RtlInitUnicodeString(&Name
, L
"Section");
2801 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2802 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2803 ObjectTypeInitializer
.PoolType
= PagedPool
;
2804 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2805 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2806 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2807 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2808 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2809 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2811 MmCreatePhysicalMemorySection();
2813 return(STATUS_SUCCESS
);
2818 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2819 ACCESS_MASK DesiredAccess
,
2820 POBJECT_ATTRIBUTES ObjectAttributes
,
2821 PLARGE_INTEGER UMaximumSize
,
2822 ULONG SectionPageProtection
,
2823 ULONG AllocationAttributes
)
2825 * Create a section which is backed by the pagefile
2828 LARGE_INTEGER MaximumSize
;
2829 PROS_SECTION_OBJECT Section
;
2830 PMM_SECTION_SEGMENT Segment
;
2833 if (UMaximumSize
== NULL
)
2835 return(STATUS_UNSUCCESSFUL
);
2837 MaximumSize
= *UMaximumSize
;
2840 * Create the section
2842 Status
= ObCreateObject(ExGetPreviousMode(),
2843 MmSectionObjectType
,
2845 ExGetPreviousMode(),
2847 sizeof(ROS_SECTION_OBJECT
),
2850 (PVOID
*)(PVOID
)&Section
);
2851 if (!NT_SUCCESS(Status
))
2859 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2860 Section
->SectionPageProtection
= SectionPageProtection
;
2861 Section
->AllocationAttributes
= AllocationAttributes
;
2862 Section
->MaximumSize
= MaximumSize
;
2863 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2864 TAG_MM_SECTION_SEGMENT
);
2865 if (Segment
== NULL
)
2867 ObDereferenceObject(Section
);
2868 return(STATUS_NO_MEMORY
);
2870 Section
->Segment
= Segment
;
2871 Segment
->ReferenceCount
= 1;
2872 ExInitializeFastMutex(&Segment
->Lock
);
2873 Segment
->FileOffset
= 0;
2874 Segment
->Protection
= SectionPageProtection
;
2875 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2876 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2877 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2878 Segment
->WriteCopy
= FALSE
;
2879 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2880 Segment
->VirtualAddress
= 0;
2881 Segment
->Characteristics
= 0;
2882 *SectionObject
= Section
;
2883 return(STATUS_SUCCESS
);
2889 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2890 ACCESS_MASK DesiredAccess
,
2891 POBJECT_ATTRIBUTES ObjectAttributes
,
2892 PLARGE_INTEGER UMaximumSize
,
2893 ULONG SectionPageProtection
,
2894 ULONG AllocationAttributes
,
2897 * Create a section backed by a data file
2900 PROS_SECTION_OBJECT Section
;
2902 LARGE_INTEGER MaximumSize
;
2903 PFILE_OBJECT FileObject
;
2904 PMM_SECTION_SEGMENT Segment
;
2906 IO_STATUS_BLOCK Iosb
;
2907 LARGE_INTEGER Offset
;
2909 FILE_STANDARD_INFORMATION FileInfo
;
2913 * Create the section
2915 Status
= ObCreateObject(ExGetPreviousMode(),
2916 MmSectionObjectType
,
2918 ExGetPreviousMode(),
2920 sizeof(ROS_SECTION_OBJECT
),
2923 (PVOID
*)(PVOID
)&Section
);
2924 if (!NT_SUCCESS(Status
))
2931 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2932 Section
->SectionPageProtection
= SectionPageProtection
;
2933 Section
->AllocationAttributes
= AllocationAttributes
;
2936 * Check file access required
2938 if (SectionPageProtection
& PAGE_READWRITE
||
2939 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2941 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2945 FileAccess
= FILE_READ_DATA
;
2949 * Reference the file handle
2951 Status
= ObReferenceObjectByHandle(FileHandle
,
2954 ExGetPreviousMode(),
2955 (PVOID
*)(PVOID
)&FileObject
,
2957 if (!NT_SUCCESS(Status
))
2959 ObDereferenceObject(Section
);
2964 * FIXME: This is propably not entirely correct. We can't look into
2965 * the standard FCB header because it might not be initialized yet
2966 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2967 * standard file information is filled on first request).
2969 Status
= IoQueryFileInformation(FileObject
,
2970 FileStandardInformation
,
2971 sizeof(FILE_STANDARD_INFORMATION
),
2974 Iosb
.Information
= Length
;
2975 if (!NT_SUCCESS(Status
))
2977 ObDereferenceObject(Section
);
2978 ObDereferenceObject(FileObject
);
2983 * FIXME: Revise this once a locking order for file size changes is
2986 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2988 MaximumSize
= *UMaximumSize
;
2992 MaximumSize
= FileInfo
.EndOfFile
;
2993 /* Mapping zero-sized files isn't allowed. */
2994 if (MaximumSize
.QuadPart
== 0)
2996 ObDereferenceObject(Section
);
2997 ObDereferenceObject(FileObject
);
2998 return STATUS_FILE_INVALID
;
3002 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3004 Status
= IoSetInformation(FileObject
,
3005 FileAllocationInformation
,
3006 sizeof(LARGE_INTEGER
),
3008 if (!NT_SUCCESS(Status
))
3010 ObDereferenceObject(Section
);
3011 ObDereferenceObject(FileObject
);
3012 return(STATUS_SECTION_NOT_EXTENDED
);
3016 if (FileObject
->SectionObjectPointer
== NULL
||
3017 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3020 * Read a bit so caching is initiated for the file object.
3021 * This is only needed because MiReadPage currently cannot
3022 * handle non-cached streams.
3024 Offset
.QuadPart
= 0;
3025 Status
= ZwReadFile(FileHandle
,
3034 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3036 ObDereferenceObject(Section
);
3037 ObDereferenceObject(FileObject
);
3040 if (FileObject
->SectionObjectPointer
== NULL
||
3041 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3043 /* FIXME: handle this situation */
3044 ObDereferenceObject(Section
);
3045 ObDereferenceObject(FileObject
);
3046 return STATUS_INVALID_PARAMETER
;
3053 Status
= MmspWaitForFileLock(FileObject
);
3054 if (Status
!= STATUS_SUCCESS
)
3056 ObDereferenceObject(Section
);
3057 ObDereferenceObject(FileObject
);
3062 * If this file hasn't been mapped as a data file before then allocate a
3063 * section segment to describe the data file mapping
3065 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3067 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3068 TAG_MM_SECTION_SEGMENT
);
3069 if (Segment
== NULL
)
3071 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3072 ObDereferenceObject(Section
);
3073 ObDereferenceObject(FileObject
);
3074 return(STATUS_NO_MEMORY
);
3076 Section
->Segment
= Segment
;
3077 Segment
->ReferenceCount
= 1;
3078 ExInitializeFastMutex(&Segment
->Lock
);
3080 * Set the lock before assigning the segment to the file object
3082 ExAcquireFastMutex(&Segment
->Lock
);
3083 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3085 Segment
->FileOffset
= 0;
3086 Segment
->Protection
= SectionPageProtection
;
3087 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3088 Segment
->Characteristics
= 0;
3089 Segment
->WriteCopy
= FALSE
;
3090 if (AllocationAttributes
& SEC_RESERVE
)
3092 Segment
->Length
= Segment
->RawLength
= 0;
3096 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3097 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3099 Segment
->VirtualAddress
= 0;
3100 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
3105 * If the file is already mapped as a data file then we may need
3109 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3111 Section
->Segment
= Segment
;
3112 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3113 MmLockSectionSegment(Segment
);
3115 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
3116 !(AllocationAttributes
& SEC_RESERVE
))
3118 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3119 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3122 MmUnlockSectionSegment(Segment
);
3123 Section
->FileObject
= FileObject
;
3124 Section
->MaximumSize
= MaximumSize
;
3125 CcRosReferenceCache(FileObject
);
3126 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3127 *SectionObject
= Section
;
3128 return(STATUS_SUCCESS
);
3132 TODO: not that great (declaring loaders statically, having to declare all of
3133 them, having to keep them extern, etc.), will fix in the future
3135 extern NTSTATUS NTAPI PeFmtCreateSection
3137 IN CONST VOID
* FileHeader
,
3138 IN SIZE_T FileHeaderSize
,
3140 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3142 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3143 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3146 extern NTSTATUS NTAPI ElfFmtCreateSection
3148 IN CONST VOID
* FileHeader
,
3149 IN SIZE_T FileHeaderSize
,
3151 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3153 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3154 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3157 /* TODO: this is a standard DDK/PSDK macro */
3158 #ifndef RTL_NUMBER_OF
3159 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3162 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3173 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3175 SIZE_T SizeOfSegments
;
3176 PMM_SECTION_SEGMENT Segments
;
3178 /* TODO: check for integer overflow */
3179 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3181 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3183 TAG_MM_SECTION_SEGMENT
);
3186 RtlZeroMemory(Segments
, SizeOfSegments
);
3194 ExeFmtpReadFile(IN PVOID File
,
3195 IN PLARGE_INTEGER Offset
,
3198 OUT PVOID
* AllocBase
,
3199 OUT PULONG ReadSize
)
3202 LARGE_INTEGER FileOffset
;
3204 ULONG OffsetAdjustment
;
3209 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3213 KeBugCheck(MEMORY_MANAGEMENT
);
3216 FileOffset
= *Offset
;
3218 /* Negative/special offset: it cannot be used in this context */
3219 if(FileOffset
.u
.HighPart
< 0)
3221 KeBugCheck(MEMORY_MANAGEMENT
);
3224 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3225 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3226 FileOffset
.u
.LowPart
= AdjustOffset
;
3228 BufferSize
= Length
+ OffsetAdjustment
;
3229 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3232 * It's ok to use paged pool, because this is a temporary buffer only used in
3233 * the loading of executables. The assumption is that MmCreateSection is
3234 * always called at low IRQLs and that these buffers don't survive a brief
3235 * initialization phase
3237 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3242 KeBugCheck(MEMORY_MANAGEMENT
);
3248 Status
= MmspPageRead(File
,
3255 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
3256 * nothing will work. But using ZwReadFile is wrong, and using its side effects
3257 * to initialize internal state is even worse. Our cache manager is in need of
3261 IO_STATUS_BLOCK Iosb
;
3263 Status
= ZwReadFile(File
,
3273 if(NT_SUCCESS(Status
))
3275 UsedSize
= Iosb
.Information
;
3280 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3282 Status
= STATUS_IN_PAGE_ERROR
;
3283 ASSERT(!NT_SUCCESS(Status
));
3286 if(NT_SUCCESS(Status
))
3288 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3289 *AllocBase
= Buffer
;
3290 *ReadSize
= UsedSize
- OffsetAdjustment
;
3294 ExFreePoolWithTag(Buffer
, 'rXmM');
3301 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3302 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3303 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3308 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3312 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3314 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3315 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
3322 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3326 MmspAssertSegmentsSorted(ImageSectionObject
);
3328 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3330 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
3334 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3335 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3336 ImageSectionObject
->Segments
[i
- 1].Length
));
3344 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3348 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3350 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
3351 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
3359 MmspCompareSegments(const void * x
,
3362 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3363 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3366 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
3367 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3371 * Ensures an image section's segments are sorted in memory
3376 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3379 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3381 MmspAssertSegmentsSorted(ImageSectionObject
);
3385 qsort(ImageSectionObject
->Segments
,
3386 ImageSectionObject
->NrSegments
,
3387 sizeof(ImageSectionObject
->Segments
[0]),
3388 MmspCompareSegments
);
3394 * Ensures an image section's segments don't overlap in memory and don't have
3395 * gaps and don't have a null size. We let them map to overlapping file regions,
3396 * though - that's not necessarily an error
3401 MmspCheckSegmentBounds
3403 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3409 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3411 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3415 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3417 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3419 if(ImageSectionObject
->Segments
[i
].Length
== 0)
3427 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3428 * page could be OK (Windows seems to be OK with them), and larger gaps
3429 * could lead to image sections spanning several discontiguous regions
3430 * (NtMapViewOfSection could then refuse to map them, and they could
3431 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3433 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3434 ImageSectionObject
->Segments
[i
- 1].Length
) !=
3435 ImageSectionObject
->Segments
[i
].VirtualAddress
)
3446 * Merges and pads an image section's segments until they all are page-aligned
3447 * and have a size that is a multiple of the page size
3452 MmspPageAlignSegments
3454 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3460 PMM_SECTION_SEGMENT EffectiveSegment
;
3462 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3464 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3469 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3471 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3474 * The first segment requires special handling
3478 ULONG_PTR VirtualAddress
;
3479 ULONG_PTR VirtualOffset
;
3481 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3483 /* Round down the virtual address to the nearest page */
3484 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3486 /* Round up the virtual size to the nearest page */
3487 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3488 EffectiveSegment
->VirtualAddress
;
3490 /* Adjust the raw address and size */
3491 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3493 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3499 * Garbage in, garbage out: unaligned base addresses make the file
3500 * offset point in curious and odd places, but that's what we were
3503 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3504 EffectiveSegment
->RawLength
+= VirtualOffset
;
3508 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3509 ULONG_PTR EndOfEffectiveSegment
;
3511 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3512 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3515 * The current segment begins exactly where the current effective
3516 * segment ended, therefore beginning a new effective segment
3518 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3521 ASSERT(LastSegment
<= i
);
3522 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3524 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3526 if (LastSegment
!= i
)
3529 * Copy the current segment. If necessary, the effective segment
3530 * will be expanded later
3532 *EffectiveSegment
= *Segment
;
3536 * Page-align the virtual size. We know for sure the virtual address
3539 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3540 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3543 * The current segment is still part of the current effective segment:
3544 * extend the effective segment to reflect this
3546 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3548 static const ULONG FlagsToProtection
[16] =
3556 PAGE_EXECUTE_READWRITE
,
3557 PAGE_EXECUTE_READWRITE
,
3562 PAGE_EXECUTE_WRITECOPY
,
3563 PAGE_EXECUTE_WRITECOPY
,
3564 PAGE_EXECUTE_WRITECOPY
,
3565 PAGE_EXECUTE_WRITECOPY
3568 unsigned ProtectionFlags
;
3571 * Extend the file size
3574 /* Unaligned segments must be contiguous within the file */
3575 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3576 EffectiveSegment
->RawLength
))
3581 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3584 * Extend the virtual size
3586 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3588 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3589 EffectiveSegment
->VirtualAddress
;
3592 * Merge the protection
3594 EffectiveSegment
->Protection
|= Segment
->Protection
;
3596 /* Clean up redundance */
3597 ProtectionFlags
= 0;
3599 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3600 ProtectionFlags
|= 1 << 0;
3602 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3603 ProtectionFlags
|= 1 << 1;
3605 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3606 ProtectionFlags
|= 1 << 2;
3608 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3609 ProtectionFlags
|= 1 << 3;
3611 ASSERT(ProtectionFlags
< 16);
3612 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3614 /* If a segment was required to be shared and cannot, fail */
3615 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3616 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3622 * We assume no holes between segments at this point
3626 KeBugCheck(MEMORY_MANAGEMENT
);
3630 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3636 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3637 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3639 LARGE_INTEGER Offset
;
3641 PVOID FileHeaderBuffer
;
3642 ULONG FileHeaderSize
;
3644 ULONG OldNrSegments
;
3649 * Read the beginning of the file (2 pages). Should be enough to contain
3650 * all (or most) of the headers
3652 Offset
.QuadPart
= 0;
3654 /* FIXME: use FileObject instead of FileHandle */
3655 Status
= ExeFmtpReadFile (FileHandle
,
3662 if (!NT_SUCCESS(Status
))
3665 if (FileHeaderSize
== 0)
3667 ExFreePool(FileHeaderBuffer
);
3668 return STATUS_UNSUCCESSFUL
;
3672 * Look for a loader that can handle this executable
3674 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3676 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3679 /* FIXME: use FileObject instead of FileHandle */
3680 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3686 ExeFmtpAllocateSegments
);
3688 if (!NT_SUCCESS(Status
))
3690 if (ImageSectionObject
->Segments
)
3692 ExFreePool(ImageSectionObject
->Segments
);
3693 ImageSectionObject
->Segments
= NULL
;
3697 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3701 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3704 * No loader handled the format
3706 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3708 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3709 ASSERT(!NT_SUCCESS(Status
));
3712 if (!NT_SUCCESS(Status
))
3715 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3720 /* FIXME? are these values platform-dependent? */
3721 if(ImageSectionObject
->StackReserve
== 0)
3722 ImageSectionObject
->StackReserve
= 0x40000;
3724 if(ImageSectionObject
->StackCommit
== 0)
3725 ImageSectionObject
->StackCommit
= 0x1000;
3727 if(ImageSectionObject
->ImageBase
== 0)
3729 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3730 ImageSectionObject
->ImageBase
= 0x10000000;
3732 ImageSectionObject
->ImageBase
= 0x00400000;
3736 * And now the fun part: fixing the segments
3739 /* Sort them by virtual address */
3740 MmspSortSegments(ImageSectionObject
, Flags
);
3742 /* Ensure they don't overlap in memory */
3743 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3744 return STATUS_INVALID_IMAGE_FORMAT
;
3746 /* Ensure they are aligned */
3747 OldNrSegments
= ImageSectionObject
->NrSegments
;
3749 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3750 return STATUS_INVALID_IMAGE_FORMAT
;
3752 /* Trim them if the alignment phase merged some of them */
3753 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3755 PMM_SECTION_SEGMENT Segments
;
3756 SIZE_T SizeOfSegments
;
3758 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3760 Segments
= ExAllocatePoolWithTag(PagedPool
,
3762 TAG_MM_SECTION_SEGMENT
);
3764 if (Segments
== NULL
)
3765 return STATUS_INSUFFICIENT_RESOURCES
;
3767 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3768 ExFreePool(ImageSectionObject
->Segments
);
3769 ImageSectionObject
->Segments
= Segments
;
3772 /* And finish their initialization */
3773 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3775 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3776 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3778 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3779 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3782 ASSERT(NT_SUCCESS(Status
));
3787 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3788 ACCESS_MASK DesiredAccess
,
3789 POBJECT_ATTRIBUTES ObjectAttributes
,
3790 PLARGE_INTEGER UMaximumSize
,
3791 ULONG SectionPageProtection
,
3792 ULONG AllocationAttributes
,
3795 PROS_SECTION_OBJECT Section
;
3797 PFILE_OBJECT FileObject
;
3798 PMM_SECTION_SEGMENT SectionSegments
;
3799 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3801 ULONG FileAccess
= 0;
3804 * Check file access required
3806 if (SectionPageProtection
& PAGE_READWRITE
||
3807 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3809 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3813 FileAccess
= FILE_READ_DATA
;
3817 * Reference the file handle
3819 Status
= ObReferenceObjectByHandle(FileHandle
,
3822 ExGetPreviousMode(),
3823 (PVOID
*)(PVOID
)&FileObject
,
3826 if (!NT_SUCCESS(Status
))
3832 * Create the section
3834 Status
= ObCreateObject (ExGetPreviousMode(),
3835 MmSectionObjectType
,
3837 ExGetPreviousMode(),
3839 sizeof(ROS_SECTION_OBJECT
),
3842 (PVOID
*)(PVOID
)&Section
);
3843 if (!NT_SUCCESS(Status
))
3845 ObDereferenceObject(FileObject
);
3852 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3853 Section
->SectionPageProtection
= SectionPageProtection
;
3854 Section
->AllocationAttributes
= AllocationAttributes
;
3857 * Initialized caching for this file object if previously caching
3858 * was initialized for the same on disk file
3860 Status
= CcTryToInitializeFileCache(FileObject
);
3862 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3864 NTSTATUS StatusExeFmt
;
3866 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3867 if (ImageSectionObject
== NULL
)
3869 ObDereferenceObject(FileObject
);
3870 ObDereferenceObject(Section
);
3871 return(STATUS_NO_MEMORY
);
3874 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3876 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3878 if (!NT_SUCCESS(StatusExeFmt
))
3880 if(ImageSectionObject
->Segments
!= NULL
)
3881 ExFreePool(ImageSectionObject
->Segments
);
3883 ExFreePool(ImageSectionObject
);
3884 ObDereferenceObject(Section
);
3885 ObDereferenceObject(FileObject
);
3886 return(StatusExeFmt
);
3889 Section
->ImageSection
= ImageSectionObject
;
3890 ASSERT(ImageSectionObject
->Segments
);
3895 Status
= MmspWaitForFileLock(FileObject
);
3896 if (!NT_SUCCESS(Status
))
3898 ExFreePool(ImageSectionObject
->Segments
);
3899 ExFreePool(ImageSectionObject
);
3900 ObDereferenceObject(Section
);
3901 ObDereferenceObject(FileObject
);
3905 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3906 ImageSectionObject
, NULL
))
3909 * An other thread has initialized the same image in the background
3911 ExFreePool(ImageSectionObject
->Segments
);
3912 ExFreePool(ImageSectionObject
);
3913 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3914 Section
->ImageSection
= ImageSectionObject
;
3915 SectionSegments
= ImageSectionObject
->Segments
;
3917 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3919 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3923 Status
= StatusExeFmt
;
3930 Status
= MmspWaitForFileLock(FileObject
);
3931 if (Status
!= STATUS_SUCCESS
)
3933 ObDereferenceObject(Section
);
3934 ObDereferenceObject(FileObject
);
3938 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3939 Section
->ImageSection
= ImageSectionObject
;
3940 SectionSegments
= ImageSectionObject
->Segments
;
3943 * Otherwise just reference all the section segments
3945 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3947 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3950 Status
= STATUS_SUCCESS
;
3952 Section
->FileObject
= FileObject
;
3953 CcRosReferenceCache(FileObject
);
3954 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3955 *SectionObject
= Section
;
3962 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3963 PROS_SECTION_OBJECT Section
,
3964 PMM_SECTION_SEGMENT Segment
,
3969 ULONG AllocationType
)
3973 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3975 BoundaryAddressMultiple
.QuadPart
= 0;
3977 Status
= MmCreateMemoryArea(AddressSpace
,
3978 MEMORY_AREA_SECTION_VIEW
,
3985 BoundaryAddressMultiple
);
3986 if (!NT_SUCCESS(Status
))
3988 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3989 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3993 ObReferenceObject((PVOID
)Section
);
3995 MArea
->Data
.SectionData
.Segment
= Segment
;
3996 MArea
->Data
.SectionData
.Section
= Section
;
3997 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3998 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3999 ViewSize
, 0, Protect
);
4001 return(STATUS_SUCCESS
);
4007 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
4008 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4011 PFILE_OBJECT FileObject
;
4014 SWAPENTRY SavedSwapEntry
;
4017 PROS_SECTION_OBJECT Section
;
4018 PMM_SECTION_SEGMENT Segment
;
4019 PMMSUPPORT AddressSpace
;
4022 AddressSpace
= (PMMSUPPORT
)Context
;
4023 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4025 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4027 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
4028 MemoryArea
->Data
.SectionData
.ViewOffset
;
4030 Section
= MemoryArea
->Data
.SectionData
.Section
;
4031 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4033 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4037 MmUnlockSectionSegment(Segment
);
4038 MmUnlockAddressSpace(AddressSpace
);
4040 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4041 if (Status
!= STATUS_SUCCESS
)
4043 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4044 KeBugCheck(MEMORY_MANAGEMENT
);
4047 MmLockAddressSpace(AddressSpace
);
4048 MmLockSectionSegment(Segment
);
4049 MmspCompleteAndReleasePageOp(PageOp
);
4050 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4053 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
4056 * For a dirty, datafile, non-private page mark it as dirty in the
4059 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4061 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4063 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4064 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4065 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
4066 ASSERT(SwapEntry
== 0);
4075 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4077 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4078 KeBugCheck(MEMORY_MANAGEMENT
);
4080 MmFreeSwapPage(SwapEntry
);
4084 if (IS_SWAP_FROM_SSE(Entry
) ||
4085 Page
!= PFN_FROM_SSE(Entry
))
4090 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4092 DPRINT1("Found a private page in a pagefile section.\n");
4093 KeBugCheck(MEMORY_MANAGEMENT
);
4096 * Just dereference private pages
4098 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4099 if (SavedSwapEntry
!= 0)
4101 MmFreeSwapPage(SavedSwapEntry
);
4102 MmSetSavedSwapEntryPage(Page
, 0);
4104 MmDeleteRmap(Page
, Process
, Address
);
4105 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4109 MmDeleteRmap(Page
, Process
, Address
);
4110 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4116 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4120 PMEMORY_AREA MemoryArea
;
4121 PROS_SECTION_OBJECT Section
;
4122 PMM_SECTION_SEGMENT Segment
;
4123 PLIST_ENTRY CurrentEntry
;
4124 PMM_REGION CurrentRegion
;
4125 PLIST_ENTRY RegionListHead
;
4127 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4129 if (MemoryArea
== NULL
)
4131 return(STATUS_UNSUCCESSFUL
);
4134 MemoryArea
->DeleteInProgress
= TRUE
;
4135 Section
= MemoryArea
->Data
.SectionData
.Section
;
4136 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4138 MmLockSectionSegment(Segment
);
4140 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4141 while (!IsListEmpty(RegionListHead
))
4143 CurrentEntry
= RemoveHeadList(RegionListHead
);
4144 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4145 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4148 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4150 Status
= MmFreeMemoryArea(AddressSpace
,
4157 Status
= MmFreeMemoryArea(AddressSpace
,
4162 MmUnlockSectionSegment(Segment
);
4163 ObDereferenceObject(Section
);
4171 MmUnmapViewOfSection(PEPROCESS Process
,
4175 PMEMORY_AREA MemoryArea
;
4176 PMMSUPPORT AddressSpace
;
4177 PROS_SECTION_OBJECT Section
;
4180 PVOID ImageBaseAddress
= 0;
4182 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4183 Process
, BaseAddress
);
4187 AddressSpace
= &Process
->Vm
;
4189 MmLockAddressSpace(AddressSpace
);
4190 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4192 if (MemoryArea
== NULL
||
4193 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4194 MemoryArea
->DeleteInProgress
)
4196 MmUnlockAddressSpace(AddressSpace
);
4197 return STATUS_NOT_MAPPED_VIEW
;
4200 MemoryArea
->DeleteInProgress
= TRUE
;
4202 while (MemoryArea
->PageOpCount
)
4204 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4208 Offset
-= PAGE_SIZE
;
4209 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4210 MemoryArea
->Data
.SectionData
.Segment
,
4211 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4214 MmUnlockAddressSpace(AddressSpace
);
4215 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4216 if (Status
!= STATUS_SUCCESS
)
4218 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4219 KeBugCheck(MEMORY_MANAGEMENT
);
4221 MmLockAddressSpace(AddressSpace
);
4222 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4224 if (MemoryArea
== NULL
||
4225 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4227 MmUnlockAddressSpace(AddressSpace
);
4228 return STATUS_NOT_MAPPED_VIEW
;
4235 Section
= MemoryArea
->Data
.SectionData
.Section
;
4237 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4241 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4242 PMM_SECTION_SEGMENT SectionSegments
;
4243 PMM_SECTION_SEGMENT Segment
;
4245 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4246 ImageSectionObject
= Section
->ImageSection
;
4247 SectionSegments
= ImageSectionObject
->Segments
;
4248 NrSegments
= ImageSectionObject
->NrSegments
;
4250 /* Search for the current segment within the section segments
4251 * and calculate the image base address */
4252 for (i
= 0; i
< NrSegments
; i
++)
4254 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4256 if (Segment
== &SectionSegments
[i
])
4258 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4263 if (i
>= NrSegments
)
4265 KeBugCheck(MEMORY_MANAGEMENT
);
4268 for (i
= 0; i
< NrSegments
; i
++)
4270 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4272 PVOID SBaseAddress
= (PVOID
)
4273 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4275 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4281 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4284 MmUnlockAddressSpace(AddressSpace
);
4286 /* Notify debugger */
4287 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4289 return(STATUS_SUCCESS
);
4296 * Queries the information of a section object.
4298 * @param SectionHandle
4299 * Handle to the section object. It must be opened with SECTION_QUERY
4301 * @param SectionInformationClass
4302 * Index to a certain information structure. Can be either
4303 * SectionBasicInformation or SectionImageInformation. The latter
4304 * is valid only for sections that were created with the SEC_IMAGE
4306 * @param SectionInformation
4307 * Caller supplies storage for resulting information.
4309 * Size of the supplied storage.
4310 * @param ResultLength
4318 NtQuerySection(IN HANDLE SectionHandle
,
4319 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4320 OUT PVOID SectionInformation
,
4321 IN SIZE_T SectionInformationLength
,
4322 OUT PSIZE_T ResultLength OPTIONAL
)
4324 PROS_SECTION_OBJECT Section
;
4325 KPROCESSOR_MODE PreviousMode
;
4329 PreviousMode
= ExGetPreviousMode();
4331 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4333 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4335 SectionInformationLength
,
4340 if(!NT_SUCCESS(Status
))
4342 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4346 Status
= ObReferenceObjectByHandle(SectionHandle
,
4348 MmSectionObjectType
,
4350 (PVOID
*)(PVOID
)&Section
,
4352 if (NT_SUCCESS(Status
))
4354 switch (SectionInformationClass
)
4356 case SectionBasicInformation
:
4358 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4362 Sbi
->Attributes
= Section
->AllocationAttributes
;
4363 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4365 Sbi
->BaseAddress
= 0;
4366 Sbi
->Size
.QuadPart
= 0;
4370 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4371 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4374 if (ResultLength
!= NULL
)
4376 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4378 Status
= STATUS_SUCCESS
;
4380 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4382 Status
= _SEH2_GetExceptionCode();
4389 case SectionImageInformation
:
4391 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4395 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4396 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4398 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4399 ImageSectionObject
= Section
->ImageSection
;
4401 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4402 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4403 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4404 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4405 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4406 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4407 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4408 Sii
->Machine
= ImageSectionObject
->Machine
;
4409 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4412 if (ResultLength
!= NULL
)
4414 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4416 Status
= STATUS_SUCCESS
;
4418 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4420 Status
= _SEH2_GetExceptionCode();
4428 ObDereferenceObject(Section
);
4434 /**********************************************************************
4436 * MmMapViewOfSection
4439 * Maps a view of a section into the virtual address space of a
4444 * Pointer to the section object.
4447 * Pointer to the process.
4450 * Desired base address (or NULL) on entry;
4451 * Actual base address of the view on exit.
4454 * Number of high order address bits that must be zero.
4457 * Size in bytes of the initially committed section of
4461 * Offset in bytes from the beginning of the section
4462 * to the beginning of the view.
4465 * Desired length of map (or zero to map all) on entry
4466 * Actual length mapped on exit.
4468 * InheritDisposition
4469 * Specified how the view is to be shared with
4473 * Type of allocation for the pages.
4476 * Protection for the committed region of the view.
4484 MmMapViewOfSection(IN PVOID SectionObject
,
4485 IN PEPROCESS Process
,
4486 IN OUT PVOID
*BaseAddress
,
4487 IN ULONG_PTR ZeroBits
,
4488 IN SIZE_T CommitSize
,
4489 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4490 IN OUT PSIZE_T ViewSize
,
4491 IN SECTION_INHERIT InheritDisposition
,
4492 IN ULONG AllocationType
,
4495 PROS_SECTION_OBJECT Section
;
4496 PMMSUPPORT AddressSpace
;
4498 NTSTATUS Status
= STATUS_SUCCESS
;
4500 if ((ULONG_PTR
)SectionObject
& 1)
4502 return MmMapViewOfArm3Section((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4516 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4518 return STATUS_INVALID_PAGE_PROTECTION
;
4522 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4523 AddressSpace
= &Process
->Vm
;
4525 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4527 MmLockAddressSpace(AddressSpace
);
4529 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4533 ULONG_PTR ImageBase
;
4535 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4536 PMM_SECTION_SEGMENT SectionSegments
;
4538 ImageSectionObject
= Section
->ImageSection
;
4539 SectionSegments
= ImageSectionObject
->Segments
;
4540 NrSegments
= ImageSectionObject
->NrSegments
;
4543 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4546 ImageBase
= ImageSectionObject
->ImageBase
;
4550 for (i
= 0; i
< NrSegments
; i
++)
4552 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4554 ULONG_PTR MaxExtent
;
4555 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4556 SectionSegments
[i
].Length
;
4557 ImageSize
= max(ImageSize
, MaxExtent
);
4561 ImageSectionObject
->ImageSize
= ImageSize
;
4563 /* Check there is enough space to map the section at that point. */
4564 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4565 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4567 /* Fail if the user requested a fixed base address. */
4568 if ((*BaseAddress
) != NULL
)
4570 MmUnlockAddressSpace(AddressSpace
);
4571 return(STATUS_UNSUCCESSFUL
);
4573 /* Otherwise find a gap to map the image. */
4574 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4577 MmUnlockAddressSpace(AddressSpace
);
4578 return(STATUS_UNSUCCESSFUL
);
4582 for (i
= 0; i
< NrSegments
; i
++)
4584 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4586 PVOID SBaseAddress
= (PVOID
)
4587 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4588 MmLockSectionSegment(&SectionSegments
[i
]);
4589 Status
= MmMapViewOfSegment(AddressSpace
,
4591 &SectionSegments
[i
],
4593 SectionSegments
[i
].Length
,
4594 SectionSegments
[i
].Protection
,
4597 MmUnlockSectionSegment(&SectionSegments
[i
]);
4598 if (!NT_SUCCESS(Status
))
4600 MmUnlockAddressSpace(AddressSpace
);
4606 *BaseAddress
= (PVOID
)ImageBase
;
4610 /* check for write access */
4611 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4612 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4614 MmUnlockAddressSpace(AddressSpace
);
4615 return STATUS_SECTION_PROTECTION
;
4617 /* check for read access */
4618 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4619 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4621 MmUnlockAddressSpace(AddressSpace
);
4622 return STATUS_SECTION_PROTECTION
;
4624 /* check for execute access */
4625 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4626 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4628 MmUnlockAddressSpace(AddressSpace
);
4629 return STATUS_SECTION_PROTECTION
;
4632 if (ViewSize
== NULL
)
4634 /* Following this pointer would lead to us to the dark side */
4635 /* What to do? Bugcheck? Return status? Do the mambo? */
4636 KeBugCheck(MEMORY_MANAGEMENT
);
4639 if (SectionOffset
== NULL
)
4645 ViewOffset
= SectionOffset
->u
.LowPart
;
4648 if ((ViewOffset
% PAGE_SIZE
) != 0)
4650 MmUnlockAddressSpace(AddressSpace
);
4651 return(STATUS_MAPPED_ALIGNMENT
);
4654 if ((*ViewSize
) == 0)
4656 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4658 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4660 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4663 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4665 MmLockSectionSegment(Section
->Segment
);
4666 Status
= MmMapViewOfSegment(AddressSpace
,
4673 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4674 MmUnlockSectionSegment(Section
->Segment
);
4675 if (!NT_SUCCESS(Status
))
4677 MmUnlockAddressSpace(AddressSpace
);
4682 MmUnlockAddressSpace(AddressSpace
);
4684 return(STATUS_SUCCESS
);
4691 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4692 IN PLARGE_INTEGER NewFileSize
)
4694 /* Check whether an ImageSectionObject exists */
4695 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4697 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4701 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4703 PMM_SECTION_SEGMENT Segment
;
4705 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4708 if (Segment
->ReferenceCount
!= 0)
4710 /* Check size of file */
4711 if (SectionObjectPointer
->SharedCacheMap
)
4713 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4714 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4722 /* Something must gone wrong
4723 * how can we have a Section but no
4725 DPRINT("ERROR: DataSectionObject without reference!\n");
4729 DPRINT("FIXME: didn't check for outstanding write probes\n");
4741 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4742 IN MMFLUSH_TYPE FlushType
)
4746 case MmFlushForDelete
:
4747 if (SectionObjectPointer
->ImageSectionObject
||
4748 SectionObjectPointer
->DataSectionObject
)
4752 CcRosSetRemoveOnClose(SectionObjectPointer
);
4754 case MmFlushForWrite
:
4764 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4765 OUT PVOID
* MappedBase
,
4766 IN OUT PSIZE_T ViewSize
)
4768 PROS_SECTION_OBJECT Section
;
4769 PMMSUPPORT AddressSpace
;
4773 if ((ULONG_PTR
)SectionObject
& 1)
4775 extern PVOID MmSession
;
4776 return MiMapViewInSystemSpace((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4782 DPRINT("MmMapViewInSystemSpace() called\n");
4784 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4785 AddressSpace
= MmGetKernelAddressSpace();
4787 MmLockAddressSpace(AddressSpace
);
4790 if ((*ViewSize
) == 0)
4792 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4794 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4796 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4799 MmLockSectionSegment(Section
->Segment
);
4802 Status
= MmMapViewOfSegment(AddressSpace
,
4811 MmUnlockSectionSegment(Section
->Segment
);
4812 MmUnlockAddressSpace(AddressSpace
);
4821 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4823 PMMSUPPORT AddressSpace
;
4826 DPRINT("MmUnmapViewInSystemSpace() called\n");
4828 AddressSpace
= MmGetKernelAddressSpace();
4830 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4836 /**********************************************************************
4841 * Creates a section object.
4844 * SectionObject (OUT)
4845 * Caller supplied storage for the resulting pointer
4846 * to a SECTION_OBJECT instance;
4849 * Specifies the desired access to the section can be a
4851 * STANDARD_RIGHTS_REQUIRED |
4853 * SECTION_MAP_WRITE |
4854 * SECTION_MAP_READ |
4855 * SECTION_MAP_EXECUTE
4857 * ObjectAttributes [OPTIONAL]
4858 * Initialized attributes for the object can be used
4859 * to create a named section;
4862 * Maximizes the size of the memory section. Must be
4863 * non-NULL for a page-file backed section.
4864 * If value specified for a mapped file and the file is
4865 * not large enough, file will be extended.
4867 * SectionPageProtection
4868 * Can be a combination of:
4874 * AllocationAttributes
4875 * Can be a combination of:
4880 * Handle to a file to create a section mapped to a file
4881 * instead of a memory backed section;
4892 MmCreateSection (OUT PVOID
* Section
,
4893 IN ACCESS_MASK DesiredAccess
,
4894 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4895 IN PLARGE_INTEGER MaximumSize
,
4896 IN ULONG SectionPageProtection
,
4897 IN ULONG AllocationAttributes
,
4898 IN HANDLE FileHandle OPTIONAL
,
4899 IN PFILE_OBJECT File OPTIONAL
)
4902 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4904 /* Check if an ARM3 section is being created instead */
4905 if (AllocationAttributes
& 1)
4907 DPRINT1("arm 3 path\n");
4908 return MmCreateArm3Section(Section
,
4912 SectionPageProtection
,
4913 AllocationAttributes
&~ 1,
4919 * Check the protection
4921 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4922 if (Protection
!= PAGE_READONLY
&&
4923 Protection
!= PAGE_READWRITE
&&
4924 Protection
!= PAGE_WRITECOPY
&&
4925 Protection
!= PAGE_EXECUTE
&&
4926 Protection
!= PAGE_EXECUTE_READ
&&
4927 Protection
!= PAGE_EXECUTE_READWRITE
&&
4928 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4930 return STATUS_INVALID_PAGE_PROTECTION
;
4933 if (AllocationAttributes
& SEC_IMAGE
)
4935 return(MmCreateImageSection(SectionObject
,
4939 SectionPageProtection
,
4940 AllocationAttributes
,
4944 if (FileHandle
!= NULL
)
4946 return(MmCreateDataFileSection(SectionObject
,
4950 SectionPageProtection
,
4951 AllocationAttributes
,
4955 return(MmCreatePageFileSection(SectionObject
,
4959 SectionPageProtection
,
4960 AllocationAttributes
));