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
);
1216 * There is a window between taking the page fault and locking the
1217 * address space when another thread could load the page so we check
1220 if (MmIsPagePresent(Process
, Address
))
1222 return(STATUS_SUCCESS
);
1226 * Check for the virtual memory area being deleted.
1228 if (MemoryArea
->DeleteInProgress
)
1230 return(STATUS_UNSUCCESSFUL
);
1233 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1234 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1235 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1237 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1238 Section
= MemoryArea
->Data
.SectionData
.Section
;
1239 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1240 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1242 ASSERT(Region
!= NULL
);
1246 MmLockSectionSegment(Segment
);
1247 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1249 * Check if this page needs to be mapped COW
1251 if ((Segment
->WriteCopy
) &&
1252 (Region
->Protect
== PAGE_READWRITE
||
1253 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1255 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1259 Attributes
= Region
->Protect
;
1263 * Check if someone else is already handling this fault, if so wait
1266 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1268 MmUnlockSectionSegment(Segment
);
1269 MmUnlockAddressSpace(AddressSpace
);
1270 MiWaitForPageEvent(NULL
, NULL
);
1271 MmLockAddressSpace(AddressSpace
);
1272 DPRINT("Address 0x%.8X\n", Address
);
1273 return(STATUS_MM_RESTART_OPERATION
);
1276 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1280 SWAPENTRY SwapEntry
;
1282 * Is it a wait entry?
1284 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1286 if (SwapEntry
== MM_WAIT_ENTRY
)
1288 MmUnlockSectionSegment(Segment
);
1289 MmUnlockAddressSpace(AddressSpace
);
1290 MiWaitForPageEvent(NULL
, NULL
);
1291 MmLockAddressSpace(AddressSpace
);
1292 return STATUS_MM_RESTART_OPERATION
;
1296 * Must be private page we have swapped out.
1302 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1304 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1305 KeBugCheck(MEMORY_MANAGEMENT
);
1308 MmUnlockSectionSegment(Segment
);
1309 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1311 MmUnlockAddressSpace(AddressSpace
);
1312 MI_SET_USAGE(MI_USAGE_SECTION
);
1313 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1314 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1315 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1316 if (!NT_SUCCESS(Status
))
1318 KeBugCheck(MEMORY_MANAGEMENT
);
1321 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1322 if (!NT_SUCCESS(Status
))
1324 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1325 KeBugCheck(MEMORY_MANAGEMENT
);
1327 MmLockAddressSpace(AddressSpace
);
1328 Status
= MmCreateVirtualMapping(Process
,
1333 if (!NT_SUCCESS(Status
))
1335 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1336 KeBugCheck(MEMORY_MANAGEMENT
);
1341 * Store the swap entry for later use.
1343 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1346 * Add the page to the process's working set
1348 MmInsertRmap(Page
, Process
, Address
);
1350 * Finish the operation
1352 MiSetPageEvent(Process
, Address
);
1353 DPRINT("Address 0x%.8X\n", Address
);
1354 return(STATUS_SUCCESS
);
1358 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1360 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1362 MmUnlockSectionSegment(Segment
);
1364 * Just map the desired physical page
1366 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1367 Status
= MmCreateVirtualMappingUnsafe(Process
,
1372 if (!NT_SUCCESS(Status
))
1374 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1375 KeBugCheck(MEMORY_MANAGEMENT
);
1380 * Cleanup and release locks
1382 MiSetPageEvent(Process
, Address
);
1383 DPRINT("Address 0x%.8X\n", Address
);
1384 return(STATUS_SUCCESS
);
1388 * Map anonymous memory for BSS sections
1390 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1392 MmUnlockSectionSegment(Segment
);
1393 MI_SET_USAGE(MI_USAGE_SECTION
);
1394 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1395 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1396 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1397 if (!NT_SUCCESS(Status
))
1399 MmUnlockAddressSpace(AddressSpace
);
1400 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1401 MmLockAddressSpace(AddressSpace
);
1403 if (!NT_SUCCESS(Status
))
1405 KeBugCheck(MEMORY_MANAGEMENT
);
1407 Status
= MmCreateVirtualMapping(Process
,
1412 if (!NT_SUCCESS(Status
))
1414 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1415 KeBugCheck(MEMORY_MANAGEMENT
);
1418 MmInsertRmap(Page
, Process
, Address
);
1421 * Cleanup and release locks
1423 MiSetPageEvent(Process
, Address
);
1424 DPRINT("Address 0x%.8X\n", Address
);
1425 return(STATUS_SUCCESS
);
1429 * Get the entry corresponding to the offset within the section
1431 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1436 * If the entry is zero (and it can't change because we have
1437 * locked the segment) then we need to load the page.
1441 * Release all our locks and read in the page from disk
1443 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1444 MmUnlockSectionSegment(Segment
);
1445 MmUnlockAddressSpace(AddressSpace
);
1447 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1448 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1449 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1451 MI_SET_USAGE(MI_USAGE_SECTION
);
1452 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1453 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1454 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1455 if (!NT_SUCCESS(Status
))
1457 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1463 Status
= MiReadPage(MemoryArea
, (ULONG_PTR
)Offset
.QuadPart
, &Page
);
1464 if (!NT_SUCCESS(Status
))
1466 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1469 if (!NT_SUCCESS(Status
))
1472 * FIXME: What do we know in this case?
1475 * Cleanup and release locks
1477 MmLockAddressSpace(AddressSpace
);
1478 MiSetPageEvent(Process
, Address
);
1479 DPRINT("Address 0x%.8X\n", Address
);
1484 * Mark the offset within the section as having valid, in-memory
1487 MmLockAddressSpace(AddressSpace
);
1488 MmLockSectionSegment(Segment
);
1489 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1490 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1491 MmUnlockSectionSegment(Segment
);
1493 Status
= MmCreateVirtualMapping(Process
,
1498 if (!NT_SUCCESS(Status
))
1500 DPRINT1("Unable to create virtual mapping\n");
1501 KeBugCheck(MEMORY_MANAGEMENT
);
1503 MmInsertRmap(Page
, Process
, Address
);
1505 MiSetPageEvent(Process
, Address
);
1506 DPRINT("Address 0x%.8X\n", Address
);
1507 return(STATUS_SUCCESS
);
1509 else if (IS_SWAP_FROM_SSE(Entry
))
1511 SWAPENTRY SwapEntry
;
1513 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1516 * Release all our locks and read in the page from disk
1518 MmUnlockSectionSegment(Segment
);
1520 MmUnlockAddressSpace(AddressSpace
);
1521 MI_SET_USAGE(MI_USAGE_SECTION
);
1522 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1523 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1524 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1525 if (!NT_SUCCESS(Status
))
1527 KeBugCheck(MEMORY_MANAGEMENT
);
1530 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1531 if (!NT_SUCCESS(Status
))
1533 KeBugCheck(MEMORY_MANAGEMENT
);
1537 * Relock the address space and segment
1539 MmLockAddressSpace(AddressSpace
);
1540 MmLockSectionSegment(Segment
);
1543 * Check the entry. No one should change the status of a page
1544 * that has a pending page-in.
1546 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1547 if (Entry
!= Entry1
)
1549 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1550 KeBugCheck(MEMORY_MANAGEMENT
);
1554 * Mark the offset within the section as having valid, in-memory
1557 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1558 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1559 MmUnlockSectionSegment(Segment
);
1562 * Save the swap entry.
1564 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1565 Status
= MmCreateVirtualMapping(Process
,
1570 if (!NT_SUCCESS(Status
))
1572 DPRINT1("Unable to create virtual mapping\n");
1573 KeBugCheck(MEMORY_MANAGEMENT
);
1575 MmInsertRmap(Page
, Process
, Address
);
1576 MiSetPageEvent(Process
, Address
);
1577 DPRINT("Address 0x%.8X\n", Address
);
1578 return(STATUS_SUCCESS
);
1583 * If the section offset is already in-memory and valid then just
1584 * take another reference to the page
1587 Page
= PFN_FROM_SSE(Entry
);
1589 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1590 MmUnlockSectionSegment(Segment
);
1592 Status
= MmCreateVirtualMapping(Process
,
1597 if (!NT_SUCCESS(Status
))
1599 DPRINT1("Unable to create virtual mapping\n");
1600 KeBugCheck(MEMORY_MANAGEMENT
);
1602 MmInsertRmap(Page
, Process
, Address
);
1603 MiSetPageEvent(Process
, Address
);
1604 DPRINT("Address 0x%.8X\n", Address
);
1605 return(STATUS_SUCCESS
);
1611 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1612 MEMORY_AREA
* MemoryArea
,
1615 PMM_SECTION_SEGMENT Segment
;
1616 PROS_SECTION_OBJECT Section
;
1621 LARGE_INTEGER Offset
;
1624 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1625 SWAPENTRY SwapEntry
;
1627 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
);
1630 * Check if the page has already been set readwrite
1632 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1634 DPRINT("Address 0x%.8X\n", Address
);
1635 return(STATUS_SUCCESS
);
1639 * Find the offset of the page
1641 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1642 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1643 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1645 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1646 Section
= MemoryArea
->Data
.SectionData
.Section
;
1647 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1648 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1650 ASSERT(Region
!= NULL
);
1654 MmLockSectionSegment(Segment
);
1656 OldPage
= MmGetPfnForProcess(Process
, Address
);
1657 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1659 MmUnlockSectionSegment(Segment
);
1662 * Check if we are doing COW
1664 if (!((Segment
->WriteCopy
) &&
1665 (Region
->Protect
== PAGE_READWRITE
||
1666 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1668 DPRINT("Address 0x%.8X\n", Address
);
1669 return(STATUS_ACCESS_VIOLATION
);
1672 if (IS_SWAP_FROM_SSE(Entry
) ||
1673 PFN_FROM_SSE(Entry
) != OldPage
)
1675 /* This is a private page. We must only change the page protection. */
1676 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1677 return(STATUS_SUCCESS
);
1681 DPRINT("OldPage == 0!\n");
1684 * Get or create a pageop
1686 MmLockSectionSegment(Segment
);
1687 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1690 * Wait for any other operations to complete
1692 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1694 MmUnlockSectionSegment(Segment
);
1695 MmUnlockAddressSpace(AddressSpace
);
1696 MiWaitForPageEvent(NULL
, NULL
);
1698 * Restart the operation
1700 MmLockAddressSpace(AddressSpace
);
1701 DPRINT("Address 0x%.8X\n", Address
);
1702 return(STATUS_MM_RESTART_OPERATION
);
1705 MmDeleteRmap(OldPage
, Process
, PAddress
);
1706 MmDeleteVirtualMapping(Process
, PAddress
, FALSE
, NULL
, NULL
);
1707 MmCreatePageFileMapping(Process
, PAddress
, MM_WAIT_ENTRY
);
1710 * Release locks now we have the pageop
1712 MmUnlockSectionSegment(Segment
);
1713 MmUnlockAddressSpace(AddressSpace
);
1718 MI_SET_USAGE(MI_USAGE_SECTION
);
1719 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1720 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1721 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1722 if (!NT_SUCCESS(Status
))
1724 KeBugCheck(MEMORY_MANAGEMENT
);
1730 MiCopyFromUserPage(NewPage
, OldPage
);
1732 MmLockAddressSpace(AddressSpace
);
1735 * Set the PTE to point to the new page
1737 MmDeletePageFileMapping(Process
, PAddress
, &SwapEntry
);
1738 Status
= MmCreateVirtualMapping(Process
,
1743 if (!NT_SUCCESS(Status
))
1745 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1746 KeBugCheck(MEMORY_MANAGEMENT
);
1749 if (!NT_SUCCESS(Status
))
1751 DPRINT1("Unable to create virtual mapping\n");
1752 KeBugCheck(MEMORY_MANAGEMENT
);
1756 * Unshare the old page.
1758 DPRINT("Swapping page (Old %x New %x)\n", OldPage
, NewPage
);
1759 MmInsertRmap(NewPage
, Process
, PAddress
);
1760 MmLockSectionSegment(Segment
);
1761 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1762 MmUnlockSectionSegment(Segment
);
1764 MiSetPageEvent(Process
, Address
);
1765 DPRINT("Address 0x%.8X\n", Address
);
1766 return(STATUS_SUCCESS
);
1770 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1772 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1774 PFN_NUMBER Page
= 0;
1776 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1779 MmLockAddressSpace(&Process
->Vm
);
1782 MmDeleteVirtualMapping(Process
,
1789 PageOutContext
->WasDirty
= TRUE
;
1791 if (!PageOutContext
->Private
)
1793 MmLockSectionSegment(PageOutContext
->Segment
);
1794 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1795 PageOutContext
->Segment
,
1796 &PageOutContext
->Offset
,
1797 PageOutContext
->WasDirty
,
1799 &PageOutContext
->SectionEntry
);
1800 MmUnlockSectionSegment(PageOutContext
->Segment
);
1804 MmUnlockAddressSpace(&Process
->Vm
);
1807 if (PageOutContext
->Private
)
1809 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1815 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1816 MEMORY_AREA
* MemoryArea
,
1817 PVOID Address
, ULONG_PTR Entry
)
1820 MM_SECTION_PAGEOUT_CONTEXT Context
;
1821 SWAPENTRY SwapEntry
;
1822 ULONGLONG FileOffset
;
1824 PFILE_OBJECT FileObject
;
1828 BOOLEAN DirectMapped
;
1829 BOOLEAN IsImageSection
;
1830 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1833 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1836 * Get the segment and section.
1838 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1839 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1840 Context
.SectionEntry
= Entry
;
1841 Context
.CallingProcess
= Process
;
1843 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1844 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1845 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1847 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1849 FileObject
= Context
.Section
->FileObject
;
1850 DirectMapped
= FALSE
;
1852 MmLockSectionSegment(Context
.Segment
);
1855 if (FileObject
!= NULL
&&
1856 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1858 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1861 * If the file system is letting us go directly to the cache and the
1862 * memory area was mapped at an offset in the file which is page aligned
1863 * then note this is a direct mapped page.
1865 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1866 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1868 DirectMapped
= TRUE
;
1875 * This should never happen since mappings of physical memory are never
1876 * placed in the rmap lists.
1878 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1880 DPRINT1("Trying to page out from physical memory section address 0x%X "
1881 "process %d\n", Address
,
1882 Process
? Process
->UniqueProcessId
: 0);
1883 KeBugCheck(MEMORY_MANAGEMENT
);
1887 * Get the section segment entry and the physical address.
1889 if (!MmIsPagePresent(Process
, Address
))
1891 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1892 Process
? Process
->UniqueProcessId
: 0, Address
);
1893 KeBugCheck(MEMORY_MANAGEMENT
);
1895 Page
= MmGetPfnForProcess(Process
, Address
);
1896 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1899 * Check the reference count to ensure this page can be paged out
1901 if (MmGetReferenceCountPage(Page
) != 1)
1903 DPRINT("Cannot page out locked section page: 0x%p (RefCount: %d)\n",
1904 Page
, MmGetReferenceCountPage(Page
));
1905 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1906 MmUnlockSectionSegment(Context
.Segment
);
1907 return STATUS_UNSUCCESSFUL
;
1911 * Prepare the context structure for the rmap delete call.
1913 MmUnlockSectionSegment(Context
.Segment
);
1914 Context
.WasDirty
= FALSE
;
1915 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1916 IS_SWAP_FROM_SSE(Entry
) ||
1917 PFN_FROM_SSE(Entry
) != Page
)
1919 Context
.Private
= TRUE
;
1923 Context
.Private
= FALSE
;
1927 * Take an additional reference to the page or the cache segment.
1929 if (DirectMapped
&& !Context
.Private
)
1931 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
1933 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1934 KeBugCheck(MEMORY_MANAGEMENT
);
1939 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1940 MmReferencePage(Page
);
1941 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1944 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1946 /* Since we passed in a surrogate, we'll get back the page entry
1947 * state in our context. This is intended to make intermediate
1948 * decrements of share count not release the wait entry.
1950 Entry
= Context
.SectionEntry
;
1953 * If this wasn't a private page then we should have reduced the entry to
1954 * zero by deleting all the rmaps.
1956 if (!Context
.Private
&& Entry
!= 0)
1958 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1959 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1961 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
1966 * If the page wasn't dirty then we can just free it as for a readonly page.
1967 * Since we unmapped all the mappings above we know it will not suddenly
1969 * If the page is from a pagefile section and has no swap entry,
1970 * we can't free the page at this point.
1972 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1973 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1975 if (Context
.Private
)
1977 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1978 Context
.WasDirty
? "dirty" : "clean", Address
);
1979 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
1981 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1983 MmSetSavedSwapEntryPage(Page
, 0);
1984 MmLockSectionSegment(Context
.Segment
);
1985 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1986 MmUnlockSectionSegment(Context
.Segment
);
1987 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1988 MiSetPageEvent(NULL
, NULL
);
1989 return(STATUS_SUCCESS
);
1992 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
1994 if (Context
.Private
)
1996 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1997 Context
.WasDirty
? "dirty" : "clean", Address
);
1998 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2000 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2002 MmSetSavedSwapEntryPage(Page
, 0);
2005 MmLockSectionSegment(Context
.Segment
);
2006 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2007 MmUnlockSectionSegment(Context
.Segment
);
2009 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2010 MiSetPageEvent(NULL
, NULL
);
2011 return(STATUS_SUCCESS
);
2014 else if (!Context
.Private
&& DirectMapped
)
2018 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2020 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2023 Status
= CcRosUnmapCacheSegment(Bcb
, (ULONG
)FileOffset
, FALSE
);
2025 Status
= STATUS_SUCCESS
;
2028 if (!NT_SUCCESS(Status
))
2030 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2031 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Bcb
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2034 MiSetPageEvent(NULL
, NULL
);
2035 return(STATUS_SUCCESS
);
2037 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2041 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2043 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2045 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2046 MiSetPageEvent(NULL
, NULL
);
2047 return(STATUS_SUCCESS
);
2049 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2051 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2052 MmSetSavedSwapEntryPage(Page
, 0);
2053 MmLockAddressSpace(AddressSpace
);
2054 Status
= MmCreatePageFileMapping(Process
,
2057 MmUnlockAddressSpace(AddressSpace
);
2058 if (!NT_SUCCESS(Status
))
2060 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2061 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2063 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2064 MiSetPageEvent(NULL
, NULL
);
2065 return(STATUS_SUCCESS
);
2069 * If necessary, allocate an entry in the paging file for this page
2073 SwapEntry
= MmAllocSwapPage();
2076 MmShowOutOfSpaceMessagePagingFile();
2077 MmLockAddressSpace(AddressSpace
);
2079 * For private pages restore the old mappings.
2081 if (Context
.Private
)
2083 Status
= MmCreateVirtualMapping(Process
,
2085 MemoryArea
->Protect
,
2088 MmSetDirtyPage(Process
, Address
);
2097 * For non-private pages if the page wasn't direct mapped then
2098 * set it back into the section segment entry so we don't loose
2099 * our copy. Otherwise it will be handled by the cache manager.
2101 Status
= MmCreateVirtualMapping(Process
,
2103 MemoryArea
->Protect
,
2106 MmSetDirtyPage(Process
, Address
);
2110 // If we got here, the previous entry should have been a wait
2111 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2112 MmLockSectionSegment(Context
.Segment
);
2113 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2114 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2115 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2116 MmUnlockSectionSegment(Context
.Segment
);
2118 MmUnlockAddressSpace(AddressSpace
);
2119 MiSetPageEvent(NULL
, NULL
);
2120 return(STATUS_PAGEFILE_QUOTA
);
2125 * Write the page to the pagefile
2127 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2128 if (!NT_SUCCESS(Status
))
2130 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2133 * As above: undo our actions.
2134 * FIXME: Also free the swap page.
2136 MmLockAddressSpace(AddressSpace
);
2137 if (Context
.Private
)
2139 Status
= MmCreateVirtualMapping(Process
,
2141 MemoryArea
->Protect
,
2144 MmSetDirtyPage(Process
, Address
);
2151 Status
= MmCreateVirtualMapping(Process
,
2153 MemoryArea
->Protect
,
2156 MmSetDirtyPage(Process
, Address
);
2160 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2161 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2163 MmUnlockAddressSpace(AddressSpace
);
2164 MiSetPageEvent(NULL
, NULL
);
2165 return(STATUS_UNSUCCESSFUL
);
2169 * Otherwise we have succeeded.
2171 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2172 MmSetSavedSwapEntryPage(Page
, 0);
2173 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2174 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2176 MmLockSectionSegment(Context
.Segment
);
2177 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2178 MmUnlockSectionSegment(Context
.Segment
);
2182 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2185 if (Context
.Private
)
2187 MmLockAddressSpace(AddressSpace
);
2188 MmLockSectionSegment(Context
.Segment
);
2189 Status
= MmCreatePageFileMapping(Process
,
2192 MmUnlockSectionSegment(Context
.Segment
);
2193 MmUnlockAddressSpace(AddressSpace
);
2194 if (!NT_SUCCESS(Status
))
2196 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2197 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2202 MmLockAddressSpace(AddressSpace
);
2203 MmLockSectionSegment(Context
.Segment
);
2204 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2205 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2206 MmUnlockSectionSegment(Context
.Segment
);
2207 MmUnlockAddressSpace(AddressSpace
);
2210 MiSetPageEvent(NULL
, NULL
);
2211 return(STATUS_SUCCESS
);
2216 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2217 PMEMORY_AREA MemoryArea
,
2221 LARGE_INTEGER Offset
;
2222 PROS_SECTION_OBJECT Section
;
2223 PMM_SECTION_SEGMENT Segment
;
2225 SWAPENTRY SwapEntry
;
2229 PFILE_OBJECT FileObject
;
2231 BOOLEAN DirectMapped
;
2232 BOOLEAN IsImageSection
;
2233 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2235 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2237 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2238 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2241 * Get the segment and section.
2243 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2244 Section
= MemoryArea
->Data
.SectionData
.Section
;
2245 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2247 FileObject
= Section
->FileObject
;
2248 DirectMapped
= FALSE
;
2249 if (FileObject
!= NULL
&&
2250 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2252 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2255 * If the file system is letting us go directly to the cache and the
2256 * memory area was mapped at an offset in the file which is page aligned
2257 * then note this is a direct mapped page.
2259 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2260 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2262 DirectMapped
= TRUE
;
2267 * This should never happen since mappings of physical memory are never
2268 * placed in the rmap lists.
2270 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2272 DPRINT1("Trying to write back page from physical memory mapped at %X "
2273 "process %d\n", Address
,
2274 Process
? Process
->UniqueProcessId
: 0);
2275 KeBugCheck(MEMORY_MANAGEMENT
);
2279 * Get the section segment entry and the physical address.
2281 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2282 if (!MmIsPagePresent(Process
, Address
))
2284 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2285 Process
? Process
->UniqueProcessId
: 0, Address
);
2286 KeBugCheck(MEMORY_MANAGEMENT
);
2288 Page
= MmGetPfnForProcess(Process
, Address
);
2289 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2292 * Check for a private (COWed) page.
2294 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2295 IS_SWAP_FROM_SSE(Entry
) ||
2296 PFN_FROM_SSE(Entry
) != Page
)
2306 * Speculatively set all mappings of the page to clean.
2308 MmSetCleanAllRmaps(Page
);
2311 * If this page was direct mapped from the cache then the cache manager
2312 * will take care of writing it back to disk.
2314 if (DirectMapped
&& !Private
)
2316 LARGE_INTEGER SOffset
;
2317 ASSERT(SwapEntry
== 0);
2318 SOffset
.QuadPart
= Offset
.QuadPart
+ Segment
->Image
.FileOffset
;
2320 CcRosMarkDirtyCacheSegment(Bcb
, Offset
.LowPart
);
2322 MmLockSectionSegment(Segment
);
2323 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2324 MmUnlockSectionSegment(Segment
);
2325 MiSetPageEvent(NULL
, NULL
);
2326 return(STATUS_SUCCESS
);
2330 * If necessary, allocate an entry in the paging file for this page
2334 SwapEntry
= MmAllocSwapPage();
2337 MmSetDirtyAllRmaps(Page
);
2338 MiSetPageEvent(NULL
, NULL
);
2339 return(STATUS_PAGEFILE_QUOTA
);
2341 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2345 * Write the page to the pagefile
2347 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2348 if (!NT_SUCCESS(Status
))
2350 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2352 MmSetDirtyAllRmaps(Page
);
2353 MiSetPageEvent(NULL
, NULL
);
2354 return(STATUS_UNSUCCESSFUL
);
2358 * Otherwise we have succeeded.
2360 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2361 MiSetPageEvent(NULL
, NULL
);
2362 return(STATUS_SUCCESS
);
2366 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2374 PMEMORY_AREA MemoryArea
;
2375 PMM_SECTION_SEGMENT Segment
;
2376 BOOLEAN DoCOW
= FALSE
;
2378 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2380 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2381 ASSERT(MemoryArea
!= NULL
);
2382 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2383 MmLockSectionSegment(Segment
);
2385 if ((Segment
->WriteCopy
) &&
2386 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2391 if (OldProtect
!= NewProtect
)
2393 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2395 SWAPENTRY SwapEntry
;
2396 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2397 ULONG Protect
= NewProtect
;
2399 /* Wait for a wait entry to disappear */
2401 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
2402 if (SwapEntry
!= MM_WAIT_ENTRY
)
2404 MiWaitForPageEvent(Process
, Address
);
2408 * If we doing COW for this segment then check if the page is
2411 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2413 LARGE_INTEGER Offset
;
2417 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2418 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2419 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2421 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
2422 * IS_SWAP_FROM_SSE and we'll do the right thing.
2424 Page
= MmGetPfnForProcess(Process
, Address
);
2426 Protect
= PAGE_READONLY
;
2427 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2428 IS_SWAP_FROM_SSE(Entry
) ||
2429 PFN_FROM_SSE(Entry
) != Page
)
2431 Protect
= NewProtect
;
2435 if (MmIsPagePresent(Process
, Address
))
2437 MmSetPageProtect(Process
, Address
,
2443 MmUnlockSectionSegment(Segment
);
2448 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2449 PMEMORY_AREA MemoryArea
,
2457 ULONG_PTR MaxLength
;
2459 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2460 if (Length
> MaxLength
)
2461 Length
= (ULONG
)MaxLength
;
2463 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2464 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2466 ASSERT(Region
!= NULL
);
2468 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2469 Region
->Protect
!= Protect
)
2471 return STATUS_INVALID_PAGE_PROTECTION
;
2474 *OldProtect
= Region
->Protect
;
2475 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2476 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2477 BaseAddress
, Length
, Region
->Type
, Protect
,
2478 MmAlterViewAttributes
);
2484 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2486 PMEMORY_BASIC_INFORMATION Info
,
2487 PSIZE_T ResultLength
)
2490 PVOID RegionBaseAddress
;
2491 PROS_SECTION_OBJECT Section
;
2492 PMM_SECTION_SEGMENT Segment
;
2494 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2495 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2496 Address
, &RegionBaseAddress
);
2499 return STATUS_UNSUCCESSFUL
;
2502 Section
= MemoryArea
->Data
.SectionData
.Section
;
2503 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2505 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2506 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2507 Info
->Type
= MEM_IMAGE
;
2511 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2512 Info
->Type
= MEM_MAPPED
;
2514 Info
->BaseAddress
= RegionBaseAddress
;
2515 Info
->AllocationProtect
= MemoryArea
->Protect
;
2516 Info
->RegionSize
= Region
->Length
;
2517 Info
->State
= MEM_COMMIT
;
2518 Info
->Protect
= Region
->Protect
;
2520 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2521 return(STATUS_SUCCESS
);
2526 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2529 LARGE_INTEGER Offset
;
2531 SWAPENTRY SavedSwapEntry
;
2536 MmLockSectionSegment(Segment
);
2538 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2539 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2541 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2544 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2545 if (IS_SWAP_FROM_SSE(Entry
))
2547 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2551 Page
= PFN_FROM_SSE(Entry
);
2552 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2553 if (SavedSwapEntry
!= 0)
2555 MmSetSavedSwapEntryPage(Page
, 0);
2556 MmFreeSwapPage(SavedSwapEntry
);
2558 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2563 MmUnlockSectionSegment(Segment
);
2567 MmpDeleteSection(PVOID ObjectBody
)
2569 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2571 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2572 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2577 PMM_SECTION_SEGMENT SectionSegments
;
2580 * NOTE: Section->ImageSection can be NULL for short time
2581 * during the section creating. If we fail for some reason
2582 * until the image section is properly initialized we shouldn't
2583 * process further here.
2585 if (Section
->ImageSection
== NULL
)
2588 SectionSegments
= Section
->ImageSection
->Segments
;
2589 NrSegments
= Section
->ImageSection
->NrSegments
;
2591 for (i
= 0; i
< NrSegments
; i
++)
2593 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2595 MmLockSectionSegment(&SectionSegments
[i
]);
2597 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2598 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2600 MmUnlockSectionSegment(&SectionSegments
[i
]);
2603 MmpFreePageFileSegment(&SectionSegments
[i
]);
2609 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2612 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2615 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2617 DPRINT("Freeing section segment\n");
2618 Section
->Segment
= NULL
;
2619 MmFinalizeSegment(Segment
);
2623 DPRINT("RefCount %d\n", RefCount
);
2630 * NOTE: Section->Segment can be NULL for short time
2631 * during the section creating.
2633 if (Section
->Segment
== NULL
)
2636 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2638 MmpFreePageFileSegment(Section
->Segment
);
2639 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2640 ExFreePool(Section
->Segment
);
2641 Section
->Segment
= NULL
;
2645 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2648 if (Section
->FileObject
!= NULL
)
2651 CcRosDereferenceCache(Section
->FileObject
);
2653 ObDereferenceObject(Section
->FileObject
);
2654 Section
->FileObject
= NULL
;
2659 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2661 IN ACCESS_MASK GrantedAccess
,
2662 IN ULONG ProcessHandleCount
,
2663 IN ULONG SystemHandleCount
)
2665 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2666 Object
, ProcessHandleCount
);
2672 MmCreatePhysicalMemorySection(VOID
)
2674 PROS_SECTION_OBJECT PhysSection
;
2676 OBJECT_ATTRIBUTES Obj
;
2677 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2678 LARGE_INTEGER SectionSize
;
2682 * Create the section mapping physical memory
2684 SectionSize
.QuadPart
= 0xFFFFFFFF;
2685 InitializeObjectAttributes(&Obj
,
2690 Status
= MmCreateSection((PVOID
)&PhysSection
,
2694 PAGE_EXECUTE_READWRITE
,
2698 if (!NT_SUCCESS(Status
))
2700 DPRINT1("Failed to create PhysicalMemory section\n");
2701 KeBugCheck(MEMORY_MANAGEMENT
);
2703 Status
= ObInsertObject(PhysSection
,
2709 if (!NT_SUCCESS(Status
))
2711 ObDereferenceObject(PhysSection
);
2713 ObCloseHandle(Handle
, KernelMode
);
2714 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2715 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2717 return(STATUS_SUCCESS
);
2723 MmInitSectionImplementation(VOID
)
2725 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2726 UNICODE_STRING Name
;
2728 DPRINT("Creating Section Object Type\n");
2730 /* Initialize the section based root */
2731 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2732 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2734 /* Initialize the Section object type */
2735 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2736 RtlInitUnicodeString(&Name
, L
"Section");
2737 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2738 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2739 ObjectTypeInitializer
.PoolType
= PagedPool
;
2740 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2741 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2742 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2743 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2744 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2745 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2747 MmCreatePhysicalMemorySection();
2749 return(STATUS_SUCCESS
);
2754 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2755 ACCESS_MASK DesiredAccess
,
2756 POBJECT_ATTRIBUTES ObjectAttributes
,
2757 PLARGE_INTEGER UMaximumSize
,
2758 ULONG SectionPageProtection
,
2759 ULONG AllocationAttributes
)
2761 * Create a section which is backed by the pagefile
2764 LARGE_INTEGER MaximumSize
;
2765 PROS_SECTION_OBJECT Section
;
2766 PMM_SECTION_SEGMENT Segment
;
2769 if (UMaximumSize
== NULL
)
2771 return(STATUS_UNSUCCESSFUL
);
2773 MaximumSize
= *UMaximumSize
;
2776 * Create the section
2778 Status
= ObCreateObject(ExGetPreviousMode(),
2779 MmSectionObjectType
,
2781 ExGetPreviousMode(),
2783 sizeof(ROS_SECTION_OBJECT
),
2786 (PVOID
*)(PVOID
)&Section
);
2787 if (!NT_SUCCESS(Status
))
2795 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2796 Section
->Type
= 'SC';
2797 Section
->Size
= 'TN';
2798 Section
->SectionPageProtection
= SectionPageProtection
;
2799 Section
->AllocationAttributes
= AllocationAttributes
;
2800 Section
->MaximumSize
= MaximumSize
;
2801 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2802 TAG_MM_SECTION_SEGMENT
);
2803 if (Segment
== NULL
)
2805 ObDereferenceObject(Section
);
2806 return(STATUS_NO_MEMORY
);
2808 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2809 Section
->Segment
= Segment
;
2810 Segment
->ReferenceCount
= 1;
2811 ExInitializeFastMutex(&Segment
->Lock
);
2812 Segment
->Image
.FileOffset
= 0;
2813 Segment
->Protection
= SectionPageProtection
;
2814 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2815 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2816 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2817 Segment
->WriteCopy
= FALSE
;
2818 Segment
->Image
.VirtualAddress
= 0;
2819 Segment
->Image
.Characteristics
= 0;
2820 *SectionObject
= Section
;
2821 MiInitializeSectionPageTable(Segment
);
2822 return(STATUS_SUCCESS
);
2827 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2828 ACCESS_MASK DesiredAccess
,
2829 POBJECT_ATTRIBUTES ObjectAttributes
,
2830 PLARGE_INTEGER UMaximumSize
,
2831 ULONG SectionPageProtection
,
2832 ULONG AllocationAttributes
,
2835 * Create a section backed by a data file
2838 PROS_SECTION_OBJECT Section
;
2840 LARGE_INTEGER MaximumSize
;
2841 PFILE_OBJECT FileObject
;
2842 PMM_SECTION_SEGMENT Segment
;
2844 IO_STATUS_BLOCK Iosb
;
2845 LARGE_INTEGER Offset
;
2847 FILE_STANDARD_INFORMATION FileInfo
;
2851 * Create the section
2853 Status
= ObCreateObject(ExGetPreviousMode(),
2854 MmSectionObjectType
,
2856 ExGetPreviousMode(),
2858 sizeof(ROS_SECTION_OBJECT
),
2862 if (!NT_SUCCESS(Status
))
2869 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2870 Section
->Type
= 'SC';
2871 Section
->Size
= 'TN';
2872 Section
->SectionPageProtection
= SectionPageProtection
;
2873 Section
->AllocationAttributes
= AllocationAttributes
;
2876 * Reference the file handle
2878 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2879 Status
= ObReferenceObjectByHandle(FileHandle
,
2882 ExGetPreviousMode(),
2883 (PVOID
*)(PVOID
)&FileObject
,
2885 if (!NT_SUCCESS(Status
))
2887 ObDereferenceObject(Section
);
2892 * FIXME: This is propably not entirely correct. We can't look into
2893 * the standard FCB header because it might not be initialized yet
2894 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2895 * standard file information is filled on first request).
2897 Status
= IoQueryFileInformation(FileObject
,
2898 FileStandardInformation
,
2899 sizeof(FILE_STANDARD_INFORMATION
),
2902 Iosb
.Information
= Length
;
2903 if (!NT_SUCCESS(Status
))
2905 ObDereferenceObject(Section
);
2906 ObDereferenceObject(FileObject
);
2911 * FIXME: Revise this once a locking order for file size changes is
2914 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2916 MaximumSize
= *UMaximumSize
;
2920 MaximumSize
= FileInfo
.EndOfFile
;
2921 /* Mapping zero-sized files isn't allowed. */
2922 if (MaximumSize
.QuadPart
== 0)
2924 ObDereferenceObject(Section
);
2925 ObDereferenceObject(FileObject
);
2926 return STATUS_FILE_INVALID
;
2930 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2932 Status
= IoSetInformation(FileObject
,
2933 FileAllocationInformation
,
2934 sizeof(LARGE_INTEGER
),
2936 if (!NT_SUCCESS(Status
))
2938 ObDereferenceObject(Section
);
2939 ObDereferenceObject(FileObject
);
2940 return(STATUS_SECTION_NOT_EXTENDED
);
2944 if (FileObject
->SectionObjectPointer
== NULL
||
2945 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2948 * Read a bit so caching is initiated for the file object.
2949 * This is only needed because MiReadPage currently cannot
2950 * handle non-cached streams.
2952 Offset
.QuadPart
= 0;
2953 Status
= ZwReadFile(FileHandle
,
2962 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2964 ObDereferenceObject(Section
);
2965 ObDereferenceObject(FileObject
);
2968 if (FileObject
->SectionObjectPointer
== NULL
||
2969 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2971 /* FIXME: handle this situation */
2972 ObDereferenceObject(Section
);
2973 ObDereferenceObject(FileObject
);
2974 return STATUS_INVALID_PARAMETER
;
2981 Status
= MmspWaitForFileLock(FileObject
);
2982 if (Status
!= STATUS_SUCCESS
)
2984 ObDereferenceObject(Section
);
2985 ObDereferenceObject(FileObject
);
2990 * If this file hasn't been mapped as a data file before then allocate a
2991 * section segment to describe the data file mapping
2993 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2995 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2996 TAG_MM_SECTION_SEGMENT
);
2997 if (Segment
== NULL
)
2999 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3000 ObDereferenceObject(Section
);
3001 ObDereferenceObject(FileObject
);
3002 return(STATUS_NO_MEMORY
);
3004 Section
->Segment
= Segment
;
3005 Segment
->ReferenceCount
= 1;
3006 ExInitializeFastMutex(&Segment
->Lock
);
3008 * Set the lock before assigning the segment to the file object
3010 ExAcquireFastMutex(&Segment
->Lock
);
3011 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3013 Segment
->Image
.FileOffset
= 0;
3014 Segment
->Protection
= SectionPageProtection
;
3015 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3016 Segment
->Image
.Characteristics
= 0;
3017 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3018 if (AllocationAttributes
& SEC_RESERVE
)
3020 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3024 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3025 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3027 Segment
->Image
.VirtualAddress
= 0;
3028 Segment
->Locked
= TRUE
;
3029 MiInitializeSectionPageTable(Segment
);
3034 * If the file is already mapped as a data file then we may need
3038 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3040 Section
->Segment
= Segment
;
3041 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3042 MmLockSectionSegment(Segment
);
3044 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3045 !(AllocationAttributes
& SEC_RESERVE
))
3047 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3048 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3051 MmUnlockSectionSegment(Segment
);
3052 Section
->FileObject
= FileObject
;
3053 Section
->MaximumSize
= MaximumSize
;
3055 CcRosReferenceCache(FileObject
);
3057 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3058 *SectionObject
= Section
;
3059 return(STATUS_SUCCESS
);
3063 TODO: not that great (declaring loaders statically, having to declare all of
3064 them, having to keep them extern, etc.), will fix in the future
3066 extern NTSTATUS NTAPI PeFmtCreateSection
3068 IN CONST VOID
* FileHeader
,
3069 IN SIZE_T FileHeaderSize
,
3071 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3073 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3074 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3077 extern NTSTATUS NTAPI ElfFmtCreateSection
3079 IN CONST VOID
* FileHeader
,
3080 IN SIZE_T FileHeaderSize
,
3082 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3084 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3085 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3088 /* TODO: this is a standard DDK/PSDK macro */
3089 #ifndef RTL_NUMBER_OF
3090 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3093 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3104 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3106 SIZE_T SizeOfSegments
;
3107 PMM_SECTION_SEGMENT Segments
;
3109 /* TODO: check for integer overflow */
3110 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3112 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3114 TAG_MM_SECTION_SEGMENT
);
3117 RtlZeroMemory(Segments
, SizeOfSegments
);
3125 ExeFmtpReadFile(IN PVOID File
,
3126 IN PLARGE_INTEGER Offset
,
3129 OUT PVOID
* AllocBase
,
3130 OUT PULONG ReadSize
)
3133 LARGE_INTEGER FileOffset
;
3135 ULONG OffsetAdjustment
;
3139 PFILE_OBJECT FileObject
= File
;
3140 IO_STATUS_BLOCK Iosb
;
3142 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3146 KeBugCheck(MEMORY_MANAGEMENT
);
3149 FileOffset
= *Offset
;
3151 /* Negative/special offset: it cannot be used in this context */
3152 if(FileOffset
.u
.HighPart
< 0)
3154 KeBugCheck(MEMORY_MANAGEMENT
);
3157 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3158 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3159 FileOffset
.u
.LowPart
= AdjustOffset
;
3161 BufferSize
= Length
+ OffsetAdjustment
;
3162 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3165 * It's ok to use paged pool, because this is a temporary buffer only used in
3166 * the loading of executables. The assumption is that MmCreateSection is
3167 * always called at low IRQLs and that these buffers don't survive a brief
3168 * initialization phase
3170 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3175 KeBugCheck(MEMORY_MANAGEMENT
);
3180 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3182 UsedSize
= (ULONG
)Iosb
.Information
;
3184 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3186 Status
= STATUS_IN_PAGE_ERROR
;
3187 ASSERT(!NT_SUCCESS(Status
));
3190 if(NT_SUCCESS(Status
))
3192 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3193 *AllocBase
= Buffer
;
3194 *ReadSize
= UsedSize
- OffsetAdjustment
;
3198 ExFreePoolWithTag(Buffer
, 'rXmM');
3205 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3206 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3207 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3212 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3216 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3218 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3219 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3226 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3230 MmspAssertSegmentsSorted(ImageSectionObject
);
3232 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3234 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3238 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3239 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3240 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3248 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3252 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3254 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3255 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3263 MmspCompareSegments(const void * x
,
3266 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3267 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3270 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3271 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3275 * Ensures an image section's segments are sorted in memory
3280 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3283 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3285 MmspAssertSegmentsSorted(ImageSectionObject
);
3289 qsort(ImageSectionObject
->Segments
,
3290 ImageSectionObject
->NrSegments
,
3291 sizeof(ImageSectionObject
->Segments
[0]),
3292 MmspCompareSegments
);
3298 * Ensures an image section's segments don't overlap in memory and don't have
3299 * gaps and don't have a null size. We let them map to overlapping file regions,
3300 * though - that's not necessarily an error
3305 MmspCheckSegmentBounds
3307 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3313 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3315 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3319 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3321 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3323 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3331 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3332 * page could be OK (Windows seems to be OK with them), and larger gaps
3333 * could lead to image sections spanning several discontiguous regions
3334 * (NtMapViewOfSection could then refuse to map them, and they could
3335 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3337 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3338 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3339 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3350 * Merges and pads an image section's segments until they all are page-aligned
3351 * and have a size that is a multiple of the page size
3356 MmspPageAlignSegments
3358 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3364 PMM_SECTION_SEGMENT EffectiveSegment
;
3366 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3368 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3373 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3375 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3378 * The first segment requires special handling
3382 ULONG_PTR VirtualAddress
;
3383 ULONG_PTR VirtualOffset
;
3385 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3387 /* Round down the virtual address to the nearest page */
3388 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3390 /* Round up the virtual size to the nearest page */
3391 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3392 EffectiveSegment
->Image
.VirtualAddress
;
3394 /* Adjust the raw address and size */
3395 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3397 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3403 * Garbage in, garbage out: unaligned base addresses make the file
3404 * offset point in curious and odd places, but that's what we were
3407 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3408 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3412 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3413 ULONG_PTR EndOfEffectiveSegment
;
3415 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3416 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3419 * The current segment begins exactly where the current effective
3420 * segment ended, therefore beginning a new effective segment
3422 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3425 ASSERT(LastSegment
<= i
);
3426 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3428 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3430 if (LastSegment
!= i
)
3433 * Copy the current segment. If necessary, the effective segment
3434 * will be expanded later
3436 *EffectiveSegment
= *Segment
;
3440 * Page-align the virtual size. We know for sure the virtual address
3443 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3444 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3447 * The current segment is still part of the current effective segment:
3448 * extend the effective segment to reflect this
3450 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3452 static const ULONG FlagsToProtection
[16] =
3460 PAGE_EXECUTE_READWRITE
,
3461 PAGE_EXECUTE_READWRITE
,
3466 PAGE_EXECUTE_WRITECOPY
,
3467 PAGE_EXECUTE_WRITECOPY
,
3468 PAGE_EXECUTE_WRITECOPY
,
3469 PAGE_EXECUTE_WRITECOPY
3472 unsigned ProtectionFlags
;
3475 * Extend the file size
3478 /* Unaligned segments must be contiguous within the file */
3479 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3480 EffectiveSegment
->RawLength
.QuadPart
))
3485 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3488 * Extend the virtual size
3490 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3492 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3493 EffectiveSegment
->Image
.VirtualAddress
;
3496 * Merge the protection
3498 EffectiveSegment
->Protection
|= Segment
->Protection
;
3500 /* Clean up redundance */
3501 ProtectionFlags
= 0;
3503 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3504 ProtectionFlags
|= 1 << 0;
3506 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3507 ProtectionFlags
|= 1 << 1;
3509 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3510 ProtectionFlags
|= 1 << 2;
3512 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3513 ProtectionFlags
|= 1 << 3;
3515 ASSERT(ProtectionFlags
< 16);
3516 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3518 /* If a segment was required to be shared and cannot, fail */
3519 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3520 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3526 * We assume no holes between segments at this point
3530 KeBugCheck(MEMORY_MANAGEMENT
);
3534 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3540 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3541 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3543 LARGE_INTEGER Offset
;
3545 PVOID FileHeaderBuffer
;
3546 ULONG FileHeaderSize
;
3548 ULONG OldNrSegments
;
3553 * Read the beginning of the file (2 pages). Should be enough to contain
3554 * all (or most) of the headers
3556 Offset
.QuadPart
= 0;
3558 /* FIXME: use FileObject instead of FileHandle */
3559 Status
= ExeFmtpReadFile (FileHandle
,
3566 if (!NT_SUCCESS(Status
))
3569 if (FileHeaderSize
== 0)
3571 ExFreePool(FileHeaderBuffer
);
3572 return STATUS_UNSUCCESSFUL
;
3576 * Look for a loader that can handle this executable
3578 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3580 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3583 /* FIXME: use FileObject instead of FileHandle */
3584 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3590 ExeFmtpAllocateSegments
);
3592 if (!NT_SUCCESS(Status
))
3594 if (ImageSectionObject
->Segments
)
3596 ExFreePool(ImageSectionObject
->Segments
);
3597 ImageSectionObject
->Segments
= NULL
;
3601 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3605 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3608 * No loader handled the format
3610 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3612 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3613 ASSERT(!NT_SUCCESS(Status
));
3616 if (!NT_SUCCESS(Status
))
3619 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3624 /* FIXME? are these values platform-dependent? */
3625 if(ImageSectionObject
->StackReserve
== 0)
3626 ImageSectionObject
->StackReserve
= 0x40000;
3628 if(ImageSectionObject
->StackCommit
== 0)
3629 ImageSectionObject
->StackCommit
= 0x1000;
3631 if(ImageSectionObject
->ImageBase
== 0)
3633 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3634 ImageSectionObject
->ImageBase
= 0x10000000;
3636 ImageSectionObject
->ImageBase
= 0x00400000;
3640 * And now the fun part: fixing the segments
3643 /* Sort them by virtual address */
3644 MmspSortSegments(ImageSectionObject
, Flags
);
3646 /* Ensure they don't overlap in memory */
3647 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3648 return STATUS_INVALID_IMAGE_FORMAT
;
3650 /* Ensure they are aligned */
3651 OldNrSegments
= ImageSectionObject
->NrSegments
;
3653 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3654 return STATUS_INVALID_IMAGE_FORMAT
;
3656 /* Trim them if the alignment phase merged some of them */
3657 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3659 PMM_SECTION_SEGMENT Segments
;
3660 SIZE_T SizeOfSegments
;
3662 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3664 Segments
= ExAllocatePoolWithTag(PagedPool
,
3666 TAG_MM_SECTION_SEGMENT
);
3668 if (Segments
== NULL
)
3669 return STATUS_INSUFFICIENT_RESOURCES
;
3671 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3672 ExFreePool(ImageSectionObject
->Segments
);
3673 ImageSectionObject
->Segments
= Segments
;
3676 /* And finish their initialization */
3677 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3679 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3680 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3681 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3684 ASSERT(NT_SUCCESS(Status
));
3689 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3690 ACCESS_MASK DesiredAccess
,
3691 POBJECT_ATTRIBUTES ObjectAttributes
,
3692 PLARGE_INTEGER UMaximumSize
,
3693 ULONG SectionPageProtection
,
3694 ULONG AllocationAttributes
,
3695 PFILE_OBJECT FileObject
)
3697 PROS_SECTION_OBJECT Section
;
3699 PMM_SECTION_SEGMENT SectionSegments
;
3700 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3703 if (FileObject
== NULL
)
3704 return STATUS_INVALID_FILE_FOR_SECTION
;
3707 * Create the section
3709 Status
= ObCreateObject (ExGetPreviousMode(),
3710 MmSectionObjectType
,
3712 ExGetPreviousMode(),
3714 sizeof(ROS_SECTION_OBJECT
),
3717 (PVOID
*)(PVOID
)&Section
);
3718 if (!NT_SUCCESS(Status
))
3720 ObDereferenceObject(FileObject
);
3727 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3728 Section
->Type
= 'SC';
3729 Section
->Size
= 'TN';
3730 Section
->SectionPageProtection
= SectionPageProtection
;
3731 Section
->AllocationAttributes
= AllocationAttributes
;
3735 * Initialized caching for this file object if previously caching
3736 * was initialized for the same on disk file
3738 Status
= CcTryToInitializeFileCache(FileObject
);
3740 Status
= STATUS_SUCCESS
;
3743 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3745 NTSTATUS StatusExeFmt
;
3747 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3748 if (ImageSectionObject
== NULL
)
3750 ObDereferenceObject(FileObject
);
3751 ObDereferenceObject(Section
);
3752 return(STATUS_NO_MEMORY
);
3755 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3757 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3759 if (!NT_SUCCESS(StatusExeFmt
))
3761 if(ImageSectionObject
->Segments
!= NULL
)
3762 ExFreePool(ImageSectionObject
->Segments
);
3764 ExFreePool(ImageSectionObject
);
3765 ObDereferenceObject(Section
);
3766 ObDereferenceObject(FileObject
);
3767 return(StatusExeFmt
);
3770 Section
->ImageSection
= ImageSectionObject
;
3771 ASSERT(ImageSectionObject
->Segments
);
3776 Status
= MmspWaitForFileLock(FileObject
);
3777 if (!NT_SUCCESS(Status
))
3779 ExFreePool(ImageSectionObject
->Segments
);
3780 ExFreePool(ImageSectionObject
);
3781 ObDereferenceObject(Section
);
3782 ObDereferenceObject(FileObject
);
3786 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3787 ImageSectionObject
, NULL
))
3790 * An other thread has initialized the same image in the background
3792 ExFreePool(ImageSectionObject
->Segments
);
3793 ExFreePool(ImageSectionObject
);
3794 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3795 Section
->ImageSection
= ImageSectionObject
;
3796 SectionSegments
= ImageSectionObject
->Segments
;
3798 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3800 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3804 Status
= StatusExeFmt
;
3811 Status
= MmspWaitForFileLock(FileObject
);
3812 if (Status
!= STATUS_SUCCESS
)
3814 ObDereferenceObject(Section
);
3815 ObDereferenceObject(FileObject
);
3819 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3820 Section
->ImageSection
= ImageSectionObject
;
3821 SectionSegments
= ImageSectionObject
->Segments
;
3824 * Otherwise just reference all the section segments
3826 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3828 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3831 Status
= STATUS_SUCCESS
;
3833 Section
->FileObject
= FileObject
;
3835 CcRosReferenceCache(FileObject
);
3837 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3838 *SectionObject
= Section
;
3845 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3846 PROS_SECTION_OBJECT Section
,
3847 PMM_SECTION_SEGMENT Segment
,
3852 ULONG AllocationType
)
3856 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3858 if (Segment
->WriteCopy
)
3860 /* We have to do this because the not present fault
3861 * and access fault handlers depend on the protection
3862 * that should be granted AFTER the COW fault takes
3863 * place to be in Region->Protect. The not present fault
3864 * handler changes this to the correct protection for COW when
3865 * mapping the pages into the process's address space. If a COW
3866 * fault takes place, the access fault handler sets the page protection
3867 * to these values for the newly copied pages
3869 if (Protect
== PAGE_WRITECOPY
)
3870 Protect
= PAGE_READWRITE
;
3871 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3872 Protect
= PAGE_EXECUTE_READWRITE
;
3875 BoundaryAddressMultiple
.QuadPart
= 0;
3878 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
3879 LARGE_INTEGER FileOffset
;
3880 FileOffset
.QuadPart
= ViewOffset
;
3881 ObReferenceObject(Section
);
3882 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3885 Status
= MmCreateMemoryArea(AddressSpace
,
3886 MEMORY_AREA_SECTION_VIEW
,
3893 BoundaryAddressMultiple
);
3894 if (!NT_SUCCESS(Status
))
3896 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3897 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3901 ObReferenceObject((PVOID
)Section
);
3903 MArea
->Data
.SectionData
.Segment
= Segment
;
3904 MArea
->Data
.SectionData
.Section
= Section
;
3905 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3906 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3907 ViewSize
, 0, Protect
);
3909 return(STATUS_SUCCESS
);
3914 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3915 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3918 PFILE_OBJECT FileObject
;
3920 LARGE_INTEGER Offset
;
3921 SWAPENTRY SavedSwapEntry
;
3922 PROS_SECTION_OBJECT Section
;
3923 PMM_SECTION_SEGMENT Segment
;
3924 PMMSUPPORT AddressSpace
;
3927 AddressSpace
= (PMMSUPPORT
)Context
;
3928 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3930 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3932 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3933 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3935 Section
= MemoryArea
->Data
.SectionData
.Section
;
3936 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3938 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3939 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
3941 MmUnlockSectionSegment(Segment
);
3942 MmUnlockAddressSpace(AddressSpace
);
3944 MiWaitForPageEvent(NULL
, NULL
);
3946 MmLockAddressSpace(AddressSpace
);
3947 MmLockSectionSegment(Segment
);
3948 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3952 * For a dirty, datafile, non-private page mark it as dirty in the
3955 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3957 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3959 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3960 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3962 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)(Offset
.QuadPart
+ Segment
->Image
.FileOffset
));
3964 ASSERT(SwapEntry
== 0);
3973 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3975 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3976 KeBugCheck(MEMORY_MANAGEMENT
);
3978 MmFreeSwapPage(SwapEntry
);
3982 if (IS_SWAP_FROM_SSE(Entry
) ||
3983 Page
!= PFN_FROM_SSE(Entry
))
3988 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3990 DPRINT1("Found a private page in a pagefile section.\n");
3991 KeBugCheck(MEMORY_MANAGEMENT
);
3994 * Just dereference private pages
3996 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3997 if (SavedSwapEntry
!= 0)
3999 MmFreeSwapPage(SavedSwapEntry
);
4000 MmSetSavedSwapEntryPage(Page
, 0);
4002 MmDeleteRmap(Page
, Process
, Address
);
4003 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4007 MmDeleteRmap(Page
, Process
, Address
);
4008 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
4014 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4018 PMEMORY_AREA MemoryArea
;
4019 PROS_SECTION_OBJECT Section
;
4020 PMM_SECTION_SEGMENT Segment
;
4021 PLIST_ENTRY CurrentEntry
;
4022 PMM_REGION CurrentRegion
;
4023 PLIST_ENTRY RegionListHead
;
4025 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4027 if (MemoryArea
== NULL
)
4029 return(STATUS_UNSUCCESSFUL
);
4032 MemoryArea
->DeleteInProgress
= TRUE
;
4033 Section
= MemoryArea
->Data
.SectionData
.Section
;
4034 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4037 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4038 return MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4041 MmLockSectionSegment(Segment
);
4043 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4044 while (!IsListEmpty(RegionListHead
))
4046 CurrentEntry
= RemoveHeadList(RegionListHead
);
4047 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4048 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4051 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4053 Status
= MmFreeMemoryArea(AddressSpace
,
4060 Status
= MmFreeMemoryArea(AddressSpace
,
4065 MmUnlockSectionSegment(Segment
);
4066 ObDereferenceObject(Section
);
4072 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4073 IN PVOID BaseAddress
,
4077 PMEMORY_AREA MemoryArea
;
4078 PMMSUPPORT AddressSpace
;
4079 PROS_SECTION_OBJECT Section
;
4080 PVOID ImageBaseAddress
= 0;
4082 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4083 Process
, BaseAddress
);
4087 AddressSpace
= &Process
->Vm
;
4089 MmLockAddressSpace(AddressSpace
);
4090 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4092 if (MemoryArea
== NULL
||
4093 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4094 MemoryArea
->DeleteInProgress
)
4096 ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4097 MmUnlockAddressSpace(AddressSpace
);
4098 return STATUS_NOT_MAPPED_VIEW
;
4101 MemoryArea
->DeleteInProgress
= TRUE
;
4103 Section
= MemoryArea
->Data
.SectionData
.Section
;
4105 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4109 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4110 PMM_SECTION_SEGMENT SectionSegments
;
4111 PMM_SECTION_SEGMENT Segment
;
4113 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4114 ImageSectionObject
= Section
->ImageSection
;
4115 SectionSegments
= ImageSectionObject
->Segments
;
4116 NrSegments
= ImageSectionObject
->NrSegments
;
4118 /* Search for the current segment within the section segments
4119 * and calculate the image base address */
4120 for (i
= 0; i
< NrSegments
; i
++)
4122 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4124 if (Segment
== &SectionSegments
[i
])
4126 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4131 if (i
>= NrSegments
)
4133 KeBugCheck(MEMORY_MANAGEMENT
);
4136 for (i
= 0; i
< NrSegments
; i
++)
4138 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4140 PVOID SBaseAddress
= (PVOID
)
4141 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4143 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4149 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4152 MmUnlockAddressSpace(AddressSpace
);
4154 /* Notify debugger */
4155 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4157 return(STATUS_SUCCESS
);
4164 * Queries the information of a section object.
4166 * @param SectionHandle
4167 * Handle to the section object. It must be opened with SECTION_QUERY
4169 * @param SectionInformationClass
4170 * Index to a certain information structure. Can be either
4171 * SectionBasicInformation or SectionImageInformation. The latter
4172 * is valid only for sections that were created with the SEC_IMAGE
4174 * @param SectionInformation
4175 * Caller supplies storage for resulting information.
4177 * Size of the supplied storage.
4178 * @param ResultLength
4186 NtQuerySection(IN HANDLE SectionHandle
,
4187 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4188 OUT PVOID SectionInformation
,
4189 IN SIZE_T SectionInformationLength
,
4190 OUT PSIZE_T ResultLength OPTIONAL
)
4192 PROS_SECTION_OBJECT Section
;
4193 KPROCESSOR_MODE PreviousMode
;
4197 PreviousMode
= ExGetPreviousMode();
4199 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4201 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4203 (ULONG
)SectionInformationLength
,
4208 if(!NT_SUCCESS(Status
))
4210 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4214 Status
= ObReferenceObjectByHandle(SectionHandle
,
4216 MmSectionObjectType
,
4218 (PVOID
*)(PVOID
)&Section
,
4220 if (NT_SUCCESS(Status
))
4222 switch (SectionInformationClass
)
4224 case SectionBasicInformation
:
4226 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4230 Sbi
->Attributes
= Section
->AllocationAttributes
;
4231 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4233 Sbi
->BaseAddress
= 0;
4234 Sbi
->Size
.QuadPart
= 0;
4238 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4239 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4242 if (ResultLength
!= NULL
)
4244 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4246 Status
= STATUS_SUCCESS
;
4248 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4250 Status
= _SEH2_GetExceptionCode();
4257 case SectionImageInformation
:
4259 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4263 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4264 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4266 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4267 ImageSectionObject
= Section
->ImageSection
;
4269 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4270 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4271 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4272 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4273 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4274 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4275 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4276 Sii
->Machine
= ImageSectionObject
->Machine
;
4277 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4280 if (ResultLength
!= NULL
)
4282 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4284 Status
= STATUS_SUCCESS
;
4286 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4288 Status
= _SEH2_GetExceptionCode();
4296 ObDereferenceObject(Section
);
4302 /**********************************************************************
4304 * MmMapViewOfSection
4307 * Maps a view of a section into the virtual address space of a
4312 * Pointer to the section object.
4315 * Pointer to the process.
4318 * Desired base address (or NULL) on entry;
4319 * Actual base address of the view on exit.
4322 * Number of high order address bits that must be zero.
4325 * Size in bytes of the initially committed section of
4329 * Offset in bytes from the beginning of the section
4330 * to the beginning of the view.
4333 * Desired length of map (or zero to map all) on entry
4334 * Actual length mapped on exit.
4336 * InheritDisposition
4337 * Specified how the view is to be shared with
4341 * Type of allocation for the pages.
4344 * Protection for the committed region of the view.
4352 MmMapViewOfSection(IN PVOID SectionObject
,
4353 IN PEPROCESS Process
,
4354 IN OUT PVOID
*BaseAddress
,
4355 IN ULONG_PTR ZeroBits
,
4356 IN SIZE_T CommitSize
,
4357 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4358 IN OUT PSIZE_T ViewSize
,
4359 IN SECTION_INHERIT InheritDisposition
,
4360 IN ULONG AllocationType
,
4363 PROS_SECTION_OBJECT Section
;
4364 PMMSUPPORT AddressSpace
;
4366 NTSTATUS Status
= STATUS_SUCCESS
;
4367 BOOLEAN NotAtBase
= FALSE
;
4369 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4371 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4372 return MmMapViewOfArm3Section(SectionObject
,
4386 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4388 return STATUS_INVALID_PAGE_PROTECTION
;
4392 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4393 AddressSpace
= &Process
->Vm
;
4395 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4397 MmLockAddressSpace(AddressSpace
);
4399 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4403 ULONG_PTR ImageBase
;
4405 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4406 PMM_SECTION_SEGMENT SectionSegments
;
4408 ImageSectionObject
= Section
->ImageSection
;
4409 SectionSegments
= ImageSectionObject
->Segments
;
4410 NrSegments
= ImageSectionObject
->NrSegments
;
4413 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4416 ImageBase
= ImageSectionObject
->ImageBase
;
4420 for (i
= 0; i
< NrSegments
; i
++)
4422 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4424 ULONG_PTR MaxExtent
;
4425 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4426 SectionSegments
[i
].Length
.QuadPart
);
4427 ImageSize
= max(ImageSize
, MaxExtent
);
4431 ImageSectionObject
->ImageSize
= (ULONG
)ImageSize
;
4433 /* Check for an illegal base address */
4434 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4436 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4439 /* Check there is enough space to map the section at that point. */
4440 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4441 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4443 /* Fail if the user requested a fixed base address. */
4444 if ((*BaseAddress
) != NULL
)
4446 MmUnlockAddressSpace(AddressSpace
);
4447 return(STATUS_UNSUCCESSFUL
);
4449 /* Otherwise find a gap to map the image. */
4450 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4453 MmUnlockAddressSpace(AddressSpace
);
4454 return(STATUS_UNSUCCESSFUL
);
4456 /* Remember that we loaded image at a different base address */
4460 for (i
= 0; i
< NrSegments
; i
++)
4462 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4464 PVOID SBaseAddress
= (PVOID
)
4465 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4466 MmLockSectionSegment(&SectionSegments
[i
]);
4467 Status
= MmMapViewOfSegment(AddressSpace
,
4469 &SectionSegments
[i
],
4471 SectionSegments
[i
].Length
.LowPart
,
4472 SectionSegments
[i
].Protection
,
4475 MmUnlockSectionSegment(&SectionSegments
[i
]);
4476 if (!NT_SUCCESS(Status
))
4478 MmUnlockAddressSpace(AddressSpace
);
4484 *BaseAddress
= (PVOID
)ImageBase
;
4485 *ViewSize
= ImageSize
;
4489 /* check for write access */
4490 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4491 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4493 MmUnlockAddressSpace(AddressSpace
);
4494 return STATUS_SECTION_PROTECTION
;
4496 /* check for read access */
4497 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4498 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4500 MmUnlockAddressSpace(AddressSpace
);
4501 return STATUS_SECTION_PROTECTION
;
4503 /* check for execute access */
4504 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4505 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4507 MmUnlockAddressSpace(AddressSpace
);
4508 return STATUS_SECTION_PROTECTION
;
4511 if (ViewSize
== NULL
)
4513 /* Following this pointer would lead to us to the dark side */
4514 /* What to do? Bugcheck? Return status? Do the mambo? */
4515 KeBugCheck(MEMORY_MANAGEMENT
);
4518 if (SectionOffset
== NULL
)
4524 ViewOffset
= SectionOffset
->u
.LowPart
;
4527 if ((ViewOffset
% PAGE_SIZE
) != 0)
4529 MmUnlockAddressSpace(AddressSpace
);
4530 return(STATUS_MAPPED_ALIGNMENT
);
4533 if ((*ViewSize
) == 0)
4535 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4537 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4539 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4542 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4544 MmLockSectionSegment(Section
->Segment
);
4545 Status
= MmMapViewOfSegment(AddressSpace
,
4552 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4553 MmUnlockSectionSegment(Section
->Segment
);
4554 if (!NT_SUCCESS(Status
))
4556 MmUnlockAddressSpace(AddressSpace
);
4561 MmUnlockAddressSpace(AddressSpace
);
4564 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4566 Status
= STATUS_SUCCESS
;
4575 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4576 IN PLARGE_INTEGER NewFileSize
)
4578 /* Check whether an ImageSectionObject exists */
4579 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4581 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4585 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4587 PMM_SECTION_SEGMENT Segment
;
4589 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4592 if (Segment
->ReferenceCount
!= 0)
4595 CC_FILE_SIZES FileSizes
;
4597 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4600 /* Check size of file */
4601 if (SectionObjectPointer
->SharedCacheMap
)
4603 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4608 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4617 /* Check size of file */
4618 if (SectionObjectPointer
->SharedCacheMap
)
4620 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4621 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4630 /* Something must gone wrong
4631 * how can we have a Section but no
4633 DPRINT("ERROR: DataSectionObject without reference!\n");
4637 DPRINT("FIXME: didn't check for outstanding write probes\n");
4649 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4650 IN MMFLUSH_TYPE FlushType
)
4652 BOOLEAN Result
= TRUE
;
4654 PMM_SECTION_SEGMENT Segment
;
4659 case MmFlushForDelete
:
4660 if (SectionObjectPointer
->ImageSectionObject
||
4661 SectionObjectPointer
->DataSectionObject
)
4666 CcRosSetRemoveOnClose(SectionObjectPointer
);
4669 case MmFlushForWrite
:
4671 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4673 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4676 if (SectionObjectPointer
->ImageSectionObject
) {
4677 DPRINT1("SectionObject has ImageSection\n");
4683 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4685 DPRINT("Result %d\n", Result
);
4697 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4698 OUT PVOID
* MappedBase
,
4699 IN OUT PSIZE_T ViewSize
)
4701 PROS_SECTION_OBJECT Section
;
4702 PMMSUPPORT AddressSpace
;
4706 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4708 return MiMapViewInSystemSpace(SectionObject
,
4714 DPRINT("MmMapViewInSystemSpace() called\n");
4716 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4717 AddressSpace
= MmGetKernelAddressSpace();
4719 MmLockAddressSpace(AddressSpace
);
4722 if ((*ViewSize
) == 0)
4724 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4726 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4728 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4731 MmLockSectionSegment(Section
->Segment
);
4734 Status
= MmMapViewOfSegment(AddressSpace
,
4743 MmUnlockSectionSegment(Section
->Segment
);
4744 MmUnlockAddressSpace(AddressSpace
);
4751 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4753 PMMSUPPORT AddressSpace
;
4756 DPRINT("MmUnmapViewInSystemSpace() called\n");
4758 AddressSpace
= MmGetKernelAddressSpace();
4760 MmLockAddressSpace(AddressSpace
);
4762 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4764 MmUnlockAddressSpace(AddressSpace
);
4769 /**********************************************************************
4774 * Creates a section object.
4777 * SectionObject (OUT)
4778 * Caller supplied storage for the resulting pointer
4779 * to a SECTION_OBJECT instance;
4782 * Specifies the desired access to the section can be a
4784 * STANDARD_RIGHTS_REQUIRED |
4786 * SECTION_MAP_WRITE |
4787 * SECTION_MAP_READ |
4788 * SECTION_MAP_EXECUTE
4790 * ObjectAttributes [OPTIONAL]
4791 * Initialized attributes for the object can be used
4792 * to create a named section;
4795 * Maximizes the size of the memory section. Must be
4796 * non-NULL for a page-file backed section.
4797 * If value specified for a mapped file and the file is
4798 * not large enough, file will be extended.
4800 * SectionPageProtection
4801 * Can be a combination of:
4807 * AllocationAttributes
4808 * Can be a combination of:
4813 * Handle to a file to create a section mapped to a file
4814 * instead of a memory backed section;
4825 MmCreateSection (OUT PVOID
* Section
,
4826 IN ACCESS_MASK DesiredAccess
,
4827 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4828 IN PLARGE_INTEGER MaximumSize
,
4829 IN ULONG SectionPageProtection
,
4830 IN ULONG AllocationAttributes
,
4831 IN HANDLE FileHandle OPTIONAL
,
4832 IN PFILE_OBJECT FileObject OPTIONAL
)
4835 ULONG Protection
, FileAccess
;
4836 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4838 /* Check if an ARM3 section is being created instead */
4839 if (AllocationAttributes
& 1)
4841 DPRINT1("Creating ARM3 section\n");
4842 return MmCreateArm3Section(Section
,
4846 SectionPageProtection
,
4847 AllocationAttributes
&~ 1,
4853 * Check the protection
4855 Protection
= SectionPageProtection
& ~(PAGE_GUARD
| PAGE_NOCACHE
);
4856 if (Protection
!= PAGE_READONLY
&&
4857 Protection
!= PAGE_READWRITE
&&
4858 Protection
!= PAGE_WRITECOPY
&&
4859 Protection
!= PAGE_EXECUTE
&&
4860 Protection
!= PAGE_EXECUTE_READ
&&
4861 Protection
!= PAGE_EXECUTE_READWRITE
&&
4862 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4864 return STATUS_INVALID_PAGE_PROTECTION
;
4867 if ((DesiredAccess
& SECTION_MAP_WRITE
) &&
4868 (Protection
== PAGE_READWRITE
||
4869 Protection
== PAGE_EXECUTE_READWRITE
) &&
4870 !(AllocationAttributes
& SEC_IMAGE
))
4872 DPRINT("Creating a section with WRITE access\n");
4873 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
| SYNCHRONIZE
;
4877 DPRINT("Creating a section with READ access\n");
4878 FileAccess
= FILE_READ_DATA
| SYNCHRONIZE
;
4881 /* FIXME: somehow combine this with the above checks */
4882 if (AllocationAttributes
& SEC_IMAGE
)
4883 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
4885 if (!FileObject
&& FileHandle
)
4887 Status
= ObReferenceObjectByHandle(FileHandle
,
4890 ExGetPreviousMode(),
4891 (PVOID
*)&FileObject
,
4893 if (!NT_SUCCESS(Status
))
4895 DPRINT("Failed: 0x%08lx\n", Status
);
4899 else if (FileObject
)
4900 ObReferenceObject(FileObject
);
4902 #ifndef NEWCC // A hack for initializing caching.
4903 // This is needed only in the old case.
4906 IO_STATUS_BLOCK Iosb
;
4909 LARGE_INTEGER ByteOffset
;
4910 ByteOffset
.QuadPart
= 0;
4911 Status
= ZwReadFile(FileHandle
,
4920 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
4922 // Caching is initialized...
4926 if (AllocationAttributes
& SEC_IMAGE
)
4928 Status
= MmCreateImageSection(SectionObject
,
4932 SectionPageProtection
,
4933 AllocationAttributes
,
4937 else if (FileHandle
!= NULL
)
4939 Status
= MmCreateDataFileSection(SectionObject
,
4943 SectionPageProtection
,
4944 AllocationAttributes
,
4947 ObDereferenceObject(FileObject
);
4950 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
4952 Status
= MmCreateCacheSection(SectionObject
,
4956 SectionPageProtection
,
4957 AllocationAttributes
,
4963 Status
= MmCreatePageFileSection(SectionObject
,
4967 SectionPageProtection
,
4968 AllocationAttributes
);
4975 MmModifyAttributes(IN PMMSUPPORT AddressSpace
,
4976 IN PVOID BaseAddress
,
4977 IN SIZE_T RegionSize
,
4979 IN ULONG OldProtect
,
4981 IN ULONG NewProtect
)
4984 // This function is deprecated but remains in order to support VirtualAlloc
4985 // calls with MEM_COMMIT on top of MapViewOfFile calls with SEC_RESERVE.
4987 // Win32k's shared user heap, for example, uses that mechanism. The two
4988 // conditions when this function needs to do something are ASSERTed for,
4989 // because they should not arise.
4991 if (NewType
== MEM_RESERVE
&& OldType
== MEM_COMMIT
)
4996 if ((NewType
== MEM_COMMIT
) && (OldType
== MEM_COMMIT
))
4998 ASSERT(OldProtect
== NewProtect
);
5004 MiRosAllocateVirtualMemory(IN HANDLE ProcessHandle
,
5005 IN PEPROCESS Process
,
5006 IN PMEMORY_AREA MemoryArea
,
5007 IN PMMSUPPORT AddressSpace
,
5008 IN OUT PVOID
* UBaseAddress
,
5009 IN BOOLEAN Attached
,
5010 IN OUT PSIZE_T URegionSize
,
5011 IN ULONG AllocationType
,
5014 ULONG_PTR PRegionSize
;
5015 ULONG Type
, RegionSize
;
5017 PVOID PBaseAddress
, BaseAddress
;
5018 KAPC_STATE ApcState
;
5020 PBaseAddress
= *UBaseAddress
;
5021 PRegionSize
= *URegionSize
;
5023 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(PBaseAddress
);
5024 RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)PBaseAddress
+ PRegionSize
) -
5025 PAGE_ROUND_DOWN(PBaseAddress
);
5026 Type
= (AllocationType
& MEM_COMMIT
) ? MEM_COMMIT
: MEM_RESERVE
;
5028 ASSERT(PBaseAddress
!= 0);
5029 ASSERT(Type
== MEM_COMMIT
);
5030 ASSERT(MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
);
5031 ASSERT(((ULONG_PTR
)BaseAddress
+ RegionSize
) <= (ULONG_PTR
)MemoryArea
->EndingAddress
);
5032 ASSERT(((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
) >= RegionSize
);
5033 ASSERT(MemoryArea
->Data
.SectionData
.RegionListHead
.Flink
);
5035 Status
= MmAlterRegion(AddressSpace
,
5036 MemoryArea
->StartingAddress
,
5037 &MemoryArea
->Data
.SectionData
.RegionListHead
,
5042 MmModifyAttributes
);
5044 MmUnlockAddressSpace(AddressSpace
);
5045 if (Attached
) KeUnstackDetachProcess(&ApcState
);
5046 if (ProcessHandle
!= NtCurrentProcess()) ObDereferenceObject(Process
);
5047 if (NT_SUCCESS(Status
))
5049 *UBaseAddress
= BaseAddress
;
5050 *URegionSize
= RegionSize
;
5058 MiRosProtectVirtualMemory(IN PEPROCESS Process
,
5059 IN OUT PVOID
*BaseAddress
,
5060 IN OUT PSIZE_T NumberOfBytesToProtect
,
5061 IN ULONG NewAccessProtection
,
5062 OUT PULONG OldAccessProtection OPTIONAL
)
5064 PMEMORY_AREA MemoryArea
;
5065 PMMSUPPORT AddressSpace
;
5066 ULONG OldAccessProtection_
;
5069 *NumberOfBytesToProtect
= PAGE_ROUND_UP((ULONG_PTR
)(*BaseAddress
) + (*NumberOfBytesToProtect
)) - PAGE_ROUND_DOWN(*BaseAddress
);
5070 *BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(*BaseAddress
);
5072 AddressSpace
= &Process
->Vm
;
5073 MmLockAddressSpace(AddressSpace
);
5074 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, *BaseAddress
);
5075 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
5077 MmUnlockAddressSpace(AddressSpace
);
5078 return STATUS_UNSUCCESSFUL
;
5081 if (OldAccessProtection
== NULL
) OldAccessProtection
= &OldAccessProtection_
;
5083 if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
5085 Status
= MmProtectSectionView(AddressSpace
,
5088 *NumberOfBytesToProtect
,
5089 NewAccessProtection
,
5090 OldAccessProtection
);
5094 /* FIXME: Should we return failure or success in this case? */
5095 Status
= STATUS_CONFLICTING_ADDRESSES
;
5098 MmUnlockAddressSpace(AddressSpace
);