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 *****************************************************************/
48 #include "../cache/newcc.h"
49 #include "../cache/section/newmm.h"
52 #include <reactos/exeformat.h>
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 #include "ARM3/miarm.h"
61 #undef MmSetPageEntrySectionSegment
62 #define MmSetPageEntrySectionSegment(S,O,E) do { \
63 DPRINT("SetPageEntrySectionSegment(old,%x,%x,%x)\n",(S),(O)->LowPart,E); \
64 _MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__); \
67 extern MMSESSION MmSession
;
71 MiMapViewInSystemSpace(IN PVOID Section
,
73 OUT PVOID
*MappedBase
,
74 IN OUT PSIZE_T ViewSize
);
78 MmCreateArm3Section(OUT PVOID
*SectionObject
,
79 IN ACCESS_MASK DesiredAccess
,
80 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
81 IN PLARGE_INTEGER InputMaximumSize
,
82 IN ULONG SectionPageProtection
,
83 IN ULONG AllocationAttributes
,
84 IN HANDLE FileHandle OPTIONAL
,
85 IN PFILE_OBJECT FileObject OPTIONAL
);
89 MmMapViewOfArm3Section(IN PVOID SectionObject
,
91 IN OUT PVOID
*BaseAddress
,
92 IN ULONG_PTR ZeroBits
,
94 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
95 IN OUT PSIZE_T ViewSize
,
96 IN SECTION_INHERIT InheritDisposition
,
97 IN ULONG AllocationType
,
101 // PeFmtCreateSection depends on the following:
103 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE
>= sizeof(IMAGE_DOS_HEADER
));
104 C_ASSERT(sizeof(IMAGE_NT_HEADERS32
) <= sizeof(IMAGE_NT_HEADERS64
));
106 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64
));
107 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64
, FileHeader
));
108 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
) == FIELD_OFFSET(IMAGE_NT_HEADERS64
, OptionalHeader
));
110 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Magic
));
111 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SectionAlignment
));
112 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, FileAlignment
));
113 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, Subsystem
));
114 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MinorSubsystemVersion
));
115 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, MajorSubsystemVersion
));
116 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, AddressOfEntryPoint
));
117 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfCode
));
118 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32
, IMAGE_OPTIONAL_HEADER64
, SizeOfHeaders
));
120 /* TYPES *********************************************************************/
124 PROS_SECTION_OBJECT Section
;
125 PMM_SECTION_SEGMENT Segment
;
126 LARGE_INTEGER Offset
;
129 PEPROCESS CallingProcess
;
130 ULONG_PTR SectionEntry
;
132 MM_SECTION_PAGEOUT_CONTEXT
;
134 /* GLOBALS *******************************************************************/
136 POBJECT_TYPE MmSectionObjectType
= NULL
;
138 ULONG_PTR MmSubsectionBase
;
140 static ULONG SectionCharacteristicsToProtect
[16] =
142 PAGE_NOACCESS
, /* 0 = NONE */
143 PAGE_NOACCESS
, /* 1 = SHARED */
144 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
145 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
146 PAGE_READONLY
, /* 4 = READABLE */
147 PAGE_READONLY
, /* 5 = READABLE, SHARED */
148 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
149 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
151 * FIXME? do we really need the WriteCopy field in segments? can't we use
152 * PAGE_WRITECOPY here?
154 PAGE_READWRITE
, /* 8 = WRITABLE */
155 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
156 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
157 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
158 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
159 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
160 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
161 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
164 ACCESS_MASK NTAPI
MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection
);
165 static GENERIC_MAPPING MmpSectionMapping
= {
166 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
167 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
168 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
171 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
173 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
174 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
177 /* FUNCTIONS *****************************************************************/
182 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
183 File Format Specification", revision 6.0 (February 1999)
185 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
186 IN SIZE_T FileHeaderSize
,
188 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
190 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
191 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
194 ULONG cbFileHeaderOffsetSize
= 0;
195 ULONG cbSectionHeadersOffset
= 0;
196 ULONG cbSectionHeadersSize
;
197 ULONG cbSectionHeadersOffsetSize
= 0;
198 ULONG cbOptHeaderSize
;
199 ULONG cbHeadersSize
= 0;
200 ULONG nSectionAlignment
;
201 ULONG nFileAlignment
;
202 const IMAGE_DOS_HEADER
* pidhDosHeader
;
203 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
204 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
205 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
206 PMM_SECTION_SEGMENT pssSegments
;
207 LARGE_INTEGER lnOffset
;
209 SIZE_T nPrevVirtualEndOfSegment
= 0;
210 ULONG nFileSizeOfHeaders
= 0;
214 ASSERT(FileHeaderSize
> 0);
216 ASSERT(ImageSectionObject
);
218 ASSERT(AllocateSegmentsCb
);
220 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
222 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
224 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
227 pidhDosHeader
= FileHeader
;
230 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
232 /* image too small to be an MZ executable */
233 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
234 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
236 /* no MZ signature */
237 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
238 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
240 /* not a Windows executable */
241 if(pidhDosHeader
->e_lfanew
<= 0)
242 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
245 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
247 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
248 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
250 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
255 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
256 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
258 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
259 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
263 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
264 * need to read the header from the file
266 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
267 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
269 ULONG cbNtHeaderSize
;
273 l_ReadHeaderFromFile
:
275 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
277 /* read the header from the file */
278 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
280 if(!NT_SUCCESS(nStatus
))
281 DIE(("ReadFile failed, status %08X\n", nStatus
));
285 ASSERT(cbReadSize
> 0);
287 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
289 /* the buffer doesn't contain the file header */
290 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
291 DIE(("The file doesn't contain the PE file header\n"));
293 pinhNtHeader
= pData
;
295 /* object still not aligned: copy it to the beginning of the buffer */
296 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
298 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
299 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
300 pinhNtHeader
= pBuffer
;
303 /* invalid NT header */
304 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
306 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
307 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
309 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
311 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
312 DIE(("The full NT header is too large\n"));
314 /* the buffer doesn't contain the whole NT header */
315 if(cbReadSize
< cbNtHeaderSize
)
316 DIE(("The file doesn't contain the full NT header\n"));
320 ULONG cbOptHeaderOffsetSize
= 0;
322 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
324 /* don't trust an invalid NT header */
325 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
326 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
328 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
329 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
331 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
332 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
334 /* the buffer doesn't contain the whole NT header: read it from the file */
335 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
336 goto l_ReadHeaderFromFile
;
339 /* read information from the NT header */
340 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
341 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
343 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
345 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
346 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
348 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
350 switch(piohOptHeader
->Magic
)
352 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
353 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
357 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
360 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
361 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
363 /* See [1], section 3.4.2 */
364 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
366 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
367 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
369 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
370 DIE(("The section alignment is smaller than the file alignment\n"));
372 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
373 nFileAlignment
= piohOptHeader
->FileAlignment
;
375 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
376 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
380 nSectionAlignment
= PAGE_SIZE
;
381 nFileAlignment
= PAGE_SIZE
;
384 ASSERT(IsPowerOf2(nSectionAlignment
));
385 ASSERT(IsPowerOf2(nFileAlignment
));
387 switch(piohOptHeader
->Magic
)
390 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
392 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
393 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
395 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
396 ImageSectionObject
->ImageSize
= piohOptHeader
->SizeOfImage
;
398 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
399 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
401 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
402 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
408 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
410 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
412 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
414 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
416 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
417 DIE(("ImageBase exceeds the address space\n"));
419 ImageSectionObject
->ImageBase
= (ULONG_PTR
)pioh64OptHeader
->ImageBase
;
422 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
424 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
425 DIE(("SizeOfImage exceeds the address space\n"));
427 ImageSectionObject
->ImageSize
= pioh64OptHeader
->SizeOfImage
;
430 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
432 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
433 DIE(("SizeOfStackReserve exceeds the address space\n"));
435 ImageSectionObject
->StackReserve
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackReserve
;
438 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
440 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
441 DIE(("SizeOfStackCommit exceeds the address space\n"));
443 ImageSectionObject
->StackCommit
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackCommit
;
450 /* [1], section 3.4.2 */
451 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
452 DIE(("ImageBase is not aligned on a 64KB boundary"));
454 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
456 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
458 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
459 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
461 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
462 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
466 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
468 ImageSectionObject
->EntryPoint
= ImageSectionObject
->ImageBase
+
469 piohOptHeader
->AddressOfEntryPoint
;
472 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
473 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
475 ImageSectionObject
->Executable
= TRUE
;
477 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
478 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
480 /* SECTION HEADERS */
481 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
483 /* see [1], section 3.3 */
484 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
485 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
488 * the additional segment is for the file's headers. They need to be present for
489 * the benefit of the dynamic loader (to locate exports, defaults for thread
490 * parameters, resources, etc.)
492 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
494 /* file offset for the section headers */
495 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
496 DIE(("Offset overflow\n"));
498 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
499 DIE(("Offset overflow\n"));
501 /* size of the section headers */
502 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
503 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
505 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
506 DIE(("Section headers too large\n"));
508 /* size of the executable's headers */
509 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
511 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
512 // DIE(("SizeOfHeaders is not aligned\n"));
514 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
515 DIE(("The section headers overflow SizeOfHeaders\n"));
517 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
519 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
520 DIE(("Overflow aligning the size of headers\n"));
527 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
528 /* WARNING: piohOptHeader IS NO LONGER USABLE */
529 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
531 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
532 pishSectionHeaders
= NULL
;
536 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
537 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
539 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
540 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
544 * the buffer doesn't contain the section headers, or the alignment is wrong:
545 * read the headers from the file
547 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
548 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
553 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
555 /* read the header from the file */
556 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
558 if(!NT_SUCCESS(nStatus
))
559 DIE(("ReadFile failed with status %08X\n", nStatus
));
563 ASSERT(cbReadSize
> 0);
565 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
567 /* the buffer doesn't contain all the section headers */
568 if(cbReadSize
< cbSectionHeadersSize
)
569 DIE(("The file doesn't contain all of the section headers\n"));
571 pishSectionHeaders
= pData
;
573 /* object still not aligned: copy it to the beginning of the buffer */
574 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
576 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
577 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
578 pishSectionHeaders
= pBuffer
;
583 /* allocate the segments */
584 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
585 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
587 if(ImageSectionObject
->Segments
== NULL
)
588 DIE(("AllocateSegments failed\n"));
590 /* initialize the headers segment */
591 pssSegments
= ImageSectionObject
->Segments
;
593 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
595 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
596 DIE(("Cannot align the size of the section headers\n"));
598 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
599 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
600 DIE(("Cannot align the size of the section headers\n"));
602 pssSegments
[0].Image
.FileOffset
= 0;
603 pssSegments
[0].Protection
= PAGE_READONLY
;
604 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
605 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
606 pssSegments
[0].Image
.VirtualAddress
= 0;
607 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
608 pssSegments
[0].WriteCopy
= TRUE
;
610 /* skip the headers segment */
613 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
615 /* convert the executable sections into segments. See also [1], section 4 */
616 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
618 ULONG nCharacteristics
;
620 /* validate the alignment */
621 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
622 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
624 /* sections must be contiguous, ordered by base address and non-overlapping */
625 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
626 DIE(("Memory gap between section %u and the previous\n", i
));
628 /* ignore explicit BSS sections */
629 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
631 /* validate the alignment */
633 /* Yes, this should be a multiple of FileAlignment, but there's
634 * stuff out there that isn't. We can cope with that
636 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
637 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
640 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
641 // DIE(("PointerToRawData[%u] is not aligned\n", i));
644 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
645 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
649 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
650 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
653 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
655 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
657 /* no explicit protection */
658 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
660 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
661 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
663 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
664 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
666 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
667 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
670 /* see table above */
671 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
672 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
674 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
675 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
677 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
679 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
680 /* FIXME: always false */
681 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
682 DIE(("Cannot align the virtual size of section %u\n", i
));
684 if(pssSegments
[i
].Length
.QuadPart
== 0)
685 DIE(("Virtual size of section %u is null\n", i
));
687 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
688 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
690 /* ensure the memory image is no larger than 4GB */
691 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
692 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
693 DIE(("The image is too large\n"));
696 if(nSectionAlignment
>= PAGE_SIZE
)
697 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
700 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;
710 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
711 * ARGUMENTS: PFILE_OBJECT to wait for.
712 * RETURNS: Status of the wait.
715 MmspWaitForFileLock(PFILE_OBJECT File
)
717 return STATUS_SUCCESS
;
718 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
723 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
725 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
727 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
728 PMM_SECTION_SEGMENT SectionSegments
;
732 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
733 NrSegments
= ImageSectionObject
->NrSegments
;
734 SectionSegments
= ImageSectionObject
->Segments
;
735 for (i
= 0; i
< NrSegments
; i
++)
737 if (SectionSegments
[i
].ReferenceCount
!= 0)
739 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
740 SectionSegments
[i
].ReferenceCount
);
741 KeBugCheck(MEMORY_MANAGEMENT
);
743 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
745 ExFreePool(ImageSectionObject
->Segments
);
746 ExFreePool(ImageSectionObject
);
747 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
749 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
751 PMM_SECTION_SEGMENT Segment
;
753 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
756 if (Segment
->ReferenceCount
!= 0)
758 DPRINT1("Data segment still referenced\n");
759 KeBugCheck(MEMORY_MANAGEMENT
);
761 MmFreePageTablesSectionSegment(Segment
, NULL
);
763 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
769 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
770 PLARGE_INTEGER Offset
)
774 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
777 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
778 KeBugCheck(MEMORY_MANAGEMENT
);
780 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
782 DPRINT1("Maximum share count reached\n");
783 KeBugCheck(MEMORY_MANAGEMENT
);
785 if (IS_SWAP_FROM_SSE(Entry
))
787 KeBugCheck(MEMORY_MANAGEMENT
);
789 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
790 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
795 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
796 PMM_SECTION_SEGMENT Segment
,
797 PLARGE_INTEGER Offset
,
802 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
803 BOOLEAN IsDirectMapped
= FALSE
;
807 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
808 KeBugCheck(MEMORY_MANAGEMENT
);
810 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
812 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
813 KeBugCheck(MEMORY_MANAGEMENT
);
815 if (IS_SWAP_FROM_SSE(Entry
))
817 KeBugCheck(MEMORY_MANAGEMENT
);
819 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
821 * If we reducing the share count of this entry to zero then set the entry
822 * to zero and tell the cache the page is no longer mapped.
824 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
826 PFILE_OBJECT FileObject
;
830 SWAPENTRY SavedSwapEntry
;
832 BOOLEAN IsImageSection
;
833 LARGE_INTEGER FileOffset
;
835 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
837 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
839 Page
= PFN_FROM_SSE(Entry
);
840 FileObject
= Section
->FileObject
;
841 if (FileObject
!= NULL
&&
842 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
846 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
847 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
850 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
851 IsDirectMapped
= TRUE
;
853 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
.LowPart
, Dirty
);
855 Status
= STATUS_SUCCESS
;
857 if (!NT_SUCCESS(Status
))
859 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
860 KeBugCheck(MEMORY_MANAGEMENT
);
866 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
867 if (SavedSwapEntry
== 0)
870 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
871 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
875 * Try to page out this page and set the swap entry
876 * within the section segment. There exist no rmap entry
877 * for this page. The pager thread can't page out a
878 * page without a rmap entry.
880 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
881 if (InEntry
) *InEntry
= Entry
;
882 MiSetPageEvent(NULL
, NULL
);
886 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
887 if (InEntry
) *InEntry
= 0;
888 MiSetPageEvent(NULL
, NULL
);
891 MmReleasePageMemoryConsumer(MC_USER
, Page
);
897 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
898 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
906 * We hold all locks. Nobody can do something with the current
907 * process and the current segment (also not within an other process).
910 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
911 if (!NT_SUCCESS(Status
))
913 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
914 KeBugCheck(MEMORY_MANAGEMENT
);
917 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
918 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
919 MmSetSavedSwapEntryPage(Page
, 0);
920 MiSetPageEvent(NULL
, NULL
);
922 MmReleasePageMemoryConsumer(MC_USER
, Page
);
926 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
927 KeBugCheck(MEMORY_MANAGEMENT
);
936 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
938 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
941 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
945 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
948 PCACHE_SEGMENT CacheSeg
;
949 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
950 CacheSeg
= CcRosLookupCacheSegment(Bcb
, (ULONG
)(SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
));
953 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
963 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
967 PVOID DestAddress
, SrcAddress
;
969 Process
= PsGetCurrentProcess();
970 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
971 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
972 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
974 return(STATUS_NO_MEMORY
);
976 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
977 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
978 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
979 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
980 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
981 return(STATUS_SUCCESS
);
987 MiReadPage(PMEMORY_AREA MemoryArea
,
991 * FUNCTION: Read a page for a section backed memory area.
993 * MemoryArea - Memory area to read the page for.
994 * Offset - Offset of the page to read.
995 * Page - Variable that receives a page contains the read data.
999 ULONGLONG FileOffset
;
1002 PCACHE_SEGMENT CacheSeg
;
1003 PFILE_OBJECT FileObject
;
1005 ULONG_PTR RawLength
;
1007 BOOLEAN IsImageSection
;
1010 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1011 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1012 RawLength
= (ULONG_PTR
)(MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
);
1013 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1014 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1018 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1021 * If the file system is letting us go directly to the cache and the
1022 * memory area was mapped at an offset in the file which is page aligned
1023 * then get the related cache segment.
1025 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1026 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1027 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1031 * Get the related cache segment; we use a lower level interface than
1032 * filesystems do because it is safe for us to use an offset with a
1033 * alignment less than the file system block size.
1035 Status
= CcRosGetCacheSegment(Bcb
,
1041 if (!NT_SUCCESS(Status
))
1048 * If the cache segment isn't up to date then call the file
1049 * system to read in the data.
1051 Status
= ReadCacheSegment(CacheSeg
);
1052 if (!NT_SUCCESS(Status
))
1054 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1059 * Retrieve the page from the cache segment that we actually want.
1061 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1062 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1064 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1071 ULONG_PTR CacheSegOffset
;
1074 * Allocate a page, this is rather complicated by the possibility
1075 * we might have to move other things out of memory
1077 MI_SET_USAGE(MI_USAGE_SECTION
);
1078 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1079 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1080 if (!NT_SUCCESS(Status
))
1084 Status
= CcRosGetCacheSegment(Bcb
,
1090 if (!NT_SUCCESS(Status
))
1097 * If the cache segment isn't up to date then call the file
1098 * system to read in the data.
1100 Status
= ReadCacheSegment(CacheSeg
);
1101 if (!NT_SUCCESS(Status
))
1103 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1108 Process
= PsGetCurrentProcess();
1109 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1110 CacheSegOffset
= (ULONG_PTR
)(BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
);
1111 Length
= RawLength
- SegOffset
;
1112 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1114 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1116 else if (CacheSegOffset
>= PAGE_SIZE
)
1118 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1122 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1123 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1124 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1125 Status
= CcRosGetCacheSegment(Bcb
,
1126 (ULONG
)(FileOffset
+ CacheSegOffset
),
1131 if (!NT_SUCCESS(Status
))
1138 * If the cache segment isn't up to date then call the file
1139 * system to read in the data.
1141 Status
= ReadCacheSegment(CacheSeg
);
1142 if (!NT_SUCCESS(Status
))
1144 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1148 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1149 if (Length
< PAGE_SIZE
)
1151 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1155 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1158 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1159 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1161 return(STATUS_SUCCESS
);
1166 MiReadPage(PMEMORY_AREA MemoryArea
,
1167 ULONG_PTR SegOffset
,
1170 * FUNCTION: Read a page for a section backed memory area.
1172 * MemoryArea - Memory area to read the page for.
1173 * Offset - Offset of the page to read.
1174 * Page - Variable that receives a page contains the read data.
1177 MM_REQUIRED_RESOURCES Resources
;
1180 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1182 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1183 Resources
.FileOffset
.QuadPart
= SegOffset
+
1184 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1185 Resources
.Consumer
= MC_USER
;
1186 Resources
.Amount
= PAGE_SIZE
;
1188 DPRINT("%S, offset 0x%x, len 0x%x, page 0x%x\n", ((PFILE_OBJECT
)Resources
.Context
)->FileName
.Buffer
, Resources
.FileOffset
.LowPart
, Resources
.Amount
, Resources
.Page
[0]);
1190 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1191 *Page
= Resources
.Page
[0];
1198 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1199 MEMORY_AREA
* MemoryArea
,
1203 LARGE_INTEGER Offset
;
1206 PROS_SECTION_OBJECT Section
;
1207 PMM_SECTION_SEGMENT Segment
;
1212 BOOLEAN HasSwapEntry
;
1214 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1215 SWAPENTRY SwapEntry
;
1218 * There is a window between taking the page fault and locking the
1219 * address space when another thread could load the page so we check
1222 if (MmIsPagePresent(Process
, Address
))
1224 return(STATUS_SUCCESS
);
1227 if (MmIsDisabledPage(Process
, Address
))
1229 return(STATUS_ACCESS_VIOLATION
);
1233 * Check for the virtual memory area being deleted.
1235 if (MemoryArea
->DeleteInProgress
)
1237 return(STATUS_UNSUCCESSFUL
);
1240 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1241 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1242 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1244 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1245 Section
= MemoryArea
->Data
.SectionData
.Section
;
1246 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1247 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1249 ASSERT(Region
!= NULL
);
1253 MmLockSectionSegment(Segment
);
1254 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1256 * Check if this page needs to be mapped COW
1258 if ((Segment
->WriteCopy
) &&
1259 (Region
->Protect
== PAGE_READWRITE
||
1260 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1262 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1266 Attributes
= Region
->Protect
;
1270 * Check if someone else is already handling this fault, if so wait
1273 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1275 MmUnlockSectionSegment(Segment
);
1276 MmUnlockAddressSpace(AddressSpace
);
1277 MiWaitForPageEvent(NULL
, NULL
);
1278 MmLockAddressSpace(AddressSpace
);
1279 DPRINT("Address 0x%.8X\n", Address
);
1280 return(STATUS_MM_RESTART_OPERATION
);
1283 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1287 SWAPENTRY DummyEntry
;
1290 * Is it a wait entry?
1292 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1294 if (SwapEntry
== MM_WAIT_ENTRY
)
1296 MmUnlockSectionSegment(Segment
);
1297 MmUnlockAddressSpace(AddressSpace
);
1298 MiWaitForPageEvent(NULL
, NULL
);
1299 MmLockAddressSpace(AddressSpace
);
1300 return STATUS_MM_RESTART_OPERATION
;
1304 * Must be private page we have swapped out.
1310 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1312 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1313 KeBugCheck(MEMORY_MANAGEMENT
);
1316 MmUnlockSectionSegment(Segment
);
1317 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1318 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1320 MmUnlockAddressSpace(AddressSpace
);
1321 MI_SET_USAGE(MI_USAGE_SECTION
);
1322 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1323 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1324 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1325 if (!NT_SUCCESS(Status
))
1327 KeBugCheck(MEMORY_MANAGEMENT
);
1330 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1331 if (!NT_SUCCESS(Status
))
1333 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1334 KeBugCheck(MEMORY_MANAGEMENT
);
1336 MmLockAddressSpace(AddressSpace
);
1337 MmDeletePageFileMapping(Process
, PAddress
, &DummyEntry
);
1338 Status
= MmCreateVirtualMapping(Process
,
1343 if (!NT_SUCCESS(Status
))
1345 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1346 KeBugCheck(MEMORY_MANAGEMENT
);
1351 * Store the swap entry for later use.
1353 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1356 * Add the page to the process's working set
1358 MmInsertRmap(Page
, Process
, Address
);
1360 * Finish the operation
1362 MiSetPageEvent(Process
, Address
);
1363 DPRINT("Address 0x%.8X\n", Address
);
1364 return(STATUS_SUCCESS
);
1368 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1370 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1372 MmUnlockSectionSegment(Segment
);
1374 * Just map the desired physical page
1376 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1377 Status
= MmCreateVirtualMappingUnsafe(Process
,
1382 if (!NT_SUCCESS(Status
))
1384 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1385 KeBugCheck(MEMORY_MANAGEMENT
);
1390 * Cleanup and release locks
1392 MiSetPageEvent(Process
, Address
);
1393 DPRINT("Address 0x%.8X\n", Address
);
1394 return(STATUS_SUCCESS
);
1398 * Get the entry corresponding to the offset within the section
1400 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1404 SWAPENTRY FakeSwapEntry
;
1407 * If the entry is zero (and it can't change because we have
1408 * locked the segment) then we need to load the page.
1412 * Release all our locks and read in the page from disk
1414 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1415 MmUnlockSectionSegment(Segment
);
1416 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1417 MmUnlockAddressSpace(AddressSpace
);
1419 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1420 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1421 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1423 MI_SET_USAGE(MI_USAGE_SECTION
);
1424 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1425 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1426 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1427 if (!NT_SUCCESS(Status
))
1429 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1435 Status
= MiReadPage(MemoryArea
, (ULONG_PTR
)Offset
.QuadPart
, &Page
);
1436 if (!NT_SUCCESS(Status
))
1438 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1441 if (!NT_SUCCESS(Status
))
1444 * FIXME: What do we know in this case?
1447 * Cleanup and release locks
1449 MmLockAddressSpace(AddressSpace
);
1450 MiSetPageEvent(Process
, Address
);
1451 DPRINT("Address 0x%.8X\n", Address
);
1456 * Mark the offset within the section as having valid, in-memory
1459 MmLockAddressSpace(AddressSpace
);
1460 MmLockSectionSegment(Segment
);
1461 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1462 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1463 MmUnlockSectionSegment(Segment
);
1465 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1466 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1467 Page
, Process
, PAddress
, Attributes
);
1468 Status
= MmCreateVirtualMapping(Process
,
1473 if (!NT_SUCCESS(Status
))
1475 DPRINT1("Unable to create virtual mapping\n");
1476 KeBugCheck(MEMORY_MANAGEMENT
);
1478 ASSERT(MmIsPagePresent(Process
, PAddress
));
1479 MmInsertRmap(Page
, Process
, Address
);
1481 MiSetPageEvent(Process
, Address
);
1482 DPRINT("Address 0x%.8X\n", Address
);
1483 return(STATUS_SUCCESS
);
1485 else if (IS_SWAP_FROM_SSE(Entry
))
1487 SWAPENTRY SwapEntry
;
1489 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1492 * Release all our locks and read in the page from disk
1494 MmUnlockSectionSegment(Segment
);
1496 MmUnlockAddressSpace(AddressSpace
);
1497 MI_SET_USAGE(MI_USAGE_SECTION
);
1498 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1499 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1500 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1501 if (!NT_SUCCESS(Status
))
1503 KeBugCheck(MEMORY_MANAGEMENT
);
1506 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1507 if (!NT_SUCCESS(Status
))
1509 KeBugCheck(MEMORY_MANAGEMENT
);
1513 * Relock the address space and segment
1515 MmLockAddressSpace(AddressSpace
);
1516 MmLockSectionSegment(Segment
);
1519 * Check the entry. No one should change the status of a page
1520 * that has a pending page-in.
1522 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1523 if (Entry
!= Entry1
)
1525 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1526 KeBugCheck(MEMORY_MANAGEMENT
);
1530 * Mark the offset within the section as having valid, in-memory
1533 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1534 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1535 MmUnlockSectionSegment(Segment
);
1538 * Save the swap entry.
1540 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1541 Status
= MmCreateVirtualMapping(Process
,
1546 if (!NT_SUCCESS(Status
))
1548 DPRINT1("Unable to create virtual mapping\n");
1549 KeBugCheck(MEMORY_MANAGEMENT
);
1551 MmInsertRmap(Page
, Process
, Address
);
1552 MiSetPageEvent(Process
, Address
);
1553 DPRINT("Address 0x%.8X\n", Address
);
1554 return(STATUS_SUCCESS
);
1559 * If the section offset is already in-memory and valid then just
1560 * take another reference to the page
1563 Page
= PFN_FROM_SSE(Entry
);
1565 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1566 MmUnlockSectionSegment(Segment
);
1568 Status
= MmCreateVirtualMapping(Process
,
1573 if (!NT_SUCCESS(Status
))
1575 DPRINT1("Unable to create virtual mapping\n");
1576 KeBugCheck(MEMORY_MANAGEMENT
);
1578 MmInsertRmap(Page
, Process
, Address
);
1579 MiSetPageEvent(Process
, Address
);
1580 DPRINT("Address 0x%.8X\n", Address
);
1581 return(STATUS_SUCCESS
);
1587 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1588 MEMORY_AREA
* MemoryArea
,
1591 PMM_SECTION_SEGMENT Segment
;
1592 PROS_SECTION_OBJECT Section
;
1597 LARGE_INTEGER Offset
;
1600 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1601 SWAPENTRY SwapEntry
;
1603 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
);
1606 * Check if the page has already been set readwrite
1608 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1610 DPRINT("Address 0x%.8X\n", Address
);
1611 return(STATUS_SUCCESS
);
1615 * Find the offset of the page
1617 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1618 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1619 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1621 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1622 Section
= MemoryArea
->Data
.SectionData
.Section
;
1623 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1624 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1626 ASSERT(Region
!= NULL
);
1630 MmLockSectionSegment(Segment
);
1632 OldPage
= MmGetPfnForProcess(Process
, Address
);
1633 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1635 MmUnlockSectionSegment(Segment
);
1638 * Check if we are doing COW
1640 if (!((Segment
->WriteCopy
) &&
1641 (Region
->Protect
== PAGE_READWRITE
||
1642 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1644 DPRINT("Address 0x%.8X\n", Address
);
1645 return(STATUS_ACCESS_VIOLATION
);
1648 if (IS_SWAP_FROM_SSE(Entry
) ||
1649 PFN_FROM_SSE(Entry
) != OldPage
)
1651 /* This is a private page. We must only change the page protection. */
1652 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1653 return(STATUS_SUCCESS
);
1657 DPRINT("OldPage == 0!\n");
1660 * Get or create a pageop
1662 MmLockSectionSegment(Segment
);
1663 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1666 * Wait for any other operations to complete
1668 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1670 MmUnlockSectionSegment(Segment
);
1671 MmUnlockAddressSpace(AddressSpace
);
1672 MiWaitForPageEvent(NULL
, NULL
);
1674 * Restart the operation
1676 MmLockAddressSpace(AddressSpace
);
1677 DPRINT("Address 0x%.8X\n", Address
);
1678 return(STATUS_MM_RESTART_OPERATION
);
1681 MmDeleteRmap(OldPage
, Process
, PAddress
);
1682 MmDeleteVirtualMapping(Process
, PAddress
, FALSE
, NULL
, NULL
);
1683 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1686 * Release locks now we have the pageop
1688 MmUnlockSectionSegment(Segment
);
1689 MmUnlockAddressSpace(AddressSpace
);
1694 MI_SET_USAGE(MI_USAGE_SECTION
);
1695 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1696 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1697 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1698 if (!NT_SUCCESS(Status
))
1700 KeBugCheck(MEMORY_MANAGEMENT
);
1706 MiCopyFromUserPage(NewPage
, OldPage
);
1708 MmLockAddressSpace(AddressSpace
);
1711 * Set the PTE to point to the new page
1713 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1714 Status
= MmCreateVirtualMapping(Process
,
1719 if (!NT_SUCCESS(Status
))
1721 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
1722 KeBugCheck(MEMORY_MANAGEMENT
);
1727 * Unshare the old page.
1729 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1730 MmInsertRmap(NewPage
, Process
, PAddress
);
1731 MmLockSectionSegment(Segment
);
1732 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1733 MmUnlockSectionSegment(Segment
);
1735 MiSetPageEvent(Process
, Address
);
1736 DPRINT("Address 0x%.8X\n", Address
);
1737 return(STATUS_SUCCESS
);
1741 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1743 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1745 PFN_NUMBER Page
= 0;
1747 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1750 MmLockAddressSpace(&Process
->Vm
);
1753 MmDeleteVirtualMapping(Process
,
1760 PageOutContext
->WasDirty
= TRUE
;
1762 if (!PageOutContext
->Private
)
1764 MmLockSectionSegment(PageOutContext
->Segment
);
1765 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1766 PageOutContext
->Segment
,
1767 &PageOutContext
->Offset
,
1768 PageOutContext
->WasDirty
,
1770 &PageOutContext
->SectionEntry
);
1771 MmUnlockSectionSegment(PageOutContext
->Segment
);
1775 MmUnlockAddressSpace(&Process
->Vm
);
1778 if (PageOutContext
->Private
)
1780 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1786 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1787 MEMORY_AREA
* MemoryArea
,
1788 PVOID Address
, ULONG_PTR Entry
)
1791 MM_SECTION_PAGEOUT_CONTEXT Context
;
1792 SWAPENTRY SwapEntry
;
1793 ULONGLONG FileOffset
;
1795 PFILE_OBJECT FileObject
;
1799 BOOLEAN DirectMapped
;
1800 BOOLEAN IsImageSection
;
1801 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1804 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1807 * Get the segment and section.
1809 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1810 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1811 Context
.SectionEntry
= Entry
;
1812 Context
.CallingProcess
= Process
;
1814 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1815 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1816 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1818 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1820 FileObject
= Context
.Section
->FileObject
;
1821 DirectMapped
= FALSE
;
1823 MmLockSectionSegment(Context
.Segment
);
1826 if (FileObject
!= NULL
&&
1827 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1829 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1832 * If the file system is letting us go directly to the cache and the
1833 * memory area was mapped at an offset in the file which is page aligned
1834 * then note this is a direct mapped page.
1836 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1837 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1839 DirectMapped
= TRUE
;
1846 * This should never happen since mappings of physical memory are never
1847 * placed in the rmap lists.
1849 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1851 DPRINT1("Trying to page out from physical memory section address 0x%X "
1852 "process %d\n", Address
,
1853 Process
? Process
->UniqueProcessId
: 0);
1854 KeBugCheck(MEMORY_MANAGEMENT
);
1858 * Get the section segment entry and the physical address.
1860 if (!MmIsPagePresent(Process
, Address
))
1862 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1863 Process
? Process
->UniqueProcessId
: 0, Address
);
1864 KeBugCheck(MEMORY_MANAGEMENT
);
1866 Page
= MmGetPfnForProcess(Process
, Address
);
1867 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1870 * Check the reference count to ensure this page can be paged out
1872 if (MmGetReferenceCountPage(Page
) != 1)
1874 DPRINT("Cannot page out locked section page: 0x%p (RefCount: %d)\n",
1875 Page
, MmGetReferenceCountPage(Page
));
1876 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1877 MmUnlockSectionSegment(Context
.Segment
);
1878 return STATUS_UNSUCCESSFUL
;
1882 * Prepare the context structure for the rmap delete call.
1884 MmUnlockSectionSegment(Context
.Segment
);
1885 Context
.WasDirty
= FALSE
;
1886 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1887 IS_SWAP_FROM_SSE(Entry
) ||
1888 PFN_FROM_SSE(Entry
) != Page
)
1890 Context
.Private
= TRUE
;
1894 Context
.Private
= FALSE
;
1898 * Take an additional reference to the page or the cache segment.
1900 if (DirectMapped
&& !Context
.Private
)
1902 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
1904 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1905 KeBugCheck(MEMORY_MANAGEMENT
);
1910 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1911 MmReferencePage(Page
);
1912 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1915 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1917 /* Since we passed in a surrogate, we'll get back the page entry
1918 * state in our context. This is intended to make intermediate
1919 * decrements of share count not release the wait entry.
1921 Entry
= Context
.SectionEntry
;
1924 * If this wasn't a private page then we should have reduced the entry to
1925 * zero by deleting all the rmaps.
1927 if (!Context
.Private
&& Entry
!= 0)
1929 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1930 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1932 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
1937 * If the page wasn't dirty then we can just free it as for a readonly page.
1938 * Since we unmapped all the mappings above we know it will not suddenly
1940 * If the page is from a pagefile section and has no swap entry,
1941 * we can't free the page at this point.
1943 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1944 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1946 if (Context
.Private
)
1948 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1949 Context
.WasDirty
? "dirty" : "clean", Address
);
1950 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
1952 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1954 MmSetSavedSwapEntryPage(Page
, 0);
1955 MmLockSectionSegment(Context
.Segment
);
1956 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1957 MmUnlockSectionSegment(Context
.Segment
);
1958 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1959 MiSetPageEvent(NULL
, NULL
);
1960 return(STATUS_SUCCESS
);
1963 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
1965 if (Context
.Private
)
1967 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1968 Context
.WasDirty
? "dirty" : "clean", Address
);
1969 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
1971 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1973 MmSetSavedSwapEntryPage(Page
, 0);
1976 MmLockSectionSegment(Context
.Segment
);
1977 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1978 MmUnlockSectionSegment(Context
.Segment
);
1980 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1981 MiSetPageEvent(NULL
, NULL
);
1982 return(STATUS_SUCCESS
);
1985 else if (!Context
.Private
&& DirectMapped
)
1989 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1991 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
1994 Status
= CcRosUnmapCacheSegment(Bcb
, (ULONG
)FileOffset
, FALSE
);
1996 Status
= STATUS_SUCCESS
;
1999 if (!NT_SUCCESS(Status
))
2001 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2002 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Bcb
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2005 MiSetPageEvent(NULL
, NULL
);
2006 return(STATUS_SUCCESS
);
2008 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2012 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2014 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2016 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2017 MiSetPageEvent(NULL
, NULL
);
2018 return(STATUS_SUCCESS
);
2020 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2022 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2023 MmSetSavedSwapEntryPage(Page
, 0);
2024 MmLockAddressSpace(AddressSpace
);
2025 Status
= MmCreatePageFileMapping(Process
,
2028 MmUnlockAddressSpace(AddressSpace
);
2029 if (!NT_SUCCESS(Status
))
2031 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2032 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2034 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2035 MiSetPageEvent(NULL
, NULL
);
2036 return(STATUS_SUCCESS
);
2040 * If necessary, allocate an entry in the paging file for this page
2044 SwapEntry
= MmAllocSwapPage();
2047 MmShowOutOfSpaceMessagePagingFile();
2048 MmLockAddressSpace(AddressSpace
);
2050 * For private pages restore the old mappings.
2052 if (Context
.Private
)
2054 Status
= MmCreateVirtualMapping(Process
,
2056 MemoryArea
->Protect
,
2059 MmSetDirtyPage(Process
, Address
);
2068 * For non-private pages if the page wasn't direct mapped then
2069 * set it back into the section segment entry so we don't loose
2070 * our copy. Otherwise it will be handled by the cache manager.
2072 Status
= MmCreateVirtualMapping(Process
,
2074 MemoryArea
->Protect
,
2077 MmSetDirtyPage(Process
, Address
);
2081 // If we got here, the previous entry should have been a wait
2082 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2083 MmLockSectionSegment(Context
.Segment
);
2084 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2085 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2086 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2087 MmUnlockSectionSegment(Context
.Segment
);
2089 MmUnlockAddressSpace(AddressSpace
);
2090 MiSetPageEvent(NULL
, NULL
);
2091 return(STATUS_PAGEFILE_QUOTA
);
2096 * Write the page to the pagefile
2098 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2099 if (!NT_SUCCESS(Status
))
2101 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2104 * As above: undo our actions.
2105 * FIXME: Also free the swap page.
2107 MmLockAddressSpace(AddressSpace
);
2108 if (Context
.Private
)
2110 Status
= MmCreateVirtualMapping(Process
,
2112 MemoryArea
->Protect
,
2115 MmSetDirtyPage(Process
, Address
);
2122 Status
= MmCreateVirtualMapping(Process
,
2124 MemoryArea
->Protect
,
2127 MmSetDirtyPage(Process
, Address
);
2131 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2132 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2134 MmUnlockAddressSpace(AddressSpace
);
2135 MiSetPageEvent(NULL
, NULL
);
2136 return(STATUS_UNSUCCESSFUL
);
2140 * Otherwise we have succeeded.
2142 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2143 MmSetSavedSwapEntryPage(Page
, 0);
2144 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2145 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2147 MmLockSectionSegment(Context
.Segment
);
2148 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2149 MmUnlockSectionSegment(Context
.Segment
);
2153 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2156 if (Context
.Private
)
2158 MmLockAddressSpace(AddressSpace
);
2159 MmLockSectionSegment(Context
.Segment
);
2160 Status
= MmCreatePageFileMapping(Process
,
2163 /* We had placed a wait entry upon entry ... replace it before leaving */
2164 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2165 MmUnlockSectionSegment(Context
.Segment
);
2166 MmUnlockAddressSpace(AddressSpace
);
2167 if (!NT_SUCCESS(Status
))
2169 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2170 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2175 MmLockAddressSpace(AddressSpace
);
2176 MmLockSectionSegment(Context
.Segment
);
2177 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2178 /* We had placed a wait entry upon entry ... replace it before leaving */
2179 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2180 MmUnlockSectionSegment(Context
.Segment
);
2181 MmUnlockAddressSpace(AddressSpace
);
2184 MiSetPageEvent(NULL
, NULL
);
2185 return(STATUS_SUCCESS
);
2190 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2191 PMEMORY_AREA MemoryArea
,
2195 LARGE_INTEGER Offset
;
2196 PROS_SECTION_OBJECT Section
;
2197 PMM_SECTION_SEGMENT Segment
;
2199 SWAPENTRY SwapEntry
;
2203 PFILE_OBJECT FileObject
;
2205 BOOLEAN DirectMapped
;
2206 BOOLEAN IsImageSection
;
2207 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2209 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2211 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2212 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2215 * Get the segment and section.
2217 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2218 Section
= MemoryArea
->Data
.SectionData
.Section
;
2219 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2221 FileObject
= Section
->FileObject
;
2222 DirectMapped
= FALSE
;
2223 if (FileObject
!= NULL
&&
2224 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2226 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2229 * If the file system is letting us go directly to the cache and the
2230 * memory area was mapped at an offset in the file which is page aligned
2231 * then note this is a direct mapped page.
2233 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2234 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2236 DirectMapped
= TRUE
;
2241 * This should never happen since mappings of physical memory are never
2242 * placed in the rmap lists.
2244 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2246 DPRINT1("Trying to write back page from physical memory mapped at %X "
2247 "process %d\n", Address
,
2248 Process
? Process
->UniqueProcessId
: 0);
2249 KeBugCheck(MEMORY_MANAGEMENT
);
2253 * Get the section segment entry and the physical address.
2255 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2256 if (!MmIsPagePresent(Process
, Address
))
2258 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2259 Process
? Process
->UniqueProcessId
: 0, Address
);
2260 KeBugCheck(MEMORY_MANAGEMENT
);
2262 Page
= MmGetPfnForProcess(Process
, Address
);
2263 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2266 * Check for a private (COWed) page.
2268 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2269 IS_SWAP_FROM_SSE(Entry
) ||
2270 PFN_FROM_SSE(Entry
) != Page
)
2280 * Speculatively set all mappings of the page to clean.
2282 MmSetCleanAllRmaps(Page
);
2285 * If this page was direct mapped from the cache then the cache manager
2286 * will take care of writing it back to disk.
2288 if (DirectMapped
&& !Private
)
2290 LARGE_INTEGER SOffset
;
2291 ASSERT(SwapEntry
== 0);
2292 SOffset
.QuadPart
= Offset
.QuadPart
+ Segment
->Image
.FileOffset
;
2294 CcRosMarkDirtyCacheSegment(Bcb
, Offset
.LowPart
);
2296 MmLockSectionSegment(Segment
);
2297 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2298 MmUnlockSectionSegment(Segment
);
2299 MiSetPageEvent(NULL
, NULL
);
2300 return(STATUS_SUCCESS
);
2304 * If necessary, allocate an entry in the paging file for this page
2308 SwapEntry
= MmAllocSwapPage();
2311 MmSetDirtyAllRmaps(Page
);
2312 MiSetPageEvent(NULL
, NULL
);
2313 return(STATUS_PAGEFILE_QUOTA
);
2315 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2319 * Write the page to the pagefile
2321 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2322 if (!NT_SUCCESS(Status
))
2324 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2326 MmSetDirtyAllRmaps(Page
);
2327 MiSetPageEvent(NULL
, NULL
);
2328 return(STATUS_UNSUCCESSFUL
);
2332 * Otherwise we have succeeded.
2334 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2335 MiSetPageEvent(NULL
, NULL
);
2336 return(STATUS_SUCCESS
);
2340 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2348 PMEMORY_AREA MemoryArea
;
2349 PMM_SECTION_SEGMENT Segment
;
2350 BOOLEAN DoCOW
= FALSE
;
2352 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2354 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2355 ASSERT(MemoryArea
!= NULL
);
2356 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2357 MmLockSectionSegment(Segment
);
2359 if ((Segment
->WriteCopy
) &&
2360 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2365 if (OldProtect
!= NewProtect
)
2367 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2369 SWAPENTRY SwapEntry
;
2370 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2371 ULONG Protect
= NewProtect
;
2373 /* Wait for a wait entry to disappear */
2375 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2376 if (SwapEntry
!= MM_WAIT_ENTRY
)
2378 MiWaitForPageEvent(Process
, Address
);
2382 * If we doing COW for this segment then check if the page is
2385 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2387 LARGE_INTEGER Offset
;
2391 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2392 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2393 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2395 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2396 * IS_SWAP_FROM_SSE and we'll do the right thing.
2398 Page
= MmGetPfnForProcess(Process
, Address
);
2400 Protect
= PAGE_READONLY
;
2401 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2402 IS_SWAP_FROM_SSE(Entry
) ||
2403 PFN_FROM_SSE(Entry
) != Page
)
2405 Protect
= NewProtect
;
2409 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2411 MmSetPageProtect(Process
, Address
,
2417 MmUnlockSectionSegment(Segment
);
2422 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2423 PMEMORY_AREA MemoryArea
,
2431 ULONG_PTR MaxLength
;
2433 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2434 if (Length
> MaxLength
)
2435 Length
= (ULONG
)MaxLength
;
2437 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2438 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2440 ASSERT(Region
!= NULL
);
2442 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2443 Region
->Protect
!= Protect
)
2445 return STATUS_INVALID_PAGE_PROTECTION
;
2448 *OldProtect
= Region
->Protect
;
2449 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2450 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2451 BaseAddress
, Length
, Region
->Type
, Protect
,
2452 MmAlterViewAttributes
);
2458 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2460 PMEMORY_BASIC_INFORMATION Info
,
2461 PSIZE_T ResultLength
)
2464 PVOID RegionBaseAddress
;
2465 PROS_SECTION_OBJECT Section
;
2466 PMM_SECTION_SEGMENT Segment
;
2468 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2469 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2470 Address
, &RegionBaseAddress
);
2473 return STATUS_UNSUCCESSFUL
;
2476 Section
= MemoryArea
->Data
.SectionData
.Section
;
2477 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2479 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2480 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2481 Info
->Type
= MEM_IMAGE
;
2485 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2486 Info
->Type
= MEM_MAPPED
;
2488 Info
->BaseAddress
= RegionBaseAddress
;
2489 Info
->AllocationProtect
= MemoryArea
->Protect
;
2490 Info
->RegionSize
= Region
->Length
;
2491 Info
->State
= MEM_COMMIT
;
2492 Info
->Protect
= Region
->Protect
;
2494 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2495 return(STATUS_SUCCESS
);
2500 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2503 LARGE_INTEGER Offset
;
2505 SWAPENTRY SavedSwapEntry
;
2510 MmLockSectionSegment(Segment
);
2512 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2513 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2515 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2518 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2519 if (IS_SWAP_FROM_SSE(Entry
))
2521 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2525 Page
= PFN_FROM_SSE(Entry
);
2526 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2527 if (SavedSwapEntry
!= 0)
2529 MmSetSavedSwapEntryPage(Page
, 0);
2530 MmFreeSwapPage(SavedSwapEntry
);
2532 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2537 MmUnlockSectionSegment(Segment
);
2541 MmpDeleteSection(PVOID ObjectBody
)
2543 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2545 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2546 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2551 PMM_SECTION_SEGMENT SectionSegments
;
2554 * NOTE: Section->ImageSection can be NULL for short time
2555 * during the section creating. If we fail for some reason
2556 * until the image section is properly initialized we shouldn't
2557 * process further here.
2559 if (Section
->ImageSection
== NULL
)
2562 SectionSegments
= Section
->ImageSection
->Segments
;
2563 NrSegments
= Section
->ImageSection
->NrSegments
;
2565 for (i
= 0; i
< NrSegments
; i
++)
2567 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2569 MmLockSectionSegment(&SectionSegments
[i
]);
2571 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2572 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2574 MmUnlockSectionSegment(&SectionSegments
[i
]);
2577 MmpFreePageFileSegment(&SectionSegments
[i
]);
2583 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2586 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2589 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2591 DPRINT("Freeing section segment\n");
2592 Section
->Segment
= NULL
;
2593 MmFinalizeSegment(Segment
);
2597 DPRINT("RefCount %d\n", RefCount
);
2604 * NOTE: Section->Segment can be NULL for short time
2605 * during the section creating.
2607 if (Section
->Segment
== NULL
)
2610 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2612 MmpFreePageFileSegment(Section
->Segment
);
2613 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2614 ExFreePool(Section
->Segment
);
2615 Section
->Segment
= NULL
;
2619 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2622 if (Section
->FileObject
!= NULL
)
2625 CcRosDereferenceCache(Section
->FileObject
);
2627 ObDereferenceObject(Section
->FileObject
);
2628 Section
->FileObject
= NULL
;
2633 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2635 IN ACCESS_MASK GrantedAccess
,
2636 IN ULONG ProcessHandleCount
,
2637 IN ULONG SystemHandleCount
)
2639 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2640 Object
, ProcessHandleCount
);
2646 MmCreatePhysicalMemorySection(VOID
)
2648 PROS_SECTION_OBJECT PhysSection
;
2650 OBJECT_ATTRIBUTES Obj
;
2651 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2652 LARGE_INTEGER SectionSize
;
2656 * Create the section mapping physical memory
2658 SectionSize
.QuadPart
= 0xFFFFFFFF;
2659 InitializeObjectAttributes(&Obj
,
2664 Status
= MmCreateSection((PVOID
)&PhysSection
,
2668 PAGE_EXECUTE_READWRITE
,
2672 if (!NT_SUCCESS(Status
))
2674 DPRINT1("Failed to create PhysicalMemory section\n");
2675 KeBugCheck(MEMORY_MANAGEMENT
);
2677 Status
= ObInsertObject(PhysSection
,
2683 if (!NT_SUCCESS(Status
))
2685 ObDereferenceObject(PhysSection
);
2687 ObCloseHandle(Handle
, KernelMode
);
2688 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2689 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2691 return(STATUS_SUCCESS
);
2697 MmInitSectionImplementation(VOID
)
2699 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2700 UNICODE_STRING Name
;
2702 DPRINT("Creating Section Object Type\n");
2704 /* Initialize the section based root */
2705 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2706 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2708 /* Initialize the Section object type */
2709 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2710 RtlInitUnicodeString(&Name
, L
"Section");
2711 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2712 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2713 ObjectTypeInitializer
.PoolType
= PagedPool
;
2714 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2715 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2716 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2717 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2718 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2719 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
2720 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2722 MmCreatePhysicalMemorySection();
2724 return(STATUS_SUCCESS
);
2729 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2730 ACCESS_MASK DesiredAccess
,
2731 POBJECT_ATTRIBUTES ObjectAttributes
,
2732 PLARGE_INTEGER UMaximumSize
,
2733 ULONG SectionPageProtection
,
2734 ULONG AllocationAttributes
)
2736 * Create a section which is backed by the pagefile
2739 LARGE_INTEGER MaximumSize
;
2740 PROS_SECTION_OBJECT Section
;
2741 PMM_SECTION_SEGMENT Segment
;
2744 if (UMaximumSize
== NULL
)
2746 return(STATUS_UNSUCCESSFUL
);
2748 MaximumSize
= *UMaximumSize
;
2751 * Create the section
2753 Status
= ObCreateObject(ExGetPreviousMode(),
2754 MmSectionObjectType
,
2756 ExGetPreviousMode(),
2758 sizeof(ROS_SECTION_OBJECT
),
2761 (PVOID
*)(PVOID
)&Section
);
2762 if (!NT_SUCCESS(Status
))
2770 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2771 Section
->Type
= 'SC';
2772 Section
->Size
= 'TN';
2773 Section
->SectionPageProtection
= SectionPageProtection
;
2774 Section
->AllocationAttributes
= AllocationAttributes
;
2775 Section
->MaximumSize
= MaximumSize
;
2776 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2777 TAG_MM_SECTION_SEGMENT
);
2778 if (Segment
== NULL
)
2780 ObDereferenceObject(Section
);
2781 return(STATUS_NO_MEMORY
);
2783 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2784 Section
->Segment
= Segment
;
2785 Segment
->ReferenceCount
= 1;
2786 ExInitializeFastMutex(&Segment
->Lock
);
2787 Segment
->Image
.FileOffset
= 0;
2788 Segment
->Protection
= SectionPageProtection
;
2789 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2790 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2791 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2792 Segment
->WriteCopy
= FALSE
;
2793 Segment
->Image
.VirtualAddress
= 0;
2794 Segment
->Image
.Characteristics
= 0;
2795 *SectionObject
= Section
;
2796 MiInitializeSectionPageTable(Segment
);
2797 return(STATUS_SUCCESS
);
2802 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2803 ACCESS_MASK DesiredAccess
,
2804 POBJECT_ATTRIBUTES ObjectAttributes
,
2805 PLARGE_INTEGER UMaximumSize
,
2806 ULONG SectionPageProtection
,
2807 ULONG AllocationAttributes
,
2810 * Create a section backed by a data file
2813 PROS_SECTION_OBJECT Section
;
2815 LARGE_INTEGER MaximumSize
;
2816 PFILE_OBJECT FileObject
;
2817 PMM_SECTION_SEGMENT Segment
;
2819 IO_STATUS_BLOCK Iosb
;
2820 LARGE_INTEGER Offset
;
2822 FILE_STANDARD_INFORMATION FileInfo
;
2826 * Create the section
2828 Status
= ObCreateObject(ExGetPreviousMode(),
2829 MmSectionObjectType
,
2831 ExGetPreviousMode(),
2833 sizeof(ROS_SECTION_OBJECT
),
2837 if (!NT_SUCCESS(Status
))
2844 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2845 Section
->Type
= 'SC';
2846 Section
->Size
= 'TN';
2847 Section
->SectionPageProtection
= SectionPageProtection
;
2848 Section
->AllocationAttributes
= AllocationAttributes
;
2851 * Reference the file handle
2853 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2854 Status
= ObReferenceObjectByHandle(FileHandle
,
2857 ExGetPreviousMode(),
2858 (PVOID
*)(PVOID
)&FileObject
,
2860 if (!NT_SUCCESS(Status
))
2862 ObDereferenceObject(Section
);
2867 * FIXME: This is propably not entirely correct. We can't look into
2868 * the standard FCB header because it might not be initialized yet
2869 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2870 * standard file information is filled on first request).
2872 Status
= IoQueryFileInformation(FileObject
,
2873 FileStandardInformation
,
2874 sizeof(FILE_STANDARD_INFORMATION
),
2877 Iosb
.Information
= Length
;
2878 if (!NT_SUCCESS(Status
))
2880 ObDereferenceObject(Section
);
2881 ObDereferenceObject(FileObject
);
2886 * FIXME: Revise this once a locking order for file size changes is
2889 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2891 MaximumSize
= *UMaximumSize
;
2895 MaximumSize
= FileInfo
.EndOfFile
;
2896 /* Mapping zero-sized files isn't allowed. */
2897 if (MaximumSize
.QuadPart
== 0)
2899 ObDereferenceObject(Section
);
2900 ObDereferenceObject(FileObject
);
2901 return STATUS_FILE_INVALID
;
2905 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2907 Status
= IoSetInformation(FileObject
,
2908 FileAllocationInformation
,
2909 sizeof(LARGE_INTEGER
),
2911 if (!NT_SUCCESS(Status
))
2913 ObDereferenceObject(Section
);
2914 ObDereferenceObject(FileObject
);
2915 return(STATUS_SECTION_NOT_EXTENDED
);
2919 if (FileObject
->SectionObjectPointer
== NULL
||
2920 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2923 * Read a bit so caching is initiated for the file object.
2924 * This is only needed because MiReadPage currently cannot
2925 * handle non-cached streams.
2927 Offset
.QuadPart
= 0;
2928 Status
= ZwReadFile(FileHandle
,
2937 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2939 ObDereferenceObject(Section
);
2940 ObDereferenceObject(FileObject
);
2943 if (FileObject
->SectionObjectPointer
== NULL
||
2944 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2946 /* FIXME: handle this situation */
2947 ObDereferenceObject(Section
);
2948 ObDereferenceObject(FileObject
);
2949 return STATUS_INVALID_PARAMETER
;
2956 Status
= MmspWaitForFileLock(FileObject
);
2957 if (Status
!= STATUS_SUCCESS
)
2959 ObDereferenceObject(Section
);
2960 ObDereferenceObject(FileObject
);
2965 * If this file hasn't been mapped as a data file before then allocate a
2966 * section segment to describe the data file mapping
2968 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2970 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2971 TAG_MM_SECTION_SEGMENT
);
2972 if (Segment
== NULL
)
2974 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2975 ObDereferenceObject(Section
);
2976 ObDereferenceObject(FileObject
);
2977 return(STATUS_NO_MEMORY
);
2979 Section
->Segment
= Segment
;
2980 Segment
->ReferenceCount
= 1;
2981 ExInitializeFastMutex(&Segment
->Lock
);
2983 * Set the lock before assigning the segment to the file object
2985 ExAcquireFastMutex(&Segment
->Lock
);
2986 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2988 Segment
->Image
.FileOffset
= 0;
2989 Segment
->Protection
= SectionPageProtection
;
2990 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2991 Segment
->Image
.Characteristics
= 0;
2992 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
2993 if (AllocationAttributes
& SEC_RESERVE
)
2995 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
2999 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3000 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3002 Segment
->Image
.VirtualAddress
= 0;
3003 Segment
->Locked
= TRUE
;
3004 MiInitializeSectionPageTable(Segment
);
3009 * If the file is already mapped as a data file then we may need
3013 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3015 Section
->Segment
= Segment
;
3016 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3017 MmLockSectionSegment(Segment
);
3019 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3020 !(AllocationAttributes
& SEC_RESERVE
))
3022 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3023 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3026 MmUnlockSectionSegment(Segment
);
3027 Section
->FileObject
= FileObject
;
3028 Section
->MaximumSize
= MaximumSize
;
3030 CcRosReferenceCache(FileObject
);
3032 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3033 *SectionObject
= Section
;
3034 return(STATUS_SUCCESS
);
3038 TODO: not that great (declaring loaders statically, having to declare all of
3039 them, having to keep them extern, etc.), will fix in the future
3041 extern NTSTATUS NTAPI PeFmtCreateSection
3043 IN CONST VOID
* FileHeader
,
3044 IN SIZE_T FileHeaderSize
,
3046 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3048 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3049 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3052 extern NTSTATUS NTAPI ElfFmtCreateSection
3054 IN CONST VOID
* FileHeader
,
3055 IN SIZE_T FileHeaderSize
,
3057 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3059 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3060 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3063 /* TODO: this is a standard DDK/PSDK macro */
3064 #ifndef RTL_NUMBER_OF
3065 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3068 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3079 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3081 SIZE_T SizeOfSegments
;
3082 PMM_SECTION_SEGMENT Segments
;
3084 /* TODO: check for integer overflow */
3085 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3087 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3089 TAG_MM_SECTION_SEGMENT
);
3092 RtlZeroMemory(Segments
, SizeOfSegments
);
3100 ExeFmtpReadFile(IN PVOID File
,
3101 IN PLARGE_INTEGER Offset
,
3104 OUT PVOID
* AllocBase
,
3105 OUT PULONG ReadSize
)
3108 LARGE_INTEGER FileOffset
;
3110 ULONG OffsetAdjustment
;
3114 PFILE_OBJECT FileObject
= File
;
3115 IO_STATUS_BLOCK Iosb
;
3117 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3121 KeBugCheck(MEMORY_MANAGEMENT
);
3124 FileOffset
= *Offset
;
3126 /* Negative/special offset: it cannot be used in this context */
3127 if(FileOffset
.u
.HighPart
< 0)
3129 KeBugCheck(MEMORY_MANAGEMENT
);
3132 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3133 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3134 FileOffset
.u
.LowPart
= AdjustOffset
;
3136 BufferSize
= Length
+ OffsetAdjustment
;
3137 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3140 * It's ok to use paged pool, because this is a temporary buffer only used in
3141 * the loading of executables. The assumption is that MmCreateSection is
3142 * always called at low IRQLs and that these buffers don't survive a brief
3143 * initialization phase
3145 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3150 KeBugCheck(MEMORY_MANAGEMENT
);
3155 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3157 UsedSize
= (ULONG
)Iosb
.Information
;
3159 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3161 Status
= STATUS_IN_PAGE_ERROR
;
3162 ASSERT(!NT_SUCCESS(Status
));
3165 if(NT_SUCCESS(Status
))
3167 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3168 *AllocBase
= Buffer
;
3169 *ReadSize
= UsedSize
- OffsetAdjustment
;
3173 ExFreePoolWithTag(Buffer
, 'rXmM');
3180 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3181 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3182 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3187 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3191 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3193 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3194 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3201 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3205 MmspAssertSegmentsSorted(ImageSectionObject
);
3207 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3209 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3213 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3214 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3215 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3223 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3227 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3229 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3230 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3238 MmspCompareSegments(const void * x
,
3241 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3242 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3245 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3246 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3250 * Ensures an image section's segments are sorted in memory
3255 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3258 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3260 MmspAssertSegmentsSorted(ImageSectionObject
);
3264 qsort(ImageSectionObject
->Segments
,
3265 ImageSectionObject
->NrSegments
,
3266 sizeof(ImageSectionObject
->Segments
[0]),
3267 MmspCompareSegments
);
3273 * Ensures an image section's segments don't overlap in memory and don't have
3274 * gaps and don't have a null size. We let them map to overlapping file regions,
3275 * though - that's not necessarily an error
3280 MmspCheckSegmentBounds
3282 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3288 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3290 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3294 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3296 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3298 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3306 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3307 * page could be OK (Windows seems to be OK with them), and larger gaps
3308 * could lead to image sections spanning several discontiguous regions
3309 * (NtMapViewOfSection could then refuse to map them, and they could
3310 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3312 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3313 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3314 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3325 * Merges and pads an image section's segments until they all are page-aligned
3326 * and have a size that is a multiple of the page size
3331 MmspPageAlignSegments
3333 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3339 PMM_SECTION_SEGMENT EffectiveSegment
;
3341 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3343 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3348 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3350 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3353 * The first segment requires special handling
3357 ULONG_PTR VirtualAddress
;
3358 ULONG_PTR VirtualOffset
;
3360 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3362 /* Round down the virtual address to the nearest page */
3363 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3365 /* Round up the virtual size to the nearest page */
3366 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3367 EffectiveSegment
->Image
.VirtualAddress
;
3369 /* Adjust the raw address and size */
3370 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3372 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3378 * Garbage in, garbage out: unaligned base addresses make the file
3379 * offset point in curious and odd places, but that's what we were
3382 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3383 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3387 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3388 ULONG_PTR EndOfEffectiveSegment
;
3390 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3391 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3394 * The current segment begins exactly where the current effective
3395 * segment ended, therefore beginning a new effective segment
3397 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3400 ASSERT(LastSegment
<= i
);
3401 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3403 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3405 if (LastSegment
!= i
)
3408 * Copy the current segment. If necessary, the effective segment
3409 * will be expanded later
3411 *EffectiveSegment
= *Segment
;
3415 * Page-align the virtual size. We know for sure the virtual address
3418 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3419 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3422 * The current segment is still part of the current effective segment:
3423 * extend the effective segment to reflect this
3425 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3427 static const ULONG FlagsToProtection
[16] =
3435 PAGE_EXECUTE_READWRITE
,
3436 PAGE_EXECUTE_READWRITE
,
3441 PAGE_EXECUTE_WRITECOPY
,
3442 PAGE_EXECUTE_WRITECOPY
,
3443 PAGE_EXECUTE_WRITECOPY
,
3444 PAGE_EXECUTE_WRITECOPY
3447 unsigned ProtectionFlags
;
3450 * Extend the file size
3453 /* Unaligned segments must be contiguous within the file */
3454 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3455 EffectiveSegment
->RawLength
.QuadPart
))
3460 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3463 * Extend the virtual size
3465 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3467 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3468 EffectiveSegment
->Image
.VirtualAddress
;
3471 * Merge the protection
3473 EffectiveSegment
->Protection
|= Segment
->Protection
;
3475 /* Clean up redundance */
3476 ProtectionFlags
= 0;
3478 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3479 ProtectionFlags
|= 1 << 0;
3481 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3482 ProtectionFlags
|= 1 << 1;
3484 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3485 ProtectionFlags
|= 1 << 2;
3487 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3488 ProtectionFlags
|= 1 << 3;
3490 ASSERT(ProtectionFlags
< 16);
3491 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3493 /* If a segment was required to be shared and cannot, fail */
3494 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3495 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3501 * We assume no holes between segments at this point
3505 KeBugCheck(MEMORY_MANAGEMENT
);
3509 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3515 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3516 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3518 LARGE_INTEGER Offset
;
3520 PVOID FileHeaderBuffer
;
3521 ULONG FileHeaderSize
;
3523 ULONG OldNrSegments
;
3528 * Read the beginning of the file (2 pages). Should be enough to contain
3529 * all (or most) of the headers
3531 Offset
.QuadPart
= 0;
3533 /* FIXME: use FileObject instead of FileHandle */
3534 Status
= ExeFmtpReadFile (FileHandle
,
3541 if (!NT_SUCCESS(Status
))
3544 if (FileHeaderSize
== 0)
3546 ExFreePool(FileHeaderBuffer
);
3547 return STATUS_UNSUCCESSFUL
;
3551 * Look for a loader that can handle this executable
3553 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3555 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3558 /* FIXME: use FileObject instead of FileHandle */
3559 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3565 ExeFmtpAllocateSegments
);
3567 if (!NT_SUCCESS(Status
))
3569 if (ImageSectionObject
->Segments
)
3571 ExFreePool(ImageSectionObject
->Segments
);
3572 ImageSectionObject
->Segments
= NULL
;
3576 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3580 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3583 * No loader handled the format
3585 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3587 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3588 ASSERT(!NT_SUCCESS(Status
));
3591 if (!NT_SUCCESS(Status
))
3594 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3599 /* FIXME? are these values platform-dependent? */
3600 if(ImageSectionObject
->StackReserve
== 0)
3601 ImageSectionObject
->StackReserve
= 0x40000;
3603 if(ImageSectionObject
->StackCommit
== 0)
3604 ImageSectionObject
->StackCommit
= 0x1000;
3606 if(ImageSectionObject
->ImageBase
== 0)
3608 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3609 ImageSectionObject
->ImageBase
= 0x10000000;
3611 ImageSectionObject
->ImageBase
= 0x00400000;
3615 * And now the fun part: fixing the segments
3618 /* Sort them by virtual address */
3619 MmspSortSegments(ImageSectionObject
, Flags
);
3621 /* Ensure they don't overlap in memory */
3622 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3623 return STATUS_INVALID_IMAGE_FORMAT
;
3625 /* Ensure they are aligned */
3626 OldNrSegments
= ImageSectionObject
->NrSegments
;
3628 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3629 return STATUS_INVALID_IMAGE_FORMAT
;
3631 /* Trim them if the alignment phase merged some of them */
3632 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3634 PMM_SECTION_SEGMENT Segments
;
3635 SIZE_T SizeOfSegments
;
3637 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3639 Segments
= ExAllocatePoolWithTag(PagedPool
,
3641 TAG_MM_SECTION_SEGMENT
);
3643 if (Segments
== NULL
)
3644 return STATUS_INSUFFICIENT_RESOURCES
;
3646 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3647 ExFreePool(ImageSectionObject
->Segments
);
3648 ImageSectionObject
->Segments
= Segments
;
3651 /* And finish their initialization */
3652 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3654 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3655 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3656 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3659 ASSERT(NT_SUCCESS(Status
));
3664 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3665 ACCESS_MASK DesiredAccess
,
3666 POBJECT_ATTRIBUTES ObjectAttributes
,
3667 PLARGE_INTEGER UMaximumSize
,
3668 ULONG SectionPageProtection
,
3669 ULONG AllocationAttributes
,
3670 PFILE_OBJECT FileObject
)
3672 PROS_SECTION_OBJECT Section
;
3674 PMM_SECTION_SEGMENT SectionSegments
;
3675 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3678 if (FileObject
== NULL
)
3679 return STATUS_INVALID_FILE_FOR_SECTION
;
3682 * Create the section
3684 Status
= ObCreateObject (ExGetPreviousMode(),
3685 MmSectionObjectType
,
3687 ExGetPreviousMode(),
3689 sizeof(ROS_SECTION_OBJECT
),
3692 (PVOID
*)(PVOID
)&Section
);
3693 if (!NT_SUCCESS(Status
))
3695 ObDereferenceObject(FileObject
);
3702 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3703 Section
->Type
= 'SC';
3704 Section
->Size
= 'TN';
3705 Section
->SectionPageProtection
= SectionPageProtection
;
3706 Section
->AllocationAttributes
= AllocationAttributes
;
3710 * Initialized caching for this file object if previously caching
3711 * was initialized for the same on disk file
3713 Status
= CcTryToInitializeFileCache(FileObject
);
3715 Status
= STATUS_SUCCESS
;
3718 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3720 NTSTATUS StatusExeFmt
;
3722 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3723 if (ImageSectionObject
== NULL
)
3725 ObDereferenceObject(FileObject
);
3726 ObDereferenceObject(Section
);
3727 return(STATUS_NO_MEMORY
);
3730 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3732 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3734 if (!NT_SUCCESS(StatusExeFmt
))
3736 if(ImageSectionObject
->Segments
!= NULL
)
3737 ExFreePool(ImageSectionObject
->Segments
);
3739 ExFreePoolWithTag(ImageSectionObject
, TAG_MM_SECTION_SEGMENT
);
3740 ObDereferenceObject(Section
);
3741 ObDereferenceObject(FileObject
);
3742 return(StatusExeFmt
);
3745 Section
->ImageSection
= ImageSectionObject
;
3746 ASSERT(ImageSectionObject
->Segments
);
3751 Status
= MmspWaitForFileLock(FileObject
);
3752 if (!NT_SUCCESS(Status
))
3754 ExFreePool(ImageSectionObject
->Segments
);
3755 ExFreePool(ImageSectionObject
);
3756 ObDereferenceObject(Section
);
3757 ObDereferenceObject(FileObject
);
3761 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3762 ImageSectionObject
, NULL
))
3765 * An other thread has initialized the same image in the background
3767 ExFreePool(ImageSectionObject
->Segments
);
3768 ExFreePool(ImageSectionObject
);
3769 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3770 Section
->ImageSection
= ImageSectionObject
;
3771 SectionSegments
= ImageSectionObject
->Segments
;
3773 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3775 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3779 Status
= StatusExeFmt
;
3786 Status
= MmspWaitForFileLock(FileObject
);
3787 if (Status
!= STATUS_SUCCESS
)
3789 ObDereferenceObject(Section
);
3790 ObDereferenceObject(FileObject
);
3794 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3795 Section
->ImageSection
= ImageSectionObject
;
3796 SectionSegments
= ImageSectionObject
->Segments
;
3799 * Otherwise just reference all the section segments
3801 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3803 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3806 Status
= STATUS_SUCCESS
;
3808 Section
->FileObject
= FileObject
;
3810 CcRosReferenceCache(FileObject
);
3812 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3813 *SectionObject
= Section
;
3820 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3821 PROS_SECTION_OBJECT Section
,
3822 PMM_SECTION_SEGMENT Segment
,
3827 ULONG AllocationType
)
3831 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3833 if (Segment
->WriteCopy
)
3835 /* We have to do this because the not present fault
3836 * and access fault handlers depend on the protection
3837 * that should be granted AFTER the COW fault takes
3838 * place to be in Region->Protect. The not present fault
3839 * handler changes this to the correct protection for COW when
3840 * mapping the pages into the process's address space. If a COW
3841 * fault takes place, the access fault handler sets the page protection
3842 * to these values for the newly copied pages
3844 if (Protect
== PAGE_WRITECOPY
)
3845 Protect
= PAGE_READWRITE
;
3846 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3847 Protect
= PAGE_EXECUTE_READWRITE
;
3850 BoundaryAddressMultiple
.QuadPart
= 0;
3853 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
3854 LARGE_INTEGER FileOffset
;
3855 FileOffset
.QuadPart
= ViewOffset
;
3856 ObReferenceObject(Section
);
3857 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3860 Status
= MmCreateMemoryArea(AddressSpace
,
3861 MEMORY_AREA_SECTION_VIEW
,
3868 BoundaryAddressMultiple
);
3869 if (!NT_SUCCESS(Status
))
3871 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3872 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3876 ObReferenceObject((PVOID
)Section
);
3878 MArea
->Data
.SectionData
.Segment
= Segment
;
3879 MArea
->Data
.SectionData
.Section
= Section
;
3880 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3881 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3882 ViewSize
, 0, Protect
);
3884 return(STATUS_SUCCESS
);
3889 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3890 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3893 PFILE_OBJECT FileObject
;
3895 LARGE_INTEGER Offset
;
3896 SWAPENTRY SavedSwapEntry
;
3897 PROS_SECTION_OBJECT Section
;
3898 PMM_SECTION_SEGMENT Segment
;
3899 PMMSUPPORT AddressSpace
;
3902 AddressSpace
= (PMMSUPPORT
)Context
;
3903 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3905 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3907 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3908 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3910 Section
= MemoryArea
->Data
.SectionData
.Section
;
3911 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3913 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3914 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
3916 MmUnlockSectionSegment(Segment
);
3917 MmUnlockAddressSpace(AddressSpace
);
3919 MiWaitForPageEvent(NULL
, NULL
);
3921 MmLockAddressSpace(AddressSpace
);
3922 MmLockSectionSegment(Segment
);
3923 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3927 * For a dirty, datafile, non-private page mark it as dirty in the
3930 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3932 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3934 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3935 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3937 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)(Offset
.QuadPart
+ Segment
->Image
.FileOffset
));
3939 ASSERT(SwapEntry
== 0);
3948 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3950 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3951 KeBugCheck(MEMORY_MANAGEMENT
);
3953 MmFreeSwapPage(SwapEntry
);
3957 if (IS_SWAP_FROM_SSE(Entry
) ||
3958 Page
!= PFN_FROM_SSE(Entry
))
3963 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3965 DPRINT1("Found a private page in a pagefile section.\n");
3966 KeBugCheck(MEMORY_MANAGEMENT
);
3969 * Just dereference private pages
3971 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3972 if (SavedSwapEntry
!= 0)
3974 MmFreeSwapPage(SavedSwapEntry
);
3975 MmSetSavedSwapEntryPage(Page
, 0);
3977 MmDeleteRmap(Page
, Process
, Address
);
3978 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3982 MmDeleteRmap(Page
, Process
, Address
);
3983 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
3989 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
3993 PMEMORY_AREA MemoryArea
;
3994 PROS_SECTION_OBJECT Section
;
3995 PMM_SECTION_SEGMENT Segment
;
3996 PLIST_ENTRY CurrentEntry
;
3997 PMM_REGION CurrentRegion
;
3998 PLIST_ENTRY RegionListHead
;
4000 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4002 if (MemoryArea
== NULL
)
4004 return(STATUS_UNSUCCESSFUL
);
4007 MemoryArea
->DeleteInProgress
= TRUE
;
4008 Section
= MemoryArea
->Data
.SectionData
.Section
;
4009 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4012 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4013 return MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4016 MmLockSectionSegment(Segment
);
4018 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4019 while (!IsListEmpty(RegionListHead
))
4021 CurrentEntry
= RemoveHeadList(RegionListHead
);
4022 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4023 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4026 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4028 Status
= MmFreeMemoryArea(AddressSpace
,
4035 Status
= MmFreeMemoryArea(AddressSpace
,
4040 MmUnlockSectionSegment(Segment
);
4041 ObDereferenceObject(Section
);
4047 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4048 IN PVOID BaseAddress
,
4052 PMEMORY_AREA MemoryArea
;
4053 PMMSUPPORT AddressSpace
;
4054 PROS_SECTION_OBJECT Section
;
4055 PVOID ImageBaseAddress
= 0;
4057 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4058 Process
, BaseAddress
);
4062 AddressSpace
= Process
? &Process
->Vm
: MmGetKernelAddressSpace();
4064 MmLockAddressSpace(AddressSpace
);
4065 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4067 if (MemoryArea
== NULL
||
4068 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4069 MemoryArea
->DeleteInProgress
)
4071 ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4072 MmUnlockAddressSpace(AddressSpace
);
4073 return STATUS_NOT_MAPPED_VIEW
;
4076 MemoryArea
->DeleteInProgress
= TRUE
;
4078 Section
= MemoryArea
->Data
.SectionData
.Section
;
4080 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4084 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4085 PMM_SECTION_SEGMENT SectionSegments
;
4086 PMM_SECTION_SEGMENT Segment
;
4088 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4089 ImageSectionObject
= Section
->ImageSection
;
4090 SectionSegments
= ImageSectionObject
->Segments
;
4091 NrSegments
= ImageSectionObject
->NrSegments
;
4093 /* Search for the current segment within the section segments
4094 * and calculate the image base address */
4095 for (i
= 0; i
< NrSegments
; i
++)
4097 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4099 if (Segment
== &SectionSegments
[i
])
4101 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4106 if (i
>= NrSegments
)
4108 KeBugCheck(MEMORY_MANAGEMENT
);
4111 for (i
= 0; i
< NrSegments
; i
++)
4113 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4115 PVOID SBaseAddress
= (PVOID
)
4116 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4118 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4124 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4127 MmUnlockAddressSpace(AddressSpace
);
4129 /* Notify debugger */
4130 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4132 return(STATUS_SUCCESS
);
4139 * Queries the information of a section object.
4141 * @param SectionHandle
4142 * Handle to the section object. It must be opened with SECTION_QUERY
4144 * @param SectionInformationClass
4145 * Index to a certain information structure. Can be either
4146 * SectionBasicInformation or SectionImageInformation. The latter
4147 * is valid only for sections that were created with the SEC_IMAGE
4149 * @param SectionInformation
4150 * Caller supplies storage for resulting information.
4152 * Size of the supplied storage.
4153 * @param ResultLength
4161 NtQuerySection(IN HANDLE SectionHandle
,
4162 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4163 OUT PVOID SectionInformation
,
4164 IN SIZE_T SectionInformationLength
,
4165 OUT PSIZE_T ResultLength OPTIONAL
)
4167 PROS_SECTION_OBJECT Section
;
4168 KPROCESSOR_MODE PreviousMode
;
4172 PreviousMode
= ExGetPreviousMode();
4174 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4176 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4178 (ULONG
)SectionInformationLength
,
4183 if(!NT_SUCCESS(Status
))
4185 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4189 Status
= ObReferenceObjectByHandle(SectionHandle
,
4191 MmSectionObjectType
,
4193 (PVOID
*)(PVOID
)&Section
,
4195 if (NT_SUCCESS(Status
))
4197 switch (SectionInformationClass
)
4199 case SectionBasicInformation
:
4201 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4205 Sbi
->Attributes
= Section
->AllocationAttributes
;
4206 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4208 Sbi
->BaseAddress
= 0;
4209 Sbi
->Size
.QuadPart
= 0;
4213 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4214 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4217 if (ResultLength
!= NULL
)
4219 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4221 Status
= STATUS_SUCCESS
;
4223 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4225 Status
= _SEH2_GetExceptionCode();
4232 case SectionImageInformation
:
4234 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4238 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4239 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4241 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4242 ImageSectionObject
= Section
->ImageSection
;
4244 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4245 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4246 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4247 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4248 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4249 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4250 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4251 Sii
->Machine
= ImageSectionObject
->Machine
;
4252 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4255 if (ResultLength
!= NULL
)
4257 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4259 Status
= STATUS_SUCCESS
;
4261 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4263 Status
= _SEH2_GetExceptionCode();
4271 ObDereferenceObject(Section
);
4277 /**********************************************************************
4279 * MmMapViewOfSection
4282 * Maps a view of a section into the virtual address space of a
4287 * Pointer to the section object.
4290 * Pointer to the process.
4293 * Desired base address (or NULL) on entry;
4294 * Actual base address of the view on exit.
4297 * Number of high order address bits that must be zero.
4300 * Size in bytes of the initially committed section of
4304 * Offset in bytes from the beginning of the section
4305 * to the beginning of the view.
4308 * Desired length of map (or zero to map all) on entry
4309 * Actual length mapped on exit.
4311 * InheritDisposition
4312 * Specified how the view is to be shared with
4316 * Type of allocation for the pages.
4319 * Protection for the committed region of the view.
4327 MmMapViewOfSection(IN PVOID SectionObject
,
4328 IN PEPROCESS Process
,
4329 IN OUT PVOID
*BaseAddress
,
4330 IN ULONG_PTR ZeroBits
,
4331 IN SIZE_T CommitSize
,
4332 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4333 IN OUT PSIZE_T ViewSize
,
4334 IN SECTION_INHERIT InheritDisposition
,
4335 IN ULONG AllocationType
,
4338 PROS_SECTION_OBJECT Section
;
4339 PMMSUPPORT AddressSpace
;
4341 NTSTATUS Status
= STATUS_SUCCESS
;
4342 BOOLEAN NotAtBase
= FALSE
;
4344 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4346 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4347 return MmMapViewOfArm3Section(SectionObject
,
4361 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4363 return STATUS_INVALID_PAGE_PROTECTION
;
4367 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4368 AddressSpace
= &Process
->Vm
;
4370 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4372 MmLockAddressSpace(AddressSpace
);
4374 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4378 ULONG_PTR ImageBase
;
4380 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4381 PMM_SECTION_SEGMENT SectionSegments
;
4383 ImageSectionObject
= Section
->ImageSection
;
4384 SectionSegments
= ImageSectionObject
->Segments
;
4385 NrSegments
= ImageSectionObject
->NrSegments
;
4388 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4391 ImageBase
= ImageSectionObject
->ImageBase
;
4395 for (i
= 0; i
< NrSegments
; i
++)
4397 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4399 ULONG_PTR MaxExtent
;
4400 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4401 SectionSegments
[i
].Length
.QuadPart
);
4402 ImageSize
= max(ImageSize
, MaxExtent
);
4406 ImageSectionObject
->ImageSize
= (ULONG
)ImageSize
;
4408 /* Check for an illegal base address */
4409 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4411 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4414 /* Check there is enough space to map the section at that point. */
4415 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4416 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4418 /* Fail if the user requested a fixed base address. */
4419 if ((*BaseAddress
) != NULL
)
4421 MmUnlockAddressSpace(AddressSpace
);
4422 return(STATUS_UNSUCCESSFUL
);
4424 /* Otherwise find a gap to map the image. */
4425 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4428 MmUnlockAddressSpace(AddressSpace
);
4429 return(STATUS_UNSUCCESSFUL
);
4431 /* Remember that we loaded image at a different base address */
4435 for (i
= 0; i
< NrSegments
; i
++)
4437 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4439 PVOID SBaseAddress
= (PVOID
)
4440 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4441 MmLockSectionSegment(&SectionSegments
[i
]);
4442 Status
= MmMapViewOfSegment(AddressSpace
,
4444 &SectionSegments
[i
],
4446 SectionSegments
[i
].Length
.LowPart
,
4447 SectionSegments
[i
].Protection
,
4450 MmUnlockSectionSegment(&SectionSegments
[i
]);
4451 if (!NT_SUCCESS(Status
))
4453 MmUnlockAddressSpace(AddressSpace
);
4459 *BaseAddress
= (PVOID
)ImageBase
;
4460 *ViewSize
= ImageSize
;
4464 /* check for write access */
4465 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4466 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4468 MmUnlockAddressSpace(AddressSpace
);
4469 return STATUS_SECTION_PROTECTION
;
4471 /* check for read access */
4472 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4473 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4475 MmUnlockAddressSpace(AddressSpace
);
4476 return STATUS_SECTION_PROTECTION
;
4478 /* check for execute access */
4479 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4480 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4482 MmUnlockAddressSpace(AddressSpace
);
4483 return STATUS_SECTION_PROTECTION
;
4486 if (ViewSize
== NULL
)
4488 /* Following this pointer would lead to us to the dark side */
4489 /* What to do? Bugcheck? Return status? Do the mambo? */
4490 KeBugCheck(MEMORY_MANAGEMENT
);
4493 if (SectionOffset
== NULL
)
4499 ViewOffset
= SectionOffset
->u
.LowPart
;
4502 if ((ViewOffset
% PAGE_SIZE
) != 0)
4504 MmUnlockAddressSpace(AddressSpace
);
4505 return(STATUS_MAPPED_ALIGNMENT
);
4508 if ((*ViewSize
) == 0)
4510 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4512 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4514 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4517 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4519 MmLockSectionSegment(Section
->Segment
);
4520 Status
= MmMapViewOfSegment(AddressSpace
,
4527 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4528 MmUnlockSectionSegment(Section
->Segment
);
4529 if (!NT_SUCCESS(Status
))
4531 MmUnlockAddressSpace(AddressSpace
);
4536 MmUnlockAddressSpace(AddressSpace
);
4539 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4541 Status
= STATUS_SUCCESS
;
4550 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4551 IN PLARGE_INTEGER NewFileSize
)
4553 /* Check whether an ImageSectionObject exists */
4554 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4556 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4560 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4562 PMM_SECTION_SEGMENT Segment
;
4564 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4567 if (Segment
->ReferenceCount
!= 0)
4570 CC_FILE_SIZES FileSizes
;
4572 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4575 /* Check size of file */
4576 if (SectionObjectPointer
->SharedCacheMap
)
4578 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4583 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4592 /* Check size of file */
4593 if (SectionObjectPointer
->SharedCacheMap
)
4595 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4596 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4605 /* Something must gone wrong
4606 * how can we have a Section but no
4608 DPRINT("ERROR: DataSectionObject without reference!\n");
4612 DPRINT("FIXME: didn't check for outstanding write probes\n");
4624 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4625 IN MMFLUSH_TYPE FlushType
)
4627 BOOLEAN Result
= TRUE
;
4629 PMM_SECTION_SEGMENT Segment
;
4634 case MmFlushForDelete
:
4635 if (SectionObjectPointer
->ImageSectionObject
||
4636 SectionObjectPointer
->DataSectionObject
)
4641 CcRosSetRemoveOnClose(SectionObjectPointer
);
4644 case MmFlushForWrite
:
4646 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4648 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4651 if (SectionObjectPointer
->ImageSectionObject
) {
4652 DPRINT1("SectionObject has ImageSection\n");
4658 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4660 DPRINT("Result %d\n", Result
);
4672 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4673 OUT PVOID
* MappedBase
,
4674 IN OUT PSIZE_T ViewSize
)
4676 PROS_SECTION_OBJECT Section
;
4677 PMMSUPPORT AddressSpace
;
4681 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4683 return MiMapViewInSystemSpace(SectionObject
,
4689 DPRINT("MmMapViewInSystemSpace() called\n");
4691 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4692 AddressSpace
= MmGetKernelAddressSpace();
4694 MmLockAddressSpace(AddressSpace
);
4697 if ((*ViewSize
) == 0)
4699 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4701 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4703 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4706 MmLockSectionSegment(Section
->Segment
);
4709 Status
= MmMapViewOfSegment(AddressSpace
,
4718 MmUnlockSectionSegment(Section
->Segment
);
4719 MmUnlockAddressSpace(AddressSpace
);
4726 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4728 PMMSUPPORT AddressSpace
;
4731 DPRINT("MmUnmapViewInSystemSpace() called\n");
4733 AddressSpace
= MmGetKernelAddressSpace();
4735 MmLockAddressSpace(AddressSpace
);
4737 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4739 MmUnlockAddressSpace(AddressSpace
);
4744 /**********************************************************************
4749 * Creates a section object.
4752 * SectionObject (OUT)
4753 * Caller supplied storage for the resulting pointer
4754 * to a SECTION_OBJECT instance;
4757 * Specifies the desired access to the section can be a
4759 * STANDARD_RIGHTS_REQUIRED |
4761 * SECTION_MAP_WRITE |
4762 * SECTION_MAP_READ |
4763 * SECTION_MAP_EXECUTE
4765 * ObjectAttributes [OPTIONAL]
4766 * Initialized attributes for the object can be used
4767 * to create a named section;
4770 * Maximizes the size of the memory section. Must be
4771 * non-NULL for a page-file backed section.
4772 * If value specified for a mapped file and the file is
4773 * not large enough, file will be extended.
4775 * SectionPageProtection
4776 * Can be a combination of:
4782 * AllocationAttributes
4783 * Can be a combination of:
4788 * Handle to a file to create a section mapped to a file
4789 * instead of a memory backed section;
4800 MmCreateSection (OUT PVOID
* Section
,
4801 IN ACCESS_MASK DesiredAccess
,
4802 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4803 IN PLARGE_INTEGER MaximumSize
,
4804 IN ULONG SectionPageProtection
,
4805 IN ULONG AllocationAttributes
,
4806 IN HANDLE FileHandle OPTIONAL
,
4807 IN PFILE_OBJECT FileObject OPTIONAL
)
4810 ULONG Protection
, FileAccess
;
4811 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4813 /* Check if an ARM3 section is being created instead */
4814 if (!(AllocationAttributes
& (SEC_IMAGE
| SEC_PHYSICALMEMORY
)))
4816 if (!(FileObject
) && !(FileHandle
))
4818 return MmCreateArm3Section(Section
,
4822 SectionPageProtection
,
4823 AllocationAttributes
&~ 1,
4830 * Check the protection
4832 Protection
= SectionPageProtection
& ~(PAGE_GUARD
| PAGE_NOCACHE
);
4833 if (Protection
!= PAGE_READONLY
&&
4834 Protection
!= PAGE_READWRITE
&&
4835 Protection
!= PAGE_WRITECOPY
&&
4836 Protection
!= PAGE_EXECUTE
&&
4837 Protection
!= PAGE_EXECUTE_READ
&&
4838 Protection
!= PAGE_EXECUTE_READWRITE
&&
4839 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4841 return STATUS_INVALID_PAGE_PROTECTION
;
4844 if ((DesiredAccess
& SECTION_MAP_WRITE
) &&
4845 (Protection
== PAGE_READWRITE
||
4846 Protection
== PAGE_EXECUTE_READWRITE
) &&
4847 !(AllocationAttributes
& SEC_IMAGE
))
4849 DPRINT("Creating a section with WRITE access\n");
4850 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
| SYNCHRONIZE
;
4854 DPRINT("Creating a section with READ access\n");
4855 FileAccess
= FILE_READ_DATA
| SYNCHRONIZE
;
4858 /* FIXME: somehow combine this with the above checks */
4859 if (AllocationAttributes
& SEC_IMAGE
)
4860 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
4862 if (!FileObject
&& FileHandle
)
4864 Status
= ObReferenceObjectByHandle(FileHandle
,
4867 ExGetPreviousMode(),
4868 (PVOID
*)&FileObject
,
4870 if (!NT_SUCCESS(Status
))
4872 DPRINT("Failed: 0x%08lx\n", Status
);
4876 else if (FileObject
)
4877 ObReferenceObject(FileObject
);
4879 #ifndef NEWCC // A hack for initializing caching.
4880 // This is needed only in the old case.
4883 IO_STATUS_BLOCK Iosb
;
4886 LARGE_INTEGER ByteOffset
;
4887 ByteOffset
.QuadPart
= 0;
4888 Status
= ZwReadFile(FileHandle
,
4897 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
4899 // Caching is initialized...
4903 if (AllocationAttributes
& SEC_IMAGE
)
4905 Status
= MmCreateImageSection(SectionObject
,
4909 SectionPageProtection
,
4910 AllocationAttributes
,
4914 else if (FileHandle
!= NULL
)
4916 Status
= MmCreateDataFileSection(SectionObject
,
4920 SectionPageProtection
,
4921 AllocationAttributes
,
4924 ObDereferenceObject(FileObject
);
4927 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
4929 Status
= MmCreateCacheSection(SectionObject
,
4933 SectionPageProtection
,
4934 AllocationAttributes
,
4940 if ((AllocationAttributes
& SEC_PHYSICALMEMORY
) == 0)
4942 DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes
, FileObject
, FileHandle
);
4944 // ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
4945 Status
= MmCreatePageFileSection(SectionObject
,
4949 SectionPageProtection
,
4950 AllocationAttributes
);