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 if(nSectionAlignment
>= PAGE_SIZE
)
694 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
697 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;
706 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
709 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
710 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
711 * RETURNS: Status of the wait.
714 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
716 LARGE_INTEGER Timeout
;
717 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
719 Timeout
.QuadPart
= -100000000LL; // 10 sec
722 Timeout
.QuadPart
= -100000000; // 10 sec
725 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
730 * FUNCTION: Sets the page op completion event and releases the page op.
731 * ARGUMENTS: PMM_PAGEOP.
732 * RETURNS: In shorter time than it takes you to even read this
733 * description, so don't even think about geting a mug of coffee.
736 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
738 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
739 MmReleasePageOp(PageOp
);
744 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
745 * ARGUMENTS: PFILE_OBJECT to wait for.
746 * RETURNS: Status of the wait.
749 MmspWaitForFileLock(PFILE_OBJECT File
)
751 return STATUS_SUCCESS
;
752 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
757 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
760 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
762 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
764 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
766 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
774 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
776 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
778 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
779 PMM_SECTION_SEGMENT SectionSegments
;
783 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
784 NrSegments
= ImageSectionObject
->NrSegments
;
785 SectionSegments
= ImageSectionObject
->Segments
;
786 for (i
= 0; i
< NrSegments
; i
++)
788 if (SectionSegments
[i
].ReferenceCount
!= 0)
790 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
791 SectionSegments
[i
].ReferenceCount
);
792 KeBugCheck(MEMORY_MANAGEMENT
);
794 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
796 ExFreePool(ImageSectionObject
->Segments
);
797 ExFreePool(ImageSectionObject
);
798 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
800 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
802 PMM_SECTION_SEGMENT Segment
;
804 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
807 if (Segment
->ReferenceCount
!= 0)
809 DPRINT1("Data segment still referenced\n");
810 KeBugCheck(MEMORY_MANAGEMENT
);
812 MmFreePageTablesSectionSegment(Segment
);
814 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
820 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
822 ExAcquireFastMutex(&Segment
->Lock
);
827 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
829 ExReleaseFastMutex(&Segment
->Lock
);
834 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
838 PSECTION_PAGE_TABLE Table
;
839 ULONG DirectoryOffset
;
842 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
844 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
848 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
849 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
853 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
854 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
855 TAG_SECTION_PAGE_TABLE
);
858 KeBugCheck(MEMORY_MANAGEMENT
);
860 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
861 DPRINT("Table %x\n", Table
);
864 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
865 Table
->Entry
[TableOffset
] = Entry
;
871 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
874 PSECTION_PAGE_TABLE Table
;
876 ULONG DirectoryOffset
;
879 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
881 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
883 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
887 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
888 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
889 DPRINT("Table %x\n", Table
);
895 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
896 Entry
= Table
->Entry
[TableOffset
];
902 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
907 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
910 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
911 KeBugCheck(MEMORY_MANAGEMENT
);
913 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
915 DPRINT1("Maximum share count reached\n");
916 KeBugCheck(MEMORY_MANAGEMENT
);
918 if (IS_SWAP_FROM_SSE(Entry
))
920 KeBugCheck(MEMORY_MANAGEMENT
);
922 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
923 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
928 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
929 PMM_SECTION_SEGMENT Segment
,
935 BOOLEAN IsDirectMapped
= FALSE
;
937 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
940 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
941 KeBugCheck(MEMORY_MANAGEMENT
);
943 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
945 DPRINT1("Zero share count for unshare\n");
946 KeBugCheck(MEMORY_MANAGEMENT
);
948 if (IS_SWAP_FROM_SSE(Entry
))
950 KeBugCheck(MEMORY_MANAGEMENT
);
952 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
954 * If we reducing the share count of this entry to zero then set the entry
955 * to zero and tell the cache the page is no longer mapped.
957 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
959 PFILE_OBJECT FileObject
;
961 SWAPENTRY SavedSwapEntry
;
963 BOOLEAN IsImageSection
;
966 FileOffset
= Offset
+ Segment
->FileOffset
;
968 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
970 Page
= PFN_FROM_SSE(Entry
);
971 FileObject
= Section
->FileObject
;
972 if (FileObject
!= NULL
&&
973 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
976 if ((FileOffset
% PAGE_SIZE
) == 0 &&
977 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
980 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
981 IsDirectMapped
= TRUE
;
983 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
985 Status
= STATUS_SUCCESS
;
987 if (!NT_SUCCESS(Status
))
989 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
990 KeBugCheck(MEMORY_MANAGEMENT
);
995 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
996 if (SavedSwapEntry
== 0)
999 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1000 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
1004 * Try to page out this page and set the swap entry
1005 * within the section segment. There exist no rmap entry
1006 * for this page. The pager thread can't page out a
1007 * page without a rmap entry.
1009 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1013 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
1014 if (!IsDirectMapped
)
1016 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1022 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1023 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1031 * We hold all locks. Nobody can do something with the current
1032 * process and the current segment (also not within an other process).
1035 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
1036 if (!NT_SUCCESS(Status
))
1038 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
1039 KeBugCheck(MEMORY_MANAGEMENT
);
1042 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
1043 MmSetSavedSwapEntryPage(Page
, 0);
1045 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1049 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1050 KeBugCheck(MEMORY_MANAGEMENT
);
1056 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1058 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
1061 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
1065 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1068 PCACHE_SEGMENT CacheSeg
;
1069 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
1070 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
1073 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
1083 MiCopyFromUserPage(PFN_NUMBER DestPage
, PVOID SourceAddress
)
1089 Process
= PsGetCurrentProcess();
1090 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1091 if (TempAddress
== NULL
)
1093 return(STATUS_NO_MEMORY
);
1095 memcpy(TempAddress
, SourceAddress
, PAGE_SIZE
);
1096 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
1097 return(STATUS_SUCCESS
);
1103 MiReadPage(PMEMORY_AREA MemoryArea
,
1107 * FUNCTION: Read a page for a section backed memory area.
1109 * MemoryArea - Memory area to read the page for.
1110 * Offset - Offset of the page to read.
1111 * Page - Variable that receives a page contains the read data.
1118 PCACHE_SEGMENT CacheSeg
;
1119 PFILE_OBJECT FileObject
;
1123 BOOLEAN IsImageSection
;
1126 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1127 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1128 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
1129 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
1130 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1134 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1137 * If the file system is letting us go directly to the cache and the
1138 * memory area was mapped at an offset in the file which is page aligned
1139 * then get the related cache segment.
1141 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1142 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
1143 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1147 * Get the related cache segment; we use a lower level interface than
1148 * filesystems do because it is safe for us to use an offset with a
1149 * alignment less than the file system block size.
1151 Status
= CcRosGetCacheSegment(Bcb
,
1157 if (!NT_SUCCESS(Status
))
1164 * If the cache segment isn't up to date then call the file
1165 * system to read in the data.
1167 Status
= ReadCacheSegment(CacheSeg
);
1168 if (!NT_SUCCESS(Status
))
1170 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1175 * Retrieve the page from the cache segment that we actually want.
1177 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1178 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1180 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1187 ULONG CacheSegOffset
;
1190 * Allocate a page, this is rather complicated by the possibility
1191 * we might have to move other things out of memory
1193 MI_SET_USAGE(MI_USAGE_SECTION
);
1194 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1195 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1196 if (!NT_SUCCESS(Status
))
1200 Status
= CcRosGetCacheSegment(Bcb
,
1206 if (!NT_SUCCESS(Status
))
1213 * If the cache segment isn't up to date then call the file
1214 * system to read in the data.
1216 Status
= ReadCacheSegment(CacheSeg
);
1217 if (!NT_SUCCESS(Status
))
1219 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1224 Process
= PsGetCurrentProcess();
1225 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1226 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
1227 Length
= RawLength
- SegOffset
;
1228 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1230 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1232 else if (CacheSegOffset
>= PAGE_SIZE
)
1234 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1238 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1239 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1240 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1241 Status
= CcRosGetCacheSegment(Bcb
,
1242 FileOffset
+ CacheSegOffset
,
1247 if (!NT_SUCCESS(Status
))
1254 * If the cache segment isn't up to date then call the file
1255 * system to read in the data.
1257 Status
= ReadCacheSegment(CacheSeg
);
1258 if (!NT_SUCCESS(Status
))
1260 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1264 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1265 if (Length
< PAGE_SIZE
)
1267 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1271 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1274 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1275 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1277 return(STATUS_SUCCESS
);
1282 MiReadPage(PMEMORY_AREA MemoryArea
,
1286 * FUNCTION: Read a page for a section backed memory area.
1288 * MemoryArea - Memory area to read the page for.
1289 * Offset - Offset of the page to read.
1290 * Page - Variable that receives a page contains the read data.
1293 MM_REQUIRED_RESOURCES Resources
= { };
1295 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1296 Resources
.FileOffset
.QuadPart
= SegOffset
+
1297 MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
1298 Resources
.Consumer
= MC_USER
;
1299 Resources
.Amount
= PAGE_SIZE
;
1301 DPRINT1("%S, offset %x, len %d, page %x\n", ((PFILE_OBJECT
)Resources
.Context
)->FileName
.Buffer
, Resources
.FileOffset
.LowPart
, Resources
.Amount
, Resources
.Page
[0]);
1303 NTSTATUS Status
= MiReadFilePage(NULL
, NULL
, &Resources
);
1304 *Page
= Resources
.Page
[0];
1311 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1312 MEMORY_AREA
* MemoryArea
,
1320 PROS_SECTION_OBJECT Section
;
1321 PMM_SECTION_SEGMENT Segment
;
1327 BOOLEAN HasSwapEntry
;
1328 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1331 * There is a window between taking the page fault and locking the
1332 * address space when another thread could load the page so we check
1335 if (MmIsPagePresent(Process
, Address
))
1337 return(STATUS_SUCCESS
);
1340 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1341 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1342 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1344 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1345 Section
= MemoryArea
->Data
.SectionData
.Section
;
1346 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1347 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1352 MmLockSectionSegment(Segment
);
1355 * Check if this page needs to be mapped COW
1357 if ((Segment
->WriteCopy
) &&
1358 (Region
->Protect
== PAGE_READWRITE
||
1359 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1361 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1365 Attributes
= Region
->Protect
;
1369 * Get or create a page operation descriptor
1371 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
1374 DPRINT1("MmGetPageOp failed\n");
1375 KeBugCheck(MEMORY_MANAGEMENT
);
1379 * Check if someone else is already handling this fault, if so wait
1382 if (PageOp
->Thread
!= PsGetCurrentThread())
1384 MmUnlockSectionSegment(Segment
);
1385 MmUnlockAddressSpace(AddressSpace
);
1386 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1388 * Check for various strange conditions
1390 if (Status
!= STATUS_SUCCESS
)
1392 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1393 KeBugCheck(MEMORY_MANAGEMENT
);
1395 if (PageOp
->Status
== STATUS_PENDING
)
1397 DPRINT1("Woke for page op before completion\n");
1398 KeBugCheck(MEMORY_MANAGEMENT
);
1400 MmLockAddressSpace(AddressSpace
);
1402 * If this wasn't a pagein then restart the operation
1404 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
1406 MmspCompleteAndReleasePageOp(PageOp
);
1407 DPRINT("Address 0x%.8X\n", Address
);
1408 return(STATUS_MM_RESTART_OPERATION
);
1412 * If the thread handling this fault has failed then we don't retry
1414 if (!NT_SUCCESS(PageOp
->Status
))
1416 Status
= PageOp
->Status
;
1417 MmspCompleteAndReleasePageOp(PageOp
);
1418 DPRINT("Address 0x%.8X\n", Address
);
1421 MmLockSectionSegment(Segment
);
1423 * If the completed fault was for another address space then set the
1426 if (!MmIsPagePresent(Process
, Address
))
1428 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1429 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1431 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
1434 * The page was a private page in another or in our address space
1436 MmUnlockSectionSegment(Segment
);
1437 MmspCompleteAndReleasePageOp(PageOp
);
1438 return(STATUS_MM_RESTART_OPERATION
);
1441 Page
= PFN_FROM_SSE(Entry
);
1443 MmSharePageEntrySectionSegment(Segment
, Offset
);
1445 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
1446 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
1448 Status
= MmCreateVirtualMapping(Process
,
1453 if (!NT_SUCCESS(Status
))
1455 DPRINT1("Unable to create virtual mapping\n");
1456 KeBugCheck(MEMORY_MANAGEMENT
);
1458 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1460 MmUnlockSectionSegment(Segment
);
1461 PageOp
->Status
= STATUS_SUCCESS
;
1462 MmspCompleteAndReleasePageOp(PageOp
);
1463 DPRINT("Address 0x%.8X\n", Address
);
1464 return(STATUS_SUCCESS
);
1467 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1471 * Must be private page we have swapped out.
1473 SWAPENTRY SwapEntry
;
1478 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1480 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1481 KeBugCheck(MEMORY_MANAGEMENT
);
1484 MmUnlockSectionSegment(Segment
);
1485 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
1487 MmUnlockAddressSpace(AddressSpace
);
1488 MI_SET_USAGE(MI_USAGE_SECTION
);
1489 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1490 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1491 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1492 if (!NT_SUCCESS(Status
))
1494 KeBugCheck(MEMORY_MANAGEMENT
);
1497 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1498 if (!NT_SUCCESS(Status
))
1500 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1501 KeBugCheck(MEMORY_MANAGEMENT
);
1503 MmLockAddressSpace(AddressSpace
);
1504 Status
= MmCreateVirtualMapping(Process
,
1509 if (!NT_SUCCESS(Status
))
1511 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1512 KeBugCheck(MEMORY_MANAGEMENT
);
1517 * Store the swap entry for later use.
1519 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1522 * Add the page to the process's working set
1524 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1527 * Finish the operation
1529 PageOp
->Status
= STATUS_SUCCESS
;
1530 MmspCompleteAndReleasePageOp(PageOp
);
1531 DPRINT("Address 0x%.8X\n", Address
);
1532 return(STATUS_SUCCESS
);
1536 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1538 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1540 MmUnlockSectionSegment(Segment
);
1542 * Just map the desired physical page
1544 Page
= Offset
>> PAGE_SHIFT
;
1545 Status
= MmCreateVirtualMappingUnsafe(Process
,
1550 if (!NT_SUCCESS(Status
))
1552 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1553 KeBugCheck(MEMORY_MANAGEMENT
);
1558 * Cleanup and release locks
1560 PageOp
->Status
= STATUS_SUCCESS
;
1561 MmspCompleteAndReleasePageOp(PageOp
);
1562 DPRINT("Address 0x%.8X\n", Address
);
1563 return(STATUS_SUCCESS
);
1567 * Map anonymous memory for BSS sections
1569 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1571 MmUnlockSectionSegment(Segment
);
1572 MI_SET_USAGE(MI_USAGE_SECTION
);
1573 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1574 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1575 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1576 if (!NT_SUCCESS(Status
))
1578 MmUnlockAddressSpace(AddressSpace
);
1579 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1580 MmLockAddressSpace(AddressSpace
);
1582 if (!NT_SUCCESS(Status
))
1584 KeBugCheck(MEMORY_MANAGEMENT
);
1586 Status
= MmCreateVirtualMapping(Process
,
1591 if (!NT_SUCCESS(Status
))
1593 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1594 KeBugCheck(MEMORY_MANAGEMENT
);
1597 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1600 * Cleanup and release locks
1602 PageOp
->Status
= STATUS_SUCCESS
;
1603 MmspCompleteAndReleasePageOp(PageOp
);
1604 DPRINT("Address 0x%.8X\n", Address
);
1605 return(STATUS_SUCCESS
);
1609 * Get the entry corresponding to the offset within the section
1611 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1616 * If the entry is zero (and it can't change because we have
1617 * locked the segment) then we need to load the page.
1621 * Release all our locks and read in the page from disk
1623 MmUnlockSectionSegment(Segment
);
1624 MmUnlockAddressSpace(AddressSpace
);
1626 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1627 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1629 MI_SET_USAGE(MI_USAGE_SECTION
);
1630 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1631 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1632 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1633 if (!NT_SUCCESS(Status
))
1635 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1641 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1642 if (!NT_SUCCESS(Status
))
1644 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1647 if (!NT_SUCCESS(Status
))
1650 * FIXME: What do we know in this case?
1653 * Cleanup and release locks
1655 MmLockAddressSpace(AddressSpace
);
1656 PageOp
->Status
= Status
;
1657 MmspCompleteAndReleasePageOp(PageOp
);
1658 DPRINT("Address 0x%.8X\n", Address
);
1662 * Relock the address space and segment
1664 MmLockAddressSpace(AddressSpace
);
1665 MmLockSectionSegment(Segment
);
1668 * Check the entry. No one should change the status of a page
1669 * that has a pending page-in.
1671 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1672 if (Entry
!= Entry1
)
1674 DPRINT1("Someone changed ppte entry while we slept\n");
1675 KeBugCheck(MEMORY_MANAGEMENT
);
1679 * Mark the offset within the section as having valid, in-memory
1682 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1683 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1684 MmUnlockSectionSegment(Segment
);
1686 Status
= MmCreateVirtualMapping(Process
,
1691 if (!NT_SUCCESS(Status
))
1693 DPRINT1("Unable to create virtual mapping\n");
1694 KeBugCheck(MEMORY_MANAGEMENT
);
1696 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1698 PageOp
->Status
= STATUS_SUCCESS
;
1699 MmspCompleteAndReleasePageOp(PageOp
);
1700 DPRINT("Address 0x%.8X\n", Address
);
1701 return(STATUS_SUCCESS
);
1703 else if (IS_SWAP_FROM_SSE(Entry
))
1705 SWAPENTRY SwapEntry
;
1707 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1710 * Release all our locks and read in the page from disk
1712 MmUnlockSectionSegment(Segment
);
1714 MmUnlockAddressSpace(AddressSpace
);
1715 MI_SET_USAGE(MI_USAGE_SECTION
);
1716 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1717 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1718 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1719 if (!NT_SUCCESS(Status
))
1721 KeBugCheck(MEMORY_MANAGEMENT
);
1724 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1725 if (!NT_SUCCESS(Status
))
1727 KeBugCheck(MEMORY_MANAGEMENT
);
1731 * Relock the address space and segment
1733 MmLockAddressSpace(AddressSpace
);
1734 MmLockSectionSegment(Segment
);
1737 * Check the entry. No one should change the status of a page
1738 * that has a pending page-in.
1740 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1741 if (Entry
!= Entry1
)
1743 DPRINT1("Someone changed ppte entry while we slept\n");
1744 KeBugCheck(MEMORY_MANAGEMENT
);
1748 * Mark the offset within the section as having valid, in-memory
1751 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1752 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1753 MmUnlockSectionSegment(Segment
);
1756 * Save the swap entry.
1758 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1759 Status
= MmCreateVirtualMapping(Process
,
1764 if (!NT_SUCCESS(Status
))
1766 DPRINT1("Unable to create virtual mapping\n");
1767 KeBugCheck(MEMORY_MANAGEMENT
);
1769 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1770 PageOp
->Status
= STATUS_SUCCESS
;
1771 MmspCompleteAndReleasePageOp(PageOp
);
1772 DPRINT("Address 0x%.8X\n", Address
);
1773 return(STATUS_SUCCESS
);
1778 * If the section offset is already in-memory and valid then just
1779 * take another reference to the page
1782 Page
= PFN_FROM_SSE(Entry
);
1784 MmSharePageEntrySectionSegment(Segment
, Offset
);
1785 MmUnlockSectionSegment(Segment
);
1787 Status
= MmCreateVirtualMapping(Process
,
1792 if (!NT_SUCCESS(Status
))
1794 DPRINT1("Unable to create virtual mapping\n");
1795 KeBugCheck(MEMORY_MANAGEMENT
);
1797 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1798 PageOp
->Status
= STATUS_SUCCESS
;
1799 MmspCompleteAndReleasePageOp(PageOp
);
1800 DPRINT("Address 0x%.8X\n", Address
);
1801 return(STATUS_SUCCESS
);
1807 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1808 MEMORY_AREA
* MemoryArea
,
1812 PMM_SECTION_SEGMENT Segment
;
1813 PROS_SECTION_OBJECT Section
;
1822 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1824 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1827 * Check if the page has been paged out or has already been set readwrite
1829 if (!MmIsPagePresent(Process
, Address
) ||
1830 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1832 DPRINT("Address 0x%.8X\n", Address
);
1833 return(STATUS_SUCCESS
);
1837 * Find the offset of the page
1839 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1840 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1841 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1843 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1844 Section
= MemoryArea
->Data
.SectionData
.Section
;
1845 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1846 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1851 MmLockSectionSegment(Segment
);
1853 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1854 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1856 MmUnlockSectionSegment(Segment
);
1859 * Check if we are doing COW
1861 if (!((Segment
->WriteCopy
) &&
1862 (Region
->Protect
== PAGE_READWRITE
||
1863 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1865 DPRINT("Address 0x%.8X\n", Address
);
1866 return(STATUS_ACCESS_VIOLATION
);
1869 if (IS_SWAP_FROM_SSE(Entry
) ||
1870 PFN_FROM_SSE(Entry
) != OldPage
)
1872 /* This is a private page. We must only change the page protection. */
1873 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1874 return(STATUS_SUCCESS
);
1878 * Get or create a pageop
1880 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1881 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1884 DPRINT1("MmGetPageOp failed\n");
1885 KeBugCheck(MEMORY_MANAGEMENT
);
1889 * Wait for any other operations to complete
1891 if (PageOp
->Thread
!= PsGetCurrentThread())
1893 MmUnlockAddressSpace(AddressSpace
);
1894 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1896 * Check for various strange conditions
1898 if (Status
== STATUS_TIMEOUT
)
1900 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1901 KeBugCheck(MEMORY_MANAGEMENT
);
1903 if (PageOp
->Status
== STATUS_PENDING
)
1905 DPRINT1("Woke for page op before completion\n");
1906 KeBugCheck(MEMORY_MANAGEMENT
);
1909 * Restart the operation
1911 MmLockAddressSpace(AddressSpace
);
1912 MmspCompleteAndReleasePageOp(PageOp
);
1913 DPRINT("Address 0x%.8X\n", Address
);
1914 return(STATUS_MM_RESTART_OPERATION
);
1918 * Release locks now we have the pageop
1920 MmUnlockAddressSpace(AddressSpace
);
1925 MI_SET_USAGE(MI_USAGE_SECTION
);
1926 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1927 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1928 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1929 if (!NT_SUCCESS(Status
))
1931 KeBugCheck(MEMORY_MANAGEMENT
);
1937 MiCopyFromUserPage(NewPage
, PAddress
);
1939 MmLockAddressSpace(AddressSpace
);
1941 * Delete the old entry.
1943 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1946 * Set the PTE to point to the new page
1948 Status
= MmCreateVirtualMapping(Process
,
1953 if (!NT_SUCCESS(Status
))
1955 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1956 KeBugCheck(MEMORY_MANAGEMENT
);
1959 if (!NT_SUCCESS(Status
))
1961 DPRINT1("Unable to create virtual mapping\n");
1962 KeBugCheck(MEMORY_MANAGEMENT
);
1966 * Unshare the old page.
1968 MmDeleteRmap(OldPage
, Process
, PAddress
);
1969 MmInsertRmap(NewPage
, Process
, PAddress
);
1970 MmLockSectionSegment(Segment
);
1971 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1972 MmUnlockSectionSegment(Segment
);
1974 PageOp
->Status
= STATUS_SUCCESS
;
1975 MmspCompleteAndReleasePageOp(PageOp
);
1976 DPRINT("Address 0x%.8X\n", Address
);
1977 return(STATUS_SUCCESS
);
1981 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1983 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1987 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1990 MmLockAddressSpace(&Process
->Vm
);
1993 MmDeleteVirtualMapping(Process
,
2000 PageOutContext
->WasDirty
= TRUE
;
2002 if (!PageOutContext
->Private
)
2004 MmLockSectionSegment(PageOutContext
->Segment
);
2005 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
2006 PageOutContext
->Segment
,
2007 PageOutContext
->Offset
,
2008 PageOutContext
->WasDirty
,
2010 MmUnlockSectionSegment(PageOutContext
->Segment
);
2014 MmUnlockAddressSpace(&Process
->Vm
);
2017 if (PageOutContext
->Private
)
2019 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2022 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
2027 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
2028 MEMORY_AREA
* MemoryArea
,
2033 MM_SECTION_PAGEOUT_CONTEXT Context
;
2034 SWAPENTRY SwapEntry
;
2038 PFILE_OBJECT FileObject
;
2042 BOOLEAN DirectMapped
;
2043 BOOLEAN IsImageSection
;
2044 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2047 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2050 * Get the segment and section.
2052 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2053 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
2055 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2056 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2057 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
2059 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2061 FileObject
= Context
.Section
->FileObject
;
2062 DirectMapped
= FALSE
;
2064 if (FileObject
!= NULL
&&
2065 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2067 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2070 * If the file system is letting us go directly to the cache and the
2071 * memory area was mapped at an offset in the file which is page aligned
2072 * then note this is a direct mapped page.
2074 if ((FileOffset
% PAGE_SIZE
) == 0 &&
2075 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
2077 DirectMapped
= TRUE
;
2084 * This should never happen since mappings of physical memory are never
2085 * placed in the rmap lists.
2087 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2089 DPRINT1("Trying to page out from physical memory section address 0x%X "
2090 "process %d\n", Address
,
2091 Process
? Process
->UniqueProcessId
: 0);
2092 KeBugCheck(MEMORY_MANAGEMENT
);
2096 * Get the section segment entry and the physical address.
2098 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
2099 if (!MmIsPagePresent(Process
, Address
))
2101 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2102 Process
? Process
->UniqueProcessId
: 0, Address
);
2103 KeBugCheck(MEMORY_MANAGEMENT
);
2105 Page
= MmGetPfnForProcess(Process
, Address
);
2106 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2109 * Prepare the context structure for the rmap delete call.
2111 Context
.WasDirty
= FALSE
;
2112 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2113 IS_SWAP_FROM_SSE(Entry
) ||
2114 PFN_FROM_SSE(Entry
) != Page
)
2116 Context
.Private
= TRUE
;
2120 Context
.Private
= FALSE
;
2124 * Take an additional reference to the page or the cache segment.
2126 if (DirectMapped
&& !Context
.Private
)
2128 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
2130 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2131 KeBugCheck(MEMORY_MANAGEMENT
);
2136 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
2137 MmReferencePage(Page
);
2138 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
2141 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2144 * If this wasn't a private page then we should have reduced the entry to
2145 * zero by deleting all the rmaps.
2147 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
2149 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2150 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2152 KeBugCheck(MEMORY_MANAGEMENT
);
2157 * If the page wasn't dirty then we can just free it as for a readonly page.
2158 * Since we unmapped all the mappings above we know it will not suddenly
2160 * If the page is from a pagefile section and has no swap entry,
2161 * we can't free the page at this point.
2163 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2164 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2166 if (Context
.Private
)
2168 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
2169 Context
.WasDirty
? "dirty" : "clean", Address
);
2170 KeBugCheck(MEMORY_MANAGEMENT
);
2172 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2174 MmSetSavedSwapEntryPage(Page
, 0);
2175 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2176 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2177 PageOp
->Status
= STATUS_SUCCESS
;
2178 MmspCompleteAndReleasePageOp(PageOp
);
2179 return(STATUS_SUCCESS
);
2182 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2184 if (Context
.Private
)
2186 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2187 Context
.WasDirty
? "dirty" : "clean", Address
);
2188 KeBugCheck(MEMORY_MANAGEMENT
);
2190 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2192 MmSetSavedSwapEntryPage(Page
, 0);
2195 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2197 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2198 PageOp
->Status
= STATUS_SUCCESS
;
2199 MmspCompleteAndReleasePageOp(PageOp
);
2200 return(STATUS_SUCCESS
);
2203 else if (!Context
.Private
&& DirectMapped
)
2207 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2209 KeBugCheck(MEMORY_MANAGEMENT
);
2212 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
2214 Status
= STATUS_SUCCESS
;
2216 if (!NT_SUCCESS(Status
))
2218 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2219 KeBugCheck(MEMORY_MANAGEMENT
);
2221 PageOp
->Status
= STATUS_SUCCESS
;
2222 MmspCompleteAndReleasePageOp(PageOp
);
2223 return(STATUS_SUCCESS
);
2225 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2229 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2231 KeBugCheck(MEMORY_MANAGEMENT
);
2233 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2234 PageOp
->Status
= STATUS_SUCCESS
;
2235 MmspCompleteAndReleasePageOp(PageOp
);
2236 return(STATUS_SUCCESS
);
2238 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2240 MmSetSavedSwapEntryPage(Page
, 0);
2241 MmLockAddressSpace(AddressSpace
);
2242 Status
= MmCreatePageFileMapping(Process
,
2245 MmUnlockAddressSpace(AddressSpace
);
2246 if (!NT_SUCCESS(Status
))
2248 KeBugCheck(MEMORY_MANAGEMENT
);
2250 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2251 PageOp
->Status
= STATUS_SUCCESS
;
2252 MmspCompleteAndReleasePageOp(PageOp
);
2253 return(STATUS_SUCCESS
);
2257 * If necessary, allocate an entry in the paging file for this page
2261 SwapEntry
= MmAllocSwapPage();
2264 MmShowOutOfSpaceMessagePagingFile();
2265 MmLockAddressSpace(AddressSpace
);
2267 * For private pages restore the old mappings.
2269 if (Context
.Private
)
2271 Status
= MmCreateVirtualMapping(Process
,
2273 MemoryArea
->Protect
,
2276 MmSetDirtyPage(Process
, Address
);
2284 * For non-private pages if the page wasn't direct mapped then
2285 * set it back into the section segment entry so we don't loose
2286 * our copy. Otherwise it will be handled by the cache manager.
2288 Status
= MmCreateVirtualMapping(Process
,
2290 MemoryArea
->Protect
,
2293 MmSetDirtyPage(Process
, Address
);
2297 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2298 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2300 MmUnlockAddressSpace(AddressSpace
);
2301 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2302 MmspCompleteAndReleasePageOp(PageOp
);
2303 return(STATUS_PAGEFILE_QUOTA
);
2308 * Write the page to the pagefile
2310 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2311 if (!NT_SUCCESS(Status
))
2313 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2316 * As above: undo our actions.
2317 * FIXME: Also free the swap page.
2319 MmLockAddressSpace(AddressSpace
);
2320 if (Context
.Private
)
2322 Status
= MmCreateVirtualMapping(Process
,
2324 MemoryArea
->Protect
,
2327 MmSetDirtyPage(Process
, Address
);
2334 Status
= MmCreateVirtualMapping(Process
,
2336 MemoryArea
->Protect
,
2339 MmSetDirtyPage(Process
, Address
);
2343 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2344 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2346 MmUnlockAddressSpace(AddressSpace
);
2347 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2348 MmspCompleteAndReleasePageOp(PageOp
);
2349 return(STATUS_UNSUCCESSFUL
);
2353 * Otherwise we have succeeded.
2355 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2356 MmSetSavedSwapEntryPage(Page
, 0);
2357 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2358 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
2360 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2364 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2367 if (Context
.Private
)
2369 MmLockAddressSpace(AddressSpace
);
2370 Status
= MmCreatePageFileMapping(Process
,
2373 MmUnlockAddressSpace(AddressSpace
);
2374 if (!NT_SUCCESS(Status
))
2376 KeBugCheck(MEMORY_MANAGEMENT
);
2381 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2382 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
2385 PageOp
->Status
= STATUS_SUCCESS
;
2386 MmspCompleteAndReleasePageOp(PageOp
);
2387 return(STATUS_SUCCESS
);
2392 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2393 PMEMORY_AREA MemoryArea
,
2398 PROS_SECTION_OBJECT Section
;
2399 PMM_SECTION_SEGMENT Segment
;
2401 SWAPENTRY SwapEntry
;
2405 PFILE_OBJECT FileObject
;
2407 BOOLEAN DirectMapped
;
2408 BOOLEAN IsImageSection
;
2409 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2411 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2413 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2414 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2417 * Get the segment and section.
2419 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2420 Section
= MemoryArea
->Data
.SectionData
.Section
;
2421 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2423 FileObject
= Section
->FileObject
;
2424 DirectMapped
= FALSE
;
2425 if (FileObject
!= NULL
&&
2426 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
2428 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2431 * If the file system is letting us go directly to the cache and the
2432 * memory area was mapped at an offset in the file which is page aligned
2433 * then note this is a direct mapped page.
2435 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
2436 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
2438 DirectMapped
= TRUE
;
2443 * This should never happen since mappings of physical memory are never
2444 * placed in the rmap lists.
2446 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2448 DPRINT1("Trying to write back page from physical memory mapped at %X "
2449 "process %d\n", Address
,
2450 Process
? Process
->UniqueProcessId
: 0);
2451 KeBugCheck(MEMORY_MANAGEMENT
);
2455 * Get the section segment entry and the physical address.
2457 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2458 if (!MmIsPagePresent(Process
, Address
))
2460 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2461 Process
? Process
->UniqueProcessId
: 0, Address
);
2462 KeBugCheck(MEMORY_MANAGEMENT
);
2464 Page
= MmGetPfnForProcess(Process
, Address
);
2465 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2468 * Check for a private (COWed) page.
2470 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2471 IS_SWAP_FROM_SSE(Entry
) ||
2472 PFN_FROM_SSE(Entry
) != Page
)
2482 * Speculatively set all mappings of the page to clean.
2484 MmSetCleanAllRmaps(Page
);
2487 * If this page was direct mapped from the cache then the cache manager
2488 * will take care of writing it back to disk.
2490 if (DirectMapped
&& !Private
)
2492 ASSERT(SwapEntry
== 0);
2494 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
2496 PageOp
->Status
= STATUS_SUCCESS
;
2497 MmspCompleteAndReleasePageOp(PageOp
);
2498 return(STATUS_SUCCESS
);
2502 * If necessary, allocate an entry in the paging file for this page
2506 SwapEntry
= MmAllocSwapPage();
2509 MmSetDirtyAllRmaps(Page
);
2510 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2511 MmspCompleteAndReleasePageOp(PageOp
);
2512 return(STATUS_PAGEFILE_QUOTA
);
2514 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2518 * Write the page to the pagefile
2520 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2521 if (!NT_SUCCESS(Status
))
2523 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2525 MmSetDirtyAllRmaps(Page
);
2526 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2527 MmspCompleteAndReleasePageOp(PageOp
);
2528 return(STATUS_UNSUCCESSFUL
);
2532 * Otherwise we have succeeded.
2534 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2535 PageOp
->Status
= STATUS_SUCCESS
;
2536 MmspCompleteAndReleasePageOp(PageOp
);
2537 return(STATUS_SUCCESS
);
2541 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2549 PMEMORY_AREA MemoryArea
;
2550 PMM_SECTION_SEGMENT Segment
;
2551 BOOLEAN DoCOW
= FALSE
;
2553 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2555 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2556 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2558 if ((Segment
->WriteCopy
) &&
2559 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2564 if (OldProtect
!= NewProtect
)
2566 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2568 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2569 ULONG Protect
= NewProtect
;
2572 * If we doing COW for this segment then check if the page is
2575 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2581 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2582 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2583 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2584 Page
= MmGetPfnForProcess(Process
, Address
);
2586 Protect
= PAGE_READONLY
;
2587 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2588 IS_SWAP_FROM_SSE(Entry
) ||
2589 PFN_FROM_SSE(Entry
) != Page
)
2591 Protect
= NewProtect
;
2595 if (MmIsPagePresent(Process
, Address
))
2597 MmSetPageProtect(Process
, Address
,
2606 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2607 PMEMORY_AREA MemoryArea
,
2615 ULONG_PTR MaxLength
;
2617 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2618 if (Length
> MaxLength
)
2621 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2622 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2624 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2625 Region
->Protect
!= Protect
)
2627 return STATUS_INVALID_PAGE_PROTECTION
;
2630 *OldProtect
= Region
->Protect
;
2631 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2632 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2633 BaseAddress
, Length
, Region
->Type
, Protect
,
2634 MmAlterViewAttributes
);
2640 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2642 PMEMORY_BASIC_INFORMATION Info
,
2643 PSIZE_T ResultLength
)
2646 PVOID RegionBaseAddress
;
2647 PROS_SECTION_OBJECT Section
;
2648 PMM_SECTION_SEGMENT Segment
;
2650 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2651 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2652 Address
, &RegionBaseAddress
);
2655 return STATUS_UNSUCCESSFUL
;
2658 Section
= MemoryArea
->Data
.SectionData
.Section
;
2659 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2661 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2662 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2663 Info
->Type
= MEM_IMAGE
;
2667 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2668 Info
->Type
= MEM_MAPPED
;
2670 Info
->BaseAddress
= RegionBaseAddress
;
2671 Info
->AllocationProtect
= MemoryArea
->Protect
;
2672 Info
->RegionSize
= Region
->Length
;
2673 Info
->State
= MEM_COMMIT
;
2674 Info
->Protect
= Region
->Protect
;
2676 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2677 return(STATUS_SUCCESS
);
2682 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2687 ULONG SavedSwapEntry
;
2692 Length
= PAGE_ROUND_UP(Segment
->Length
);
2693 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2695 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2698 if (IS_SWAP_FROM_SSE(Entry
))
2700 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2704 Page
= PFN_FROM_SSE(Entry
);
2705 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2706 if (SavedSwapEntry
!= 0)
2708 MmSetSavedSwapEntryPage(Page
, 0);
2709 MmFreeSwapPage(SavedSwapEntry
);
2711 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2713 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2719 MmpDeleteSection(PVOID ObjectBody
)
2721 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2723 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2724 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2729 PMM_SECTION_SEGMENT SectionSegments
;
2732 * NOTE: Section->ImageSection can be NULL for short time
2733 * during the section creating. If we fail for some reason
2734 * until the image section is properly initialized we shouldn't
2735 * process further here.
2737 if (Section
->ImageSection
== NULL
)
2740 SectionSegments
= Section
->ImageSection
->Segments
;
2741 NrSegments
= Section
->ImageSection
->NrSegments
;
2743 for (i
= 0; i
< NrSegments
; i
++)
2745 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2747 MmLockSectionSegment(&SectionSegments
[i
]);
2749 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2750 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2754 MmpFreePageFileSegment(&SectionSegments
[i
]);
2756 MmUnlockSectionSegment(&SectionSegments
[i
]);
2763 * NOTE: Section->Segment can be NULL for short time
2764 * during the section creating.
2766 if (Section
->Segment
== NULL
)
2769 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2771 MmpFreePageFileSegment(Section
->Segment
);
2772 MmFreePageTablesSectionSegment(Section
->Segment
);
2773 ExFreePool(Section
->Segment
);
2774 Section
->Segment
= NULL
;
2778 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2781 if (Section
->FileObject
!= NULL
)
2784 CcRosDereferenceCache(Section
->FileObject
);
2786 ObDereferenceObject(Section
->FileObject
);
2787 Section
->FileObject
= NULL
;
2792 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2794 IN ACCESS_MASK GrantedAccess
,
2795 IN ULONG ProcessHandleCount
,
2796 IN ULONG SystemHandleCount
)
2798 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2799 Object
, ProcessHandleCount
);
2805 MmCreatePhysicalMemorySection(VOID
)
2807 PROS_SECTION_OBJECT PhysSection
;
2809 OBJECT_ATTRIBUTES Obj
;
2810 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2811 LARGE_INTEGER SectionSize
;
2815 * Create the section mapping physical memory
2817 SectionSize
.QuadPart
= 0xFFFFFFFF;
2818 InitializeObjectAttributes(&Obj
,
2823 Status
= MmCreateSection((PVOID
)&PhysSection
,
2827 PAGE_EXECUTE_READWRITE
,
2831 if (!NT_SUCCESS(Status
))
2833 DPRINT1("Failed to create PhysicalMemory section\n");
2834 KeBugCheck(MEMORY_MANAGEMENT
);
2836 Status
= ObInsertObject(PhysSection
,
2842 if (!NT_SUCCESS(Status
))
2844 ObDereferenceObject(PhysSection
);
2846 ObCloseHandle(Handle
, KernelMode
);
2847 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2848 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2850 return(STATUS_SUCCESS
);
2856 MmInitSectionImplementation(VOID
)
2858 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2859 UNICODE_STRING Name
;
2861 DPRINT("Creating Section Object Type\n");
2863 /* Initialize the Section object type */
2864 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2865 RtlInitUnicodeString(&Name
, L
"Section");
2866 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2867 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2868 ObjectTypeInitializer
.PoolType
= PagedPool
;
2869 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2870 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2871 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2872 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2873 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2874 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2876 MmCreatePhysicalMemorySection();
2878 return(STATUS_SUCCESS
);
2883 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2884 ACCESS_MASK DesiredAccess
,
2885 POBJECT_ATTRIBUTES ObjectAttributes
,
2886 PLARGE_INTEGER UMaximumSize
,
2887 ULONG SectionPageProtection
,
2888 ULONG AllocationAttributes
)
2890 * Create a section which is backed by the pagefile
2893 LARGE_INTEGER MaximumSize
;
2894 PROS_SECTION_OBJECT Section
;
2895 PMM_SECTION_SEGMENT Segment
;
2898 if (UMaximumSize
== NULL
)
2900 return(STATUS_UNSUCCESSFUL
);
2902 MaximumSize
= *UMaximumSize
;
2905 * Create the section
2907 Status
= ObCreateObject(ExGetPreviousMode(),
2908 MmSectionObjectType
,
2910 ExGetPreviousMode(),
2912 sizeof(ROS_SECTION_OBJECT
),
2915 (PVOID
*)(PVOID
)&Section
);
2916 if (!NT_SUCCESS(Status
))
2924 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2925 Section
->SectionPageProtection
= SectionPageProtection
;
2926 Section
->AllocationAttributes
= AllocationAttributes
;
2927 Section
->MaximumSize
= MaximumSize
;
2928 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2929 TAG_MM_SECTION_SEGMENT
);
2930 if (Segment
== NULL
)
2932 ObDereferenceObject(Section
);
2933 return(STATUS_NO_MEMORY
);
2935 Section
->Segment
= Segment
;
2936 Segment
->ReferenceCount
= 1;
2937 ExInitializeFastMutex(&Segment
->Lock
);
2938 Segment
->FileOffset
= 0;
2939 Segment
->Protection
= SectionPageProtection
;
2940 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2941 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2942 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2943 Segment
->WriteCopy
= FALSE
;
2944 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2945 Segment
->VirtualAddress
= 0;
2946 Segment
->Characteristics
= 0;
2947 *SectionObject
= Section
;
2948 return(STATUS_SUCCESS
);
2954 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2955 ACCESS_MASK DesiredAccess
,
2956 POBJECT_ATTRIBUTES ObjectAttributes
,
2957 PLARGE_INTEGER UMaximumSize
,
2958 ULONG SectionPageProtection
,
2959 ULONG AllocationAttributes
,
2962 * Create a section backed by a data file
2965 PROS_SECTION_OBJECT Section
;
2967 LARGE_INTEGER MaximumSize
;
2968 PFILE_OBJECT FileObject
;
2969 PMM_SECTION_SEGMENT Segment
;
2971 IO_STATUS_BLOCK Iosb
;
2972 LARGE_INTEGER Offset
;
2974 FILE_STANDARD_INFORMATION FileInfo
;
2978 * Create the section
2980 Status
= ObCreateObject(ExGetPreviousMode(),
2981 MmSectionObjectType
,
2983 ExGetPreviousMode(),
2985 sizeof(ROS_SECTION_OBJECT
),
2988 (PVOID
*)(PVOID
)&Section
);
2989 if (!NT_SUCCESS(Status
))
2996 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2997 Section
->SectionPageProtection
= SectionPageProtection
;
2998 Section
->AllocationAttributes
= AllocationAttributes
;
3001 * Check file access required
3003 if (SectionPageProtection
& PAGE_READWRITE
||
3004 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3006 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3010 FileAccess
= FILE_READ_DATA
;
3014 * Reference the file handle
3016 Status
= ObReferenceObjectByHandle(FileHandle
,
3019 ExGetPreviousMode(),
3020 (PVOID
*)(PVOID
)&FileObject
,
3022 if (!NT_SUCCESS(Status
))
3024 ObDereferenceObject(Section
);
3029 * FIXME: This is propably not entirely correct. We can't look into
3030 * the standard FCB header because it might not be initialized yet
3031 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
3032 * standard file information is filled on first request).
3034 Status
= IoQueryFileInformation(FileObject
,
3035 FileStandardInformation
,
3036 sizeof(FILE_STANDARD_INFORMATION
),
3039 Iosb
.Information
= Length
;
3040 if (!NT_SUCCESS(Status
))
3042 ObDereferenceObject(Section
);
3043 ObDereferenceObject(FileObject
);
3048 * FIXME: Revise this once a locking order for file size changes is
3051 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
3053 MaximumSize
= *UMaximumSize
;
3057 MaximumSize
= FileInfo
.EndOfFile
;
3058 /* Mapping zero-sized files isn't allowed. */
3059 if (MaximumSize
.QuadPart
== 0)
3061 ObDereferenceObject(Section
);
3062 ObDereferenceObject(FileObject
);
3063 return STATUS_FILE_INVALID
;
3067 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3069 Status
= IoSetInformation(FileObject
,
3070 FileAllocationInformation
,
3071 sizeof(LARGE_INTEGER
),
3073 if (!NT_SUCCESS(Status
))
3075 ObDereferenceObject(Section
);
3076 ObDereferenceObject(FileObject
);
3077 return(STATUS_SECTION_NOT_EXTENDED
);
3081 if (FileObject
->SectionObjectPointer
== NULL
||
3082 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3085 * Read a bit so caching is initiated for the file object.
3086 * This is only needed because MiReadPage currently cannot
3087 * handle non-cached streams.
3089 Offset
.QuadPart
= 0;
3090 Status
= ZwReadFile(FileHandle
,
3099 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3101 ObDereferenceObject(Section
);
3102 ObDereferenceObject(FileObject
);
3105 if (FileObject
->SectionObjectPointer
== NULL
||
3106 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3108 /* FIXME: handle this situation */
3109 ObDereferenceObject(Section
);
3110 ObDereferenceObject(FileObject
);
3111 return STATUS_INVALID_PARAMETER
;
3118 Status
= MmspWaitForFileLock(FileObject
);
3119 if (Status
!= STATUS_SUCCESS
)
3121 ObDereferenceObject(Section
);
3122 ObDereferenceObject(FileObject
);
3127 * If this file hasn't been mapped as a data file before then allocate a
3128 * section segment to describe the data file mapping
3130 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3132 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3133 TAG_MM_SECTION_SEGMENT
);
3134 if (Segment
== NULL
)
3136 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3137 ObDereferenceObject(Section
);
3138 ObDereferenceObject(FileObject
);
3139 return(STATUS_NO_MEMORY
);
3141 Section
->Segment
= Segment
;
3142 Segment
->ReferenceCount
= 1;
3143 ExInitializeFastMutex(&Segment
->Lock
);
3145 * Set the lock before assigning the segment to the file object
3147 ExAcquireFastMutex(&Segment
->Lock
);
3148 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3150 Segment
->FileOffset
= 0;
3151 Segment
->Protection
= SectionPageProtection
;
3152 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3153 Segment
->Characteristics
= 0;
3154 Segment
->WriteCopy
= FALSE
;
3155 if (AllocationAttributes
& SEC_RESERVE
)
3157 Segment
->Length
= Segment
->RawLength
= 0;
3161 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3162 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3164 Segment
->VirtualAddress
= 0;
3165 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
3170 * If the file is already mapped as a data file then we may need
3174 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3176 Section
->Segment
= Segment
;
3177 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3178 MmLockSectionSegment(Segment
);
3180 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
3181 !(AllocationAttributes
& SEC_RESERVE
))
3183 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
3184 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
3187 MmUnlockSectionSegment(Segment
);
3188 Section
->FileObject
= FileObject
;
3189 Section
->MaximumSize
= MaximumSize
;
3191 CcRosReferenceCache(FileObject
);
3193 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3194 *SectionObject
= Section
;
3195 return(STATUS_SUCCESS
);
3199 TODO: not that great (declaring loaders statically, having to declare all of
3200 them, having to keep them extern, etc.), will fix in the future
3202 extern NTSTATUS NTAPI PeFmtCreateSection
3204 IN CONST VOID
* FileHeader
,
3205 IN SIZE_T FileHeaderSize
,
3207 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3209 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3210 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3213 extern NTSTATUS NTAPI ElfFmtCreateSection
3215 IN CONST VOID
* FileHeader
,
3216 IN SIZE_T FileHeaderSize
,
3218 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3220 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3221 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3224 /* TODO: this is a standard DDK/PSDK macro */
3225 #ifndef RTL_NUMBER_OF
3226 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3229 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3240 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3242 SIZE_T SizeOfSegments
;
3243 PMM_SECTION_SEGMENT Segments
;
3245 /* TODO: check for integer overflow */
3246 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3248 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3250 TAG_MM_SECTION_SEGMENT
);
3253 RtlZeroMemory(Segments
, SizeOfSegments
);
3261 ExeFmtpReadFile(IN PVOID File
,
3262 IN PLARGE_INTEGER Offset
,
3265 OUT PVOID
* AllocBase
,
3266 OUT PULONG ReadSize
)
3269 LARGE_INTEGER FileOffset
;
3271 ULONG OffsetAdjustment
;
3276 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3280 KeBugCheck(MEMORY_MANAGEMENT
);
3283 FileOffset
= *Offset
;
3285 /* Negative/special offset: it cannot be used in this context */
3286 if(FileOffset
.u
.HighPart
< 0)
3288 KeBugCheck(MEMORY_MANAGEMENT
);
3291 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3292 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3293 FileOffset
.u
.LowPart
= AdjustOffset
;
3295 BufferSize
= Length
+ OffsetAdjustment
;
3296 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3299 * It's ok to use paged pool, because this is a temporary buffer only used in
3300 * the loading of executables. The assumption is that MmCreateSection is
3301 * always called at low IRQLs and that these buffers don't survive a brief
3302 * initialization phase
3304 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3309 KeBugCheck(MEMORY_MANAGEMENT
);
3315 Status
= MmspPageRead(File
,
3322 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
3323 * nothing will work. But using ZwReadFile is wrong, and using its side effects
3324 * to initialize internal state is even worse. Our cache manager is in need of
3328 IO_STATUS_BLOCK Iosb
;
3330 Status
= ZwReadFile(File
,
3340 if(NT_SUCCESS(Status
))
3342 UsedSize
= Iosb
.Information
;
3347 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3349 Status
= STATUS_IN_PAGE_ERROR
;
3350 ASSERT(!NT_SUCCESS(Status
));
3353 if(NT_SUCCESS(Status
))
3355 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3356 *AllocBase
= Buffer
;
3357 *ReadSize
= UsedSize
- OffsetAdjustment
;
3361 ExFreePoolWithTag(Buffer
, 'rXmM');
3368 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3369 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3370 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3375 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3379 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3381 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3382 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
3389 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3393 MmspAssertSegmentsSorted(ImageSectionObject
);
3395 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3397 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
3401 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
3402 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3403 ImageSectionObject
->Segments
[i
- 1].Length
));
3411 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3415 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3417 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
3418 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
3426 MmspCompareSegments(const void * x
,
3429 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3430 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3433 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
3434 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3438 * Ensures an image section's segments are sorted in memory
3443 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3446 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3448 MmspAssertSegmentsSorted(ImageSectionObject
);
3452 qsort(ImageSectionObject
->Segments
,
3453 ImageSectionObject
->NrSegments
,
3454 sizeof(ImageSectionObject
->Segments
[0]),
3455 MmspCompareSegments
);
3461 * Ensures an image section's segments don't overlap in memory and don't have
3462 * gaps and don't have a null size. We let them map to overlapping file regions,
3463 * though - that's not necessarily an error
3468 MmspCheckSegmentBounds
3470 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3476 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3478 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3482 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3484 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3486 if(ImageSectionObject
->Segments
[i
].Length
== 0)
3494 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3495 * page could be OK (Windows seems to be OK with them), and larger gaps
3496 * could lead to image sections spanning several discontiguous regions
3497 * (NtMapViewOfSection could then refuse to map them, and they could
3498 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3500 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3501 ImageSectionObject
->Segments
[i
- 1].Length
) !=
3502 ImageSectionObject
->Segments
[i
].VirtualAddress
)
3513 * Merges and pads an image section's segments until they all are page-aligned
3514 * and have a size that is a multiple of the page size
3519 MmspPageAlignSegments
3521 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3527 PMM_SECTION_SEGMENT EffectiveSegment
;
3529 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3531 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3536 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3538 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3541 * The first segment requires special handling
3545 ULONG_PTR VirtualAddress
;
3546 ULONG_PTR VirtualOffset
;
3548 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3550 /* Round down the virtual address to the nearest page */
3551 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3553 /* Round up the virtual size to the nearest page */
3554 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3555 EffectiveSegment
->VirtualAddress
;
3557 /* Adjust the raw address and size */
3558 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3560 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3566 * Garbage in, garbage out: unaligned base addresses make the file
3567 * offset point in curious and odd places, but that's what we were
3570 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3571 EffectiveSegment
->RawLength
+= VirtualOffset
;
3575 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3576 ULONG_PTR EndOfEffectiveSegment
;
3578 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3579 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3582 * The current segment begins exactly where the current effective
3583 * segment ended, therefore beginning a new effective segment
3585 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3588 ASSERT(LastSegment
<= i
);
3589 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3591 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3593 if (LastSegment
!= i
)
3596 * Copy the current segment. If necessary, the effective segment
3597 * will be expanded later
3599 *EffectiveSegment
= *Segment
;
3603 * Page-align the virtual size. We know for sure the virtual address
3606 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3607 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3610 * The current segment is still part of the current effective segment:
3611 * extend the effective segment to reflect this
3613 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3615 static const ULONG FlagsToProtection
[16] =
3623 PAGE_EXECUTE_READWRITE
,
3624 PAGE_EXECUTE_READWRITE
,
3629 PAGE_EXECUTE_WRITECOPY
,
3630 PAGE_EXECUTE_WRITECOPY
,
3631 PAGE_EXECUTE_WRITECOPY
,
3632 PAGE_EXECUTE_WRITECOPY
3635 unsigned ProtectionFlags
;
3638 * Extend the file size
3641 /* Unaligned segments must be contiguous within the file */
3642 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3643 EffectiveSegment
->RawLength
))
3648 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3651 * Extend the virtual size
3653 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3655 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3656 EffectiveSegment
->VirtualAddress
;
3659 * Merge the protection
3661 EffectiveSegment
->Protection
|= Segment
->Protection
;
3663 /* Clean up redundance */
3664 ProtectionFlags
= 0;
3666 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3667 ProtectionFlags
|= 1 << 0;
3669 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3670 ProtectionFlags
|= 1 << 1;
3672 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3673 ProtectionFlags
|= 1 << 2;
3675 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3676 ProtectionFlags
|= 1 << 3;
3678 ASSERT(ProtectionFlags
< 16);
3679 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3681 /* If a segment was required to be shared and cannot, fail */
3682 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3683 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3689 * We assume no holes between segments at this point
3693 KeBugCheck(MEMORY_MANAGEMENT
);
3697 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3703 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3704 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3706 LARGE_INTEGER Offset
;
3708 PVOID FileHeaderBuffer
;
3709 ULONG FileHeaderSize
;
3711 ULONG OldNrSegments
;
3716 * Read the beginning of the file (2 pages). Should be enough to contain
3717 * all (or most) of the headers
3719 Offset
.QuadPart
= 0;
3721 /* FIXME: use FileObject instead of FileHandle */
3722 Status
= ExeFmtpReadFile (FileHandle
,
3729 if (!NT_SUCCESS(Status
))
3732 if (FileHeaderSize
== 0)
3734 ExFreePool(FileHeaderBuffer
);
3735 return STATUS_UNSUCCESSFUL
;
3739 * Look for a loader that can handle this executable
3741 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3743 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3746 /* FIXME: use FileObject instead of FileHandle */
3747 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3753 ExeFmtpAllocateSegments
);
3755 if (!NT_SUCCESS(Status
))
3757 if (ImageSectionObject
->Segments
)
3759 ExFreePool(ImageSectionObject
->Segments
);
3760 ImageSectionObject
->Segments
= NULL
;
3764 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3768 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3771 * No loader handled the format
3773 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3775 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3776 ASSERT(!NT_SUCCESS(Status
));
3779 if (!NT_SUCCESS(Status
))
3782 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3787 /* FIXME? are these values platform-dependent? */
3788 if(ImageSectionObject
->StackReserve
== 0)
3789 ImageSectionObject
->StackReserve
= 0x40000;
3791 if(ImageSectionObject
->StackCommit
== 0)
3792 ImageSectionObject
->StackCommit
= 0x1000;
3794 if(ImageSectionObject
->ImageBase
== 0)
3796 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3797 ImageSectionObject
->ImageBase
= 0x10000000;
3799 ImageSectionObject
->ImageBase
= 0x00400000;
3803 * And now the fun part: fixing the segments
3806 /* Sort them by virtual address */
3807 MmspSortSegments(ImageSectionObject
, Flags
);
3809 /* Ensure they don't overlap in memory */
3810 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3811 return STATUS_INVALID_IMAGE_FORMAT
;
3813 /* Ensure they are aligned */
3814 OldNrSegments
= ImageSectionObject
->NrSegments
;
3816 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3817 return STATUS_INVALID_IMAGE_FORMAT
;
3819 /* Trim them if the alignment phase merged some of them */
3820 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3822 PMM_SECTION_SEGMENT Segments
;
3823 SIZE_T SizeOfSegments
;
3825 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3827 Segments
= ExAllocatePoolWithTag(PagedPool
,
3829 TAG_MM_SECTION_SEGMENT
);
3831 if (Segments
== NULL
)
3832 return STATUS_INSUFFICIENT_RESOURCES
;
3834 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3835 ExFreePool(ImageSectionObject
->Segments
);
3836 ImageSectionObject
->Segments
= Segments
;
3839 /* And finish their initialization */
3840 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3842 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3843 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3845 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3846 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3849 ASSERT(NT_SUCCESS(Status
));
3854 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3855 ACCESS_MASK DesiredAccess
,
3856 POBJECT_ATTRIBUTES ObjectAttributes
,
3857 PLARGE_INTEGER UMaximumSize
,
3858 ULONG SectionPageProtection
,
3859 ULONG AllocationAttributes
,
3862 PROS_SECTION_OBJECT Section
;
3864 PFILE_OBJECT FileObject
;
3865 PMM_SECTION_SEGMENT SectionSegments
;
3866 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3868 ULONG FileAccess
= 0;
3871 * Check file access required
3873 if (SectionPageProtection
& PAGE_READWRITE
||
3874 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3876 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3880 FileAccess
= FILE_READ_DATA
;
3884 * Reference the file handle
3886 Status
= ObReferenceObjectByHandle(FileHandle
,
3889 ExGetPreviousMode(),
3890 (PVOID
*)(PVOID
)&FileObject
,
3893 if (!NT_SUCCESS(Status
))
3899 * Create the section
3901 Status
= ObCreateObject (ExGetPreviousMode(),
3902 MmSectionObjectType
,
3904 ExGetPreviousMode(),
3906 sizeof(ROS_SECTION_OBJECT
),
3909 (PVOID
*)(PVOID
)&Section
);
3910 if (!NT_SUCCESS(Status
))
3912 ObDereferenceObject(FileObject
);
3919 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3920 Section
->SectionPageProtection
= SectionPageProtection
;
3921 Section
->AllocationAttributes
= AllocationAttributes
;
3925 * Initialized caching for this file object if previously caching
3926 * was initialized for the same on disk file
3928 Status
= CcTryToInitializeFileCache(FileObject
);
3930 Status
= STATUS_SUCCESS
;
3933 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3935 NTSTATUS StatusExeFmt
;
3937 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3938 if (ImageSectionObject
== NULL
)
3940 ObDereferenceObject(FileObject
);
3941 ObDereferenceObject(Section
);
3942 return(STATUS_NO_MEMORY
);
3945 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3947 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3949 if (!NT_SUCCESS(StatusExeFmt
))
3951 if(ImageSectionObject
->Segments
!= NULL
)
3952 ExFreePool(ImageSectionObject
->Segments
);
3954 ExFreePool(ImageSectionObject
);
3955 ObDereferenceObject(Section
);
3956 ObDereferenceObject(FileObject
);
3957 return(StatusExeFmt
);
3960 Section
->ImageSection
= ImageSectionObject
;
3961 ASSERT(ImageSectionObject
->Segments
);
3966 Status
= MmspWaitForFileLock(FileObject
);
3967 if (!NT_SUCCESS(Status
))
3969 ExFreePool(ImageSectionObject
->Segments
);
3970 ExFreePool(ImageSectionObject
);
3971 ObDereferenceObject(Section
);
3972 ObDereferenceObject(FileObject
);
3976 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3977 ImageSectionObject
, NULL
))
3980 * An other thread has initialized the same image in the background
3982 ExFreePool(ImageSectionObject
->Segments
);
3983 ExFreePool(ImageSectionObject
);
3984 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3985 Section
->ImageSection
= ImageSectionObject
;
3986 SectionSegments
= ImageSectionObject
->Segments
;
3988 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3990 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3994 Status
= StatusExeFmt
;
4001 Status
= MmspWaitForFileLock(FileObject
);
4002 if (Status
!= STATUS_SUCCESS
)
4004 ObDereferenceObject(Section
);
4005 ObDereferenceObject(FileObject
);
4009 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
4010 Section
->ImageSection
= ImageSectionObject
;
4011 SectionSegments
= ImageSectionObject
->Segments
;
4014 * Otherwise just reference all the section segments
4016 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
4018 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
4021 Status
= STATUS_SUCCESS
;
4023 Section
->FileObject
= FileObject
;
4025 CcRosReferenceCache(FileObject
);
4027 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
4028 *SectionObject
= Section
;
4035 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
4036 PROS_SECTION_OBJECT Section
,
4037 PMM_SECTION_SEGMENT Segment
,
4042 ULONG AllocationType
)
4046 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4048 BoundaryAddressMultiple
.QuadPart
= 0;
4050 Status
= MmCreateMemoryArea(AddressSpace
,
4051 MEMORY_AREA_SECTION_VIEW
,
4058 BoundaryAddressMultiple
);
4059 if (!NT_SUCCESS(Status
))
4061 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
4062 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
4066 ObReferenceObject((PVOID
)Section
);
4068 MArea
->Data
.SectionData
.Segment
= Segment
;
4069 MArea
->Data
.SectionData
.Section
= Section
;
4070 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
4071 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
4072 ViewSize
, 0, Protect
);
4074 return(STATUS_SUCCESS
);
4080 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
4081 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4084 PFILE_OBJECT FileObject
;
4087 SWAPENTRY SavedSwapEntry
;
4090 PROS_SECTION_OBJECT Section
;
4091 PMM_SECTION_SEGMENT Segment
;
4092 PMMSUPPORT AddressSpace
;
4095 AddressSpace
= (PMMSUPPORT
)Context
;
4096 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4098 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4100 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
4101 MemoryArea
->Data
.SectionData
.ViewOffset
;
4103 Section
= MemoryArea
->Data
.SectionData
.Section
;
4104 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4106 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4110 MmUnlockSectionSegment(Segment
);
4111 MmUnlockAddressSpace(AddressSpace
);
4113 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4114 if (Status
!= STATUS_SUCCESS
)
4116 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4117 KeBugCheck(MEMORY_MANAGEMENT
);
4120 MmLockAddressSpace(AddressSpace
);
4121 MmLockSectionSegment(Segment
);
4122 MmspCompleteAndReleasePageOp(PageOp
);
4123 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
4126 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
4129 * For a dirty, datafile, non-private page mark it as dirty in the
4132 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4134 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4136 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4137 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4139 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
4141 ASSERT(SwapEntry
== 0);
4150 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4152 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4153 KeBugCheck(MEMORY_MANAGEMENT
);
4155 MmFreeSwapPage(SwapEntry
);
4159 if (IS_SWAP_FROM_SSE(Entry
) ||
4160 Page
!= PFN_FROM_SSE(Entry
))
4165 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4167 DPRINT1("Found a private page in a pagefile section.\n");
4168 KeBugCheck(MEMORY_MANAGEMENT
);
4171 * Just dereference private pages
4173 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4174 if (SavedSwapEntry
!= 0)
4176 MmFreeSwapPage(SavedSwapEntry
);
4177 MmSetSavedSwapEntryPage(Page
, 0);
4179 MmDeleteRmap(Page
, Process
, Address
);
4180 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4184 MmDeleteRmap(Page
, Process
, Address
);
4185 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4191 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4195 PMEMORY_AREA MemoryArea
;
4196 PROS_SECTION_OBJECT Section
;
4197 PMM_SECTION_SEGMENT Segment
;
4198 PLIST_ENTRY CurrentEntry
;
4199 PMM_REGION CurrentRegion
;
4200 PLIST_ENTRY RegionListHead
;
4202 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4204 if (MemoryArea
== NULL
)
4206 return(STATUS_UNSUCCESSFUL
);
4209 MemoryArea
->DeleteInProgress
= TRUE
;
4210 Section
= MemoryArea
->Data
.SectionData
.Section
;
4211 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4213 MmLockSectionSegment(Segment
);
4215 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4216 while (!IsListEmpty(RegionListHead
))
4218 CurrentEntry
= RemoveHeadList(RegionListHead
);
4219 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4220 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4223 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4225 Status
= MmFreeMemoryArea(AddressSpace
,
4232 Status
= MmFreeMemoryArea(AddressSpace
,
4237 MmUnlockSectionSegment(Segment
);
4238 ObDereferenceObject(Section
);
4246 MmUnmapViewOfSection(PEPROCESS Process
,
4250 PMEMORY_AREA MemoryArea
;
4251 PMMSUPPORT AddressSpace
;
4252 PROS_SECTION_OBJECT Section
;
4255 PVOID ImageBaseAddress
= 0;
4257 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4258 Process
, BaseAddress
);
4262 AddressSpace
= &Process
->Vm
;
4264 MmLockAddressSpace(AddressSpace
);
4265 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4267 if (MemoryArea
== NULL
||
4268 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4269 MemoryArea
->DeleteInProgress
)
4271 MmUnlockAddressSpace(AddressSpace
);
4272 return STATUS_NOT_MAPPED_VIEW
;
4275 MemoryArea
->DeleteInProgress
= TRUE
;
4277 while (MemoryArea
->PageOpCount
)
4279 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4283 Offset
-= PAGE_SIZE
;
4284 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4285 MemoryArea
->Data
.SectionData
.Segment
,
4286 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4289 MmUnlockAddressSpace(AddressSpace
);
4290 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4291 if (Status
!= STATUS_SUCCESS
)
4293 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4294 KeBugCheck(MEMORY_MANAGEMENT
);
4296 MmLockAddressSpace(AddressSpace
);
4297 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4299 if (MemoryArea
== NULL
||
4300 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4302 MmUnlockAddressSpace(AddressSpace
);
4303 return STATUS_NOT_MAPPED_VIEW
;
4310 Section
= MemoryArea
->Data
.SectionData
.Section
;
4312 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4316 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4317 PMM_SECTION_SEGMENT SectionSegments
;
4318 PMM_SECTION_SEGMENT Segment
;
4320 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4321 ImageSectionObject
= Section
->ImageSection
;
4322 SectionSegments
= ImageSectionObject
->Segments
;
4323 NrSegments
= ImageSectionObject
->NrSegments
;
4325 /* Search for the current segment within the section segments
4326 * and calculate the image base address */
4327 for (i
= 0; i
< NrSegments
; i
++)
4329 if (Segment
== &SectionSegments
[i
])
4331 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4335 if (i
>= NrSegments
)
4337 KeBugCheck(MEMORY_MANAGEMENT
);
4340 for (i
= 0; i
< NrSegments
; i
++)
4342 PVOID SBaseAddress
= (PVOID
)
4343 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4345 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4350 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4353 MmUnlockAddressSpace(AddressSpace
);
4355 /* Notify debugger */
4356 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4358 return(STATUS_SUCCESS
);
4365 * Queries the information of a section object.
4367 * @param SectionHandle
4368 * Handle to the section object. It must be opened with SECTION_QUERY
4370 * @param SectionInformationClass
4371 * Index to a certain information structure. Can be either
4372 * SectionBasicInformation or SectionImageInformation. The latter
4373 * is valid only for sections that were created with the SEC_IMAGE
4375 * @param SectionInformation
4376 * Caller supplies storage for resulting information.
4378 * Size of the supplied storage.
4379 * @param ResultLength
4387 NtQuerySection(IN HANDLE SectionHandle
,
4388 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4389 OUT PVOID SectionInformation
,
4390 IN SIZE_T SectionInformationLength
,
4391 OUT PSIZE_T ResultLength OPTIONAL
)
4393 PROS_SECTION_OBJECT Section
;
4394 KPROCESSOR_MODE PreviousMode
;
4398 PreviousMode
= ExGetPreviousMode();
4400 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4402 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4404 SectionInformationLength
,
4409 if(!NT_SUCCESS(Status
))
4411 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4415 Status
= ObReferenceObjectByHandle(SectionHandle
,
4417 MmSectionObjectType
,
4419 (PVOID
*)(PVOID
)&Section
,
4421 if (NT_SUCCESS(Status
))
4423 switch (SectionInformationClass
)
4425 case SectionBasicInformation
:
4427 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4431 Sbi
->Attributes
= Section
->AllocationAttributes
;
4432 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4434 Sbi
->BaseAddress
= 0;
4435 Sbi
->Size
.QuadPart
= 0;
4439 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4440 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4443 if (ResultLength
!= NULL
)
4445 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4447 Status
= STATUS_SUCCESS
;
4449 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4451 Status
= _SEH2_GetExceptionCode();
4458 case SectionImageInformation
:
4460 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4464 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4465 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4467 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4468 ImageSectionObject
= Section
->ImageSection
;
4470 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4471 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4472 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4473 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4474 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4475 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4476 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4477 Sii
->Machine
= ImageSectionObject
->Machine
;
4478 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4481 if (ResultLength
!= NULL
)
4483 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4485 Status
= STATUS_SUCCESS
;
4487 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4489 Status
= _SEH2_GetExceptionCode();
4497 ObDereferenceObject(Section
);
4503 /**********************************************************************
4505 * MmMapViewOfSection
4508 * Maps a view of a section into the virtual address space of a
4513 * Pointer to the section object.
4516 * Pointer to the process.
4519 * Desired base address (or NULL) on entry;
4520 * Actual base address of the view on exit.
4523 * Number of high order address bits that must be zero.
4526 * Size in bytes of the initially committed section of
4530 * Offset in bytes from the beginning of the section
4531 * to the beginning of the view.
4534 * Desired length of map (or zero to map all) on entry
4535 * Actual length mapped on exit.
4537 * InheritDisposition
4538 * Specified how the view is to be shared with
4542 * Type of allocation for the pages.
4545 * Protection for the committed region of the view.
4553 MmMapViewOfSection(IN PVOID SectionObject
,
4554 IN PEPROCESS Process
,
4555 IN OUT PVOID
*BaseAddress
,
4556 IN ULONG_PTR ZeroBits
,
4557 IN SIZE_T CommitSize
,
4558 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4559 IN OUT PSIZE_T ViewSize
,
4560 IN SECTION_INHERIT InheritDisposition
,
4561 IN ULONG AllocationType
,
4564 PROS_SECTION_OBJECT Section
;
4565 PMMSUPPORT AddressSpace
;
4567 NTSTATUS Status
= STATUS_SUCCESS
;
4568 BOOLEAN NotAtBase
= FALSE
;
4570 if ((ULONG_PTR
)SectionObject
& 1)
4572 return MmMapViewOfArm3Section((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4586 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4588 return STATUS_INVALID_PAGE_PROTECTION
;
4592 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4593 AddressSpace
= &Process
->Vm
;
4595 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4597 MmLockAddressSpace(AddressSpace
);
4599 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4603 ULONG_PTR ImageBase
;
4605 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4606 PMM_SECTION_SEGMENT SectionSegments
;
4608 ImageSectionObject
= Section
->ImageSection
;
4609 SectionSegments
= ImageSectionObject
->Segments
;
4610 NrSegments
= ImageSectionObject
->NrSegments
;
4613 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4616 ImageBase
= ImageSectionObject
->ImageBase
;
4620 for (i
= 0; i
< NrSegments
; i
++)
4622 ULONG_PTR MaxExtent
;
4623 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4624 SectionSegments
[i
].Length
;
4625 ImageSize
= max(ImageSize
, MaxExtent
);
4628 ImageSectionObject
->ImageSize
= ImageSize
;
4630 /* Check there is enough space to map the section at that point. */
4631 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4632 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4634 /* Fail if the user requested a fixed base address. */
4635 if ((*BaseAddress
) != NULL
)
4637 MmUnlockAddressSpace(AddressSpace
);
4638 return(STATUS_UNSUCCESSFUL
);
4640 /* Otherwise find a gap to map the image. */
4641 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4644 MmUnlockAddressSpace(AddressSpace
);
4645 return(STATUS_UNSUCCESSFUL
);
4647 /* Remember that we loaded image at a different base address */
4651 for (i
= 0; i
< NrSegments
; i
++)
4653 PVOID SBaseAddress
= (PVOID
)
4654 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4655 MmLockSectionSegment(&SectionSegments
[i
]);
4656 Status
= MmMapViewOfSegment(AddressSpace
,
4658 &SectionSegments
[i
],
4660 SectionSegments
[i
].Length
,
4661 SectionSegments
[i
].Protection
,
4664 MmUnlockSectionSegment(&SectionSegments
[i
]);
4665 if (!NT_SUCCESS(Status
))
4667 MmUnlockAddressSpace(AddressSpace
);
4672 *BaseAddress
= (PVOID
)ImageBase
;
4673 *ViewSize
= ImageSize
;
4677 /* check for write access */
4678 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4679 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4681 MmUnlockAddressSpace(AddressSpace
);
4682 return STATUS_SECTION_PROTECTION
;
4684 /* check for read access */
4685 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4686 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4688 MmUnlockAddressSpace(AddressSpace
);
4689 return STATUS_SECTION_PROTECTION
;
4691 /* check for execute access */
4692 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4693 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4695 MmUnlockAddressSpace(AddressSpace
);
4696 return STATUS_SECTION_PROTECTION
;
4699 if (ViewSize
== NULL
)
4701 /* Following this pointer would lead to us to the dark side */
4702 /* What to do? Bugcheck? Return status? Do the mambo? */
4703 KeBugCheck(MEMORY_MANAGEMENT
);
4706 if (SectionOffset
== NULL
)
4712 ViewOffset
= SectionOffset
->u
.LowPart
;
4715 if ((ViewOffset
% PAGE_SIZE
) != 0)
4717 MmUnlockAddressSpace(AddressSpace
);
4718 return(STATUS_MAPPED_ALIGNMENT
);
4721 if ((*ViewSize
) == 0)
4723 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4725 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4727 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4730 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4732 MmLockSectionSegment(Section
->Segment
);
4733 Status
= MmMapViewOfSegment(AddressSpace
,
4740 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4741 MmUnlockSectionSegment(Section
->Segment
);
4742 if (!NT_SUCCESS(Status
))
4744 MmUnlockAddressSpace(AddressSpace
);
4749 MmUnlockAddressSpace(AddressSpace
);
4752 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4754 Status
= STATUS_SUCCESS
;
4763 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4764 IN PLARGE_INTEGER NewFileSize
)
4766 /* Check whether an ImageSectionObject exists */
4767 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4769 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4773 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4775 PMM_SECTION_SEGMENT Segment
;
4777 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4780 if (Segment
->ReferenceCount
!= 0)
4782 /* Check size of file */
4783 if (SectionObjectPointer
->SharedCacheMap
)
4785 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4786 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4794 /* Something must gone wrong
4795 * how can we have a Section but no
4797 DPRINT("ERROR: DataSectionObject without reference!\n");
4801 DPRINT("FIXME: didn't check for outstanding write probes\n");
4813 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4814 IN MMFLUSH_TYPE FlushType
)
4818 case MmFlushForDelete
:
4819 if (SectionObjectPointer
->ImageSectionObject
||
4820 SectionObjectPointer
->DataSectionObject
)
4825 CcRosSetRemoveOnClose(SectionObjectPointer
);
4828 case MmFlushForWrite
:
4838 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4839 OUT PVOID
* MappedBase
,
4840 IN OUT PSIZE_T ViewSize
)
4842 PROS_SECTION_OBJECT Section
;
4843 PMMSUPPORT AddressSpace
;
4847 if ((ULONG_PTR
)SectionObject
& 1)
4849 extern PVOID MmSession
;
4850 return MiMapViewInSystemSpace((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4856 DPRINT("MmMapViewInSystemSpace() called\n");
4858 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4859 AddressSpace
= MmGetKernelAddressSpace();
4861 MmLockAddressSpace(AddressSpace
);
4864 if ((*ViewSize
) == 0)
4866 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4868 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4870 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4873 MmLockSectionSegment(Section
->Segment
);
4876 Status
= MmMapViewOfSegment(AddressSpace
,
4885 MmUnlockSectionSegment(Section
->Segment
);
4886 MmUnlockAddressSpace(AddressSpace
);
4895 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4897 PMMSUPPORT AddressSpace
;
4900 DPRINT("MmUnmapViewInSystemSpace() called\n");
4902 AddressSpace
= MmGetKernelAddressSpace();
4904 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4910 /**********************************************************************
4915 * Creates a section object.
4918 * SectionObject (OUT)
4919 * Caller supplied storage for the resulting pointer
4920 * to a SECTION_OBJECT instance;
4923 * Specifies the desired access to the section can be a
4925 * STANDARD_RIGHTS_REQUIRED |
4927 * SECTION_MAP_WRITE |
4928 * SECTION_MAP_READ |
4929 * SECTION_MAP_EXECUTE
4931 * ObjectAttributes [OPTIONAL]
4932 * Initialized attributes for the object can be used
4933 * to create a named section;
4936 * Maximizes the size of the memory section. Must be
4937 * non-NULL for a page-file backed section.
4938 * If value specified for a mapped file and the file is
4939 * not large enough, file will be extended.
4941 * SectionPageProtection
4942 * Can be a combination of:
4948 * AllocationAttributes
4949 * Can be a combination of:
4954 * Handle to a file to create a section mapped to a file
4955 * instead of a memory backed section;
4966 MmCreateSection (OUT PVOID
* Section
,
4967 IN ACCESS_MASK DesiredAccess
,
4968 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4969 IN PLARGE_INTEGER MaximumSize
,
4970 IN ULONG SectionPageProtection
,
4971 IN ULONG AllocationAttributes
,
4972 IN HANDLE FileHandle OPTIONAL
,
4973 IN PFILE_OBJECT File OPTIONAL
)
4976 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4978 /* Check if an ARM3 section is being created instead */
4979 if (AllocationAttributes
& 1)
4981 DPRINT1("arm 3 path\n");
4982 return MmCreateArm3Section(Section
,
4986 SectionPageProtection
,
4987 AllocationAttributes
&~ 1,
4993 * Check the protection
4995 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4996 if (Protection
!= PAGE_READONLY
&&
4997 Protection
!= PAGE_READWRITE
&&
4998 Protection
!= PAGE_WRITECOPY
&&
4999 Protection
!= PAGE_EXECUTE
&&
5000 Protection
!= PAGE_EXECUTE_READ
&&
5001 Protection
!= PAGE_EXECUTE_READWRITE
&&
5002 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5004 return STATUS_INVALID_PAGE_PROTECTION
;
5007 if (AllocationAttributes
& SEC_IMAGE
)
5009 return(MmCreateImageSection(SectionObject
,
5013 SectionPageProtection
,
5014 AllocationAttributes
,
5018 if (FileHandle
!= NULL
)
5020 return(MmCreateDataFileSection(SectionObject
,
5024 SectionPageProtection
,
5025 AllocationAttributes
,
5029 return(MmCreatePageFileSection(SectionObject
,
5033 SectionPageProtection
,
5034 AllocationAttributes
));