2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
49 #include "../cache/section/newmm.h"
53 #include <reactos/exeformat.h>
55 #if defined (ALLOC_PRAGMA)
56 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
57 #pragma alloc_text(INIT, MmInitSectionImplementation)
62 MiMapViewInSystemSpace(IN PVOID Section
,
64 OUT PVOID
*MappedBase
,
65 IN OUT PSIZE_T ViewSize
);
69 MmCreateArm3Section(OUT PVOID
*SectionObject
,
70 IN ACCESS_MASK DesiredAccess
,
71 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
72 IN PLARGE_INTEGER InputMaximumSize
,
73 IN ULONG SectionPageProtection
,
74 IN ULONG AllocationAttributes
,
75 IN HANDLE FileHandle OPTIONAL
,
76 IN PFILE_OBJECT FileObject OPTIONAL
);
80 MmMapViewOfArm3Section(IN PVOID SectionObject
,
82 IN OUT PVOID
*BaseAddress
,
83 IN ULONG_PTR ZeroBits
,
85 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
86 IN OUT PSIZE_T ViewSize
,
87 IN SECTION_INHERIT InheritDisposition
,
88 IN ULONG AllocationType
,
92 // PeFmtCreateSection depends on the following:
94 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
95 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
97 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
98 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
99 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
101 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
102 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
103 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
104 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
105 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
106 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
107 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
108 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
109 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
111 /* TYPES *********************************************************************/
115 PROS_SECTION_OBJECT Section
;
116 PMM_SECTION_SEGMENT Segment
;
121 MM_SECTION_PAGEOUT_CONTEXT
;
123 /* GLOBALS *******************************************************************/
125 POBJECT_TYPE MmSectionObjectType
= NULL
;
127 SIZE_T MmAllocationFragment
;
129 ULONG_PTR MmSubsectionBase
;
131 static ULONG SectionCharacteristicsToProtect
[16] =
133 PAGE_NOACCESS
, /* 0 = NONE */
134 PAGE_NOACCESS
, /* 1 = SHARED */
135 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
136 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
137 PAGE_READONLY
, /* 4 = READABLE */
138 PAGE_READONLY
, /* 5 = READABLE, SHARED */
139 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
140 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
142 * FIXME? do we really need the WriteCopy field in segments? can't we use
143 * PAGE_WRITECOPY here?
145 PAGE_READWRITE
, /* 8 = WRITABLE */
146 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
147 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
148 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
149 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
150 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
151 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
152 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
155 static GENERIC_MAPPING MmpSectionMapping
= {
156 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
157 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
158 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
161 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
162 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
163 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
164 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
165 #define MAX_SHARE_COUNT 0x7FF
166 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
167 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
168 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
170 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
172 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
173 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
176 /* FUNCTIONS *****************************************************************/
181 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
182 File Format Specification", revision 6.0 (February 1999)
184 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
185 IN SIZE_T FileHeaderSize
,
187 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
189 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
190 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
193 ULONG cbFileHeaderOffsetSize
= 0;
194 ULONG cbSectionHeadersOffset
= 0;
195 ULONG cbSectionHeadersSize
;
196 ULONG cbSectionHeadersOffsetSize
= 0;
197 ULONG cbOptHeaderSize
;
198 ULONG cbHeadersSize
= 0;
199 ULONG nSectionAlignment
;
200 ULONG nFileAlignment
;
201 const IMAGE_DOS_HEADER
* pidhDosHeader
;
202 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
203 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
204 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
205 PMM_SECTION_SEGMENT pssSegments
;
206 LARGE_INTEGER lnOffset
;
208 ULONG nPrevVirtualEndOfSegment
= 0;
209 ULONG nFileSizeOfHeaders
= 0;
213 ASSERT(FileHeaderSize
> 0);
215 ASSERT(ImageSectionObject
);
217 ASSERT(AllocateSegmentsCb
);
219 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
221 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
223 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
226 pidhDosHeader
= FileHeader
;
229 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
231 /* image too small to be an MZ executable */
232 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
233 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
235 /* no MZ signature */
236 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
237 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
239 /* not a Windows executable */
240 if(pidhDosHeader
->e_lfanew
<= 0)
241 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
244 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
246 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
247 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
249 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
254 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
255 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
257 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
258 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
262 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
263 * need to read the header from the file
265 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
266 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
268 ULONG cbNtHeaderSize
;
272 l_ReadHeaderFromFile
:
274 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
276 /* read the header from the file */
277 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
279 if(!NT_SUCCESS(nStatus
))
280 DIE(("ReadFile failed, status %08X\n", nStatus
));
284 ASSERT(cbReadSize
> 0);
286 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
288 /* the buffer doesn't contain the file header */
289 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
290 DIE(("The file doesn't contain the PE file header\n"));
292 pinhNtHeader
= pData
;
294 /* object still not aligned: copy it to the beginning of the buffer */
295 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
297 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
298 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
299 pinhNtHeader
= pBuffer
;
302 /* invalid NT header */
303 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
305 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
306 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
308 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
310 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
311 DIE(("The full NT header is too large\n"));
313 /* the buffer doesn't contain the whole NT header */
314 if(cbReadSize
< cbNtHeaderSize
)
315 DIE(("The file doesn't contain the full NT header\n"));
319 ULONG cbOptHeaderOffsetSize
= 0;
321 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
323 /* don't trust an invalid NT header */
324 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
325 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
327 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
328 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
330 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
331 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
333 /* the buffer doesn't contain the whole NT header: read it from the file */
334 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
335 goto l_ReadHeaderFromFile
;
338 /* read information from the NT header */
339 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
340 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
342 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
344 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
345 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
347 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
349 switch(piohOptHeader
->Magic
)
351 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
352 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
356 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
359 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
360 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
362 /* See [1], section 3.4.2 */
363 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
365 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
366 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
368 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
369 DIE(("The section alignment is smaller than the file alignment\n"));
371 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
372 nFileAlignment
= piohOptHeader
->FileAlignment
;
374 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
375 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
379 nSectionAlignment
= PAGE_SIZE
;
380 nFileAlignment
= PAGE_SIZE
;
383 ASSERT(IsPowerOf2(nSectionAlignment
));
384 ASSERT(IsPowerOf2(nFileAlignment
));
386 switch(piohOptHeader
->Magic
)
389 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
391 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
392 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
394 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
395 ImageSectionObject
->ImageSize
= piohOptHeader
->SizeOfImage
;
397 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
398 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
400 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
401 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
407 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
409 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
411 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
413 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
415 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
416 DIE(("ImageBase exceeds the address space\n"));
418 ImageSectionObject
->ImageBase
= (ULONG_PTR
)pioh64OptHeader
->ImageBase
;
421 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
423 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
424 DIE(("SizeOfImage exceeds the address space\n"));
426 ImageSectionObject
->ImageSize
= pioh64OptHeader
->SizeOfImage
;
429 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
431 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
432 DIE(("SizeOfStackReserve exceeds the address space\n"));
434 ImageSectionObject
->StackReserve
= pioh64OptHeader
->SizeOfStackReserve
;
437 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
439 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
440 DIE(("SizeOfStackCommit exceeds the address space\n"));
442 ImageSectionObject
->StackCommit
= pioh64OptHeader
->SizeOfStackCommit
;
449 /* [1], section 3.4.2 */
450 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
451 DIE(("ImageBase is not aligned on a 64KB boundary"));
453 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
455 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
457 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
458 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
460 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
461 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
465 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
467 ImageSectionObject
->EntryPoint
= piohOptHeader
->ImageBase
+
468 piohOptHeader
->AddressOfEntryPoint
;
471 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
472 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
474 ImageSectionObject
->Executable
= TRUE
;
476 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
477 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
479 /* SECTION HEADERS */
480 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
482 /* see [1], section 3.3 */
483 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
484 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
487 * the additional segment is for the file's headers. They need to be present for
488 * the benefit of the dynamic loader (to locate exports, defaults for thread
489 * parameters, resources, etc.)
491 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
493 /* file offset for the section headers */
494 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
495 DIE(("Offset overflow\n"));
497 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
498 DIE(("Offset overflow\n"));
500 /* size of the section headers */
501 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
502 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
504 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
505 DIE(("Section headers too large\n"));
507 /* size of the executable's headers */
508 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
510 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
511 // DIE(("SizeOfHeaders is not aligned\n"));
513 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
514 DIE(("The section headers overflow SizeOfHeaders\n"));
516 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
518 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
519 DIE(("Overflow aligning the size of headers\n"));
526 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
527 /* WARNING: piohOptHeader IS NO LONGER USABLE */
528 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
530 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
531 pishSectionHeaders
= NULL
;
535 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
536 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
538 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
539 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
543 * the buffer doesn't contain the section headers, or the alignment is wrong:
544 * read the headers from the file
546 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
547 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
552 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
554 /* read the header from the file */
555 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
557 if(!NT_SUCCESS(nStatus
))
558 DIE(("ReadFile failed with status %08X\n", nStatus
));
562 ASSERT(cbReadSize
> 0);
564 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
566 /* the buffer doesn't contain all the section headers */
567 if(cbReadSize
< cbSectionHeadersSize
)
568 DIE(("The file doesn't contain all of the section headers\n"));
570 pishSectionHeaders
= pData
;
572 /* object still not aligned: copy it to the beginning of the buffer */
573 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
575 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
576 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
577 pishSectionHeaders
= pBuffer
;
582 /* allocate the segments */
583 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
584 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
586 if(ImageSectionObject
->Segments
== NULL
)
587 DIE(("AllocateSegments failed\n"));
589 /* initialize the headers segment */
590 pssSegments
= ImageSectionObject
->Segments
;
592 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
594 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
595 DIE(("Cannot align the size of the section headers\n"));
597 if(!AlignUp(&nPrevVirtualEndOfSegment
, cbHeadersSize
, nSectionAlignment
))
598 DIE(("Cannot align the size of the section headers\n"));
600 pssSegments
[0].FileOffset
= 0;
601 pssSegments
[0].Protection
= PAGE_READONLY
;
602 pssSegments
[0].Length
= nPrevVirtualEndOfSegment
;
603 pssSegments
[0].RawLength
= nFileSizeOfHeaders
;
604 pssSegments
[0].VirtualAddress
= 0;
605 pssSegments
[0].Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
606 pssSegments
[0].WriteCopy
= TRUE
;
608 /* skip the headers segment */
611 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
613 /* convert the executable sections into segments. See also [1], section 4 */
614 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
616 ULONG nCharacteristics
;
618 /* validate the alignment */
619 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
620 DIE(("VirtualAddress[%u] is not aligned\n", i
));
622 /* sections must be contiguous, ordered by base address and non-overlapping */
623 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
624 DIE(("Memory gap between section %u and the previous\n", i
));
626 /* ignore explicit BSS sections */
627 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
629 /* validate the alignment */
631 /* Yes, this should be a multiple of FileAlignment, but there's
632 * stuff out there that isn't. We can cope with that
634 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
635 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
638 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
639 // DIE(("PointerToRawData[%u] is not aligned\n", i));
642 pssSegments
[i
].FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
643 pssSegments
[i
].RawLength
= pishSectionHeaders
[i
].SizeOfRawData
;
647 ASSERT(pssSegments
[i
].FileOffset
== 0);
648 ASSERT(pssSegments
[i
].RawLength
== 0);
651 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].FileOffset
, pssSegments
[i
].RawLength
));
653 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
655 /* no explicit protection */
656 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
658 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
659 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
661 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
662 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
664 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
665 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
668 /* see table above */
669 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
670 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
672 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
673 pssSegments
[i
].Length
= pishSectionHeaders
[i
].SizeOfRawData
;
675 pssSegments
[i
].Length
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
677 if(!AlignUp(&pssSegments
[i
].Length
, pssSegments
[i
].Length
, nSectionAlignment
))
678 DIE(("Cannot align the virtual size of section %u\n", i
));
680 ASSERT(IsAligned(pssSegments
[i
].Length
, nSectionAlignment
));
682 if(pssSegments
[i
].Length
== 0)
683 DIE(("Virtual size of section %u is null\n", i
));
685 pssSegments
[i
].VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
686 pssSegments
[i
].Characteristics
= pishSectionHeaders
[i
].Characteristics
;
688 /* ensure the memory image is no larger than 4GB */
689 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment
, pssSegments
[i
].VirtualAddress
, pssSegments
[i
].Length
))
690 DIE(("The image is larger than 4GB\n"));
693 /* spare our caller some work in validating the segments */
694 *Flags
= EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
| EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
;
696 if(nSectionAlignment
>= PAGE_SIZE
)
697 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
700 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;
709 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
712 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
713 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
714 * RETURNS: Status of the wait.
717 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
719 LARGE_INTEGER Timeout
;
720 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
722 Timeout
.QuadPart
= -100000000LL; // 10 sec
725 Timeout
.QuadPart
= -100000000; // 10 sec
728 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
733 * FUNCTION: Sets the page op completion event and releases the page op.
734 * ARGUMENTS: PMM_PAGEOP.
735 * RETURNS: In shorter time than it takes you to even read this
736 * description, so don't even think about geting a mug of coffee.
739 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
741 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
742 MmReleasePageOp(PageOp
);
747 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
748 * ARGUMENTS: PFILE_OBJECT to wait for.
749 * RETURNS: Status of the wait.
752 MmspWaitForFileLock(PFILE_OBJECT File
)
754 return STATUS_SUCCESS
;
755 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
760 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
763 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
765 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
767 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
769 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
777 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
779 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
781 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
782 PMM_SECTION_SEGMENT SectionSegments
;
786 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
787 NrSegments
= ImageSectionObject
->NrSegments
;
788 SectionSegments
= ImageSectionObject
->Segments
;
789 for (i
= 0; i
< NrSegments
; i
++)
791 if (SectionSegments
[i
].ReferenceCount
!= 0)
793 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
794 SectionSegments
[i
].ReferenceCount
);
795 KeBugCheck(MEMORY_MANAGEMENT
);
797 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
799 ExFreePool(ImageSectionObject
->Segments
);
800 ExFreePool(ImageSectionObject
);
801 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
803 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
805 PMM_SECTION_SEGMENT Segment
;
807 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
810 if (Segment
->ReferenceCount
!= 0)
812 DPRINT1("Data segment still referenced\n");
813 KeBugCheck(MEMORY_MANAGEMENT
);
815 MmFreePageTablesSectionSegment(Segment
);
817 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
823 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
825 ExAcquireFastMutex(&Segment
->Lock
);
830 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
832 ExReleaseFastMutex(&Segment
->Lock
);
837 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
841 PSECTION_PAGE_TABLE Table
;
842 ULONG DirectoryOffset
;
845 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
847 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
851 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
852 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
856 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
857 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
858 TAG_SECTION_PAGE_TABLE
);
861 KeBugCheck(MEMORY_MANAGEMENT
);
863 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
864 DPRINT("Table %x\n", Table
);
867 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
868 Table
->Entry
[TableOffset
] = Entry
;
874 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
877 PSECTION_PAGE_TABLE Table
;
879 ULONG DirectoryOffset
;
882 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
884 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
886 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
890 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
891 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
892 DPRINT("Table %x\n", Table
);
898 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
899 Entry
= Table
->Entry
[TableOffset
];
905 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
910 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
913 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
914 KeBugCheck(MEMORY_MANAGEMENT
);
916 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
918 DPRINT1("Maximum share count reached\n");
919 KeBugCheck(MEMORY_MANAGEMENT
);
921 if (IS_SWAP_FROM_SSE(Entry
))
923 KeBugCheck(MEMORY_MANAGEMENT
);
925 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
926 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
931 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
932 PMM_SECTION_SEGMENT Segment
,
938 BOOLEAN IsDirectMapped
= FALSE
;
940 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
943 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
944 KeBugCheck(MEMORY_MANAGEMENT
);
946 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
948 DPRINT1("Zero share count for unshare\n");
949 KeBugCheck(MEMORY_MANAGEMENT
);
951 if (IS_SWAP_FROM_SSE(Entry
))
953 KeBugCheck(MEMORY_MANAGEMENT
);
955 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
957 * If we reducing the share count of this entry to zero then set the entry
958 * to zero and tell the cache the page is no longer mapped.
960 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
962 PFILE_OBJECT FileObject
;
964 SWAPENTRY SavedSwapEntry
;
966 BOOLEAN IsImageSection
;
969 FileOffset
= Offset
+ Segment
->FileOffset
;
971 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
973 Page
= PFN_FROM_SSE(Entry
);
974 FileObject
= Section
->FileObject
;
975 if (FileObject
!= NULL
&&
976 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
979 if ((FileOffset
% PAGE_SIZE
) == 0 &&
980 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
983 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
984 IsDirectMapped
= TRUE
;
986 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
988 Status
= STATUS_SUCCESS
;
990 if (!NT_SUCCESS(Status
))
992 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
993 KeBugCheck(MEMORY_MANAGEMENT
);
998 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
999 if (SavedSwapEntry
== 0)
1002 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1003 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
1007 * Try to page out this page and set the swap entry
1008 * within the section segment. There exist no rmap entry
1009 * for this page. The pager thread can't page out a
1010 * page without a rmap entry.
1012 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1016 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
1017 if (!IsDirectMapped
)
1019 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1025 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1026 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1034 * We hold all locks. Nobody can do something with the current
1035 * process and the current segment (also not within an other process).
1038 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
1039 if (!NT_SUCCESS(Status
))
1041 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
1042 KeBugCheck(MEMORY_MANAGEMENT
);
1045 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
1046 MmSetSavedSwapEntryPage(Page
, 0);
1048 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1052 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1053 KeBugCheck(MEMORY_MANAGEMENT
);
1059 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1061 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1064 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1068 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1071 PCACHE_SEGMENT CacheSeg
;
1072 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1073 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
1076 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
1086 MiCopyFromUserPage(PFN_NUMBER DestPage
, PVOID SourceAddress
)
1092 Process
= PsGetCurrentProcess();
1093 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1094 if (TempAddress
== NULL
)
1096 return(STATUS_NO_MEMORY
);
1098 memcpy(TempAddress
, SourceAddress
, PAGE_SIZE
);
1099 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
1100 return(STATUS_SUCCESS
);
1106 MiReadPage(PMEMORY_AREA MemoryArea
,
1110 * FUNCTION: Read a page for a section backed memory area.
1112 * MemoryArea - Memory area to read the page for.
1113 * Offset - Offset of the page to read.
1114 * Page - Variable that receives a page contains the read data.
1121 PCACHE_SEGMENT CacheSeg
;
1122 PFILE_OBJECT FileObject
;
1126 BOOLEAN IsImageSection
;
1129 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1130 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1131 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
1132 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
1133 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1137 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1140 * If the file system is letting us go directly to the cache and the
1141 * memory area was mapped at an offset in the file which is page aligned
1142 * then get the related cache segment.
1144 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1145 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
1146 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1150 * Get the related cache segment; we use a lower level interface than
1151 * filesystems do because it is safe for us to use an offset with a
1152 * alignment less than the file system block size.
1154 Status
= CcRosGetCacheSegment(Bcb
,
1160 if (!NT_SUCCESS(Status
))
1167 * If the cache segment isn't up to date then call the file
1168 * system to read in the data.
1170 Status
= ReadCacheSegment(CacheSeg
);
1171 if (!NT_SUCCESS(Status
))
1173 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1178 * Retrieve the page from the cache segment that we actually want.
1180 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1181 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1183 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1190 ULONG CacheSegOffset
;
1193 * Allocate a page, this is rather complicated by the possibility
1194 * we might have to move other things out of memory
1196 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1197 if (!NT_SUCCESS(Status
))
1201 Status
= CcRosGetCacheSegment(Bcb
,
1207 if (!NT_SUCCESS(Status
))
1214 * If the cache segment isn't up to date then call the file
1215 * system to read in the data.
1217 Status
= ReadCacheSegment(CacheSeg
);
1218 if (!NT_SUCCESS(Status
))
1220 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1225 Process
= PsGetCurrentProcess();
1226 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1227 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
1228 Length
= RawLength
- SegOffset
;
1229 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1231 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1233 else if (CacheSegOffset
>= PAGE_SIZE
)
1235 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1239 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1240 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1241 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1242 Status
= CcRosGetCacheSegment(Bcb
,
1243 FileOffset
+ CacheSegOffset
,
1248 if (!NT_SUCCESS(Status
))
1255 * If the cache segment isn't up to date then call the file
1256 * system to read in the data.
1258 Status
= ReadCacheSegment(CacheSeg
);
1259 if (!NT_SUCCESS(Status
))
1261 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1265 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1266 if (Length
< PAGE_SIZE
)
1268 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1272 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1275 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1276 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1278 return(STATUS_SUCCESS
);
1283 MiReadPage(PMEMORY_AREA MemoryArea
,
1287 * FUNCTION: Read a page for a section backed memory area.
1289 * MemoryArea - Memory area to read the page for.
1290 * Offset - Offset of the page to read.
1291 * Page - Variable that receives a page contains the read data.
1294 MM_REQUIRED_RESOURCES Resources
= { };
1296 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1297 Resources
.FileOffset
.QuadPart
= SegOffset
+
1298 MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
1299 Resources
.Consumer
= MC_USER
;
1300 Resources
.Amount
= PAGE_SIZE
;
1302 DPRINT1("%S, offset %x, len %d, page %x\n", ((PFILE_OBJECT
)Resources
.Context
)->FileName
.Buffer
, Resources
.FileOffset
.LowPart
, Resources
.Amount
, Resources
.Page
[0]);
1304 NTSTATUS Status
= MiReadFilePage(NULL
, NULL
, &Resources
);
1305 *Page
= Resources
.Page
[0];
1312 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1313 MEMORY_AREA
* MemoryArea
,
1321 PROS_SECTION_OBJECT Section
;
1322 PMM_SECTION_SEGMENT Segment
;
1328 BOOLEAN HasSwapEntry
;
1329 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1332 * There is a window between taking the page fault and locking the
1333 * address space when another thread could load the page so we check
1336 if (MmIsPagePresent(Process
, Address
))
1338 return(STATUS_SUCCESS
);
1341 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1342 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1343 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1345 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1346 Section
= MemoryArea
->Data
.SectionData
.Section
;
1347 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1348 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1353 MmLockSectionSegment(Segment
);
1356 * Check if this page needs to be mapped COW
1358 if ((Segment
->WriteCopy
) &&
1359 (Region
->Protect
== PAGE_READWRITE
||
1360 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1362 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1366 Attributes
= Region
->Protect
;
1370 * Get or create a page operation descriptor
1372 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
1375 DPRINT1("MmGetPageOp failed\n");
1376 KeBugCheck(MEMORY_MANAGEMENT
);
1380 * Check if someone else is already handling this fault, if so wait
1383 if (PageOp
->Thread
!= PsGetCurrentThread())
1385 MmUnlockSectionSegment(Segment
);
1386 MmUnlockAddressSpace(AddressSpace
);
1387 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1389 * Check for various strange conditions
1391 if (Status
!= STATUS_SUCCESS
)
1393 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1394 KeBugCheck(MEMORY_MANAGEMENT
);
1396 if (PageOp
->Status
== STATUS_PENDING
)
1398 DPRINT1("Woke for page op before completion\n");
1399 KeBugCheck(MEMORY_MANAGEMENT
);
1401 MmLockAddressSpace(AddressSpace
);
1403 * If this wasn't a pagein then restart the operation
1405 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
1407 MmspCompleteAndReleasePageOp(PageOp
);
1408 DPRINT("Address 0x%.8X\n", Address
);
1409 return(STATUS_MM_RESTART_OPERATION
);
1413 * If the thread handling this fault has failed then we don't retry
1415 if (!NT_SUCCESS(PageOp
->Status
))
1417 Status
= PageOp
->Status
;
1418 MmspCompleteAndReleasePageOp(PageOp
);
1419 DPRINT("Address 0x%.8X\n", Address
);
1422 MmLockSectionSegment(Segment
);
1424 * If the completed fault was for another address space then set the
1427 if (!MmIsPagePresent(Process
, Address
))
1429 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1430 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1432 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
1435 * The page was a private page in another or in our address space
1437 MmUnlockSectionSegment(Segment
);
1438 MmspCompleteAndReleasePageOp(PageOp
);
1439 return(STATUS_MM_RESTART_OPERATION
);
1442 Page
= PFN_FROM_SSE(Entry
);
1444 MmSharePageEntrySectionSegment(Segment
, Offset
);
1446 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
1447 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
1449 Status
= MmCreateVirtualMapping(Process
,
1454 if (!NT_SUCCESS(Status
))
1456 DPRINT1("Unable to create virtual mapping\n");
1457 KeBugCheck(MEMORY_MANAGEMENT
);
1459 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1461 MmUnlockSectionSegment(Segment
);
1462 PageOp
->Status
= STATUS_SUCCESS
;
1463 MmspCompleteAndReleasePageOp(PageOp
);
1464 DPRINT("Address 0x%.8X\n", Address
);
1465 return(STATUS_SUCCESS
);
1468 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1472 * Must be private page we have swapped out.
1474 SWAPENTRY SwapEntry
;
1479 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1481 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1482 KeBugCheck(MEMORY_MANAGEMENT
);
1485 MmUnlockSectionSegment(Segment
);
1486 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
1488 MmUnlockAddressSpace(AddressSpace
);
1489 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1490 if (!NT_SUCCESS(Status
))
1492 KeBugCheck(MEMORY_MANAGEMENT
);
1495 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1496 if (!NT_SUCCESS(Status
))
1498 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1499 KeBugCheck(MEMORY_MANAGEMENT
);
1501 MmLockAddressSpace(AddressSpace
);
1502 Status
= MmCreateVirtualMapping(Process
,
1507 if (!NT_SUCCESS(Status
))
1509 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1510 KeBugCheck(MEMORY_MANAGEMENT
);
1515 * Store the swap entry for later use.
1517 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1520 * Add the page to the process's working set
1522 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1525 * Finish the operation
1527 PageOp
->Status
= STATUS_SUCCESS
;
1528 MmspCompleteAndReleasePageOp(PageOp
);
1529 DPRINT("Address 0x%.8X\n", Address
);
1530 return(STATUS_SUCCESS
);
1534 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1536 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1538 MmUnlockSectionSegment(Segment
);
1540 * Just map the desired physical page
1542 Page
= Offset
>> PAGE_SHIFT
;
1543 Status
= MmCreateVirtualMappingUnsafe(Process
,
1548 if (!NT_SUCCESS(Status
))
1550 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1551 KeBugCheck(MEMORY_MANAGEMENT
);
1556 * Cleanup and release locks
1558 PageOp
->Status
= STATUS_SUCCESS
;
1559 MmspCompleteAndReleasePageOp(PageOp
);
1560 DPRINT("Address 0x%.8X\n", Address
);
1561 return(STATUS_SUCCESS
);
1565 * Map anonymous memory for BSS sections
1567 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1569 MmUnlockSectionSegment(Segment
);
1570 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1571 if (!NT_SUCCESS(Status
))
1573 MmUnlockAddressSpace(AddressSpace
);
1574 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1575 MmLockAddressSpace(AddressSpace
);
1577 if (!NT_SUCCESS(Status
))
1579 KeBugCheck(MEMORY_MANAGEMENT
);
1581 Status
= MmCreateVirtualMapping(Process
,
1586 if (!NT_SUCCESS(Status
))
1588 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1589 KeBugCheck(MEMORY_MANAGEMENT
);
1592 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1595 * Cleanup and release locks
1597 PageOp
->Status
= STATUS_SUCCESS
;
1598 MmspCompleteAndReleasePageOp(PageOp
);
1599 DPRINT("Address 0x%.8X\n", Address
);
1600 return(STATUS_SUCCESS
);
1604 * Get the entry corresponding to the offset within the section
1606 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1611 * If the entry is zero (and it can't change because we have
1612 * locked the segment) then we need to load the page.
1616 * Release all our locks and read in the page from disk
1618 MmUnlockSectionSegment(Segment
);
1619 MmUnlockAddressSpace(AddressSpace
);
1621 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1622 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1624 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1625 if (!NT_SUCCESS(Status
))
1627 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1633 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1634 if (!NT_SUCCESS(Status
))
1636 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1639 if (!NT_SUCCESS(Status
))
1642 * FIXME: What do we know in this case?
1645 * Cleanup and release locks
1647 MmLockAddressSpace(AddressSpace
);
1648 PageOp
->Status
= Status
;
1649 MmspCompleteAndReleasePageOp(PageOp
);
1650 DPRINT("Address 0x%.8X\n", Address
);
1654 * Relock the address space and segment
1656 MmLockAddressSpace(AddressSpace
);
1657 MmLockSectionSegment(Segment
);
1660 * Check the entry. No one should change the status of a page
1661 * that has a pending page-in.
1663 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1664 if (Entry
!= Entry1
)
1666 DPRINT1("Someone changed ppte entry while we slept\n");
1667 KeBugCheck(MEMORY_MANAGEMENT
);
1671 * Mark the offset within the section as having valid, in-memory
1674 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1675 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1676 MmUnlockSectionSegment(Segment
);
1678 Status
= MmCreateVirtualMapping(Process
,
1683 if (!NT_SUCCESS(Status
))
1685 DPRINT1("Unable to create virtual mapping\n");
1686 KeBugCheck(MEMORY_MANAGEMENT
);
1688 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1690 PageOp
->Status
= STATUS_SUCCESS
;
1691 MmspCompleteAndReleasePageOp(PageOp
);
1692 DPRINT("Address 0x%.8X\n", Address
);
1693 return(STATUS_SUCCESS
);
1695 else if (IS_SWAP_FROM_SSE(Entry
))
1697 SWAPENTRY SwapEntry
;
1699 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1702 * Release all our locks and read in the page from disk
1704 MmUnlockSectionSegment(Segment
);
1706 MmUnlockAddressSpace(AddressSpace
);
1708 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1709 if (!NT_SUCCESS(Status
))
1711 KeBugCheck(MEMORY_MANAGEMENT
);
1714 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1715 if (!NT_SUCCESS(Status
))
1717 KeBugCheck(MEMORY_MANAGEMENT
);
1721 * Relock the address space and segment
1723 MmLockAddressSpace(AddressSpace
);
1724 MmLockSectionSegment(Segment
);
1727 * Check the entry. No one should change the status of a page
1728 * that has a pending page-in.
1730 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1731 if (Entry
!= Entry1
)
1733 DPRINT1("Someone changed ppte entry while we slept\n");
1734 KeBugCheck(MEMORY_MANAGEMENT
);
1738 * Mark the offset within the section as having valid, in-memory
1741 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1742 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1743 MmUnlockSectionSegment(Segment
);
1746 * Save the swap entry.
1748 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1749 Status
= MmCreateVirtualMapping(Process
,
1754 if (!NT_SUCCESS(Status
))
1756 DPRINT1("Unable to create virtual mapping\n");
1757 KeBugCheck(MEMORY_MANAGEMENT
);
1759 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1760 PageOp
->Status
= STATUS_SUCCESS
;
1761 MmspCompleteAndReleasePageOp(PageOp
);
1762 DPRINT("Address 0x%.8X\n", Address
);
1763 return(STATUS_SUCCESS
);
1768 * If the section offset is already in-memory and valid then just
1769 * take another reference to the page
1772 Page
= PFN_FROM_SSE(Entry
);
1774 MmSharePageEntrySectionSegment(Segment
, Offset
);
1775 MmUnlockSectionSegment(Segment
);
1777 Status
= MmCreateVirtualMapping(Process
,
1782 if (!NT_SUCCESS(Status
))
1784 DPRINT1("Unable to create virtual mapping\n");
1785 KeBugCheck(MEMORY_MANAGEMENT
);
1787 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1788 PageOp
->Status
= STATUS_SUCCESS
;
1789 MmspCompleteAndReleasePageOp(PageOp
);
1790 DPRINT("Address 0x%.8X\n", Address
);
1791 return(STATUS_SUCCESS
);
1797 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1798 MEMORY_AREA
* MemoryArea
,
1802 PMM_SECTION_SEGMENT Segment
;
1803 PROS_SECTION_OBJECT Section
;
1812 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1814 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1817 * Check if the page has been paged out or has already been set readwrite
1819 if (!MmIsPagePresent(Process
, Address
) ||
1820 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1822 DPRINT("Address 0x%.8X\n", Address
);
1823 return(STATUS_SUCCESS
);
1827 * Find the offset of the page
1829 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1830 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1831 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1833 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1834 Section
= MemoryArea
->Data
.SectionData
.Section
;
1835 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1836 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1841 MmLockSectionSegment(Segment
);
1843 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1844 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1846 MmUnlockSectionSegment(Segment
);
1849 * Check if we are doing COW
1851 if (!((Segment
->WriteCopy
) &&
1852 (Region
->Protect
== PAGE_READWRITE
||
1853 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1855 DPRINT("Address 0x%.8X\n", Address
);
1856 return(STATUS_ACCESS_VIOLATION
);
1859 if (IS_SWAP_FROM_SSE(Entry
) ||
1860 PFN_FROM_SSE(Entry
) != OldPage
)
1862 /* This is a private page. We must only change the page protection. */
1863 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1864 return(STATUS_SUCCESS
);
1868 * Get or create a pageop
1870 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1871 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1874 DPRINT1("MmGetPageOp failed\n");
1875 KeBugCheck(MEMORY_MANAGEMENT
);
1879 * Wait for any other operations to complete
1881 if (PageOp
->Thread
!= PsGetCurrentThread())
1883 MmUnlockAddressSpace(AddressSpace
);
1884 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1886 * Check for various strange conditions
1888 if (Status
== STATUS_TIMEOUT
)
1890 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1891 KeBugCheck(MEMORY_MANAGEMENT
);
1893 if (PageOp
->Status
== STATUS_PENDING
)
1895 DPRINT1("Woke for page op before completion\n");
1896 KeBugCheck(MEMORY_MANAGEMENT
);
1899 * Restart the operation
1901 MmLockAddressSpace(AddressSpace
);
1902 MmspCompleteAndReleasePageOp(PageOp
);
1903 DPRINT("Address 0x%.8X\n", Address
);
1904 return(STATUS_MM_RESTART_OPERATION
);
1908 * Release locks now we have the pageop
1910 MmUnlockAddressSpace(AddressSpace
);
1915 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1916 if (!NT_SUCCESS(Status
))
1918 KeBugCheck(MEMORY_MANAGEMENT
);
1924 MiCopyFromUserPage(NewPage
, PAddress
);
1926 MmLockAddressSpace(AddressSpace
);
1928 * Delete the old entry.
1930 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1933 * Set the PTE to point to the new page
1935 Status
= MmCreateVirtualMapping(Process
,
1940 if (!NT_SUCCESS(Status
))
1942 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1943 KeBugCheck(MEMORY_MANAGEMENT
);
1946 if (!NT_SUCCESS(Status
))
1948 DPRINT1("Unable to create virtual mapping\n");
1949 KeBugCheck(MEMORY_MANAGEMENT
);
1953 * Unshare the old page.
1955 MmDeleteRmap(OldPage
, Process
, PAddress
);
1956 MmInsertRmap(NewPage
, Process
, PAddress
);
1957 MmLockSectionSegment(Segment
);
1958 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1959 MmUnlockSectionSegment(Segment
);
1961 PageOp
->Status
= STATUS_SUCCESS
;
1962 MmspCompleteAndReleasePageOp(PageOp
);
1963 DPRINT("Address 0x%.8X\n", Address
);
1964 return(STATUS_SUCCESS
);
1968 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1970 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1974 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1977 MmLockAddressSpace(&Process
->Vm
);
1980 MmDeleteVirtualMapping(Process
,
1987 PageOutContext
->WasDirty
= TRUE
;
1989 if (!PageOutContext
->Private
)
1991 MmLockSectionSegment(PageOutContext
->Segment
);
1992 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1993 PageOutContext
->Segment
,
1994 PageOutContext
->Offset
,
1995 PageOutContext
->WasDirty
,
1997 MmUnlockSectionSegment(PageOutContext
->Segment
);
2001 MmUnlockAddressSpace(&Process
->Vm
);
2004 if (PageOutContext
->Private
)
2006 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2009 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
2014 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
2015 MEMORY_AREA
* MemoryArea
,
2020 MM_SECTION_PAGEOUT_CONTEXT Context
;
2021 SWAPENTRY SwapEntry
;
2025 PFILE_OBJECT FileObject
;
2027 BOOLEAN DirectMapped
;
2028 BOOLEAN IsImageSection
;
2029 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2032 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2035 * Get the segment and section.
2037 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2038 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
2040 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2041 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2042 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
2044 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2046 FileObject
= Context
.Section
->FileObject
;
2047 DirectMapped
= FALSE
;
2048 if (FileObject
!= NULL
&&
2049 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2051 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2054 * If the file system is letting us go directly to the cache and the
2055 * memory area was mapped at an offset in the file which is page aligned
2056 * then note this is a direct mapped page.
2058 if ((FileOffset
% PAGE_SIZE
) == 0 &&
2059 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
2061 DirectMapped
= TRUE
;
2067 * This should never happen since mappings of physical memory are never
2068 * placed in the rmap lists.
2070 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2072 DPRINT1("Trying to page out from physical memory section address 0x%X "
2073 "process %d\n", Address
,
2074 Process
? Process
->UniqueProcessId
: 0);
2075 KeBugCheck(MEMORY_MANAGEMENT
);
2079 * Get the section segment entry and the physical address.
2081 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
2082 if (!MmIsPagePresent(Process
, Address
))
2084 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2085 Process
? Process
->UniqueProcessId
: 0, Address
);
2086 KeBugCheck(MEMORY_MANAGEMENT
);
2088 Page
= MmGetPfnForProcess(Process
, Address
);
2089 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2092 * Prepare the context structure for the rmap delete call.
2094 Context
.WasDirty
= FALSE
;
2095 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2096 IS_SWAP_FROM_SSE(Entry
) ||
2097 PFN_FROM_SSE(Entry
) != Page
)
2099 Context
.Private
= TRUE
;
2103 Context
.Private
= FALSE
;
2107 * Take an additional reference to the page or the cache segment.
2109 if (DirectMapped
&& !Context
.Private
)
2111 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
2113 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2114 KeBugCheck(MEMORY_MANAGEMENT
);
2119 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
2120 MmReferencePage(Page
);
2121 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
2124 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2127 * If this wasn't a private page then we should have reduced the entry to
2128 * zero by deleting all the rmaps.
2130 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
2132 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2133 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2135 KeBugCheck(MEMORY_MANAGEMENT
);
2140 * If the page wasn't dirty then we can just free it as for a readonly page.
2141 * Since we unmapped all the mappings above we know it will not suddenly
2143 * If the page is from a pagefile section and has no swap entry,
2144 * we can't free the page at this point.
2146 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2147 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2149 if (Context
.Private
)
2151 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
2152 Context
.WasDirty
? "dirty" : "clean", Address
);
2153 KeBugCheck(MEMORY_MANAGEMENT
);
2155 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2157 MmSetSavedSwapEntryPage(Page
, 0);
2158 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2159 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2160 PageOp
->Status
= STATUS_SUCCESS
;
2161 MmspCompleteAndReleasePageOp(PageOp
);
2162 return(STATUS_SUCCESS
);
2165 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2167 if (Context
.Private
)
2169 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2170 Context
.WasDirty
? "dirty" : "clean", Address
);
2171 KeBugCheck(MEMORY_MANAGEMENT
);
2173 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2175 MmSetSavedSwapEntryPage(Page
, 0);
2178 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2180 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2181 PageOp
->Status
= STATUS_SUCCESS
;
2182 MmspCompleteAndReleasePageOp(PageOp
);
2183 return(STATUS_SUCCESS
);
2186 else if (!Context
.Private
&& DirectMapped
)
2190 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2192 KeBugCheck(MEMORY_MANAGEMENT
);
2195 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
2197 Status
= STATUS_SUCCESS
;
2199 if (!NT_SUCCESS(Status
))
2201 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2202 KeBugCheck(MEMORY_MANAGEMENT
);
2204 PageOp
->Status
= STATUS_SUCCESS
;
2205 MmspCompleteAndReleasePageOp(PageOp
);
2206 return(STATUS_SUCCESS
);
2208 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2212 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2214 KeBugCheck(MEMORY_MANAGEMENT
);
2216 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2217 PageOp
->Status
= STATUS_SUCCESS
;
2218 MmspCompleteAndReleasePageOp(PageOp
);
2219 return(STATUS_SUCCESS
);
2221 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2223 MmSetSavedSwapEntryPage(Page
, 0);
2224 MmLockAddressSpace(AddressSpace
);
2225 Status
= MmCreatePageFileMapping(Process
,
2228 MmUnlockAddressSpace(AddressSpace
);
2229 if (!NT_SUCCESS(Status
))
2231 KeBugCheck(MEMORY_MANAGEMENT
);
2233 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2234 PageOp
->Status
= STATUS_SUCCESS
;
2235 MmspCompleteAndReleasePageOp(PageOp
);
2236 return(STATUS_SUCCESS
);
2240 * If necessary, allocate an entry in the paging file for this page
2244 SwapEntry
= MmAllocSwapPage();
2247 MmShowOutOfSpaceMessagePagingFile();
2248 MmLockAddressSpace(AddressSpace
);
2250 * For private pages restore the old mappings.
2252 if (Context
.Private
)
2254 Status
= MmCreateVirtualMapping(Process
,
2256 MemoryArea
->Protect
,
2259 MmSetDirtyPage(Process
, Address
);
2267 * For non-private pages if the page wasn't direct mapped then
2268 * set it back into the section segment entry so we don't loose
2269 * our copy. Otherwise it will be handled by the cache manager.
2271 Status
= MmCreateVirtualMapping(Process
,
2273 MemoryArea
->Protect
,
2276 MmSetDirtyPage(Process
, Address
);
2280 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2281 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2283 MmUnlockAddressSpace(AddressSpace
);
2284 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2285 MmspCompleteAndReleasePageOp(PageOp
);
2286 return(STATUS_PAGEFILE_QUOTA
);
2291 * Write the page to the pagefile
2293 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2294 if (!NT_SUCCESS(Status
))
2296 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2299 * As above: undo our actions.
2300 * FIXME: Also free the swap page.
2302 MmLockAddressSpace(AddressSpace
);
2303 if (Context
.Private
)
2305 Status
= MmCreateVirtualMapping(Process
,
2307 MemoryArea
->Protect
,
2310 MmSetDirtyPage(Process
, Address
);
2317 Status
= MmCreateVirtualMapping(Process
,
2319 MemoryArea
->Protect
,
2322 MmSetDirtyPage(Process
, Address
);
2326 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2327 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2329 MmUnlockAddressSpace(AddressSpace
);
2330 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2331 MmspCompleteAndReleasePageOp(PageOp
);
2332 return(STATUS_UNSUCCESSFUL
);
2336 * Otherwise we have succeeded.
2338 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2339 MmSetSavedSwapEntryPage(Page
, 0);
2340 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2341 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2343 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2347 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2350 if (Context
.Private
)
2352 MmLockAddressSpace(AddressSpace
);
2353 Status
= MmCreatePageFileMapping(Process
,
2356 MmUnlockAddressSpace(AddressSpace
);
2357 if (!NT_SUCCESS(Status
))
2359 KeBugCheck(MEMORY_MANAGEMENT
);
2364 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2365 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2368 PageOp
->Status
= STATUS_SUCCESS
;
2369 MmspCompleteAndReleasePageOp(PageOp
);
2370 return(STATUS_SUCCESS
);
2375 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2376 PMEMORY_AREA MemoryArea
,
2381 PROS_SECTION_OBJECT Section
;
2382 PMM_SECTION_SEGMENT Segment
;
2384 SWAPENTRY SwapEntry
;
2388 PFILE_OBJECT FileObject
;
2390 BOOLEAN DirectMapped
;
2391 BOOLEAN IsImageSection
;
2392 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2394 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2396 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2397 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2400 * Get the segment and section.
2402 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2403 Section
= MemoryArea
->Data
.SectionData
.Section
;
2404 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2406 FileObject
= Section
->FileObject
;
2407 DirectMapped
= FALSE
;
2408 if (FileObject
!= NULL
&&
2409 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2411 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2414 * If the file system is letting us go directly to the cache and the
2415 * memory area was mapped at an offset in the file which is page aligned
2416 * then note this is a direct mapped page.
2418 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
2419 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
2421 DirectMapped
= TRUE
;
2426 * This should never happen since mappings of physical memory are never
2427 * placed in the rmap lists.
2429 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2431 DPRINT1("Trying to write back page from physical memory mapped at %X "
2432 "process %d\n", Address
,
2433 Process
? Process
->UniqueProcessId
: 0);
2434 KeBugCheck(MEMORY_MANAGEMENT
);
2438 * Get the section segment entry and the physical address.
2440 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2441 if (!MmIsPagePresent(Process
, Address
))
2443 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2444 Process
? Process
->UniqueProcessId
: 0, Address
);
2445 KeBugCheck(MEMORY_MANAGEMENT
);
2447 Page
= MmGetPfnForProcess(Process
, Address
);
2448 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2451 * Check for a private (COWed) page.
2453 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2454 IS_SWAP_FROM_SSE(Entry
) ||
2455 PFN_FROM_SSE(Entry
) != Page
)
2465 * Speculatively set all mappings of the page to clean.
2467 MmSetCleanAllRmaps(Page
);
2470 * If this page was direct mapped from the cache then the cache manager
2471 * will take care of writing it back to disk.
2473 if (DirectMapped
&& !Private
)
2475 ASSERT(SwapEntry
== 0);
2477 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
2479 PageOp
->Status
= STATUS_SUCCESS
;
2480 MmspCompleteAndReleasePageOp(PageOp
);
2481 return(STATUS_SUCCESS
);
2485 * If necessary, allocate an entry in the paging file for this page
2489 SwapEntry
= MmAllocSwapPage();
2492 MmSetDirtyAllRmaps(Page
);
2493 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2494 MmspCompleteAndReleasePageOp(PageOp
);
2495 return(STATUS_PAGEFILE_QUOTA
);
2497 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2501 * Write the page to the pagefile
2503 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2504 if (!NT_SUCCESS(Status
))
2506 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2508 MmSetDirtyAllRmaps(Page
);
2509 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2510 MmspCompleteAndReleasePageOp(PageOp
);
2511 return(STATUS_UNSUCCESSFUL
);
2515 * Otherwise we have succeeded.
2517 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2518 PageOp
->Status
= STATUS_SUCCESS
;
2519 MmspCompleteAndReleasePageOp(PageOp
);
2520 return(STATUS_SUCCESS
);
2524 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2532 PMEMORY_AREA MemoryArea
;
2533 PMM_SECTION_SEGMENT Segment
;
2534 BOOLEAN DoCOW
= FALSE
;
2536 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2538 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2539 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2541 if ((Segment
->WriteCopy
) &&
2542 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2547 if (OldProtect
!= NewProtect
)
2549 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2551 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2552 ULONG Protect
= NewProtect
;
2555 * If we doing COW for this segment then check if the page is
2558 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2564 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2565 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2566 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2567 Page
= MmGetPfnForProcess(Process
, Address
);
2569 Protect
= PAGE_READONLY
;
2570 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2571 IS_SWAP_FROM_SSE(Entry
) ||
2572 PFN_FROM_SSE(Entry
) != Page
)
2574 Protect
= NewProtect
;
2578 if (MmIsPagePresent(Process
, Address
))
2580 MmSetPageProtect(Process
, Address
,
2589 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2590 PMEMORY_AREA MemoryArea
,
2598 ULONG_PTR MaxLength
;
2600 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2601 if (Length
> MaxLength
)
2604 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2605 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2607 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2608 Region
->Protect
!= Protect
)
2610 return STATUS_INVALID_PAGE_PROTECTION
;
2613 *OldProtect
= Region
->Protect
;
2614 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2615 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2616 BaseAddress
, Length
, Region
->Type
, Protect
,
2617 MmAlterViewAttributes
);
2623 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2625 PMEMORY_BASIC_INFORMATION Info
,
2626 PSIZE_T ResultLength
)
2629 PVOID RegionBaseAddress
;
2630 PROS_SECTION_OBJECT Section
;
2631 PMM_SECTION_SEGMENT Segment
;
2633 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2634 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2635 Address
, &RegionBaseAddress
);
2638 return STATUS_UNSUCCESSFUL
;
2641 Section
= MemoryArea
->Data
.SectionData
.Section
;
2642 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2644 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2645 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2646 Info
->Type
= MEM_IMAGE
;
2650 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2651 Info
->Type
= MEM_MAPPED
;
2653 Info
->BaseAddress
= RegionBaseAddress
;
2654 Info
->AllocationProtect
= MemoryArea
->Protect
;
2655 Info
->RegionSize
= Region
->Length
;
2656 Info
->State
= MEM_COMMIT
;
2657 Info
->Protect
= Region
->Protect
;
2659 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2660 return(STATUS_SUCCESS
);
2665 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2670 ULONG SavedSwapEntry
;
2675 Length
= PAGE_ROUND_UP(Segment
->Length
);
2676 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2678 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2681 if (IS_SWAP_FROM_SSE(Entry
))
2683 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2687 Page
= PFN_FROM_SSE(Entry
);
2688 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2689 if (SavedSwapEntry
!= 0)
2691 MmSetSavedSwapEntryPage(Page
, 0);
2692 MmFreeSwapPage(SavedSwapEntry
);
2694 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2696 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2702 MmpDeleteSection(PVOID ObjectBody
)
2704 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2706 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2707 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2712 PMM_SECTION_SEGMENT SectionSegments
;
2715 * NOTE: Section->ImageSection can be NULL for short time
2716 * during the section creating. If we fail for some reason
2717 * until the image section is properly initialized we shouldn't
2718 * process further here.
2720 if (Section
->ImageSection
== NULL
)
2723 SectionSegments
= Section
->ImageSection
->Segments
;
2724 NrSegments
= Section
->ImageSection
->NrSegments
;
2726 for (i
= 0; i
< NrSegments
; i
++)
2728 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2730 MmLockSectionSegment(&SectionSegments
[i
]);
2732 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2733 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2737 MmpFreePageFileSegment(&SectionSegments
[i
]);
2739 MmUnlockSectionSegment(&SectionSegments
[i
]);
2746 * NOTE: Section->Segment can be NULL for short time
2747 * during the section creating.
2749 if (Section
->Segment
== NULL
)
2752 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2754 MmpFreePageFileSegment(Section
->Segment
);
2755 MmFreePageTablesSectionSegment(Section
->Segment
);
2756 ExFreePool(Section
->Segment
);
2757 Section
->Segment
= NULL
;
2761 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2764 if (Section
->FileObject
!= NULL
)
2767 CcRosDereferenceCache(Section
->FileObject
);
2769 ObDereferenceObject(Section
->FileObject
);
2770 Section
->FileObject
= NULL
;
2775 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2777 IN ACCESS_MASK GrantedAccess
,
2778 IN ULONG ProcessHandleCount
,
2779 IN ULONG SystemHandleCount
)
2781 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2782 Object
, ProcessHandleCount
);
2788 MmCreatePhysicalMemorySection(VOID
)
2790 PROS_SECTION_OBJECT PhysSection
;
2792 OBJECT_ATTRIBUTES Obj
;
2793 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2794 LARGE_INTEGER SectionSize
;
2798 * Create the section mapping physical memory
2800 SectionSize
.QuadPart
= 0xFFFFFFFF;
2801 InitializeObjectAttributes(&Obj
,
2806 Status
= MmCreateSection((PVOID
)&PhysSection
,
2810 PAGE_EXECUTE_READWRITE
,
2814 if (!NT_SUCCESS(Status
))
2816 DPRINT1("Failed to create PhysicalMemory section\n");
2817 KeBugCheck(MEMORY_MANAGEMENT
);
2819 Status
= ObInsertObject(PhysSection
,
2825 if (!NT_SUCCESS(Status
))
2827 ObDereferenceObject(PhysSection
);
2829 ObCloseHandle(Handle
, KernelMode
);
2830 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2831 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2833 return(STATUS_SUCCESS
);
2839 MmInitSectionImplementation(VOID
)
2841 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2842 UNICODE_STRING Name
;
2844 DPRINT("Creating Section Object Type\n");
2846 /* Initialize the Section object type */
2847 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2848 RtlInitUnicodeString(&Name
, L
"Section");
2849 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2850 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2851 ObjectTypeInitializer
.PoolType
= PagedPool
;
2852 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2853 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2854 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2855 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2856 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2857 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2859 MmCreatePhysicalMemorySection();
2861 return(STATUS_SUCCESS
);
2866 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2867 ACCESS_MASK DesiredAccess
,
2868 POBJECT_ATTRIBUTES ObjectAttributes
,
2869 PLARGE_INTEGER UMaximumSize
,
2870 ULONG SectionPageProtection
,
2871 ULONG AllocationAttributes
)
2873 * Create a section which is backed by the pagefile
2876 LARGE_INTEGER MaximumSize
;
2877 PROS_SECTION_OBJECT Section
;
2878 PMM_SECTION_SEGMENT Segment
;
2881 if (UMaximumSize
== NULL
)
2883 return(STATUS_UNSUCCESSFUL
);
2885 MaximumSize
= *UMaximumSize
;
2888 * Create the section
2890 Status
= ObCreateObject(ExGetPreviousMode(),
2891 MmSectionObjectType
,
2893 ExGetPreviousMode(),
2895 sizeof(ROS_SECTION_OBJECT
),
2898 (PVOID
*)(PVOID
)&Section
);
2899 if (!NT_SUCCESS(Status
))
2907 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2908 Section
->SectionPageProtection
= SectionPageProtection
;
2909 Section
->AllocationAttributes
= AllocationAttributes
;
2910 Section
->MaximumSize
= MaximumSize
;
2911 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2912 TAG_MM_SECTION_SEGMENT
);
2913 if (Segment
== NULL
)
2915 ObDereferenceObject(Section
);
2916 return(STATUS_NO_MEMORY
);
2918 Section
->Segment
= Segment
;
2919 Segment
->ReferenceCount
= 1;
2920 ExInitializeFastMutex(&Segment
->Lock
);
2921 Segment
->FileOffset
= 0;
2922 Segment
->Protection
= SectionPageProtection
;
2923 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2924 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2925 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2926 Segment
->WriteCopy
= FALSE
;
2927 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2928 Segment
->VirtualAddress
= 0;
2929 Segment
->Characteristics
= 0;
2930 *SectionObject
= Section
;
2931 return(STATUS_SUCCESS
);
2937 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2938 ACCESS_MASK DesiredAccess
,
2939 POBJECT_ATTRIBUTES ObjectAttributes
,
2940 PLARGE_INTEGER UMaximumSize
,
2941 ULONG SectionPageProtection
,
2942 ULONG AllocationAttributes
,
2945 * Create a section backed by a data file
2948 PROS_SECTION_OBJECT Section
;
2950 LARGE_INTEGER MaximumSize
;
2951 PFILE_OBJECT FileObject
;
2952 PMM_SECTION_SEGMENT Segment
;
2954 IO_STATUS_BLOCK Iosb
;
2955 LARGE_INTEGER Offset
;
2957 FILE_STANDARD_INFORMATION FileInfo
;
2961 * Create the section
2963 Status
= ObCreateObject(ExGetPreviousMode(),
2964 MmSectionObjectType
,
2966 ExGetPreviousMode(),
2968 sizeof(ROS_SECTION_OBJECT
),
2971 (PVOID
*)(PVOID
)&Section
);
2972 if (!NT_SUCCESS(Status
))
2979 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2980 Section
->SectionPageProtection
= SectionPageProtection
;
2981 Section
->AllocationAttributes
= AllocationAttributes
;
2984 * Check file access required
2986 if (SectionPageProtection
& PAGE_READWRITE
||
2987 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2989 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2993 FileAccess
= FILE_READ_DATA
;
2997 * Reference the file handle
2999 Status
= ObReferenceObjectByHandle(FileHandle
,
3002 ExGetPreviousMode(),
3003 (PVOID
*)(PVOID
)&FileObject
,
3005 if (!NT_SUCCESS(Status
))
3007 ObDereferenceObject(Section
);
3012 * FIXME: This is propably not entirely correct. We can't look into
3013 * the standard FCB header because it might not be initialized yet
3014 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
3015 * standard file information is filled on first request).
3017 Status
= IoQueryFileInformation(FileObject
,
3018 FileStandardInformation
,
3019 sizeof(FILE_STANDARD_INFORMATION
),
3022 Iosb
.Information
= Length
;
3023 if (!NT_SUCCESS(Status
))
3025 ObDereferenceObject(Section
);
3026 ObDereferenceObject(FileObject
);
3031 * FIXME: Revise this once a locking order for file size changes is
3034 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
3036 MaximumSize
= *UMaximumSize
;
3040 MaximumSize
= FileInfo
.EndOfFile
;
3041 /* Mapping zero-sized files isn't allowed. */
3042 if (MaximumSize
.QuadPart
== 0)
3044 ObDereferenceObject(Section
);
3045 ObDereferenceObject(FileObject
);
3046 return STATUS_FILE_INVALID
;
3050 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3052 Status
= IoSetInformation(FileObject
,
3053 FileAllocationInformation
,
3054 sizeof(LARGE_INTEGER
),
3056 if (!NT_SUCCESS(Status
))
3058 ObDereferenceObject(Section
);
3059 ObDereferenceObject(FileObject
);
3060 return(STATUS_SECTION_NOT_EXTENDED
);
3064 if (FileObject
->SectionObjectPointer
== NULL
||
3065 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3068 * Read a bit so caching is initiated for the file object.
3069 * This is only needed because MiReadPage currently cannot
3070 * handle non-cached streams.
3072 Offset
.QuadPart
= 0;
3073 Status
= ZwReadFile(FileHandle
,
3082 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3084 ObDereferenceObject(Section
);
3085 ObDereferenceObject(FileObject
);
3088 if (FileObject
->SectionObjectPointer
== NULL
||
3089 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3091 /* FIXME: handle this situation */
3092 ObDereferenceObject(Section
);
3093 ObDereferenceObject(FileObject
);
3094 return STATUS_INVALID_PARAMETER
;
3101 Status
= MmspWaitForFileLock(FileObject
);
3102 if (Status
!= STATUS_SUCCESS
)
3104 ObDereferenceObject(Section
);
3105 ObDereferenceObject(FileObject
);
3110 * If this file hasn't been mapped as a data file before then allocate a
3111 * section segment to describe the data file mapping
3113 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3115 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3116 TAG_MM_SECTION_SEGMENT
);
3117 if (Segment
== NULL
)
3119 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3120 ObDereferenceObject(Section
);
3121 ObDereferenceObject(FileObject
);
3122 return(STATUS_NO_MEMORY
);
3124 Section
->Segment
= Segment
;
3125 Segment
->ReferenceCount
= 1;
3126 ExInitializeFastMutex(&Segment
->Lock
);
3128 * Set the lock before assigning the segment to the file object
3130 ExAcquireFastMutex(&Segment
->Lock
);
3131 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3133 Segment
->FileOffset
= 0;
3134 Segment
->Protection
= SectionPageProtection
;
3135 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3136 Segment
->Characteristics
= 0;
3137 Segment
->WriteCopy
= FALSE
;
3138 if (AllocationAttributes
& SEC_RESERVE
)
3140 Segment
->Length
= Segment
->RawLength
= 0;
3144 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3145 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3147 Segment
->VirtualAddress
= 0;
3148 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
3153 * If the file is already mapped as a data file then we may need
3157 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3159 Section
->Segment
= Segment
;
3160 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3161 MmLockSectionSegment(Segment
);
3163 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
3164 !(AllocationAttributes
& SEC_RESERVE
))
3166 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3167 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3170 MmUnlockSectionSegment(Segment
);
3171 Section
->FileObject
= FileObject
;
3172 Section
->MaximumSize
= MaximumSize
;
3174 CcRosReferenceCache(FileObject
);
3176 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3177 *SectionObject
= Section
;
3178 return(STATUS_SUCCESS
);
3182 TODO: not that great (declaring loaders statically, having to declare all of
3183 them, having to keep them extern, etc.), will fix in the future
3185 extern NTSTATUS NTAPI PeFmtCreateSection
3187 IN CONST VOID
* FileHeader
,
3188 IN SIZE_T FileHeaderSize
,
3190 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3192 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3193 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3196 extern NTSTATUS NTAPI ElfFmtCreateSection
3198 IN CONST VOID
* FileHeader
,
3199 IN SIZE_T FileHeaderSize
,
3201 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3203 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3204 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3207 /* TODO: this is a standard DDK/PSDK macro */
3208 #ifndef RTL_NUMBER_OF
3209 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3212 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3223 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3225 SIZE_T SizeOfSegments
;
3226 PMM_SECTION_SEGMENT Segments
;
3228 /* TODO: check for integer overflow */
3229 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3231 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3233 TAG_MM_SECTION_SEGMENT
);
3236 RtlZeroMemory(Segments
, SizeOfSegments
);
3244 ExeFmtpReadFile(IN PVOID File
,
3245 IN PLARGE_INTEGER Offset
,
3248 OUT PVOID
* AllocBase
,
3249 OUT PULONG ReadSize
)
3252 LARGE_INTEGER FileOffset
;
3254 ULONG OffsetAdjustment
;
3259 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3263 KeBugCheck(MEMORY_MANAGEMENT
);
3266 FileOffset
= *Offset
;
3268 /* Negative/special offset: it cannot be used in this context */
3269 if(FileOffset
.u
.HighPart
< 0)
3271 KeBugCheck(MEMORY_MANAGEMENT
);
3274 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3275 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3276 FileOffset
.u
.LowPart
= AdjustOffset
;
3278 BufferSize
= Length
+ OffsetAdjustment
;
3279 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3282 * It's ok to use paged pool, because this is a temporary buffer only used in
3283 * the loading of executables. The assumption is that MmCreateSection is
3284 * always called at low IRQLs and that these buffers don't survive a brief
3285 * initialization phase
3287 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3292 KeBugCheck(MEMORY_MANAGEMENT
);
3298 Status
= MmspPageRead(File
,
3305 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
3306 * nothing will work. But using ZwReadFile is wrong, and using its side effects
3307 * to initialize internal state is even worse. Our cache manager is in need of
3311 IO_STATUS_BLOCK Iosb
;
3313 Status
= ZwReadFile(File
,
3323 if(NT_SUCCESS(Status
))
3325 UsedSize
= Iosb
.Information
;
3330 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3332 Status
= STATUS_IN_PAGE_ERROR
;
3333 ASSERT(!NT_SUCCESS(Status
));
3336 if(NT_SUCCESS(Status
))
3338 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3339 *AllocBase
= Buffer
;
3340 *ReadSize
= UsedSize
- OffsetAdjustment
;
3344 ExFreePoolWithTag(Buffer
, 'rXmM');
3351 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3352 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3353 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3358 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3362 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3364 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3365 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
3372 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3376 MmspAssertSegmentsSorted(ImageSectionObject
);
3378 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3380 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
3384 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3385 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3386 ImageSectionObject
->Segments
[i
- 1].Length
));
3394 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3398 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3400 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
3401 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
3409 MmspCompareSegments(const void * x
,
3412 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3413 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3416 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
3417 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3421 * Ensures an image section's segments are sorted in memory
3426 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3429 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3431 MmspAssertSegmentsSorted(ImageSectionObject
);
3435 qsort(ImageSectionObject
->Segments
,
3436 ImageSectionObject
->NrSegments
,
3437 sizeof(ImageSectionObject
->Segments
[0]),
3438 MmspCompareSegments
);
3444 * Ensures an image section's segments don't overlap in memory and don't have
3445 * gaps and don't have a null size. We let them map to overlapping file regions,
3446 * though - that's not necessarily an error
3451 MmspCheckSegmentBounds
3453 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3459 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3461 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3465 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3467 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3469 if(ImageSectionObject
->Segments
[i
].Length
== 0)
3477 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3478 * page could be OK (Windows seems to be OK with them), and larger gaps
3479 * could lead to image sections spanning several discontiguous regions
3480 * (NtMapViewOfSection could then refuse to map them, and they could
3481 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3483 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3484 ImageSectionObject
->Segments
[i
- 1].Length
) !=
3485 ImageSectionObject
->Segments
[i
].VirtualAddress
)
3496 * Merges and pads an image section's segments until they all are page-aligned
3497 * and have a size that is a multiple of the page size
3502 MmspPageAlignSegments
3504 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3510 PMM_SECTION_SEGMENT EffectiveSegment
;
3512 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3514 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3519 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3521 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3524 * The first segment requires special handling
3528 ULONG_PTR VirtualAddress
;
3529 ULONG_PTR VirtualOffset
;
3531 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3533 /* Round down the virtual address to the nearest page */
3534 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3536 /* Round up the virtual size to the nearest page */
3537 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3538 EffectiveSegment
->VirtualAddress
;
3540 /* Adjust the raw address and size */
3541 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3543 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3549 * Garbage in, garbage out: unaligned base addresses make the file
3550 * offset point in curious and odd places, but that's what we were
3553 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3554 EffectiveSegment
->RawLength
+= VirtualOffset
;
3558 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3559 ULONG_PTR EndOfEffectiveSegment
;
3561 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3562 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3565 * The current segment begins exactly where the current effective
3566 * segment ended, therefore beginning a new effective segment
3568 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3571 ASSERT(LastSegment
<= i
);
3572 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3574 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3576 if (LastSegment
!= i
)
3579 * Copy the current segment. If necessary, the effective segment
3580 * will be expanded later
3582 *EffectiveSegment
= *Segment
;
3586 * Page-align the virtual size. We know for sure the virtual address
3589 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3590 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3593 * The current segment is still part of the current effective segment:
3594 * extend the effective segment to reflect this
3596 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3598 static const ULONG FlagsToProtection
[16] =
3606 PAGE_EXECUTE_READWRITE
,
3607 PAGE_EXECUTE_READWRITE
,
3612 PAGE_EXECUTE_WRITECOPY
,
3613 PAGE_EXECUTE_WRITECOPY
,
3614 PAGE_EXECUTE_WRITECOPY
,
3615 PAGE_EXECUTE_WRITECOPY
3618 unsigned ProtectionFlags
;
3621 * Extend the file size
3624 /* Unaligned segments must be contiguous within the file */
3625 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3626 EffectiveSegment
->RawLength
))
3631 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3634 * Extend the virtual size
3636 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3638 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3639 EffectiveSegment
->VirtualAddress
;
3642 * Merge the protection
3644 EffectiveSegment
->Protection
|= Segment
->Protection
;
3646 /* Clean up redundance */
3647 ProtectionFlags
= 0;
3649 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3650 ProtectionFlags
|= 1 << 0;
3652 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3653 ProtectionFlags
|= 1 << 1;
3655 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3656 ProtectionFlags
|= 1 << 2;
3658 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3659 ProtectionFlags
|= 1 << 3;
3661 ASSERT(ProtectionFlags
< 16);
3662 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3664 /* If a segment was required to be shared and cannot, fail */
3665 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3666 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3672 * We assume no holes between segments at this point
3676 KeBugCheck(MEMORY_MANAGEMENT
);
3680 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3686 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3687 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3689 LARGE_INTEGER Offset
;
3691 PVOID FileHeaderBuffer
;
3692 ULONG FileHeaderSize
;
3694 ULONG OldNrSegments
;
3699 * Read the beginning of the file (2 pages). Should be enough to contain
3700 * all (or most) of the headers
3702 Offset
.QuadPart
= 0;
3704 /* FIXME: use FileObject instead of FileHandle */
3705 Status
= ExeFmtpReadFile (FileHandle
,
3712 if (!NT_SUCCESS(Status
))
3715 if (FileHeaderSize
== 0)
3717 ExFreePool(FileHeaderBuffer
);
3718 return STATUS_UNSUCCESSFUL
;
3722 * Look for a loader that can handle this executable
3724 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3726 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3729 /* FIXME: use FileObject instead of FileHandle */
3730 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3736 ExeFmtpAllocateSegments
);
3738 if (!NT_SUCCESS(Status
))
3740 if (ImageSectionObject
->Segments
)
3742 ExFreePool(ImageSectionObject
->Segments
);
3743 ImageSectionObject
->Segments
= NULL
;
3747 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3751 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3754 * No loader handled the format
3756 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3758 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3759 ASSERT(!NT_SUCCESS(Status
));
3762 if (!NT_SUCCESS(Status
))
3765 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3770 /* FIXME? are these values platform-dependent? */
3771 if(ImageSectionObject
->StackReserve
== 0)
3772 ImageSectionObject
->StackReserve
= 0x40000;
3774 if(ImageSectionObject
->StackCommit
== 0)
3775 ImageSectionObject
->StackCommit
= 0x1000;
3777 if(ImageSectionObject
->ImageBase
== 0)
3779 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3780 ImageSectionObject
->ImageBase
= 0x10000000;
3782 ImageSectionObject
->ImageBase
= 0x00400000;
3786 * And now the fun part: fixing the segments
3789 /* Sort them by virtual address */
3790 MmspSortSegments(ImageSectionObject
, Flags
);
3792 /* Ensure they don't overlap in memory */
3793 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3794 return STATUS_INVALID_IMAGE_FORMAT
;
3796 /* Ensure they are aligned */
3797 OldNrSegments
= ImageSectionObject
->NrSegments
;
3799 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3800 return STATUS_INVALID_IMAGE_FORMAT
;
3802 /* Trim them if the alignment phase merged some of them */
3803 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3805 PMM_SECTION_SEGMENT Segments
;
3806 SIZE_T SizeOfSegments
;
3808 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3810 Segments
= ExAllocatePoolWithTag(PagedPool
,
3812 TAG_MM_SECTION_SEGMENT
);
3814 if (Segments
== NULL
)
3815 return STATUS_INSUFFICIENT_RESOURCES
;
3817 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3818 ExFreePool(ImageSectionObject
->Segments
);
3819 ImageSectionObject
->Segments
= Segments
;
3822 /* And finish their initialization */
3823 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3825 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3826 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3828 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3829 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3832 ASSERT(NT_SUCCESS(Status
));
3837 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3838 ACCESS_MASK DesiredAccess
,
3839 POBJECT_ATTRIBUTES ObjectAttributes
,
3840 PLARGE_INTEGER UMaximumSize
,
3841 ULONG SectionPageProtection
,
3842 ULONG AllocationAttributes
,
3845 PROS_SECTION_OBJECT Section
;
3847 PFILE_OBJECT FileObject
;
3848 PMM_SECTION_SEGMENT SectionSegments
;
3849 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3851 ULONG FileAccess
= 0;
3854 * Check file access required
3856 if (SectionPageProtection
& PAGE_READWRITE
||
3857 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3859 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3863 FileAccess
= FILE_READ_DATA
;
3867 * Reference the file handle
3869 Status
= ObReferenceObjectByHandle(FileHandle
,
3872 ExGetPreviousMode(),
3873 (PVOID
*)(PVOID
)&FileObject
,
3876 if (!NT_SUCCESS(Status
))
3882 * Create the section
3884 Status
= ObCreateObject (ExGetPreviousMode(),
3885 MmSectionObjectType
,
3887 ExGetPreviousMode(),
3889 sizeof(ROS_SECTION_OBJECT
),
3892 (PVOID
*)(PVOID
)&Section
);
3893 if (!NT_SUCCESS(Status
))
3895 ObDereferenceObject(FileObject
);
3902 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3903 Section
->SectionPageProtection
= SectionPageProtection
;
3904 Section
->AllocationAttributes
= AllocationAttributes
;
3908 * Initialized caching for this file object if previously caching
3909 * was initialized for the same on disk file
3911 Status
= CcTryToInitializeFileCache(FileObject
);
3913 Status
= STATUS_SUCCESS
;
3916 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3918 NTSTATUS StatusExeFmt
;
3920 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3921 if (ImageSectionObject
== NULL
)
3923 ObDereferenceObject(FileObject
);
3924 ObDereferenceObject(Section
);
3925 return(STATUS_NO_MEMORY
);
3928 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3930 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3932 if (!NT_SUCCESS(StatusExeFmt
))
3934 if(ImageSectionObject
->Segments
!= NULL
)
3935 ExFreePool(ImageSectionObject
->Segments
);
3937 ExFreePool(ImageSectionObject
);
3938 ObDereferenceObject(Section
);
3939 ObDereferenceObject(FileObject
);
3940 return(StatusExeFmt
);
3943 Section
->ImageSection
= ImageSectionObject
;
3944 ASSERT(ImageSectionObject
->Segments
);
3949 Status
= MmspWaitForFileLock(FileObject
);
3950 if (!NT_SUCCESS(Status
))
3952 ExFreePool(ImageSectionObject
->Segments
);
3953 ExFreePool(ImageSectionObject
);
3954 ObDereferenceObject(Section
);
3955 ObDereferenceObject(FileObject
);
3959 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3960 ImageSectionObject
, NULL
))
3963 * An other thread has initialized the same image in the background
3965 ExFreePool(ImageSectionObject
->Segments
);
3966 ExFreePool(ImageSectionObject
);
3967 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3968 Section
->ImageSection
= ImageSectionObject
;
3969 SectionSegments
= ImageSectionObject
->Segments
;
3971 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3973 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3977 Status
= StatusExeFmt
;
3984 Status
= MmspWaitForFileLock(FileObject
);
3985 if (Status
!= STATUS_SUCCESS
)
3987 ObDereferenceObject(Section
);
3988 ObDereferenceObject(FileObject
);
3992 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3993 Section
->ImageSection
= ImageSectionObject
;
3994 SectionSegments
= ImageSectionObject
->Segments
;
3997 * Otherwise just reference all the section segments
3999 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
4001 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
4004 Status
= STATUS_SUCCESS
;
4006 Section
->FileObject
= FileObject
;
4008 CcRosReferenceCache(FileObject
);
4010 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
4011 *SectionObject
= Section
;
4018 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
4019 PROS_SECTION_OBJECT Section
,
4020 PMM_SECTION_SEGMENT Segment
,
4025 ULONG AllocationType
)
4029 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4031 BoundaryAddressMultiple
.QuadPart
= 0;
4033 Status
= MmCreateMemoryArea(AddressSpace
,
4034 MEMORY_AREA_SECTION_VIEW
,
4041 BoundaryAddressMultiple
);
4042 if (!NT_SUCCESS(Status
))
4044 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
4045 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
4049 ObReferenceObject((PVOID
)Section
);
4051 MArea
->Data
.SectionData
.Segment
= Segment
;
4052 MArea
->Data
.SectionData
.Section
= Section
;
4053 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
4054 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
4055 ViewSize
, 0, Protect
);
4057 return(STATUS_SUCCESS
);
4063 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
4064 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4067 PFILE_OBJECT FileObject
;
4070 SWAPENTRY SavedSwapEntry
;
4073 PROS_SECTION_OBJECT Section
;
4074 PMM_SECTION_SEGMENT Segment
;
4075 PMMSUPPORT AddressSpace
;
4078 AddressSpace
= (PMMSUPPORT
)Context
;
4079 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4081 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4083 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
4084 MemoryArea
->Data
.SectionData
.ViewOffset
;
4086 Section
= MemoryArea
->Data
.SectionData
.Section
;
4087 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4089 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4093 MmUnlockSectionSegment(Segment
);
4094 MmUnlockAddressSpace(AddressSpace
);
4096 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4097 if (Status
!= STATUS_SUCCESS
)
4099 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4100 KeBugCheck(MEMORY_MANAGEMENT
);
4103 MmLockAddressSpace(AddressSpace
);
4104 MmLockSectionSegment(Segment
);
4105 MmspCompleteAndReleasePageOp(PageOp
);
4106 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4109 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
4112 * For a dirty, datafile, non-private page mark it as dirty in the
4115 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4117 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4119 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4120 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4122 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
4124 ASSERT(SwapEntry
== 0);
4133 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4135 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4136 KeBugCheck(MEMORY_MANAGEMENT
);
4138 MmFreeSwapPage(SwapEntry
);
4142 if (IS_SWAP_FROM_SSE(Entry
) ||
4143 Page
!= PFN_FROM_SSE(Entry
))
4148 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4150 DPRINT1("Found a private page in a pagefile section.\n");
4151 KeBugCheck(MEMORY_MANAGEMENT
);
4154 * Just dereference private pages
4156 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4157 if (SavedSwapEntry
!= 0)
4159 MmFreeSwapPage(SavedSwapEntry
);
4160 MmSetSavedSwapEntryPage(Page
, 0);
4162 MmDeleteRmap(Page
, Process
, Address
);
4163 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4167 MmDeleteRmap(Page
, Process
, Address
);
4168 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4174 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4178 PMEMORY_AREA MemoryArea
;
4179 PROS_SECTION_OBJECT Section
;
4180 PMM_SECTION_SEGMENT Segment
;
4181 PLIST_ENTRY CurrentEntry
;
4182 PMM_REGION CurrentRegion
;
4183 PLIST_ENTRY RegionListHead
;
4185 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4187 if (MemoryArea
== NULL
)
4189 return(STATUS_UNSUCCESSFUL
);
4192 MemoryArea
->DeleteInProgress
= TRUE
;
4193 Section
= MemoryArea
->Data
.SectionData
.Section
;
4194 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4196 MmLockSectionSegment(Segment
);
4198 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4199 while (!IsListEmpty(RegionListHead
))
4201 CurrentEntry
= RemoveHeadList(RegionListHead
);
4202 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4203 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4206 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4208 Status
= MmFreeMemoryArea(AddressSpace
,
4215 Status
= MmFreeMemoryArea(AddressSpace
,
4220 MmUnlockSectionSegment(Segment
);
4221 ObDereferenceObject(Section
);
4229 MmUnmapViewOfSection(PEPROCESS Process
,
4233 PMEMORY_AREA MemoryArea
;
4234 PMMSUPPORT AddressSpace
;
4235 PROS_SECTION_OBJECT Section
;
4238 PVOID ImageBaseAddress
= 0;
4240 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4241 Process
, BaseAddress
);
4245 AddressSpace
= &Process
->Vm
;
4247 MmLockAddressSpace(AddressSpace
);
4248 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4250 if (MemoryArea
== NULL
||
4251 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4252 MemoryArea
->DeleteInProgress
)
4254 MmUnlockAddressSpace(AddressSpace
);
4255 return STATUS_NOT_MAPPED_VIEW
;
4258 MemoryArea
->DeleteInProgress
= TRUE
;
4260 while (MemoryArea
->PageOpCount
)
4262 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4266 Offset
-= PAGE_SIZE
;
4267 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4268 MemoryArea
->Data
.SectionData
.Segment
,
4269 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4272 MmUnlockAddressSpace(AddressSpace
);
4273 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4274 if (Status
!= STATUS_SUCCESS
)
4276 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4277 KeBugCheck(MEMORY_MANAGEMENT
);
4279 MmLockAddressSpace(AddressSpace
);
4280 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4282 if (MemoryArea
== NULL
||
4283 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4285 MmUnlockAddressSpace(AddressSpace
);
4286 return STATUS_NOT_MAPPED_VIEW
;
4293 Section
= MemoryArea
->Data
.SectionData
.Section
;
4295 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4299 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4300 PMM_SECTION_SEGMENT SectionSegments
;
4301 PMM_SECTION_SEGMENT Segment
;
4303 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4304 ImageSectionObject
= Section
->ImageSection
;
4305 SectionSegments
= ImageSectionObject
->Segments
;
4306 NrSegments
= ImageSectionObject
->NrSegments
;
4308 /* Search for the current segment within the section segments
4309 * and calculate the image base address */
4310 for (i
= 0; i
< NrSegments
; i
++)
4312 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4314 if (Segment
== &SectionSegments
[i
])
4316 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4321 if (i
>= NrSegments
)
4323 KeBugCheck(MEMORY_MANAGEMENT
);
4326 for (i
= 0; i
< NrSegments
; i
++)
4328 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4330 PVOID SBaseAddress
= (PVOID
)
4331 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4333 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4339 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4342 MmUnlockAddressSpace(AddressSpace
);
4344 /* Notify debugger */
4345 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4347 return(STATUS_SUCCESS
);
4354 * Queries the information of a section object.
4356 * @param SectionHandle
4357 * Handle to the section object. It must be opened with SECTION_QUERY
4359 * @param SectionInformationClass
4360 * Index to a certain information structure. Can be either
4361 * SectionBasicInformation or SectionImageInformation. The latter
4362 * is valid only for sections that were created with the SEC_IMAGE
4364 * @param SectionInformation
4365 * Caller supplies storage for resulting information.
4367 * Size of the supplied storage.
4368 * @param ResultLength
4376 NtQuerySection(IN HANDLE SectionHandle
,
4377 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4378 OUT PVOID SectionInformation
,
4379 IN SIZE_T SectionInformationLength
,
4380 OUT PSIZE_T ResultLength OPTIONAL
)
4382 PROS_SECTION_OBJECT Section
;
4383 KPROCESSOR_MODE PreviousMode
;
4387 PreviousMode
= ExGetPreviousMode();
4389 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4391 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4393 SectionInformationLength
,
4398 if(!NT_SUCCESS(Status
))
4400 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4404 Status
= ObReferenceObjectByHandle(SectionHandle
,
4406 MmSectionObjectType
,
4408 (PVOID
*)(PVOID
)&Section
,
4410 if (NT_SUCCESS(Status
))
4412 switch (SectionInformationClass
)
4414 case SectionBasicInformation
:
4416 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4420 Sbi
->Attributes
= Section
->AllocationAttributes
;
4421 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4423 Sbi
->BaseAddress
= 0;
4424 Sbi
->Size
.QuadPart
= 0;
4428 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4429 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4432 if (ResultLength
!= NULL
)
4434 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4436 Status
= STATUS_SUCCESS
;
4438 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4440 Status
= _SEH2_GetExceptionCode();
4447 case SectionImageInformation
:
4449 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4453 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4454 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4456 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4457 ImageSectionObject
= Section
->ImageSection
;
4459 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4460 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4461 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4462 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4463 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4464 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4465 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4466 Sii
->Machine
= ImageSectionObject
->Machine
;
4467 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4470 if (ResultLength
!= NULL
)
4472 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4474 Status
= STATUS_SUCCESS
;
4476 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4478 Status
= _SEH2_GetExceptionCode();
4486 ObDereferenceObject(Section
);
4492 /**********************************************************************
4494 * MmMapViewOfSection
4497 * Maps a view of a section into the virtual address space of a
4502 * Pointer to the section object.
4505 * Pointer to the process.
4508 * Desired base address (or NULL) on entry;
4509 * Actual base address of the view on exit.
4512 * Number of high order address bits that must be zero.
4515 * Size in bytes of the initially committed section of
4519 * Offset in bytes from the beginning of the section
4520 * to the beginning of the view.
4523 * Desired length of map (or zero to map all) on entry
4524 * Actual length mapped on exit.
4526 * InheritDisposition
4527 * Specified how the view is to be shared with
4531 * Type of allocation for the pages.
4534 * Protection for the committed region of the view.
4542 MmMapViewOfSection(IN PVOID SectionObject
,
4543 IN PEPROCESS Process
,
4544 IN OUT PVOID
*BaseAddress
,
4545 IN ULONG_PTR ZeroBits
,
4546 IN SIZE_T CommitSize
,
4547 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4548 IN OUT PSIZE_T ViewSize
,
4549 IN SECTION_INHERIT InheritDisposition
,
4550 IN ULONG AllocationType
,
4553 PROS_SECTION_OBJECT Section
;
4554 PMMSUPPORT AddressSpace
;
4556 NTSTATUS Status
= STATUS_SUCCESS
;
4558 if ((ULONG_PTR
)SectionObject
& 1)
4560 return MmMapViewOfArm3Section((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4574 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4576 return STATUS_INVALID_PAGE_PROTECTION
;
4580 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4581 AddressSpace
= &Process
->Vm
;
4583 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4585 MmLockAddressSpace(AddressSpace
);
4587 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4591 ULONG_PTR ImageBase
;
4593 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4594 PMM_SECTION_SEGMENT SectionSegments
;
4596 ImageSectionObject
= Section
->ImageSection
;
4597 SectionSegments
= ImageSectionObject
->Segments
;
4598 NrSegments
= ImageSectionObject
->NrSegments
;
4601 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4604 ImageBase
= ImageSectionObject
->ImageBase
;
4608 for (i
= 0; i
< NrSegments
; i
++)
4610 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4612 ULONG_PTR MaxExtent
;
4613 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4614 SectionSegments
[i
].Length
;
4615 ImageSize
= max(ImageSize
, MaxExtent
);
4619 ImageSectionObject
->ImageSize
= ImageSize
;
4621 /* Check there is enough space to map the section at that point. */
4622 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4623 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4625 /* Fail if the user requested a fixed base address. */
4626 if ((*BaseAddress
) != NULL
)
4628 MmUnlockAddressSpace(AddressSpace
);
4629 return(STATUS_UNSUCCESSFUL
);
4631 /* Otherwise find a gap to map the image. */
4632 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4635 MmUnlockAddressSpace(AddressSpace
);
4636 return(STATUS_UNSUCCESSFUL
);
4640 for (i
= 0; i
< NrSegments
; i
++)
4642 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4644 PVOID SBaseAddress
= (PVOID
)
4645 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4646 MmLockSectionSegment(&SectionSegments
[i
]);
4647 Status
= MmMapViewOfSegment(AddressSpace
,
4649 &SectionSegments
[i
],
4651 SectionSegments
[i
].Length
,
4652 SectionSegments
[i
].Protection
,
4655 MmUnlockSectionSegment(&SectionSegments
[i
]);
4656 if (!NT_SUCCESS(Status
))
4658 MmUnlockAddressSpace(AddressSpace
);
4664 *BaseAddress
= (PVOID
)ImageBase
;
4668 /* check for write access */
4669 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4670 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4672 MmUnlockAddressSpace(AddressSpace
);
4673 return STATUS_SECTION_PROTECTION
;
4675 /* check for read access */
4676 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4677 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4679 MmUnlockAddressSpace(AddressSpace
);
4680 return STATUS_SECTION_PROTECTION
;
4682 /* check for execute access */
4683 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4684 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4686 MmUnlockAddressSpace(AddressSpace
);
4687 return STATUS_SECTION_PROTECTION
;
4690 if (ViewSize
== NULL
)
4692 /* Following this pointer would lead to us to the dark side */
4693 /* What to do? Bugcheck? Return status? Do the mambo? */
4694 KeBugCheck(MEMORY_MANAGEMENT
);
4697 if (SectionOffset
== NULL
)
4703 ViewOffset
= SectionOffset
->u
.LowPart
;
4706 if ((ViewOffset
% PAGE_SIZE
) != 0)
4708 MmUnlockAddressSpace(AddressSpace
);
4709 return(STATUS_MAPPED_ALIGNMENT
);
4712 if ((*ViewSize
) == 0)
4714 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4716 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4718 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4721 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4723 MmLockSectionSegment(Section
->Segment
);
4724 Status
= MmMapViewOfSegment(AddressSpace
,
4731 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4732 MmUnlockSectionSegment(Section
->Segment
);
4733 if (!NT_SUCCESS(Status
))
4735 MmUnlockAddressSpace(AddressSpace
);
4740 MmUnlockAddressSpace(AddressSpace
);
4742 return(STATUS_SUCCESS
);
4749 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4750 IN PLARGE_INTEGER NewFileSize
)
4752 /* Check whether an ImageSectionObject exists */
4753 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4755 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4759 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4761 PMM_SECTION_SEGMENT Segment
;
4763 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4766 if (Segment
->ReferenceCount
!= 0)
4768 /* Check size of file */
4769 if (SectionObjectPointer
->SharedCacheMap
)
4771 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4772 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4780 /* Something must gone wrong
4781 * how can we have a Section but no
4783 DPRINT("ERROR: DataSectionObject without reference!\n");
4787 DPRINT("FIXME: didn't check for outstanding write probes\n");
4799 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4800 IN MMFLUSH_TYPE FlushType
)
4804 case MmFlushForDelete
:
4805 if (SectionObjectPointer
->ImageSectionObject
||
4806 SectionObjectPointer
->DataSectionObject
)
4811 CcRosSetRemoveOnClose(SectionObjectPointer
);
4814 case MmFlushForWrite
:
4824 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4825 OUT PVOID
* MappedBase
,
4826 IN OUT PSIZE_T ViewSize
)
4828 PROS_SECTION_OBJECT Section
;
4829 PMMSUPPORT AddressSpace
;
4833 if ((ULONG_PTR
)SectionObject
& 1)
4835 extern PVOID MmSession
;
4836 return MiMapViewInSystemSpace((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4842 DPRINT("MmMapViewInSystemSpace() called\n");
4844 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4845 AddressSpace
= MmGetKernelAddressSpace();
4847 MmLockAddressSpace(AddressSpace
);
4850 if ((*ViewSize
) == 0)
4852 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4854 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4856 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4859 MmLockSectionSegment(Section
->Segment
);
4862 Status
= MmMapViewOfSegment(AddressSpace
,
4871 MmUnlockSectionSegment(Section
->Segment
);
4872 MmUnlockAddressSpace(AddressSpace
);
4881 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4883 PMMSUPPORT AddressSpace
;
4886 DPRINT("MmUnmapViewInSystemSpace() called\n");
4888 AddressSpace
= MmGetKernelAddressSpace();
4890 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4896 /**********************************************************************
4901 * Creates a section object.
4904 * SectionObject (OUT)
4905 * Caller supplied storage for the resulting pointer
4906 * to a SECTION_OBJECT instance;
4909 * Specifies the desired access to the section can be a
4911 * STANDARD_RIGHTS_REQUIRED |
4913 * SECTION_MAP_WRITE |
4914 * SECTION_MAP_READ |
4915 * SECTION_MAP_EXECUTE
4917 * ObjectAttributes [OPTIONAL]
4918 * Initialized attributes for the object can be used
4919 * to create a named section;
4922 * Maximizes the size of the memory section. Must be
4923 * non-NULL for a page-file backed section.
4924 * If value specified for a mapped file and the file is
4925 * not large enough, file will be extended.
4927 * SectionPageProtection
4928 * Can be a combination of:
4934 * AllocationAttributes
4935 * Can be a combination of:
4940 * Handle to a file to create a section mapped to a file
4941 * instead of a memory backed section;
4952 MmCreateSection (OUT PVOID
* Section
,
4953 IN ACCESS_MASK DesiredAccess
,
4954 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4955 IN PLARGE_INTEGER MaximumSize
,
4956 IN ULONG SectionPageProtection
,
4957 IN ULONG AllocationAttributes
,
4958 IN HANDLE FileHandle OPTIONAL
,
4959 IN PFILE_OBJECT File OPTIONAL
)
4962 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4964 /* Check if an ARM3 section is being created instead */
4965 if (AllocationAttributes
& 1)
4967 DPRINT1("arm 3 path\n");
4968 return MmCreateArm3Section(Section
,
4972 SectionPageProtection
,
4973 AllocationAttributes
&~ 1,
4979 * Check the protection
4981 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4982 if (Protection
!= PAGE_READONLY
&&
4983 Protection
!= PAGE_READWRITE
&&
4984 Protection
!= PAGE_WRITECOPY
&&
4985 Protection
!= PAGE_EXECUTE
&&
4986 Protection
!= PAGE_EXECUTE_READ
&&
4987 Protection
!= PAGE_EXECUTE_READWRITE
&&
4988 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4990 return STATUS_INVALID_PAGE_PROTECTION
;
4993 if (AllocationAttributes
& SEC_IMAGE
)
4995 return(MmCreateImageSection(SectionObject
,
4999 SectionPageProtection
,
5000 AllocationAttributes
,
5004 if (FileHandle
!= NULL
)
5006 return(MmCreateDataFileSection(SectionObject
,
5010 SectionPageProtection
,
5011 AllocationAttributes
,
5015 return(MmCreatePageFileSection(SectionObject
,
5019 SectionPageProtection
,
5020 AllocationAttributes
));