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
, PVOID SourceAddress
)
968 ASSERT((ULONG_PTR
)SourceAddress
% PAGE_SIZE
== 0);
969 Process
= PsGetCurrentProcess();
970 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
971 if (TempAddress
== NULL
)
973 return(STATUS_NO_MEMORY
);
975 ASSERT((ULONG_PTR
)TempAddress
% PAGE_SIZE
== 0);
976 RtlCopyMemory(TempAddress
, SourceAddress
, PAGE_SIZE
);
977 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
978 return(STATUS_SUCCESS
);
984 MiReadPage(PMEMORY_AREA MemoryArea
,
988 * FUNCTION: Read a page for a section backed memory area.
990 * MemoryArea - Memory area to read the page for.
991 * Offset - Offset of the page to read.
992 * Page - Variable that receives a page contains the read data.
996 ULONGLONG FileOffset
;
999 PCACHE_SEGMENT CacheSeg
;
1000 PFILE_OBJECT FileObject
;
1002 ULONG_PTR RawLength
;
1004 BOOLEAN IsImageSection
;
1007 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1008 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1009 RawLength
= (ULONG_PTR
)(MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
);
1010 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1011 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1015 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1018 * If the file system is letting us go directly to the cache and the
1019 * memory area was mapped at an offset in the file which is page aligned
1020 * then get the related cache segment.
1022 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1023 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1024 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1028 * Get the related cache segment; we use a lower level interface than
1029 * filesystems do because it is safe for us to use an offset with a
1030 * alignment less than the file system block size.
1032 Status
= CcRosGetCacheSegment(Bcb
,
1038 if (!NT_SUCCESS(Status
))
1045 * If the cache segment isn't up to date then call the file
1046 * system to read in the data.
1048 Status
= ReadCacheSegment(CacheSeg
);
1049 if (!NT_SUCCESS(Status
))
1051 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1056 * Retrieve the page from the cache segment that we actually want.
1058 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1059 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1061 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1068 ULONG_PTR CacheSegOffset
;
1071 * Allocate a page, this is rather complicated by the possibility
1072 * we might have to move other things out of memory
1074 MI_SET_USAGE(MI_USAGE_SECTION
);
1075 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1076 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1077 if (!NT_SUCCESS(Status
))
1081 Status
= CcRosGetCacheSegment(Bcb
,
1087 if (!NT_SUCCESS(Status
))
1094 * If the cache segment isn't up to date then call the file
1095 * system to read in the data.
1097 Status
= ReadCacheSegment(CacheSeg
);
1098 if (!NT_SUCCESS(Status
))
1100 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1105 Process
= PsGetCurrentProcess();
1106 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1107 CacheSegOffset
= (ULONG_PTR
)(BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
);
1108 Length
= RawLength
- SegOffset
;
1109 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1111 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1113 else if (CacheSegOffset
>= PAGE_SIZE
)
1115 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1119 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1120 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1121 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1122 Status
= CcRosGetCacheSegment(Bcb
,
1123 (ULONG
)(FileOffset
+ CacheSegOffset
),
1128 if (!NT_SUCCESS(Status
))
1135 * If the cache segment isn't up to date then call the file
1136 * system to read in the data.
1138 Status
= ReadCacheSegment(CacheSeg
);
1139 if (!NT_SUCCESS(Status
))
1141 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1145 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1146 if (Length
< PAGE_SIZE
)
1148 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1152 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1155 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1156 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1158 return(STATUS_SUCCESS
);
1163 MiReadPage(PMEMORY_AREA MemoryArea
,
1167 * FUNCTION: Read a page for a section backed memory area.
1169 * MemoryArea - Memory area to read the page for.
1170 * Offset - Offset of the page to read.
1171 * Page - Variable that receives a page contains the read data.
1174 MM_REQUIRED_RESOURCES Resources
;
1177 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1179 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1180 Resources
.FileOffset
.QuadPart
= SegOffset
+
1181 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1182 Resources
.Consumer
= MC_USER
;
1183 Resources
.Amount
= PAGE_SIZE
;
1185 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]);
1187 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1188 *Page
= Resources
.Page
[0];
1195 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1196 MEMORY_AREA
* MemoryArea
,
1200 LARGE_INTEGER Offset
;
1203 PROS_SECTION_OBJECT Section
;
1204 PMM_SECTION_SEGMENT Segment
;
1209 BOOLEAN HasSwapEntry
;
1211 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1214 * There is a window between taking the page fault and locking the
1215 * address space when another thread could load the page so we check
1218 if (MmIsPagePresent(Process
, Address
))
1220 return(STATUS_SUCCESS
);
1224 * Check for the virtual memory area being deleted.
1226 if (MemoryArea
->DeleteInProgress
)
1228 return(STATUS_UNSUCCESSFUL
);
1231 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1232 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1233 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1235 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1236 Section
= MemoryArea
->Data
.SectionData
.Section
;
1237 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1238 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1240 ASSERT(Region
!= NULL
);
1244 MmLockSectionSegment(Segment
);
1245 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1247 * Check if this page needs to be mapped COW
1249 if ((Segment
->WriteCopy
) &&
1250 (Region
->Protect
== PAGE_READWRITE
||
1251 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1253 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1257 Attributes
= Region
->Protect
;
1261 * Check if someone else is already handling this fault, if so wait
1264 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
1266 MmUnlockSectionSegment(Segment
);
1267 MmUnlockAddressSpace(AddressSpace
);
1268 MiWaitForPageEvent(NULL
, NULL
);
1269 MmLockAddressSpace(AddressSpace
);
1270 DPRINT("Address 0x%.8X\n", Address
);
1271 return(STATUS_MM_RESTART_OPERATION
);
1274 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1278 SWAPENTRY SwapEntry
;
1280 * Is it a wait entry?
1282 MmGetPageFileMapping(Process
, Address
, &SwapEntry
);
1284 if (SwapEntry
== MM_WAIT_ENTRY
)
1286 MmUnlockSectionSegment(Segment
);
1287 MmUnlockAddressSpace(AddressSpace
);
1288 MiWaitForPageEvent(NULL
, NULL
);
1289 MmLockAddressSpace(AddressSpace
);
1290 return STATUS_MM_RESTART_OPERATION
;
1294 * Must be private page we have swapped out.
1300 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1302 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1303 KeBugCheck(MEMORY_MANAGEMENT
);
1306 MmUnlockSectionSegment(Segment
);
1307 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1309 MmUnlockAddressSpace(AddressSpace
);
1310 MI_SET_USAGE(MI_USAGE_SECTION
);
1311 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1312 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1313 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1314 if (!NT_SUCCESS(Status
))
1316 KeBugCheck(MEMORY_MANAGEMENT
);
1319 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1320 if (!NT_SUCCESS(Status
))
1322 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1323 KeBugCheck(MEMORY_MANAGEMENT
);
1325 MmLockAddressSpace(AddressSpace
);
1326 Status
= MmCreateVirtualMapping(Process
,
1331 if (!NT_SUCCESS(Status
))
1333 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1334 KeBugCheck(MEMORY_MANAGEMENT
);
1339 * Store the swap entry for later use.
1341 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1344 * Add the page to the process's working set
1346 MmInsertRmap(Page
, Process
, Address
);
1348 * Finish the operation
1350 MiSetPageEvent(Process
, Address
);
1351 DPRINT("Address 0x%.8X\n", Address
);
1352 return(STATUS_SUCCESS
);
1356 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1358 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1360 MmUnlockSectionSegment(Segment
);
1362 * Just map the desired physical page
1364 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1365 Status
= MmCreateVirtualMappingUnsafe(Process
,
1370 if (!NT_SUCCESS(Status
))
1372 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1373 KeBugCheck(MEMORY_MANAGEMENT
);
1378 * Cleanup and release locks
1380 MiSetPageEvent(Process
, Address
);
1381 DPRINT("Address 0x%.8X\n", Address
);
1382 return(STATUS_SUCCESS
);
1386 * Map anonymous memory for BSS sections
1388 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1390 MmUnlockSectionSegment(Segment
);
1391 MI_SET_USAGE(MI_USAGE_SECTION
);
1392 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1393 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1394 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1395 if (!NT_SUCCESS(Status
))
1397 MmUnlockAddressSpace(AddressSpace
);
1398 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1399 MmLockAddressSpace(AddressSpace
);
1401 if (!NT_SUCCESS(Status
))
1403 KeBugCheck(MEMORY_MANAGEMENT
);
1405 Status
= MmCreateVirtualMapping(Process
,
1410 if (!NT_SUCCESS(Status
))
1412 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1413 KeBugCheck(MEMORY_MANAGEMENT
);
1416 MmInsertRmap(Page
, Process
, Address
);
1419 * Cleanup and release locks
1421 MiSetPageEvent(Process
, Address
);
1422 DPRINT("Address 0x%.8X\n", Address
);
1423 return(STATUS_SUCCESS
);
1427 * Get the entry corresponding to the offset within the section
1429 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1434 * If the entry is zero (and it can't change because we have
1435 * locked the segment) then we need to load the page.
1439 * Release all our locks and read in the page from disk
1441 MmSetPageEntrySectionSegment(Segment
, &Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
1442 MmUnlockSectionSegment(Segment
);
1443 MmUnlockAddressSpace(AddressSpace
);
1445 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1446 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1447 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1449 MI_SET_USAGE(MI_USAGE_SECTION
);
1450 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1451 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1452 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1453 if (!NT_SUCCESS(Status
))
1455 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1461 Status
= MiReadPage(MemoryArea
, (ULONG_PTR
)Offset
.QuadPart
, &Page
);
1462 if (!NT_SUCCESS(Status
))
1464 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1467 if (!NT_SUCCESS(Status
))
1470 * FIXME: What do we know in this case?
1473 * Cleanup and release locks
1475 MmLockAddressSpace(AddressSpace
);
1476 MiSetPageEvent(Process
, Address
);
1477 DPRINT("Address 0x%.8X\n", Address
);
1482 * Mark the offset within the section as having valid, in-memory
1485 MmLockAddressSpace(AddressSpace
);
1486 MmLockSectionSegment(Segment
);
1487 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1488 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1489 MmUnlockSectionSegment(Segment
);
1491 Status
= MmCreateVirtualMapping(Process
,
1496 if (!NT_SUCCESS(Status
))
1498 DPRINT1("Unable to create virtual mapping\n");
1499 KeBugCheck(MEMORY_MANAGEMENT
);
1501 MmInsertRmap(Page
, Process
, Address
);
1503 MiSetPageEvent(Process
, Address
);
1504 DPRINT("Address 0x%.8X\n", Address
);
1505 return(STATUS_SUCCESS
);
1507 else if (IS_SWAP_FROM_SSE(Entry
))
1509 SWAPENTRY SwapEntry
;
1511 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1514 * Release all our locks and read in the page from disk
1516 MmUnlockSectionSegment(Segment
);
1518 MmUnlockAddressSpace(AddressSpace
);
1519 MI_SET_USAGE(MI_USAGE_SECTION
);
1520 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1521 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1522 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1523 if (!NT_SUCCESS(Status
))
1525 KeBugCheck(MEMORY_MANAGEMENT
);
1528 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1529 if (!NT_SUCCESS(Status
))
1531 KeBugCheck(MEMORY_MANAGEMENT
);
1535 * Relock the address space and segment
1537 MmLockAddressSpace(AddressSpace
);
1538 MmLockSectionSegment(Segment
);
1541 * Check the entry. No one should change the status of a page
1542 * that has a pending page-in.
1544 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1545 if (Entry
!= Entry1
)
1547 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry
, Entry1
);
1548 KeBugCheck(MEMORY_MANAGEMENT
);
1552 * Mark the offset within the section as having valid, in-memory
1555 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1556 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1557 MmUnlockSectionSegment(Segment
);
1560 * Save the swap entry.
1562 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1563 Status
= MmCreateVirtualMapping(Process
,
1568 if (!NT_SUCCESS(Status
))
1570 DPRINT1("Unable to create virtual mapping\n");
1571 KeBugCheck(MEMORY_MANAGEMENT
);
1573 MmInsertRmap(Page
, Process
, Address
);
1574 MiSetPageEvent(Process
, Address
);
1575 DPRINT("Address 0x%.8X\n", Address
);
1576 return(STATUS_SUCCESS
);
1581 * If the section offset is already in-memory and valid then just
1582 * take another reference to the page
1585 Page
= PFN_FROM_SSE(Entry
);
1587 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1588 MmUnlockSectionSegment(Segment
);
1590 Status
= MmCreateVirtualMapping(Process
,
1595 if (!NT_SUCCESS(Status
))
1597 DPRINT1("Unable to create virtual mapping\n");
1598 KeBugCheck(MEMORY_MANAGEMENT
);
1600 MmInsertRmap(Page
, Process
, Address
);
1601 MiSetPageEvent(Process
, Address
);
1602 DPRINT("Address 0x%.8X\n", Address
);
1603 return(STATUS_SUCCESS
);
1609 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1610 MEMORY_AREA
* MemoryArea
,
1613 PMM_SECTION_SEGMENT Segment
;
1614 PROS_SECTION_OBJECT Section
;
1619 LARGE_INTEGER Offset
;
1622 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1624 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
);
1627 * Check if the page has already been set readwrite
1629 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1631 DPRINT("Address 0x%.8X\n", Address
);
1632 return(STATUS_SUCCESS
);
1636 * Find the offset of the page
1638 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1639 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1640 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1642 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1643 Section
= MemoryArea
->Data
.SectionData
.Section
;
1644 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1645 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1647 ASSERT(Region
!= NULL
);
1651 MmLockSectionSegment(Segment
);
1653 OldPage
= MmGetPfnForProcess(Process
, Address
);
1654 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1656 MmUnlockSectionSegment(Segment
);
1659 * Check if we are doing COW
1661 if (!((Segment
->WriteCopy
) &&
1662 (Region
->Protect
== PAGE_READWRITE
||
1663 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1665 DPRINT("Address 0x%.8X\n", Address
);
1666 return(STATUS_ACCESS_VIOLATION
);
1669 if (IS_SWAP_FROM_SSE(Entry
) ||
1670 PFN_FROM_SSE(Entry
) != OldPage
)
1672 /* This is a private page. We must only change the page protection. */
1673 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1674 return(STATUS_SUCCESS
);
1678 DPRINT("OldPage == 0!\n");
1681 * Get or create a pageop
1683 MmLockSectionSegment(Segment
);
1684 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1687 * Wait for any other operations to complete
1689 if (Entry
== SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY
))
1691 MmUnlockSectionSegment(Segment
);
1692 MmUnlockAddressSpace(AddressSpace
);
1693 MiWaitForPageEvent(NULL
, NULL
);
1695 * Restart the operation
1697 MmLockAddressSpace(AddressSpace
);
1698 DPRINT("Address 0x%.8X\n", Address
);
1699 return(STATUS_MM_RESTART_OPERATION
);
1703 * Release locks now we have the pageop
1705 MmUnlockSectionSegment(Segment
);
1706 MmUnlockAddressSpace(AddressSpace
);
1711 MI_SET_USAGE(MI_USAGE_SECTION
);
1712 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1713 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1714 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1715 if (!NT_SUCCESS(Status
))
1717 KeBugCheck(MEMORY_MANAGEMENT
);
1723 MiCopyFromUserPage(NewPage
, PAddress
);
1725 MmLockAddressSpace(AddressSpace
);
1727 * Delete the old entry.
1729 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1732 * Set the PTE to point to the new page
1734 Status
= MmCreateVirtualMapping(Process
,
1739 if (!NT_SUCCESS(Status
))
1741 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1742 KeBugCheck(MEMORY_MANAGEMENT
);
1745 if (!NT_SUCCESS(Status
))
1747 DPRINT1("Unable to create virtual mapping\n");
1748 KeBugCheck(MEMORY_MANAGEMENT
);
1752 * Unshare the old page.
1754 MmDeleteRmap(OldPage
, Process
, PAddress
);
1755 MmInsertRmap(NewPage
, Process
, PAddress
);
1756 MmLockSectionSegment(Segment
);
1757 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
, NULL
);
1758 MmUnlockSectionSegment(Segment
);
1760 MiSetPageEvent(Process
, Address
);
1761 DPRINT("Address 0x%.8X\n", Address
);
1762 return(STATUS_SUCCESS
);
1766 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1768 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1770 PFN_NUMBER Page
= 0;
1772 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1775 MmLockAddressSpace(&Process
->Vm
);
1778 MmDeleteVirtualMapping(Process
,
1785 PageOutContext
->WasDirty
= TRUE
;
1787 if (!PageOutContext
->Private
)
1789 MmLockSectionSegment(PageOutContext
->Segment
);
1790 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1791 PageOutContext
->Segment
,
1792 &PageOutContext
->Offset
,
1793 PageOutContext
->WasDirty
,
1795 &PageOutContext
->SectionEntry
);
1796 MmUnlockSectionSegment(PageOutContext
->Segment
);
1800 MmUnlockAddressSpace(&Process
->Vm
);
1803 if (PageOutContext
->Private
)
1805 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1811 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1812 MEMORY_AREA
* MemoryArea
,
1813 PVOID Address
, ULONG_PTR Entry
)
1816 MM_SECTION_PAGEOUT_CONTEXT Context
;
1817 SWAPENTRY SwapEntry
;
1818 ULONGLONG FileOffset
;
1820 PFILE_OBJECT FileObject
;
1824 BOOLEAN DirectMapped
;
1825 BOOLEAN IsImageSection
;
1826 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1829 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1832 * Get the segment and section.
1834 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1835 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1836 Context
.SectionEntry
= Entry
;
1837 Context
.CallingProcess
= Process
;
1839 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1840 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1841 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1843 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1845 FileObject
= Context
.Section
->FileObject
;
1846 DirectMapped
= FALSE
;
1848 MmLockSectionSegment(Context
.Segment
);
1851 if (FileObject
!= NULL
&&
1852 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1854 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1857 * If the file system is letting us go directly to the cache and the
1858 * memory area was mapped at an offset in the file which is page aligned
1859 * then note this is a direct mapped page.
1861 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1862 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
1864 DirectMapped
= TRUE
;
1871 * This should never happen since mappings of physical memory are never
1872 * placed in the rmap lists.
1874 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1876 DPRINT1("Trying to page out from physical memory section address 0x%X "
1877 "process %d\n", Address
,
1878 Process
? Process
->UniqueProcessId
: 0);
1879 KeBugCheck(MEMORY_MANAGEMENT
);
1883 * Get the section segment entry and the physical address.
1885 if (!MmIsPagePresent(Process
, Address
))
1887 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1888 Process
? Process
->UniqueProcessId
: 0, Address
);
1889 KeBugCheck(MEMORY_MANAGEMENT
);
1891 Page
= MmGetPfnForProcess(Process
, Address
);
1892 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1895 * Check the reference count to ensure this page can be paged out
1897 if (MmGetReferenceCountPage(Page
) != 1)
1899 DPRINT("Cannot page out locked section page: 0x%p (RefCount: %d)\n",
1900 Page
, MmGetReferenceCountPage(Page
));
1901 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
1902 MmUnlockSectionSegment(Context
.Segment
);
1903 return STATUS_UNSUCCESSFUL
;
1907 * Prepare the context structure for the rmap delete call.
1909 MmUnlockSectionSegment(Context
.Segment
);
1910 Context
.WasDirty
= FALSE
;
1911 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1912 IS_SWAP_FROM_SSE(Entry
) ||
1913 PFN_FROM_SSE(Entry
) != Page
)
1915 Context
.Private
= TRUE
;
1919 Context
.Private
= FALSE
;
1923 * Take an additional reference to the page or the cache segment.
1925 if (DirectMapped
&& !Context
.Private
)
1927 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
1929 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1930 KeBugCheck(MEMORY_MANAGEMENT
);
1935 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1936 MmReferencePage(Page
);
1937 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1940 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1942 /* Since we passed in a surrogate, we'll get back the page entry
1943 * state in our context. This is intended to make intermediate
1944 * decrements of share count not release the wait entry.
1946 Entry
= Context
.SectionEntry
;
1949 * If this wasn't a private page then we should have reduced the entry to
1950 * zero by deleting all the rmaps.
1952 if (!Context
.Private
&& Entry
!= 0)
1954 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1955 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1957 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
1962 * If the page wasn't dirty then we can just free it as for a readonly page.
1963 * Since we unmapped all the mappings above we know it will not suddenly
1965 * If the page is from a pagefile section and has no swap entry,
1966 * we can't free the page at this point.
1968 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1969 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1971 if (Context
.Private
)
1973 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1974 Context
.WasDirty
? "dirty" : "clean", Address
);
1975 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
1977 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1979 MmSetSavedSwapEntryPage(Page
, 0);
1980 MmLockSectionSegment(Context
.Segment
);
1981 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1982 MmUnlockSectionSegment(Context
.Segment
);
1983 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1984 MiSetPageEvent(NULL
, NULL
);
1985 return(STATUS_SUCCESS
);
1988 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
1990 if (Context
.Private
)
1992 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1993 Context
.WasDirty
? "dirty" : "clean", Address
);
1994 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
1996 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1998 MmSetSavedSwapEntryPage(Page
, 0);
2001 MmLockSectionSegment(Context
.Segment
);
2002 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2003 MmUnlockSectionSegment(Context
.Segment
);
2005 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2006 MiSetPageEvent(NULL
, NULL
);
2007 return(STATUS_SUCCESS
);
2010 else if (!Context
.Private
&& DirectMapped
)
2014 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2016 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2019 Status
= CcRosUnmapCacheSegment(Bcb
, (ULONG
)FileOffset
, FALSE
);
2021 Status
= STATUS_SUCCESS
;
2024 if (!NT_SUCCESS(Status
))
2026 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2027 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Bcb
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2030 MiSetPageEvent(NULL
, NULL
);
2031 return(STATUS_SUCCESS
);
2033 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2037 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2039 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2041 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2042 MiSetPageEvent(NULL
, NULL
);
2043 return(STATUS_SUCCESS
);
2045 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2047 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2048 MmSetSavedSwapEntryPage(Page
, 0);
2049 MmLockAddressSpace(AddressSpace
);
2050 Status
= MmCreatePageFileMapping(Process
,
2053 MmUnlockAddressSpace(AddressSpace
);
2054 if (!NT_SUCCESS(Status
))
2056 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2057 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2059 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2060 MiSetPageEvent(NULL
, NULL
);
2061 return(STATUS_SUCCESS
);
2065 * If necessary, allocate an entry in the paging file for this page
2069 SwapEntry
= MmAllocSwapPage();
2072 MmShowOutOfSpaceMessagePagingFile();
2073 MmLockAddressSpace(AddressSpace
);
2075 * For private pages restore the old mappings.
2077 if (Context
.Private
)
2079 Status
= MmCreateVirtualMapping(Process
,
2081 MemoryArea
->Protect
,
2084 MmSetDirtyPage(Process
, Address
);
2093 * For non-private pages if the page wasn't direct mapped then
2094 * set it back into the section segment entry so we don't loose
2095 * our copy. Otherwise it will be handled by the cache manager.
2097 Status
= MmCreateVirtualMapping(Process
,
2099 MemoryArea
->Protect
,
2102 MmSetDirtyPage(Process
, Address
);
2106 // If we got here, the previous entry should have been a wait
2107 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2108 MmLockSectionSegment(Context
.Segment
);
2109 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2110 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2111 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2112 MmUnlockSectionSegment(Context
.Segment
);
2114 MmUnlockAddressSpace(AddressSpace
);
2115 MiSetPageEvent(NULL
, NULL
);
2116 return(STATUS_PAGEFILE_QUOTA
);
2121 * Write the page to the pagefile
2123 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2124 if (!NT_SUCCESS(Status
))
2126 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2129 * As above: undo our actions.
2130 * FIXME: Also free the swap page.
2132 MmLockAddressSpace(AddressSpace
);
2133 if (Context
.Private
)
2135 Status
= MmCreateVirtualMapping(Process
,
2137 MemoryArea
->Protect
,
2140 MmSetDirtyPage(Process
, Address
);
2147 Status
= MmCreateVirtualMapping(Process
,
2149 MemoryArea
->Protect
,
2152 MmSetDirtyPage(Process
, Address
);
2156 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2157 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2159 MmUnlockAddressSpace(AddressSpace
);
2160 MiSetPageEvent(NULL
, NULL
);
2161 return(STATUS_UNSUCCESSFUL
);
2165 * Otherwise we have succeeded.
2167 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2168 MmSetSavedSwapEntryPage(Page
, 0);
2169 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2170 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2172 MmLockSectionSegment(Context
.Segment
);
2173 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2174 MmUnlockSectionSegment(Context
.Segment
);
2178 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2181 if (Context
.Private
)
2183 MmLockAddressSpace(AddressSpace
);
2184 MmLockSectionSegment(Context
.Segment
);
2185 Status
= MmCreatePageFileMapping(Process
,
2188 MmUnlockSectionSegment(Context
.Segment
);
2189 MmUnlockAddressSpace(AddressSpace
);
2190 if (!NT_SUCCESS(Status
))
2192 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2193 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2198 MmLockAddressSpace(AddressSpace
);
2199 MmLockSectionSegment(Context
.Segment
);
2200 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2201 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2202 MmUnlockSectionSegment(Context
.Segment
);
2203 MmUnlockAddressSpace(AddressSpace
);
2206 MiSetPageEvent(NULL
, NULL
);
2207 return(STATUS_SUCCESS
);
2212 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2213 PMEMORY_AREA MemoryArea
,
2217 LARGE_INTEGER Offset
;
2218 PROS_SECTION_OBJECT Section
;
2219 PMM_SECTION_SEGMENT Segment
;
2221 SWAPENTRY SwapEntry
;
2225 PFILE_OBJECT FileObject
;
2227 BOOLEAN DirectMapped
;
2228 BOOLEAN IsImageSection
;
2229 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2231 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2233 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2234 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2237 * Get the segment and section.
2239 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2240 Section
= MemoryArea
->Data
.SectionData
.Section
;
2241 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2243 FileObject
= Section
->FileObject
;
2244 DirectMapped
= FALSE
;
2245 if (FileObject
!= NULL
&&
2246 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2248 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2251 * If the file system is letting us go directly to the cache and the
2252 * memory area was mapped at an offset in the file which is page aligned
2253 * then note this is a direct mapped page.
2255 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2256 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2258 DirectMapped
= TRUE
;
2263 * This should never happen since mappings of physical memory are never
2264 * placed in the rmap lists.
2266 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2268 DPRINT1("Trying to write back page from physical memory mapped at %X "
2269 "process %d\n", Address
,
2270 Process
? Process
->UniqueProcessId
: 0);
2271 KeBugCheck(MEMORY_MANAGEMENT
);
2275 * Get the section segment entry and the physical address.
2277 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2278 if (!MmIsPagePresent(Process
, Address
))
2280 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2281 Process
? Process
->UniqueProcessId
: 0, Address
);
2282 KeBugCheck(MEMORY_MANAGEMENT
);
2284 Page
= MmGetPfnForProcess(Process
, Address
);
2285 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2288 * Check for a private (COWed) page.
2290 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2291 IS_SWAP_FROM_SSE(Entry
) ||
2292 PFN_FROM_SSE(Entry
) != Page
)
2302 * Speculatively set all mappings of the page to clean.
2304 MmSetCleanAllRmaps(Page
);
2307 * If this page was direct mapped from the cache then the cache manager
2308 * will take care of writing it back to disk.
2310 if (DirectMapped
&& !Private
)
2312 LARGE_INTEGER SOffset
;
2313 ASSERT(SwapEntry
== 0);
2314 SOffset
.QuadPart
= Offset
.QuadPart
+ Segment
->Image
.FileOffset
;
2316 CcRosMarkDirtyCacheSegment(Bcb
, Offset
.LowPart
);
2318 MmLockSectionSegment(Segment
);
2319 MmSetPageEntrySectionSegment(Segment
, &Offset
, PageEntry
);
2320 MmUnlockSectionSegment(Segment
);
2321 MiSetPageEvent(NULL
, NULL
);
2322 return(STATUS_SUCCESS
);
2326 * If necessary, allocate an entry in the paging file for this page
2330 SwapEntry
= MmAllocSwapPage();
2333 MmSetDirtyAllRmaps(Page
);
2334 MiSetPageEvent(NULL
, NULL
);
2335 return(STATUS_PAGEFILE_QUOTA
);
2337 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2341 * Write the page to the pagefile
2343 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2344 if (!NT_SUCCESS(Status
))
2346 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2348 MmSetDirtyAllRmaps(Page
);
2349 MiSetPageEvent(NULL
, NULL
);
2350 return(STATUS_UNSUCCESSFUL
);
2354 * Otherwise we have succeeded.
2356 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2357 MiSetPageEvent(NULL
, NULL
);
2358 return(STATUS_SUCCESS
);
2362 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2370 PMEMORY_AREA MemoryArea
;
2371 PMM_SECTION_SEGMENT Segment
;
2372 BOOLEAN DoCOW
= FALSE
;
2374 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2376 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2377 ASSERT(MemoryArea
!= NULL
);
2378 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2379 MmLockSectionSegment(Segment
);
2381 if ((Segment
->WriteCopy
) &&
2382 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2387 if (OldProtect
!= NewProtect
)
2389 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2391 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2392 ULONG Protect
= NewProtect
;
2395 * If we doing COW for this segment then check if the page is
2398 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2400 LARGE_INTEGER Offset
;
2404 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2405 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2406 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2407 Page
= MmGetPfnForProcess(Process
, Address
);
2409 Protect
= PAGE_READONLY
;
2410 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2411 IS_SWAP_FROM_SSE(Entry
) ||
2412 PFN_FROM_SSE(Entry
) != Page
)
2414 Protect
= NewProtect
;
2418 if (MmIsPagePresent(Process
, Address
))
2420 MmSetPageProtect(Process
, Address
,
2426 MmUnlockSectionSegment(Segment
);
2431 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2432 PMEMORY_AREA MemoryArea
,
2440 ULONG_PTR MaxLength
;
2442 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2443 if (Length
> MaxLength
)
2444 Length
= (ULONG
)MaxLength
;
2446 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2447 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2449 ASSERT(Region
!= NULL
);
2451 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2452 Region
->Protect
!= Protect
)
2454 return STATUS_INVALID_PAGE_PROTECTION
;
2457 *OldProtect
= Region
->Protect
;
2458 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2459 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2460 BaseAddress
, Length
, Region
->Type
, Protect
,
2461 MmAlterViewAttributes
);
2467 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2469 PMEMORY_BASIC_INFORMATION Info
,
2470 PSIZE_T ResultLength
)
2473 PVOID RegionBaseAddress
;
2474 PROS_SECTION_OBJECT Section
;
2475 PMM_SECTION_SEGMENT Segment
;
2477 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2478 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2479 Address
, &RegionBaseAddress
);
2482 return STATUS_UNSUCCESSFUL
;
2485 Section
= MemoryArea
->Data
.SectionData
.Section
;
2486 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2488 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2489 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2490 Info
->Type
= MEM_IMAGE
;
2494 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2495 Info
->Type
= MEM_MAPPED
;
2497 Info
->BaseAddress
= RegionBaseAddress
;
2498 Info
->AllocationProtect
= MemoryArea
->Protect
;
2499 Info
->RegionSize
= Region
->Length
;
2500 Info
->State
= MEM_COMMIT
;
2501 Info
->Protect
= Region
->Protect
;
2503 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2504 return(STATUS_SUCCESS
);
2509 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2512 LARGE_INTEGER Offset
;
2514 SWAPENTRY SavedSwapEntry
;
2519 MmLockSectionSegment(Segment
);
2521 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2522 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2524 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2527 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2528 if (IS_SWAP_FROM_SSE(Entry
))
2530 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2534 Page
= PFN_FROM_SSE(Entry
);
2535 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2536 if (SavedSwapEntry
!= 0)
2538 MmSetSavedSwapEntryPage(Page
, 0);
2539 MmFreeSwapPage(SavedSwapEntry
);
2541 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2546 MmUnlockSectionSegment(Segment
);
2550 MmpDeleteSection(PVOID ObjectBody
)
2552 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2554 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2555 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2560 PMM_SECTION_SEGMENT SectionSegments
;
2563 * NOTE: Section->ImageSection can be NULL for short time
2564 * during the section creating. If we fail for some reason
2565 * until the image section is properly initialized we shouldn't
2566 * process further here.
2568 if (Section
->ImageSection
== NULL
)
2571 SectionSegments
= Section
->ImageSection
->Segments
;
2572 NrSegments
= Section
->ImageSection
->NrSegments
;
2574 for (i
= 0; i
< NrSegments
; i
++)
2576 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2578 MmLockSectionSegment(&SectionSegments
[i
]);
2580 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2581 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2583 MmUnlockSectionSegment(&SectionSegments
[i
]);
2586 MmpFreePageFileSegment(&SectionSegments
[i
]);
2592 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2595 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2598 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2600 DPRINT("Freeing section segment\n");
2601 Section
->Segment
= NULL
;
2602 MmFinalizeSegment(Segment
);
2606 DPRINT("RefCount %d\n", RefCount
);
2613 * NOTE: Section->Segment can be NULL for short time
2614 * during the section creating.
2616 if (Section
->Segment
== NULL
)
2619 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2621 MmpFreePageFileSegment(Section
->Segment
);
2622 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2623 ExFreePool(Section
->Segment
);
2624 Section
->Segment
= NULL
;
2628 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2631 if (Section
->FileObject
!= NULL
)
2634 CcRosDereferenceCache(Section
->FileObject
);
2636 ObDereferenceObject(Section
->FileObject
);
2637 Section
->FileObject
= NULL
;
2642 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2644 IN ACCESS_MASK GrantedAccess
,
2645 IN ULONG ProcessHandleCount
,
2646 IN ULONG SystemHandleCount
)
2648 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2649 Object
, ProcessHandleCount
);
2655 MmCreatePhysicalMemorySection(VOID
)
2657 PROS_SECTION_OBJECT PhysSection
;
2659 OBJECT_ATTRIBUTES Obj
;
2660 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2661 LARGE_INTEGER SectionSize
;
2665 * Create the section mapping physical memory
2667 SectionSize
.QuadPart
= 0xFFFFFFFF;
2668 InitializeObjectAttributes(&Obj
,
2673 Status
= MmCreateSection((PVOID
)&PhysSection
,
2677 PAGE_EXECUTE_READWRITE
,
2681 if (!NT_SUCCESS(Status
))
2683 DPRINT1("Failed to create PhysicalMemory section\n");
2684 KeBugCheck(MEMORY_MANAGEMENT
);
2686 Status
= ObInsertObject(PhysSection
,
2692 if (!NT_SUCCESS(Status
))
2694 ObDereferenceObject(PhysSection
);
2696 ObCloseHandle(Handle
, KernelMode
);
2697 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2698 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2700 return(STATUS_SUCCESS
);
2706 MmInitSectionImplementation(VOID
)
2708 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2709 UNICODE_STRING Name
;
2711 DPRINT("Creating Section Object Type\n");
2713 /* Initialize the section based root */
2714 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2715 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2717 /* Initialize the Section object type */
2718 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2719 RtlInitUnicodeString(&Name
, L
"Section");
2720 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2721 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2722 ObjectTypeInitializer
.PoolType
= PagedPool
;
2723 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2724 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2725 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2726 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2727 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2728 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2730 MmCreatePhysicalMemorySection();
2732 return(STATUS_SUCCESS
);
2737 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2738 ACCESS_MASK DesiredAccess
,
2739 POBJECT_ATTRIBUTES ObjectAttributes
,
2740 PLARGE_INTEGER UMaximumSize
,
2741 ULONG SectionPageProtection
,
2742 ULONG AllocationAttributes
)
2744 * Create a section which is backed by the pagefile
2747 LARGE_INTEGER MaximumSize
;
2748 PROS_SECTION_OBJECT Section
;
2749 PMM_SECTION_SEGMENT Segment
;
2752 if (UMaximumSize
== NULL
)
2754 return(STATUS_UNSUCCESSFUL
);
2756 MaximumSize
= *UMaximumSize
;
2759 * Create the section
2761 Status
= ObCreateObject(ExGetPreviousMode(),
2762 MmSectionObjectType
,
2764 ExGetPreviousMode(),
2766 sizeof(ROS_SECTION_OBJECT
),
2769 (PVOID
*)(PVOID
)&Section
);
2770 if (!NT_SUCCESS(Status
))
2778 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2779 Section
->Type
= 'SC';
2780 Section
->Size
= 'TN';
2781 Section
->SectionPageProtection
= SectionPageProtection
;
2782 Section
->AllocationAttributes
= AllocationAttributes
;
2783 Section
->MaximumSize
= MaximumSize
;
2784 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2785 TAG_MM_SECTION_SEGMENT
);
2786 if (Segment
== NULL
)
2788 ObDereferenceObject(Section
);
2789 return(STATUS_NO_MEMORY
);
2791 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2792 Section
->Segment
= Segment
;
2793 Segment
->ReferenceCount
= 1;
2794 ExInitializeFastMutex(&Segment
->Lock
);
2795 Segment
->Image
.FileOffset
= 0;
2796 Segment
->Protection
= SectionPageProtection
;
2797 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2798 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2799 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2800 Segment
->WriteCopy
= FALSE
;
2801 Segment
->Image
.VirtualAddress
= 0;
2802 Segment
->Image
.Characteristics
= 0;
2803 *SectionObject
= Section
;
2804 MiInitializeSectionPageTable(Segment
);
2805 return(STATUS_SUCCESS
);
2810 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2811 ACCESS_MASK DesiredAccess
,
2812 POBJECT_ATTRIBUTES ObjectAttributes
,
2813 PLARGE_INTEGER UMaximumSize
,
2814 ULONG SectionPageProtection
,
2815 ULONG AllocationAttributes
,
2818 * Create a section backed by a data file
2821 PROS_SECTION_OBJECT Section
;
2823 LARGE_INTEGER MaximumSize
;
2824 PFILE_OBJECT FileObject
;
2825 PMM_SECTION_SEGMENT Segment
;
2827 IO_STATUS_BLOCK Iosb
;
2828 LARGE_INTEGER Offset
;
2830 FILE_STANDARD_INFORMATION FileInfo
;
2834 * Create the section
2836 Status
= ObCreateObject(ExGetPreviousMode(),
2837 MmSectionObjectType
,
2839 ExGetPreviousMode(),
2841 sizeof(ROS_SECTION_OBJECT
),
2845 if (!NT_SUCCESS(Status
))
2852 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2853 Section
->Type
= 'SC';
2854 Section
->Size
= 'TN';
2855 Section
->SectionPageProtection
= SectionPageProtection
;
2856 Section
->AllocationAttributes
= AllocationAttributes
;
2859 * Reference the file handle
2861 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2862 Status
= ObReferenceObjectByHandle(FileHandle
,
2865 ExGetPreviousMode(),
2866 (PVOID
*)(PVOID
)&FileObject
,
2868 if (!NT_SUCCESS(Status
))
2870 ObDereferenceObject(Section
);
2875 * FIXME: This is propably not entirely correct. We can't look into
2876 * the standard FCB header because it might not be initialized yet
2877 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2878 * standard file information is filled on first request).
2880 Status
= IoQueryFileInformation(FileObject
,
2881 FileStandardInformation
,
2882 sizeof(FILE_STANDARD_INFORMATION
),
2885 Iosb
.Information
= Length
;
2886 if (!NT_SUCCESS(Status
))
2888 ObDereferenceObject(Section
);
2889 ObDereferenceObject(FileObject
);
2894 * FIXME: Revise this once a locking order for file size changes is
2897 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2899 MaximumSize
= *UMaximumSize
;
2903 MaximumSize
= FileInfo
.EndOfFile
;
2904 /* Mapping zero-sized files isn't allowed. */
2905 if (MaximumSize
.QuadPart
== 0)
2907 ObDereferenceObject(Section
);
2908 ObDereferenceObject(FileObject
);
2909 return STATUS_FILE_INVALID
;
2913 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2915 Status
= IoSetInformation(FileObject
,
2916 FileAllocationInformation
,
2917 sizeof(LARGE_INTEGER
),
2919 if (!NT_SUCCESS(Status
))
2921 ObDereferenceObject(Section
);
2922 ObDereferenceObject(FileObject
);
2923 return(STATUS_SECTION_NOT_EXTENDED
);
2927 if (FileObject
->SectionObjectPointer
== NULL
||
2928 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2931 * Read a bit so caching is initiated for the file object.
2932 * This is only needed because MiReadPage currently cannot
2933 * handle non-cached streams.
2935 Offset
.QuadPart
= 0;
2936 Status
= ZwReadFile(FileHandle
,
2945 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2947 ObDereferenceObject(Section
);
2948 ObDereferenceObject(FileObject
);
2951 if (FileObject
->SectionObjectPointer
== NULL
||
2952 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2954 /* FIXME: handle this situation */
2955 ObDereferenceObject(Section
);
2956 ObDereferenceObject(FileObject
);
2957 return STATUS_INVALID_PARAMETER
;
2964 Status
= MmspWaitForFileLock(FileObject
);
2965 if (Status
!= STATUS_SUCCESS
)
2967 ObDereferenceObject(Section
);
2968 ObDereferenceObject(FileObject
);
2973 * If this file hasn't been mapped as a data file before then allocate a
2974 * section segment to describe the data file mapping
2976 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2978 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2979 TAG_MM_SECTION_SEGMENT
);
2980 if (Segment
== NULL
)
2982 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2983 ObDereferenceObject(Section
);
2984 ObDereferenceObject(FileObject
);
2985 return(STATUS_NO_MEMORY
);
2987 Section
->Segment
= Segment
;
2988 Segment
->ReferenceCount
= 1;
2989 ExInitializeFastMutex(&Segment
->Lock
);
2991 * Set the lock before assigning the segment to the file object
2993 ExAcquireFastMutex(&Segment
->Lock
);
2994 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2996 Segment
->Image
.FileOffset
= 0;
2997 Segment
->Protection
= SectionPageProtection
;
2998 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2999 Segment
->Image
.Characteristics
= 0;
3000 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3001 if (AllocationAttributes
& SEC_RESERVE
)
3003 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3007 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3008 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3010 Segment
->Image
.VirtualAddress
= 0;
3011 Segment
->Locked
= TRUE
;
3012 MiInitializeSectionPageTable(Segment
);
3017 * If the file is already mapped as a data file then we may need
3021 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3023 Section
->Segment
= Segment
;
3024 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3025 MmLockSectionSegment(Segment
);
3027 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3028 !(AllocationAttributes
& SEC_RESERVE
))
3030 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3031 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3034 MmUnlockSectionSegment(Segment
);
3035 Section
->FileObject
= FileObject
;
3036 Section
->MaximumSize
= MaximumSize
;
3038 CcRosReferenceCache(FileObject
);
3040 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3041 *SectionObject
= Section
;
3042 return(STATUS_SUCCESS
);
3046 TODO: not that great (declaring loaders statically, having to declare all of
3047 them, having to keep them extern, etc.), will fix in the future
3049 extern NTSTATUS NTAPI PeFmtCreateSection
3051 IN CONST VOID
* FileHeader
,
3052 IN SIZE_T FileHeaderSize
,
3054 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3056 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3057 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3060 extern NTSTATUS NTAPI ElfFmtCreateSection
3062 IN CONST VOID
* FileHeader
,
3063 IN SIZE_T FileHeaderSize
,
3065 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3067 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3068 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3071 /* TODO: this is a standard DDK/PSDK macro */
3072 #ifndef RTL_NUMBER_OF
3073 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3076 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3087 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3089 SIZE_T SizeOfSegments
;
3090 PMM_SECTION_SEGMENT Segments
;
3092 /* TODO: check for integer overflow */
3093 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3095 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3097 TAG_MM_SECTION_SEGMENT
);
3100 RtlZeroMemory(Segments
, SizeOfSegments
);
3108 ExeFmtpReadFile(IN PVOID File
,
3109 IN PLARGE_INTEGER Offset
,
3112 OUT PVOID
* AllocBase
,
3113 OUT PULONG ReadSize
)
3116 LARGE_INTEGER FileOffset
;
3118 ULONG OffsetAdjustment
;
3122 PFILE_OBJECT FileObject
= File
;
3123 IO_STATUS_BLOCK Iosb
;
3125 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3129 KeBugCheck(MEMORY_MANAGEMENT
);
3132 FileOffset
= *Offset
;
3134 /* Negative/special offset: it cannot be used in this context */
3135 if(FileOffset
.u
.HighPart
< 0)
3137 KeBugCheck(MEMORY_MANAGEMENT
);
3140 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3141 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3142 FileOffset
.u
.LowPart
= AdjustOffset
;
3144 BufferSize
= Length
+ OffsetAdjustment
;
3145 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3148 * It's ok to use paged pool, because this is a temporary buffer only used in
3149 * the loading of executables. The assumption is that MmCreateSection is
3150 * always called at low IRQLs and that these buffers don't survive a brief
3151 * initialization phase
3153 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3158 KeBugCheck(MEMORY_MANAGEMENT
);
3163 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3165 UsedSize
= (ULONG
)Iosb
.Information
;
3167 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3169 Status
= STATUS_IN_PAGE_ERROR
;
3170 ASSERT(!NT_SUCCESS(Status
));
3173 if(NT_SUCCESS(Status
))
3175 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3176 *AllocBase
= Buffer
;
3177 *ReadSize
= UsedSize
- OffsetAdjustment
;
3181 ExFreePoolWithTag(Buffer
, 'rXmM');
3188 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3189 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3190 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3195 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3199 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3201 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3202 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3209 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3213 MmspAssertSegmentsSorted(ImageSectionObject
);
3215 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3217 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3221 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3222 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3223 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3231 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3235 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3237 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3238 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3246 MmspCompareSegments(const void * x
,
3249 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3250 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3253 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3254 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3258 * Ensures an image section's segments are sorted in memory
3263 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3266 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3268 MmspAssertSegmentsSorted(ImageSectionObject
);
3272 qsort(ImageSectionObject
->Segments
,
3273 ImageSectionObject
->NrSegments
,
3274 sizeof(ImageSectionObject
->Segments
[0]),
3275 MmspCompareSegments
);
3281 * Ensures an image section's segments don't overlap in memory and don't have
3282 * gaps and don't have a null size. We let them map to overlapping file regions,
3283 * though - that's not necessarily an error
3288 MmspCheckSegmentBounds
3290 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3296 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3298 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3302 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3304 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3306 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3314 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3315 * page could be OK (Windows seems to be OK with them), and larger gaps
3316 * could lead to image sections spanning several discontiguous regions
3317 * (NtMapViewOfSection could then refuse to map them, and they could
3318 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3320 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3321 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3322 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3333 * Merges and pads an image section's segments until they all are page-aligned
3334 * and have a size that is a multiple of the page size
3339 MmspPageAlignSegments
3341 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3347 PMM_SECTION_SEGMENT EffectiveSegment
;
3349 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3351 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3356 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3358 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3361 * The first segment requires special handling
3365 ULONG_PTR VirtualAddress
;
3366 ULONG_PTR VirtualOffset
;
3368 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3370 /* Round down the virtual address to the nearest page */
3371 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3373 /* Round up the virtual size to the nearest page */
3374 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3375 EffectiveSegment
->Image
.VirtualAddress
;
3377 /* Adjust the raw address and size */
3378 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3380 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3386 * Garbage in, garbage out: unaligned base addresses make the file
3387 * offset point in curious and odd places, but that's what we were
3390 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3391 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3395 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3396 ULONG_PTR EndOfEffectiveSegment
;
3398 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3399 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3402 * The current segment begins exactly where the current effective
3403 * segment ended, therefore beginning a new effective segment
3405 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3408 ASSERT(LastSegment
<= i
);
3409 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3411 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3413 if (LastSegment
!= i
)
3416 * Copy the current segment. If necessary, the effective segment
3417 * will be expanded later
3419 *EffectiveSegment
= *Segment
;
3423 * Page-align the virtual size. We know for sure the virtual address
3426 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3427 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3430 * The current segment is still part of the current effective segment:
3431 * extend the effective segment to reflect this
3433 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3435 static const ULONG FlagsToProtection
[16] =
3443 PAGE_EXECUTE_READWRITE
,
3444 PAGE_EXECUTE_READWRITE
,
3449 PAGE_EXECUTE_WRITECOPY
,
3450 PAGE_EXECUTE_WRITECOPY
,
3451 PAGE_EXECUTE_WRITECOPY
,
3452 PAGE_EXECUTE_WRITECOPY
3455 unsigned ProtectionFlags
;
3458 * Extend the file size
3461 /* Unaligned segments must be contiguous within the file */
3462 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3463 EffectiveSegment
->RawLength
.QuadPart
))
3468 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3471 * Extend the virtual size
3473 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3475 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3476 EffectiveSegment
->Image
.VirtualAddress
;
3479 * Merge the protection
3481 EffectiveSegment
->Protection
|= Segment
->Protection
;
3483 /* Clean up redundance */
3484 ProtectionFlags
= 0;
3486 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3487 ProtectionFlags
|= 1 << 0;
3489 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3490 ProtectionFlags
|= 1 << 1;
3492 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3493 ProtectionFlags
|= 1 << 2;
3495 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3496 ProtectionFlags
|= 1 << 3;
3498 ASSERT(ProtectionFlags
< 16);
3499 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3501 /* If a segment was required to be shared and cannot, fail */
3502 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3503 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3509 * We assume no holes between segments at this point
3513 KeBugCheck(MEMORY_MANAGEMENT
);
3517 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3523 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3524 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3526 LARGE_INTEGER Offset
;
3528 PVOID FileHeaderBuffer
;
3529 ULONG FileHeaderSize
;
3531 ULONG OldNrSegments
;
3536 * Read the beginning of the file (2 pages). Should be enough to contain
3537 * all (or most) of the headers
3539 Offset
.QuadPart
= 0;
3541 /* FIXME: use FileObject instead of FileHandle */
3542 Status
= ExeFmtpReadFile (FileHandle
,
3549 if (!NT_SUCCESS(Status
))
3552 if (FileHeaderSize
== 0)
3554 ExFreePool(FileHeaderBuffer
);
3555 return STATUS_UNSUCCESSFUL
;
3559 * Look for a loader that can handle this executable
3561 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3563 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3566 /* FIXME: use FileObject instead of FileHandle */
3567 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3573 ExeFmtpAllocateSegments
);
3575 if (!NT_SUCCESS(Status
))
3577 if (ImageSectionObject
->Segments
)
3579 ExFreePool(ImageSectionObject
->Segments
);
3580 ImageSectionObject
->Segments
= NULL
;
3584 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3588 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3591 * No loader handled the format
3593 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3595 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3596 ASSERT(!NT_SUCCESS(Status
));
3599 if (!NT_SUCCESS(Status
))
3602 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3607 /* FIXME? are these values platform-dependent? */
3608 if(ImageSectionObject
->StackReserve
== 0)
3609 ImageSectionObject
->StackReserve
= 0x40000;
3611 if(ImageSectionObject
->StackCommit
== 0)
3612 ImageSectionObject
->StackCommit
= 0x1000;
3614 if(ImageSectionObject
->ImageBase
== 0)
3616 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3617 ImageSectionObject
->ImageBase
= 0x10000000;
3619 ImageSectionObject
->ImageBase
= 0x00400000;
3623 * And now the fun part: fixing the segments
3626 /* Sort them by virtual address */
3627 MmspSortSegments(ImageSectionObject
, Flags
);
3629 /* Ensure they don't overlap in memory */
3630 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3631 return STATUS_INVALID_IMAGE_FORMAT
;
3633 /* Ensure they are aligned */
3634 OldNrSegments
= ImageSectionObject
->NrSegments
;
3636 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3637 return STATUS_INVALID_IMAGE_FORMAT
;
3639 /* Trim them if the alignment phase merged some of them */
3640 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3642 PMM_SECTION_SEGMENT Segments
;
3643 SIZE_T SizeOfSegments
;
3645 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3647 Segments
= ExAllocatePoolWithTag(PagedPool
,
3649 TAG_MM_SECTION_SEGMENT
);
3651 if (Segments
== NULL
)
3652 return STATUS_INSUFFICIENT_RESOURCES
;
3654 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3655 ExFreePool(ImageSectionObject
->Segments
);
3656 ImageSectionObject
->Segments
= Segments
;
3659 /* And finish their initialization */
3660 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3662 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3663 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3664 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3667 ASSERT(NT_SUCCESS(Status
));
3672 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3673 ACCESS_MASK DesiredAccess
,
3674 POBJECT_ATTRIBUTES ObjectAttributes
,
3675 PLARGE_INTEGER UMaximumSize
,
3676 ULONG SectionPageProtection
,
3677 ULONG AllocationAttributes
,
3678 PFILE_OBJECT FileObject
)
3680 PROS_SECTION_OBJECT Section
;
3682 PMM_SECTION_SEGMENT SectionSegments
;
3683 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3686 if (FileObject
== NULL
)
3687 return STATUS_INVALID_FILE_FOR_SECTION
;
3690 * Create the section
3692 Status
= ObCreateObject (ExGetPreviousMode(),
3693 MmSectionObjectType
,
3695 ExGetPreviousMode(),
3697 sizeof(ROS_SECTION_OBJECT
),
3700 (PVOID
*)(PVOID
)&Section
);
3701 if (!NT_SUCCESS(Status
))
3703 ObDereferenceObject(FileObject
);
3710 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3711 Section
->Type
= 'SC';
3712 Section
->Size
= 'TN';
3713 Section
->SectionPageProtection
= SectionPageProtection
;
3714 Section
->AllocationAttributes
= AllocationAttributes
;
3718 * Initialized caching for this file object if previously caching
3719 * was initialized for the same on disk file
3721 Status
= CcTryToInitializeFileCache(FileObject
);
3723 Status
= STATUS_SUCCESS
;
3726 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3728 NTSTATUS StatusExeFmt
;
3730 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3731 if (ImageSectionObject
== NULL
)
3733 ObDereferenceObject(FileObject
);
3734 ObDereferenceObject(Section
);
3735 return(STATUS_NO_MEMORY
);
3738 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3740 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3742 if (!NT_SUCCESS(StatusExeFmt
))
3744 if(ImageSectionObject
->Segments
!= NULL
)
3745 ExFreePool(ImageSectionObject
->Segments
);
3747 ExFreePool(ImageSectionObject
);
3748 ObDereferenceObject(Section
);
3749 ObDereferenceObject(FileObject
);
3750 return(StatusExeFmt
);
3753 Section
->ImageSection
= ImageSectionObject
;
3754 ASSERT(ImageSectionObject
->Segments
);
3759 Status
= MmspWaitForFileLock(FileObject
);
3760 if (!NT_SUCCESS(Status
))
3762 ExFreePool(ImageSectionObject
->Segments
);
3763 ExFreePool(ImageSectionObject
);
3764 ObDereferenceObject(Section
);
3765 ObDereferenceObject(FileObject
);
3769 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3770 ImageSectionObject
, NULL
))
3773 * An other thread has initialized the same image in the background
3775 ExFreePool(ImageSectionObject
->Segments
);
3776 ExFreePool(ImageSectionObject
);
3777 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3778 Section
->ImageSection
= ImageSectionObject
;
3779 SectionSegments
= ImageSectionObject
->Segments
;
3781 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3783 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3787 Status
= StatusExeFmt
;
3794 Status
= MmspWaitForFileLock(FileObject
);
3795 if (Status
!= STATUS_SUCCESS
)
3797 ObDereferenceObject(Section
);
3798 ObDereferenceObject(FileObject
);
3802 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3803 Section
->ImageSection
= ImageSectionObject
;
3804 SectionSegments
= ImageSectionObject
->Segments
;
3807 * Otherwise just reference all the section segments
3809 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3811 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3814 Status
= STATUS_SUCCESS
;
3816 Section
->FileObject
= FileObject
;
3818 CcRosReferenceCache(FileObject
);
3820 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3821 *SectionObject
= Section
;
3828 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3829 PROS_SECTION_OBJECT Section
,
3830 PMM_SECTION_SEGMENT Segment
,
3835 ULONG AllocationType
)
3839 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3841 if (Segment
->WriteCopy
)
3843 /* We have to do this because the not present fault
3844 * and access fault handlers depend on the protection
3845 * that should be granted AFTER the COW fault takes
3846 * place to be in Region->Protect. The not present fault
3847 * handler changes this to the correct protection for COW when
3848 * mapping the pages into the process's address space. If a COW
3849 * fault takes place, the access fault handler sets the page protection
3850 * to these values for the newly copied pages
3852 if (Protect
== PAGE_WRITECOPY
)
3853 Protect
= PAGE_READWRITE
;
3854 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3855 Protect
= PAGE_EXECUTE_READWRITE
;
3858 BoundaryAddressMultiple
.QuadPart
= 0;
3861 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
3862 LARGE_INTEGER FileOffset
;
3863 FileOffset
.QuadPart
= ViewOffset
;
3864 ObReferenceObject(Section
);
3865 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
3868 Status
= MmCreateMemoryArea(AddressSpace
,
3869 MEMORY_AREA_SECTION_VIEW
,
3876 BoundaryAddressMultiple
);
3877 if (!NT_SUCCESS(Status
))
3879 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3880 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3884 ObReferenceObject((PVOID
)Section
);
3886 MArea
->Data
.SectionData
.Segment
= Segment
;
3887 MArea
->Data
.SectionData
.Section
= Section
;
3888 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
3889 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3890 ViewSize
, 0, Protect
);
3892 return(STATUS_SUCCESS
);
3897 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3898 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3901 PFILE_OBJECT FileObject
;
3903 LARGE_INTEGER Offset
;
3904 SWAPENTRY SavedSwapEntry
;
3905 PROS_SECTION_OBJECT Section
;
3906 PMM_SECTION_SEGMENT Segment
;
3907 PMMSUPPORT AddressSpace
;
3910 AddressSpace
= (PMMSUPPORT
)Context
;
3911 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3913 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3915 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3916 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
3918 Section
= MemoryArea
->Data
.SectionData
.Section
;
3919 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3921 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3922 while (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
3924 MmUnlockSectionSegment(Segment
);
3925 MmUnlockAddressSpace(AddressSpace
);
3927 MiWaitForPageEvent(NULL
, NULL
);
3929 MmLockAddressSpace(AddressSpace
);
3930 MmLockSectionSegment(Segment
);
3931 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
3935 * For a dirty, datafile, non-private page mark it as dirty in the
3938 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3940 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3942 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3943 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3945 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)(Offset
.QuadPart
+ Segment
->Image
.FileOffset
));
3947 ASSERT(SwapEntry
== 0);
3956 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3958 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3959 KeBugCheck(MEMORY_MANAGEMENT
);
3961 MmFreeSwapPage(SwapEntry
);
3965 if (IS_SWAP_FROM_SSE(Entry
) ||
3966 Page
!= PFN_FROM_SSE(Entry
))
3971 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3973 DPRINT1("Found a private page in a pagefile section.\n");
3974 KeBugCheck(MEMORY_MANAGEMENT
);
3977 * Just dereference private pages
3979 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3980 if (SavedSwapEntry
!= 0)
3982 MmFreeSwapPage(SavedSwapEntry
);
3983 MmSetSavedSwapEntryPage(Page
, 0);
3985 MmDeleteRmap(Page
, Process
, Address
);
3986 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3990 MmDeleteRmap(Page
, Process
, Address
);
3991 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
, NULL
);
3997 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4001 PMEMORY_AREA MemoryArea
;
4002 PROS_SECTION_OBJECT Section
;
4003 PMM_SECTION_SEGMENT Segment
;
4004 PLIST_ENTRY CurrentEntry
;
4005 PMM_REGION CurrentRegion
;
4006 PLIST_ENTRY RegionListHead
;
4008 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4010 if (MemoryArea
== NULL
)
4012 return(STATUS_UNSUCCESSFUL
);
4015 MemoryArea
->DeleteInProgress
= TRUE
;
4016 Section
= MemoryArea
->Data
.SectionData
.Section
;
4017 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4020 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4021 return MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4024 MmLockSectionSegment(Segment
);
4026 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4027 while (!IsListEmpty(RegionListHead
))
4029 CurrentEntry
= RemoveHeadList(RegionListHead
);
4030 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4031 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4034 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4036 Status
= MmFreeMemoryArea(AddressSpace
,
4043 Status
= MmFreeMemoryArea(AddressSpace
,
4048 MmUnlockSectionSegment(Segment
);
4049 ObDereferenceObject(Section
);
4055 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4056 IN PVOID BaseAddress
,
4060 PMEMORY_AREA MemoryArea
;
4061 PMMSUPPORT AddressSpace
;
4062 PROS_SECTION_OBJECT Section
;
4063 PVOID ImageBaseAddress
= 0;
4065 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4066 Process
, BaseAddress
);
4070 AddressSpace
= &Process
->Vm
;
4072 MmLockAddressSpace(AddressSpace
);
4073 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4075 if (MemoryArea
== NULL
||
4076 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4077 MemoryArea
->DeleteInProgress
)
4079 ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4080 MmUnlockAddressSpace(AddressSpace
);
4081 return STATUS_NOT_MAPPED_VIEW
;
4084 MemoryArea
->DeleteInProgress
= TRUE
;
4086 Section
= MemoryArea
->Data
.SectionData
.Section
;
4088 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4092 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4093 PMM_SECTION_SEGMENT SectionSegments
;
4094 PMM_SECTION_SEGMENT Segment
;
4096 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4097 ImageSectionObject
= Section
->ImageSection
;
4098 SectionSegments
= ImageSectionObject
->Segments
;
4099 NrSegments
= ImageSectionObject
->NrSegments
;
4101 /* Search for the current segment within the section segments
4102 * and calculate the image base address */
4103 for (i
= 0; i
< NrSegments
; i
++)
4105 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4107 if (Segment
== &SectionSegments
[i
])
4109 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4114 if (i
>= NrSegments
)
4116 KeBugCheck(MEMORY_MANAGEMENT
);
4119 for (i
= 0; i
< NrSegments
; i
++)
4121 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4123 PVOID SBaseAddress
= (PVOID
)
4124 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4126 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4132 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4135 MmUnlockAddressSpace(AddressSpace
);
4137 /* Notify debugger */
4138 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4140 return(STATUS_SUCCESS
);
4147 * Queries the information of a section object.
4149 * @param SectionHandle
4150 * Handle to the section object. It must be opened with SECTION_QUERY
4152 * @param SectionInformationClass
4153 * Index to a certain information structure. Can be either
4154 * SectionBasicInformation or SectionImageInformation. The latter
4155 * is valid only for sections that were created with the SEC_IMAGE
4157 * @param SectionInformation
4158 * Caller supplies storage for resulting information.
4160 * Size of the supplied storage.
4161 * @param ResultLength
4169 NtQuerySection(IN HANDLE SectionHandle
,
4170 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4171 OUT PVOID SectionInformation
,
4172 IN SIZE_T SectionInformationLength
,
4173 OUT PSIZE_T ResultLength OPTIONAL
)
4175 PROS_SECTION_OBJECT Section
;
4176 KPROCESSOR_MODE PreviousMode
;
4180 PreviousMode
= ExGetPreviousMode();
4182 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4184 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4186 (ULONG
)SectionInformationLength
,
4191 if(!NT_SUCCESS(Status
))
4193 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4197 Status
= ObReferenceObjectByHandle(SectionHandle
,
4199 MmSectionObjectType
,
4201 (PVOID
*)(PVOID
)&Section
,
4203 if (NT_SUCCESS(Status
))
4205 switch (SectionInformationClass
)
4207 case SectionBasicInformation
:
4209 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4213 Sbi
->Attributes
= Section
->AllocationAttributes
;
4214 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4216 Sbi
->BaseAddress
= 0;
4217 Sbi
->Size
.QuadPart
= 0;
4221 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4222 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4225 if (ResultLength
!= NULL
)
4227 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4229 Status
= STATUS_SUCCESS
;
4231 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4233 Status
= _SEH2_GetExceptionCode();
4240 case SectionImageInformation
:
4242 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4246 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4247 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4249 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4250 ImageSectionObject
= Section
->ImageSection
;
4252 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4253 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4254 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4255 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4256 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4257 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4258 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4259 Sii
->Machine
= ImageSectionObject
->Machine
;
4260 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4263 if (ResultLength
!= NULL
)
4265 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4267 Status
= STATUS_SUCCESS
;
4269 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4271 Status
= _SEH2_GetExceptionCode();
4279 ObDereferenceObject(Section
);
4285 /**********************************************************************
4287 * MmMapViewOfSection
4290 * Maps a view of a section into the virtual address space of a
4295 * Pointer to the section object.
4298 * Pointer to the process.
4301 * Desired base address (or NULL) on entry;
4302 * Actual base address of the view on exit.
4305 * Number of high order address bits that must be zero.
4308 * Size in bytes of the initially committed section of
4312 * Offset in bytes from the beginning of the section
4313 * to the beginning of the view.
4316 * Desired length of map (or zero to map all) on entry
4317 * Actual length mapped on exit.
4319 * InheritDisposition
4320 * Specified how the view is to be shared with
4324 * Type of allocation for the pages.
4327 * Protection for the committed region of the view.
4335 MmMapViewOfSection(IN PVOID SectionObject
,
4336 IN PEPROCESS Process
,
4337 IN OUT PVOID
*BaseAddress
,
4338 IN ULONG_PTR ZeroBits
,
4339 IN SIZE_T CommitSize
,
4340 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4341 IN OUT PSIZE_T ViewSize
,
4342 IN SECTION_INHERIT InheritDisposition
,
4343 IN ULONG AllocationType
,
4346 PROS_SECTION_OBJECT Section
;
4347 PMMSUPPORT AddressSpace
;
4349 NTSTATUS Status
= STATUS_SUCCESS
;
4350 BOOLEAN NotAtBase
= FALSE
;
4352 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4354 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4355 return MmMapViewOfArm3Section(SectionObject
,
4369 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4371 return STATUS_INVALID_PAGE_PROTECTION
;
4375 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4376 AddressSpace
= &Process
->Vm
;
4378 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4380 MmLockAddressSpace(AddressSpace
);
4382 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4386 ULONG_PTR ImageBase
;
4388 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4389 PMM_SECTION_SEGMENT SectionSegments
;
4391 ImageSectionObject
= Section
->ImageSection
;
4392 SectionSegments
= ImageSectionObject
->Segments
;
4393 NrSegments
= ImageSectionObject
->NrSegments
;
4396 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4399 ImageBase
= ImageSectionObject
->ImageBase
;
4403 for (i
= 0; i
< NrSegments
; i
++)
4405 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4407 ULONG_PTR MaxExtent
;
4408 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4409 SectionSegments
[i
].Length
.QuadPart
);
4410 ImageSize
= max(ImageSize
, MaxExtent
);
4414 ImageSectionObject
->ImageSize
= (ULONG
)ImageSize
;
4416 /* Check for an illegal base address */
4417 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4419 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4422 /* Check there is enough space to map the section at that point. */
4423 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4424 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4426 /* Fail if the user requested a fixed base address. */
4427 if ((*BaseAddress
) != NULL
)
4429 MmUnlockAddressSpace(AddressSpace
);
4430 return(STATUS_UNSUCCESSFUL
);
4432 /* Otherwise find a gap to map the image. */
4433 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4436 MmUnlockAddressSpace(AddressSpace
);
4437 return(STATUS_UNSUCCESSFUL
);
4439 /* Remember that we loaded image at a different base address */
4443 for (i
= 0; i
< NrSegments
; i
++)
4445 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4447 PVOID SBaseAddress
= (PVOID
)
4448 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4449 MmLockSectionSegment(&SectionSegments
[i
]);
4450 Status
= MmMapViewOfSegment(AddressSpace
,
4452 &SectionSegments
[i
],
4454 SectionSegments
[i
].Length
.LowPart
,
4455 SectionSegments
[i
].Protection
,
4458 MmUnlockSectionSegment(&SectionSegments
[i
]);
4459 if (!NT_SUCCESS(Status
))
4461 MmUnlockAddressSpace(AddressSpace
);
4467 *BaseAddress
= (PVOID
)ImageBase
;
4468 *ViewSize
= ImageSize
;
4472 /* check for write access */
4473 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4474 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4476 MmUnlockAddressSpace(AddressSpace
);
4477 return STATUS_SECTION_PROTECTION
;
4479 /* check for read access */
4480 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4481 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4483 MmUnlockAddressSpace(AddressSpace
);
4484 return STATUS_SECTION_PROTECTION
;
4486 /* check for execute access */
4487 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4488 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4490 MmUnlockAddressSpace(AddressSpace
);
4491 return STATUS_SECTION_PROTECTION
;
4494 if (ViewSize
== NULL
)
4496 /* Following this pointer would lead to us to the dark side */
4497 /* What to do? Bugcheck? Return status? Do the mambo? */
4498 KeBugCheck(MEMORY_MANAGEMENT
);
4501 if (SectionOffset
== NULL
)
4507 ViewOffset
= SectionOffset
->u
.LowPart
;
4510 if ((ViewOffset
% PAGE_SIZE
) != 0)
4512 MmUnlockAddressSpace(AddressSpace
);
4513 return(STATUS_MAPPED_ALIGNMENT
);
4516 if ((*ViewSize
) == 0)
4518 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4520 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4522 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4525 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4527 MmLockSectionSegment(Section
->Segment
);
4528 Status
= MmMapViewOfSegment(AddressSpace
,
4535 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4536 MmUnlockSectionSegment(Section
->Segment
);
4537 if (!NT_SUCCESS(Status
))
4539 MmUnlockAddressSpace(AddressSpace
);
4544 MmUnlockAddressSpace(AddressSpace
);
4547 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4549 Status
= STATUS_SUCCESS
;
4558 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4559 IN PLARGE_INTEGER NewFileSize
)
4561 /* Check whether an ImageSectionObject exists */
4562 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4564 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4568 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4570 PMM_SECTION_SEGMENT Segment
;
4572 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4575 if (Segment
->ReferenceCount
!= 0)
4578 CC_FILE_SIZES FileSizes
;
4580 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4583 /* Check size of file */
4584 if (SectionObjectPointer
->SharedCacheMap
)
4586 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4591 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4600 /* Check size of file */
4601 if (SectionObjectPointer
->SharedCacheMap
)
4603 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4604 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4613 /* Something must gone wrong
4614 * how can we have a Section but no
4616 DPRINT("ERROR: DataSectionObject without reference!\n");
4620 DPRINT("FIXME: didn't check for outstanding write probes\n");
4632 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4633 IN MMFLUSH_TYPE FlushType
)
4635 BOOLEAN Result
= TRUE
;
4637 PMM_SECTION_SEGMENT Segment
;
4642 case MmFlushForDelete
:
4643 if (SectionObjectPointer
->ImageSectionObject
||
4644 SectionObjectPointer
->DataSectionObject
)
4649 CcRosSetRemoveOnClose(SectionObjectPointer
);
4652 case MmFlushForWrite
:
4654 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4656 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4659 if (SectionObjectPointer
->ImageSectionObject
) {
4660 DPRINT1("SectionObject has ImageSection\n");
4666 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4668 DPRINT("Result %d\n", Result
);
4680 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4681 OUT PVOID
* MappedBase
,
4682 IN OUT PSIZE_T ViewSize
)
4684 PROS_SECTION_OBJECT Section
;
4685 PMMSUPPORT AddressSpace
;
4689 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4691 return MiMapViewInSystemSpace(SectionObject
,
4697 DPRINT("MmMapViewInSystemSpace() called\n");
4699 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4700 AddressSpace
= MmGetKernelAddressSpace();
4702 MmLockAddressSpace(AddressSpace
);
4705 if ((*ViewSize
) == 0)
4707 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4709 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4711 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4714 MmLockSectionSegment(Section
->Segment
);
4717 Status
= MmMapViewOfSegment(AddressSpace
,
4726 MmUnlockSectionSegment(Section
->Segment
);
4727 MmUnlockAddressSpace(AddressSpace
);
4734 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4736 PMMSUPPORT AddressSpace
;
4739 DPRINT("MmUnmapViewInSystemSpace() called\n");
4741 AddressSpace
= MmGetKernelAddressSpace();
4743 MmLockAddressSpace(AddressSpace
);
4745 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4747 MmUnlockAddressSpace(AddressSpace
);
4752 /**********************************************************************
4757 * Creates a section object.
4760 * SectionObject (OUT)
4761 * Caller supplied storage for the resulting pointer
4762 * to a SECTION_OBJECT instance;
4765 * Specifies the desired access to the section can be a
4767 * STANDARD_RIGHTS_REQUIRED |
4769 * SECTION_MAP_WRITE |
4770 * SECTION_MAP_READ |
4771 * SECTION_MAP_EXECUTE
4773 * ObjectAttributes [OPTIONAL]
4774 * Initialized attributes for the object can be used
4775 * to create a named section;
4778 * Maximizes the size of the memory section. Must be
4779 * non-NULL for a page-file backed section.
4780 * If value specified for a mapped file and the file is
4781 * not large enough, file will be extended.
4783 * SectionPageProtection
4784 * Can be a combination of:
4790 * AllocationAttributes
4791 * Can be a combination of:
4796 * Handle to a file to create a section mapped to a file
4797 * instead of a memory backed section;
4808 MmCreateSection (OUT PVOID
* Section
,
4809 IN ACCESS_MASK DesiredAccess
,
4810 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4811 IN PLARGE_INTEGER MaximumSize
,
4812 IN ULONG SectionPageProtection
,
4813 IN ULONG AllocationAttributes
,
4814 IN HANDLE FileHandle OPTIONAL
,
4815 IN PFILE_OBJECT FileObject OPTIONAL
)
4818 ULONG Protection
, FileAccess
;
4819 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4821 /* Check if an ARM3 section is being created instead */
4822 if (AllocationAttributes
& 1)
4824 DPRINT1("Creating ARM3 section\n");
4825 return MmCreateArm3Section(Section
,
4829 SectionPageProtection
,
4830 AllocationAttributes
&~ 1,
4836 * Check the protection
4838 Protection
= SectionPageProtection
& ~(PAGE_GUARD
| PAGE_NOCACHE
);
4839 if (Protection
!= PAGE_READONLY
&&
4840 Protection
!= PAGE_READWRITE
&&
4841 Protection
!= PAGE_WRITECOPY
&&
4842 Protection
!= PAGE_EXECUTE
&&
4843 Protection
!= PAGE_EXECUTE_READ
&&
4844 Protection
!= PAGE_EXECUTE_READWRITE
&&
4845 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4847 return STATUS_INVALID_PAGE_PROTECTION
;
4850 if ((DesiredAccess
& SECTION_MAP_WRITE
) &&
4851 (Protection
== PAGE_READWRITE
||
4852 Protection
== PAGE_EXECUTE_READWRITE
) &&
4853 !(AllocationAttributes
& SEC_IMAGE
))
4855 DPRINT("Creating a section with WRITE access\n");
4856 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
| SYNCHRONIZE
;
4860 DPRINT("Creating a section with READ access\n");
4861 FileAccess
= FILE_READ_DATA
| SYNCHRONIZE
;
4864 /* FIXME: somehow combine this with the above checks */
4865 if (AllocationAttributes
& SEC_IMAGE
)
4866 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
4868 if (!FileObject
&& FileHandle
)
4870 Status
= ObReferenceObjectByHandle(FileHandle
,
4873 ExGetPreviousMode(),
4874 (PVOID
*)&FileObject
,
4876 if (!NT_SUCCESS(Status
))
4878 DPRINT("Failed: 0x%08lx\n", Status
);
4882 else if (FileObject
)
4883 ObReferenceObject(FileObject
);
4885 #ifndef NEWCC // A hack for initializing caching.
4886 // This is needed only in the old case.
4889 IO_STATUS_BLOCK Iosb
;
4892 LARGE_INTEGER ByteOffset
;
4893 ByteOffset
.QuadPart
= 0;
4894 Status
= ZwReadFile(FileHandle
,
4903 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
4905 // Caching is initialized...
4909 if (AllocationAttributes
& SEC_IMAGE
)
4911 Status
= MmCreateImageSection(SectionObject
,
4915 SectionPageProtection
,
4916 AllocationAttributes
,
4920 else if (FileHandle
!= NULL
)
4922 Status
= MmCreateDataFileSection(SectionObject
,
4926 SectionPageProtection
,
4927 AllocationAttributes
,
4930 ObDereferenceObject(FileObject
);
4933 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
4935 Status
= MmCreateCacheSection(SectionObject
,
4939 SectionPageProtection
,
4940 AllocationAttributes
,
4946 Status
= MmCreatePageFileSection(SectionObject
,
4950 SectionPageProtection
,
4951 AllocationAttributes
);
4958 MmModifyAttributes(IN PMMSUPPORT AddressSpace
,
4959 IN PVOID BaseAddress
,
4960 IN SIZE_T RegionSize
,
4962 IN ULONG OldProtect
,
4964 IN ULONG NewProtect
)
4967 // This function is deprecated but remains in order to support VirtualAlloc
4968 // calls with MEM_COMMIT on top of MapViewOfFile calls with SEC_RESERVE.
4970 // Win32k's shared user heap, for example, uses that mechanism. The two
4971 // conditions when this function needs to do something are ASSERTed for,
4972 // because they should not arise.
4974 if (NewType
== MEM_RESERVE
&& OldType
== MEM_COMMIT
)
4979 if ((NewType
== MEM_COMMIT
) && (OldType
== MEM_COMMIT
))
4981 ASSERT(OldProtect
== NewProtect
);
4987 MiRosAllocateVirtualMemory(IN HANDLE ProcessHandle
,
4988 IN PEPROCESS Process
,
4989 IN PMEMORY_AREA MemoryArea
,
4990 IN PMMSUPPORT AddressSpace
,
4991 IN OUT PVOID
* UBaseAddress
,
4992 IN BOOLEAN Attached
,
4993 IN OUT PSIZE_T URegionSize
,
4994 IN ULONG AllocationType
,
4997 ULONG_PTR PRegionSize
;
4998 ULONG Type
, RegionSize
;
5000 PVOID PBaseAddress
, BaseAddress
;
5001 KAPC_STATE ApcState
;
5003 PBaseAddress
= *UBaseAddress
;
5004 PRegionSize
= *URegionSize
;
5006 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(PBaseAddress
);
5007 RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)PBaseAddress
+ PRegionSize
) -
5008 PAGE_ROUND_DOWN(PBaseAddress
);
5009 Type
= (AllocationType
& MEM_COMMIT
) ? MEM_COMMIT
: MEM_RESERVE
;
5011 ASSERT(PBaseAddress
!= 0);
5012 ASSERT(Type
== MEM_COMMIT
);
5013 ASSERT(MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
);
5014 ASSERT(((ULONG_PTR
)BaseAddress
+ RegionSize
) <= (ULONG_PTR
)MemoryArea
->EndingAddress
);
5015 ASSERT(((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
) >= RegionSize
);
5016 ASSERT(MemoryArea
->Data
.SectionData
.RegionListHead
.Flink
);
5018 Status
= MmAlterRegion(AddressSpace
,
5019 MemoryArea
->StartingAddress
,
5020 &MemoryArea
->Data
.SectionData
.RegionListHead
,
5025 MmModifyAttributes
);
5027 MmUnlockAddressSpace(AddressSpace
);
5028 if (Attached
) KeUnstackDetachProcess(&ApcState
);
5029 if (ProcessHandle
!= NtCurrentProcess()) ObDereferenceObject(Process
);
5030 if (NT_SUCCESS(Status
))
5032 *UBaseAddress
= BaseAddress
;
5033 *URegionSize
= RegionSize
;
5041 MiRosProtectVirtualMemory(IN PEPROCESS Process
,
5042 IN OUT PVOID
*BaseAddress
,
5043 IN OUT PSIZE_T NumberOfBytesToProtect
,
5044 IN ULONG NewAccessProtection
,
5045 OUT PULONG OldAccessProtection OPTIONAL
)
5047 PMEMORY_AREA MemoryArea
;
5048 PMMSUPPORT AddressSpace
;
5049 ULONG OldAccessProtection_
;
5052 *NumberOfBytesToProtect
= PAGE_ROUND_UP((ULONG_PTR
)(*BaseAddress
) + (*NumberOfBytesToProtect
)) - PAGE_ROUND_DOWN(*BaseAddress
);
5053 *BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(*BaseAddress
);
5055 AddressSpace
= &Process
->Vm
;
5056 MmLockAddressSpace(AddressSpace
);
5057 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, *BaseAddress
);
5058 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
5060 MmUnlockAddressSpace(AddressSpace
);
5061 return STATUS_UNSUCCESSFUL
;
5064 if (OldAccessProtection
== NULL
) OldAccessProtection
= &OldAccessProtection_
;
5066 if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
5068 Status
= MmProtectSectionView(AddressSpace
,
5071 *NumberOfBytesToProtect
,
5072 NewAccessProtection
,
5073 OldAccessProtection
);
5077 /* FIXME: Should we return failure or success in this case? */
5078 Status
= STATUS_CONFLICTING_ADDRESSES
;
5081 MmUnlockAddressSpace(AddressSpace
);