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
);
4205 MmUnmapViewOfSection(PEPROCESS Process
,
4209 PMEMORY_AREA MemoryArea
;
4210 PMMSUPPORT AddressSpace
;
4211 PROS_SECTION_OBJECT Section
;
4214 PVOID ImageBaseAddress
= 0;
4216 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4217 Process
, BaseAddress
);
4221 AddressSpace
= &Process
->Vm
;
4223 MmLockAddressSpace(AddressSpace
);
4224 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4226 if (MemoryArea
== NULL
||
4227 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4228 MemoryArea
->DeleteInProgress
)
4230 ASSERT(MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
);
4231 MmUnlockAddressSpace(AddressSpace
);
4232 return STATUS_NOT_MAPPED_VIEW
;
4235 MemoryArea
->DeleteInProgress
= TRUE
;
4237 while (MemoryArea
->PageOpCount
)
4239 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4243 Offset
-= PAGE_SIZE
;
4244 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4245 MemoryArea
->Data
.SectionData
.Segment
,
4246 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
);
4249 MmUnlockAddressSpace(AddressSpace
);
4250 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4251 if (Status
!= STATUS_SUCCESS
)
4253 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4254 KeBugCheck(MEMORY_MANAGEMENT
);
4256 MmLockAddressSpace(AddressSpace
);
4257 MmspCompleteAndReleasePageOp(PageOp
);
4258 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4260 if (MemoryArea
== NULL
||
4261 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4263 MmUnlockAddressSpace(AddressSpace
);
4264 return STATUS_NOT_MAPPED_VIEW
;
4271 Section
= MemoryArea
->Data
.SectionData
.Section
;
4273 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4277 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4278 PMM_SECTION_SEGMENT SectionSegments
;
4279 PMM_SECTION_SEGMENT Segment
;
4281 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4282 ImageSectionObject
= Section
->ImageSection
;
4283 SectionSegments
= ImageSectionObject
->Segments
;
4284 NrSegments
= ImageSectionObject
->NrSegments
;
4286 /* Search for the current segment within the section segments
4287 * and calculate the image base address */
4288 for (i
= 0; i
< NrSegments
; i
++)
4290 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4292 if (Segment
== &SectionSegments
[i
])
4294 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4299 if (i
>= NrSegments
)
4301 KeBugCheck(MEMORY_MANAGEMENT
);
4304 for (i
= 0; i
< NrSegments
; i
++)
4306 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4308 PVOID SBaseAddress
= (PVOID
)
4309 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4311 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4317 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4320 MmUnlockAddressSpace(AddressSpace
);
4322 /* Notify debugger */
4323 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4325 return(STATUS_SUCCESS
);
4332 * Queries the information of a section object.
4334 * @param SectionHandle
4335 * Handle to the section object. It must be opened with SECTION_QUERY
4337 * @param SectionInformationClass
4338 * Index to a certain information structure. Can be either
4339 * SectionBasicInformation or SectionImageInformation. The latter
4340 * is valid only for sections that were created with the SEC_IMAGE
4342 * @param SectionInformation
4343 * Caller supplies storage for resulting information.
4345 * Size of the supplied storage.
4346 * @param ResultLength
4354 NtQuerySection(IN HANDLE SectionHandle
,
4355 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4356 OUT PVOID SectionInformation
,
4357 IN SIZE_T SectionInformationLength
,
4358 OUT PSIZE_T ResultLength OPTIONAL
)
4360 PROS_SECTION_OBJECT Section
;
4361 KPROCESSOR_MODE PreviousMode
;
4365 PreviousMode
= ExGetPreviousMode();
4367 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4369 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4371 (ULONG
)SectionInformationLength
,
4376 if(!NT_SUCCESS(Status
))
4378 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4382 Status
= ObReferenceObjectByHandle(SectionHandle
,
4384 MmSectionObjectType
,
4386 (PVOID
*)(PVOID
)&Section
,
4388 if (NT_SUCCESS(Status
))
4390 switch (SectionInformationClass
)
4392 case SectionBasicInformation
:
4394 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4398 Sbi
->Attributes
= Section
->AllocationAttributes
;
4399 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4401 Sbi
->BaseAddress
= 0;
4402 Sbi
->Size
.QuadPart
= 0;
4406 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4407 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4410 if (ResultLength
!= NULL
)
4412 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4414 Status
= STATUS_SUCCESS
;
4416 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4418 Status
= _SEH2_GetExceptionCode();
4425 case SectionImageInformation
:
4427 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4431 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4432 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4434 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4435 ImageSectionObject
= Section
->ImageSection
;
4437 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4438 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4439 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4440 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4441 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4442 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4443 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4444 Sii
->Machine
= ImageSectionObject
->Machine
;
4445 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4448 if (ResultLength
!= NULL
)
4450 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4452 Status
= STATUS_SUCCESS
;
4454 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4456 Status
= _SEH2_GetExceptionCode();
4464 ObDereferenceObject(Section
);
4470 /**********************************************************************
4472 * MmMapViewOfSection
4475 * Maps a view of a section into the virtual address space of a
4480 * Pointer to the section object.
4483 * Pointer to the process.
4486 * Desired base address (or NULL) on entry;
4487 * Actual base address of the view on exit.
4490 * Number of high order address bits that must be zero.
4493 * Size in bytes of the initially committed section of
4497 * Offset in bytes from the beginning of the section
4498 * to the beginning of the view.
4501 * Desired length of map (or zero to map all) on entry
4502 * Actual length mapped on exit.
4504 * InheritDisposition
4505 * Specified how the view is to be shared with
4509 * Type of allocation for the pages.
4512 * Protection for the committed region of the view.
4520 MmMapViewOfSection(IN PVOID SectionObject
,
4521 IN PEPROCESS Process
,
4522 IN OUT PVOID
*BaseAddress
,
4523 IN ULONG_PTR ZeroBits
,
4524 IN SIZE_T CommitSize
,
4525 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4526 IN OUT PSIZE_T ViewSize
,
4527 IN SECTION_INHERIT InheritDisposition
,
4528 IN ULONG AllocationType
,
4531 PROS_SECTION_OBJECT Section
;
4532 PMMSUPPORT AddressSpace
;
4534 NTSTATUS Status
= STATUS_SUCCESS
;
4535 BOOLEAN NotAtBase
= FALSE
;
4537 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4539 DPRINT("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4540 return MmMapViewOfArm3Section(SectionObject
,
4554 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4556 return STATUS_INVALID_PAGE_PROTECTION
;
4560 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4561 AddressSpace
= &Process
->Vm
;
4563 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4565 MmLockAddressSpace(AddressSpace
);
4567 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4571 ULONG_PTR ImageBase
;
4573 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4574 PMM_SECTION_SEGMENT SectionSegments
;
4576 ImageSectionObject
= Section
->ImageSection
;
4577 SectionSegments
= ImageSectionObject
->Segments
;
4578 NrSegments
= ImageSectionObject
->NrSegments
;
4581 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4584 ImageBase
= ImageSectionObject
->ImageBase
;
4588 for (i
= 0; i
< NrSegments
; i
++)
4590 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4592 ULONG_PTR MaxExtent
;
4593 MaxExtent
= (ULONG_PTR
)(SectionSegments
[i
].Image
.VirtualAddress
+
4594 SectionSegments
[i
].Length
.QuadPart
);
4595 ImageSize
= max(ImageSize
, MaxExtent
);
4599 ImageSectionObject
->ImageSize
= (ULONG
)ImageSize
;
4601 /* Check for an illegal base address */
4602 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4604 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4607 /* Check there is enough space to map the section at that point. */
4608 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4609 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4611 /* Fail if the user requested a fixed base address. */
4612 if ((*BaseAddress
) != NULL
)
4614 MmUnlockAddressSpace(AddressSpace
);
4615 return(STATUS_UNSUCCESSFUL
);
4617 /* Otherwise find a gap to map the image. */
4618 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4621 MmUnlockAddressSpace(AddressSpace
);
4622 return(STATUS_UNSUCCESSFUL
);
4624 /* Remember that we loaded image at a different base address */
4628 for (i
= 0; i
< NrSegments
; i
++)
4630 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4632 PVOID SBaseAddress
= (PVOID
)
4633 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4634 MmLockSectionSegment(&SectionSegments
[i
]);
4635 Status
= MmMapViewOfSegment(AddressSpace
,
4637 &SectionSegments
[i
],
4639 SectionSegments
[i
].Length
.LowPart
,
4640 SectionSegments
[i
].Protection
,
4643 MmUnlockSectionSegment(&SectionSegments
[i
]);
4644 if (!NT_SUCCESS(Status
))
4646 MmUnlockAddressSpace(AddressSpace
);
4652 *BaseAddress
= (PVOID
)ImageBase
;
4653 *ViewSize
= ImageSize
;
4657 /* check for write access */
4658 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4659 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4661 MmUnlockAddressSpace(AddressSpace
);
4662 return STATUS_SECTION_PROTECTION
;
4664 /* check for read access */
4665 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4666 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4668 MmUnlockAddressSpace(AddressSpace
);
4669 return STATUS_SECTION_PROTECTION
;
4671 /* check for execute access */
4672 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4673 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4675 MmUnlockAddressSpace(AddressSpace
);
4676 return STATUS_SECTION_PROTECTION
;
4679 if (ViewSize
== NULL
)
4681 /* Following this pointer would lead to us to the dark side */
4682 /* What to do? Bugcheck? Return status? Do the mambo? */
4683 KeBugCheck(MEMORY_MANAGEMENT
);
4686 if (SectionOffset
== NULL
)
4692 ViewOffset
= SectionOffset
->u
.LowPart
;
4695 if ((ViewOffset
% PAGE_SIZE
) != 0)
4697 MmUnlockAddressSpace(AddressSpace
);
4698 return(STATUS_MAPPED_ALIGNMENT
);
4701 if ((*ViewSize
) == 0)
4703 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4705 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4707 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4710 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4712 MmLockSectionSegment(Section
->Segment
);
4713 Status
= MmMapViewOfSegment(AddressSpace
,
4720 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4721 MmUnlockSectionSegment(Section
->Segment
);
4722 if (!NT_SUCCESS(Status
))
4724 MmUnlockAddressSpace(AddressSpace
);
4729 MmUnlockAddressSpace(AddressSpace
);
4732 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4734 Status
= STATUS_SUCCESS
;
4743 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4744 IN PLARGE_INTEGER NewFileSize
)
4746 /* Check whether an ImageSectionObject exists */
4747 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4749 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4753 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4755 PMM_SECTION_SEGMENT Segment
;
4757 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4760 if (Segment
->ReferenceCount
!= 0)
4763 CC_FILE_SIZES FileSizes
;
4765 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4768 /* Check size of file */
4769 if (SectionObjectPointer
->SharedCacheMap
)
4771 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4776 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4785 /* Check size of file */
4786 if (SectionObjectPointer
->SharedCacheMap
)
4788 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4789 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4798 /* Something must gone wrong
4799 * how can we have a Section but no
4801 DPRINT("ERROR: DataSectionObject without reference!\n");
4805 DPRINT("FIXME: didn't check for outstanding write probes\n");
4817 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4818 IN MMFLUSH_TYPE FlushType
)
4820 BOOLEAN Result
= TRUE
;
4822 PMM_SECTION_SEGMENT Segment
;
4827 case MmFlushForDelete
:
4828 if (SectionObjectPointer
->ImageSectionObject
||
4829 SectionObjectPointer
->DataSectionObject
)
4834 CcRosSetRemoveOnClose(SectionObjectPointer
);
4837 case MmFlushForWrite
:
4839 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4841 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4844 if (SectionObjectPointer
->ImageSectionObject
) {
4845 DPRINT1("SectionObject has ImageSection\n");
4851 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4853 DPRINT("Result %d\n", Result
);
4865 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4866 OUT PVOID
* MappedBase
,
4867 IN OUT PSIZE_T ViewSize
)
4869 PROS_SECTION_OBJECT Section
;
4870 PMMSUPPORT AddressSpace
;
4874 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4876 return MiMapViewInSystemSpace(SectionObject
,
4882 DPRINT("MmMapViewInSystemSpace() called\n");
4884 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4885 AddressSpace
= MmGetKernelAddressSpace();
4887 MmLockAddressSpace(AddressSpace
);
4890 if ((*ViewSize
) == 0)
4892 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4894 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4896 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4899 MmLockSectionSegment(Section
->Segment
);
4902 Status
= MmMapViewOfSegment(AddressSpace
,
4911 MmUnlockSectionSegment(Section
->Segment
);
4912 MmUnlockAddressSpace(AddressSpace
);
4919 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase
)
4921 PMMSUPPORT AddressSpace
;
4924 DPRINT("MmUnmapViewInSystemSpace() called\n");
4926 AddressSpace
= MmGetKernelAddressSpace();
4928 MmLockAddressSpace(AddressSpace
);
4930 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4932 MmUnlockAddressSpace(AddressSpace
);
4937 /**********************************************************************
4942 * Creates a section object.
4945 * SectionObject (OUT)
4946 * Caller supplied storage for the resulting pointer
4947 * to a SECTION_OBJECT instance;
4950 * Specifies the desired access to the section can be a
4952 * STANDARD_RIGHTS_REQUIRED |
4954 * SECTION_MAP_WRITE |
4955 * SECTION_MAP_READ |
4956 * SECTION_MAP_EXECUTE
4958 * ObjectAttributes [OPTIONAL]
4959 * Initialized attributes for the object can be used
4960 * to create a named section;
4963 * Maximizes the size of the memory section. Must be
4964 * non-NULL for a page-file backed section.
4965 * If value specified for a mapped file and the file is
4966 * not large enough, file will be extended.
4968 * SectionPageProtection
4969 * Can be a combination of:
4975 * AllocationAttributes
4976 * Can be a combination of:
4981 * Handle to a file to create a section mapped to a file
4982 * instead of a memory backed section;
4993 MmCreateSection (OUT PVOID
* Section
,
4994 IN ACCESS_MASK DesiredAccess
,
4995 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4996 IN PLARGE_INTEGER MaximumSize
,
4997 IN ULONG SectionPageProtection
,
4998 IN ULONG AllocationAttributes
,
4999 IN HANDLE FileHandle OPTIONAL
,
5000 IN PFILE_OBJECT FileObject OPTIONAL
)
5003 ULONG Protection
, FileAccess
;
5004 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
5006 /* Check if an ARM3 section is being created instead */
5007 if (AllocationAttributes
& 1)
5009 DPRINT1("Creating ARM3 section\n");
5010 return MmCreateArm3Section(Section
,
5014 SectionPageProtection
,
5015 AllocationAttributes
&~ 1,
5021 * Check the protection
5023 Protection
= SectionPageProtection
& ~(PAGE_GUARD
| PAGE_NOCACHE
);
5024 if (Protection
!= PAGE_READONLY
&&
5025 Protection
!= PAGE_READWRITE
&&
5026 Protection
!= PAGE_WRITECOPY
&&
5027 Protection
!= PAGE_EXECUTE
&&
5028 Protection
!= PAGE_EXECUTE_READ
&&
5029 Protection
!= PAGE_EXECUTE_READWRITE
&&
5030 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5032 return STATUS_INVALID_PAGE_PROTECTION
;
5035 if ((DesiredAccess
& SECTION_MAP_WRITE
) &&
5036 (Protection
== PAGE_READWRITE
||
5037 Protection
== PAGE_EXECUTE_READWRITE
) &&
5038 !(AllocationAttributes
& SEC_IMAGE
))
5040 DPRINT("Creating a section with WRITE access\n");
5041 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
| SYNCHRONIZE
;
5045 DPRINT("Creating a section with READ access\n");
5046 FileAccess
= FILE_READ_DATA
| SYNCHRONIZE
;
5049 /* FIXME: somehow combine this with the above checks */
5050 if (AllocationAttributes
& SEC_IMAGE
)
5051 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
5053 if (!FileObject
&& FileHandle
)
5055 Status
= ObReferenceObjectByHandle(FileHandle
,
5058 ExGetPreviousMode(),
5059 (PVOID
*)&FileObject
,
5061 if (!NT_SUCCESS(Status
))
5063 DPRINT("Failed: 0x%08lx\n", Status
);
5067 else if (FileObject
)
5068 ObReferenceObject(FileObject
);
5070 #ifndef NEWCC // A hack for initializing caching.
5071 // This is needed only in the old case.
5074 IO_STATUS_BLOCK Iosb
;
5077 LARGE_INTEGER ByteOffset
;
5078 ByteOffset
.QuadPart
= 0;
5079 Status
= ZwReadFile(FileHandle
,
5088 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5090 // Caching is initialized...
5094 if (AllocationAttributes
& SEC_IMAGE
)
5096 Status
= MmCreateImageSection(SectionObject
,
5100 SectionPageProtection
,
5101 AllocationAttributes
,
5105 else if (FileHandle
!= NULL
)
5107 Status
= MmCreateDataFileSection(SectionObject
,
5111 SectionPageProtection
,
5112 AllocationAttributes
,
5115 ObDereferenceObject(FileObject
);
5118 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5120 Status
= MmCreateCacheSection(SectionObject
,
5124 SectionPageProtection
,
5125 AllocationAttributes
,
5131 Status
= MmCreatePageFileSection(SectionObject
,
5135 SectionPageProtection
,
5136 AllocationAttributes
);
5143 MmModifyAttributes(IN PMMSUPPORT AddressSpace
,
5144 IN PVOID BaseAddress
,
5145 IN SIZE_T RegionSize
,
5147 IN ULONG OldProtect
,
5149 IN ULONG NewProtect
)
5152 // This function is deprecated but remains in order to support VirtualAlloc
5153 // calls with MEM_COMMIT on top of MapViewOfFile calls with SEC_RESERVE.
5155 // Win32k's shared user heap, for example, uses that mechanism. The two
5156 // conditions when this function needs to do something are ASSERTed for,
5157 // because they should not arise.
5159 if (NewType
== MEM_RESERVE
&& OldType
== MEM_COMMIT
)
5164 if ((NewType
== MEM_COMMIT
) && (OldType
== MEM_COMMIT
))
5166 ASSERT(OldProtect
== NewProtect
);
5172 MiRosAllocateVirtualMemory(IN HANDLE ProcessHandle
,
5173 IN PEPROCESS Process
,
5174 IN PMEMORY_AREA MemoryArea
,
5175 IN PMMSUPPORT AddressSpace
,
5176 IN OUT PVOID
* UBaseAddress
,
5177 IN BOOLEAN Attached
,
5178 IN OUT PSIZE_T URegionSize
,
5179 IN ULONG AllocationType
,
5182 ULONG_PTR PRegionSize
;
5183 ULONG Type
, RegionSize
;
5185 PVOID PBaseAddress
, BaseAddress
;
5186 KAPC_STATE ApcState
;
5188 PBaseAddress
= *UBaseAddress
;
5189 PRegionSize
= *URegionSize
;
5191 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(PBaseAddress
);
5192 RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)PBaseAddress
+ PRegionSize
) -
5193 PAGE_ROUND_DOWN(PBaseAddress
);
5194 Type
= (AllocationType
& MEM_COMMIT
) ? MEM_COMMIT
: MEM_RESERVE
;
5196 ASSERT(PBaseAddress
!= 0);
5197 ASSERT(Type
== MEM_COMMIT
);
5198 ASSERT(MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
);
5199 ASSERT(((ULONG_PTR
)BaseAddress
+ RegionSize
) <= (ULONG_PTR
)MemoryArea
->EndingAddress
);
5200 ASSERT(((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
) >= RegionSize
);
5201 ASSERT(MemoryArea
->Data
.SectionData
.RegionListHead
.Flink
);
5203 Status
= MmAlterRegion(AddressSpace
,
5204 MemoryArea
->StartingAddress
,
5205 &MemoryArea
->Data
.SectionData
.RegionListHead
,
5210 MmModifyAttributes
);
5212 MmUnlockAddressSpace(AddressSpace
);
5213 if (Attached
) KeUnstackDetachProcess(&ApcState
);
5214 if (ProcessHandle
!= NtCurrentProcess()) ObDereferenceObject(Process
);
5215 if (NT_SUCCESS(Status
))
5217 *UBaseAddress
= BaseAddress
;
5218 *URegionSize
= RegionSize
;
5226 MiRosProtectVirtualMemory(IN PEPROCESS Process
,
5227 IN OUT PVOID
*BaseAddress
,
5228 IN OUT PSIZE_T NumberOfBytesToProtect
,
5229 IN ULONG NewAccessProtection
,
5230 OUT PULONG OldAccessProtection OPTIONAL
)
5232 PMEMORY_AREA MemoryArea
;
5233 PMMSUPPORT AddressSpace
;
5234 ULONG OldAccessProtection_
;
5237 *NumberOfBytesToProtect
= PAGE_ROUND_UP((ULONG_PTR
)(*BaseAddress
) + (*NumberOfBytesToProtect
)) - PAGE_ROUND_DOWN(*BaseAddress
);
5238 *BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(*BaseAddress
);
5240 AddressSpace
= &Process
->Vm
;
5241 MmLockAddressSpace(AddressSpace
);
5242 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, *BaseAddress
);
5243 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
5245 MmUnlockAddressSpace(AddressSpace
);
5246 return STATUS_UNSUCCESSFUL
;
5249 if (OldAccessProtection
== NULL
) OldAccessProtection
= &OldAccessProtection_
;
5251 if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
5253 Status
= MmProtectSectionView(AddressSpace
,
5256 *NumberOfBytesToProtect
,
5257 NewAccessProtection
,
5258 OldAccessProtection
);
5262 /* FIXME: Should we return failure or success in this case? */
5263 Status
= STATUS_CONFLICTING_ADDRESSES
;
5266 MmUnlockAddressSpace(AddressSpace
);