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
;
131 MM_SECTION_PAGEOUT_CONTEXT
;
133 /* GLOBALS *******************************************************************/
135 POBJECT_TYPE MmSectionObjectType
= NULL
;
137 ULONG_PTR MmSubsectionBase
;
139 static ULONG SectionCharacteristicsToProtect
[16] =
141 PAGE_NOACCESS
, /* 0 = NONE */
142 PAGE_NOACCESS
, /* 1 = SHARED */
143 PAGE_EXECUTE
, /* 2 = EXECUTABLE */
144 PAGE_EXECUTE
, /* 3 = EXECUTABLE, SHARED */
145 PAGE_READONLY
, /* 4 = READABLE */
146 PAGE_READONLY
, /* 5 = READABLE, SHARED */
147 PAGE_EXECUTE_READ
, /* 6 = READABLE, EXECUTABLE */
148 PAGE_EXECUTE_READ
, /* 7 = READABLE, EXECUTABLE, SHARED */
150 * FIXME? do we really need the WriteCopy field in segments? can't we use
151 * PAGE_WRITECOPY here?
153 PAGE_READWRITE
, /* 8 = WRITABLE */
154 PAGE_READWRITE
, /* 9 = WRITABLE, SHARED */
155 PAGE_EXECUTE_READWRITE
, /* 10 = WRITABLE, EXECUTABLE */
156 PAGE_EXECUTE_READWRITE
, /* 11 = WRITABLE, EXECUTABLE, SHARED */
157 PAGE_READWRITE
, /* 12 = WRITABLE, READABLE */
158 PAGE_READWRITE
, /* 13 = WRITABLE, READABLE, SHARED */
159 PAGE_EXECUTE_READWRITE
, /* 14 = WRITABLE, READABLE, EXECUTABLE */
160 PAGE_EXECUTE_READWRITE
, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
163 ACCESS_MASK NTAPI
MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection
);
164 static GENERIC_MAPPING MmpSectionMapping
= {
165 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
166 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
167 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
170 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
172 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
173 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
176 /* FUNCTIONS *****************************************************************/
181 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
182 File Format Specification", revision 6.0 (February 1999)
184 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
185 IN SIZE_T FileHeaderSize
,
187 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
189 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
190 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
193 ULONG cbFileHeaderOffsetSize
= 0;
194 ULONG cbSectionHeadersOffset
= 0;
195 ULONG cbSectionHeadersSize
;
196 ULONG cbSectionHeadersOffsetSize
= 0;
197 ULONG cbOptHeaderSize
;
198 ULONG cbHeadersSize
= 0;
199 ULONG nSectionAlignment
;
200 ULONG nFileAlignment
;
201 const IMAGE_DOS_HEADER
* pidhDosHeader
;
202 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
203 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
204 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
205 PMM_SECTION_SEGMENT pssSegments
;
206 LARGE_INTEGER lnOffset
;
208 SIZE_T nPrevVirtualEndOfSegment
= 0;
209 ULONG nFileSizeOfHeaders
= 0;
213 ASSERT(FileHeaderSize
> 0);
215 ASSERT(ImageSectionObject
);
217 ASSERT(AllocateSegmentsCb
);
219 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
221 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
223 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
226 pidhDosHeader
= FileHeader
;
229 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
231 /* image too small to be an MZ executable */
232 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
233 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
235 /* no MZ signature */
236 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
237 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
239 /* not a Windows executable */
240 if(pidhDosHeader
->e_lfanew
<= 0)
241 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
244 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
246 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
247 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
249 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
254 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
255 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
257 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
258 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
262 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
263 * need to read the header from the file
265 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
266 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
268 ULONG cbNtHeaderSize
;
272 l_ReadHeaderFromFile
:
274 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
276 /* read the header from the file */
277 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
279 if(!NT_SUCCESS(nStatus
))
280 DIE(("ReadFile failed, status %08X\n", nStatus
));
284 ASSERT(cbReadSize
> 0);
286 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
288 /* the buffer doesn't contain the file header */
289 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
290 DIE(("The file doesn't contain the PE file header\n"));
292 pinhNtHeader
= pData
;
294 /* object still not aligned: copy it to the beginning of the buffer */
295 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
297 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
298 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
299 pinhNtHeader
= pBuffer
;
302 /* invalid NT header */
303 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
305 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
306 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
308 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
310 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
311 DIE(("The full NT header is too large\n"));
313 /* the buffer doesn't contain the whole NT header */
314 if(cbReadSize
< cbNtHeaderSize
)
315 DIE(("The file doesn't contain the full NT header\n"));
319 ULONG cbOptHeaderOffsetSize
= 0;
321 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
323 /* don't trust an invalid NT header */
324 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
325 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
327 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
328 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
330 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
331 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
333 /* the buffer doesn't contain the whole NT header: read it from the file */
334 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
335 goto l_ReadHeaderFromFile
;
338 /* read information from the NT header */
339 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
340 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
342 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
344 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
345 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
347 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
349 switch(piohOptHeader
->Magic
)
351 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
352 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
356 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
359 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
360 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
362 /* See [1], section 3.4.2 */
363 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
365 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
366 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
368 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
369 DIE(("The section alignment is smaller than the file alignment\n"));
371 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
372 nFileAlignment
= piohOptHeader
->FileAlignment
;
374 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
375 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
379 nSectionAlignment
= PAGE_SIZE
;
380 nFileAlignment
= PAGE_SIZE
;
383 ASSERT(IsPowerOf2(nSectionAlignment
));
384 ASSERT(IsPowerOf2(nFileAlignment
));
386 switch(piohOptHeader
->Magic
)
389 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
391 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
392 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
394 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
395 ImageSectionObject
->ImageSize
= piohOptHeader
->SizeOfImage
;
397 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
398 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
400 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
401 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
407 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
409 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
411 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
413 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
415 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
416 DIE(("ImageBase exceeds the address space\n"));
418 ImageSectionObject
->ImageBase
= (ULONG_PTR
)pioh64OptHeader
->ImageBase
;
421 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
423 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
424 DIE(("SizeOfImage exceeds the address space\n"));
426 ImageSectionObject
->ImageSize
= pioh64OptHeader
->SizeOfImage
;
429 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
431 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
432 DIE(("SizeOfStackReserve exceeds the address space\n"));
434 ImageSectionObject
->StackReserve
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackReserve
;
437 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
439 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
440 DIE(("SizeOfStackCommit exceeds the address space\n"));
442 ImageSectionObject
->StackCommit
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackCommit
;
449 /* [1], section 3.4.2 */
450 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
451 DIE(("ImageBase is not aligned on a 64KB boundary"));
453 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
455 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
457 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
458 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
460 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
461 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
465 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
467 ImageSectionObject
->EntryPoint
= ImageSectionObject
->ImageBase
+
468 piohOptHeader
->AddressOfEntryPoint
;
471 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
472 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
474 ImageSectionObject
->Executable
= TRUE
;
476 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
477 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
479 /* SECTION HEADERS */
480 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
482 /* see [1], section 3.3 */
483 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
484 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
487 * the additional segment is for the file's headers. They need to be present for
488 * the benefit of the dynamic loader (to locate exports, defaults for thread
489 * parameters, resources, etc.)
491 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
493 /* file offset for the section headers */
494 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
495 DIE(("Offset overflow\n"));
497 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
498 DIE(("Offset overflow\n"));
500 /* size of the section headers */
501 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
502 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
504 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
505 DIE(("Section headers too large\n"));
507 /* size of the executable's headers */
508 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
510 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
511 // DIE(("SizeOfHeaders is not aligned\n"));
513 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
514 DIE(("The section headers overflow SizeOfHeaders\n"));
516 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
518 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
519 DIE(("Overflow aligning the size of headers\n"));
526 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
527 /* WARNING: piohOptHeader IS NO LONGER USABLE */
528 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
530 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
531 pishSectionHeaders
= NULL
;
535 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
536 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
538 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
539 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
543 * the buffer doesn't contain the section headers, or the alignment is wrong:
544 * read the headers from the file
546 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
547 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
552 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
554 /* read the header from the file */
555 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
557 if(!NT_SUCCESS(nStatus
))
558 DIE(("ReadFile failed with status %08X\n", nStatus
));
562 ASSERT(cbReadSize
> 0);
564 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
566 /* the buffer doesn't contain all the section headers */
567 if(cbReadSize
< cbSectionHeadersSize
)
568 DIE(("The file doesn't contain all of the section headers\n"));
570 pishSectionHeaders
= pData
;
572 /* object still not aligned: copy it to the beginning of the buffer */
573 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
575 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
576 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
577 pishSectionHeaders
= pBuffer
;
582 /* allocate the segments */
583 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
584 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
586 if(ImageSectionObject
->Segments
== NULL
)
587 DIE(("AllocateSegments failed\n"));
589 /* initialize the headers segment */
590 pssSegments
= ImageSectionObject
->Segments
;
592 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
594 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
595 DIE(("Cannot align the size of the section headers\n"));
597 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
598 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
599 DIE(("Cannot align the size of the section headers\n"));
601 pssSegments
[0].Image
.FileOffset
= 0;
602 pssSegments
[0].Protection
= PAGE_READONLY
;
603 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
604 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
605 pssSegments
[0].Image
.VirtualAddress
= 0;
606 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
607 pssSegments
[0].WriteCopy
= TRUE
;
609 /* skip the headers segment */
612 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
614 /* convert the executable sections into segments. See also [1], section 4 */
615 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
617 ULONG nCharacteristics
;
619 /* validate the alignment */
620 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
621 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
623 /* sections must be contiguous, ordered by base address and non-overlapping */
624 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
625 DIE(("Memory gap between section %u and the previous\n", i
));
627 /* ignore explicit BSS sections */
628 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
630 /* validate the alignment */
632 /* Yes, this should be a multiple of FileAlignment, but there's
633 * stuff out there that isn't. We can cope with that
635 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
636 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
639 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
640 // DIE(("PointerToRawData[%u] is not aligned\n", i));
643 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
644 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
648 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
649 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
652 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
654 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
656 /* no explicit protection */
657 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
659 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
660 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
662 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
663 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
665 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
666 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
669 /* see table above */
670 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
671 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
673 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
674 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
676 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
678 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
679 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
680 DIE(("Cannot align the virtual size of section %u\n", i
));
682 if(pssSegments
[i
].Length
.QuadPart
== 0)
683 DIE(("Virtual size of section %u is null\n", i
));
685 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
686 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
688 /* ensure the memory image is no larger than 4GB */
689 nPrevVirtualEndOfSegment
= (ULONG_PTR
)(pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
);
690 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
691 DIE(("The image is too large\n"));
694 if(nSectionAlignment
>= PAGE_SIZE
)
695 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
698 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;
707 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
710 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
711 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
712 * RETURNS: Status of the wait.
715 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
717 LARGE_INTEGER Timeout
;
718 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
720 Timeout
.QuadPart
= -100000000LL; // 10 sec
723 Timeout
.QuadPart
= -100000000; // 10 sec
726 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
731 * FUNCTION: Sets the page op completion event and releases the page op.
732 * ARGUMENTS: PMM_PAGEOP.
733 * RETURNS: In shorter time than it takes you to even read this
734 * description, so don't even think about geting a mug of coffee.
737 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
739 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
740 MmReleasePageOp(PageOp
);
745 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
746 * ARGUMENTS: PFILE_OBJECT to wait for.
747 * RETURNS: Status of the wait.
750 MmspWaitForFileLock(PFILE_OBJECT File
)
752 return STATUS_SUCCESS
;
753 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
758 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
760 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
762 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
763 PMM_SECTION_SEGMENT SectionSegments
;
767 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
768 NrSegments
= ImageSectionObject
->NrSegments
;
769 SectionSegments
= ImageSectionObject
->Segments
;
770 for (i
= 0; i
< NrSegments
; i
++)
772 if (SectionSegments
[i
].ReferenceCount
!= 0)
774 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
775 SectionSegments
[i
].ReferenceCount
);
776 KeBugCheck(MEMORY_MANAGEMENT
);
778 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
780 ExFreePool(ImageSectionObject
->Segments
);
781 ExFreePool(ImageSectionObject
);
782 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
784 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
786 PMM_SECTION_SEGMENT Segment
;
788 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
791 if (Segment
->ReferenceCount
!= 0)
793 DPRINT1("Data segment still referenced\n");
794 KeBugCheck(MEMORY_MANAGEMENT
);
796 MmFreePageTablesSectionSegment(Segment
, NULL
);
798 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
804 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
805 PLARGE_INTEGER Offset
)
809 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
812 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
813 KeBugCheck(MEMORY_MANAGEMENT
);
815 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
817 DPRINT1("Maximum share count reached\n");
818 KeBugCheck(MEMORY_MANAGEMENT
);
820 if (IS_SWAP_FROM_SSE(Entry
))
822 KeBugCheck(MEMORY_MANAGEMENT
);
824 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
825 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
830 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
831 PMM_SECTION_SEGMENT Segment
,
832 PLARGE_INTEGER Offset
,
837 BOOLEAN IsDirectMapped
= FALSE
;
839 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
842 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
843 KeBugCheck(MEMORY_MANAGEMENT
);
845 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
847 DPRINT1("Zero share count for unshare\n");
848 KeBugCheck(MEMORY_MANAGEMENT
);
850 if (IS_SWAP_FROM_SSE(Entry
))
852 KeBugCheck(MEMORY_MANAGEMENT
);
854 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
856 * If we reducing the share count of this entry to zero then set the entry
857 * to zero and tell the cache the page is no longer mapped.
859 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
861 PFILE_OBJECT FileObject
;
865 SWAPENTRY SavedSwapEntry
;
867 BOOLEAN IsImageSection
;
868 LARGE_INTEGER FileOffset
;
870 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
872 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
874 Page
= PFN_FROM_SSE(Entry
);
875 FileObject
= Section
->FileObject
;
876 if (FileObject
!= NULL
&&
877 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
881 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
882 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
885 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
886 IsDirectMapped
= TRUE
;
888 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
.LowPart
, Dirty
);
890 Status
= STATUS_SUCCESS
;
892 if (!NT_SUCCESS(Status
))
894 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
895 KeBugCheck(MEMORY_MANAGEMENT
);
901 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
902 if (SavedSwapEntry
== 0)
905 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
906 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
910 * Try to page out this page and set the swap entry
911 * within the section segment. There exist no rmap entry
912 * for this page. The pager thread can't page out a
913 * page without a rmap entry.
915 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
919 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
922 MmReleasePageMemoryConsumer(MC_USER
, Page
);
928 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
929 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
937 * We hold all locks. Nobody can do something with the current
938 * process and the current segment (also not within an other process).
941 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
942 if (!NT_SUCCESS(Status
))
944 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
945 KeBugCheck(MEMORY_MANAGEMENT
);
948 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
949 MmSetSavedSwapEntryPage(Page
, 0);
951 MmReleasePageMemoryConsumer(MC_USER
, Page
);
955 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
956 KeBugCheck(MEMORY_MANAGEMENT
);
962 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
964 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
967 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
971 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
974 PCACHE_SEGMENT CacheSeg
;
975 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
976 CacheSeg
= CcRosLookupCacheSegment(Bcb
, (ULONG
)(SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
));
979 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
989 MiCopyFromUserPage(PFN_NUMBER DestPage
, PVOID SourceAddress
)
995 ASSERT((ULONG_PTR
)SourceAddress
% PAGE_SIZE
== 0);
996 Process
= PsGetCurrentProcess();
997 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
998 if (TempAddress
== NULL
)
1000 return(STATUS_NO_MEMORY
);
1002 ASSERT((ULONG_PTR
)TempAddress
% PAGE_SIZE
== 0);
1003 RtlCopyMemory(TempAddress
, SourceAddress
, PAGE_SIZE
);
1004 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
1005 return(STATUS_SUCCESS
);
1011 MiReadPage(PMEMORY_AREA MemoryArea
,
1012 ULONG_PTR SegOffset
,
1015 * FUNCTION: Read a page for a section backed memory area.
1017 * MemoryArea - Memory area to read the page for.
1018 * Offset - Offset of the page to read.
1019 * Page - Variable that receives a page contains the read data.
1023 ULONGLONG FileOffset
;
1026 PCACHE_SEGMENT CacheSeg
;
1027 PFILE_OBJECT FileObject
;
1029 ULONG_PTR RawLength
;
1031 BOOLEAN IsImageSection
;
1034 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1035 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1036 RawLength
= (ULONG_PTR
)(MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
);
1037 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1038 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1042 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1045 * If the file system is letting us go directly to the cache and the
1046 * memory area was mapped at an offset in the file which is page aligned
1047 * then get the related cache segment.
1049 if (((FileOffset
% PAGE_SIZE
) == 0) &&
1050 ((SegOffset
+ PAGE_SIZE
<= RawLength
) || !IsImageSection
) &&
1051 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1055 * Get the related cache segment; we use a lower level interface than
1056 * filesystems do because it is safe for us to use an offset with a
1057 * alignment less than the file system block size.
1059 Status
= CcRosGetCacheSegment(Bcb
,
1065 if (!NT_SUCCESS(Status
))
1072 * If the cache segment isn't up to date then call the file
1073 * system to read in the data.
1075 Status
= ReadCacheSegment(CacheSeg
);
1076 if (!NT_SUCCESS(Status
))
1078 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1083 * Retrieve the page from the cache segment that we actually want.
1085 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1086 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1088 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1095 ULONG_PTR CacheSegOffset
;
1098 * Allocate a page, this is rather complicated by the possibility
1099 * we might have to move other things out of memory
1101 MI_SET_USAGE(MI_USAGE_SECTION
);
1102 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1103 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1104 if (!NT_SUCCESS(Status
))
1108 Status
= CcRosGetCacheSegment(Bcb
,
1114 if (!NT_SUCCESS(Status
))
1121 * If the cache segment isn't up to date then call the file
1122 * system to read in the data.
1124 Status
= ReadCacheSegment(CacheSeg
);
1125 if (!NT_SUCCESS(Status
))
1127 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1132 Process
= PsGetCurrentProcess();
1133 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1134 CacheSegOffset
= (ULONG_PTR
)(BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
);
1135 Length
= RawLength
- SegOffset
;
1136 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1138 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1140 else if (CacheSegOffset
>= PAGE_SIZE
)
1142 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1146 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1147 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1148 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1149 Status
= CcRosGetCacheSegment(Bcb
,
1150 (ULONG
)(FileOffset
+ CacheSegOffset
),
1155 if (!NT_SUCCESS(Status
))
1162 * If the cache segment isn't up to date then call the file
1163 * system to read in the data.
1165 Status
= ReadCacheSegment(CacheSeg
);
1166 if (!NT_SUCCESS(Status
))
1168 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1172 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1173 if (Length
< PAGE_SIZE
)
1175 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1179 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1182 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1183 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1185 return(STATUS_SUCCESS
);
1190 MiReadPage(PMEMORY_AREA MemoryArea
,
1194 * FUNCTION: Read a page for a section backed memory area.
1196 * MemoryArea - Memory area to read the page for.
1197 * Offset - Offset of the page to read.
1198 * Page - Variable that receives a page contains the read data.
1201 MM_REQUIRED_RESOURCES Resources
;
1204 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1206 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1207 Resources
.FileOffset
.QuadPart
= SegOffset
+
1208 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1209 Resources
.Consumer
= MC_USER
;
1210 Resources
.Amount
= PAGE_SIZE
;
1212 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]);
1214 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1215 *Page
= Resources
.Page
[0];
1222 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1223 MEMORY_AREA
* MemoryArea
,
1227 LARGE_INTEGER Offset
;
1230 PROS_SECTION_OBJECT Section
;
1231 PMM_SECTION_SEGMENT Segment
;
1237 BOOLEAN HasSwapEntry
;
1239 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1242 * There is a window between taking the page fault and locking the
1243 * address space when another thread could load the page so we check
1246 if (MmIsPagePresent(Process
, Address
))
1248 return(STATUS_SUCCESS
);
1252 * Check for the virtual memory area being deleted.
1254 if (MemoryArea
->DeleteInProgress
)
1256 return(STATUS_UNSUCCESSFUL
);
1259 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1260 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1261 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1263 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1264 Section
= MemoryArea
->Data
.SectionData
.Section
;
1265 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1266 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1268 ASSERT(Region
!= NULL
);
1272 MmLockSectionSegment(Segment
);
1275 * Check if this page needs to be mapped COW
1277 if ((Segment
->WriteCopy
) &&
1278 (Region
->Protect
== PAGE_READWRITE
||
1279 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1281 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1285 Attributes
= Region
->Protect
;
1289 * Get or create a page operation descriptor
1291 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
.LowPart
, MM_PAGEOP_PAGEIN
, FALSE
);
1294 DPRINT1("MmGetPageOp failed\n");
1295 KeBugCheck(MEMORY_MANAGEMENT
);
1299 * Check if someone else is already handling this fault, if so wait
1302 if (PageOp
->Thread
!= PsGetCurrentThread())
1304 MmUnlockSectionSegment(Segment
);
1305 MmUnlockAddressSpace(AddressSpace
);
1306 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1308 * Check for various strange conditions
1310 if (Status
!= STATUS_SUCCESS
)
1312 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1313 KeBugCheck(MEMORY_MANAGEMENT
);
1315 if (PageOp
->Status
== STATUS_PENDING
)
1317 DPRINT1("Woke for page op before completion\n");
1318 KeBugCheck(MEMORY_MANAGEMENT
);
1320 MmLockAddressSpace(AddressSpace
);
1322 * If this wasn't a pagein then restart the operation
1324 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
1326 MmspCompleteAndReleasePageOp(PageOp
);
1327 DPRINT("Address 0x%.8X\n", Address
);
1328 return(STATUS_MM_RESTART_OPERATION
);
1332 * If the thread handling this fault has failed then we don't retry
1334 if (!NT_SUCCESS(PageOp
->Status
))
1336 Status
= PageOp
->Status
;
1337 MmspCompleteAndReleasePageOp(PageOp
);
1338 DPRINT("Address 0x%.8X\n", Address
);
1341 MmLockSectionSegment(Segment
);
1343 * If the completed fault was for another address space then set the
1346 if (!MmIsPagePresent(Process
, Address
))
1348 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1349 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1351 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
1354 * The page was a private page in another or in our address space
1356 MmUnlockSectionSegment(Segment
);
1357 MmspCompleteAndReleasePageOp(PageOp
);
1358 return(STATUS_MM_RESTART_OPERATION
);
1361 Page
= PFN_FROM_SSE(Entry
);
1363 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1365 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
1366 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
1368 Status
= MmCreateVirtualMapping(Process
,
1373 if (!NT_SUCCESS(Status
))
1375 DPRINT1("Unable to create virtual mapping\n");
1376 KeBugCheck(MEMORY_MANAGEMENT
);
1378 MmInsertRmap(Page
, Process
, Address
);
1380 MmUnlockSectionSegment(Segment
);
1381 PageOp
->Status
= STATUS_SUCCESS
;
1382 MmspCompleteAndReleasePageOp(PageOp
);
1383 DPRINT("Address 0x%.8X\n", Address
);
1384 return(STATUS_SUCCESS
);
1387 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1391 * Must be private page we have swapped out.
1393 SWAPENTRY SwapEntry
;
1398 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1400 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1401 KeBugCheck(MEMORY_MANAGEMENT
);
1404 MmUnlockSectionSegment(Segment
);
1405 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1407 MmUnlockAddressSpace(AddressSpace
);
1408 MI_SET_USAGE(MI_USAGE_SECTION
);
1409 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1410 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1411 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1412 if (!NT_SUCCESS(Status
))
1414 KeBugCheck(MEMORY_MANAGEMENT
);
1417 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1418 if (!NT_SUCCESS(Status
))
1420 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1421 KeBugCheck(MEMORY_MANAGEMENT
);
1423 MmLockAddressSpace(AddressSpace
);
1424 Status
= MmCreateVirtualMapping(Process
,
1429 if (!NT_SUCCESS(Status
))
1431 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1432 KeBugCheck(MEMORY_MANAGEMENT
);
1437 * Store the swap entry for later use.
1439 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1442 * Add the page to the process's working set
1444 MmInsertRmap(Page
, Process
, Address
);
1446 * Finish the operation
1448 PageOp
->Status
= STATUS_SUCCESS
;
1449 MmspCompleteAndReleasePageOp(PageOp
);
1450 DPRINT("Address 0x%.8X\n", Address
);
1451 return(STATUS_SUCCESS
);
1455 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1457 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1459 MmUnlockSectionSegment(Segment
);
1461 * Just map the desired physical page
1463 Page
= (PFN_NUMBER
)(Offset
.QuadPart
>> PAGE_SHIFT
);
1464 Status
= MmCreateVirtualMappingUnsafe(Process
,
1469 if (!NT_SUCCESS(Status
))
1471 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1472 KeBugCheck(MEMORY_MANAGEMENT
);
1477 * Cleanup and release locks
1479 PageOp
->Status
= STATUS_SUCCESS
;
1480 MmspCompleteAndReleasePageOp(PageOp
);
1481 DPRINT("Address 0x%.8X\n", Address
);
1482 return(STATUS_SUCCESS
);
1486 * Map anonymous memory for BSS sections
1488 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1490 MmUnlockSectionSegment(Segment
);
1491 MI_SET_USAGE(MI_USAGE_SECTION
);
1492 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1493 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1494 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1495 if (!NT_SUCCESS(Status
))
1497 MmUnlockAddressSpace(AddressSpace
);
1498 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1499 MmLockAddressSpace(AddressSpace
);
1501 if (!NT_SUCCESS(Status
))
1503 KeBugCheck(MEMORY_MANAGEMENT
);
1505 Status
= MmCreateVirtualMapping(Process
,
1510 if (!NT_SUCCESS(Status
))
1512 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1513 KeBugCheck(MEMORY_MANAGEMENT
);
1516 MmInsertRmap(Page
, Process
, Address
);
1519 * Cleanup and release locks
1521 PageOp
->Status
= STATUS_SUCCESS
;
1522 MmspCompleteAndReleasePageOp(PageOp
);
1523 DPRINT("Address 0x%.8X\n", Address
);
1524 return(STATUS_SUCCESS
);
1528 * Get the entry corresponding to the offset within the section
1530 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1535 * If the entry is zero (and it can't change because we have
1536 * locked the segment) then we need to load the page.
1540 * Release all our locks and read in the page from disk
1542 MmUnlockSectionSegment(Segment
);
1543 MmUnlockAddressSpace(AddressSpace
);
1545 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1546 ((Offset
.QuadPart
>= (LONGLONG
)PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) &&
1547 (Section
->AllocationAttributes
& SEC_IMAGE
))))
1549 MI_SET_USAGE(MI_USAGE_SECTION
);
1550 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1551 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1552 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1553 if (!NT_SUCCESS(Status
))
1555 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1561 Status
= MiReadPage(MemoryArea
, (ULONG_PTR
)Offset
.QuadPart
, &Page
);
1562 if (!NT_SUCCESS(Status
))
1564 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1567 if (!NT_SUCCESS(Status
))
1570 * FIXME: What do we know in this case?
1573 * Cleanup and release locks
1575 MmLockAddressSpace(AddressSpace
);
1576 PageOp
->Status
= Status
;
1577 MmspCompleteAndReleasePageOp(PageOp
);
1578 DPRINT("Address 0x%.8X\n", Address
);
1582 * Relock the address space and segment
1584 MmLockAddressSpace(AddressSpace
);
1585 MmLockSectionSegment(Segment
);
1588 * Check the entry. No one should change the status of a page
1589 * that has a pending page-in.
1591 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1592 if (Entry
!= Entry1
)
1594 DPRINT1("Someone changed ppte entry while we slept\n");
1595 KeBugCheck(MEMORY_MANAGEMENT
);
1599 * Mark the offset within the section as having valid, in-memory
1602 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1603 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1604 MmUnlockSectionSegment(Segment
);
1606 Status
= MmCreateVirtualMapping(Process
,
1611 if (!NT_SUCCESS(Status
))
1613 DPRINT1("Unable to create virtual mapping\n");
1614 KeBugCheck(MEMORY_MANAGEMENT
);
1616 MmInsertRmap(Page
, Process
, Address
);
1618 PageOp
->Status
= STATUS_SUCCESS
;
1619 MmspCompleteAndReleasePageOp(PageOp
);
1620 DPRINT("Address 0x%.8X\n", Address
);
1621 return(STATUS_SUCCESS
);
1623 else if (IS_SWAP_FROM_SSE(Entry
))
1625 SWAPENTRY SwapEntry
;
1627 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1630 * Release all our locks and read in the page from disk
1632 MmUnlockSectionSegment(Segment
);
1634 MmUnlockAddressSpace(AddressSpace
);
1635 MI_SET_USAGE(MI_USAGE_SECTION
);
1636 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1637 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1638 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1639 if (!NT_SUCCESS(Status
))
1641 KeBugCheck(MEMORY_MANAGEMENT
);
1644 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1645 if (!NT_SUCCESS(Status
))
1647 KeBugCheck(MEMORY_MANAGEMENT
);
1651 * Relock the address space and segment
1653 MmLockAddressSpace(AddressSpace
);
1654 MmLockSectionSegment(Segment
);
1657 * Check the entry. No one should change the status of a page
1658 * that has a pending page-in.
1660 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1661 if (Entry
!= Entry1
)
1663 DPRINT1("Someone changed ppte entry while we slept\n");
1664 KeBugCheck(MEMORY_MANAGEMENT
);
1668 * Mark the offset within the section as having valid, in-memory
1671 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1672 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1673 MmUnlockSectionSegment(Segment
);
1676 * Save the swap entry.
1678 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1679 Status
= MmCreateVirtualMapping(Process
,
1684 if (!NT_SUCCESS(Status
))
1686 DPRINT1("Unable to create virtual mapping\n");
1687 KeBugCheck(MEMORY_MANAGEMENT
);
1689 MmInsertRmap(Page
, Process
, Address
);
1690 PageOp
->Status
= STATUS_SUCCESS
;
1691 MmspCompleteAndReleasePageOp(PageOp
);
1692 DPRINT("Address 0x%.8X\n", Address
);
1693 return(STATUS_SUCCESS
);
1698 * If the section offset is already in-memory and valid then just
1699 * take another reference to the page
1702 Page
= PFN_FROM_SSE(Entry
);
1704 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1705 MmUnlockSectionSegment(Segment
);
1707 Status
= MmCreateVirtualMapping(Process
,
1712 if (!NT_SUCCESS(Status
))
1714 DPRINT1("Unable to create virtual mapping\n");
1715 KeBugCheck(MEMORY_MANAGEMENT
);
1717 MmInsertRmap(Page
, Process
, Address
);
1718 PageOp
->Status
= STATUS_SUCCESS
;
1719 MmspCompleteAndReleasePageOp(PageOp
);
1720 DPRINT("Address 0x%.8X\n", Address
);
1721 return(STATUS_SUCCESS
);
1727 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1728 MEMORY_AREA
* MemoryArea
,
1731 PMM_SECTION_SEGMENT Segment
;
1732 PROS_SECTION_OBJECT Section
;
1737 LARGE_INTEGER Offset
;
1741 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1743 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
);
1746 * Check if the page has already been set readwrite
1748 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1750 DPRINT("Address 0x%.8X\n", Address
);
1751 return(STATUS_SUCCESS
);
1755 * Find the offset of the page
1757 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1758 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1759 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1761 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1762 Section
= MemoryArea
->Data
.SectionData
.Section
;
1763 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1764 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1766 ASSERT(Region
!= NULL
);
1770 MmLockSectionSegment(Segment
);
1772 OldPage
= MmGetPfnForProcess(Process
, Address
);
1773 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1775 MmUnlockSectionSegment(Segment
);
1778 * Check if we are doing COW
1780 if (!((Segment
->WriteCopy
) &&
1781 (Region
->Protect
== PAGE_READWRITE
||
1782 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1784 DPRINT("Address 0x%.8X\n", Address
);
1785 return(STATUS_ACCESS_VIOLATION
);
1788 if (IS_SWAP_FROM_SSE(Entry
) ||
1789 PFN_FROM_SSE(Entry
) != OldPage
)
1791 /* This is a private page. We must only change the page protection. */
1792 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1793 return(STATUS_SUCCESS
);
1797 DPRINT("OldPage == 0!\n");
1800 * Get or create a pageop
1802 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
.LowPart
,
1803 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1806 DPRINT1("MmGetPageOp failed\n");
1807 KeBugCheck(MEMORY_MANAGEMENT
);
1811 * Wait for any other operations to complete
1813 if (PageOp
->Thread
!= PsGetCurrentThread())
1815 MmUnlockAddressSpace(AddressSpace
);
1816 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1818 * Check for various strange conditions
1820 if (Status
== STATUS_TIMEOUT
)
1822 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1823 KeBugCheck(MEMORY_MANAGEMENT
);
1825 if (PageOp
->Status
== STATUS_PENDING
)
1827 DPRINT1("Woke for page op before completion\n");
1828 KeBugCheck(MEMORY_MANAGEMENT
);
1831 * Restart the operation
1833 MmLockAddressSpace(AddressSpace
);
1834 MmspCompleteAndReleasePageOp(PageOp
);
1835 DPRINT("Address 0x%.8X\n", Address
);
1836 return(STATUS_MM_RESTART_OPERATION
);
1840 * Release locks now we have the pageop
1842 MmUnlockAddressSpace(AddressSpace
);
1847 MI_SET_USAGE(MI_USAGE_SECTION
);
1848 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1849 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1850 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1851 if (!NT_SUCCESS(Status
))
1853 KeBugCheck(MEMORY_MANAGEMENT
);
1859 MiCopyFromUserPage(NewPage
, PAddress
);
1861 MmLockAddressSpace(AddressSpace
);
1863 * Delete the old entry.
1865 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1868 * Set the PTE to point to the new page
1870 Status
= MmCreateVirtualMapping(Process
,
1875 if (!NT_SUCCESS(Status
))
1877 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1878 KeBugCheck(MEMORY_MANAGEMENT
);
1881 if (!NT_SUCCESS(Status
))
1883 DPRINT1("Unable to create virtual mapping\n");
1884 KeBugCheck(MEMORY_MANAGEMENT
);
1888 * Unshare the old page.
1890 MmDeleteRmap(OldPage
, Process
, PAddress
);
1891 MmInsertRmap(NewPage
, Process
, PAddress
);
1892 MmLockSectionSegment(Segment
);
1893 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
);
1894 MmUnlockSectionSegment(Segment
);
1896 PageOp
->Status
= STATUS_SUCCESS
;
1897 MmspCompleteAndReleasePageOp(PageOp
);
1898 DPRINT("Address 0x%.8X\n", Address
);
1899 return(STATUS_SUCCESS
);
1903 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1905 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1909 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1912 MmLockAddressSpace(&Process
->Vm
);
1915 MmDeleteVirtualMapping(Process
,
1922 PageOutContext
->WasDirty
= TRUE
;
1924 if (!PageOutContext
->Private
)
1926 MmLockSectionSegment(PageOutContext
->Segment
);
1927 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1928 PageOutContext
->Segment
,
1929 &PageOutContext
->Offset
,
1930 PageOutContext
->WasDirty
,
1932 MmUnlockSectionSegment(PageOutContext
->Segment
);
1936 MmUnlockAddressSpace(&Process
->Vm
);
1939 if (PageOutContext
->Private
)
1941 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1944 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1949 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1950 MEMORY_AREA
* MemoryArea
,
1955 MM_SECTION_PAGEOUT_CONTEXT Context
;
1956 SWAPENTRY SwapEntry
;
1958 ULONGLONG FileOffset
;
1960 PFILE_OBJECT FileObject
;
1964 BOOLEAN DirectMapped
;
1965 BOOLEAN IsImageSection
;
1966 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1969 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1972 * Get the segment and section.
1974 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1975 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1976 Context
.CallingProcess
= Process
;
1978 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1979 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1980 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1982 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1984 FileObject
= Context
.Section
->FileObject
;
1985 DirectMapped
= FALSE
;
1988 if (FileObject
!= NULL
&&
1989 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1991 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1994 * If the file system is letting us go directly to the cache and the
1995 * memory area was mapped at an offset in the file which is page aligned
1996 * then note this is a direct mapped page.
1998 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1999 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2001 DirectMapped
= TRUE
;
2008 * This should never happen since mappings of physical memory are never
2009 * placed in the rmap lists.
2011 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2013 DPRINT1("Trying to page out from physical memory section address 0x%X "
2014 "process %d\n", Address
,
2015 Process
? Process
->UniqueProcessId
: 0);
2016 KeBugCheck(MEMORY_MANAGEMENT
);
2020 * Get the section segment entry and the physical address.
2022 if (!MmIsPagePresent(Process
, Address
))
2024 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2025 Process
? Process
->UniqueProcessId
: 0, Address
);
2026 KeBugCheck(MEMORY_MANAGEMENT
);
2028 Page
= MmGetPfnForProcess(Process
, Address
);
2029 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2032 * Check the reference count to ensure this page can be paged out
2034 if (MmGetReferenceCountPage(Page
) != 1)
2036 DPRINT("Cannot page out locked section page: 0x%p (RefCount: %d)\n",
2037 Page
, MmGetReferenceCountPage(Page
));
2038 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2039 MmspCompleteAndReleasePageOp(PageOp
);
2040 return STATUS_UNSUCCESSFUL
;
2044 * Prepare the context structure for the rmap delete call.
2046 MmLockSectionSegment(Context
.Segment
);
2047 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2048 MmUnlockSectionSegment(Context
.Segment
);
2049 Context
.WasDirty
= FALSE
;
2050 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2051 IS_SWAP_FROM_SSE(Entry
) ||
2052 PFN_FROM_SSE(Entry
) != Page
)
2054 Context
.Private
= TRUE
;
2058 Context
.Private
= FALSE
;
2062 * Take an additional reference to the page or the cache segment.
2064 if (DirectMapped
&& !Context
.Private
)
2066 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
2068 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2069 KeBugCheck(MEMORY_MANAGEMENT
);
2074 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
2075 MmReferencePage(Page
);
2076 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
2079 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2080 MmLockSectionSegment(Context
.Segment
);
2081 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2082 MmUnlockSectionSegment(Context
.Segment
);
2085 * If this wasn't a private page then we should have reduced the entry to
2086 * zero by deleting all the rmaps.
2088 if (!Context
.Private
&& Entry
!= 0)
2090 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2091 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2093 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2098 * If the page wasn't dirty then we can just free it as for a readonly page.
2099 * Since we unmapped all the mappings above we know it will not suddenly
2101 * If the page is from a pagefile section and has no swap entry,
2102 * we can't free the page at this point.
2104 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2105 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2107 if (Context
.Private
)
2109 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
2110 Context
.WasDirty
? "dirty" : "clean", Address
);
2111 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2113 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2115 MmSetSavedSwapEntryPage(Page
, 0);
2116 MmLockSectionSegment(Context
.Segment
);
2117 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2118 MmUnlockSectionSegment(Context
.Segment
);
2119 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2120 PageOp
->Status
= STATUS_SUCCESS
;
2121 MmspCompleteAndReleasePageOp(PageOp
);
2122 return(STATUS_SUCCESS
);
2125 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2127 if (Context
.Private
)
2129 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2130 Context
.WasDirty
? "dirty" : "clean", Address
);
2131 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2133 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2135 MmSetSavedSwapEntryPage(Page
, 0);
2138 MmLockSectionSegment(Context
.Segment
);
2139 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2140 MmUnlockSectionSegment(Context
.Segment
);
2142 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2143 PageOp
->Status
= STATUS_SUCCESS
;
2144 MmspCompleteAndReleasePageOp(PageOp
);
2145 return(STATUS_SUCCESS
);
2148 else if (!Context
.Private
&& DirectMapped
)
2152 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2154 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2157 Status
= CcRosUnmapCacheSegment(Bcb
, (ULONG
)FileOffset
, FALSE
);
2159 Status
= STATUS_SUCCESS
;
2162 if (!NT_SUCCESS(Status
))
2164 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2165 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Bcb
, (ULONG_PTR
)FileOffset
, (ULONG_PTR
)Address
);
2168 PageOp
->Status
= STATUS_SUCCESS
;
2169 MmspCompleteAndReleasePageOp(PageOp
);
2170 return(STATUS_SUCCESS
);
2172 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2176 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2178 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2180 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2181 PageOp
->Status
= STATUS_SUCCESS
;
2182 MmspCompleteAndReleasePageOp(PageOp
);
2183 return(STATUS_SUCCESS
);
2185 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2187 DPRINT1("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2188 MmSetSavedSwapEntryPage(Page
, 0);
2189 MmLockAddressSpace(AddressSpace
);
2190 Status
= MmCreatePageFileMapping(Process
,
2193 MmUnlockAddressSpace(AddressSpace
);
2194 if (!NT_SUCCESS(Status
))
2196 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2197 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2199 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2200 PageOp
->Status
= STATUS_SUCCESS
;
2201 MmspCompleteAndReleasePageOp(PageOp
);
2202 return(STATUS_SUCCESS
);
2206 * If necessary, allocate an entry in the paging file for this page
2210 SwapEntry
= MmAllocSwapPage();
2213 MmShowOutOfSpaceMessagePagingFile();
2214 MmLockAddressSpace(AddressSpace
);
2216 * For private pages restore the old mappings.
2218 if (Context
.Private
)
2220 Status
= MmCreateVirtualMapping(Process
,
2222 MemoryArea
->Protect
,
2225 MmSetDirtyPage(Process
, Address
);
2234 * For non-private pages if the page wasn't direct mapped then
2235 * set it back into the section segment entry so we don't loose
2236 * our copy. Otherwise it will be handled by the cache manager.
2238 Status
= MmCreateVirtualMapping(Process
,
2240 MemoryArea
->Protect
,
2243 MmSetDirtyPage(Process
, Address
);
2247 // If we got here, the previous entry should have been a wait
2248 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2249 MmLockSectionSegment(Context
.Segment
);
2250 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2251 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2252 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2253 MmUnlockSectionSegment(Context
.Segment
);
2255 MmUnlockAddressSpace(AddressSpace
);
2256 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2257 MmspCompleteAndReleasePageOp(PageOp
);
2258 return(STATUS_PAGEFILE_QUOTA
);
2263 * Write the page to the pagefile
2265 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2266 if (!NT_SUCCESS(Status
))
2268 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2271 * As above: undo our actions.
2272 * FIXME: Also free the swap page.
2274 MmLockAddressSpace(AddressSpace
);
2275 if (Context
.Private
)
2277 Status
= MmCreateVirtualMapping(Process
,
2279 MemoryArea
->Protect
,
2282 MmSetDirtyPage(Process
, Address
);
2289 Status
= MmCreateVirtualMapping(Process
,
2291 MemoryArea
->Protect
,
2294 MmSetDirtyPage(Process
, Address
);
2298 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2299 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2301 MmUnlockAddressSpace(AddressSpace
);
2302 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2303 MmspCompleteAndReleasePageOp(PageOp
);
2304 return(STATUS_UNSUCCESSFUL
);
2308 * Otherwise we have succeeded.
2310 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2311 MmLockSectionSegment(Context
.Segment
);
2312 MmSetSavedSwapEntryPage(Page
, 0);
2313 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2314 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2316 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2320 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2323 if (Context
.Private
)
2325 MmLockAddressSpace(AddressSpace
);
2326 Status
= MmCreatePageFileMapping(Process
,
2329 MmUnlockAddressSpace(AddressSpace
);
2330 if (!NT_SUCCESS(Status
))
2332 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2333 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2338 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2339 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2342 MmUnlockSectionSegment(Context
.Segment
);
2343 PageOp
->Status
= STATUS_SUCCESS
;
2344 MmspCompleteAndReleasePageOp(PageOp
);
2345 return(STATUS_SUCCESS
);
2350 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2351 PMEMORY_AREA MemoryArea
,
2355 LARGE_INTEGER Offset
;
2356 PROS_SECTION_OBJECT Section
;
2357 PMM_SECTION_SEGMENT Segment
;
2359 SWAPENTRY SwapEntry
;
2363 PFILE_OBJECT FileObject
;
2365 BOOLEAN DirectMapped
;
2366 BOOLEAN IsImageSection
;
2367 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2369 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2371 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2372 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2375 * Get the segment and section.
2377 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2378 Section
= MemoryArea
->Data
.SectionData
.Section
;
2379 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2381 FileObject
= Section
->FileObject
;
2382 DirectMapped
= FALSE
;
2383 if (FileObject
!= NULL
&&
2384 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2386 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2389 * If the file system is letting us go directly to the cache and the
2390 * memory area was mapped at an offset in the file which is page aligned
2391 * then note this is a direct mapped page.
2393 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2394 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2396 DirectMapped
= TRUE
;
2401 * This should never happen since mappings of physical memory are never
2402 * placed in the rmap lists.
2404 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2406 DPRINT1("Trying to write back page from physical memory mapped at %X "
2407 "process %d\n", Address
,
2408 Process
? Process
->UniqueProcessId
: 0);
2409 KeBugCheck(MEMORY_MANAGEMENT
);
2413 * Get the section segment entry and the physical address.
2415 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2416 if (!MmIsPagePresent(Process
, Address
))
2418 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2419 Process
? Process
->UniqueProcessId
: 0, Address
);
2420 KeBugCheck(MEMORY_MANAGEMENT
);
2422 Page
= MmGetPfnForProcess(Process
, Address
);
2423 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2426 * Check for a private (COWed) page.
2428 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2429 IS_SWAP_FROM_SSE(Entry
) ||
2430 PFN_FROM_SSE(Entry
) != Page
)
2440 * Speculatively set all mappings of the page to clean.
2442 MmSetCleanAllRmaps(Page
);
2445 * If this page was direct mapped from the cache then the cache manager
2446 * will take care of writing it back to disk.
2448 if (DirectMapped
&& !Private
)
2450 ASSERT(SwapEntry
== 0);
2452 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)(Offset
.QuadPart
+ Segment
->Image
.FileOffset
));
2454 PageOp
->Status
= STATUS_SUCCESS
;
2455 MmspCompleteAndReleasePageOp(PageOp
);
2456 return(STATUS_SUCCESS
);
2460 * If necessary, allocate an entry in the paging file for this page
2464 SwapEntry
= MmAllocSwapPage();
2467 MmSetDirtyAllRmaps(Page
);
2468 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2469 MmspCompleteAndReleasePageOp(PageOp
);
2470 return(STATUS_PAGEFILE_QUOTA
);
2472 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2476 * Write the page to the pagefile
2478 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2479 if (!NT_SUCCESS(Status
))
2481 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2483 MmSetDirtyAllRmaps(Page
);
2484 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2485 MmspCompleteAndReleasePageOp(PageOp
);
2486 return(STATUS_UNSUCCESSFUL
);
2490 * Otherwise we have succeeded.
2492 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2493 PageOp
->Status
= STATUS_SUCCESS
;
2494 MmspCompleteAndReleasePageOp(PageOp
);
2495 return(STATUS_SUCCESS
);
2499 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2507 PMEMORY_AREA MemoryArea
;
2508 PMM_SECTION_SEGMENT Segment
;
2509 BOOLEAN DoCOW
= FALSE
;
2511 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2513 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2514 ASSERT(MemoryArea
!= NULL
);
2515 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2516 MmLockSectionSegment(Segment
);
2518 if ((Segment
->WriteCopy
) &&
2519 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2524 if (OldProtect
!= NewProtect
)
2526 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2528 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2529 ULONG Protect
= NewProtect
;
2532 * If we doing COW for this segment then check if the page is
2535 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2537 LARGE_INTEGER Offset
;
2541 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2542 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2543 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2544 Page
= MmGetPfnForProcess(Process
, Address
);
2546 Protect
= PAGE_READONLY
;
2547 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2548 IS_SWAP_FROM_SSE(Entry
) ||
2549 PFN_FROM_SSE(Entry
) != Page
)
2551 Protect
= NewProtect
;
2555 if (MmIsPagePresent(Process
, Address
))
2557 MmSetPageProtect(Process
, Address
,
2563 MmUnlockSectionSegment(Segment
);
2568 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2569 PMEMORY_AREA MemoryArea
,
2577 ULONG_PTR MaxLength
;
2579 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2580 if (Length
> MaxLength
)
2581 Length
= (ULONG
)MaxLength
;
2583 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2584 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2586 ASSERT(Region
!= NULL
);
2588 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2589 Region
->Protect
!= Protect
)
2591 return STATUS_INVALID_PAGE_PROTECTION
;
2594 *OldProtect
= Region
->Protect
;
2595 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2596 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2597 BaseAddress
, Length
, Region
->Type
, Protect
,
2598 MmAlterViewAttributes
);
2604 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2606 PMEMORY_BASIC_INFORMATION Info
,
2607 PSIZE_T ResultLength
)
2610 PVOID RegionBaseAddress
;
2611 PROS_SECTION_OBJECT Section
;
2612 PMM_SECTION_SEGMENT Segment
;
2614 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2615 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2616 Address
, &RegionBaseAddress
);
2619 return STATUS_UNSUCCESSFUL
;
2622 Section
= MemoryArea
->Data
.SectionData
.Section
;
2623 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2625 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2626 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2627 Info
->Type
= MEM_IMAGE
;
2631 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2632 Info
->Type
= MEM_MAPPED
;
2634 Info
->BaseAddress
= RegionBaseAddress
;
2635 Info
->AllocationProtect
= MemoryArea
->Protect
;
2636 Info
->RegionSize
= Region
->Length
;
2637 Info
->State
= MEM_COMMIT
;
2638 Info
->Protect
= Region
->Protect
;
2640 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2641 return(STATUS_SUCCESS
);
2646 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2649 LARGE_INTEGER Offset
;
2651 SWAPENTRY SavedSwapEntry
;
2656 MmLockSectionSegment(Segment
);
2658 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2659 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2661 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2664 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2665 if (IS_SWAP_FROM_SSE(Entry
))
2667 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2671 Page
= PFN_FROM_SSE(Entry
);
2672 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2673 if (SavedSwapEntry
!= 0)
2675 MmSetSavedSwapEntryPage(Page
, 0);
2676 MmFreeSwapPage(SavedSwapEntry
);
2678 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2683 MmUnlockSectionSegment(Segment
);
2687 MmpDeleteSection(PVOID ObjectBody
)
2689 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2691 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2692 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2697 PMM_SECTION_SEGMENT SectionSegments
;
2700 * NOTE: Section->ImageSection can be NULL for short time
2701 * during the section creating. If we fail for some reason
2702 * until the image section is properly initialized we shouldn't
2703 * process further here.
2705 if (Section
->ImageSection
== NULL
)
2708 SectionSegments
= Section
->ImageSection
->Segments
;
2709 NrSegments
= Section
->ImageSection
->NrSegments
;
2711 for (i
= 0; i
< NrSegments
; i
++)
2713 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2715 MmLockSectionSegment(&SectionSegments
[i
]);
2717 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2718 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2720 MmUnlockSectionSegment(&SectionSegments
[i
]);
2723 MmpFreePageFileSegment(&SectionSegments
[i
]);
2729 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2732 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2735 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2737 DPRINT("Freeing section segment\n");
2738 Section
->Segment
= NULL
;
2739 MmFinalizeSegment(Segment
);
2743 DPRINT("RefCount %d\n", RefCount
);
2750 * NOTE: Section->Segment can be NULL for short time
2751 * during the section creating.
2753 if (Section
->Segment
== NULL
)
2756 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2758 MmpFreePageFileSegment(Section
->Segment
);
2759 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2760 ExFreePool(Section
->Segment
);
2761 Section
->Segment
= NULL
;
2765 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2768 if (Section
->FileObject
!= NULL
)
2771 CcRosDereferenceCache(Section
->FileObject
);
2773 ObDereferenceObject(Section
->FileObject
);
2774 Section
->FileObject
= NULL
;
2779 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2781 IN ACCESS_MASK GrantedAccess
,
2782 IN ULONG ProcessHandleCount
,
2783 IN ULONG SystemHandleCount
)
2785 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2786 Object
, ProcessHandleCount
);
2792 MmCreatePhysicalMemorySection(VOID
)
2794 PROS_SECTION_OBJECT PhysSection
;
2796 OBJECT_ATTRIBUTES Obj
;
2797 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2798 LARGE_INTEGER SectionSize
;
2802 * Create the section mapping physical memory
2804 SectionSize
.QuadPart
= 0xFFFFFFFF;
2805 InitializeObjectAttributes(&Obj
,
2810 Status
= MmCreateSection((PVOID
)&PhysSection
,
2814 PAGE_EXECUTE_READWRITE
,
2818 if (!NT_SUCCESS(Status
))
2820 DPRINT1("Failed to create PhysicalMemory section\n");
2821 KeBugCheck(MEMORY_MANAGEMENT
);
2823 Status
= ObInsertObject(PhysSection
,
2829 if (!NT_SUCCESS(Status
))
2831 ObDereferenceObject(PhysSection
);
2833 ObCloseHandle(Handle
, KernelMode
);
2834 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2835 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2837 return(STATUS_SUCCESS
);
2843 MmInitSectionImplementation(VOID
)
2845 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2846 UNICODE_STRING Name
;
2848 DPRINT("Creating Section Object Type\n");
2850 /* Initialize the section based root */
2851 ASSERT(MmSectionBasedRoot
.NumberGenericTableElements
== 0);
2852 MmSectionBasedRoot
.BalancedRoot
.u1
.Parent
= &MmSectionBasedRoot
.BalancedRoot
;
2854 /* Initialize the Section object type */
2855 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2856 RtlInitUnicodeString(&Name
, L
"Section");
2857 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2858 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2859 ObjectTypeInitializer
.PoolType
= PagedPool
;
2860 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2861 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2862 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2863 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2864 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2865 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2867 MmCreatePhysicalMemorySection();
2869 return(STATUS_SUCCESS
);
2874 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2875 ACCESS_MASK DesiredAccess
,
2876 POBJECT_ATTRIBUTES ObjectAttributes
,
2877 PLARGE_INTEGER UMaximumSize
,
2878 ULONG SectionPageProtection
,
2879 ULONG AllocationAttributes
)
2881 * Create a section which is backed by the pagefile
2884 LARGE_INTEGER MaximumSize
;
2885 PROS_SECTION_OBJECT Section
;
2886 PMM_SECTION_SEGMENT Segment
;
2889 if (UMaximumSize
== NULL
)
2891 return(STATUS_UNSUCCESSFUL
);
2893 MaximumSize
= *UMaximumSize
;
2896 * Create the section
2898 Status
= ObCreateObject(ExGetPreviousMode(),
2899 MmSectionObjectType
,
2901 ExGetPreviousMode(),
2903 sizeof(ROS_SECTION_OBJECT
),
2906 (PVOID
*)(PVOID
)&Section
);
2907 if (!NT_SUCCESS(Status
))
2915 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2916 Section
->Type
= 'SC';
2917 Section
->Size
= 'TN';
2918 Section
->SectionPageProtection
= SectionPageProtection
;
2919 Section
->AllocationAttributes
= AllocationAttributes
;
2920 Section
->MaximumSize
= MaximumSize
;
2921 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2922 TAG_MM_SECTION_SEGMENT
);
2923 if (Segment
== NULL
)
2925 ObDereferenceObject(Section
);
2926 return(STATUS_NO_MEMORY
);
2928 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2929 Section
->Segment
= Segment
;
2930 Segment
->ReferenceCount
= 1;
2931 ExInitializeFastMutex(&Segment
->Lock
);
2932 Segment
->Image
.FileOffset
= 0;
2933 Segment
->Protection
= SectionPageProtection
;
2934 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2935 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2936 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2937 Segment
->WriteCopy
= FALSE
;
2938 Segment
->Image
.VirtualAddress
= 0;
2939 Segment
->Image
.Characteristics
= 0;
2940 *SectionObject
= Section
;
2941 MiInitializeSectionPageTable(Segment
);
2942 return(STATUS_SUCCESS
);
2947 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2948 ACCESS_MASK DesiredAccess
,
2949 POBJECT_ATTRIBUTES ObjectAttributes
,
2950 PLARGE_INTEGER UMaximumSize
,
2951 ULONG SectionPageProtection
,
2952 ULONG AllocationAttributes
,
2955 * Create a section backed by a data file
2958 PROS_SECTION_OBJECT Section
;
2960 LARGE_INTEGER MaximumSize
;
2961 PFILE_OBJECT FileObject
;
2962 PMM_SECTION_SEGMENT Segment
;
2964 IO_STATUS_BLOCK Iosb
;
2965 LARGE_INTEGER Offset
;
2967 FILE_STANDARD_INFORMATION FileInfo
;
2971 * Create the section
2973 Status
= ObCreateObject(ExGetPreviousMode(),
2974 MmSectionObjectType
,
2976 ExGetPreviousMode(),
2978 sizeof(ROS_SECTION_OBJECT
),
2982 if (!NT_SUCCESS(Status
))
2989 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2990 Section
->Type
= 'SC';
2991 Section
->Size
= 'TN';
2992 Section
->SectionPageProtection
= SectionPageProtection
;
2993 Section
->AllocationAttributes
= AllocationAttributes
;
2996 * Reference the file handle
2998 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
2999 Status
= ObReferenceObjectByHandle(FileHandle
,
3002 ExGetPreviousMode(),
3003 (PVOID
*)(PVOID
)&FileObject
,
3005 if (!NT_SUCCESS(Status
))
3007 ObDereferenceObject(Section
);
3012 * FIXME: This is propably not entirely correct. We can't look into
3013 * the standard FCB header because it might not be initialized yet
3014 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
3015 * standard file information is filled on first request).
3017 Status
= IoQueryFileInformation(FileObject
,
3018 FileStandardInformation
,
3019 sizeof(FILE_STANDARD_INFORMATION
),
3022 Iosb
.Information
= Length
;
3023 if (!NT_SUCCESS(Status
))
3025 ObDereferenceObject(Section
);
3026 ObDereferenceObject(FileObject
);
3031 * FIXME: Revise this once a locking order for file size changes is
3034 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
3036 MaximumSize
= *UMaximumSize
;
3040 MaximumSize
= FileInfo
.EndOfFile
;
3041 /* Mapping zero-sized files isn't allowed. */
3042 if (MaximumSize
.QuadPart
== 0)
3044 ObDereferenceObject(Section
);
3045 ObDereferenceObject(FileObject
);
3046 return STATUS_FILE_INVALID
;
3050 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3052 Status
= IoSetInformation(FileObject
,
3053 FileAllocationInformation
,
3054 sizeof(LARGE_INTEGER
),
3056 if (!NT_SUCCESS(Status
))
3058 ObDereferenceObject(Section
);
3059 ObDereferenceObject(FileObject
);
3060 return(STATUS_SECTION_NOT_EXTENDED
);
3064 if (FileObject
->SectionObjectPointer
== NULL
||
3065 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3068 * Read a bit so caching is initiated for the file object.
3069 * This is only needed because MiReadPage currently cannot
3070 * handle non-cached streams.
3072 Offset
.QuadPart
= 0;
3073 Status
= ZwReadFile(FileHandle
,
3082 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3084 ObDereferenceObject(Section
);
3085 ObDereferenceObject(FileObject
);
3088 if (FileObject
->SectionObjectPointer
== NULL
||
3089 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3091 /* FIXME: handle this situation */
3092 ObDereferenceObject(Section
);
3093 ObDereferenceObject(FileObject
);
3094 return STATUS_INVALID_PARAMETER
;
3101 Status
= MmspWaitForFileLock(FileObject
);
3102 if (Status
!= STATUS_SUCCESS
)
3104 ObDereferenceObject(Section
);
3105 ObDereferenceObject(FileObject
);
3110 * If this file hasn't been mapped as a data file before then allocate a
3111 * section segment to describe the data file mapping
3113 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3115 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3116 TAG_MM_SECTION_SEGMENT
);
3117 if (Segment
== NULL
)
3119 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3120 ObDereferenceObject(Section
);
3121 ObDereferenceObject(FileObject
);
3122 return(STATUS_NO_MEMORY
);
3124 Section
->Segment
= Segment
;
3125 Segment
->ReferenceCount
= 1;
3126 ExInitializeFastMutex(&Segment
->Lock
);
3128 * Set the lock before assigning the segment to the file object
3130 ExAcquireFastMutex(&Segment
->Lock
);
3131 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3133 Segment
->Image
.FileOffset
= 0;
3134 Segment
->Protection
= SectionPageProtection
;
3135 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3136 Segment
->Image
.Characteristics
= 0;
3137 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3138 if (AllocationAttributes
& SEC_RESERVE
)
3140 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3144 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3145 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3147 Segment
->Image
.VirtualAddress
= 0;
3148 Segment
->Locked
= TRUE
;
3149 MiInitializeSectionPageTable(Segment
);
3154 * If the file is already mapped as a data file then we may need
3158 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3160 Section
->Segment
= Segment
;
3161 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3162 MmLockSectionSegment(Segment
);
3164 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3165 !(AllocationAttributes
& SEC_RESERVE
))
3167 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3168 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3171 MmUnlockSectionSegment(Segment
);
3172 Section
->FileObject
= FileObject
;
3173 Section
->MaximumSize
= MaximumSize
;
3175 CcRosReferenceCache(FileObject
);
3177 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3178 *SectionObject
= Section
;
3179 return(STATUS_SUCCESS
);
3183 TODO: not that great (declaring loaders statically, having to declare all of
3184 them, having to keep them extern, etc.), will fix in the future
3186 extern NTSTATUS NTAPI PeFmtCreateSection
3188 IN CONST VOID
* FileHeader
,
3189 IN SIZE_T FileHeaderSize
,
3191 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3193 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3194 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3197 extern NTSTATUS NTAPI ElfFmtCreateSection
3199 IN CONST VOID
* FileHeader
,
3200 IN SIZE_T FileHeaderSize
,
3202 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3204 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3205 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3208 /* TODO: this is a standard DDK/PSDK macro */
3209 #ifndef RTL_NUMBER_OF
3210 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3213 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3224 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3226 SIZE_T SizeOfSegments
;
3227 PMM_SECTION_SEGMENT Segments
;
3229 /* TODO: check for integer overflow */
3230 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3232 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3234 TAG_MM_SECTION_SEGMENT
);
3237 RtlZeroMemory(Segments
, SizeOfSegments
);
3245 ExeFmtpReadFile(IN PVOID File
,
3246 IN PLARGE_INTEGER Offset
,
3249 OUT PVOID
* AllocBase
,
3250 OUT PULONG ReadSize
)
3253 LARGE_INTEGER FileOffset
;
3255 ULONG OffsetAdjustment
;
3259 PFILE_OBJECT FileObject
= File
;
3260 IO_STATUS_BLOCK Iosb
;
3262 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3266 KeBugCheck(MEMORY_MANAGEMENT
);
3269 FileOffset
= *Offset
;
3271 /* Negative/special offset: it cannot be used in this context */
3272 if(FileOffset
.u
.HighPart
< 0)
3274 KeBugCheck(MEMORY_MANAGEMENT
);
3277 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3278 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3279 FileOffset
.u
.LowPart
= AdjustOffset
;
3281 BufferSize
= Length
+ OffsetAdjustment
;
3282 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3285 * It's ok to use paged pool, because this is a temporary buffer only used in
3286 * the loading of executables. The assumption is that MmCreateSection is
3287 * always called at low IRQLs and that these buffers don't survive a brief
3288 * initialization phase
3290 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3295 KeBugCheck(MEMORY_MANAGEMENT
);
3300 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3302 UsedSize
= (ULONG
)Iosb
.Information
;
3304 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3306 Status
= STATUS_IN_PAGE_ERROR
;
3307 ASSERT(!NT_SUCCESS(Status
));
3310 if(NT_SUCCESS(Status
))
3312 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3313 *AllocBase
= Buffer
;
3314 *ReadSize
= UsedSize
- OffsetAdjustment
;
3318 ExFreePoolWithTag(Buffer
, 'rXmM');
3325 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3326 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3327 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3332 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3336 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3338 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3339 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3346 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3350 MmspAssertSegmentsSorted(ImageSectionObject
);
3352 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3354 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3358 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3359 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3360 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3368 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3372 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3374 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3375 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3383 MmspCompareSegments(const void * x
,
3386 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3387 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3390 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3391 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3395 * Ensures an image section's segments are sorted in memory
3400 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3403 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3405 MmspAssertSegmentsSorted(ImageSectionObject
);
3409 qsort(ImageSectionObject
->Segments
,
3410 ImageSectionObject
->NrSegments
,
3411 sizeof(ImageSectionObject
->Segments
[0]),
3412 MmspCompareSegments
);
3418 * Ensures an image section's segments don't overlap in memory and don't have
3419 * gaps and don't have a null size. We let them map to overlapping file regions,
3420 * though - that's not necessarily an error
3425 MmspCheckSegmentBounds
3427 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3433 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3435 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3439 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3441 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3443 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3451 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3452 * page could be OK (Windows seems to be OK with them), and larger gaps
3453 * could lead to image sections spanning several discontiguous regions
3454 * (NtMapViewOfSection could then refuse to map them, and they could
3455 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3457 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3458 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3459 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3470 * Merges and pads an image section's segments until they all are page-aligned
3471 * and have a size that is a multiple of the page size
3476 MmspPageAlignSegments
3478 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3484 PMM_SECTION_SEGMENT EffectiveSegment
;
3486 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3488 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3493 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3495 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3498 * The first segment requires special handling
3502 ULONG_PTR VirtualAddress
;
3503 ULONG_PTR VirtualOffset
;
3505 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3507 /* Round down the virtual address to the nearest page */
3508 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3510 /* Round up the virtual size to the nearest page */
3511 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3512 EffectiveSegment
->Image
.VirtualAddress
;
3514 /* Adjust the raw address and size */
3515 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3517 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3523 * Garbage in, garbage out: unaligned base addresses make the file
3524 * offset point in curious and odd places, but that's what we were
3527 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3528 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3532 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3533 ULONG_PTR EndOfEffectiveSegment
;
3535 EndOfEffectiveSegment
= (ULONG_PTR
)(EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
);
3536 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3539 * The current segment begins exactly where the current effective
3540 * segment ended, therefore beginning a new effective segment
3542 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3545 ASSERT(LastSegment
<= i
);
3546 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3548 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3550 if (LastSegment
!= i
)
3553 * Copy the current segment. If necessary, the effective segment
3554 * will be expanded later
3556 *EffectiveSegment
= *Segment
;
3560 * Page-align the virtual size. We know for sure the virtual address
3563 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3564 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3567 * The current segment is still part of the current effective segment:
3568 * extend the effective segment to reflect this
3570 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3572 static const ULONG FlagsToProtection
[16] =
3580 PAGE_EXECUTE_READWRITE
,
3581 PAGE_EXECUTE_READWRITE
,
3586 PAGE_EXECUTE_WRITECOPY
,
3587 PAGE_EXECUTE_WRITECOPY
,
3588 PAGE_EXECUTE_WRITECOPY
,
3589 PAGE_EXECUTE_WRITECOPY
3592 unsigned ProtectionFlags
;
3595 * Extend the file size
3598 /* Unaligned segments must be contiguous within the file */
3599 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3600 EffectiveSegment
->RawLength
.QuadPart
))
3605 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3608 * Extend the virtual size
3610 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3612 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3613 EffectiveSegment
->Image
.VirtualAddress
;
3616 * Merge the protection
3618 EffectiveSegment
->Protection
|= Segment
->Protection
;
3620 /* Clean up redundance */
3621 ProtectionFlags
= 0;
3623 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3624 ProtectionFlags
|= 1 << 0;
3626 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3627 ProtectionFlags
|= 1 << 1;
3629 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3630 ProtectionFlags
|= 1 << 2;
3632 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3633 ProtectionFlags
|= 1 << 3;
3635 ASSERT(ProtectionFlags
< 16);
3636 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3638 /* If a segment was required to be shared and cannot, fail */
3639 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3640 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3646 * We assume no holes between segments at this point
3650 KeBugCheck(MEMORY_MANAGEMENT
);
3654 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3660 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3661 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3663 LARGE_INTEGER Offset
;
3665 PVOID FileHeaderBuffer
;
3666 ULONG FileHeaderSize
;
3668 ULONG OldNrSegments
;
3673 * Read the beginning of the file (2 pages). Should be enough to contain
3674 * all (or most) of the headers
3676 Offset
.QuadPart
= 0;
3678 /* FIXME: use FileObject instead of FileHandle */
3679 Status
= ExeFmtpReadFile (FileHandle
,
3686 if (!NT_SUCCESS(Status
))
3689 if (FileHeaderSize
== 0)
3691 ExFreePool(FileHeaderBuffer
);
3692 return STATUS_UNSUCCESSFUL
;
3696 * Look for a loader that can handle this executable
3698 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3700 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3703 /* FIXME: use FileObject instead of FileHandle */
3704 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3710 ExeFmtpAllocateSegments
);
3712 if (!NT_SUCCESS(Status
))
3714 if (ImageSectionObject
->Segments
)
3716 ExFreePool(ImageSectionObject
->Segments
);
3717 ImageSectionObject
->Segments
= NULL
;
3721 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3725 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3728 * No loader handled the format
3730 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3732 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3733 ASSERT(!NT_SUCCESS(Status
));
3736 if (!NT_SUCCESS(Status
))
3739 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3744 /* FIXME? are these values platform-dependent? */
3745 if(ImageSectionObject
->StackReserve
== 0)
3746 ImageSectionObject
->StackReserve
= 0x40000;
3748 if(ImageSectionObject
->StackCommit
== 0)
3749 ImageSectionObject
->StackCommit
= 0x1000;
3751 if(ImageSectionObject
->ImageBase
== 0)
3753 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3754 ImageSectionObject
->ImageBase
= 0x10000000;
3756 ImageSectionObject
->ImageBase
= 0x00400000;
3760 * And now the fun part: fixing the segments
3763 /* Sort them by virtual address */
3764 MmspSortSegments(ImageSectionObject
, Flags
);
3766 /* Ensure they don't overlap in memory */
3767 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3768 return STATUS_INVALID_IMAGE_FORMAT
;
3770 /* Ensure they are aligned */
3771 OldNrSegments
= ImageSectionObject
->NrSegments
;
3773 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3774 return STATUS_INVALID_IMAGE_FORMAT
;
3776 /* Trim them if the alignment phase merged some of them */
3777 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3779 PMM_SECTION_SEGMENT Segments
;
3780 SIZE_T SizeOfSegments
;
3782 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3784 Segments
= ExAllocatePoolWithTag(PagedPool
,
3786 TAG_MM_SECTION_SEGMENT
);
3788 if (Segments
== NULL
)
3789 return STATUS_INSUFFICIENT_RESOURCES
;
3791 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3792 ExFreePool(ImageSectionObject
->Segments
);
3793 ImageSectionObject
->Segments
= Segments
;
3796 /* And finish their initialization */
3797 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3799 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3800 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3801 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3804 ASSERT(NT_SUCCESS(Status
));
3809 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3810 ACCESS_MASK DesiredAccess
,
3811 POBJECT_ATTRIBUTES ObjectAttributes
,
3812 PLARGE_INTEGER UMaximumSize
,
3813 ULONG SectionPageProtection
,
3814 ULONG AllocationAttributes
,
3815 PFILE_OBJECT FileObject
)
3817 PROS_SECTION_OBJECT Section
;
3819 PMM_SECTION_SEGMENT SectionSegments
;
3820 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3823 if (FileObject
== NULL
)
3824 return STATUS_INVALID_FILE_FOR_SECTION
;
3827 * Create the section
3829 Status
= ObCreateObject (ExGetPreviousMode(),
3830 MmSectionObjectType
,
3832 ExGetPreviousMode(),
3834 sizeof(ROS_SECTION_OBJECT
),
3837 (PVOID
*)(PVOID
)&Section
);
3838 if (!NT_SUCCESS(Status
))
3840 ObDereferenceObject(FileObject
);
3847 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3848 Section
->Type
= 'SC';
3849 Section
->Size
= 'TN';
3850 Section
->SectionPageProtection
= SectionPageProtection
;
3851 Section
->AllocationAttributes
= AllocationAttributes
;
3855 * Initialized caching for this file object if previously caching
3856 * was initialized for the same on disk file
3858 Status
= CcTryToInitializeFileCache(FileObject
);
3860 Status
= STATUS_SUCCESS
;
3863 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3865 NTSTATUS StatusExeFmt
;
3867 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3868 if (ImageSectionObject
== NULL
)
3870 ObDereferenceObject(FileObject
);
3871 ObDereferenceObject(Section
);
3872 return(STATUS_NO_MEMORY
);
3875 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3877 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3879 if (!NT_SUCCESS(StatusExeFmt
))
3881 if(ImageSectionObject
->Segments
!= NULL
)
3882 ExFreePool(ImageSectionObject
->Segments
);
3884 ExFreePool(ImageSectionObject
);
3885 ObDereferenceObject(Section
);
3886 ObDereferenceObject(FileObject
);
3887 return(StatusExeFmt
);
3890 Section
->ImageSection
= ImageSectionObject
;
3891 ASSERT(ImageSectionObject
->Segments
);
3896 Status
= MmspWaitForFileLock(FileObject
);
3897 if (!NT_SUCCESS(Status
))
3899 ExFreePool(ImageSectionObject
->Segments
);
3900 ExFreePool(ImageSectionObject
);
3901 ObDereferenceObject(Section
);
3902 ObDereferenceObject(FileObject
);
3906 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3907 ImageSectionObject
, NULL
))
3910 * An other thread has initialized the same image in the background
3912 ExFreePool(ImageSectionObject
->Segments
);
3913 ExFreePool(ImageSectionObject
);
3914 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3915 Section
->ImageSection
= ImageSectionObject
;
3916 SectionSegments
= ImageSectionObject
->Segments
;
3918 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3920 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3924 Status
= StatusExeFmt
;
3931 Status
= MmspWaitForFileLock(FileObject
);
3932 if (Status
!= STATUS_SUCCESS
)
3934 ObDereferenceObject(Section
);
3935 ObDereferenceObject(FileObject
);
3939 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3940 Section
->ImageSection
= ImageSectionObject
;
3941 SectionSegments
= ImageSectionObject
->Segments
;
3944 * Otherwise just reference all the section segments
3946 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3948 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3951 Status
= STATUS_SUCCESS
;
3953 Section
->FileObject
= FileObject
;
3955 CcRosReferenceCache(FileObject
);
3957 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3958 *SectionObject
= Section
;
3965 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3966 PROS_SECTION_OBJECT Section
,
3967 PMM_SECTION_SEGMENT Segment
,
3972 ULONG AllocationType
)
3976 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3978 if (Segment
->WriteCopy
)
3980 /* We have to do this because the not present fault
3981 * and access fault handlers depend on the protection
3982 * that should be granted AFTER the COW fault takes
3983 * place to be in Region->Protect. The not present fault
3984 * handler changes this to the correct protection for COW when
3985 * mapping the pages into the process's address space. If a COW
3986 * fault takes place, the access fault handler sets the page protection
3987 * to these values for the newly copied pages
3989 if (Protect
== PAGE_WRITECOPY
)
3990 Protect
= PAGE_READWRITE
;
3991 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3992 Protect
= PAGE_EXECUTE_READWRITE
;
3995 BoundaryAddressMultiple
.QuadPart
= 0;
3998 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
3999 LARGE_INTEGER FileOffset
;
4000 FileOffset
.QuadPart
= ViewOffset
;
4001 ObReferenceObject(Section
);
4002 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
4005 Status
= MmCreateMemoryArea(AddressSpace
,
4006 MEMORY_AREA_SECTION_VIEW
,
4013 BoundaryAddressMultiple
);
4014 if (!NT_SUCCESS(Status
))
4016 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
4017 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
4021 ObReferenceObject((PVOID
)Section
);
4023 MArea
->Data
.SectionData
.Segment
= Segment
;
4024 MArea
->Data
.SectionData
.Section
= Section
;
4025 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
4026 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
4027 ViewSize
, 0, Protect
);
4029 return(STATUS_SUCCESS
);
4034 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
4035 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4038 PFILE_OBJECT FileObject
;
4040 LARGE_INTEGER Offset
;
4041 SWAPENTRY SavedSwapEntry
;
4044 PROS_SECTION_OBJECT Section
;
4045 PMM_SECTION_SEGMENT Segment
;
4046 PMMSUPPORT AddressSpace
;
4049 AddressSpace
= (PMMSUPPORT
)Context
;
4050 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4052 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4054 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
4055 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
4057 Section
= MemoryArea
->Data
.SectionData
.Section
;
4058 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4060 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
.LowPart
);
4064 MmUnlockSectionSegment(Segment
);
4065 MmUnlockAddressSpace(AddressSpace
);
4067 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4068 if (Status
!= STATUS_SUCCESS
)
4070 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4071 KeBugCheck(MEMORY_MANAGEMENT
);
4074 MmLockAddressSpace(AddressSpace
);
4075 MmLockSectionSegment(Segment
);
4076 MmspCompleteAndReleasePageOp(PageOp
);
4077 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
.LowPart
);
4080 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4083 * For a dirty, datafile, non-private page mark it as dirty in the
4086 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4088 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4090 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4091 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4093 CcRosMarkDirtyCacheSegment(Bcb
, (ULONG
)(Offset
.QuadPart
+ Segment
->Image
.FileOffset
));
4095 ASSERT(SwapEntry
== 0);
4104 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4106 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4107 KeBugCheck(MEMORY_MANAGEMENT
);
4109 MmFreeSwapPage(SwapEntry
);
4113 if (IS_SWAP_FROM_SSE(Entry
) ||
4114 Page
!= PFN_FROM_SSE(Entry
))
4119 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4121 DPRINT1("Found a private page in a pagefile section.\n");
4122 KeBugCheck(MEMORY_MANAGEMENT
);
4125 * Just dereference private pages
4127 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4128 if (SavedSwapEntry
!= 0)
4130 MmFreeSwapPage(SavedSwapEntry
);
4131 MmSetSavedSwapEntryPage(Page
, 0);
4133 MmDeleteRmap(Page
, Process
, Address
);
4134 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4138 MmDeleteRmap(Page
, Process
, Address
);
4139 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
);
4145 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4149 PMEMORY_AREA MemoryArea
;
4150 PROS_SECTION_OBJECT Section
;
4151 PMM_SECTION_SEGMENT Segment
;
4152 PLIST_ENTRY CurrentEntry
;
4153 PMM_REGION CurrentRegion
;
4154 PLIST_ENTRY RegionListHead
;
4156 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4158 if (MemoryArea
== NULL
)
4160 return(STATUS_UNSUCCESSFUL
);
4163 MemoryArea
->DeleteInProgress
= TRUE
;
4164 Section
= MemoryArea
->Data
.SectionData
.Section
;
4165 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4168 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4169 return MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4172 MmLockSectionSegment(Segment
);
4174 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4175 while (!IsListEmpty(RegionListHead
))
4177 CurrentEntry
= RemoveHeadList(RegionListHead
);
4178 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4179 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4182 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4184 Status
= MmFreeMemoryArea(AddressSpace
,
4191 Status
= MmFreeMemoryArea(AddressSpace
,
4196 MmUnlockSectionSegment(Segment
);
4197 ObDereferenceObject(Section
);
4203 MiRosUnmapViewOfSection(IN PEPROCESS Process
,
4204 IN PVOID BaseAddress
,
4208 PMEMORY_AREA MemoryArea
;
4209 PMMSUPPORT AddressSpace
;
4210 PROS_SECTION_OBJECT Section
;
4213 PVOID ImageBaseAddress
= 0;
4215 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4216 Process
, BaseAddress
);
4220 AddressSpace
= &Process
->Vm
;
4222 MmLockAddressSpace(AddressSpace
);
4223 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4225 if (MemoryArea
== NULL
||
4226 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4227 MemoryArea
->DeleteInProgress
)
4229 ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4230 MmUnlockAddressSpace(AddressSpace
);
4231 return STATUS_NOT_MAPPED_VIEW
;
4234 MemoryArea
->DeleteInProgress
= TRUE
;
4236 while (MemoryArea
->PageOpCount
)
4238 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4242 Offset
-= PAGE_SIZE
;
4243 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4244 MemoryArea
->Data
.SectionData
.Segment
,
4245 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
);
4248 MmUnlockAddressSpace(AddressSpace
);
4249 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4250 if (Status
!= STATUS_SUCCESS
)
4252 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4253 KeBugCheck(MEMORY_MANAGEMENT
);
4255 MmLockAddressSpace(AddressSpace
);
4256 MmspCompleteAndReleasePageOp(PageOp
);
4257 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4259 if (MemoryArea
== NULL
||
4260 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4262 MmUnlockAddressSpace(AddressSpace
);
4263 return STATUS_NOT_MAPPED_VIEW
;
4270 Section
= MemoryArea
->Data
.SectionData
.Section
;
4272 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4276 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4277 PMM_SECTION_SEGMENT SectionSegments
;
4278 PMM_SECTION_SEGMENT Segment
;
4280 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4281 ImageSectionObject
= Section
->ImageSection
;
4282 SectionSegments
= ImageSectionObject
->Segments
;
4283 NrSegments
= ImageSectionObject
->NrSegments
;
4285 /* Search for the current segment within the section segments
4286 * and calculate the image base address */
4287 for (i
= 0; i
< NrSegments
; i
++)
4289 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4291 if (Segment
== &SectionSegments
[i
])
4293 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4298 if (i
>= NrSegments
)
4300 KeBugCheck(MEMORY_MANAGEMENT
);
4303 for (i
= 0; i
< NrSegments
; i
++)
4305 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4307 PVOID SBaseAddress
= (PVOID
)
4308 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4310 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4316 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4319 MmUnlockAddressSpace(AddressSpace
);
4321 /* Notify debugger */
4322 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4324 return(STATUS_SUCCESS
);
4331 * Queries the information of a section object.
4333 * @param SectionHandle
4334 * Handle to the section object. It must be opened with SECTION_QUERY
4336 * @param SectionInformationClass
4337 * Index to a certain information structure. Can be either
4338 * SectionBasicInformation or SectionImageInformation. The latter
4339 * is valid only for sections that were created with the SEC_IMAGE
4341 * @param SectionInformation
4342 * Caller supplies storage for resulting information.
4344 * Size of the supplied storage.
4345 * @param ResultLength
4353 NtQuerySection(IN HANDLE SectionHandle
,
4354 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4355 OUT PVOID SectionInformation
,
4356 IN SIZE_T SectionInformationLength
,
4357 OUT PSIZE_T ResultLength OPTIONAL
)
4359 PROS_SECTION_OBJECT Section
;
4360 KPROCESSOR_MODE PreviousMode
;
4364 PreviousMode
= ExGetPreviousMode();
4366 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4368 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4370 (ULONG
)SectionInformationLength
,
4375 if(!NT_SUCCESS(Status
))
4377 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4381 Status
= ObReferenceObjectByHandle(SectionHandle
,
4383 MmSectionObjectType
,
4385 (PVOID
*)(PVOID
)&Section
,
4387 if (NT_SUCCESS(Status
))
4389 switch (SectionInformationClass
)
4391 case SectionBasicInformation
:
4393 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4397 Sbi
->Attributes
= Section
->AllocationAttributes
;
4398 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4400 Sbi
->BaseAddress
= 0;
4401 Sbi
->Size
.QuadPart
= 0;
4405 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4406 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4409 if (ResultLength
!= NULL
)
4411 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4413 Status
= STATUS_SUCCESS
;
4415 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4417 Status
= _SEH2_GetExceptionCode();
4424 case SectionImageInformation
:
4426 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4430 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4431 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4433 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4434 ImageSectionObject
= Section
->ImageSection
;
4436 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4437 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4438 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4439 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4440 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4441 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4442 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4443 Sii
->Machine
= ImageSectionObject
->Machine
;
4444 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4447 if (ResultLength
!= NULL
)
4449 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4451 Status
= STATUS_SUCCESS
;
4453 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4455 Status
= _SEH2_GetExceptionCode();
4463 ObDereferenceObject(Section
);
4469 /**********************************************************************
4471 * MmMapViewOfSection
4474 * Maps a view of a section into the virtual address space of a
4479 * Pointer to the section object.
4482 * Pointer to the process.
4485 * Desired base address (or NULL) on entry;
4486 * Actual base address of the view on exit.
4489 * Number of high order address bits that must be zero.
4492 * Size in bytes of the initially committed section of
4496 * Offset in bytes from the beginning of the section
4497 * to the beginning of the view.
4500 * Desired length of map (or zero to map all) on entry
4501 * Actual length mapped on exit.
4503 * InheritDisposition
4504 * Specified how the view is to be shared with
4508 * Type of allocation for the pages.
4511 * Protection for the committed region of the view.
4519 MmMapViewOfSection(IN PVOID SectionObject
,
4520 IN PEPROCESS Process
,
4521 IN OUT PVOID
*BaseAddress
,
4522 IN ULONG_PTR ZeroBits
,
4523 IN SIZE_T CommitSize
,
4524 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4525 IN OUT PSIZE_T ViewSize
,
4526 IN SECTION_INHERIT InheritDisposition
,
4527 IN ULONG AllocationType
,
4530 PROS_SECTION_OBJECT Section
;
4531 PMMSUPPORT AddressSpace
;
4533 NTSTATUS Status
= STATUS_SUCCESS
;
4534 BOOLEAN NotAtBase
= FALSE
;
4536 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4538 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4539 return MmMapViewOfArm3Section(SectionObject
,
4553 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4555 return STATUS_INVALID_PAGE_PROTECTION
;
4559 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4560 AddressSpace
= &Process
->Vm
;
4562 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4564 MmLockAddressSpace(AddressSpace
);
4566 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4570 ULONG_PTR ImageBase
;
4572 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4573 PMM_SECTION_SEGMENT SectionSegments
;
4575 ImageSectionObject
= Section
->ImageSection
;
4576 SectionSegments
= ImageSectionObject
->Segments
;
4577 NrSegments
= ImageSectionObject
->NrSegments
;
4580 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4583 ImageBase
= ImageSectionObject
->ImageBase
;
4587 for (i
= 0; i
< NrSegments
; i
++)
4589 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4591 ULONG_PTR MaxExtent
;
4592 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4593 SectionSegments
[i
].Length
.QuadPart
);
4594 ImageSize
= max(ImageSize
, MaxExtent
);
4598 ImageSectionObject
->ImageSize
= (ULONG
)ImageSize
;
4600 /* Check for an illegal base address */
4601 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4603 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4606 /* Check there is enough space to map the section at that point. */
4607 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4608 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4610 /* Fail if the user requested a fixed base address. */
4611 if ((*BaseAddress
) != NULL
)
4613 MmUnlockAddressSpace(AddressSpace
);
4614 return(STATUS_UNSUCCESSFUL
);
4616 /* Otherwise find a gap to map the image. */
4617 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4620 MmUnlockAddressSpace(AddressSpace
);
4621 return(STATUS_UNSUCCESSFUL
);
4623 /* Remember that we loaded image at a different base address */
4627 for (i
= 0; i
< NrSegments
; i
++)
4629 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4631 PVOID SBaseAddress
= (PVOID
)
4632 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4633 MmLockSectionSegment(&SectionSegments
[i
]);
4634 Status
= MmMapViewOfSegment(AddressSpace
,
4636 &SectionSegments
[i
],
4638 SectionSegments
[i
].Length
.LowPart
,
4639 SectionSegments
[i
].Protection
,
4642 MmUnlockSectionSegment(&SectionSegments
[i
]);
4643 if (!NT_SUCCESS(Status
))
4645 MmUnlockAddressSpace(AddressSpace
);
4651 *BaseAddress
= (PVOID
)ImageBase
;
4652 *ViewSize
= ImageSize
;
4656 /* check for write access */
4657 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4658 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4660 MmUnlockAddressSpace(AddressSpace
);
4661 return STATUS_SECTION_PROTECTION
;
4663 /* check for read access */
4664 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4665 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4667 MmUnlockAddressSpace(AddressSpace
);
4668 return STATUS_SECTION_PROTECTION
;
4670 /* check for execute access */
4671 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4672 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4674 MmUnlockAddressSpace(AddressSpace
);
4675 return STATUS_SECTION_PROTECTION
;
4678 if (ViewSize
== NULL
)
4680 /* Following this pointer would lead to us to the dark side */
4681 /* What to do? Bugcheck? Return status? Do the mambo? */
4682 KeBugCheck(MEMORY_MANAGEMENT
);
4685 if (SectionOffset
== NULL
)
4691 ViewOffset
= SectionOffset
->u
.LowPart
;
4694 if ((ViewOffset
% PAGE_SIZE
) != 0)
4696 MmUnlockAddressSpace(AddressSpace
);
4697 return(STATUS_MAPPED_ALIGNMENT
);
4700 if ((*ViewSize
) == 0)
4702 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4704 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4706 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4709 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4711 MmLockSectionSegment(Section
->Segment
);
4712 Status
= MmMapViewOfSegment(AddressSpace
,
4719 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4720 MmUnlockSectionSegment(Section
->Segment
);
4721 if (!NT_SUCCESS(Status
))
4723 MmUnlockAddressSpace(AddressSpace
);
4728 MmUnlockAddressSpace(AddressSpace
);
4731 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4733 Status
= STATUS_SUCCESS
;
4742 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4743 IN PLARGE_INTEGER NewFileSize
)
4745 /* Check whether an ImageSectionObject exists */
4746 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4748 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4752 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4754 PMM_SECTION_SEGMENT Segment
;
4756 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4759 if (Segment
->ReferenceCount
!= 0)
4762 CC_FILE_SIZES FileSizes
;
4764 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4767 /* Check size of file */
4768 if (SectionObjectPointer
->SharedCacheMap
)
4770 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4775 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4784 /* Check size of file */
4785 if (SectionObjectPointer
->SharedCacheMap
)
4787 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4788 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4797 /* Something must gone wrong
4798 * how can we have a Section but no
4800 DPRINT("ERROR: DataSectionObject without reference!\n");
4804 DPRINT("FIXME: didn't check for outstanding write probes\n");
4816 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4817 IN MMFLUSH_TYPE FlushType
)
4819 BOOLEAN Result
= TRUE
;
4821 PMM_SECTION_SEGMENT Segment
;
4826 case MmFlushForDelete
:
4827 if (SectionObjectPointer
->ImageSectionObject
||
4828 SectionObjectPointer
->DataSectionObject
)
4833 CcRosSetRemoveOnClose(SectionObjectPointer
);
4836 case MmFlushForWrite
:
4838 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4840 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4843 if (SectionObjectPointer
->ImageSectionObject
) {
4844 DPRINT1("SectionObject has ImageSection\n");
4850 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4852 DPRINT("Result %d\n", Result
);
4864 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4865 OUT PVOID
* MappedBase
,
4866 IN OUT PSIZE_T ViewSize
)
4868 PROS_SECTION_OBJECT Section
;
4869 PMMSUPPORT AddressSpace
;
4873 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4875 return MiMapViewInSystemSpace(SectionObject
,
4881 DPRINT("MmMapViewInSystemSpace() called\n");
4883 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4884 AddressSpace
= MmGetKernelAddressSpace();
4886 MmLockAddressSpace(AddressSpace
);
4889 if ((*ViewSize
) == 0)
4891 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4893 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4895 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4898 MmLockSectionSegment(Section
->Segment
);
4901 Status
= MmMapViewOfSegment(AddressSpace
,
4910 MmUnlockSectionSegment(Section
->Segment
);
4911 MmUnlockAddressSpace(AddressSpace
);
4918 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4920 PMMSUPPORT AddressSpace
;
4923 DPRINT("MmUnmapViewInSystemSpace() called\n");
4925 AddressSpace
= MmGetKernelAddressSpace();
4927 MmLockAddressSpace(AddressSpace
);
4929 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4931 MmUnlockAddressSpace(AddressSpace
);
4936 /**********************************************************************
4941 * Creates a section object.
4944 * SectionObject (OUT)
4945 * Caller supplied storage for the resulting pointer
4946 * to a SECTION_OBJECT instance;
4949 * Specifies the desired access to the section can be a
4951 * STANDARD_RIGHTS_REQUIRED |
4953 * SECTION_MAP_WRITE |
4954 * SECTION_MAP_READ |
4955 * SECTION_MAP_EXECUTE
4957 * ObjectAttributes [OPTIONAL]
4958 * Initialized attributes for the object can be used
4959 * to create a named section;
4962 * Maximizes the size of the memory section. Must be
4963 * non-NULL for a page-file backed section.
4964 * If value specified for a mapped file and the file is
4965 * not large enough, file will be extended.
4967 * SectionPageProtection
4968 * Can be a combination of:
4974 * AllocationAttributes
4975 * Can be a combination of:
4980 * Handle to a file to create a section mapped to a file
4981 * instead of a memory backed section;
4992 MmCreateSection (OUT PVOID
* Section
,
4993 IN ACCESS_MASK DesiredAccess
,
4994 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4995 IN PLARGE_INTEGER MaximumSize
,
4996 IN ULONG SectionPageProtection
,
4997 IN ULONG AllocationAttributes
,
4998 IN HANDLE FileHandle OPTIONAL
,
4999 IN PFILE_OBJECT FileObject OPTIONAL
)
5002 ULONG Protection
, FileAccess
;
5003 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
5005 /* Check if an ARM3 section is being created instead */
5006 if (AllocationAttributes
& 1)
5008 DPRINT1("Creating ARM3 section\n");
5009 return MmCreateArm3Section(Section
,
5013 SectionPageProtection
,
5014 AllocationAttributes
&~ 1,
5020 * Check the protection
5022 Protection
= SectionPageProtection
& ~(PAGE_GUARD
| PAGE_NOCACHE
);
5023 if (Protection
!= PAGE_READONLY
&&
5024 Protection
!= PAGE_READWRITE
&&
5025 Protection
!= PAGE_WRITECOPY
&&
5026 Protection
!= PAGE_EXECUTE
&&
5027 Protection
!= PAGE_EXECUTE_READ
&&
5028 Protection
!= PAGE_EXECUTE_READWRITE
&&
5029 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5031 return STATUS_INVALID_PAGE_PROTECTION
;
5034 if ((DesiredAccess
& SECTION_MAP_WRITE
) &&
5035 (Protection
== PAGE_READWRITE
||
5036 Protection
== PAGE_EXECUTE_READWRITE
) &&
5037 !(AllocationAttributes
& SEC_IMAGE
))
5039 DPRINT("Creating a section with WRITE access\n");
5040 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
| SYNCHRONIZE
;
5044 DPRINT("Creating a section with READ access\n");
5045 FileAccess
= FILE_READ_DATA
| SYNCHRONIZE
;
5048 /* FIXME: somehow combine this with the above checks */
5049 if (AllocationAttributes
& SEC_IMAGE
)
5050 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
5052 if (!FileObject
&& FileHandle
)
5054 Status
= ObReferenceObjectByHandle(FileHandle
,
5057 ExGetPreviousMode(),
5058 (PVOID
*)&FileObject
,
5060 if (!NT_SUCCESS(Status
))
5062 DPRINT("Failed: 0x%08lx\n", Status
);
5066 else if (FileObject
)
5067 ObReferenceObject(FileObject
);
5069 #ifndef NEWCC // A hack for initializing caching.
5070 // This is needed only in the old case.
5073 IO_STATUS_BLOCK Iosb
;
5076 LARGE_INTEGER ByteOffset
;
5077 ByteOffset
.QuadPart
= 0;
5078 Status
= ZwReadFile(FileHandle
,
5087 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5089 // Caching is initialized...
5093 if (AllocationAttributes
& SEC_IMAGE
)
5095 Status
= MmCreateImageSection(SectionObject
,
5099 SectionPageProtection
,
5100 AllocationAttributes
,
5104 else if (FileHandle
!= NULL
)
5106 Status
= MmCreateDataFileSection(SectionObject
,
5110 SectionPageProtection
,
5111 AllocationAttributes
,
5114 ObDereferenceObject(FileObject
);
5117 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5119 Status
= MmCreateCacheSection(SectionObject
,
5123 SectionPageProtection
,
5124 AllocationAttributes
,
5130 Status
= MmCreatePageFileSection(SectionObject
,
5134 SectionPageProtection
,
5135 AllocationAttributes
);
5142 MmModifyAttributes(IN PMMSUPPORT AddressSpace
,
5143 IN PVOID BaseAddress
,
5144 IN SIZE_T RegionSize
,
5146 IN ULONG OldProtect
,
5148 IN ULONG NewProtect
)
5151 // This function is deprecated but remains in order to support VirtualAlloc
5152 // calls with MEM_COMMIT on top of MapViewOfFile calls with SEC_RESERVE.
5154 // Win32k's shared user heap, for example, uses that mechanism. The two
5155 // conditions when this function needs to do something are ASSERTed for,
5156 // because they should not arise.
5158 if (NewType
== MEM_RESERVE
&& OldType
== MEM_COMMIT
)
5163 if ((NewType
== MEM_COMMIT
) && (OldType
== MEM_COMMIT
))
5165 ASSERT(OldProtect
== NewProtect
);
5171 MiRosAllocateVirtualMemory(IN HANDLE ProcessHandle
,
5172 IN PEPROCESS Process
,
5173 IN PMEMORY_AREA MemoryArea
,
5174 IN PMMSUPPORT AddressSpace
,
5175 IN OUT PVOID
* UBaseAddress
,
5176 IN BOOLEAN Attached
,
5177 IN OUT PSIZE_T URegionSize
,
5178 IN ULONG AllocationType
,
5181 ULONG_PTR PRegionSize
;
5182 ULONG Type
, RegionSize
;
5184 PVOID PBaseAddress
, BaseAddress
;
5185 KAPC_STATE ApcState
;
5187 PBaseAddress
= *UBaseAddress
;
5188 PRegionSize
= *URegionSize
;
5190 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(PBaseAddress
);
5191 RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)PBaseAddress
+ PRegionSize
) -
5192 PAGE_ROUND_DOWN(PBaseAddress
);
5193 Type
= (AllocationType
& MEM_COMMIT
) ? MEM_COMMIT
: MEM_RESERVE
;
5195 ASSERT(PBaseAddress
!= 0);
5196 ASSERT(Type
== MEM_COMMIT
);
5197 ASSERT(MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
);
5198 ASSERT(((ULONG_PTR
)BaseAddress
+ RegionSize
) <= (ULONG_PTR
)MemoryArea
->EndingAddress
);
5199 ASSERT(((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
) >= RegionSize
);
5200 ASSERT(MemoryArea
->Data
.SectionData
.RegionListHead
.Flink
);
5202 Status
= MmAlterRegion(AddressSpace
,
5203 MemoryArea
->StartingAddress
,
5204 &MemoryArea
->Data
.SectionData
.RegionListHead
,
5209 MmModifyAttributes
);
5211 MmUnlockAddressSpace(AddressSpace
);
5212 if (Attached
) KeUnstackDetachProcess(&ApcState
);
5213 if (ProcessHandle
!= NtCurrentProcess()) ObDereferenceObject(Process
);
5214 if (NT_SUCCESS(Status
))
5216 *UBaseAddress
= BaseAddress
;
5217 *URegionSize
= RegionSize
;
5225 MiRosProtectVirtualMemory(IN PEPROCESS Process
,
5226 IN OUT PVOID
*BaseAddress
,
5227 IN OUT PSIZE_T NumberOfBytesToProtect
,
5228 IN ULONG NewAccessProtection
,
5229 OUT PULONG OldAccessProtection OPTIONAL
)
5231 PMEMORY_AREA MemoryArea
;
5232 PMMSUPPORT AddressSpace
;
5233 ULONG OldAccessProtection_
;
5236 *NumberOfBytesToProtect
= PAGE_ROUND_UP((ULONG_PTR
)(*BaseAddress
) + (*NumberOfBytesToProtect
)) - PAGE_ROUND_DOWN(*BaseAddress
);
5237 *BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(*BaseAddress
);
5239 AddressSpace
= &Process
->Vm
;
5240 MmLockAddressSpace(AddressSpace
);
5241 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, *BaseAddress
);
5242 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
5244 MmUnlockAddressSpace(AddressSpace
);
5245 return STATUS_UNSUCCESSFUL
;
5248 if (OldAccessProtection
== NULL
) OldAccessProtection
= &OldAccessProtection_
;
5250 if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
5252 Status
= MmProtectSectionView(AddressSpace
,
5255 *NumberOfBytesToProtect
,
5256 NewAccessProtection
,
5257 OldAccessProtection
);
5261 /* FIXME: Should we return failure or success in this case? */
5262 Status
= STATUS_CONFLICTING_ADDRESSES
;
5265 MmUnlockAddressSpace(AddressSpace
);