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 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
171 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
172 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFC) >> 2)
173 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
174 #define MAX_SHARE_COUNT 0x3FF
175 #define MAKE_SSE(P, C) ((P) | ((C) << 2))
176 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
177 #define MAKE_SWAP_SSE(S) (((ULONG)(S) << 1) | 0x1)
179 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
181 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
182 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
185 /* FUNCTIONS *****************************************************************/
190 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
191 File Format Specification", revision 6.0 (February 1999)
193 NTSTATUS NTAPI
PeFmtCreateSection(IN CONST VOID
* FileHeader
,
194 IN SIZE_T FileHeaderSize
,
196 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
198 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
199 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
)
202 ULONG cbFileHeaderOffsetSize
= 0;
203 ULONG cbSectionHeadersOffset
= 0;
204 ULONG cbSectionHeadersSize
;
205 ULONG cbSectionHeadersOffsetSize
= 0;
206 ULONG cbOptHeaderSize
;
207 ULONG cbHeadersSize
= 0;
208 ULONG nSectionAlignment
;
209 ULONG nFileAlignment
;
210 const IMAGE_DOS_HEADER
* pidhDosHeader
;
211 const IMAGE_NT_HEADERS32
* pinhNtHeader
;
212 const IMAGE_OPTIONAL_HEADER32
* piohOptHeader
;
213 const IMAGE_SECTION_HEADER
* pishSectionHeaders
;
214 PMM_SECTION_SEGMENT pssSegments
;
215 LARGE_INTEGER lnOffset
;
217 SIZE_T nPrevVirtualEndOfSegment
= 0;
218 ULONG nFileSizeOfHeaders
= 0;
222 ASSERT(FileHeaderSize
> 0);
224 ASSERT(ImageSectionObject
);
226 ASSERT(AllocateSegmentsCb
);
228 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, FileHeaderSize
));
230 ASSERT(((UINT_PTR
)FileHeader
% TYPE_ALIGNMENT(IMAGE_DOS_HEADER
)) == 0);
232 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
235 pidhDosHeader
= FileHeader
;
238 nStatus
= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
;
240 /* image too small to be an MZ executable */
241 if(FileHeaderSize
< sizeof(IMAGE_DOS_HEADER
))
242 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize
));
244 /* no MZ signature */
245 if(pidhDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
246 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader
->e_magic
));
248 /* not a Windows executable */
249 if(pidhDosHeader
->e_lfanew
<= 0)
250 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader
->e_lfanew
));
253 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
255 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
)))
256 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
258 if(FileHeaderSize
< cbFileHeaderOffsetSize
)
263 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
264 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
266 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, pidhDosHeader
->e_lfanew
));
267 pinhNtHeader
= (PVOID
)((UINT_PTR
)FileHeader
+ pidhDosHeader
->e_lfanew
);
271 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
272 * need to read the header from the file
274 if(FileHeaderSize
< cbFileHeaderOffsetSize
||
275 (UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
277 ULONG cbNtHeaderSize
;
281 l_ReadHeaderFromFile
:
283 lnOffset
.QuadPart
= pidhDosHeader
->e_lfanew
;
285 /* read the header from the file */
286 nStatus
= ReadFileCb(File
, &lnOffset
, sizeof(IMAGE_NT_HEADERS64
), &pData
, &pBuffer
, &cbReadSize
);
288 if(!NT_SUCCESS(nStatus
))
289 DIE(("ReadFile failed, status %08X\n", nStatus
));
293 ASSERT(cbReadSize
> 0);
295 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
297 /* the buffer doesn't contain the file header */
298 if(cbReadSize
< RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32
, FileHeader
))
299 DIE(("The file doesn't contain the PE file header\n"));
301 pinhNtHeader
= pData
;
303 /* object still not aligned: copy it to the beginning of the buffer */
304 if((UINT_PTR
)pinhNtHeader
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) != 0)
306 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_NT_HEADERS32
) == 0);
307 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
308 pinhNtHeader
= pBuffer
;
311 /* invalid NT header */
312 nStatus
= STATUS_INVALID_IMAGE_PROTECT
;
314 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
315 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
317 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
319 if(!Intsafe_AddULong32(&cbNtHeaderSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
320 DIE(("The full NT header is too large\n"));
322 /* the buffer doesn't contain the whole NT header */
323 if(cbReadSize
< cbNtHeaderSize
)
324 DIE(("The file doesn't contain the full NT header\n"));
328 ULONG cbOptHeaderOffsetSize
= 0;
330 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
332 /* don't trust an invalid NT header */
333 if(pinhNtHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
334 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader
->Signature
));
336 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
337 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader
->e_lfanew
));
339 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize
, cbOptHeaderOffsetSize
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
340 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
));
342 /* the buffer doesn't contain the whole NT header: read it from the file */
343 if(cbOptHeaderOffsetSize
> FileHeaderSize
)
344 goto l_ReadHeaderFromFile
;
347 /* read information from the NT header */
348 piohOptHeader
= &pinhNtHeader
->OptionalHeader
;
349 cbOptHeaderSize
= pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
;
351 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
353 if(!RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Magic
))
354 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize
));
356 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
358 switch(piohOptHeader
->Magic
)
360 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
361 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
365 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader
->Magic
));
368 if (RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SectionAlignment
) &&
369 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, FileAlignment
))
371 /* See [1], section 3.4.2 */
372 if(piohOptHeader
->SectionAlignment
< PAGE_SIZE
)
374 if(piohOptHeader
->FileAlignment
!= piohOptHeader
->SectionAlignment
)
375 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
377 else if(piohOptHeader
->SectionAlignment
< piohOptHeader
->FileAlignment
)
378 DIE(("The section alignment is smaller than the file alignment\n"));
380 nSectionAlignment
= piohOptHeader
->SectionAlignment
;
381 nFileAlignment
= piohOptHeader
->FileAlignment
;
383 if(!IsPowerOf2(nSectionAlignment
) || !IsPowerOf2(nFileAlignment
))
384 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment
, nFileAlignment
));
388 nSectionAlignment
= PAGE_SIZE
;
389 nFileAlignment
= PAGE_SIZE
;
392 ASSERT(IsPowerOf2(nSectionAlignment
));
393 ASSERT(IsPowerOf2(nFileAlignment
));
395 switch(piohOptHeader
->Magic
)
398 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
400 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, ImageBase
))
401 ImageSectionObject
->ImageBase
= piohOptHeader
->ImageBase
;
403 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfImage
))
404 ImageSectionObject
->ImageSize
= piohOptHeader
->SizeOfImage
;
406 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
407 ImageSectionObject
->StackReserve
= piohOptHeader
->SizeOfStackReserve
;
409 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
410 ImageSectionObject
->StackCommit
= piohOptHeader
->SizeOfStackCommit
;
416 case IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
418 const IMAGE_OPTIONAL_HEADER64
* pioh64OptHeader
;
420 pioh64OptHeader
= (const IMAGE_OPTIONAL_HEADER64
*)piohOptHeader
;
422 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, ImageBase
))
424 if(pioh64OptHeader
->ImageBase
> MAXULONG_PTR
)
425 DIE(("ImageBase exceeds the address space\n"));
427 ImageSectionObject
->ImageBase
= (ULONG_PTR
)pioh64OptHeader
->ImageBase
;
430 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfImage
))
432 if(pioh64OptHeader
->SizeOfImage
> MAXULONG_PTR
)
433 DIE(("SizeOfImage exceeds the address space\n"));
435 ImageSectionObject
->ImageSize
= pioh64OptHeader
->SizeOfImage
;
438 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackReserve
))
440 if(pioh64OptHeader
->SizeOfStackReserve
> MAXULONG_PTR
)
441 DIE(("SizeOfStackReserve exceeds the address space\n"));
443 ImageSectionObject
->StackReserve
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackReserve
;
446 if(RTL_CONTAINS_FIELD(pioh64OptHeader
, cbOptHeaderSize
, SizeOfStackCommit
))
448 if(pioh64OptHeader
->SizeOfStackCommit
> MAXULONG_PTR
)
449 DIE(("SizeOfStackCommit exceeds the address space\n"));
451 ImageSectionObject
->StackCommit
= (ULONG_PTR
)pioh64OptHeader
->SizeOfStackCommit
;
458 /* [1], section 3.4.2 */
459 if((ULONG_PTR
)ImageSectionObject
->ImageBase
% 0x10000)
460 DIE(("ImageBase is not aligned on a 64KB boundary"));
462 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, Subsystem
))
464 ImageSectionObject
->Subsystem
= piohOptHeader
->Subsystem
;
466 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MinorSubsystemVersion
) &&
467 RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, MajorSubsystemVersion
))
469 ImageSectionObject
->MinorSubsystemVersion
= piohOptHeader
->MinorSubsystemVersion
;
470 ImageSectionObject
->MajorSubsystemVersion
= piohOptHeader
->MajorSubsystemVersion
;
474 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, AddressOfEntryPoint
))
476 ImageSectionObject
->EntryPoint
= ImageSectionObject
->ImageBase
+
477 piohOptHeader
->AddressOfEntryPoint
;
480 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfCode
))
481 ImageSectionObject
->Executable
= piohOptHeader
->SizeOfCode
!= 0;
483 ImageSectionObject
->Executable
= TRUE
;
485 ImageSectionObject
->ImageCharacteristics
= pinhNtHeader
->FileHeader
.Characteristics
;
486 ImageSectionObject
->Machine
= pinhNtHeader
->FileHeader
.Machine
;
488 /* SECTION HEADERS */
489 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
491 /* see [1], section 3.3 */
492 if(pinhNtHeader
->FileHeader
.NumberOfSections
> 96)
493 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader
->FileHeader
.NumberOfSections
));
496 * the additional segment is for the file's headers. They need to be present for
497 * the benefit of the dynamic loader (to locate exports, defaults for thread
498 * parameters, resources, etc.)
500 ImageSectionObject
->NrSegments
= pinhNtHeader
->FileHeader
.NumberOfSections
+ 1;
502 /* file offset for the section headers */
503 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, pidhDosHeader
->e_lfanew
, FIELD_OFFSET(IMAGE_NT_HEADERS32
, OptionalHeader
)))
504 DIE(("Offset overflow\n"));
506 if(!Intsafe_AddULong32(&cbSectionHeadersOffset
, cbSectionHeadersOffset
, pinhNtHeader
->FileHeader
.SizeOfOptionalHeader
))
507 DIE(("Offset overflow\n"));
509 /* size of the section headers */
510 ASSERT(Intsafe_CanMulULong32(pinhNtHeader
->FileHeader
.NumberOfSections
, sizeof(IMAGE_SECTION_HEADER
)));
511 cbSectionHeadersSize
= pinhNtHeader
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
513 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize
, cbSectionHeadersOffset
, cbSectionHeadersSize
))
514 DIE(("Section headers too large\n"));
516 /* size of the executable's headers */
517 if(RTL_CONTAINS_FIELD(piohOptHeader
, cbOptHeaderSize
, SizeOfHeaders
))
519 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
520 // DIE(("SizeOfHeaders is not aligned\n"));
522 if(cbSectionHeadersSize
> piohOptHeader
->SizeOfHeaders
)
523 DIE(("The section headers overflow SizeOfHeaders\n"));
525 cbHeadersSize
= piohOptHeader
->SizeOfHeaders
;
527 else if(!AlignUp(&cbHeadersSize
, cbSectionHeadersOffsetSize
, nFileAlignment
))
528 DIE(("Overflow aligning the size of headers\n"));
535 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
536 /* WARNING: piohOptHeader IS NO LONGER USABLE */
537 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
539 if(FileHeaderSize
< cbSectionHeadersOffsetSize
)
540 pishSectionHeaders
= NULL
;
544 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
545 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
547 ASSERT(Intsafe_CanOffsetPointer(FileHeader
, cbSectionHeadersOffset
));
548 pishSectionHeaders
= (PVOID
)((UINT_PTR
)FileHeader
+ cbSectionHeadersOffset
);
552 * the buffer doesn't contain the section headers, or the alignment is wrong:
553 * read the headers from the file
555 if(FileHeaderSize
< cbSectionHeadersOffsetSize
||
556 (UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
561 lnOffset
.QuadPart
= cbSectionHeadersOffset
;
563 /* read the header from the file */
564 nStatus
= ReadFileCb(File
, &lnOffset
, cbSectionHeadersSize
, &pData
, &pBuffer
, &cbReadSize
);
566 if(!NT_SUCCESS(nStatus
))
567 DIE(("ReadFile failed with status %08X\n", nStatus
));
571 ASSERT(cbReadSize
> 0);
573 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
575 /* the buffer doesn't contain all the section headers */
576 if(cbReadSize
< cbSectionHeadersSize
)
577 DIE(("The file doesn't contain all of the section headers\n"));
579 pishSectionHeaders
= pData
;
581 /* object still not aligned: copy it to the beginning of the buffer */
582 if((UINT_PTR
)pishSectionHeaders
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) != 0)
584 ASSERT((UINT_PTR
)pBuffer
% TYPE_ALIGNMENT(IMAGE_SECTION_HEADER
) == 0);
585 RtlMoveMemory(pBuffer
, pData
, cbReadSize
);
586 pishSectionHeaders
= pBuffer
;
591 /* allocate the segments */
592 nStatus
= STATUS_INSUFFICIENT_RESOURCES
;
593 ImageSectionObject
->Segments
= AllocateSegmentsCb(ImageSectionObject
->NrSegments
);
595 if(ImageSectionObject
->Segments
== NULL
)
596 DIE(("AllocateSegments failed\n"));
598 /* initialize the headers segment */
599 pssSegments
= ImageSectionObject
->Segments
;
601 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
603 if(!AlignUp(&nFileSizeOfHeaders
, cbHeadersSize
, nFileAlignment
))
604 DIE(("Cannot align the size of the section headers\n"));
606 nPrevVirtualEndOfSegment
= ALIGN_UP_BY(cbHeadersSize
, nSectionAlignment
);
607 if (nPrevVirtualEndOfSegment
< cbHeadersSize
)
608 DIE(("Cannot align the size of the section headers\n"));
610 pssSegments
[0].Image
.FileOffset
= 0;
611 pssSegments
[0].Protection
= PAGE_READONLY
;
612 pssSegments
[0].Length
.QuadPart
= nPrevVirtualEndOfSegment
;
613 pssSegments
[0].RawLength
.QuadPart
= nFileSizeOfHeaders
;
614 pssSegments
[0].Image
.VirtualAddress
= 0;
615 pssSegments
[0].Image
.Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
;
616 pssSegments
[0].WriteCopy
= TRUE
;
618 /* skip the headers segment */
621 nStatus
= STATUS_INVALID_IMAGE_FORMAT
;
623 /* convert the executable sections into segments. See also [1], section 4 */
624 for(i
= 0; i
< ImageSectionObject
->NrSegments
- 1; ++ i
)
626 ULONG nCharacteristics
;
628 /* validate the alignment */
629 if(!IsAligned(pishSectionHeaders
[i
].VirtualAddress
, nSectionAlignment
))
630 DIE(("Image.VirtualAddress[%u] is not aligned\n", i
));
632 /* sections must be contiguous, ordered by base address and non-overlapping */
633 if(pishSectionHeaders
[i
].VirtualAddress
!= nPrevVirtualEndOfSegment
)
634 DIE(("Memory gap between section %u and the previous\n", i
));
636 /* ignore explicit BSS sections */
637 if(pishSectionHeaders
[i
].SizeOfRawData
!= 0)
639 /* validate the alignment */
641 /* Yes, this should be a multiple of FileAlignment, but there's
642 * stuff out there that isn't. We can cope with that
644 if(!IsAligned(pishSectionHeaders
[i
].SizeOfRawData
, nFileAlignment
))
645 DIE(("SizeOfRawData[%u] is not aligned\n", i
));
648 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
649 // DIE(("PointerToRawData[%u] is not aligned\n", i));
652 pssSegments
[i
].Image
.FileOffset
= pishSectionHeaders
[i
].PointerToRawData
;
653 pssSegments
[i
].RawLength
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
657 ASSERT(pssSegments
[i
].Image
.FileOffset
== 0);
658 ASSERT(pssSegments
[i
].RawLength
.QuadPart
== 0);
661 ASSERT(Intsafe_CanAddLong64(pssSegments
[i
].Image
.FileOffset
, pssSegments
[i
].RawLength
.QuadPart
));
663 nCharacteristics
= pishSectionHeaders
[i
].Characteristics
;
665 /* no explicit protection */
666 if((nCharacteristics
& (IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)) == 0)
668 if(nCharacteristics
& IMAGE_SCN_CNT_CODE
)
669 nCharacteristics
|= IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
;
671 if(nCharacteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
672 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
674 if(nCharacteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
675 nCharacteristics
|= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
;
678 /* see table above */
679 pssSegments
[i
].Protection
= SectionCharacteristicsToProtect
[nCharacteristics
>> 28];
680 pssSegments
[i
].WriteCopy
= !(nCharacteristics
& IMAGE_SCN_MEM_SHARED
);
682 if(pishSectionHeaders
[i
].Misc
.VirtualSize
== 0 || pishSectionHeaders
[i
].Misc
.VirtualSize
< pishSectionHeaders
[i
].SizeOfRawData
)
683 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].SizeOfRawData
;
685 pssSegments
[i
].Length
.QuadPart
= pishSectionHeaders
[i
].Misc
.VirtualSize
;
687 pssSegments
[i
].Length
.LowPart
= ALIGN_UP_BY(pssSegments
[i
].Length
.LowPart
, nSectionAlignment
);
688 if (pssSegments
[i
].Length
.QuadPart
< pssSegments
[i
].Length
.QuadPart
)
689 DIE(("Cannot align the virtual size of section %u\n", i
));
691 if(pssSegments
[i
].Length
.QuadPart
== 0)
692 DIE(("Virtual size of section %u is null\n", i
));
694 pssSegments
[i
].Image
.VirtualAddress
= pishSectionHeaders
[i
].VirtualAddress
;
695 pssSegments
[i
].Image
.Characteristics
= pishSectionHeaders
[i
].Characteristics
;
697 /* ensure the memory image is no larger than 4GB */
698 nPrevVirtualEndOfSegment
= pssSegments
[i
].Image
.VirtualAddress
+ pssSegments
[i
].Length
.QuadPart
;
699 if (nPrevVirtualEndOfSegment
< pssSegments
[i
].Image
.VirtualAddress
)
700 DIE(("The image is too large\n"));
703 if(nSectionAlignment
>= PAGE_SIZE
)
704 *Flags
|= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
;
707 nStatus
= STATUS_ROS_EXEFMT_LOADED_FORMAT
| EXEFMT_LOADED_PE32
;
716 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
719 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
720 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
721 * RETURNS: Status of the wait.
724 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
726 LARGE_INTEGER Timeout
;
727 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
729 Timeout
.QuadPart
= -100000000LL; // 10 sec
732 Timeout
.QuadPart
= -100000000; // 10 sec
735 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
740 * FUNCTION: Sets the page op completion event and releases the page op.
741 * ARGUMENTS: PMM_PAGEOP.
742 * RETURNS: In shorter time than it takes you to even read this
743 * description, so don't even think about geting a mug of coffee.
746 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
748 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
749 MmReleasePageOp(PageOp
);
754 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
755 * ARGUMENTS: PFILE_OBJECT to wait for.
756 * RETURNS: Status of the wait.
759 MmspWaitForFileLock(PFILE_OBJECT File
)
761 return STATUS_SUCCESS
;
762 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
767 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
769 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
771 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
772 PMM_SECTION_SEGMENT SectionSegments
;
776 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
777 NrSegments
= ImageSectionObject
->NrSegments
;
778 SectionSegments
= ImageSectionObject
->Segments
;
779 for (i
= 0; i
< NrSegments
; i
++)
781 if (SectionSegments
[i
].ReferenceCount
!= 0)
783 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
784 SectionSegments
[i
].ReferenceCount
);
785 KeBugCheck(MEMORY_MANAGEMENT
);
787 MmFreePageTablesSectionSegment(&SectionSegments
[i
], NULL
);
789 ExFreePool(ImageSectionObject
->Segments
);
790 ExFreePool(ImageSectionObject
);
791 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
793 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
795 PMM_SECTION_SEGMENT Segment
;
797 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
800 if (Segment
->ReferenceCount
!= 0)
802 DPRINT1("Data segment still referenced\n");
803 KeBugCheck(MEMORY_MANAGEMENT
);
805 MmFreePageTablesSectionSegment(Segment
, NULL
);
807 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
813 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
814 PLARGE_INTEGER Offset
)
818 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
821 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
822 KeBugCheck(MEMORY_MANAGEMENT
);
824 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
826 DPRINT1("Maximum share count reached\n");
827 KeBugCheck(MEMORY_MANAGEMENT
);
829 if (IS_SWAP_FROM_SSE(Entry
))
831 KeBugCheck(MEMORY_MANAGEMENT
);
833 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
834 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
839 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
840 PMM_SECTION_SEGMENT Segment
,
841 PLARGE_INTEGER Offset
,
846 BOOLEAN IsDirectMapped
= FALSE
;
848 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
851 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
852 KeBugCheck(MEMORY_MANAGEMENT
);
854 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
856 DPRINT1("Zero share count for unshare\n");
857 KeBugCheck(MEMORY_MANAGEMENT
);
859 if (IS_SWAP_FROM_SSE(Entry
))
861 KeBugCheck(MEMORY_MANAGEMENT
);
863 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
865 * If we reducing the share count of this entry to zero then set the entry
866 * to zero and tell the cache the page is no longer mapped.
868 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
870 PFILE_OBJECT FileObject
;
874 SWAPENTRY SavedSwapEntry
;
876 BOOLEAN IsImageSection
;
877 LARGE_INTEGER FileOffset
;
879 FileOffset
.QuadPart
= Offset
->QuadPart
+ Segment
->Image
.FileOffset
;
881 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
883 Page
= PFN_FROM_SSE(Entry
);
884 FileObject
= Section
->FileObject
;
885 if (FileObject
!= NULL
&&
886 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
890 if ((FileOffset
.QuadPart
% PAGE_SIZE
) == 0 &&
891 (Offset
->QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
894 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
895 IsDirectMapped
= TRUE
;
897 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
.LowPart
, Dirty
);
899 Status
= STATUS_SUCCESS
;
901 if (!NT_SUCCESS(Status
))
903 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
904 KeBugCheck(MEMORY_MANAGEMENT
);
910 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
911 if (SavedSwapEntry
== 0)
914 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
915 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)))
919 * Try to page out this page and set the swap entry
920 * within the section segment. There exist no rmap entry
921 * for this page. The pager thread can't page out a
922 * page without a rmap entry.
924 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
928 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
931 MmReleasePageMemoryConsumer(MC_USER
, Page
);
937 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
938 (Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
946 * We hold all locks. Nobody can do something with the current
947 * process and the current segment (also not within an other process).
950 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
951 if (!NT_SUCCESS(Status
))
953 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
954 KeBugCheck(MEMORY_MANAGEMENT
);
957 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
958 MmSetSavedSwapEntryPage(Page
, 0);
960 MmReleasePageMemoryConsumer(MC_USER
, Page
);
964 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
965 KeBugCheck(MEMORY_MANAGEMENT
);
971 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
973 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
976 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
980 if (!(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
983 PCACHE_SEGMENT CacheSeg
;
984 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
985 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
);
988 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
998 MiCopyFromUserPage(PFN_NUMBER DestPage
, PVOID SourceAddress
)
1004 ASSERT((ULONG_PTR
)SourceAddress
% PAGE_SIZE
== 0);
1005 Process
= PsGetCurrentProcess();
1006 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
1007 if (TempAddress
== NULL
)
1009 return(STATUS_NO_MEMORY
);
1011 ASSERT((ULONG_PTR
)TempAddress
% PAGE_SIZE
== 0);
1012 RtlCopyMemory(TempAddress
, SourceAddress
, PAGE_SIZE
);
1013 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
1014 return(STATUS_SUCCESS
);
1020 MiReadPage(PMEMORY_AREA MemoryArea
,
1021 ULONG_PTR SegOffset
,
1024 * FUNCTION: Read a page for a section backed memory area.
1026 * MemoryArea - Memory area to read the page for.
1027 * Offset - Offset of the page to read.
1028 * Page - Variable that receives a page contains the read data.
1032 ULONG_PTR FileOffset
;
1035 PCACHE_SEGMENT CacheSeg
;
1036 PFILE_OBJECT FileObject
;
1038 ULONG_PTR RawLength
;
1040 BOOLEAN IsImageSection
;
1043 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1044 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1045 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
.QuadPart
;
1046 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1047 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1051 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
1054 * If the file system is letting us go directly to the cache and the
1055 * memory area was mapped at an offset in the file which is page aligned
1056 * then get the related cache segment.
1058 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1059 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
1060 !(MemoryArea
->Data
.SectionData
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1064 * Get the related cache segment; we use a lower level interface than
1065 * filesystems do because it is safe for us to use an offset with a
1066 * alignment less than the file system block size.
1068 Status
= CcRosGetCacheSegment(Bcb
,
1074 if (!NT_SUCCESS(Status
))
1081 * If the cache segment isn't up to date then call the file
1082 * system to read in the data.
1084 Status
= ReadCacheSegment(CacheSeg
);
1085 if (!NT_SUCCESS(Status
))
1087 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1092 * Retrieve the page from the cache segment that we actually want.
1094 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
1095 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
1097 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
1104 ULONG_PTR CacheSegOffset
;
1107 * Allocate a page, this is rather complicated by the possibility
1108 * we might have to move other things out of memory
1110 MI_SET_USAGE(MI_USAGE_SECTION
);
1111 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
1112 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
1113 if (!NT_SUCCESS(Status
))
1117 Status
= CcRosGetCacheSegment(Bcb
,
1123 if (!NT_SUCCESS(Status
))
1130 * If the cache segment isn't up to date then call the file
1131 * system to read in the data.
1133 Status
= ReadCacheSegment(CacheSeg
);
1134 if (!NT_SUCCESS(Status
))
1136 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1141 Process
= PsGetCurrentProcess();
1142 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1143 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
1144 Length
= RawLength
- SegOffset
;
1145 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
1147 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
1149 else if (CacheSegOffset
>= PAGE_SIZE
)
1151 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
1155 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
1156 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1157 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1158 Status
= CcRosGetCacheSegment(Bcb
,
1159 (ULONG
)(FileOffset
+ CacheSegOffset
),
1164 if (!NT_SUCCESS(Status
))
1171 * If the cache segment isn't up to date then call the file
1172 * system to read in the data.
1174 Status
= ReadCacheSegment(CacheSeg
);
1175 if (!NT_SUCCESS(Status
))
1177 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
1181 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
1182 if (Length
< PAGE_SIZE
)
1184 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
1188 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
1191 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
1192 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
1194 return(STATUS_SUCCESS
);
1199 MiReadPage(PMEMORY_AREA MemoryArea
,
1203 * FUNCTION: Read a page for a section backed memory area.
1205 * MemoryArea - Memory area to read the page for.
1206 * Offset - Offset of the page to read.
1207 * Page - Variable that receives a page contains the read data.
1210 MM_REQUIRED_RESOURCES Resources
;
1213 RtlZeroMemory(&Resources
, sizeof(MM_REQUIRED_RESOURCES
));
1215 Resources
.Context
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1216 Resources
.FileOffset
.QuadPart
= SegOffset
+
1217 MemoryArea
->Data
.SectionData
.Segment
->Image
.FileOffset
;
1218 Resources
.Consumer
= MC_USER
;
1219 Resources
.Amount
= PAGE_SIZE
;
1221 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]);
1223 Status
= MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea
, &Resources
);
1224 *Page
= Resources
.Page
[0];
1231 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
1232 MEMORY_AREA
* MemoryArea
,
1236 LARGE_INTEGER Offset
;
1239 PROS_SECTION_OBJECT Section
;
1240 PMM_SECTION_SEGMENT Segment
;
1246 BOOLEAN HasSwapEntry
;
1248 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1251 * There is a window between taking the page fault and locking the
1252 * address space when another thread could load the page so we check
1255 if (MmIsPagePresent(Process
, Address
))
1257 return(STATUS_SUCCESS
);
1261 * Check for the virtual memory area being deleted.
1263 if (MemoryArea
->DeleteInProgress
)
1265 return(STATUS_UNSUCCESSFUL
);
1268 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1269 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1270 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1272 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1273 Section
= MemoryArea
->Data
.SectionData
.Section
;
1274 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1275 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1277 ASSERT(Region
!= NULL
);
1281 MmLockSectionSegment(Segment
);
1284 * Check if this page needs to be mapped COW
1286 if ((Segment
->WriteCopy
) &&
1287 (Region
->Protect
== PAGE_READWRITE
||
1288 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
1290 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
1294 Attributes
= Region
->Protect
;
1298 * Get or create a page operation descriptor
1300 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
.LowPart
, MM_PAGEOP_PAGEIN
, FALSE
);
1303 DPRINT1("MmGetPageOp failed\n");
1304 KeBugCheck(MEMORY_MANAGEMENT
);
1308 * Check if someone else is already handling this fault, if so wait
1311 if (PageOp
->Thread
!= PsGetCurrentThread())
1313 MmUnlockSectionSegment(Segment
);
1314 MmUnlockAddressSpace(AddressSpace
);
1315 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1317 * Check for various strange conditions
1319 if (Status
!= STATUS_SUCCESS
)
1321 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1322 KeBugCheck(MEMORY_MANAGEMENT
);
1324 if (PageOp
->Status
== STATUS_PENDING
)
1326 DPRINT1("Woke for page op before completion\n");
1327 KeBugCheck(MEMORY_MANAGEMENT
);
1329 MmLockAddressSpace(AddressSpace
);
1331 * If this wasn't a pagein then restart the operation
1333 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
1335 MmspCompleteAndReleasePageOp(PageOp
);
1336 DPRINT("Address 0x%.8X\n", Address
);
1337 return(STATUS_MM_RESTART_OPERATION
);
1341 * If the thread handling this fault has failed then we don't retry
1343 if (!NT_SUCCESS(PageOp
->Status
))
1345 Status
= PageOp
->Status
;
1346 MmspCompleteAndReleasePageOp(PageOp
);
1347 DPRINT("Address 0x%.8X\n", Address
);
1350 MmLockSectionSegment(Segment
);
1352 * If the completed fault was for another address space then set the
1355 if (!MmIsPagePresent(Process
, Address
))
1357 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1358 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
1360 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
1363 * The page was a private page in another or in our address space
1365 MmUnlockSectionSegment(Segment
);
1366 MmspCompleteAndReleasePageOp(PageOp
);
1367 return(STATUS_MM_RESTART_OPERATION
);
1370 Page
= PFN_FROM_SSE(Entry
);
1372 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1374 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
1375 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
1377 Status
= MmCreateVirtualMapping(Process
,
1382 if (!NT_SUCCESS(Status
))
1384 DPRINT1("Unable to create virtual mapping\n");
1385 KeBugCheck(MEMORY_MANAGEMENT
);
1387 MmInsertRmap(Page
, Process
, Address
);
1389 MmUnlockSectionSegment(Segment
);
1390 PageOp
->Status
= STATUS_SUCCESS
;
1391 MmspCompleteAndReleasePageOp(PageOp
);
1392 DPRINT("Address 0x%.8X\n", Address
);
1393 return(STATUS_SUCCESS
);
1396 HasSwapEntry
= MmIsPageSwapEntry(Process
, Address
);
1400 * Must be private page we have swapped out.
1402 SWAPENTRY SwapEntry
;
1407 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1409 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1410 KeBugCheck(MEMORY_MANAGEMENT
);
1413 MmUnlockSectionSegment(Segment
);
1414 MmDeletePageFileMapping(Process
, Address
, &SwapEntry
);
1416 MmUnlockAddressSpace(AddressSpace
);
1417 MI_SET_USAGE(MI_USAGE_SECTION
);
1418 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1419 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1420 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1421 if (!NT_SUCCESS(Status
))
1423 KeBugCheck(MEMORY_MANAGEMENT
);
1426 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1427 if (!NT_SUCCESS(Status
))
1429 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
1430 KeBugCheck(MEMORY_MANAGEMENT
);
1432 MmLockAddressSpace(AddressSpace
);
1433 Status
= MmCreateVirtualMapping(Process
,
1438 if (!NT_SUCCESS(Status
))
1440 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1441 KeBugCheck(MEMORY_MANAGEMENT
);
1446 * Store the swap entry for later use.
1448 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1451 * Add the page to the process's working set
1453 MmInsertRmap(Page
, Process
, Address
);
1455 * Finish the operation
1457 PageOp
->Status
= STATUS_SUCCESS
;
1458 MmspCompleteAndReleasePageOp(PageOp
);
1459 DPRINT("Address 0x%.8X\n", Address
);
1460 return(STATUS_SUCCESS
);
1464 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1466 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1468 MmUnlockSectionSegment(Segment
);
1470 * Just map the desired physical page
1472 Page
= Offset
.QuadPart
>> PAGE_SHIFT
;
1473 Status
= MmCreateVirtualMappingUnsafe(Process
,
1478 if (!NT_SUCCESS(Status
))
1480 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1481 KeBugCheck(MEMORY_MANAGEMENT
);
1486 * Cleanup and release locks
1488 PageOp
->Status
= STATUS_SUCCESS
;
1489 MmspCompleteAndReleasePageOp(PageOp
);
1490 DPRINT("Address 0x%.8X\n", Address
);
1491 return(STATUS_SUCCESS
);
1495 * Map anonymous memory for BSS sections
1497 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1499 MmUnlockSectionSegment(Segment
);
1500 MI_SET_USAGE(MI_USAGE_SECTION
);
1501 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1502 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1503 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1504 if (!NT_SUCCESS(Status
))
1506 MmUnlockAddressSpace(AddressSpace
);
1507 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1508 MmLockAddressSpace(AddressSpace
);
1510 if (!NT_SUCCESS(Status
))
1512 KeBugCheck(MEMORY_MANAGEMENT
);
1514 Status
= MmCreateVirtualMapping(Process
,
1519 if (!NT_SUCCESS(Status
))
1521 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1522 KeBugCheck(MEMORY_MANAGEMENT
);
1525 MmInsertRmap(Page
, Process
, Address
);
1528 * Cleanup and release locks
1530 PageOp
->Status
= STATUS_SUCCESS
;
1531 MmspCompleteAndReleasePageOp(PageOp
);
1532 DPRINT("Address 0x%.8X\n", Address
);
1533 return(STATUS_SUCCESS
);
1537 * Get the entry corresponding to the offset within the section
1539 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1544 * If the entry is zero (and it can't change because we have
1545 * locked the segment) then we need to load the page.
1549 * Release all our locks and read in the page from disk
1551 MmUnlockSectionSegment(Segment
);
1552 MmUnlockAddressSpace(AddressSpace
);
1554 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1555 (Offset
.QuadPart
>= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1557 MI_SET_USAGE(MI_USAGE_SECTION
);
1558 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1559 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1560 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1561 if (!NT_SUCCESS(Status
))
1563 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1569 Status
= MiReadPage(MemoryArea
, Offset
.QuadPart
, &Page
);
1570 if (!NT_SUCCESS(Status
))
1572 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1575 if (!NT_SUCCESS(Status
))
1578 * FIXME: What do we know in this case?
1581 * Cleanup and release locks
1583 MmLockAddressSpace(AddressSpace
);
1584 PageOp
->Status
= Status
;
1585 MmspCompleteAndReleasePageOp(PageOp
);
1586 DPRINT("Address 0x%.8X\n", Address
);
1590 * Relock the address space and segment
1592 MmLockAddressSpace(AddressSpace
);
1593 MmLockSectionSegment(Segment
);
1596 * Check the entry. No one should change the status of a page
1597 * that has a pending page-in.
1599 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1600 if (Entry
!= Entry1
)
1602 DPRINT1("Someone changed ppte entry while we slept\n");
1603 KeBugCheck(MEMORY_MANAGEMENT
);
1607 * Mark the offset within the section as having valid, in-memory
1610 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1611 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1612 MmUnlockSectionSegment(Segment
);
1614 Status
= MmCreateVirtualMapping(Process
,
1619 if (!NT_SUCCESS(Status
))
1621 DPRINT1("Unable to create virtual mapping\n");
1622 KeBugCheck(MEMORY_MANAGEMENT
);
1624 MmInsertRmap(Page
, Process
, Address
);
1626 PageOp
->Status
= STATUS_SUCCESS
;
1627 MmspCompleteAndReleasePageOp(PageOp
);
1628 DPRINT("Address 0x%.8X\n", Address
);
1629 return(STATUS_SUCCESS
);
1631 else if (IS_SWAP_FROM_SSE(Entry
))
1633 SWAPENTRY SwapEntry
;
1635 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1638 * Release all our locks and read in the page from disk
1640 MmUnlockSectionSegment(Segment
);
1642 MmUnlockAddressSpace(AddressSpace
);
1643 MI_SET_USAGE(MI_USAGE_SECTION
);
1644 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1645 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1646 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1647 if (!NT_SUCCESS(Status
))
1649 KeBugCheck(MEMORY_MANAGEMENT
);
1652 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1653 if (!NT_SUCCESS(Status
))
1655 KeBugCheck(MEMORY_MANAGEMENT
);
1659 * Relock the address space and segment
1661 MmLockAddressSpace(AddressSpace
);
1662 MmLockSectionSegment(Segment
);
1665 * Check the entry. No one should change the status of a page
1666 * that has a pending page-in.
1668 Entry1
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1669 if (Entry
!= Entry1
)
1671 DPRINT1("Someone changed ppte entry while we slept\n");
1672 KeBugCheck(MEMORY_MANAGEMENT
);
1676 * Mark the offset within the section as having valid, in-memory
1679 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1680 MmSetPageEntrySectionSegment(Segment
, &Offset
, Entry
);
1681 MmUnlockSectionSegment(Segment
);
1684 * Save the swap entry.
1686 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1687 Status
= MmCreateVirtualMapping(Process
,
1692 if (!NT_SUCCESS(Status
))
1694 DPRINT1("Unable to create virtual mapping\n");
1695 KeBugCheck(MEMORY_MANAGEMENT
);
1697 MmInsertRmap(Page
, Process
, Address
);
1698 PageOp
->Status
= STATUS_SUCCESS
;
1699 MmspCompleteAndReleasePageOp(PageOp
);
1700 DPRINT("Address 0x%.8X\n", Address
);
1701 return(STATUS_SUCCESS
);
1706 * If the section offset is already in-memory and valid then just
1707 * take another reference to the page
1710 Page
= PFN_FROM_SSE(Entry
);
1712 MmSharePageEntrySectionSegment(Segment
, &Offset
);
1713 MmUnlockSectionSegment(Segment
);
1715 Status
= MmCreateVirtualMapping(Process
,
1720 if (!NT_SUCCESS(Status
))
1722 DPRINT1("Unable to create virtual mapping\n");
1723 KeBugCheck(MEMORY_MANAGEMENT
);
1725 MmInsertRmap(Page
, Process
, Address
);
1726 PageOp
->Status
= STATUS_SUCCESS
;
1727 MmspCompleteAndReleasePageOp(PageOp
);
1728 DPRINT("Address 0x%.8X\n", Address
);
1729 return(STATUS_SUCCESS
);
1735 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1736 MEMORY_AREA
* MemoryArea
,
1739 PMM_SECTION_SEGMENT Segment
;
1740 PROS_SECTION_OBJECT Section
;
1745 LARGE_INTEGER Offset
;
1749 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1751 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
);
1754 * Check if the page has already been set readwrite
1756 if (MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1758 DPRINT("Address 0x%.8X\n", Address
);
1759 return(STATUS_SUCCESS
);
1763 * Find the offset of the page
1765 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1766 Offset
.QuadPart
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1767 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1769 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1770 Section
= MemoryArea
->Data
.SectionData
.Section
;
1771 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1772 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1774 ASSERT(Region
!= NULL
);
1778 MmLockSectionSegment(Segment
);
1780 OldPage
= MmGetPfnForProcess(Process
, Address
);
1781 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
1783 MmUnlockSectionSegment(Segment
);
1786 * Check if we are doing COW
1788 if (!((Segment
->WriteCopy
) &&
1789 (Region
->Protect
== PAGE_READWRITE
||
1790 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1792 DPRINT("Address 0x%.8X\n", Address
);
1793 return(STATUS_ACCESS_VIOLATION
);
1796 if (IS_SWAP_FROM_SSE(Entry
) ||
1797 PFN_FROM_SSE(Entry
) != OldPage
)
1799 /* This is a private page. We must only change the page protection. */
1800 MmSetPageProtect(Process
, Address
, Region
->Protect
);
1801 return(STATUS_SUCCESS
);
1805 DPRINT("OldPage == 0!\n");
1808 * Get or create a pageop
1810 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
.LowPart
,
1811 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1814 DPRINT1("MmGetPageOp failed\n");
1815 KeBugCheck(MEMORY_MANAGEMENT
);
1819 * Wait for any other operations to complete
1821 if (PageOp
->Thread
!= PsGetCurrentThread())
1823 MmUnlockAddressSpace(AddressSpace
);
1824 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1826 * Check for various strange conditions
1828 if (Status
== STATUS_TIMEOUT
)
1830 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1831 KeBugCheck(MEMORY_MANAGEMENT
);
1833 if (PageOp
->Status
== STATUS_PENDING
)
1835 DPRINT1("Woke for page op before completion\n");
1836 KeBugCheck(MEMORY_MANAGEMENT
);
1839 * Restart the operation
1841 MmLockAddressSpace(AddressSpace
);
1842 MmspCompleteAndReleasePageOp(PageOp
);
1843 DPRINT("Address 0x%.8X\n", Address
);
1844 return(STATUS_MM_RESTART_OPERATION
);
1848 * Release locks now we have the pageop
1850 MmUnlockAddressSpace(AddressSpace
);
1855 MI_SET_USAGE(MI_USAGE_SECTION
);
1856 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
1857 if (!Process
) MI_SET_PROCESS2("Kernel Section");
1858 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1859 if (!NT_SUCCESS(Status
))
1861 KeBugCheck(MEMORY_MANAGEMENT
);
1867 MiCopyFromUserPage(NewPage
, PAddress
);
1869 MmLockAddressSpace(AddressSpace
);
1871 * Delete the old entry.
1873 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1876 * Set the PTE to point to the new page
1878 Status
= MmCreateVirtualMapping(Process
,
1883 if (!NT_SUCCESS(Status
))
1885 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1886 KeBugCheck(MEMORY_MANAGEMENT
);
1889 if (!NT_SUCCESS(Status
))
1891 DPRINT1("Unable to create virtual mapping\n");
1892 KeBugCheck(MEMORY_MANAGEMENT
);
1896 * Unshare the old page.
1898 MmDeleteRmap(OldPage
, Process
, PAddress
);
1899 MmInsertRmap(NewPage
, Process
, PAddress
);
1900 MmLockSectionSegment(Segment
);
1901 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, FALSE
, FALSE
);
1902 MmUnlockSectionSegment(Segment
);
1904 PageOp
->Status
= STATUS_SUCCESS
;
1905 MmspCompleteAndReleasePageOp(PageOp
);
1906 DPRINT("Address 0x%.8X\n", Address
);
1907 return(STATUS_SUCCESS
);
1911 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1913 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1917 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1920 MmLockAddressSpace(&Process
->Vm
);
1923 MmDeleteVirtualMapping(Process
,
1930 PageOutContext
->WasDirty
= TRUE
;
1932 if (!PageOutContext
->Private
)
1934 MmLockSectionSegment(PageOutContext
->Segment
);
1935 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1936 PageOutContext
->Segment
,
1937 &PageOutContext
->Offset
,
1938 PageOutContext
->WasDirty
,
1940 MmUnlockSectionSegment(PageOutContext
->Segment
);
1944 MmUnlockAddressSpace(&Process
->Vm
);
1947 if (PageOutContext
->Private
)
1949 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1952 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1957 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1958 MEMORY_AREA
* MemoryArea
,
1963 MM_SECTION_PAGEOUT_CONTEXT Context
;
1964 SWAPENTRY SwapEntry
;
1968 PFILE_OBJECT FileObject
;
1972 BOOLEAN DirectMapped
;
1973 BOOLEAN IsImageSection
;
1974 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1977 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1980 * Get the segment and section.
1982 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1983 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1984 Context
.CallingProcess
= Process
;
1986 Context
.Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1987 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
1988 FileOffset
= Context
.Offset
.QuadPart
+ Context
.Segment
->Image
.FileOffset
;
1990 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1992 FileObject
= Context
.Section
->FileObject
;
1993 DirectMapped
= FALSE
;
1996 if (FileObject
!= NULL
&&
1997 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
1999 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2002 * If the file system is letting us go directly to the cache and the
2003 * memory area was mapped at an offset in the file which is page aligned
2004 * then note this is a direct mapped page.
2006 if ((FileOffset
% PAGE_SIZE
) == 0 &&
2007 (Context
.Offset
.QuadPart
+ PAGE_SIZE
<= Context
.Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2009 DirectMapped
= TRUE
;
2016 * This should never happen since mappings of physical memory are never
2017 * placed in the rmap lists.
2019 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2021 DPRINT1("Trying to page out from physical memory section address 0x%X "
2022 "process %d\n", Address
,
2023 Process
? Process
->UniqueProcessId
: 0);
2024 KeBugCheck(MEMORY_MANAGEMENT
);
2028 * Get the section segment entry and the physical address.
2030 if (!MmIsPagePresent(Process
, Address
))
2032 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2033 Process
? Process
->UniqueProcessId
: 0, Address
);
2034 KeBugCheck(MEMORY_MANAGEMENT
);
2036 Page
= MmGetPfnForProcess(Process
, Address
);
2037 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2040 * Check the reference count to ensure this page can be paged out
2042 if (MmGetReferenceCountPage(Page
) != 1)
2044 DPRINT("Cannot page out locked section page: 0x%p (RefCount: %d)\n",
2045 Page
, MmGetReferenceCountPage(Page
));
2046 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2047 MmspCompleteAndReleasePageOp(PageOp
);
2048 return STATUS_UNSUCCESSFUL
;
2052 * Prepare the context structure for the rmap delete call.
2054 MmLockSectionSegment(Context
.Segment
);
2055 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2056 MmUnlockSectionSegment(Context
.Segment
);
2057 Context
.WasDirty
= FALSE
;
2058 if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2059 IS_SWAP_FROM_SSE(Entry
) ||
2060 PFN_FROM_SSE(Entry
) != Page
)
2062 Context
.Private
= TRUE
;
2066 Context
.Private
= FALSE
;
2070 * Take an additional reference to the page or the cache segment.
2072 if (DirectMapped
&& !Context
.Private
)
2074 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
.LowPart
))
2076 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2077 KeBugCheck(MEMORY_MANAGEMENT
);
2082 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
2083 MmReferencePage(Page
);
2084 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
2087 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
2088 MmLockSectionSegment(Context
.Segment
);
2089 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2090 MmUnlockSectionSegment(Context
.Segment
);
2093 * If this wasn't a private page then we should have reduced the entry to
2094 * zero by deleting all the rmaps.
2096 if (!Context
.Private
&& Entry
!= 0)
2098 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
2099 !(Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2101 KeBugCheckEx(MEMORY_MANAGEMENT
, Entry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2106 * If the page wasn't dirty then we can just free it as for a readonly page.
2107 * Since we unmapped all the mappings above we know it will not suddenly
2109 * If the page is from a pagefile section and has no swap entry,
2110 * we can't free the page at this point.
2112 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2113 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2115 if (Context
.Private
)
2117 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
2118 Context
.WasDirty
? "dirty" : "clean", Address
);
2119 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2121 if (!Context
.WasDirty
&& SwapEntry
!= 0)
2123 MmSetSavedSwapEntryPage(Page
, 0);
2124 MmLockSectionSegment(Context
.Segment
);
2125 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2126 MmUnlockSectionSegment(Context
.Segment
);
2127 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2128 PageOp
->Status
= STATUS_SUCCESS
;
2129 MmspCompleteAndReleasePageOp(PageOp
);
2130 return(STATUS_SUCCESS
);
2133 else if (Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2135 if (Context
.Private
)
2137 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2138 Context
.WasDirty
? "dirty" : "clean", Address
);
2139 KeBugCheckEx(MEMORY_MANAGEMENT
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
2141 if (!Context
.WasDirty
|| SwapEntry
!= 0)
2143 MmSetSavedSwapEntryPage(Page
, 0);
2146 MmLockSectionSegment(Context
.Segment
);
2147 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2148 MmUnlockSectionSegment(Context
.Segment
);
2150 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2151 PageOp
->Status
= STATUS_SUCCESS
;
2152 MmspCompleteAndReleasePageOp(PageOp
);
2153 return(STATUS_SUCCESS
);
2156 else if (!Context
.Private
&& DirectMapped
)
2160 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2162 KeBugCheckEx(MEMORY_MANAGEMENT
, STATUS_UNSUCCESSFUL
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2165 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
2167 Status
= STATUS_SUCCESS
;
2170 if (!NT_SUCCESS(Status
))
2172 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
2173 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Bcb
, FileOffset
, (ULONG_PTR
)Address
);
2176 PageOp
->Status
= STATUS_SUCCESS
;
2177 MmspCompleteAndReleasePageOp(PageOp
);
2178 return(STATUS_SUCCESS
);
2180 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
2184 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2186 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, Page
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
);
2188 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2189 PageOp
->Status
= STATUS_SUCCESS
;
2190 MmspCompleteAndReleasePageOp(PageOp
);
2191 return(STATUS_SUCCESS
);
2193 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
2195 DPRINT1("Not dirty and private and not swapped (%p:%p)\n", Process
, Address
);
2196 MmSetSavedSwapEntryPage(Page
, 0);
2197 MmLockAddressSpace(AddressSpace
);
2198 Status
= MmCreatePageFileMapping(Process
,
2201 MmUnlockAddressSpace(AddressSpace
);
2202 if (!NT_SUCCESS(Status
))
2204 DPRINT1("Status %x Swapping out %p:%p\n", Status
, Process
, Address
);
2205 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2207 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2208 PageOp
->Status
= STATUS_SUCCESS
;
2209 MmspCompleteAndReleasePageOp(PageOp
);
2210 return(STATUS_SUCCESS
);
2214 * If necessary, allocate an entry in the paging file for this page
2218 SwapEntry
= MmAllocSwapPage();
2221 MmShowOutOfSpaceMessagePagingFile();
2222 MmLockAddressSpace(AddressSpace
);
2224 * For private pages restore the old mappings.
2226 if (Context
.Private
)
2228 Status
= MmCreateVirtualMapping(Process
,
2230 MemoryArea
->Protect
,
2233 MmSetDirtyPage(Process
, Address
);
2242 * For non-private pages if the page wasn't direct mapped then
2243 * set it back into the section segment entry so we don't loose
2244 * our copy. Otherwise it will be handled by the cache manager.
2246 Status
= MmCreateVirtualMapping(Process
,
2248 MemoryArea
->Protect
,
2251 MmSetDirtyPage(Process
, Address
);
2255 // If we got here, the previous entry should have been a wait
2256 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2257 MmLockSectionSegment(Context
.Segment
);
2258 OldEntry
= MmGetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
);
2259 ASSERT(OldEntry
== 0 || OldEntry
== MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
2260 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2261 MmUnlockSectionSegment(Context
.Segment
);
2263 MmUnlockAddressSpace(AddressSpace
);
2264 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2265 MmspCompleteAndReleasePageOp(PageOp
);
2266 return(STATUS_PAGEFILE_QUOTA
);
2271 * Write the page to the pagefile
2273 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2274 if (!NT_SUCCESS(Status
))
2276 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2279 * As above: undo our actions.
2280 * FIXME: Also free the swap page.
2282 MmLockAddressSpace(AddressSpace
);
2283 if (Context
.Private
)
2285 Status
= MmCreateVirtualMapping(Process
,
2287 MemoryArea
->Protect
,
2290 MmSetDirtyPage(Process
, Address
);
2297 Status
= MmCreateVirtualMapping(Process
,
2299 MemoryArea
->Protect
,
2302 MmSetDirtyPage(Process
, Address
);
2306 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
2307 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2309 MmUnlockAddressSpace(AddressSpace
);
2310 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2311 MmspCompleteAndReleasePageOp(PageOp
);
2312 return(STATUS_UNSUCCESSFUL
);
2316 * Otherwise we have succeeded.
2318 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2319 MmLockSectionSegment(Context
.Segment
);
2320 MmSetSavedSwapEntryPage(Page
, 0);
2321 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
2322 Context
.Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2324 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
2328 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2331 if (Context
.Private
)
2333 MmLockAddressSpace(AddressSpace
);
2334 Status
= MmCreatePageFileMapping(Process
,
2337 MmUnlockAddressSpace(AddressSpace
);
2338 if (!NT_SUCCESS(Status
))
2340 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status
, Process
, Address
);
2341 KeBugCheckEx(MEMORY_MANAGEMENT
, Status
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, SwapEntry
);
2346 Entry
= MAKE_SWAP_SSE(SwapEntry
);
2347 MmSetPageEntrySectionSegment(Context
.Segment
, &Context
.Offset
, Entry
);
2350 MmUnlockSectionSegment(Context
.Segment
);
2351 PageOp
->Status
= STATUS_SUCCESS
;
2352 MmspCompleteAndReleasePageOp(PageOp
);
2353 return(STATUS_SUCCESS
);
2358 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
2359 PMEMORY_AREA MemoryArea
,
2363 LARGE_INTEGER Offset
;
2364 PROS_SECTION_OBJECT Section
;
2365 PMM_SECTION_SEGMENT Segment
;
2367 SWAPENTRY SwapEntry
;
2371 PFILE_OBJECT FileObject
;
2373 BOOLEAN DirectMapped
;
2374 BOOLEAN IsImageSection
;
2375 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2377 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2379 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2380 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2383 * Get the segment and section.
2385 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2386 Section
= MemoryArea
->Data
.SectionData
.Section
;
2387 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
2389 FileObject
= Section
->FileObject
;
2390 DirectMapped
= FALSE
;
2391 if (FileObject
!= NULL
&&
2392 !(Segment
->Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
))
2394 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
2397 * If the file system is letting us go directly to the cache and the
2398 * memory area was mapped at an offset in the file which is page aligned
2399 * then note this is a direct mapped page.
2401 if (((Offset
.QuadPart
+ Segment
->Image
.FileOffset
) % PAGE_SIZE
) == 0 &&
2402 (Offset
.QuadPart
+ PAGE_SIZE
<= Segment
->RawLength
.QuadPart
|| !IsImageSection
))
2404 DirectMapped
= TRUE
;
2409 * This should never happen since mappings of physical memory are never
2410 * placed in the rmap lists.
2412 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
2414 DPRINT1("Trying to write back page from physical memory mapped at %X "
2415 "process %d\n", Address
,
2416 Process
? Process
->UniqueProcessId
: 0);
2417 KeBugCheck(MEMORY_MANAGEMENT
);
2421 * Get the section segment entry and the physical address.
2423 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2424 if (!MmIsPagePresent(Process
, Address
))
2426 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2427 Process
? Process
->UniqueProcessId
: 0, Address
);
2428 KeBugCheck(MEMORY_MANAGEMENT
);
2430 Page
= MmGetPfnForProcess(Process
, Address
);
2431 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
2434 * Check for a private (COWed) page.
2436 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2437 IS_SWAP_FROM_SSE(Entry
) ||
2438 PFN_FROM_SSE(Entry
) != Page
)
2448 * Speculatively set all mappings of the page to clean.
2450 MmSetCleanAllRmaps(Page
);
2453 * If this page was direct mapped from the cache then the cache manager
2454 * will take care of writing it back to disk.
2456 if (DirectMapped
&& !Private
)
2458 ASSERT(SwapEntry
== 0);
2460 CcRosMarkDirtyCacheSegment(Bcb
, Offset
.LowPart
+ Segment
->Image
.FileOffset
);
2462 PageOp
->Status
= STATUS_SUCCESS
;
2463 MmspCompleteAndReleasePageOp(PageOp
);
2464 return(STATUS_SUCCESS
);
2468 * If necessary, allocate an entry in the paging file for this page
2472 SwapEntry
= MmAllocSwapPage();
2475 MmSetDirtyAllRmaps(Page
);
2476 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2477 MmspCompleteAndReleasePageOp(PageOp
);
2478 return(STATUS_PAGEFILE_QUOTA
);
2480 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2484 * Write the page to the pagefile
2486 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2487 if (!NT_SUCCESS(Status
))
2489 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2491 MmSetDirtyAllRmaps(Page
);
2492 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2493 MmspCompleteAndReleasePageOp(PageOp
);
2494 return(STATUS_UNSUCCESSFUL
);
2498 * Otherwise we have succeeded.
2500 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2501 PageOp
->Status
= STATUS_SUCCESS
;
2502 MmspCompleteAndReleasePageOp(PageOp
);
2503 return(STATUS_SUCCESS
);
2507 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2515 PMEMORY_AREA MemoryArea
;
2516 PMM_SECTION_SEGMENT Segment
;
2517 BOOLEAN DoCOW
= FALSE
;
2519 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2521 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2522 ASSERT(MemoryArea
!= NULL
);
2523 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2524 MmLockSectionSegment(Segment
);
2526 if ((Segment
->WriteCopy
) &&
2527 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2532 if (OldProtect
!= NewProtect
)
2534 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2536 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2537 ULONG Protect
= NewProtect
;
2540 * If we doing COW for this segment then check if the page is
2543 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2545 LARGE_INTEGER Offset
;
2549 Offset
.QuadPart
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2550 + MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
2551 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2552 Page
= MmGetPfnForProcess(Process
, Address
);
2554 Protect
= PAGE_READONLY
;
2555 if (Segment
->Image
.Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2556 IS_SWAP_FROM_SSE(Entry
) ||
2557 PFN_FROM_SSE(Entry
) != Page
)
2559 Protect
= NewProtect
;
2563 if (MmIsPagePresent(Process
, Address
))
2565 MmSetPageProtect(Process
, Address
,
2571 MmUnlockSectionSegment(Segment
);
2576 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2577 PMEMORY_AREA MemoryArea
,
2585 ULONG_PTR MaxLength
;
2587 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2588 if (Length
> MaxLength
)
2589 Length
= (ULONG
)MaxLength
;
2591 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2592 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2594 ASSERT(Region
!= NULL
);
2596 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2597 Region
->Protect
!= Protect
)
2599 return STATUS_INVALID_PAGE_PROTECTION
;
2602 *OldProtect
= Region
->Protect
;
2603 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2604 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2605 BaseAddress
, Length
, Region
->Type
, Protect
,
2606 MmAlterViewAttributes
);
2612 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2614 PMEMORY_BASIC_INFORMATION Info
,
2615 PSIZE_T ResultLength
)
2618 PVOID RegionBaseAddress
;
2619 PROS_SECTION_OBJECT Section
;
2620 PMM_SECTION_SEGMENT Segment
;
2622 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2623 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2624 Address
, &RegionBaseAddress
);
2627 return STATUS_UNSUCCESSFUL
;
2630 Section
= MemoryArea
->Data
.SectionData
.Section
;
2631 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2633 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2634 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->Image
.VirtualAddress
;
2635 Info
->Type
= MEM_IMAGE
;
2639 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2640 Info
->Type
= MEM_MAPPED
;
2642 Info
->BaseAddress
= RegionBaseAddress
;
2643 Info
->AllocationProtect
= MemoryArea
->Protect
;
2644 Info
->RegionSize
= Region
->Length
;
2645 Info
->State
= MEM_COMMIT
;
2646 Info
->Protect
= Region
->Protect
;
2648 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2649 return(STATUS_SUCCESS
);
2654 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2657 LARGE_INTEGER Offset
;
2659 SWAPENTRY SavedSwapEntry
;
2664 MmLockSectionSegment(Segment
);
2666 Length
= PAGE_ROUND_UP(Segment
->Length
.QuadPart
);
2667 for (Offset
.QuadPart
= 0; Offset
.QuadPart
< Length
; Offset
.QuadPart
+= PAGE_SIZE
)
2669 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
2672 MmSetPageEntrySectionSegment(Segment
, &Offset
, 0);
2673 if (IS_SWAP_FROM_SSE(Entry
))
2675 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2679 Page
= PFN_FROM_SSE(Entry
);
2680 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2681 if (SavedSwapEntry
!= 0)
2683 MmSetSavedSwapEntryPage(Page
, 0);
2684 MmFreeSwapPage(SavedSwapEntry
);
2686 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2691 MmUnlockSectionSegment(Segment
);
2695 MmpDeleteSection(PVOID ObjectBody
)
2697 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2699 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody
);
2700 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2705 PMM_SECTION_SEGMENT SectionSegments
;
2708 * NOTE: Section->ImageSection can be NULL for short time
2709 * during the section creating. If we fail for some reason
2710 * until the image section is properly initialized we shouldn't
2711 * process further here.
2713 if (Section
->ImageSection
== NULL
)
2716 SectionSegments
= Section
->ImageSection
->Segments
;
2717 NrSegments
= Section
->ImageSection
->NrSegments
;
2719 for (i
= 0; i
< NrSegments
; i
++)
2721 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2723 MmLockSectionSegment(&SectionSegments
[i
]);
2725 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2726 if (SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_MEM_SHARED
)
2728 MmUnlockSectionSegment(&SectionSegments
[i
]);
2731 MmpFreePageFileSegment(&SectionSegments
[i
]);
2737 else if (Section
->Segment
&& Section
->Segment
->Flags
& MM_DATAFILE_SEGMENT
)
2740 PMM_SECTION_SEGMENT Segment
= Section
->Segment
;
2743 (RefCount
= InterlockedDecrementUL(&Segment
->ReferenceCount
)) == 0)
2745 DPRINT("Freeing section segment\n");
2746 Section
->Segment
= NULL
;
2747 MmFinalizeSegment(Segment
);
2751 DPRINT("RefCount %d\n", RefCount
);
2758 * NOTE: Section->Segment can be NULL for short time
2759 * during the section creating.
2761 if (Section
->Segment
== NULL
)
2764 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2766 MmpFreePageFileSegment(Section
->Segment
);
2767 MmFreePageTablesSectionSegment(Section
->Segment
, NULL
);
2768 ExFreePool(Section
->Segment
);
2769 Section
->Segment
= NULL
;
2773 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2776 if (Section
->FileObject
!= NULL
)
2779 CcRosDereferenceCache(Section
->FileObject
);
2781 ObDereferenceObject(Section
->FileObject
);
2782 Section
->FileObject
= NULL
;
2787 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2789 IN ACCESS_MASK GrantedAccess
,
2790 IN ULONG ProcessHandleCount
,
2791 IN ULONG SystemHandleCount
)
2793 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2794 Object
, ProcessHandleCount
);
2800 MmCreatePhysicalMemorySection(VOID
)
2802 PROS_SECTION_OBJECT PhysSection
;
2804 OBJECT_ATTRIBUTES Obj
;
2805 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2806 LARGE_INTEGER SectionSize
;
2810 * Create the section mapping physical memory
2812 SectionSize
.QuadPart
= 0xFFFFFFFF;
2813 InitializeObjectAttributes(&Obj
,
2818 Status
= MmCreateSection((PVOID
)&PhysSection
,
2822 PAGE_EXECUTE_READWRITE
,
2826 if (!NT_SUCCESS(Status
))
2828 DPRINT1("Failed to create PhysicalMemory section\n");
2829 KeBugCheck(MEMORY_MANAGEMENT
);
2831 Status
= ObInsertObject(PhysSection
,
2837 if (!NT_SUCCESS(Status
))
2839 ObDereferenceObject(PhysSection
);
2841 ObCloseHandle(Handle
, KernelMode
);
2842 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2843 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2845 return(STATUS_SUCCESS
);
2851 MmInitSectionImplementation(VOID
)
2853 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2854 UNICODE_STRING Name
;
2856 DPRINT("Creating Section Object Type\n");
2858 /* Initialize the Section object type */
2859 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2860 RtlInitUnicodeString(&Name
, L
"Section");
2861 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2862 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2863 ObjectTypeInitializer
.PoolType
= PagedPool
;
2864 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2865 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2866 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2867 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2868 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2869 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2871 MmCreatePhysicalMemorySection();
2873 return(STATUS_SUCCESS
);
2878 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2879 ACCESS_MASK DesiredAccess
,
2880 POBJECT_ATTRIBUTES ObjectAttributes
,
2881 PLARGE_INTEGER UMaximumSize
,
2882 ULONG SectionPageProtection
,
2883 ULONG AllocationAttributes
)
2885 * Create a section which is backed by the pagefile
2888 LARGE_INTEGER MaximumSize
;
2889 PROS_SECTION_OBJECT Section
;
2890 PMM_SECTION_SEGMENT Segment
;
2893 if (UMaximumSize
== NULL
)
2895 return(STATUS_UNSUCCESSFUL
);
2897 MaximumSize
= *UMaximumSize
;
2900 * Create the section
2902 Status
= ObCreateObject(ExGetPreviousMode(),
2903 MmSectionObjectType
,
2905 ExGetPreviousMode(),
2907 sizeof(ROS_SECTION_OBJECT
),
2910 (PVOID
*)(PVOID
)&Section
);
2911 if (!NT_SUCCESS(Status
))
2919 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2920 Section
->Type
= 'SC';
2921 Section
->Size
= 'TN';
2922 Section
->SectionPageProtection
= SectionPageProtection
;
2923 Section
->AllocationAttributes
= AllocationAttributes
;
2924 Section
->MaximumSize
= MaximumSize
;
2925 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2926 TAG_MM_SECTION_SEGMENT
);
2927 if (Segment
== NULL
)
2929 ObDereferenceObject(Section
);
2930 return(STATUS_NO_MEMORY
);
2932 RtlZeroMemory(Segment
, sizeof(MM_SECTION_SEGMENT
));
2933 Section
->Segment
= Segment
;
2934 Segment
->ReferenceCount
= 1;
2935 ExInitializeFastMutex(&Segment
->Lock
);
2936 Segment
->Image
.FileOffset
= 0;
2937 Segment
->Protection
= SectionPageProtection
;
2938 Segment
->RawLength
.QuadPart
= MaximumSize
.u
.LowPart
;
2939 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2940 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2941 Segment
->WriteCopy
= FALSE
;
2942 Segment
->Image
.VirtualAddress
= 0;
2943 Segment
->Image
.Characteristics
= 0;
2944 *SectionObject
= Section
;
2945 MiInitializeSectionPageTable(Segment
);
2946 return(STATUS_SUCCESS
);
2951 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2952 ACCESS_MASK DesiredAccess
,
2953 POBJECT_ATTRIBUTES ObjectAttributes
,
2954 PLARGE_INTEGER UMaximumSize
,
2955 ULONG SectionPageProtection
,
2956 ULONG AllocationAttributes
,
2959 * Create a section backed by a data file
2962 PROS_SECTION_OBJECT Section
;
2964 LARGE_INTEGER MaximumSize
;
2965 PFILE_OBJECT FileObject
;
2966 PMM_SECTION_SEGMENT Segment
;
2968 IO_STATUS_BLOCK Iosb
;
2969 LARGE_INTEGER Offset
;
2971 FILE_STANDARD_INFORMATION FileInfo
;
2975 * Create the section
2977 Status
= ObCreateObject(ExGetPreviousMode(),
2978 MmSectionObjectType
,
2980 ExGetPreviousMode(),
2982 sizeof(ROS_SECTION_OBJECT
),
2986 if (!NT_SUCCESS(Status
))
2993 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2994 Section
->Type
= 'SC';
2995 Section
->Size
= 'TN';
2996 Section
->SectionPageProtection
= SectionPageProtection
;
2997 Section
->AllocationAttributes
= AllocationAttributes
;
3000 * Reference the file handle
3002 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
3003 Status
= ObReferenceObjectByHandle(FileHandle
,
3006 ExGetPreviousMode(),
3007 (PVOID
*)(PVOID
)&FileObject
,
3009 if (!NT_SUCCESS(Status
))
3011 ObDereferenceObject(Section
);
3016 * FIXME: This is propably not entirely correct. We can't look into
3017 * the standard FCB header because it might not be initialized yet
3018 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
3019 * standard file information is filled on first request).
3021 Status
= IoQueryFileInformation(FileObject
,
3022 FileStandardInformation
,
3023 sizeof(FILE_STANDARD_INFORMATION
),
3026 Iosb
.Information
= Length
;
3027 if (!NT_SUCCESS(Status
))
3029 ObDereferenceObject(Section
);
3030 ObDereferenceObject(FileObject
);
3035 * FIXME: Revise this once a locking order for file size changes is
3038 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
3040 MaximumSize
= *UMaximumSize
;
3044 MaximumSize
= FileInfo
.EndOfFile
;
3045 /* Mapping zero-sized files isn't allowed. */
3046 if (MaximumSize
.QuadPart
== 0)
3048 ObDereferenceObject(Section
);
3049 ObDereferenceObject(FileObject
);
3050 return STATUS_FILE_INVALID
;
3054 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
3056 Status
= IoSetInformation(FileObject
,
3057 FileAllocationInformation
,
3058 sizeof(LARGE_INTEGER
),
3060 if (!NT_SUCCESS(Status
))
3062 ObDereferenceObject(Section
);
3063 ObDereferenceObject(FileObject
);
3064 return(STATUS_SECTION_NOT_EXTENDED
);
3068 if (FileObject
->SectionObjectPointer
== NULL
||
3069 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3072 * Read a bit so caching is initiated for the file object.
3073 * This is only needed because MiReadPage currently cannot
3074 * handle non-cached streams.
3076 Offset
.QuadPart
= 0;
3077 Status
= ZwReadFile(FileHandle
,
3086 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
3088 ObDereferenceObject(Section
);
3089 ObDereferenceObject(FileObject
);
3092 if (FileObject
->SectionObjectPointer
== NULL
||
3093 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
3095 /* FIXME: handle this situation */
3096 ObDereferenceObject(Section
);
3097 ObDereferenceObject(FileObject
);
3098 return STATUS_INVALID_PARAMETER
;
3105 Status
= MmspWaitForFileLock(FileObject
);
3106 if (Status
!= STATUS_SUCCESS
)
3108 ObDereferenceObject(Section
);
3109 ObDereferenceObject(FileObject
);
3114 * If this file hasn't been mapped as a data file before then allocate a
3115 * section segment to describe the data file mapping
3117 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
3119 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
3120 TAG_MM_SECTION_SEGMENT
);
3121 if (Segment
== NULL
)
3123 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3124 ObDereferenceObject(Section
);
3125 ObDereferenceObject(FileObject
);
3126 return(STATUS_NO_MEMORY
);
3128 Section
->Segment
= Segment
;
3129 Segment
->ReferenceCount
= 1;
3130 ExInitializeFastMutex(&Segment
->Lock
);
3132 * Set the lock before assigning the segment to the file object
3134 ExAcquireFastMutex(&Segment
->Lock
);
3135 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
3137 Segment
->Image
.FileOffset
= 0;
3138 Segment
->Protection
= SectionPageProtection
;
3139 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
3140 Segment
->Image
.Characteristics
= 0;
3141 Segment
->WriteCopy
= (SectionPageProtection
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
));
3142 if (AllocationAttributes
& SEC_RESERVE
)
3144 Segment
->Length
.QuadPart
= Segment
->RawLength
.QuadPart
= 0;
3148 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3149 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3151 Segment
->Image
.VirtualAddress
= 0;
3152 Segment
->Locked
= TRUE
;
3153 MiInitializeSectionPageTable(Segment
);
3158 * If the file is already mapped as a data file then we may need
3162 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
3164 Section
->Segment
= Segment
;
3165 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
3166 MmLockSectionSegment(Segment
);
3168 if (MaximumSize
.QuadPart
> Segment
->RawLength
.QuadPart
&&
3169 !(AllocationAttributes
& SEC_RESERVE
))
3171 Segment
->RawLength
.QuadPart
= MaximumSize
.QuadPart
;
3172 Segment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->RawLength
.QuadPart
);
3175 MmUnlockSectionSegment(Segment
);
3176 Section
->FileObject
= FileObject
;
3177 Section
->MaximumSize
= MaximumSize
;
3179 CcRosReferenceCache(FileObject
);
3181 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3182 *SectionObject
= Section
;
3183 return(STATUS_SUCCESS
);
3187 TODO: not that great (declaring loaders statically, having to declare all of
3188 them, having to keep them extern, etc.), will fix in the future
3190 extern NTSTATUS NTAPI PeFmtCreateSection
3192 IN CONST VOID
* FileHeader
,
3193 IN SIZE_T FileHeaderSize
,
3195 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3197 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3198 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3201 extern NTSTATUS NTAPI ElfFmtCreateSection
3203 IN CONST VOID
* FileHeader
,
3204 IN SIZE_T FileHeaderSize
,
3206 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3208 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
3209 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3212 /* TODO: this is a standard DDK/PSDK macro */
3213 #ifndef RTL_NUMBER_OF
3214 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3217 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
3228 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
3230 SIZE_T SizeOfSegments
;
3231 PMM_SECTION_SEGMENT Segments
;
3233 /* TODO: check for integer overflow */
3234 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
3236 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3238 TAG_MM_SECTION_SEGMENT
);
3241 RtlZeroMemory(Segments
, SizeOfSegments
);
3249 ExeFmtpReadFile(IN PVOID File
,
3250 IN PLARGE_INTEGER Offset
,
3253 OUT PVOID
* AllocBase
,
3254 OUT PULONG ReadSize
)
3257 LARGE_INTEGER FileOffset
;
3259 ULONG OffsetAdjustment
;
3263 PFILE_OBJECT FileObject
= File
;
3264 IO_STATUS_BLOCK Iosb
;
3266 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
3270 KeBugCheck(MEMORY_MANAGEMENT
);
3273 FileOffset
= *Offset
;
3275 /* Negative/special offset: it cannot be used in this context */
3276 if(FileOffset
.u
.HighPart
< 0)
3278 KeBugCheck(MEMORY_MANAGEMENT
);
3281 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
3282 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
3283 FileOffset
.u
.LowPart
= AdjustOffset
;
3285 BufferSize
= Length
+ OffsetAdjustment
;
3286 BufferSize
= PAGE_ROUND_UP(BufferSize
);
3289 * It's ok to use paged pool, because this is a temporary buffer only used in
3290 * the loading of executables. The assumption is that MmCreateSection is
3291 * always called at low IRQLs and that these buffers don't survive a brief
3292 * initialization phase
3294 Buffer
= ExAllocatePoolWithTag(PagedPool
,
3299 KeBugCheck(MEMORY_MANAGEMENT
);
3304 Status
= MiSimpleRead(FileObject
, &FileOffset
, Buffer
, BufferSize
, TRUE
, &Iosb
);
3306 UsedSize
= Iosb
.Information
;
3308 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
3310 Status
= STATUS_IN_PAGE_ERROR
;
3311 ASSERT(!NT_SUCCESS(Status
));
3314 if(NT_SUCCESS(Status
))
3316 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
3317 *AllocBase
= Buffer
;
3318 *ReadSize
= UsedSize
- OffsetAdjustment
;
3322 ExFreePoolWithTag(Buffer
, 'rXmM');
3329 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3330 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3331 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3336 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3340 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
3342 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3343 ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
);
3350 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3354 MmspAssertSegmentsSorted(ImageSectionObject
);
3356 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3358 ASSERT(ImageSectionObject
->Segments
[i
].Length
.QuadPart
> 0);
3362 ASSERT(ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
>=
3363 (ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3364 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
));
3372 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3376 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3378 ASSERT((ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3379 ASSERT((ImageSectionObject
->Segments
[i
].Length
.QuadPart
% PAGE_SIZE
) == 0);
3387 MmspCompareSegments(const void * x
,
3390 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
3391 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
3394 (Segment1
->Image
.VirtualAddress
- Segment2
->Image
.VirtualAddress
) >>
3395 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
3399 * Ensures an image section's segments are sorted in memory
3404 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3407 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
3409 MmspAssertSegmentsSorted(ImageSectionObject
);
3413 qsort(ImageSectionObject
->Segments
,
3414 ImageSectionObject
->NrSegments
,
3415 sizeof(ImageSectionObject
->Segments
[0]),
3416 MmspCompareSegments
);
3422 * Ensures an image section's segments don't overlap in memory and don't have
3423 * gaps and don't have a null size. We let them map to overlapping file regions,
3424 * though - that's not necessarily an error
3429 MmspCheckSegmentBounds
3431 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3437 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
3439 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
3443 ASSERT(ImageSectionObject
->NrSegments
>= 1);
3445 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3447 if(ImageSectionObject
->Segments
[i
].Length
.QuadPart
== 0)
3455 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3456 * page could be OK (Windows seems to be OK with them), and larger gaps
3457 * could lead to image sections spanning several discontiguous regions
3458 * (NtMapViewOfSection could then refuse to map them, and they could
3459 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3461 if ((ImageSectionObject
->Segments
[i
- 1].Image
.VirtualAddress
+
3462 ImageSectionObject
->Segments
[i
- 1].Length
.QuadPart
) !=
3463 ImageSectionObject
->Segments
[i
].Image
.VirtualAddress
)
3474 * Merges and pads an image section's segments until they all are page-aligned
3475 * and have a size that is a multiple of the page size
3480 MmspPageAlignSegments
3482 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3488 PMM_SECTION_SEGMENT EffectiveSegment
;
3490 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3492 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3497 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3499 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3502 * The first segment requires special handling
3506 ULONG_PTR VirtualAddress
;
3507 ULONG_PTR VirtualOffset
;
3509 VirtualAddress
= EffectiveSegment
->Image
.VirtualAddress
;
3511 /* Round down the virtual address to the nearest page */
3512 EffectiveSegment
->Image
.VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3514 /* Round up the virtual size to the nearest page */
3515 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
) -
3516 EffectiveSegment
->Image
.VirtualAddress
;
3518 /* Adjust the raw address and size */
3519 VirtualOffset
= VirtualAddress
- EffectiveSegment
->Image
.VirtualAddress
;
3521 if (EffectiveSegment
->Image
.FileOffset
< VirtualOffset
)
3527 * Garbage in, garbage out: unaligned base addresses make the file
3528 * offset point in curious and odd places, but that's what we were
3531 EffectiveSegment
->Image
.FileOffset
-= VirtualOffset
;
3532 EffectiveSegment
->RawLength
.QuadPart
+= VirtualOffset
;
3536 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3537 ULONG_PTR EndOfEffectiveSegment
;
3539 EndOfEffectiveSegment
= EffectiveSegment
->Image
.VirtualAddress
+ EffectiveSegment
->Length
.QuadPart
;
3540 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3543 * The current segment begins exactly where the current effective
3544 * segment ended, therefore beginning a new effective segment
3546 if (EndOfEffectiveSegment
== Segment
->Image
.VirtualAddress
)
3549 ASSERT(LastSegment
<= i
);
3550 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3552 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3554 if (LastSegment
!= i
)
3557 * Copy the current segment. If necessary, the effective segment
3558 * will be expanded later
3560 *EffectiveSegment
= *Segment
;
3564 * Page-align the virtual size. We know for sure the virtual address
3567 ASSERT((EffectiveSegment
->Image
.VirtualAddress
% PAGE_SIZE
) == 0);
3568 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(EffectiveSegment
->Length
.QuadPart
);
3571 * The current segment is still part of the current effective segment:
3572 * extend the effective segment to reflect this
3574 else if (EndOfEffectiveSegment
> Segment
->Image
.VirtualAddress
)
3576 static const ULONG FlagsToProtection
[16] =
3584 PAGE_EXECUTE_READWRITE
,
3585 PAGE_EXECUTE_READWRITE
,
3590 PAGE_EXECUTE_WRITECOPY
,
3591 PAGE_EXECUTE_WRITECOPY
,
3592 PAGE_EXECUTE_WRITECOPY
,
3593 PAGE_EXECUTE_WRITECOPY
3596 unsigned ProtectionFlags
;
3599 * Extend the file size
3602 /* Unaligned segments must be contiguous within the file */
3603 if (Segment
->Image
.FileOffset
!= (EffectiveSegment
->Image
.FileOffset
+
3604 EffectiveSegment
->RawLength
.QuadPart
))
3609 EffectiveSegment
->RawLength
.QuadPart
+= Segment
->RawLength
.QuadPart
;
3612 * Extend the virtual size
3614 ASSERT(PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) >= EndOfEffectiveSegment
);
3616 EffectiveSegment
->Length
.QuadPart
= PAGE_ROUND_UP(Segment
->Image
.VirtualAddress
+ Segment
->Length
.QuadPart
) -
3617 EffectiveSegment
->Image
.VirtualAddress
;
3620 * Merge the protection
3622 EffectiveSegment
->Protection
|= Segment
->Protection
;
3624 /* Clean up redundance */
3625 ProtectionFlags
= 0;
3627 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3628 ProtectionFlags
|= 1 << 0;
3630 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3631 ProtectionFlags
|= 1 << 1;
3633 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3634 ProtectionFlags
|= 1 << 2;
3636 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3637 ProtectionFlags
|= 1 << 3;
3639 ASSERT(ProtectionFlags
< 16);
3640 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3642 /* If a segment was required to be shared and cannot, fail */
3643 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3644 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3650 * We assume no holes between segments at this point
3654 KeBugCheck(MEMORY_MANAGEMENT
);
3658 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3664 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3665 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3667 LARGE_INTEGER Offset
;
3669 PVOID FileHeaderBuffer
;
3670 ULONG FileHeaderSize
;
3672 ULONG OldNrSegments
;
3677 * Read the beginning of the file (2 pages). Should be enough to contain
3678 * all (or most) of the headers
3680 Offset
.QuadPart
= 0;
3682 /* FIXME: use FileObject instead of FileHandle */
3683 Status
= ExeFmtpReadFile (FileHandle
,
3690 if (!NT_SUCCESS(Status
))
3693 if (FileHeaderSize
== 0)
3695 ExFreePool(FileHeaderBuffer
);
3696 return STATUS_UNSUCCESSFUL
;
3700 * Look for a loader that can handle this executable
3702 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3704 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3707 /* FIXME: use FileObject instead of FileHandle */
3708 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3714 ExeFmtpAllocateSegments
);
3716 if (!NT_SUCCESS(Status
))
3718 if (ImageSectionObject
->Segments
)
3720 ExFreePool(ImageSectionObject
->Segments
);
3721 ImageSectionObject
->Segments
= NULL
;
3725 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3729 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3732 * No loader handled the format
3734 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3736 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3737 ASSERT(!NT_SUCCESS(Status
));
3740 if (!NT_SUCCESS(Status
))
3743 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3748 /* FIXME? are these values platform-dependent? */
3749 if(ImageSectionObject
->StackReserve
== 0)
3750 ImageSectionObject
->StackReserve
= 0x40000;
3752 if(ImageSectionObject
->StackCommit
== 0)
3753 ImageSectionObject
->StackCommit
= 0x1000;
3755 if(ImageSectionObject
->ImageBase
== 0)
3757 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3758 ImageSectionObject
->ImageBase
= 0x10000000;
3760 ImageSectionObject
->ImageBase
= 0x00400000;
3764 * And now the fun part: fixing the segments
3767 /* Sort them by virtual address */
3768 MmspSortSegments(ImageSectionObject
, Flags
);
3770 /* Ensure they don't overlap in memory */
3771 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3772 return STATUS_INVALID_IMAGE_FORMAT
;
3774 /* Ensure they are aligned */
3775 OldNrSegments
= ImageSectionObject
->NrSegments
;
3777 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3778 return STATUS_INVALID_IMAGE_FORMAT
;
3780 /* Trim them if the alignment phase merged some of them */
3781 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3783 PMM_SECTION_SEGMENT Segments
;
3784 SIZE_T SizeOfSegments
;
3786 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3788 Segments
= ExAllocatePoolWithTag(PagedPool
,
3790 TAG_MM_SECTION_SEGMENT
);
3792 if (Segments
== NULL
)
3793 return STATUS_INSUFFICIENT_RESOURCES
;
3795 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3796 ExFreePool(ImageSectionObject
->Segments
);
3797 ImageSectionObject
->Segments
= Segments
;
3800 /* And finish their initialization */
3801 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3803 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3804 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3805 MiInitializeSectionPageTable(&ImageSectionObject
->Segments
[i
]);
3808 ASSERT(NT_SUCCESS(Status
));
3813 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3814 ACCESS_MASK DesiredAccess
,
3815 POBJECT_ATTRIBUTES ObjectAttributes
,
3816 PLARGE_INTEGER UMaximumSize
,
3817 ULONG SectionPageProtection
,
3818 ULONG AllocationAttributes
,
3819 PFILE_OBJECT FileObject
)
3821 PROS_SECTION_OBJECT Section
;
3823 PMM_SECTION_SEGMENT SectionSegments
;
3824 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3827 if (FileObject
== NULL
)
3828 return STATUS_INVALID_FILE_FOR_SECTION
;
3831 * Create the section
3833 Status
= ObCreateObject (ExGetPreviousMode(),
3834 MmSectionObjectType
,
3836 ExGetPreviousMode(),
3838 sizeof(ROS_SECTION_OBJECT
),
3841 (PVOID
*)(PVOID
)&Section
);
3842 if (!NT_SUCCESS(Status
))
3844 ObDereferenceObject(FileObject
);
3851 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3852 Section
->Type
= 'SC';
3853 Section
->Size
= 'TN';
3854 Section
->SectionPageProtection
= SectionPageProtection
;
3855 Section
->AllocationAttributes
= AllocationAttributes
;
3859 * Initialized caching for this file object if previously caching
3860 * was initialized for the same on disk file
3862 Status
= CcTryToInitializeFileCache(FileObject
);
3864 Status
= STATUS_SUCCESS
;
3867 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3869 NTSTATUS StatusExeFmt
;
3871 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3872 if (ImageSectionObject
== NULL
)
3874 ObDereferenceObject(FileObject
);
3875 ObDereferenceObject(Section
);
3876 return(STATUS_NO_MEMORY
);
3879 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3881 StatusExeFmt
= ExeFmtpCreateImageSection(FileObject
, ImageSectionObject
);
3883 if (!NT_SUCCESS(StatusExeFmt
))
3885 if(ImageSectionObject
->Segments
!= NULL
)
3886 ExFreePool(ImageSectionObject
->Segments
);
3888 ExFreePool(ImageSectionObject
);
3889 ObDereferenceObject(Section
);
3890 ObDereferenceObject(FileObject
);
3891 return(StatusExeFmt
);
3894 Section
->ImageSection
= ImageSectionObject
;
3895 ASSERT(ImageSectionObject
->Segments
);
3900 Status
= MmspWaitForFileLock(FileObject
);
3901 if (!NT_SUCCESS(Status
))
3903 ExFreePool(ImageSectionObject
->Segments
);
3904 ExFreePool(ImageSectionObject
);
3905 ObDereferenceObject(Section
);
3906 ObDereferenceObject(FileObject
);
3910 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3911 ImageSectionObject
, NULL
))
3914 * An other thread has initialized the same image in the background
3916 ExFreePool(ImageSectionObject
->Segments
);
3917 ExFreePool(ImageSectionObject
);
3918 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3919 Section
->ImageSection
= ImageSectionObject
;
3920 SectionSegments
= ImageSectionObject
->Segments
;
3922 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3924 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3928 Status
= StatusExeFmt
;
3935 Status
= MmspWaitForFileLock(FileObject
);
3936 if (Status
!= STATUS_SUCCESS
)
3938 ObDereferenceObject(Section
);
3939 ObDereferenceObject(FileObject
);
3943 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3944 Section
->ImageSection
= ImageSectionObject
;
3945 SectionSegments
= ImageSectionObject
->Segments
;
3948 * Otherwise just reference all the section segments
3950 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3952 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3955 Status
= STATUS_SUCCESS
;
3957 Section
->FileObject
= FileObject
;
3959 CcRosReferenceCache(FileObject
);
3961 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3962 *SectionObject
= Section
;
3969 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3970 PROS_SECTION_OBJECT Section
,
3971 PMM_SECTION_SEGMENT Segment
,
3976 ULONG AllocationType
)
3980 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3982 if (Segment
->WriteCopy
)
3984 /* We have to do this because the not present fault
3985 * and access fault handlers depend on the protection
3986 * that should be granted AFTER the COW fault takes
3987 * place to be in Region->Protect. The not present fault
3988 * handler changes this to the correct protection for COW when
3989 * mapping the pages into the process's address space. If a COW
3990 * fault takes place, the access fault handler sets the page protection
3991 * to these values for the newly copied pages
3993 if (Protect
== PAGE_WRITECOPY
)
3994 Protect
= PAGE_READWRITE
;
3995 else if (Protect
== PAGE_EXECUTE_WRITECOPY
)
3996 Protect
= PAGE_EXECUTE_READWRITE
;
3999 BoundaryAddressMultiple
.QuadPart
= 0;
4002 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
) {
4003 LARGE_INTEGER FileOffset
;
4004 FileOffset
.QuadPart
= ViewOffset
;
4005 ObReferenceObject(Section
);
4006 return _MiMapViewOfSegment(AddressSpace
, Segment
, BaseAddress
, ViewSize
, Protect
, &FileOffset
, AllocationType
, __FILE__
, __LINE__
);
4009 Status
= MmCreateMemoryArea(AddressSpace
,
4010 MEMORY_AREA_SECTION_VIEW
,
4017 BoundaryAddressMultiple
);
4018 if (!NT_SUCCESS(Status
))
4020 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
4021 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
4025 ObReferenceObject((PVOID
)Section
);
4027 MArea
->Data
.SectionData
.Segment
= Segment
;
4028 MArea
->Data
.SectionData
.Section
= Section
;
4029 MArea
->Data
.SectionData
.ViewOffset
.QuadPart
= ViewOffset
;
4030 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
4031 ViewSize
, 0, Protect
);
4033 return(STATUS_SUCCESS
);
4038 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
4039 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
4042 PFILE_OBJECT FileObject
;
4044 LARGE_INTEGER Offset
;
4045 SWAPENTRY SavedSwapEntry
;
4048 PROS_SECTION_OBJECT Section
;
4049 PMM_SECTION_SEGMENT Segment
;
4050 PMMSUPPORT AddressSpace
;
4053 AddressSpace
= (PMMSUPPORT
)Context
;
4054 Process
= MmGetAddressSpaceOwner(AddressSpace
);
4056 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
4058 Offset
.QuadPart
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
4059 MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
;
4061 Section
= MemoryArea
->Data
.SectionData
.Section
;
4062 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4064 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
.LowPart
);
4068 MmUnlockSectionSegment(Segment
);
4069 MmUnlockAddressSpace(AddressSpace
);
4071 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4072 if (Status
!= STATUS_SUCCESS
)
4074 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4075 KeBugCheck(MEMORY_MANAGEMENT
);
4078 MmLockAddressSpace(AddressSpace
);
4079 MmLockSectionSegment(Segment
);
4080 MmspCompleteAndReleasePageOp(PageOp
);
4081 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
.LowPart
);
4084 Entry
= MmGetPageEntrySectionSegment(Segment
, &Offset
);
4087 * For a dirty, datafile, non-private page mark it as dirty in the
4090 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4092 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
4094 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
4095 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
4097 CcRosMarkDirtyCacheSegment(Bcb
, Offset
.QuadPart
+ Segment
->Image
.FileOffset
);
4099 ASSERT(SwapEntry
== 0);
4108 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4110 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4111 KeBugCheck(MEMORY_MANAGEMENT
);
4113 MmFreeSwapPage(SwapEntry
);
4117 if (IS_SWAP_FROM_SSE(Entry
) ||
4118 Page
!= PFN_FROM_SSE(Entry
))
4123 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4125 DPRINT1("Found a private page in a pagefile section.\n");
4126 KeBugCheck(MEMORY_MANAGEMENT
);
4129 * Just dereference private pages
4131 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4132 if (SavedSwapEntry
!= 0)
4134 MmFreeSwapPage(SavedSwapEntry
);
4135 MmSetSavedSwapEntryPage(Page
, 0);
4137 MmDeleteRmap(Page
, Process
, Address
);
4138 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4142 MmDeleteRmap(Page
, Process
, Address
);
4143 MmUnsharePageEntrySectionSegment(Section
, Segment
, &Offset
, Dirty
, FALSE
);
4149 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4153 PMEMORY_AREA MemoryArea
;
4154 PROS_SECTION_OBJECT Section
;
4155 PMM_SECTION_SEGMENT Segment
;
4156 PLIST_ENTRY CurrentEntry
;
4157 PMM_REGION CurrentRegion
;
4158 PLIST_ENTRY RegionListHead
;
4160 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4162 if (MemoryArea
== NULL
)
4164 return(STATUS_UNSUCCESSFUL
);
4167 MemoryArea
->DeleteInProgress
= TRUE
;
4168 Section
= MemoryArea
->Data
.SectionData
.Section
;
4169 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4172 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
4173 return MmUnmapViewOfCacheSegment(AddressSpace
, BaseAddress
);
4176 MmLockSectionSegment(Segment
);
4178 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4179 while (!IsListEmpty(RegionListHead
))
4181 CurrentEntry
= RemoveHeadList(RegionListHead
);
4182 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4183 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4186 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4188 Status
= MmFreeMemoryArea(AddressSpace
,
4195 Status
= MmFreeMemoryArea(AddressSpace
,
4200 MmUnlockSectionSegment(Segment
);
4201 ObDereferenceObject(Section
);
4209 MmUnmapViewOfSection(PEPROCESS Process
,
4213 PMEMORY_AREA MemoryArea
;
4214 PMMSUPPORT AddressSpace
;
4215 PROS_SECTION_OBJECT Section
;
4218 PVOID ImageBaseAddress
= 0;
4220 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4221 Process
, BaseAddress
);
4225 AddressSpace
= &Process
->Vm
;
4227 MmLockAddressSpace(AddressSpace
);
4228 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4230 if (MemoryArea
== NULL
||
4231 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4232 MemoryArea
->DeleteInProgress
)
4234 MmUnlockAddressSpace(AddressSpace
);
4235 return STATUS_NOT_MAPPED_VIEW
;
4238 MemoryArea
->DeleteInProgress
= TRUE
;
4240 while (MemoryArea
->PageOpCount
)
4242 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4246 Offset
-= PAGE_SIZE
;
4247 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4248 MemoryArea
->Data
.SectionData
.Segment
,
4249 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
);
4252 MmUnlockAddressSpace(AddressSpace
);
4253 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4254 if (Status
!= STATUS_SUCCESS
)
4256 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4257 KeBugCheck(MEMORY_MANAGEMENT
);
4259 MmLockAddressSpace(AddressSpace
);
4260 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4262 if (MemoryArea
== NULL
||
4263 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4265 MmUnlockAddressSpace(AddressSpace
);
4266 return STATUS_NOT_MAPPED_VIEW
;
4273 Section
= MemoryArea
->Data
.SectionData
.Section
;
4275 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4279 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4280 PMM_SECTION_SEGMENT SectionSegments
;
4281 PMM_SECTION_SEGMENT Segment
;
4283 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4284 ImageSectionObject
= Section
->ImageSection
;
4285 SectionSegments
= ImageSectionObject
->Segments
;
4286 NrSegments
= ImageSectionObject
->NrSegments
;
4288 /* Search for the current segment within the section segments
4289 * and calculate the image base address */
4290 for (i
= 0; i
< NrSegments
; i
++)
4292 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4294 if (Segment
== &SectionSegments
[i
])
4296 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
;
4301 if (i
>= NrSegments
)
4303 KeBugCheck(MEMORY_MANAGEMENT
);
4306 for (i
= 0; i
< NrSegments
; i
++)
4308 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4310 PVOID SBaseAddress
= (PVOID
)
4311 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4313 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4319 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4322 MmUnlockAddressSpace(AddressSpace
);
4324 /* Notify debugger */
4325 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4327 return(STATUS_SUCCESS
);
4334 * Queries the information of a section object.
4336 * @param SectionHandle
4337 * Handle to the section object. It must be opened with SECTION_QUERY
4339 * @param SectionInformationClass
4340 * Index to a certain information structure. Can be either
4341 * SectionBasicInformation or SectionImageInformation. The latter
4342 * is valid only for sections that were created with the SEC_IMAGE
4344 * @param SectionInformation
4345 * Caller supplies storage for resulting information.
4347 * Size of the supplied storage.
4348 * @param ResultLength
4356 NtQuerySection(IN HANDLE SectionHandle
,
4357 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4358 OUT PVOID SectionInformation
,
4359 IN SIZE_T SectionInformationLength
,
4360 OUT PSIZE_T ResultLength OPTIONAL
)
4362 PROS_SECTION_OBJECT Section
;
4363 KPROCESSOR_MODE PreviousMode
;
4367 PreviousMode
= ExGetPreviousMode();
4369 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4371 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4373 (ULONG
)SectionInformationLength
,
4378 if(!NT_SUCCESS(Status
))
4380 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4384 Status
= ObReferenceObjectByHandle(SectionHandle
,
4386 MmSectionObjectType
,
4388 (PVOID
*)(PVOID
)&Section
,
4390 if (NT_SUCCESS(Status
))
4392 switch (SectionInformationClass
)
4394 case SectionBasicInformation
:
4396 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4400 Sbi
->Attributes
= Section
->AllocationAttributes
;
4401 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4403 Sbi
->BaseAddress
= 0;
4404 Sbi
->Size
.QuadPart
= 0;
4408 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->Image
.VirtualAddress
;
4409 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
.QuadPart
;
4412 if (ResultLength
!= NULL
)
4414 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4416 Status
= STATUS_SUCCESS
;
4418 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4420 Status
= _SEH2_GetExceptionCode();
4427 case SectionImageInformation
:
4429 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4433 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4434 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4436 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4437 ImageSectionObject
= Section
->ImageSection
;
4439 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4440 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4441 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4442 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4443 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4444 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4445 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4446 Sii
->Machine
= ImageSectionObject
->Machine
;
4447 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4450 if (ResultLength
!= NULL
)
4452 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4454 Status
= STATUS_SUCCESS
;
4456 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4458 Status
= _SEH2_GetExceptionCode();
4466 ObDereferenceObject(Section
);
4472 /**********************************************************************
4474 * MmMapViewOfSection
4477 * Maps a view of a section into the virtual address space of a
4482 * Pointer to the section object.
4485 * Pointer to the process.
4488 * Desired base address (or NULL) on entry;
4489 * Actual base address of the view on exit.
4492 * Number of high order address bits that must be zero.
4495 * Size in bytes of the initially committed section of
4499 * Offset in bytes from the beginning of the section
4500 * to the beginning of the view.
4503 * Desired length of map (or zero to map all) on entry
4504 * Actual length mapped on exit.
4506 * InheritDisposition
4507 * Specified how the view is to be shared with
4511 * Type of allocation for the pages.
4514 * Protection for the committed region of the view.
4522 MmMapViewOfSection(IN PVOID SectionObject
,
4523 IN PEPROCESS Process
,
4524 IN OUT PVOID
*BaseAddress
,
4525 IN ULONG_PTR ZeroBits
,
4526 IN SIZE_T CommitSize
,
4527 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4528 IN OUT PSIZE_T ViewSize
,
4529 IN SECTION_INHERIT InheritDisposition
,
4530 IN ULONG AllocationType
,
4533 PROS_SECTION_OBJECT Section
;
4534 PMMSUPPORT AddressSpace
;
4536 NTSTATUS Status
= STATUS_SUCCESS
;
4537 BOOLEAN NotAtBase
= FALSE
;
4539 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4541 DPRINT1("Mapping ARM3 section into %s\n", Process
->ImageFileName
);
4542 return MmMapViewOfArm3Section(SectionObject
,
4556 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4558 return STATUS_INVALID_PAGE_PROTECTION
;
4562 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4563 AddressSpace
= &Process
->Vm
;
4565 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4567 MmLockAddressSpace(AddressSpace
);
4569 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4573 ULONG_PTR ImageBase
;
4575 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4576 PMM_SECTION_SEGMENT SectionSegments
;
4578 ImageSectionObject
= Section
->ImageSection
;
4579 SectionSegments
= ImageSectionObject
->Segments
;
4580 NrSegments
= ImageSectionObject
->NrSegments
;
4583 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4586 ImageBase
= ImageSectionObject
->ImageBase
;
4590 for (i
= 0; i
< NrSegments
; i
++)
4592 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4594 ULONG_PTR MaxExtent
;
4595 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
+
4596 SectionSegments
[i
].Length
.QuadPart
;
4597 ImageSize
= max(ImageSize
, MaxExtent
);
4601 ImageSectionObject
->ImageSize
= (ULONG
)ImageSize
;
4603 /* Check for an illegal base address */
4604 if ((ImageBase
+ ImageSize
) > (ULONG_PTR
)MmHighestUserAddress
)
4606 ImageBase
= PAGE_ROUND_DOWN((ULONG_PTR
)MmHighestUserAddress
- ImageSize
);
4609 /* Check there is enough space to map the section at that point. */
4610 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4611 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4613 /* Fail if the user requested a fixed base address. */
4614 if ((*BaseAddress
) != NULL
)
4616 MmUnlockAddressSpace(AddressSpace
);
4617 return(STATUS_UNSUCCESSFUL
);
4619 /* Otherwise find a gap to map the image. */
4620 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4623 MmUnlockAddressSpace(AddressSpace
);
4624 return(STATUS_UNSUCCESSFUL
);
4626 /* Remember that we loaded image at a different base address */
4630 for (i
= 0; i
< NrSegments
; i
++)
4632 if (!(SectionSegments
[i
].Image
.Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4634 PVOID SBaseAddress
= (PVOID
)
4635 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].Image
.VirtualAddress
);
4636 MmLockSectionSegment(&SectionSegments
[i
]);
4637 Status
= MmMapViewOfSegment(AddressSpace
,
4639 &SectionSegments
[i
],
4641 SectionSegments
[i
].Length
.LowPart
,
4642 SectionSegments
[i
].Protection
,
4645 MmUnlockSectionSegment(&SectionSegments
[i
]);
4646 if (!NT_SUCCESS(Status
))
4648 MmUnlockAddressSpace(AddressSpace
);
4654 *BaseAddress
= (PVOID
)ImageBase
;
4655 *ViewSize
= ImageSize
;
4659 /* check for write access */
4660 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4661 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4663 MmUnlockAddressSpace(AddressSpace
);
4664 return STATUS_SECTION_PROTECTION
;
4666 /* check for read access */
4667 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4668 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4670 MmUnlockAddressSpace(AddressSpace
);
4671 return STATUS_SECTION_PROTECTION
;
4673 /* check for execute access */
4674 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4675 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4677 MmUnlockAddressSpace(AddressSpace
);
4678 return STATUS_SECTION_PROTECTION
;
4681 if (ViewSize
== NULL
)
4683 /* Following this pointer would lead to us to the dark side */
4684 /* What to do? Bugcheck? Return status? Do the mambo? */
4685 KeBugCheck(MEMORY_MANAGEMENT
);
4688 if (SectionOffset
== NULL
)
4694 ViewOffset
= SectionOffset
->u
.LowPart
;
4697 if ((ViewOffset
% PAGE_SIZE
) != 0)
4699 MmUnlockAddressSpace(AddressSpace
);
4700 return(STATUS_MAPPED_ALIGNMENT
);
4703 if ((*ViewSize
) == 0)
4705 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4707 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4709 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4712 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4714 MmLockSectionSegment(Section
->Segment
);
4715 Status
= MmMapViewOfSegment(AddressSpace
,
4722 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4723 MmUnlockSectionSegment(Section
->Segment
);
4724 if (!NT_SUCCESS(Status
))
4726 MmUnlockAddressSpace(AddressSpace
);
4731 MmUnlockAddressSpace(AddressSpace
);
4734 Status
= STATUS_IMAGE_NOT_AT_BASE
;
4736 Status
= STATUS_SUCCESS
;
4745 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4746 IN PLARGE_INTEGER NewFileSize
)
4748 /* Check whether an ImageSectionObject exists */
4749 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4751 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4755 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4757 PMM_SECTION_SEGMENT Segment
;
4759 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4762 if (Segment
->ReferenceCount
!= 0)
4765 CC_FILE_SIZES FileSizes
;
4767 if (SectionObjectPointer
->SharedCacheMap
&& (Segment
->ReferenceCount
> CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
)))
4770 /* Check size of file */
4771 if (SectionObjectPointer
->SharedCacheMap
)
4773 if (!CcGetFileSizes(Segment
->FileObject
, &FileSizes
))
4778 if (NewFileSize
->QuadPart
<= FileSizes
.FileSize
.QuadPart
)
4787 /* Check size of file */
4788 if (SectionObjectPointer
->SharedCacheMap
)
4790 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4791 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4800 /* Something must gone wrong
4801 * how can we have a Section but no
4803 DPRINT("ERROR: DataSectionObject without reference!\n");
4807 DPRINT("FIXME: didn't check for outstanding write probes\n");
4819 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4820 IN MMFLUSH_TYPE FlushType
)
4822 BOOLEAN Result
= TRUE
;
4824 PMM_SECTION_SEGMENT Segment
;
4829 case MmFlushForDelete
:
4830 if (SectionObjectPointer
->ImageSectionObject
||
4831 SectionObjectPointer
->DataSectionObject
)
4836 CcRosSetRemoveOnClose(SectionObjectPointer
);
4839 case MmFlushForWrite
:
4841 DPRINT("MmFlushImageSection(%d)\n", FlushType
);
4843 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->DataSectionObject
;
4846 if (SectionObjectPointer
->ImageSectionObject
) {
4847 DPRINT1("SectionObject has ImageSection\n");
4853 Result
= !SectionObjectPointer
->SharedCacheMap
|| (Segment
->ReferenceCount
== CcpCountCacheSections((PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
));
4855 DPRINT("Result %d\n", Result
);
4867 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4868 OUT PVOID
* MappedBase
,
4869 IN OUT PSIZE_T ViewSize
)
4871 PROS_SECTION_OBJECT Section
;
4872 PMMSUPPORT AddressSpace
;
4876 if (MiIsRosSectionObject(SectionObject
) == FALSE
)
4878 DPRINT1("ARM3 System Mapping\n");
4879 return MiMapViewInSystemSpace(SectionObject
,
4885 DPRINT("MmMapViewInSystemSpace() called\n");
4887 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4888 AddressSpace
= MmGetKernelAddressSpace();
4890 MmLockAddressSpace(AddressSpace
);
4893 if ((*ViewSize
) == 0)
4895 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4897 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4899 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4902 MmLockSectionSegment(Section
->Segment
);
4905 Status
= MmMapViewOfSegment(AddressSpace
,
4914 MmUnlockSectionSegment(Section
->Segment
);
4915 MmUnlockAddressSpace(AddressSpace
);
4924 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4926 PMMSUPPORT AddressSpace
;
4929 DPRINT("MmUnmapViewInSystemSpace() called\n");
4931 AddressSpace
= MmGetKernelAddressSpace();
4933 MmLockAddressSpace(AddressSpace
);
4935 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4937 MmUnlockAddressSpace(AddressSpace
);
4943 /**********************************************************************
4948 * Creates a section object.
4951 * SectionObject (OUT)
4952 * Caller supplied storage for the resulting pointer
4953 * to a SECTION_OBJECT instance;
4956 * Specifies the desired access to the section can be a
4958 * STANDARD_RIGHTS_REQUIRED |
4960 * SECTION_MAP_WRITE |
4961 * SECTION_MAP_READ |
4962 * SECTION_MAP_EXECUTE
4964 * ObjectAttributes [OPTIONAL]
4965 * Initialized attributes for the object can be used
4966 * to create a named section;
4969 * Maximizes the size of the memory section. Must be
4970 * non-NULL for a page-file backed section.
4971 * If value specified for a mapped file and the file is
4972 * not large enough, file will be extended.
4974 * SectionPageProtection
4975 * Can be a combination of:
4981 * AllocationAttributes
4982 * Can be a combination of:
4987 * Handle to a file to create a section mapped to a file
4988 * instead of a memory backed section;
4999 MmCreateSection (OUT PVOID
* Section
,
5000 IN ACCESS_MASK DesiredAccess
,
5001 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
5002 IN PLARGE_INTEGER MaximumSize
,
5003 IN ULONG SectionPageProtection
,
5004 IN ULONG AllocationAttributes
,
5005 IN HANDLE FileHandle OPTIONAL
,
5006 IN PFILE_OBJECT FileObject OPTIONAL
)
5009 ULONG Protection
, FileAccess
;
5010 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
5012 /* Check if an ARM3 section is being created instead */
5013 if (AllocationAttributes
& 1)
5015 DPRINT1("Creating ARM3 section\n");
5016 return MmCreateArm3Section(Section
,
5020 SectionPageProtection
,
5021 AllocationAttributes
&~ 1,
5027 * Check the protection
5029 Protection
= SectionPageProtection
& ~(PAGE_GUARD
| PAGE_NOCACHE
);
5030 if (Protection
!= PAGE_READONLY
&&
5031 Protection
!= PAGE_READWRITE
&&
5032 Protection
!= PAGE_WRITECOPY
&&
5033 Protection
!= PAGE_EXECUTE
&&
5034 Protection
!= PAGE_EXECUTE_READ
&&
5035 Protection
!= PAGE_EXECUTE_READWRITE
&&
5036 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5038 return STATUS_INVALID_PAGE_PROTECTION
;
5041 if ((DesiredAccess
& SECTION_MAP_WRITE
) &&
5042 (Protection
== PAGE_READWRITE
||
5043 Protection
== PAGE_EXECUTE_READWRITE
) &&
5044 !(AllocationAttributes
& SEC_IMAGE
))
5046 DPRINT("Creating a section with WRITE access\n");
5047 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
| SYNCHRONIZE
;
5051 DPRINT("Creating a section with READ access\n");
5052 FileAccess
= FILE_READ_DATA
| SYNCHRONIZE
;
5055 /* FIXME: somehow combine this with the above checks */
5056 if (AllocationAttributes
& SEC_IMAGE
)
5057 FileAccess
= MiArm3GetCorrectFileAccessMask(SectionPageProtection
);
5059 if (!FileObject
&& FileHandle
)
5061 Status
= ObReferenceObjectByHandle(FileHandle
,
5064 ExGetPreviousMode(),
5065 (PVOID
*)&FileObject
,
5067 if (!NT_SUCCESS(Status
))
5069 DPRINT("Failed: 0x%08lx\n", Status
);
5073 else if (FileObject
)
5074 ObReferenceObject(FileObject
);
5076 #ifndef NEWCC // A hack for initializing caching.
5077 // This is needed only in the old case.
5080 IO_STATUS_BLOCK Iosb
;
5083 LARGE_INTEGER ByteOffset
;
5084 ByteOffset
.QuadPart
= 0;
5085 Status
= ZwReadFile(FileHandle
,
5094 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
5096 // Caching is initialized...
5100 if (AllocationAttributes
& SEC_IMAGE
)
5102 Status
= MmCreateImageSection(SectionObject
,
5106 SectionPageProtection
,
5107 AllocationAttributes
,
5111 else if (FileHandle
!= NULL
)
5113 Status
= MmCreateDataFileSection(SectionObject
,
5117 SectionPageProtection
,
5118 AllocationAttributes
,
5121 ObDereferenceObject(FileObject
);
5124 else if (FileHandle
!= NULL
|| FileObject
!= NULL
)
5126 Status
= MmCreateCacheSection(SectionObject
,
5130 SectionPageProtection
,
5131 AllocationAttributes
,
5137 Status
= MmCreatePageFileSection(SectionObject
,
5141 SectionPageProtection
,
5142 AllocationAttributes
);
5149 MmModifyAttributes(IN PMMSUPPORT AddressSpace
,
5150 IN PVOID BaseAddress
,
5151 IN SIZE_T RegionSize
,
5153 IN ULONG OldProtect
,
5155 IN ULONG NewProtect
)
5158 // This function is deprecated but remains in order to support VirtualAlloc
5159 // calls with MEM_COMMIT on top of MapViewOfFile calls with SEC_RESERVE.
5161 // Win32k's shared user heap, for example, uses that mechanism. The two
5162 // conditions when this function needs to do something are ASSERTed for,
5163 // because they should not arise.
5165 if (NewType
== MEM_RESERVE
&& OldType
== MEM_COMMIT
)
5170 if ((NewType
== MEM_COMMIT
) && (OldType
== MEM_COMMIT
))
5172 ASSERT(OldProtect
== NewProtect
);
5178 MiRosAllocateVirtualMemory(IN HANDLE ProcessHandle
,
5179 IN PEPROCESS Process
,
5180 IN PMEMORY_AREA MemoryArea
,
5181 IN PMMSUPPORT AddressSpace
,
5182 IN OUT PVOID
* UBaseAddress
,
5183 IN BOOLEAN Attached
,
5184 IN OUT PSIZE_T URegionSize
,
5185 IN ULONG AllocationType
,
5188 ULONG_PTR PRegionSize
;
5189 ULONG Type
, RegionSize
;
5191 PVOID PBaseAddress
, BaseAddress
;
5192 KAPC_STATE ApcState
;
5194 PBaseAddress
= *UBaseAddress
;
5195 PRegionSize
= *URegionSize
;
5197 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(PBaseAddress
);
5198 RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)PBaseAddress
+ PRegionSize
) -
5199 PAGE_ROUND_DOWN(PBaseAddress
);
5200 Type
= (AllocationType
& MEM_COMMIT
) ? MEM_COMMIT
: MEM_RESERVE
;
5202 ASSERT(PBaseAddress
!= 0);
5203 ASSERT(Type
== MEM_COMMIT
);
5204 ASSERT(MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
);
5205 ASSERT(((ULONG_PTR
)BaseAddress
+ RegionSize
) <= (ULONG_PTR
)MemoryArea
->EndingAddress
);
5206 ASSERT(((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
) >= RegionSize
);
5207 ASSERT(MemoryArea
->Data
.SectionData
.RegionListHead
.Flink
);
5209 Status
= MmAlterRegion(AddressSpace
,
5210 MemoryArea
->StartingAddress
,
5211 &MemoryArea
->Data
.SectionData
.RegionListHead
,
5216 MmModifyAttributes
);
5218 MmUnlockAddressSpace(AddressSpace
);
5219 if (Attached
) KeUnstackDetachProcess(&ApcState
);
5220 if (ProcessHandle
!= NtCurrentProcess()) ObDereferenceObject(Process
);
5221 if (NT_SUCCESS(Status
))
5223 *UBaseAddress
= BaseAddress
;
5224 *URegionSize
= RegionSize
;
5232 MiRosProtectVirtualMemory(IN PEPROCESS Process
,
5233 IN OUT PVOID
*BaseAddress
,
5234 IN OUT PSIZE_T NumberOfBytesToProtect
,
5235 IN ULONG NewAccessProtection
,
5236 OUT PULONG OldAccessProtection OPTIONAL
)
5238 PMEMORY_AREA MemoryArea
;
5239 PMMSUPPORT AddressSpace
;
5240 ULONG OldAccessProtection_
;
5243 *NumberOfBytesToProtect
= PAGE_ROUND_UP((ULONG_PTR
)(*BaseAddress
) + (*NumberOfBytesToProtect
)) - PAGE_ROUND_DOWN(*BaseAddress
);
5244 *BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(*BaseAddress
);
5246 AddressSpace
= &Process
->Vm
;
5247 MmLockAddressSpace(AddressSpace
);
5248 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, *BaseAddress
);
5249 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
5251 MmUnlockAddressSpace(AddressSpace
);
5252 return STATUS_UNSUCCESSFUL
;
5255 if (OldAccessProtection
== NULL
) OldAccessProtection
= &OldAccessProtection_
;
5257 if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
5259 Status
= MmProtectSectionView(AddressSpace
,
5262 *NumberOfBytesToProtect
,
5263 NewAccessProtection
,
5264 OldAccessProtection
);
5268 /* FIXME: Should we return failure or success in this case? */
5269 Status
= STATUS_CONFLICTING_ADDRESSES
;
5272 MmUnlockAddressSpace(AddressSpace
);