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 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
681 DIE(("Cannot align the virtual size of section %u\n", i
));
683 if(pssSegments
[i
].Length
.QuadPart
== 0)
684 DIE(("Virtual size of section %u is null\n", i
));
686 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
687 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
689 /* ensure the memory image is no larger than 4GB */
690 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
691 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
692 DIE(("The image is too large\n"));
695 if(nSectionAlignment
>= PAGE_SIZE
)
696 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
699 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;
709 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
710 * ARGUMENTS: PFILE_OBJECT to wait for.
711 * RETURNS: Status of the wait.
714 MmspWaitForFileLock(PFILE_OBJECT File
)
716 return STATUS_SUCCESS
;
717 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
722 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
724 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
726 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
727 PMM_SECTION_SEGMENT SectionSegments
;
731 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
732 NrSegments
= ImageSectionObject
->NrSegments
;
733 SectionSegments
= ImageSectionObject
->Segments
;
734 for (i
= 0; i
< NrSegments
; i
++)
736 if (SectionSegments
[i
].ReferenceCount
!= 0)
738 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
739 SectionSegments
[i
].ReferenceCount
);
740 KeBugCheck(MEMORY_MANAGEMENT
);
742 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
744 ExFreePool(ImageSectionObject
->Segments
);
745 ExFreePool(ImageSectionObject
);
746 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
748 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
750 PMM_SECTION_SEGMENT Segment
;
752 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
755 if (Segment
->ReferenceCount
!= 0)
757 DPRINT1("Data segment still referenced\n");
758 KeBugCheck(MEMORY_MANAGEMENT
);
760 MmFreePageTablesSectionSegment(Segment
, NULL
);
762 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
768 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
769 PLARGE_INTEGER Offset
)
773 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
776 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
777 KeBugCheck(MEMORY_MANAGEMENT
);
779 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
781 DPRINT1("Maximum share count reached\n");
782 KeBugCheck(MEMORY_MANAGEMENT
);
784 if (IS_SWAP_FROM_SSE(Entry
))
786 KeBugCheck(MEMORY_MANAGEMENT
);
788 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
789 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
794 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
795 PMM_SECTION_SEGMENT Segment
,
796 PLARGE_INTEGER Offset
,
801 ULONG_PTR Entry
= InEntry
? *InEntry
: MmGetPageEntrySectionSegment(Segment
, Offset
);
802 BOOLEAN IsDirectMapped
= FALSE
;
806 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
807 KeBugCheck(MEMORY_MANAGEMENT
);
809 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
811 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment
, Offset
->LowPart
, PFN_FROM_SSE(Entry
));
812 KeBugCheck(MEMORY_MANAGEMENT
);
814 if (IS_SWAP_FROM_SSE(Entry
))
816 KeBugCheck(MEMORY_MANAGEMENT
);
818 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
820 * If we reducing the share count of this entry to zero then set the entry
821 * to zero and tell the cache the page is no longer mapped.
823 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
825 PFILE_OBJECT FileObject
;
829 SWAPENTRY SavedSwapEntry
;
831 BOOLEAN IsImageSection
;
832 LARGE_INTEGER FileOffset
;
834 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
836 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
838 Page
= PFN_FROM_SSE(Entry
);
839 FileObject
= Section
->FileObject
;
840 if (FileObject
!= NULL
&&
841 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
845 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
846 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
849 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
850 IsDirectMapped
= TRUE
;
852 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
.LowPart
, Dirty
);
854 Status
= STATUS_SUCCESS
;
856 if (!NT_SUCCESS(Status
))
858 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
859 KeBugCheck(MEMORY_MANAGEMENT
);
865 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
866 if (SavedSwapEntry
== 0)
869 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
870 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
874 * Try to page out this page and set the swap entry
875 * within the section segment. There exist no rmap entry
876 * for this page. The pager thread can't page out a
877 * page without a rmap entry.
879 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
880 if (InEntry
) *InEntry
= Entry
;
881 MiSetPageEvent(NULL
, NULL
);
885 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
886 if (InEntry
) *InEntry
= 0;
887 MiSetPageEvent(NULL
, NULL
);
890 MmReleasePageMemoryConsumer(MC_USER
, Page
);
896 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
897 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
905 * We hold all locks. Nobody can do something with the current
906 * process and the current segment (also not within an other process).
909 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
910 if (!NT_SUCCESS(Status
))
912 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
913 KeBugCheck(MEMORY_MANAGEMENT
);
916 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
917 if (InEntry
) *InEntry
= MAKE_SWAP_SSE(SavedSwapEntry
);
918 MmSetSavedSwapEntryPage(Page
, 0);
919 MiSetPageEvent(NULL
, NULL
);
921 MmReleasePageMemoryConsumer(MC_USER
, Page
);
925 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
926 KeBugCheck(MEMORY_MANAGEMENT
);
935 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
937 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
940 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
944 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
947 PCACHE_SEGMENT CacheSeg
;
948 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
949 CacheSeg
= CcRosLookupCacheSegment(Bcb
, (ULONG
)(SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
));
952 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
962 MiCopyFromUserPage(PFN_NUMBER DestPage
, PFN_NUMBER SrcPage
)
966 PVOID DestAddress
, SrcAddress
;
968 Process
= PsGetCurrentProcess();
969 DestAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
970 SrcAddress
= MiMapPageInHyperSpace(Process
, SrcPage
, &Irql2
);
971 if (DestAddress
== NULL
|| SrcAddress
== NULL
)
973 return(STATUS_NO_MEMORY
);
975 ASSERT((ULONG_PTR
)DestAddress
% PAGE_SIZE
== 0);
976 ASSERT((ULONG_PTR
)SrcAddress
% PAGE_SIZE
== 0);
977 RtlCopyMemory(DestAddress
, SrcAddress
, PAGE_SIZE
);
978 MiUnmapPageInHyperSpace(Process
, SrcAddress
, Irql2
);
979 MiUnmapPageInHyperSpace(Process
, DestAddress
, Irql
);
980 return(STATUS_SUCCESS
);
986 MiReadPage(PMEMORY_AREA MemoryArea
,
990 * FUNCTION: Read a page for a section backed memory area.
992 * MemoryArea - Memory area to read the page for.
993 * Offset - Offset of the page to read.
994 * Page - Variable that receives a page contains the read data.
998 ULONGLONG FileOffset
;
1001 PCACHE_SEGMENT CacheSeg
;
1002 PFILE_OBJECT FileObject
;
1004 ULONG_PTR RawLength
;
1006 BOOLEAN IsImageSection
;
1009 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1010 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1011 RawLength
= (ULONG_PTR
)(MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
);
1012 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1013 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1017 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1020 * If the file system is letting us go directly to the cache and the
1021 * memory area was mapped at an offset in the file which is page aligned
1022 * then get the related cache segment.
1024 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1025 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1026 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1030 * Get the related cache segment; we use a lower level interface than
1031 * filesystems do because it is safe for us to use an offset with a
1032 * alignment less than the file system block size.
1034 Status
= CcRosGetCacheSegment(Bcb
,
1040 if (!NT_SUCCESS(Status
))
1047 * If the cache segment isn't up to date then call the file
1048 * system to read in the data.
1050 Status
= ReadCacheSegment(CacheSeg
);
1051 if (!NT_SUCCESS(Status
))
1053 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1058 * Retrieve the page from the cache segment that we actually want.
1060 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1061 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1063 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1070 ULONG_PTR CacheSegOffset
;
1073 * Allocate a page, this is rather complicated by the possibility
1074 * we might have to move other things out of memory
1076 MI_SET_USAGE(MI_USAGE_SECTION
);
1077 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1078 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1079 if (!NT_SUCCESS(Status
))
1083 Status
= CcRosGetCacheSegment(Bcb
,
1089 if (!NT_SUCCESS(Status
))
1096 * If the cache segment isn't up to date then call the file
1097 * system to read in the data.
1099 Status
= ReadCacheSegment(CacheSeg
);
1100 if (!NT_SUCCESS(Status
))
1102 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1107 Process
= PsGetCurrentProcess();
1108 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1109 CacheSegOffset
= (ULONG_PTR
)(BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
);
1110 Length
= RawLength
- SegOffset
;
1111 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1113 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1115 else if (CacheSegOffset
>= PAGE_SIZE
)
1117 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1121 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1122 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1123 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1124 Status
= CcRosGetCacheSegment(Bcb
,
1125 (ULONG
)(FileOffset
+ CacheSegOffset
),
1130 if (!NT_SUCCESS(Status
))
1137 * If the cache segment isn't up to date then call the file
1138 * system to read in the data.
1140 Status
= ReadCacheSegment(CacheSeg
);
1141 if (!NT_SUCCESS(Status
))
1143 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1147 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1148 if (Length
< PAGE_SIZE
)
1150 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1154 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1157 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1158 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1160 return(STATUS_SUCCESS
);
1165 MiReadPage(PMEMORY_AREA MemoryArea
,
1166 ULONG_PTR SegOffset
,
1169 * FUNCTION: Read a page for a section backed memory area.
1171 * MemoryArea - Memory area to read the page for.
1172 * Offset - Offset of the page to read.
1173 * Page - Variable that receives a page contains the read data.
1176 MM_REQUIRED_RESOURCES Resources
;
1179 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1181 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1182 Resources
.FileOffset
.QuadPart
= SegOffset
+
1183 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1184 Resources
.Consumer
= MC_USER
;
1185 Resources
.Amount
= PAGE_SIZE
;
1187 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]);
1189 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1190 *Page
= Resources
.Page
[0];
1197 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1198 MEMORY_AREA
* MemoryArea
,
1202 LARGE_INTEGER Offset
;
1205 PROS_SECTION_OBJECT Section
;
1206 PMM_SECTION_SEGMENT Segment
;
1211 BOOLEAN HasSwapEntry
;
1213 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1214 SWAPENTRY SwapEntry
;
1217 * There is a window between taking the page fault and locking the
1218 * address space when another thread could load the page so we check
1221 if (MmIsPagePresent(Process
, Address
))
1223 return(STATUS_SUCCESS
);
1226 if (MmIsDisabledPage(Process
, Address
))
1228 return(STATUS_ACCESS_VIOLATION
);
1232 * Check for the virtual memory area being deleted.
1234 if (MemoryArea
->DeleteInProgress
)
1236 return(STATUS_UNSUCCESSFUL
);
1239 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1240 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1241 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1243 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1244 Section
= MemoryArea
->Data
.SectionData
.Section
;
1245 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1246 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1248 ASSERT(Region
!= NULL
);
1252 MmLockSectionSegment(Segment
);
1253 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1255 * Check if this page needs to be mapped COW
1257 if ((Segment
->WriteCopy
) &&
1258 (Region
->Protect
== PAGE_READWRITE
||
1259 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1261 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1265 Attributes
= Region
->Protect
;
1269 * Check if someone else is already handling this fault, if so wait
1272 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1274 MmUnlockSectionSegment(Segment
);
1275 MmUnlockAddressSpace(AddressSpace
);
1276 MiWaitForPageEvent(NULL
, NULL
);
1277 MmLockAddressSpace(AddressSpace
);
1278 DPRINT("Address 0x%.8X\n", Address
);
1279 return(STATUS_MM_RESTART_OPERATION
);
1282 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1287 * Is it a wait entry?
1289 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1291 if (SwapEntry
== MM_WAIT_ENTRY
)
1293 MmUnlockSectionSegment(Segment
);
1294 MmUnlockAddressSpace(AddressSpace
);
1295 MiWaitForPageEvent(NULL
, NULL
);
1296 MmLockAddressSpace(AddressSpace
);
1297 return STATUS_MM_RESTART_OPERATION
;
1301 * Must be private page we have swapped out.
1307 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1309 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1310 KeBugCheck(MEMORY_MANAGEMENT
);
1313 MmUnlockSectionSegment(Segment
);
1314 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1315 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1317 MmUnlockAddressSpace(AddressSpace
);
1318 MI_SET_USAGE(MI_USAGE_SECTION
);
1319 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1320 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1321 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1322 if (!NT_SUCCESS(Status
))
1324 KeBugCheck(MEMORY_MANAGEMENT
);
1327 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1328 if (!NT_SUCCESS(Status
))
1330 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1331 KeBugCheck(MEMORY_MANAGEMENT
);
1333 MmLockAddressSpace(AddressSpace
);
1334 Status
= MmCreateVirtualMapping(Process
,
1339 if (!NT_SUCCESS(Status
))
1341 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1342 KeBugCheck(MEMORY_MANAGEMENT
);
1347 * Store the swap entry for later use.
1349 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1352 * Add the page to the process's working set
1354 MmInsertRmap(Page
, Process
, Address
);
1356 * Finish the operation
1358 MiSetPageEvent(Process
, Address
);
1359 DPRINT("Address 0x%.8X\n", Address
);
1360 return(STATUS_SUCCESS
);
1364 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1366 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1368 MmUnlockSectionSegment(Segment
);
1370 * Just map the desired physical page
1372 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1373 Status
= MmCreateVirtualMappingUnsafe(Process
,
1378 if (!NT_SUCCESS(Status
))
1380 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1381 KeBugCheck(MEMORY_MANAGEMENT
);
1386 * Cleanup and release locks
1388 MiSetPageEvent(Process
, Address
);
1389 DPRINT("Address 0x%.8X\n", Address
);
1390 return(STATUS_SUCCESS
);
1394 * Map anonymous memory for BSS sections
1396 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1398 /* We'll be unlocking the address space below. Prevent us from being preempted
1399 * in faulting in the page. */
1400 MmCreatePageFileMapping(Process
, Address
, MM_WAIT_ENTRY
);
1401 MmUnlockSectionSegment(Segment
);
1402 MI_SET_USAGE(MI_USAGE_SECTION
);
1403 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1404 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1405 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1406 if (!NT_SUCCESS(Status
))
1408 MmUnlockAddressSpace(AddressSpace
);
1409 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1410 MmLockAddressSpace(AddressSpace
);
1412 if (!NT_SUCCESS(Status
))
1414 KeBugCheck(MEMORY_MANAGEMENT
);
1416 /* Remove the wait entry we placed, so that we can map the page */
1417 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1418 Status
= MmCreateVirtualMapping(Process
,
1423 if (!NT_SUCCESS(Status
))
1425 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1426 KeBugCheck(MEMORY_MANAGEMENT
);
1429 MmInsertRmap(Page
, Process
, Address
);
1432 * Cleanup and release locks
1434 MiSetPageEvent(Process
, Address
);
1435 DPRINT("Address 0x%.8X\n", Address
);
1436 return(STATUS_SUCCESS
);
1440 * Get the entry corresponding to the offset within the section
1442 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1446 SWAPENTRY FakeSwapEntry
;
1449 * If the entry is zero (and it can't change because we have
1450 * locked the segment) then we need to load the page.
1454 * Release all our locks and read in the page from disk
1456 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1457 MmUnlockSectionSegment(Segment
);
1458 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1459 MmUnlockAddressSpace(AddressSpace
);
1461 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1462 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1463 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1465 MI_SET_USAGE(MI_USAGE_SECTION
);
1466 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1467 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1468 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1469 if (!NT_SUCCESS(Status
))
1471 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1477 Status
= MiReadPage(MemoryArea
, (ULONG_PTR
)Offset
.QuadPart
, &Page
);
1478 if (!NT_SUCCESS(Status
))
1480 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1483 if (!NT_SUCCESS(Status
))
1486 * FIXME: What do we know in this case?
1489 * Cleanup and release locks
1491 MmLockAddressSpace(AddressSpace
);
1492 MiSetPageEvent(Process
, Address
);
1493 DPRINT("Address 0x%.8X\n", Address
);
1498 * Mark the offset within the section as having valid, in-memory
1501 MmLockAddressSpace(AddressSpace
);
1502 MmLockSectionSegment(Segment
);
1503 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1504 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1505 MmUnlockSectionSegment(Segment
);
1507 MmDeletePageFileMapping(Process
, PAddress
, &FakeSwapEntry
);
1508 DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
1509 Page
, Process
, PAddress
, Attributes
);
1510 Status
= MmCreateVirtualMapping(Process
,
1515 if (!NT_SUCCESS(Status
))
1517 DPRINT1("Unable to create virtual mapping\n");
1518 KeBugCheck(MEMORY_MANAGEMENT
);
1520 ASSERT(MmIsPagePresent(Process
, PAddress
));
1521 MmInsertRmap(Page
, Process
, Address
);
1523 MiSetPageEvent(Process
, Address
);
1524 DPRINT("Address 0x%.8X\n", Address
);
1525 return(STATUS_SUCCESS
);
1527 else if (IS_SWAP_FROM_SSE(Entry
))
1529 SWAPENTRY SwapEntry
;
1531 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1534 * Release all our locks and read in the page from disk
1536 MmUnlockSectionSegment(Segment
);
1538 MmUnlockAddressSpace(AddressSpace
);
1539 MI_SET_USAGE(MI_USAGE_SECTION
);
1540 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1541 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1542 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1543 if (!NT_SUCCESS(Status
))
1545 KeBugCheck(MEMORY_MANAGEMENT
);
1548 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1549 if (!NT_SUCCESS(Status
))
1551 KeBugCheck(MEMORY_MANAGEMENT
);
1555 * Relock the address space and segment
1557 MmLockAddressSpace(AddressSpace
);
1558 MmLockSectionSegment(Segment
);
1561 * Check the entry. No one should change the status of a page
1562 * that has a pending page-in.
1564 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1565 if (Entry
!= Entry1
)
1567 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1568 KeBugCheck(MEMORY_MANAGEMENT
);
1572 * Mark the offset within the section as having valid, in-memory
1575 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1576 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1577 MmUnlockSectionSegment(Segment
);
1580 * Save the swap entry.
1582 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1583 Status
= MmCreateVirtualMapping(Process
,
1588 if (!NT_SUCCESS(Status
))
1590 DPRINT1("Unable to create virtual mapping\n");
1591 KeBugCheck(MEMORY_MANAGEMENT
);
1593 MmInsertRmap(Page
, Process
, Address
);
1594 MiSetPageEvent(Process
, Address
);
1595 DPRINT("Address 0x%.8X\n", Address
);
1596 return(STATUS_SUCCESS
);
1601 * If the section offset is already in-memory and valid then just
1602 * take another reference to the page
1605 Page
= PFN_FROM_SSE(Entry
);
1607 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1608 MmUnlockSectionSegment(Segment
);
1610 Status
= MmCreateVirtualMapping(Process
,
1615 if (!NT_SUCCESS(Status
))
1617 DPRINT1("Unable to create virtual mapping\n");
1618 KeBugCheck(MEMORY_MANAGEMENT
);
1620 MmInsertRmap(Page
, Process
, Address
);
1621 MiSetPageEvent(Process
, Address
);
1622 DPRINT("Address 0x%.8X\n", Address
);
1623 return(STATUS_SUCCESS
);
1629 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1630 MEMORY_AREA
* MemoryArea
,
1633 PMM_SECTION_SEGMENT Segment
;
1634 PROS_SECTION_OBJECT Section
;
1639 LARGE_INTEGER Offset
;
1642 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1643 SWAPENTRY SwapEntry
;
1645 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
);
1648 * Check if the page has already been set readwrite
1650 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1652 DPRINT("Address 0x%.8X\n", Address
);
1653 return(STATUS_SUCCESS
);
1657 * Find the offset of the page
1659 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1660 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1661 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1663 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1664 Section
= MemoryArea
->Data
.SectionData
.Section
;
1665 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1666 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1668 ASSERT(Region
!= NULL
);
1672 MmLockSectionSegment(Segment
);
1674 OldPage
= MmGetPfnForProcess(Process
, Address
);
1675 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1677 MmUnlockSectionSegment(Segment
);
1680 * Check if we are doing COW
1682 if (!((Segment
->WriteCopy
) &&
1683 (Region
->Protect
== PAGE_READWRITE
||
1684 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1686 DPRINT("Address 0x%.8X\n", Address
);
1687 return(STATUS_ACCESS_VIOLATION
);
1690 if (IS_SWAP_FROM_SSE(Entry
) ||
1691 PFN_FROM_SSE(Entry
) != OldPage
)
1693 /* This is a private page. We must only change the page protection. */
1694 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1695 return(STATUS_SUCCESS
);
1699 DPRINT("OldPage == 0!\n");
1702 * Get or create a pageop
1704 MmLockSectionSegment(Segment
);
1705 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1708 * Wait for any other operations to complete
1710 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1712 MmUnlockSectionSegment(Segment
);
1713 MmUnlockAddressSpace(AddressSpace
);
1714 MiWaitForPageEvent(NULL
, NULL
);
1716 * Restart the operation
1718 MmLockAddressSpace(AddressSpace
);
1719 DPRINT("Address 0x%.8X\n", Address
);
1720 return(STATUS_MM_RESTART_OPERATION
);
1723 MmDeleteRmap(OldPage
, Process
, PAddress
);
1724 MmDeleteVirtualMapping(Process
, PAddress
, FALSE
, NULL
, NULL
);
1725 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1728 * Release locks now we have the pageop
1730 MmUnlockSectionSegment(Segment
);
1731 MmUnlockAddressSpace(AddressSpace
);
1736 MI_SET_USAGE(MI_USAGE_SECTION
);
1737 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1738 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1739 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1740 if (!NT_SUCCESS(Status
))
1742 KeBugCheck(MEMORY_MANAGEMENT
);
1748 MiCopyFromUserPage(NewPage
, OldPage
);
1750 MmLockAddressSpace(AddressSpace
);
1753 * Set the PTE to point to the new page
1755 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1756 Status
= MmCreateVirtualMapping(Process
,
1761 if (!NT_SUCCESS(Status
))
1763 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1764 KeBugCheck(MEMORY_MANAGEMENT
);
1767 if (!NT_SUCCESS(Status
))
1769 DPRINT1("Unable to create virtual mapping\n");
1770 KeBugCheck(MEMORY_MANAGEMENT
);
1774 * Unshare the old page.
1776 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1777 MmInsertRmap(NewPage
, Process
, PAddress
);
1778 MmLockSectionSegment(Segment
);
1779 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1780 MmUnlockSectionSegment(Segment
);
1782 MiSetPageEvent(Process
, Address
);
1783 DPRINT("Address 0x%.8X\n", Address
);
1784 return(STATUS_SUCCESS
);
1788 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1790 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1792 PFN_NUMBER Page
= 0;
1794 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1797 MmLockAddressSpace(&Process
->Vm
);
1800 MmDeleteVirtualMapping(Process
,
1807 PageOutContext
->WasDirty
= TRUE
;
1809 if (!PageOutContext
->Private
)
1811 MmLockSectionSegment(PageOutContext
->Segment
);
1812 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1813 PageOutContext
->Segment
,
1814 &PageOutContext
->Offset
,
1815 PageOutContext
->WasDirty
,
1817 &PageOutContext
->SectionEntry
);
1818 MmUnlockSectionSegment(PageOutContext
->Segment
);
1822 MmUnlockAddressSpace(&Process
->Vm
);
1825 if (PageOutContext
->Private
)
1827 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1833 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1834 MEMORY_AREA
* MemoryArea
,
1835 PVOID Address
, ULONG_PTR Entry
)
1838 MM_SECTION_PAGEOUT_CONTEXT Context
;
1839 SWAPENTRY SwapEntry
;
1840 ULONGLONG FileOffset
;
1842 PFILE_OBJECT FileObject
;
1846 BOOLEAN DirectMapped
;
1847 BOOLEAN IsImageSection
;
1848 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1851 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1854 * Get the segment and section.
1856 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1857 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1858 Context
.SectionEntry
= Entry
;
1859 Context
.CallingProcess
= Process
;
1861 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1862 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1863 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1865 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1867 FileObject
= Context
.Section
->FileObject
;
1868 DirectMapped
= FALSE
;
1870 MmLockSectionSegment(Context
.Segment
);
1873 if (FileObject
!= NULL
&&
1874 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1876 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1879 * If the file system is letting us go directly to the cache and the
1880 * memory area was mapped at an offset in the file which is page aligned
1881 * then note this is a direct mapped page.
1883 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1884 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1886 DirectMapped
= TRUE
;
1893 * This should never happen since mappings of physical memory are never
1894 * placed in the rmap lists.
1896 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1898 DPRINT1("Trying to page out from physical memory section address 0x%X "
1899 "process %d\n", Address
,
1900 Process
? Process
->UniqueProcessId
: 0);
1901 KeBugCheck(MEMORY_MANAGEMENT
);
1905 * Get the section segment entry and the physical address.
1907 if (!MmIsPagePresent(Process
, Address
))
1909 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1910 Process
? Process
->UniqueProcessId
: 0, Address
);
1911 KeBugCheck(MEMORY_MANAGEMENT
);
1913 Page
= MmGetPfnForProcess(Process
, Address
);
1914 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1917 * Check the reference count to ensure this page can be paged out
1919 if (MmGetReferenceCountPage(Page
) != 1)
1921 DPRINT("Cannot page out locked section page: 0x%p (RefCount: %d)\n",
1922 Page
, MmGetReferenceCountPage(Page
));
1923 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1924 MmUnlockSectionSegment(Context
.Segment
);
1925 return STATUS_UNSUCCESSFUL
;
1929 * Prepare the context structure for the rmap delete call.
1931 MmUnlockSectionSegment(Context
.Segment
);
1932 Context
.WasDirty
= FALSE
;
1933 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1934 IS_SWAP_FROM_SSE(Entry
) ||
1935 PFN_FROM_SSE(Entry
) != Page
)
1937 Context
.Private
= TRUE
;
1941 Context
.Private
= FALSE
;
1945 * Take an additional reference to the page or the cache segment.
1947 if (DirectMapped
&& !Context
.Private
)
1949 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
1951 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1952 KeBugCheck(MEMORY_MANAGEMENT
);
1957 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1958 MmReferencePage(Page
);
1959 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1962 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1964 /* Since we passed in a surrogate, we'll get back the page entry
1965 * state in our context. This is intended to make intermediate
1966 * decrements of share count not release the wait entry.
1968 Entry
= Context
.SectionEntry
;
1971 * If this wasn't a private page then we should have reduced the entry to
1972 * zero by deleting all the rmaps.
1974 if (!Context
.Private
&& Entry
!= 0)
1976 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1977 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1979 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
1984 * If the page wasn't dirty then we can just free it as for a readonly page.
1985 * Since we unmapped all the mappings above we know it will not suddenly
1987 * If the page is from a pagefile section and has no swap entry,
1988 * we can't free the page at this point.
1990 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1991 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1993 if (Context
.Private
)
1995 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1996 Context
.WasDirty
? "dirty" : "clean", Address
);
1997 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
1999 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2001 MmSetSavedSwapEntryPage(Page
, 0);
2002 MmLockSectionSegment(Context
.Segment
);
2003 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2004 MmUnlockSectionSegment(Context
.Segment
);
2005 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2006 MiSetPageEvent(NULL
, NULL
);
2007 return(STATUS_SUCCESS
);
2010 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2012 if (Context
.Private
)
2014 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2015 Context
.WasDirty
? "dirty" : "clean", Address
);
2016 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2018 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2020 MmSetSavedSwapEntryPage(Page
, 0);
2023 MmLockSectionSegment(Context
.Segment
);
2024 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2025 MmUnlockSectionSegment(Context
.Segment
);
2027 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2028 MiSetPageEvent(NULL
, NULL
);
2029 return(STATUS_SUCCESS
);
2032 else if (!Context
.Private
&& DirectMapped
)
2036 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2038 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2041 Status
= CcRosUnmapCacheSegment(Bcb
, (ULONG
)FileOffset
, FALSE
);
2043 Status
= STATUS_SUCCESS
;
2046 if (!NT_SUCCESS(Status
))
2048 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2049 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Bcb
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2052 MiSetPageEvent(NULL
, NULL
);
2053 return(STATUS_SUCCESS
);
2055 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2059 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2061 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2063 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2064 MiSetPageEvent(NULL
, NULL
);
2065 return(STATUS_SUCCESS
);
2067 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2069 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2070 MmSetSavedSwapEntryPage(Page
, 0);
2071 MmLockAddressSpace(AddressSpace
);
2072 Status
= MmCreatePageFileMapping(Process
,
2075 MmUnlockAddressSpace(AddressSpace
);
2076 if (!NT_SUCCESS(Status
))
2078 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2079 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2081 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2082 MiSetPageEvent(NULL
, NULL
);
2083 return(STATUS_SUCCESS
);
2087 * If necessary, allocate an entry in the paging file for this page
2091 SwapEntry
= MmAllocSwapPage();
2094 MmShowOutOfSpaceMessagePagingFile();
2095 MmLockAddressSpace(AddressSpace
);
2097 * For private pages restore the old mappings.
2099 if (Context
.Private
)
2101 Status
= MmCreateVirtualMapping(Process
,
2103 MemoryArea
->Protect
,
2106 MmSetDirtyPage(Process
, Address
);
2115 * For non-private pages if the page wasn't direct mapped then
2116 * set it back into the section segment entry so we don't loose
2117 * our copy. Otherwise it will be handled by the cache manager.
2119 Status
= MmCreateVirtualMapping(Process
,
2121 MemoryArea
->Protect
,
2124 MmSetDirtyPage(Process
, Address
);
2128 // If we got here, the previous entry should have been a wait
2129 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2130 MmLockSectionSegment(Context
.Segment
);
2131 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2132 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2133 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2134 MmUnlockSectionSegment(Context
.Segment
);
2136 MmUnlockAddressSpace(AddressSpace
);
2137 MiSetPageEvent(NULL
, NULL
);
2138 return(STATUS_PAGEFILE_QUOTA
);
2143 * Write the page to the pagefile
2145 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2146 if (!NT_SUCCESS(Status
))
2148 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2151 * As above: undo our actions.
2152 * FIXME: Also free the swap page.
2154 MmLockAddressSpace(AddressSpace
);
2155 if (Context
.Private
)
2157 Status
= MmCreateVirtualMapping(Process
,
2159 MemoryArea
->Protect
,
2162 MmSetDirtyPage(Process
, Address
);
2169 Status
= MmCreateVirtualMapping(Process
,
2171 MemoryArea
->Protect
,
2174 MmSetDirtyPage(Process
, Address
);
2178 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2179 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2181 MmUnlockAddressSpace(AddressSpace
);
2182 MiSetPageEvent(NULL
, NULL
);
2183 return(STATUS_UNSUCCESSFUL
);
2187 * Otherwise we have succeeded.
2189 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2190 MmSetSavedSwapEntryPage(Page
, 0);
2191 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2192 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2194 MmLockSectionSegment(Context
.Segment
);
2195 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2196 MmUnlockSectionSegment(Context
.Segment
);
2200 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2203 if (Context
.Private
)
2205 MmLockAddressSpace(AddressSpace
);
2206 MmLockSectionSegment(Context
.Segment
);
2207 Status
= MmCreatePageFileMapping(Process
,
2210 /* We had placed a wait entry upon entry ... replace it before leaving */
2211 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2212 MmUnlockSectionSegment(Context
.Segment
);
2213 MmUnlockAddressSpace(AddressSpace
);
2214 if (!NT_SUCCESS(Status
))
2216 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2217 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2222 MmLockAddressSpace(AddressSpace
);
2223 MmLockSectionSegment(Context
.Segment
);
2224 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2225 /* We had placed a wait entry upon entry ... replace it before leaving */
2226 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2227 MmUnlockSectionSegment(Context
.Segment
);
2228 MmUnlockAddressSpace(AddressSpace
);
2231 MiSetPageEvent(NULL
, NULL
);
2232 return(STATUS_SUCCESS
);
2237 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2238 PMEMORY_AREA MemoryArea
,
2242 LARGE_INTEGER Offset
;
2243 PROS_SECTION_OBJECT Section
;
2244 PMM_SECTION_SEGMENT Segment
;
2246 SWAPENTRY SwapEntry
;
2250 PFILE_OBJECT FileObject
;
2252 BOOLEAN DirectMapped
;
2253 BOOLEAN IsImageSection
;
2254 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2256 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2258 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2259 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2262 * Get the segment and section.
2264 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2265 Section
= MemoryArea
->Data
.SectionData
.Section
;
2266 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2268 FileObject
= Section
->FileObject
;
2269 DirectMapped
= FALSE
;
2270 if (FileObject
!= NULL
&&
2271 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2273 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2276 * If the file system is letting us go directly to the cache and the
2277 * memory area was mapped at an offset in the file which is page aligned
2278 * then note this is a direct mapped page.
2280 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2281 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2283 DirectMapped
= TRUE
;
2288 * This should never happen since mappings of physical memory are never
2289 * placed in the rmap lists.
2291 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2293 DPRINT1("Trying to write back page from physical memory mapped at %X "
2294 "process %d\n", Address
,
2295 Process
? Process
->UniqueProcessId
: 0);
2296 KeBugCheck(MEMORY_MANAGEMENT
);
2300 * Get the section segment entry and the physical address.
2302 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2303 if (!MmIsPagePresent(Process
, Address
))
2305 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2306 Process
? Process
->UniqueProcessId
: 0, Address
);
2307 KeBugCheck(MEMORY_MANAGEMENT
);
2309 Page
= MmGetPfnForProcess(Process
, Address
);
2310 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2313 * Check for a private (COWed) page.
2315 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2316 IS_SWAP_FROM_SSE(Entry
) ||
2317 PFN_FROM_SSE(Entry
) != Page
)
2327 * Speculatively set all mappings of the page to clean.
2329 MmSetCleanAllRmaps(Page
);
2332 * If this page was direct mapped from the cache then the cache manager
2333 * will take care of writing it back to disk.
2335 if (DirectMapped
&& !Private
)
2337 LARGE_INTEGER SOffset
;
2338 ASSERT(SwapEntry
== 0);
2339 SOffset
.QuadPart
= Offset
.QuadPart
+ Segment
->Image
.FileOffset
;
2341 CcRosMarkDirtyCacheSegment(Bcb
, Offset
.LowPart
);
2343 MmLockSectionSegment(Segment
);
2344 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2345 MmUnlockSectionSegment(Segment
);
2346 MiSetPageEvent(NULL
, NULL
);
2347 return(STATUS_SUCCESS
);
2351 * If necessary, allocate an entry in the paging file for this page
2355 SwapEntry
= MmAllocSwapPage();
2358 MmSetDirtyAllRmaps(Page
);
2359 MiSetPageEvent(NULL
, NULL
);
2360 return(STATUS_PAGEFILE_QUOTA
);
2362 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2366 * Write the page to the pagefile
2368 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2369 if (!NT_SUCCESS(Status
))
2371 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2373 MmSetDirtyAllRmaps(Page
);
2374 MiSetPageEvent(NULL
, NULL
);
2375 return(STATUS_UNSUCCESSFUL
);
2379 * Otherwise we have succeeded.
2381 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2382 MiSetPageEvent(NULL
, NULL
);
2383 return(STATUS_SUCCESS
);
2387 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2395 PMEMORY_AREA MemoryArea
;
2396 PMM_SECTION_SEGMENT Segment
;
2397 BOOLEAN DoCOW
= FALSE
;
2399 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2401 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2402 ASSERT(MemoryArea
!= NULL
);
2403 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2404 MmLockSectionSegment(Segment
);
2406 if ((Segment
->WriteCopy
) &&
2407 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2412 if (OldProtect
!= NewProtect
)
2414 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2416 SWAPENTRY SwapEntry
;
2417 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2418 ULONG Protect
= NewProtect
;
2420 /* Wait for a wait entry to disappear */
2422 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2423 if (SwapEntry
!= MM_WAIT_ENTRY
)
2425 MiWaitForPageEvent(Process
, Address
);
2429 * If we doing COW for this segment then check if the page is
2432 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2434 LARGE_INTEGER Offset
;
2438 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2439 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2440 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2442 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2443 * IS_SWAP_FROM_SSE and we'll do the right thing.
2445 Page
= MmGetPfnForProcess(Process
, Address
);
2447 Protect
= PAGE_READONLY
;
2448 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2449 IS_SWAP_FROM_SSE(Entry
) ||
2450 PFN_FROM_SSE(Entry
) != Page
)
2452 Protect
= NewProtect
;
2456 if (MmIsPagePresent(Process
, Address
) || MmIsDisabledPage(Process
, Address
))
2458 MmSetPageProtect(Process
, Address
,
2464 MmUnlockSectionSegment(Segment
);
2469 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2470 PMEMORY_AREA MemoryArea
,
2478 ULONG_PTR MaxLength
;
2480 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2481 if (Length
> MaxLength
)
2482 Length
= (ULONG
)MaxLength
;
2484 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2485 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2487 ASSERT(Region
!= NULL
);
2489 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2490 Region
->Protect
!= Protect
)
2492 return STATUS_INVALID_PAGE_PROTECTION
;
2495 *OldProtect
= Region
->Protect
;
2496 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2497 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2498 BaseAddress
, Length
, Region
->Type
, Protect
,
2499 MmAlterViewAttributes
);
2505 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2507 PMEMORY_BASIC_INFORMATION Info
,
2508 PSIZE_T ResultLength
)
2511 PVOID RegionBaseAddress
;
2512 PROS_SECTION_OBJECT Section
;
2513 PMM_SECTION_SEGMENT Segment
;
2515 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2516 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2517 Address
, &RegionBaseAddress
);
2520 return STATUS_UNSUCCESSFUL
;
2523 Section
= MemoryArea
->Data
.SectionData
.Section
;
2524 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2526 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2527 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2528 Info
->Type
= MEM_IMAGE
;
2532 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2533 Info
->Type
= MEM_MAPPED
;
2535 Info
->BaseAddress
= RegionBaseAddress
;
2536 Info
->AllocationProtect
= MemoryArea
->Protect
;
2537 Info
->RegionSize
= Region
->Length
;
2538 Info
->State
= MEM_COMMIT
;
2539 Info
->Protect
= Region
->Protect
;
2541 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2542 return(STATUS_SUCCESS
);
2547 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2550 LARGE_INTEGER Offset
;
2552 SWAPENTRY SavedSwapEntry
;
2557 MmLockSectionSegment(Segment
);
2559 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2560 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2562 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2565 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2566 if (IS_SWAP_FROM_SSE(Entry
))
2568 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2572 Page
= PFN_FROM_SSE(Entry
);
2573 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2574 if (SavedSwapEntry
!= 0)
2576 MmSetSavedSwapEntryPage(Page
, 0);
2577 MmFreeSwapPage(SavedSwapEntry
);
2579 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2584 MmUnlockSectionSegment(Segment
);
2588 MmpDeleteSection(PVOID ObjectBody
)
2590 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2592 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2593 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2598 PMM_SECTION_SEGMENT SectionSegments
;
2601 * NOTE: Section->ImageSection can be NULL for short time
2602 * during the section creating. If we fail for some reason
2603 * until the image section is properly initialized we shouldn't
2604 * process further here.
2606 if (Section
->ImageSection
== NULL
)
2609 SectionSegments
= Section
->ImageSection
->Segments
;
2610 NrSegments
= Section
->ImageSection
->NrSegments
;
2612 for (i
= 0; i
< NrSegments
; i
++)
2614 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2616 MmLockSectionSegment(&SectionSegments
[i
]);
2618 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2619 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2621 MmUnlockSectionSegment(&SectionSegments
[i
]);
2624 MmpFreePageFileSegment(&SectionSegments
[i
]);
2630 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2633 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2636 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2638 DPRINT("Freeing section segment\n");
2639 Section
->Segment
= NULL
;
2640 MmFinalizeSegment(Segment
);
2644 DPRINT("RefCount %d\n", RefCount
);
2651 * NOTE: Section->Segment can be NULL for short time
2652 * during the section creating.
2654 if (Section
->Segment
== NULL
)
2657 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2659 MmpFreePageFileSegment(Section
->Segment
);
2660 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2661 ExFreePool(Section
->Segment
);
2662 Section
->Segment
= NULL
;
2666 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2669 if (Section
->FileObject
!= NULL
)
2672 CcRosDereferenceCache(Section
->FileObject
);
2674 ObDereferenceObject(Section
->FileObject
);
2675 Section
->FileObject
= NULL
;
2680 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2682 IN ACCESS_MASK GrantedAccess
,
2683 IN ULONG ProcessHandleCount
,
2684 IN ULONG SystemHandleCount
)
2686 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2687 Object
, ProcessHandleCount
);
2693 MmCreatePhysicalMemorySection(VOID
)
2695 PROS_SECTION_OBJECT PhysSection
;
2697 OBJECT_ATTRIBUTES Obj
;
2698 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2699 LARGE_INTEGER SectionSize
;
2703 * Create the section mapping physical memory
2705 SectionSize
.QuadPart
= 0xFFFFFFFF;
2706 InitializeObjectAttributes(&Obj
,
2711 Status
= MmCreateSection((PVOID
)&PhysSection
,
2715 PAGE_EXECUTE_READWRITE
,
2719 if (!NT_SUCCESS(Status
))
2721 DPRINT1("Failed to create PhysicalMemory section\n");
2722 KeBugCheck(MEMORY_MANAGEMENT
);
2724 Status
= ObInsertObject(PhysSection
,
2730 if (!NT_SUCCESS(Status
))
2732 ObDereferenceObject(PhysSection
);
2734 ObCloseHandle(Handle
, KernelMode
);
2735 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2736 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2738 return(STATUS_SUCCESS
);
2744 MmInitSectionImplementation(VOID
)
2746 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2747 UNICODE_STRING Name
;
2749 DPRINT("Creating Section Object Type\n");
2751 /* Initialize the section based root */
2752 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2753 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2755 /* Initialize the Section object type */
2756 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2757 RtlInitUnicodeString(&Name
, L
"Section");
2758 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2759 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2760 ObjectTypeInitializer
.PoolType
= PagedPool
;
2761 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2762 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2763 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2764 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2765 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2766 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2768 MmCreatePhysicalMemorySection();
2770 return(STATUS_SUCCESS
);
2775 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2776 ACCESS_MASK DesiredAccess
,
2777 POBJECT_ATTRIBUTES ObjectAttributes
,
2778 PLARGE_INTEGER UMaximumSize
,
2779 ULONG SectionPageProtection
,
2780 ULONG AllocationAttributes
)
2782 * Create a section which is backed by the pagefile
2785 LARGE_INTEGER MaximumSize
;
2786 PROS_SECTION_OBJECT Section
;
2787 PMM_SECTION_SEGMENT Segment
;
2790 if (UMaximumSize
== NULL
)
2792 return(STATUS_UNSUCCESSFUL
);
2794 MaximumSize
= *UMaximumSize
;
2797 * Create the section
2799 Status
= ObCreateObject(ExGetPreviousMode(),
2800 MmSectionObjectType
,
2802 ExGetPreviousMode(),
2804 sizeof(ROS_SECTION_OBJECT
),
2807 (PVOID
*)(PVOID
)&Section
);
2808 if (!NT_SUCCESS(Status
))
2816 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2817 Section
->Type
= 'SC';
2818 Section
->Size
= 'TN';
2819 Section
->SectionPageProtection
= SectionPageProtection
;
2820 Section
->AllocationAttributes
= AllocationAttributes
;
2821 Section
->MaximumSize
= MaximumSize
;
2822 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2823 TAG_MM_SECTION_SEGMENT
);
2824 if (Segment
== NULL
)
2826 ObDereferenceObject(Section
);
2827 return(STATUS_NO_MEMORY
);
2829 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2830 Section
->Segment
= Segment
;
2831 Segment
->ReferenceCount
= 1;
2832 ExInitializeFastMutex(&Segment
->Lock
);
2833 Segment
->Image
.FileOffset
= 0;
2834 Segment
->Protection
= SectionPageProtection
;
2835 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2836 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2837 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2838 Segment
->WriteCopy
= FALSE
;
2839 Segment
->Image
.VirtualAddress
= 0;
2840 Segment
->Image
.Characteristics
= 0;
2841 *SectionObject
= Section
;
2842 MiInitializeSectionPageTable(Segment
);
2843 return(STATUS_SUCCESS
);
2848 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2849 ACCESS_MASK DesiredAccess
,
2850 POBJECT_ATTRIBUTES ObjectAttributes
,
2851 PLARGE_INTEGER UMaximumSize
,
2852 ULONG SectionPageProtection
,
2853 ULONG AllocationAttributes
,
2856 * Create a section backed by a data file
2859 PROS_SECTION_OBJECT Section
;
2861 LARGE_INTEGER MaximumSize
;
2862 PFILE_OBJECT FileObject
;
2863 PMM_SECTION_SEGMENT Segment
;
2865 IO_STATUS_BLOCK Iosb
;
2866 LARGE_INTEGER Offset
;
2868 FILE_STANDARD_INFORMATION FileInfo
;
2872 * Create the section
2874 Status
= ObCreateObject(ExGetPreviousMode(),
2875 MmSectionObjectType
,
2877 ExGetPreviousMode(),
2879 sizeof(ROS_SECTION_OBJECT
),
2883 if (!NT_SUCCESS(Status
))
2890 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2891 Section
->Type
= 'SC';
2892 Section
->Size
= 'TN';
2893 Section
->SectionPageProtection
= SectionPageProtection
;
2894 Section
->AllocationAttributes
= AllocationAttributes
;
2897 * Reference the file handle
2899 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2900 Status
= ObReferenceObjectByHandle(FileHandle
,
2903 ExGetPreviousMode(),
2904 (PVOID
*)(PVOID
)&FileObject
,
2906 if (!NT_SUCCESS(Status
))
2908 ObDereferenceObject(Section
);
2913 * FIXME: This is propably not entirely correct. We can't look into
2914 * the standard FCB header because it might not be initialized yet
2915 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2916 * standard file information is filled on first request).
2918 Status
= IoQueryFileInformation(FileObject
,
2919 FileStandardInformation
,
2920 sizeof(FILE_STANDARD_INFORMATION
),
2923 Iosb
.Information
= Length
;
2924 if (!NT_SUCCESS(Status
))
2926 ObDereferenceObject(Section
);
2927 ObDereferenceObject(FileObject
);
2932 * FIXME: Revise this once a locking order for file size changes is
2935 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2937 MaximumSize
= *UMaximumSize
;
2941 MaximumSize
= FileInfo
.EndOfFile
;
2942 /* Mapping zero-sized files isn't allowed. */
2943 if (MaximumSize
.QuadPart
== 0)
2945 ObDereferenceObject(Section
);
2946 ObDereferenceObject(FileObject
);
2947 return STATUS_FILE_INVALID
;
2951 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2953 Status
= IoSetInformation(FileObject
,
2954 FileAllocationInformation
,
2955 sizeof(LARGE_INTEGER
),
2957 if (!NT_SUCCESS(Status
))
2959 ObDereferenceObject(Section
);
2960 ObDereferenceObject(FileObject
);
2961 return(STATUS_SECTION_NOT_EXTENDED
);
2965 if (FileObject
->SectionObjectPointer
== NULL
||
2966 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2969 * Read a bit so caching is initiated for the file object.
2970 * This is only needed because MiReadPage currently cannot
2971 * handle non-cached streams.
2973 Offset
.QuadPart
= 0;
2974 Status
= ZwReadFile(FileHandle
,
2983 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2985 ObDereferenceObject(Section
);
2986 ObDereferenceObject(FileObject
);
2989 if (FileObject
->SectionObjectPointer
== NULL
||
2990 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2992 /* FIXME: handle this situation */
2993 ObDereferenceObject(Section
);
2994 ObDereferenceObject(FileObject
);
2995 return STATUS_INVALID_PARAMETER
;
3002 Status
= MmspWaitForFileLock(FileObject
);
3003 if (Status
!= STATUS_SUCCESS
)
3005 ObDereferenceObject(Section
);
3006 ObDereferenceObject(FileObject
);
3011 * If this file hasn't been mapped as a data file before then allocate a
3012 * section segment to describe the data file mapping
3014 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3016 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3017 TAG_MM_SECTION_SEGMENT
);
3018 if (Segment
== NULL
)
3020 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3021 ObDereferenceObject(Section
);
3022 ObDereferenceObject(FileObject
);
3023 return(STATUS_NO_MEMORY
);
3025 Section
->Segment
= Segment
;
3026 Segment
->ReferenceCount
= 1;
3027 ExInitializeFastMutex(&Segment
->Lock
);
3029 * Set the lock before assigning the segment to the file object
3031 ExAcquireFastMutex(&Segment
->Lock
);
3032 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3034 Segment
->Image
.FileOffset
= 0;
3035 Segment
->Protection
= SectionPageProtection
;
3036 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3037 Segment
->Image
.Characteristics
= 0;
3038 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3039 if (AllocationAttributes
& SEC_RESERVE
)
3041 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3045 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3046 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3048 Segment
->Image
.VirtualAddress
= 0;
3049 Segment
->Locked
= TRUE
;
3050 MiInitializeSectionPageTable(Segment
);
3055 * If the file is already mapped as a data file then we may need
3059 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3061 Section
->Segment
= Segment
;
3062 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3063 MmLockSectionSegment(Segment
);
3065 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3066 !(AllocationAttributes
& SEC_RESERVE
))
3068 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3069 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3072 MmUnlockSectionSegment(Segment
);
3073 Section
->FileObject
= FileObject
;
3074 Section
->MaximumSize
= MaximumSize
;
3076 CcRosReferenceCache(FileObject
);
3078 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3079 *SectionObject
= Section
;
3080 return(STATUS_SUCCESS
);
3084 TODO: not that great (declaring loaders statically, having to declare all of
3085 them, having to keep them extern, etc.), will fix in the future
3087 extern NTSTATUS NTAPI PeFmtCreateSection
3089 IN CONST VOID
* FileHeader
,
3090 IN SIZE_T FileHeaderSize
,
3092 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3094 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3095 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3098 extern NTSTATUS NTAPI ElfFmtCreateSection
3100 IN CONST VOID
* FileHeader
,
3101 IN SIZE_T FileHeaderSize
,
3103 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3105 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3106 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3109 /* TODO: this is a standard DDK/PSDK macro */
3110 #ifndef RTL_NUMBER_OF
3111 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3114 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3125 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3127 SIZE_T SizeOfSegments
;
3128 PMM_SECTION_SEGMENT Segments
;
3130 /* TODO: check for integer overflow */
3131 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3133 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3135 TAG_MM_SECTION_SEGMENT
);
3138 RtlZeroMemory(Segments
, SizeOfSegments
);
3146 ExeFmtpReadFile(IN PVOID File
,
3147 IN PLARGE_INTEGER Offset
,
3150 OUT PVOID
* AllocBase
,
3151 OUT PULONG ReadSize
)
3154 LARGE_INTEGER FileOffset
;
3156 ULONG OffsetAdjustment
;
3160 PFILE_OBJECT FileObject
= File
;
3161 IO_STATUS_BLOCK Iosb
;
3163 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3167 KeBugCheck(MEMORY_MANAGEMENT
);
3170 FileOffset
= *Offset
;
3172 /* Negative/special offset: it cannot be used in this context */
3173 if(FileOffset
.u
.HighPart
< 0)
3175 KeBugCheck(MEMORY_MANAGEMENT
);
3178 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3179 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3180 FileOffset
.u
.LowPart
= AdjustOffset
;
3182 BufferSize
= Length
+ OffsetAdjustment
;
3183 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3186 * It's ok to use paged pool, because this is a temporary buffer only used in
3187 * the loading of executables. The assumption is that MmCreateSection is
3188 * always called at low IRQLs and that these buffers don't survive a brief
3189 * initialization phase
3191 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3196 KeBugCheck(MEMORY_MANAGEMENT
);
3201 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3203 UsedSize
= (ULONG
)Iosb
.Information
;
3205 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3207 Status
= STATUS_IN_PAGE_ERROR
;
3208 ASSERT(!NT_SUCCESS(Status
));
3211 if(NT_SUCCESS(Status
))
3213 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3214 *AllocBase
= Buffer
;
3215 *ReadSize
= UsedSize
- OffsetAdjustment
;
3219 ExFreePoolWithTag(Buffer
, 'rXmM');
3226 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3227 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3228 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3233 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3237 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3239 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3240 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3247 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3251 MmspAssertSegmentsSorted(ImageSectionObject
);
3253 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3255 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3259 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3260 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3261 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3269 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3273 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3275 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3276 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3284 MmspCompareSegments(const void * x
,
3287 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3288 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3291 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3292 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3296 * Ensures an image section's segments are sorted in memory
3301 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3304 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3306 MmspAssertSegmentsSorted(ImageSectionObject
);
3310 qsort(ImageSectionObject
->Segments
,
3311 ImageSectionObject
->NrSegments
,
3312 sizeof(ImageSectionObject
->Segments
[0]),
3313 MmspCompareSegments
);
3319 * Ensures an image section's segments don't overlap in memory and don't have
3320 * gaps and don't have a null size. We let them map to overlapping file regions,
3321 * though - that's not necessarily an error
3326 MmspCheckSegmentBounds
3328 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3334 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3336 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3340 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3342 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3344 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3352 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3353 * page could be OK (Windows seems to be OK with them), and larger gaps
3354 * could lead to image sections spanning several discontiguous regions
3355 * (NtMapViewOfSection could then refuse to map them, and they could
3356 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3358 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3359 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3360 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3371 * Merges and pads an image section's segments until they all are page-aligned
3372 * and have a size that is a multiple of the page size
3377 MmspPageAlignSegments
3379 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3385 PMM_SECTION_SEGMENT EffectiveSegment
;
3387 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3389 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3394 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3396 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3399 * The first segment requires special handling
3403 ULONG_PTR VirtualAddress
;
3404 ULONG_PTR VirtualOffset
;
3406 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3408 /* Round down the virtual address to the nearest page */
3409 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3411 /* Round up the virtual size to the nearest page */
3412 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3413 EffectiveSegment
->Image
.VirtualAddress
;
3415 /* Adjust the raw address and size */
3416 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3418 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3424 * Garbage in, garbage out: unaligned base addresses make the file
3425 * offset point in curious and odd places, but that's what we were
3428 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3429 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3433 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3434 ULONG_PTR EndOfEffectiveSegment
;
3436 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3437 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3440 * The current segment begins exactly where the current effective
3441 * segment ended, therefore beginning a new effective segment
3443 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3446 ASSERT(LastSegment
<= i
);
3447 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3449 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3451 if (LastSegment
!= i
)
3454 * Copy the current segment. If necessary, the effective segment
3455 * will be expanded later
3457 *EffectiveSegment
= *Segment
;
3461 * Page-align the virtual size. We know for sure the virtual address
3464 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3465 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3468 * The current segment is still part of the current effective segment:
3469 * extend the effective segment to reflect this
3471 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3473 static const ULONG FlagsToProtection
[16] =
3481 PAGE_EXECUTE_READWRITE
,
3482 PAGE_EXECUTE_READWRITE
,
3487 PAGE_EXECUTE_WRITECOPY
,
3488 PAGE_EXECUTE_WRITECOPY
,
3489 PAGE_EXECUTE_WRITECOPY
,
3490 PAGE_EXECUTE_WRITECOPY
3493 unsigned ProtectionFlags
;
3496 * Extend the file size
3499 /* Unaligned segments must be contiguous within the file */
3500 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3501 EffectiveSegment
->RawLength
.QuadPart
))
3506 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3509 * Extend the virtual size
3511 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3513 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3514 EffectiveSegment
->Image
.VirtualAddress
;
3517 * Merge the protection
3519 EffectiveSegment
->Protection
|= Segment
->Protection
;
3521 /* Clean up redundance */
3522 ProtectionFlags
= 0;
3524 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3525 ProtectionFlags
|= 1 << 0;
3527 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3528 ProtectionFlags
|= 1 << 1;
3530 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3531 ProtectionFlags
|= 1 << 2;
3533 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3534 ProtectionFlags
|= 1 << 3;
3536 ASSERT(ProtectionFlags
< 16);
3537 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3539 /* If a segment was required to be shared and cannot, fail */
3540 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3541 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3547 * We assume no holes between segments at this point
3551 KeBugCheck(MEMORY_MANAGEMENT
);
3555 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3561 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3562 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3564 LARGE_INTEGER Offset
;
3566 PVOID FileHeaderBuffer
;
3567 ULONG FileHeaderSize
;
3569 ULONG OldNrSegments
;
3574 * Read the beginning of the file (2 pages). Should be enough to contain
3575 * all (or most) of the headers
3577 Offset
.QuadPart
= 0;
3579 /* FIXME: use FileObject instead of FileHandle */
3580 Status
= ExeFmtpReadFile (FileHandle
,
3587 if (!NT_SUCCESS(Status
))
3590 if (FileHeaderSize
== 0)
3592 ExFreePool(FileHeaderBuffer
);
3593 return STATUS_UNSUCCESSFUL
;
3597 * Look for a loader that can handle this executable
3599 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3601 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3604 /* FIXME: use FileObject instead of FileHandle */
3605 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3611 ExeFmtpAllocateSegments
);
3613 if (!NT_SUCCESS(Status
))
3615 if (ImageSectionObject
->Segments
)
3617 ExFreePool(ImageSectionObject
->Segments
);
3618 ImageSectionObject
->Segments
= NULL
;
3622 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3626 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3629 * No loader handled the format
3631 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3633 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3634 ASSERT(!NT_SUCCESS(Status
));
3637 if (!NT_SUCCESS(Status
))
3640 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3645 /* FIXME? are these values platform-dependent? */
3646 if(ImageSectionObject
->StackReserve
== 0)
3647 ImageSectionObject
->StackReserve
= 0x40000;
3649 if(ImageSectionObject
->StackCommit
== 0)
3650 ImageSectionObject
->StackCommit
= 0x1000;
3652 if(ImageSectionObject
->ImageBase
== 0)
3654 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3655 ImageSectionObject
->ImageBase
= 0x10000000;
3657 ImageSectionObject
->ImageBase
= 0x00400000;
3661 * And now the fun part: fixing the segments
3664 /* Sort them by virtual address */
3665 MmspSortSegments(ImageSectionObject
, Flags
);
3667 /* Ensure they don't overlap in memory */
3668 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3669 return STATUS_INVALID_IMAGE_FORMAT
;
3671 /* Ensure they are aligned */
3672 OldNrSegments
= ImageSectionObject
->NrSegments
;
3674 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3675 return STATUS_INVALID_IMAGE_FORMAT
;
3677 /* Trim them if the alignment phase merged some of them */
3678 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3680 PMM_SECTION_SEGMENT Segments
;
3681 SIZE_T SizeOfSegments
;
3683 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3685 Segments
= ExAllocatePoolWithTag(PagedPool
,
3687 TAG_MM_SECTION_SEGMENT
);
3689 if (Segments
== NULL
)
3690 return STATUS_INSUFFICIENT_RESOURCES
;
3692 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3693 ExFreePool(ImageSectionObject
->Segments
);
3694 ImageSectionObject
->Segments
= Segments
;
3697 /* And finish their initialization */
3698 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3700 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3701 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3702 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3705 ASSERT(NT_SUCCESS(Status
));
3710 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3711 ACCESS_MASK DesiredAccess
,
3712 POBJECT_ATTRIBUTES ObjectAttributes
,
3713 PLARGE_INTEGER UMaximumSize
,
3714 ULONG SectionPageProtection
,
3715 ULONG AllocationAttributes
,
3716 PFILE_OBJECT FileObject
)
3718 PROS_SECTION_OBJECT Section
;
3720 PMM_SECTION_SEGMENT SectionSegments
;
3721 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3724 if (FileObject
== NULL
)
3725 return STATUS_INVALID_FILE_FOR_SECTION
;
3728 * Create the section
3730 Status
= ObCreateObject (ExGetPreviousMode(),
3731 MmSectionObjectType
,
3733 ExGetPreviousMode(),
3735 sizeof(ROS_SECTION_OBJECT
),
3738 (PVOID
*)(PVOID
)&Section
);
3739 if (!NT_SUCCESS(Status
))
3741 ObDereferenceObject(FileObject
);
3748 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3749 Section
->Type
= 'SC';
3750 Section
->Size
= 'TN';
3751 Section
->SectionPageProtection
= SectionPageProtection
;
3752 Section
->AllocationAttributes
= AllocationAttributes
;
3756 * Initialized caching for this file object if previously caching
3757 * was initialized for the same on disk file
3759 Status
= CcTryToInitializeFileCache(FileObject
);
3761 Status
= STATUS_SUCCESS
;
3764 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3766 NTSTATUS StatusExeFmt
;
3768 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3769 if (ImageSectionObject
== NULL
)
3771 ObDereferenceObject(FileObject
);
3772 ObDereferenceObject(Section
);
3773 return(STATUS_NO_MEMORY
);
3776 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3778 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3780 if (!NT_SUCCESS(StatusExeFmt
))
3782 if(ImageSectionObject
->Segments
!= NULL
)
3783 ExFreePool(ImageSectionObject
->Segments
);
3785 ExFreePool(ImageSectionObject
);
3786 ObDereferenceObject(Section
);
3787 ObDereferenceObject(FileObject
);
3788 return(StatusExeFmt
);
3791 Section
->ImageSection
= ImageSectionObject
;
3792 ASSERT(ImageSectionObject
->Segments
);
3797 Status
= MmspWaitForFileLock(FileObject
);
3798 if (!NT_SUCCESS(Status
))
3800 ExFreePool(ImageSectionObject
->Segments
);
3801 ExFreePool(ImageSectionObject
);
3802 ObDereferenceObject(Section
);
3803 ObDereferenceObject(FileObject
);
3807 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3808 ImageSectionObject
, NULL
))
3811 * An other thread has initialized the same image in the background
3813 ExFreePool(ImageSectionObject
->Segments
);
3814 ExFreePool(ImageSectionObject
);
3815 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3816 Section
->ImageSection
= ImageSectionObject
;
3817 SectionSegments
= ImageSectionObject
->Segments
;
3819 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3821 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3825 Status
= StatusExeFmt
;
3832 Status
= MmspWaitForFileLock(FileObject
);
3833 if (Status
!= STATUS_SUCCESS
)
3835 ObDereferenceObject(Section
);
3836 ObDereferenceObject(FileObject
);
3840 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3841 Section
->ImageSection
= ImageSectionObject
;
3842 SectionSegments
= ImageSectionObject
->Segments
;
3845 * Otherwise just reference all the section segments
3847 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3849 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3852 Status
= STATUS_SUCCESS
;
3854 Section
->FileObject
= FileObject
;
3856 CcRosReferenceCache(FileObject
);
3858 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3859 *SectionObject
= Section
;
3866 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3867 PROS_SECTION_OBJECT Section
,
3868 PMM_SECTION_SEGMENT Segment
,
3873 ULONG AllocationType
)
3877 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3879 if (Segment
->WriteCopy
)
3881 /* We have to do this because the not present fault
3882 * and access fault handlers depend on the protection
3883 * that should be granted AFTER the COW fault takes
3884 * place to be in Region->Protect. The not present fault
3885 * handler changes this to the correct protection for COW when
3886 * mapping the pages into the process's address space. If a COW
3887 * fault takes place, the access fault handler sets the page protection
3888 * to these values for the newly copied pages
3890 if (Protect
== PAGE_WRITECOPY
)
3891 Protect
= PAGE_READWRITE
;
3892 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3893 Protect
= PAGE_EXECUTE_READWRITE
;
3896 BoundaryAddressMultiple
.QuadPart
= 0;
3899 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
3900 LARGE_INTEGER FileOffset
;
3901 FileOffset
.QuadPart
= ViewOffset
;
3902 ObReferenceObject(Section
);
3903 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3906 Status
= MmCreateMemoryArea(AddressSpace
,
3907 MEMORY_AREA_SECTION_VIEW
,
3914 BoundaryAddressMultiple
);
3915 if (!NT_SUCCESS(Status
))
3917 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3918 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3922 ObReferenceObject((PVOID
)Section
);
3924 MArea
->Data
.SectionData
.Segment
= Segment
;
3925 MArea
->Data
.SectionData
.Section
= Section
;
3926 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3927 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3928 ViewSize
, 0, Protect
);
3930 return(STATUS_SUCCESS
);
3935 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3936 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3939 PFILE_OBJECT FileObject
;
3941 LARGE_INTEGER Offset
;
3942 SWAPENTRY SavedSwapEntry
;
3943 PROS_SECTION_OBJECT Section
;
3944 PMM_SECTION_SEGMENT Segment
;
3945 PMMSUPPORT AddressSpace
;
3948 AddressSpace
= (PMMSUPPORT
)Context
;
3949 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3951 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3953 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3954 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3956 Section
= MemoryArea
->Data
.SectionData
.Section
;
3957 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3959 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3960 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
3962 MmUnlockSectionSegment(Segment
);
3963 MmUnlockAddressSpace(AddressSpace
);
3965 MiWaitForPageEvent(NULL
, NULL
);
3967 MmLockAddressSpace(AddressSpace
);
3968 MmLockSectionSegment(Segment
);
3969 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3973 * For a dirty, datafile, non-private page mark it as dirty in the
3976 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3978 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3980 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3981 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3983 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)(Offset
.QuadPart
+ Segment
->Image
.FileOffset
));
3985 ASSERT(SwapEntry
== 0);
3994 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3996 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3997 KeBugCheck(MEMORY_MANAGEMENT
);
3999 MmFreeSwapPage(SwapEntry
);
4003 if (IS_SWAP_FROM_SSE(Entry
) ||
4004 Page
!= PFN_FROM_SSE(Entry
))
4009 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4011 DPRINT1("Found a private page in a pagefile section.\n");
4012 KeBugCheck(MEMORY_MANAGEMENT
);
4015 * Just dereference private pages
4017 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4018 if (SavedSwapEntry
!= 0)
4020 MmFreeSwapPage(SavedSwapEntry
);
4021 MmSetSavedSwapEntryPage(Page
, 0);
4023 MmDeleteRmap(Page
, Process
, Address
);
4024 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4028 MmDeleteRmap(Page
, Process
, Address
);
4029 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4035 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4039 PMEMORY_AREA MemoryArea
;
4040 PROS_SECTION_OBJECT Section
;
4041 PMM_SECTION_SEGMENT Segment
;
4042 PLIST_ENTRY CurrentEntry
;
4043 PMM_REGION CurrentRegion
;
4044 PLIST_ENTRY RegionListHead
;
4046 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4048 if (MemoryArea
== NULL
)
4050 return(STATUS_UNSUCCESSFUL
);
4053 MemoryArea
->DeleteInProgress
= TRUE
;
4054 Section
= MemoryArea
->Data
.SectionData
.Section
;
4055 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4058 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4059 return MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4062 MmLockSectionSegment(Segment
);
4064 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4065 while (!IsListEmpty(RegionListHead
))
4067 CurrentEntry
= RemoveHeadList(RegionListHead
);
4068 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4069 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4072 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4074 Status
= MmFreeMemoryArea(AddressSpace
,
4081 Status
= MmFreeMemoryArea(AddressSpace
,
4086 MmUnlockSectionSegment(Segment
);
4087 ObDereferenceObject(Section
);
4093 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4094 IN PVOID BaseAddress
,
4098 PMEMORY_AREA MemoryArea
;
4099 PMMSUPPORT AddressSpace
;
4100 PROS_SECTION_OBJECT Section
;
4101 PVOID ImageBaseAddress
= 0;
4103 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4104 Process
, BaseAddress
);
4108 AddressSpace
= &Process
->Vm
;
4110 MmLockAddressSpace(AddressSpace
);
4111 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4113 if (MemoryArea
== NULL
||
4114 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4115 MemoryArea
->DeleteInProgress
)
4117 ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4118 MmUnlockAddressSpace(AddressSpace
);
4119 return STATUS_NOT_MAPPED_VIEW
;
4122 MemoryArea
->DeleteInProgress
= TRUE
;
4124 Section
= MemoryArea
->Data
.SectionData
.Section
;
4126 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4130 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4131 PMM_SECTION_SEGMENT SectionSegments
;
4132 PMM_SECTION_SEGMENT Segment
;
4134 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4135 ImageSectionObject
= Section
->ImageSection
;
4136 SectionSegments
= ImageSectionObject
->Segments
;
4137 NrSegments
= ImageSectionObject
->NrSegments
;
4139 /* Search for the current segment within the section segments
4140 * and calculate the image base address */
4141 for (i
= 0; i
< NrSegments
; i
++)
4143 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4145 if (Segment
== &SectionSegments
[i
])
4147 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4152 if (i
>= NrSegments
)
4154 KeBugCheck(MEMORY_MANAGEMENT
);
4157 for (i
= 0; i
< NrSegments
; i
++)
4159 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4161 PVOID SBaseAddress
= (PVOID
)
4162 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4164 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4170 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4173 MmUnlockAddressSpace(AddressSpace
);
4175 /* Notify debugger */
4176 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4178 return(STATUS_SUCCESS
);
4185 * Queries the information of a section object.
4187 * @param SectionHandle
4188 * Handle to the section object. It must be opened with SECTION_QUERY
4190 * @param SectionInformationClass
4191 * Index to a certain information structure. Can be either
4192 * SectionBasicInformation or SectionImageInformation. The latter
4193 * is valid only for sections that were created with the SEC_IMAGE
4195 * @param SectionInformation
4196 * Caller supplies storage for resulting information.
4198 * Size of the supplied storage.
4199 * @param ResultLength
4207 NtQuerySection(IN HANDLE SectionHandle
,
4208 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4209 OUT PVOID SectionInformation
,
4210 IN SIZE_T SectionInformationLength
,
4211 OUT PSIZE_T ResultLength OPTIONAL
)
4213 PROS_SECTION_OBJECT Section
;
4214 KPROCESSOR_MODE PreviousMode
;
4218 PreviousMode
= ExGetPreviousMode();
4220 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4222 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4224 (ULONG
)SectionInformationLength
,
4229 if(!NT_SUCCESS(Status
))
4231 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4235 Status
= ObReferenceObjectByHandle(SectionHandle
,
4237 MmSectionObjectType
,
4239 (PVOID
*)(PVOID
)&Section
,
4241 if (NT_SUCCESS(Status
))
4243 switch (SectionInformationClass
)
4245 case SectionBasicInformation
:
4247 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4251 Sbi
->Attributes
= Section
->AllocationAttributes
;
4252 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4254 Sbi
->BaseAddress
= 0;
4255 Sbi
->Size
.QuadPart
= 0;
4259 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4260 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4263 if (ResultLength
!= NULL
)
4265 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4267 Status
= STATUS_SUCCESS
;
4269 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4271 Status
= _SEH2_GetExceptionCode();
4278 case SectionImageInformation
:
4280 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4284 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4285 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4287 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4288 ImageSectionObject
= Section
->ImageSection
;
4290 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4291 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4292 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4293 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4294 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4295 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4296 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4297 Sii
->Machine
= ImageSectionObject
->Machine
;
4298 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4301 if (ResultLength
!= NULL
)
4303 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4305 Status
= STATUS_SUCCESS
;
4307 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4309 Status
= _SEH2_GetExceptionCode();
4317 ObDereferenceObject(Section
);
4323 /**********************************************************************
4325 * MmMapViewOfSection
4328 * Maps a view of a section into the virtual address space of a
4333 * Pointer to the section object.
4336 * Pointer to the process.
4339 * Desired base address (or NULL) on entry;
4340 * Actual base address of the view on exit.
4343 * Number of high order address bits that must be zero.
4346 * Size in bytes of the initially committed section of
4350 * Offset in bytes from the beginning of the section
4351 * to the beginning of the view.
4354 * Desired length of map (or zero to map all) on entry
4355 * Actual length mapped on exit.
4357 * InheritDisposition
4358 * Specified how the view is to be shared with
4362 * Type of allocation for the pages.
4365 * Protection for the committed region of the view.
4373 MmMapViewOfSection(IN PVOID SectionObject
,
4374 IN PEPROCESS Process
,
4375 IN OUT PVOID
*BaseAddress
,
4376 IN ULONG_PTR ZeroBits
,
4377 IN SIZE_T CommitSize
,
4378 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4379 IN OUT PSIZE_T ViewSize
,
4380 IN SECTION_INHERIT InheritDisposition
,
4381 IN ULONG AllocationType
,
4384 PROS_SECTION_OBJECT Section
;
4385 PMMSUPPORT AddressSpace
;
4387 NTSTATUS Status
= STATUS_SUCCESS
;
4388 BOOLEAN NotAtBase
= FALSE
;
4390 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4392 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4393 return MmMapViewOfArm3Section(SectionObject
,
4407 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4409 return STATUS_INVALID_PAGE_PROTECTION
;
4413 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4414 AddressSpace
= &Process
->Vm
;
4416 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4418 MmLockAddressSpace(AddressSpace
);
4420 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4424 ULONG_PTR ImageBase
;
4426 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4427 PMM_SECTION_SEGMENT SectionSegments
;
4429 ImageSectionObject
= Section
->ImageSection
;
4430 SectionSegments
= ImageSectionObject
->Segments
;
4431 NrSegments
= ImageSectionObject
->NrSegments
;
4434 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4437 ImageBase
= ImageSectionObject
->ImageBase
;
4441 for (i
= 0; i
< NrSegments
; i
++)
4443 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4445 ULONG_PTR MaxExtent
;
4446 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4447 SectionSegments
[i
].Length
.QuadPart
);
4448 ImageSize
= max(ImageSize
, MaxExtent
);
4452 ImageSectionObject
->ImageSize
= (ULONG
)ImageSize
;
4454 /* Check for an illegal base address */
4455 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4457 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4460 /* Check there is enough space to map the section at that point. */
4461 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4462 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4464 /* Fail if the user requested a fixed base address. */
4465 if ((*BaseAddress
) != NULL
)
4467 MmUnlockAddressSpace(AddressSpace
);
4468 return(STATUS_UNSUCCESSFUL
);
4470 /* Otherwise find a gap to map the image. */
4471 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4474 MmUnlockAddressSpace(AddressSpace
);
4475 return(STATUS_UNSUCCESSFUL
);
4477 /* Remember that we loaded image at a different base address */
4481 for (i
= 0; i
< NrSegments
; i
++)
4483 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4485 PVOID SBaseAddress
= (PVOID
)
4486 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4487 MmLockSectionSegment(&SectionSegments
[i
]);
4488 Status
= MmMapViewOfSegment(AddressSpace
,
4490 &SectionSegments
[i
],
4492 SectionSegments
[i
].Length
.LowPart
,
4493 SectionSegments
[i
].Protection
,
4496 MmUnlockSectionSegment(&SectionSegments
[i
]);
4497 if (!NT_SUCCESS(Status
))
4499 MmUnlockAddressSpace(AddressSpace
);
4505 *BaseAddress
= (PVOID
)ImageBase
;
4506 *ViewSize
= ImageSize
;
4510 /* check for write access */
4511 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4512 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4514 MmUnlockAddressSpace(AddressSpace
);
4515 return STATUS_SECTION_PROTECTION
;
4517 /* check for read access */
4518 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4519 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4521 MmUnlockAddressSpace(AddressSpace
);
4522 return STATUS_SECTION_PROTECTION
;
4524 /* check for execute access */
4525 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4526 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4528 MmUnlockAddressSpace(AddressSpace
);
4529 return STATUS_SECTION_PROTECTION
;
4532 if (ViewSize
== NULL
)
4534 /* Following this pointer would lead to us to the dark side */
4535 /* What to do? Bugcheck? Return status? Do the mambo? */
4536 KeBugCheck(MEMORY_MANAGEMENT
);
4539 if (SectionOffset
== NULL
)
4545 ViewOffset
= SectionOffset
->u
.LowPart
;
4548 if ((ViewOffset
% PAGE_SIZE
) != 0)
4550 MmUnlockAddressSpace(AddressSpace
);
4551 return(STATUS_MAPPED_ALIGNMENT
);
4554 if ((*ViewSize
) == 0)
4556 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4558 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4560 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4563 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4565 MmLockSectionSegment(Section
->Segment
);
4566 Status
= MmMapViewOfSegment(AddressSpace
,
4573 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4574 MmUnlockSectionSegment(Section
->Segment
);
4575 if (!NT_SUCCESS(Status
))
4577 MmUnlockAddressSpace(AddressSpace
);
4582 MmUnlockAddressSpace(AddressSpace
);
4585 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4587 Status
= STATUS_SUCCESS
;
4596 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4597 IN PLARGE_INTEGER NewFileSize
)
4599 /* Check whether an ImageSectionObject exists */
4600 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4602 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4606 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4608 PMM_SECTION_SEGMENT Segment
;
4610 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4613 if (Segment
->ReferenceCount
!= 0)
4616 CC_FILE_SIZES FileSizes
;
4618 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4621 /* Check size of file */
4622 if (SectionObjectPointer
->SharedCacheMap
)
4624 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4629 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4638 /* Check size of file */
4639 if (SectionObjectPointer
->SharedCacheMap
)
4641 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4642 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4651 /* Something must gone wrong
4652 * how can we have a Section but no
4654 DPRINT("ERROR: DataSectionObject without reference!\n");
4658 DPRINT("FIXME: didn't check for outstanding write probes\n");
4670 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4671 IN MMFLUSH_TYPE FlushType
)
4673 BOOLEAN Result
= TRUE
;
4675 PMM_SECTION_SEGMENT Segment
;
4680 case MmFlushForDelete
:
4681 if (SectionObjectPointer
->ImageSectionObject
||
4682 SectionObjectPointer
->DataSectionObject
)
4687 CcRosSetRemoveOnClose(SectionObjectPointer
);
4690 case MmFlushForWrite
:
4692 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4694 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4697 if (SectionObjectPointer
->ImageSectionObject
) {
4698 DPRINT1("SectionObject has ImageSection\n");
4704 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4706 DPRINT("Result %d\n", Result
);
4718 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4719 OUT PVOID
* MappedBase
,
4720 IN OUT PSIZE_T ViewSize
)
4722 PROS_SECTION_OBJECT Section
;
4723 PMMSUPPORT AddressSpace
;
4727 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4729 return MiMapViewInSystemSpace(SectionObject
,
4735 DPRINT("MmMapViewInSystemSpace() called\n");
4737 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4738 AddressSpace
= MmGetKernelAddressSpace();
4740 MmLockAddressSpace(AddressSpace
);
4743 if ((*ViewSize
) == 0)
4745 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4747 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4749 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4752 MmLockSectionSegment(Section
->Segment
);
4755 Status
= MmMapViewOfSegment(AddressSpace
,
4764 MmUnlockSectionSegment(Section
->Segment
);
4765 MmUnlockAddressSpace(AddressSpace
);
4772 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4774 PMMSUPPORT AddressSpace
;
4777 DPRINT("MmUnmapViewInSystemSpace() called\n");
4779 AddressSpace
= MmGetKernelAddressSpace();
4781 MmLockAddressSpace(AddressSpace
);
4783 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4785 MmUnlockAddressSpace(AddressSpace
);
4790 /**********************************************************************
4795 * Creates a section object.
4798 * SectionObject (OUT)
4799 * Caller supplied storage for the resulting pointer
4800 * to a SECTION_OBJECT instance;
4803 * Specifies the desired access to the section can be a
4805 * STANDARD_RIGHTS_REQUIRED |
4807 * SECTION_MAP_WRITE |
4808 * SECTION_MAP_READ |
4809 * SECTION_MAP_EXECUTE
4811 * ObjectAttributes [OPTIONAL]
4812 * Initialized attributes for the object can be used
4813 * to create a named section;
4816 * Maximizes the size of the memory section. Must be
4817 * non-NULL for a page-file backed section.
4818 * If value specified for a mapped file and the file is
4819 * not large enough, file will be extended.
4821 * SectionPageProtection
4822 * Can be a combination of:
4828 * AllocationAttributes
4829 * Can be a combination of:
4834 * Handle to a file to create a section mapped to a file
4835 * instead of a memory backed section;
4846 MmCreateSection (OUT PVOID
* Section
,
4847 IN ACCESS_MASK DesiredAccess
,
4848 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4849 IN PLARGE_INTEGER MaximumSize
,
4850 IN ULONG SectionPageProtection
,
4851 IN ULONG AllocationAttributes
,
4852 IN HANDLE FileHandle OPTIONAL
,
4853 IN PFILE_OBJECT FileObject OPTIONAL
)
4856 ULONG Protection
, FileAccess
;
4857 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4859 /* Check if an ARM3 section is being created instead */
4860 if (AllocationAttributes
& 1)
4862 DPRINT1("Creating ARM3 section\n");
4863 return MmCreateArm3Section(Section
,
4867 SectionPageProtection
,
4868 AllocationAttributes
&~ 1,
4874 * Check the protection
4876 Protection
= SectionPageProtection
& ~(PAGE_GUARD
| PAGE_NOCACHE
);
4877 if (Protection
!= PAGE_READONLY
&&
4878 Protection
!= PAGE_READWRITE
&&
4879 Protection
!= PAGE_WRITECOPY
&&
4880 Protection
!= PAGE_EXECUTE
&&
4881 Protection
!= PAGE_EXECUTE_READ
&&
4882 Protection
!= PAGE_EXECUTE_READWRITE
&&
4883 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4885 return STATUS_INVALID_PAGE_PROTECTION
;
4888 if ((DesiredAccess
& SECTION_MAP_WRITE
) &&
4889 (Protection
== PAGE_READWRITE
||
4890 Protection
== PAGE_EXECUTE_READWRITE
) &&
4891 !(AllocationAttributes
& SEC_IMAGE
))
4893 DPRINT("Creating a section with WRITE access\n");
4894 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
| SYNCHRONIZE
;
4898 DPRINT("Creating a section with READ access\n");
4899 FileAccess
= FILE_READ_DATA
| SYNCHRONIZE
;
4902 /* FIXME: somehow combine this with the above checks */
4903 if (AllocationAttributes
& SEC_IMAGE
)
4904 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
4906 if (!FileObject
&& FileHandle
)
4908 Status
= ObReferenceObjectByHandle(FileHandle
,
4911 ExGetPreviousMode(),
4912 (PVOID
*)&FileObject
,
4914 if (!NT_SUCCESS(Status
))
4916 DPRINT("Failed: 0x%08lx\n", Status
);
4920 else if (FileObject
)
4921 ObReferenceObject(FileObject
);
4923 #ifndef NEWCC // A hack for initializing caching.
4924 // This is needed only in the old case.
4927 IO_STATUS_BLOCK Iosb
;
4930 LARGE_INTEGER ByteOffset
;
4931 ByteOffset
.QuadPart
= 0;
4932 Status
= ZwReadFile(FileHandle
,
4941 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
4943 // Caching is initialized...
4947 if (AllocationAttributes
& SEC_IMAGE
)
4949 Status
= MmCreateImageSection(SectionObject
,
4953 SectionPageProtection
,
4954 AllocationAttributes
,
4958 else if (FileHandle
!= NULL
)
4960 Status
= MmCreateDataFileSection(SectionObject
,
4964 SectionPageProtection
,
4965 AllocationAttributes
,
4968 ObDereferenceObject(FileObject
);
4971 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
4973 Status
= MmCreateCacheSection(SectionObject
,
4977 SectionPageProtection
,
4978 AllocationAttributes
,
4984 Status
= MmCreatePageFileSection(SectionObject
,
4988 SectionPageProtection
,
4989 AllocationAttributes
);
4996 MmModifyAttributes(IN PMMSUPPORT AddressSpace
,
4997 IN PVOID BaseAddress
,
4998 IN SIZE_T RegionSize
,
5000 IN ULONG OldProtect
,
5002 IN ULONG NewProtect
)
5005 // This function is deprecated but remains in order to support VirtualAlloc
5006 // calls with MEM_COMMIT on top of MapViewOfFile calls with SEC_RESERVE.
5008 // Win32k's shared user heap, for example, uses that mechanism. The two
5009 // conditions when this function needs to do something are ASSERTed for,
5010 // because they should not arise.
5012 if (NewType
== MEM_RESERVE
&& OldType
== MEM_COMMIT
)
5017 if ((NewType
== MEM_COMMIT
) && (OldType
== MEM_COMMIT
))
5019 ASSERT(OldProtect
== NewProtect
);
5025 MiRosAllocateVirtualMemory(IN HANDLE ProcessHandle
,
5026 IN PEPROCESS Process
,
5027 IN PMEMORY_AREA MemoryArea
,
5028 IN PMMSUPPORT AddressSpace
,
5029 IN OUT PVOID
* UBaseAddress
,
5030 IN BOOLEAN Attached
,
5031 IN OUT PSIZE_T URegionSize
,
5032 IN ULONG AllocationType
,
5035 ULONG_PTR PRegionSize
;
5036 ULONG Type
, RegionSize
;
5038 PVOID PBaseAddress
, BaseAddress
;
5039 KAPC_STATE ApcState
;
5041 PBaseAddress
= *UBaseAddress
;
5042 PRegionSize
= *URegionSize
;
5044 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(PBaseAddress
);
5045 RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)PBaseAddress
+ PRegionSize
) -
5046 PAGE_ROUND_DOWN(PBaseAddress
);
5047 Type
= (AllocationType
& MEM_COMMIT
) ? MEM_COMMIT
: MEM_RESERVE
;
5049 ASSERT(PBaseAddress
!= 0);
5050 ASSERT(Type
== MEM_COMMIT
);
5051 ASSERT(MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
);
5052 ASSERT(((ULONG_PTR
)BaseAddress
+ RegionSize
) <= (ULONG_PTR
)MemoryArea
->EndingAddress
);
5053 ASSERT(((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
) >= RegionSize
);
5054 ASSERT(MemoryArea
->Data
.SectionData
.RegionListHead
.Flink
);
5056 Status
= MmAlterRegion(AddressSpace
,
5057 MemoryArea
->StartingAddress
,
5058 &MemoryArea
->Data
.SectionData
.RegionListHead
,
5063 MmModifyAttributes
);
5065 MmUnlockAddressSpace(AddressSpace
);
5066 if (Attached
) KeUnstackDetachProcess(&ApcState
);
5067 if (ProcessHandle
!= NtCurrentProcess()) ObDereferenceObject(Process
);
5068 if (NT_SUCCESS(Status
))
5070 *UBaseAddress
= BaseAddress
;
5071 *URegionSize
= RegionSize
;
5079 MiRosProtectVirtualMemory(IN PEPROCESS Process
,
5080 IN OUT PVOID
*BaseAddress
,
5081 IN OUT PSIZE_T NumberOfBytesToProtect
,
5082 IN ULONG NewAccessProtection
,
5083 OUT PULONG OldAccessProtection OPTIONAL
)
5085 PMEMORY_AREA MemoryArea
;
5086 PMMSUPPORT AddressSpace
;
5087 ULONG OldAccessProtection_
;
5090 *NumberOfBytesToProtect
= PAGE_ROUND_UP((ULONG_PTR
)(*BaseAddress
) + (*NumberOfBytesToProtect
)) - PAGE_ROUND_DOWN(*BaseAddress
);
5091 *BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(*BaseAddress
);
5093 AddressSpace
= &Process
->Vm
;
5094 MmLockAddressSpace(AddressSpace
);
5095 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, *BaseAddress
);
5096 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
5098 MmUnlockAddressSpace(AddressSpace
);
5099 return STATUS_UNSUCCESSFUL
;
5102 if (OldAccessProtection
== NULL
) OldAccessProtection
= &OldAccessProtection_
;
5104 if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
5106 Status
= MmProtectSectionView(AddressSpace
,
5109 *NumberOfBytesToProtect
,
5110 NewAccessProtection
,
5111 OldAccessProtection
);
5115 /* FIXME: Should we return failure or success in this case? */
5116 Status
= STATUS_CONFLICTING_ADDRESSES
;
5119 MmUnlockAddressSpace(AddressSpace
);