[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / mm / section.c
1 /*
2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
3 *
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.
8 *
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.
13 *
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.
17 *
18 *
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
22 *
23 * PROGRAMMERS: Rex Jolliff
24 * David Welch
25 * Eric Kohl
26 * Emanuele Aliberti
27 * Eugene Ingerman
28 * Casper Hornstrup
29 * KJK::Hyperion
30 * Guido de Jong
31 * Ge van Geldorp
32 * Royce Mitchell III
33 * Filip Navara
34 * Aleksey Bragin
35 * Jason Filby
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
38 * Mike Nordell
39 * Alex Ionescu
40 * Gregor Anich
41 * Steven Edwards
42 * Herve Poussineau
43 */
44
45 /* INCLUDES *****************************************************************/
46
47 #include <ntoskrnl.h>
48 #ifdef NEWCC
49 #include "../cache/section/newmm.h"
50 #endif
51 #define NDEBUG
52 #include <debug.h>
53 #include <reactos/exeformat.h>
54
55 #if defined (ALLOC_PRAGMA)
56 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
57 #pragma alloc_text(INIT, MmInitSectionImplementation)
58 #endif
59
60 NTSTATUS
61 NTAPI
62 MiMapViewInSystemSpace(IN PVOID Section,
63 IN PVOID Session,
64 OUT PVOID *MappedBase,
65 IN OUT PSIZE_T ViewSize);
66
67 NTSTATUS
68 NTAPI
69 MmCreateArm3Section(OUT PVOID *SectionObject,
70 IN ACCESS_MASK DesiredAccess,
71 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
72 IN PLARGE_INTEGER InputMaximumSize,
73 IN ULONG SectionPageProtection,
74 IN ULONG AllocationAttributes,
75 IN HANDLE FileHandle OPTIONAL,
76 IN PFILE_OBJECT FileObject OPTIONAL);
77
78 NTSTATUS
79 NTAPI
80 MmMapViewOfArm3Section(IN PVOID SectionObject,
81 IN PEPROCESS Process,
82 IN OUT PVOID *BaseAddress,
83 IN ULONG_PTR ZeroBits,
84 IN SIZE_T CommitSize,
85 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
86 IN OUT PSIZE_T ViewSize,
87 IN SECTION_INHERIT InheritDisposition,
88 IN ULONG AllocationType,
89 IN ULONG Protect);
90
91 //
92 // PeFmtCreateSection depends on the following:
93 //
94 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE >= sizeof(IMAGE_DOS_HEADER));
95 C_ASSERT(sizeof(IMAGE_NT_HEADERS32) <= sizeof(IMAGE_NT_HEADERS64));
96
97 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64));
98 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64, FileHeader));
99 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader) == FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader));
100
101 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Magic));
102 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SectionAlignment));
103 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, FileAlignment));
104 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Subsystem));
105 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MinorSubsystemVersion));
106 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MajorSubsystemVersion));
107 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint));
108 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode));
109 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfHeaders));
110
111 /* TYPES *********************************************************************/
112
113 typedef struct
114 {
115 PROS_SECTION_OBJECT Section;
116 PMM_SECTION_SEGMENT Segment;
117 ULONG Offset;
118 BOOLEAN WasDirty;
119 BOOLEAN Private;
120 }
121 MM_SECTION_PAGEOUT_CONTEXT;
122
123 /* GLOBALS *******************************************************************/
124
125 POBJECT_TYPE MmSectionObjectType = NULL;
126
127 ULONG_PTR MmSubsectionBase;
128
129 static ULONG SectionCharacteristicsToProtect[16] =
130 {
131 PAGE_NOACCESS, /* 0 = NONE */
132 PAGE_NOACCESS, /* 1 = SHARED */
133 PAGE_EXECUTE, /* 2 = EXECUTABLE */
134 PAGE_EXECUTE, /* 3 = EXECUTABLE, SHARED */
135 PAGE_READONLY, /* 4 = READABLE */
136 PAGE_READONLY, /* 5 = READABLE, SHARED */
137 PAGE_EXECUTE_READ, /* 6 = READABLE, EXECUTABLE */
138 PAGE_EXECUTE_READ, /* 7 = READABLE, EXECUTABLE, SHARED */
139 /*
140 * FIXME? do we really need the WriteCopy field in segments? can't we use
141 * PAGE_WRITECOPY here?
142 */
143 PAGE_READWRITE, /* 8 = WRITABLE */
144 PAGE_READWRITE, /* 9 = WRITABLE, SHARED */
145 PAGE_EXECUTE_READWRITE, /* 10 = WRITABLE, EXECUTABLE */
146 PAGE_EXECUTE_READWRITE, /* 11 = WRITABLE, EXECUTABLE, SHARED */
147 PAGE_READWRITE, /* 12 = WRITABLE, READABLE */
148 PAGE_READWRITE, /* 13 = WRITABLE, READABLE, SHARED */
149 PAGE_EXECUTE_READWRITE, /* 14 = WRITABLE, READABLE, EXECUTABLE */
150 PAGE_EXECUTE_READWRITE, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
151 };
152
153 static GENERIC_MAPPING MmpSectionMapping = {
154 STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
155 STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
156 STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
157 SECTION_ALL_ACCESS};
158
159 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
160 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
161 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
162 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
163 #define MAX_SHARE_COUNT 0x7FF
164 #define MAKE_SSE(P, C) ((ULONG)(P) | ((C) << 1))
165 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
166 #define MAKE_SWAP_SSE(S) (((ULONG)(S) << 1) | 0x1)
167
168 static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
169 {
170 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */
171 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionImageInformation */
172 };
173
174 /* FUNCTIONS *****************************************************************/
175
176
177 /*
178 References:
179 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
180 File Format Specification", revision 6.0 (February 1999)
181 */
182 NTSTATUS NTAPI PeFmtCreateSection(IN CONST VOID * FileHeader,
183 IN SIZE_T FileHeaderSize,
184 IN PVOID File,
185 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
186 OUT PULONG Flags,
187 IN PEXEFMT_CB_READ_FILE ReadFileCb,
188 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb)
189 {
190 NTSTATUS nStatus;
191 ULONG cbFileHeaderOffsetSize = 0;
192 ULONG cbSectionHeadersOffset = 0;
193 ULONG cbSectionHeadersSize;
194 ULONG cbSectionHeadersOffsetSize = 0;
195 ULONG cbOptHeaderSize;
196 ULONG cbHeadersSize = 0;
197 ULONG nSectionAlignment;
198 ULONG nFileAlignment;
199 const IMAGE_DOS_HEADER * pidhDosHeader;
200 const IMAGE_NT_HEADERS32 * pinhNtHeader;
201 const IMAGE_OPTIONAL_HEADER32 * piohOptHeader;
202 const IMAGE_SECTION_HEADER * pishSectionHeaders;
203 PMM_SECTION_SEGMENT pssSegments;
204 LARGE_INTEGER lnOffset;
205 PVOID pBuffer;
206 SIZE_T nPrevVirtualEndOfSegment = 0;
207 ULONG nFileSizeOfHeaders = 0;
208 ULONG i;
209
210 ASSERT(FileHeader);
211 ASSERT(FileHeaderSize > 0);
212 ASSERT(File);
213 ASSERT(ImageSectionObject);
214 ASSERT(ReadFileCb);
215 ASSERT(AllocateSegmentsCb);
216
217 ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize));
218
219 ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0);
220
221 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
222
223 pBuffer = NULL;
224 pidhDosHeader = FileHeader;
225
226 /* DOS HEADER */
227 nStatus = STATUS_ROS_EXEFMT_UNKNOWN_FORMAT;
228
229 /* image too small to be an MZ executable */
230 if(FileHeaderSize < sizeof(IMAGE_DOS_HEADER))
231 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize));
232
233 /* no MZ signature */
234 if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
235 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic));
236
237 /* not a Windows executable */
238 if(pidhDosHeader->e_lfanew <= 0)
239 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew));
240
241 /* NT HEADER */
242 nStatus = STATUS_INVALID_IMAGE_FORMAT;
243
244 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize, pidhDosHeader->e_lfanew, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader)))
245 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
246
247 if(FileHeaderSize < cbFileHeaderOffsetSize)
248 pinhNtHeader = NULL;
249 else
250 {
251 /*
252 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
253 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
254 */
255 ASSERT(Intsafe_CanOffsetPointer(FileHeader, pidhDosHeader->e_lfanew));
256 pinhNtHeader = (PVOID)((UINT_PTR)FileHeader + pidhDosHeader->e_lfanew);
257 }
258
259 /*
260 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
261 * need to read the header from the file
262 */
263 if(FileHeaderSize < cbFileHeaderOffsetSize ||
264 (UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
265 {
266 ULONG cbNtHeaderSize;
267 ULONG cbReadSize;
268 PVOID pData;
269
270 l_ReadHeaderFromFile:
271 cbNtHeaderSize = 0;
272 lnOffset.QuadPart = pidhDosHeader->e_lfanew;
273
274 /* read the header from the file */
275 nStatus = ReadFileCb(File, &lnOffset, sizeof(IMAGE_NT_HEADERS64), &pData, &pBuffer, &cbReadSize);
276
277 if(!NT_SUCCESS(nStatus))
278 DIE(("ReadFile failed, status %08X\n", nStatus));
279
280 ASSERT(pData);
281 ASSERT(pBuffer);
282 ASSERT(cbReadSize > 0);
283
284 nStatus = STATUS_INVALID_IMAGE_FORMAT;
285
286 /* the buffer doesn't contain the file header */
287 if(cbReadSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader))
288 DIE(("The file doesn't contain the PE file header\n"));
289
290 pinhNtHeader = pData;
291
292 /* object still not aligned: copy it to the beginning of the buffer */
293 if((UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
294 {
295 ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == 0);
296 RtlMoveMemory(pBuffer, pData, cbReadSize);
297 pinhNtHeader = pBuffer;
298 }
299
300 /* invalid NT header */
301 nStatus = STATUS_INVALID_IMAGE_PROTECT;
302
303 if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
304 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
305
306 nStatus = STATUS_INVALID_IMAGE_FORMAT;
307
308 if(!Intsafe_AddULong32(&cbNtHeaderSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
309 DIE(("The full NT header is too large\n"));
310
311 /* the buffer doesn't contain the whole NT header */
312 if(cbReadSize < cbNtHeaderSize)
313 DIE(("The file doesn't contain the full NT header\n"));
314 }
315 else
316 {
317 ULONG cbOptHeaderOffsetSize = 0;
318
319 nStatus = STATUS_INVALID_IMAGE_FORMAT;
320
321 /* don't trust an invalid NT header */
322 if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
323 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
324
325 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
326 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
327
328 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, cbOptHeaderOffsetSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
329 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader->FileHeader.SizeOfOptionalHeader));
330
331 /* the buffer doesn't contain the whole NT header: read it from the file */
332 if(cbOptHeaderOffsetSize > FileHeaderSize)
333 goto l_ReadHeaderFromFile;
334 }
335
336 /* read information from the NT header */
337 piohOptHeader = &pinhNtHeader->OptionalHeader;
338 cbOptHeaderSize = pinhNtHeader->FileHeader.SizeOfOptionalHeader;
339
340 nStatus = STATUS_INVALID_IMAGE_FORMAT;
341
342 if(!RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Magic))
343 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize));
344
345 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
346
347 switch(piohOptHeader->Magic)
348 {
349 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
350 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
351 break;
352
353 default:
354 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader->Magic));
355 }
356
357 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SectionAlignment) &&
358 RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, FileAlignment))
359 {
360 /* See [1], section 3.4.2 */
361 if(piohOptHeader->SectionAlignment < PAGE_SIZE)
362 {
363 if(piohOptHeader->FileAlignment != piohOptHeader->SectionAlignment)
364 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
365 }
366 else if(piohOptHeader->SectionAlignment < piohOptHeader->FileAlignment)
367 DIE(("The section alignment is smaller than the file alignment\n"));
368
369 nSectionAlignment = piohOptHeader->SectionAlignment;
370 nFileAlignment = piohOptHeader->FileAlignment;
371
372 if(!IsPowerOf2(nSectionAlignment) || !IsPowerOf2(nFileAlignment))
373 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment, nFileAlignment));
374 }
375 else
376 {
377 nSectionAlignment = PAGE_SIZE;
378 nFileAlignment = PAGE_SIZE;
379 }
380
381 ASSERT(IsPowerOf2(nSectionAlignment));
382 ASSERT(IsPowerOf2(nFileAlignment));
383
384 switch(piohOptHeader->Magic)
385 {
386 /* PE32 */
387 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
388 {
389 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, ImageBase))
390 ImageSectionObject->ImageBase = piohOptHeader->ImageBase;
391
392 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfImage))
393 ImageSectionObject->ImageSize = piohOptHeader->SizeOfImage;
394
395 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackReserve))
396 ImageSectionObject->StackReserve = piohOptHeader->SizeOfStackReserve;
397
398 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackCommit))
399 ImageSectionObject->StackCommit = piohOptHeader->SizeOfStackCommit;
400
401 break;
402 }
403
404 /* PE32+ */
405 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
406 {
407 const IMAGE_OPTIONAL_HEADER64 * pioh64OptHeader;
408
409 pioh64OptHeader = (const IMAGE_OPTIONAL_HEADER64 *)piohOptHeader;
410
411 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, ImageBase))
412 {
413 if(pioh64OptHeader->ImageBase > MAXULONG_PTR)
414 DIE(("ImageBase exceeds the address space\n"));
415
416 ImageSectionObject->ImageBase = (ULONG_PTR)pioh64OptHeader->ImageBase;
417 }
418
419 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfImage))
420 {
421 if(pioh64OptHeader->SizeOfImage > MAXULONG_PTR)
422 DIE(("SizeOfImage exceeds the address space\n"));
423
424 ImageSectionObject->ImageSize = pioh64OptHeader->SizeOfImage;
425 }
426
427 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackReserve))
428 {
429 if(pioh64OptHeader->SizeOfStackReserve > MAXULONG_PTR)
430 DIE(("SizeOfStackReserve exceeds the address space\n"));
431
432 ImageSectionObject->StackReserve = (ULONG_PTR)pioh64OptHeader->SizeOfStackReserve;
433 }
434
435 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackCommit))
436 {
437 if(pioh64OptHeader->SizeOfStackCommit > MAXULONG_PTR)
438 DIE(("SizeOfStackCommit exceeds the address space\n"));
439
440 ImageSectionObject->StackCommit = (ULONG_PTR)pioh64OptHeader->SizeOfStackCommit;
441 }
442
443 break;
444 }
445 }
446
447 /* [1], section 3.4.2 */
448 if((ULONG_PTR)ImageSectionObject->ImageBase % 0x10000)
449 DIE(("ImageBase is not aligned on a 64KB boundary"));
450
451 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Subsystem))
452 {
453 ImageSectionObject->Subsystem = piohOptHeader->Subsystem;
454
455 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MinorSubsystemVersion) &&
456 RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MajorSubsystemVersion))
457 {
458 ImageSectionObject->MinorSubsystemVersion = piohOptHeader->MinorSubsystemVersion;
459 ImageSectionObject->MajorSubsystemVersion = piohOptHeader->MajorSubsystemVersion;
460 }
461 }
462
463 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
464 {
465 ImageSectionObject->EntryPoint = piohOptHeader->ImageBase +
466 piohOptHeader->AddressOfEntryPoint;
467 }
468
469 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfCode))
470 ImageSectionObject->Executable = piohOptHeader->SizeOfCode != 0;
471 else
472 ImageSectionObject->Executable = TRUE;
473
474 ImageSectionObject->ImageCharacteristics = pinhNtHeader->FileHeader.Characteristics;
475 ImageSectionObject->Machine = pinhNtHeader->FileHeader.Machine;
476
477 /* SECTION HEADERS */
478 nStatus = STATUS_INVALID_IMAGE_FORMAT;
479
480 /* see [1], section 3.3 */
481 if(pinhNtHeader->FileHeader.NumberOfSections > 96)
482 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader->FileHeader.NumberOfSections));
483
484 /*
485 * the additional segment is for the file's headers. They need to be present for
486 * the benefit of the dynamic loader (to locate exports, defaults for thread
487 * parameters, resources, etc.)
488 */
489 ImageSectionObject->NrSegments = pinhNtHeader->FileHeader.NumberOfSections + 1;
490
491 /* file offset for the section headers */
492 if(!Intsafe_AddULong32(&cbSectionHeadersOffset, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
493 DIE(("Offset overflow\n"));
494
495 if(!Intsafe_AddULong32(&cbSectionHeadersOffset, cbSectionHeadersOffset, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
496 DIE(("Offset overflow\n"));
497
498 /* size of the section headers */
499 ASSERT(Intsafe_CanMulULong32(pinhNtHeader->FileHeader.NumberOfSections, sizeof(IMAGE_SECTION_HEADER)));
500 cbSectionHeadersSize = pinhNtHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
501
502 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize, cbSectionHeadersOffset, cbSectionHeadersSize))
503 DIE(("Section headers too large\n"));
504
505 /* size of the executable's headers */
506 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfHeaders))
507 {
508 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
509 // DIE(("SizeOfHeaders is not aligned\n"));
510
511 if(cbSectionHeadersSize > piohOptHeader->SizeOfHeaders)
512 DIE(("The section headers overflow SizeOfHeaders\n"));
513
514 cbHeadersSize = piohOptHeader->SizeOfHeaders;
515 }
516 else if(!AlignUp(&cbHeadersSize, cbSectionHeadersOffsetSize, nFileAlignment))
517 DIE(("Overflow aligning the size of headers\n"));
518
519 if(pBuffer)
520 {
521 ExFreePool(pBuffer);
522 pBuffer = NULL;
523 }
524 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
525 /* WARNING: piohOptHeader IS NO LONGER USABLE */
526 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
527
528 if(FileHeaderSize < cbSectionHeadersOffsetSize)
529 pishSectionHeaders = NULL;
530 else
531 {
532 /*
533 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
534 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
535 */
536 ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbSectionHeadersOffset));
537 pishSectionHeaders = (PVOID)((UINT_PTR)FileHeader + cbSectionHeadersOffset);
538 }
539
540 /*
541 * the buffer doesn't contain the section headers, or the alignment is wrong:
542 * read the headers from the file
543 */
544 if(FileHeaderSize < cbSectionHeadersOffsetSize ||
545 (UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
546 {
547 PVOID pData;
548 ULONG cbReadSize;
549
550 lnOffset.QuadPart = cbSectionHeadersOffset;
551
552 /* read the header from the file */
553 nStatus = ReadFileCb(File, &lnOffset, cbSectionHeadersSize, &pData, &pBuffer, &cbReadSize);
554
555 if(!NT_SUCCESS(nStatus))
556 DIE(("ReadFile failed with status %08X\n", nStatus));
557
558 ASSERT(pData);
559 ASSERT(pBuffer);
560 ASSERT(cbReadSize > 0);
561
562 nStatus = STATUS_INVALID_IMAGE_FORMAT;
563
564 /* the buffer doesn't contain all the section headers */
565 if(cbReadSize < cbSectionHeadersSize)
566 DIE(("The file doesn't contain all of the section headers\n"));
567
568 pishSectionHeaders = pData;
569
570 /* object still not aligned: copy it to the beginning of the buffer */
571 if((UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
572 {
573 ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) == 0);
574 RtlMoveMemory(pBuffer, pData, cbReadSize);
575 pishSectionHeaders = pBuffer;
576 }
577 }
578
579 /* SEGMENTS */
580 /* allocate the segments */
581 nStatus = STATUS_INSUFFICIENT_RESOURCES;
582 ImageSectionObject->Segments = AllocateSegmentsCb(ImageSectionObject->NrSegments);
583
584 if(ImageSectionObject->Segments == NULL)
585 DIE(("AllocateSegments failed\n"));
586
587 /* initialize the headers segment */
588 pssSegments = ImageSectionObject->Segments;
589
590 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
591
592 if(!AlignUp(&nFileSizeOfHeaders, cbHeadersSize, nFileAlignment))
593 DIE(("Cannot align the size of the section headers\n"));
594
595 nPrevVirtualEndOfSegment = ALIGN_UP_BY(cbHeadersSize, nSectionAlignment);
596 if (nPrevVirtualEndOfSegment < cbHeadersSize)
597 DIE(("Cannot align the size of the section headers\n"));
598
599 pssSegments[0].FileOffset = 0;
600 pssSegments[0].Protection = PAGE_READONLY;
601 pssSegments[0].Length = nPrevVirtualEndOfSegment;
602 pssSegments[0].RawLength = nFileSizeOfHeaders;
603 pssSegments[0].VirtualAddress = 0;
604 pssSegments[0].Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA;
605 pssSegments[0].WriteCopy = TRUE;
606
607 /* skip the headers segment */
608 ++ pssSegments;
609
610 nStatus = STATUS_INVALID_IMAGE_FORMAT;
611
612 /* convert the executable sections into segments. See also [1], section 4 */
613 for(i = 0; i < ImageSectionObject->NrSegments - 1; ++ i)
614 {
615 ULONG nCharacteristics;
616
617 /* validate the alignment */
618 if(!IsAligned(pishSectionHeaders[i].VirtualAddress, nSectionAlignment))
619 DIE(("VirtualAddress[%u] is not aligned\n", i));
620
621 /* sections must be contiguous, ordered by base address and non-overlapping */
622 if(pishSectionHeaders[i].VirtualAddress != nPrevVirtualEndOfSegment)
623 DIE(("Memory gap between section %u and the previous\n", i));
624
625 /* ignore explicit BSS sections */
626 if(pishSectionHeaders[i].SizeOfRawData != 0)
627 {
628 /* validate the alignment */
629 #if 0
630 /* Yes, this should be a multiple of FileAlignment, but there's
631 * stuff out there that isn't. We can cope with that
632 */
633 if(!IsAligned(pishSectionHeaders[i].SizeOfRawData, nFileAlignment))
634 DIE(("SizeOfRawData[%u] is not aligned\n", i));
635 #endif
636
637 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
638 // DIE(("PointerToRawData[%u] is not aligned\n", i));
639
640 /* conversion */
641 pssSegments[i].FileOffset = pishSectionHeaders[i].PointerToRawData;
642 pssSegments[i].RawLength = pishSectionHeaders[i].SizeOfRawData;
643 }
644 else
645 {
646 ASSERT(pssSegments[i].FileOffset == 0);
647 ASSERT(pssSegments[i].RawLength == 0);
648 }
649
650 ASSERT(Intsafe_CanAddLong64(pssSegments[i].FileOffset, pssSegments[i].RawLength));
651
652 nCharacteristics = pishSectionHeaders[i].Characteristics;
653
654 /* no explicit protection */
655 if((nCharacteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == 0)
656 {
657 if(nCharacteristics & IMAGE_SCN_CNT_CODE)
658 nCharacteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
659
660 if(nCharacteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
661 nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
662
663 if(nCharacteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
664 nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
665 }
666
667 /* see table above */
668 pssSegments[i].Protection = SectionCharacteristicsToProtect[nCharacteristics >> 28];
669 pssSegments[i].WriteCopy = !(nCharacteristics & IMAGE_SCN_MEM_SHARED);
670
671 if(pishSectionHeaders[i].Misc.VirtualSize == 0 || pishSectionHeaders[i].Misc.VirtualSize < pishSectionHeaders[i].SizeOfRawData)
672 pssSegments[i].Length = pishSectionHeaders[i].SizeOfRawData;
673 else
674 pssSegments[i].Length = pishSectionHeaders[i].Misc.VirtualSize;
675
676 pssSegments[i].Length = ALIGN_UP_BY(pssSegments[i].Length, nSectionAlignment);
677 if (pssSegments[i].Length < pssSegments[i].Length)
678 DIE(("Cannot align the virtual size of section %u\n", i));
679
680 if(pssSegments[i].Length == 0)
681 DIE(("Virtual size of section %u is null\n", i));
682
683 pssSegments[i].VirtualAddress = pishSectionHeaders[i].VirtualAddress;
684 pssSegments[i].Characteristics = pishSectionHeaders[i].Characteristics;
685
686 /* ensure the memory image is no larger than 4GB */
687 nPrevVirtualEndOfSegment = pssSegments[i].VirtualAddress + pssSegments[i].Length;
688 if (nPrevVirtualEndOfSegment < pssSegments[i].VirtualAddress)
689 DIE(("The image is too large\n"));
690 }
691
692 if(nSectionAlignment >= PAGE_SIZE)
693 *Flags |= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED;
694
695 /* Success */
696 nStatus = STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
697
698 l_Return:
699 if(pBuffer)
700 ExFreePool(pBuffer);
701
702 return nStatus;
703 }
704
705 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
706
707 /*
708 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
709 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
710 * RETURNS: Status of the wait.
711 */
712 static NTSTATUS
713 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp)
714 {
715 LARGE_INTEGER Timeout;
716 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
717
718 Timeout.QuadPart = -100000000LL; // 10 sec
719 #else
720
721 Timeout.QuadPart = -100000000; // 10 sec
722 #endif
723
724 return KeWaitForSingleObject(&PageOp->CompletionEvent, 0, KernelMode, FALSE, &Timeout);
725 }
726
727
728 /*
729 * FUNCTION: Sets the page op completion event and releases the page op.
730 * ARGUMENTS: PMM_PAGEOP.
731 * RETURNS: In shorter time than it takes you to even read this
732 * description, so don't even think about geting a mug of coffee.
733 */
734 static void
735 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp)
736 {
737 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
738 MmReleasePageOp(PageOp);
739 }
740
741
742 /*
743 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
744 * ARGUMENTS: PFILE_OBJECT to wait for.
745 * RETURNS: Status of the wait.
746 */
747 NTSTATUS
748 MmspWaitForFileLock(PFILE_OBJECT File)
749 {
750 return STATUS_SUCCESS;
751 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
752 }
753
754
755 VOID
756 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment)
757 {
758 ULONG i;
759 if (Segment->Length > NR_SECTION_PAGE_TABLES * PAGE_SIZE)
760 {
761 for (i = 0; i < NR_SECTION_PAGE_TABLES; i++)
762 {
763 if (Segment->PageDirectory.PageTables[i] != NULL)
764 {
765 ExFreePool(Segment->PageDirectory.PageTables[i]);
766 }
767 }
768 }
769 }
770
771 VOID
772 NTAPI
773 MmFreeSectionSegments(PFILE_OBJECT FileObject)
774 {
775 if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
776 {
777 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
778 PMM_SECTION_SEGMENT SectionSegments;
779 ULONG NrSegments;
780 ULONG i;
781
782 ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject;
783 NrSegments = ImageSectionObject->NrSegments;
784 SectionSegments = ImageSectionObject->Segments;
785 for (i = 0; i < NrSegments; i++)
786 {
787 if (SectionSegments[i].ReferenceCount != 0)
788 {
789 DPRINT1("Image segment %d still referenced (was %d)\n", i,
790 SectionSegments[i].ReferenceCount);
791 KeBugCheck(MEMORY_MANAGEMENT);
792 }
793 MmFreePageTablesSectionSegment(&SectionSegments[i]);
794 }
795 ExFreePool(ImageSectionObject->Segments);
796 ExFreePool(ImageSectionObject);
797 FileObject->SectionObjectPointer->ImageSectionObject = NULL;
798 }
799 if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
800 {
801 PMM_SECTION_SEGMENT Segment;
802
803 Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
804 DataSectionObject;
805
806 if (Segment->ReferenceCount != 0)
807 {
808 DPRINT1("Data segment still referenced\n");
809 KeBugCheck(MEMORY_MANAGEMENT);
810 }
811 MmFreePageTablesSectionSegment(Segment);
812 ExFreePool(Segment);
813 FileObject->SectionObjectPointer->DataSectionObject = NULL;
814 }
815 }
816
817 VOID
818 NTAPI
819 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment)
820 {
821 ExAcquireFastMutex(&Segment->Lock);
822 }
823
824 VOID
825 NTAPI
826 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment)
827 {
828 ExReleaseFastMutex(&Segment->Lock);
829 }
830
831 VOID
832 NTAPI
833 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
834 ULONG_PTR Offset,
835 ULONG_PTR Entry)
836 {
837 PSECTION_PAGE_TABLE Table;
838 ULONG_PTR DirectoryOffset;
839 ULONG_PTR TableOffset;
840
841 if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
842 {
843 Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
844 }
845 else
846 {
847 DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
848 Table = Segment->PageDirectory.PageTables[DirectoryOffset];
849 if (Table == NULL)
850 {
851 Table =
852 Segment->PageDirectory.PageTables[DirectoryOffset] =
853 ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_PAGE_TABLE),
854 TAG_SECTION_PAGE_TABLE);
855 if (Table == NULL)
856 {
857 KeBugCheck(MEMORY_MANAGEMENT);
858 }
859 memset(Table, 0, sizeof(SECTION_PAGE_TABLE));
860 DPRINT("Table %x\n", Table);
861 }
862 }
863 TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
864 Table->Entry[TableOffset] = (ULONG)Entry;
865 }
866
867
868 ULONG
869 NTAPI
870 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
871 ULONG_PTR Offset)
872 {
873 PSECTION_PAGE_TABLE Table;
874 ULONG Entry;
875 ULONG_PTR DirectoryOffset;
876 ULONG_PTR TableOffset;
877
878 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment, Offset);
879
880 if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
881 {
882 Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
883 }
884 else
885 {
886 DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
887 Table = Segment->PageDirectory.PageTables[DirectoryOffset];
888 DPRINT("Table %x\n", Table);
889 if (Table == NULL)
890 {
891 return(0);
892 }
893 }
894 TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
895 Entry = Table->Entry[TableOffset];
896 return(Entry);
897 }
898
899 VOID
900 NTAPI
901 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
902 ULONG_PTR Offset)
903 {
904 ULONG Entry;
905
906 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
907 if (Entry == 0)
908 {
909 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
910 KeBugCheck(MEMORY_MANAGEMENT);
911 }
912 if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
913 {
914 DPRINT1("Maximum share count reached\n");
915 KeBugCheck(MEMORY_MANAGEMENT);
916 }
917 if (IS_SWAP_FROM_SSE(Entry))
918 {
919 KeBugCheck(MEMORY_MANAGEMENT);
920 }
921 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1);
922 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
923 }
924
925 BOOLEAN
926 NTAPI
927 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section,
928 PMM_SECTION_SEGMENT Segment,
929 ULONG Offset,
930 BOOLEAN Dirty,
931 BOOLEAN PageOut)
932 {
933 ULONG Entry;
934 BOOLEAN IsDirectMapped = FALSE;
935
936 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
937 if (Entry == 0)
938 {
939 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
940 KeBugCheck(MEMORY_MANAGEMENT);
941 }
942 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
943 {
944 DPRINT1("Zero share count for unshare\n");
945 KeBugCheck(MEMORY_MANAGEMENT);
946 }
947 if (IS_SWAP_FROM_SSE(Entry))
948 {
949 KeBugCheck(MEMORY_MANAGEMENT);
950 }
951 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1);
952 /*
953 * If we reducing the share count of this entry to zero then set the entry
954 * to zero and tell the cache the page is no longer mapped.
955 */
956 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
957 {
958 PFILE_OBJECT FileObject;
959 PBCB Bcb;
960 SWAPENTRY SavedSwapEntry;
961 PFN_NUMBER Page;
962 BOOLEAN IsImageSection;
963 ULONG FileOffset;
964
965 FileOffset = Offset + Segment->FileOffset;
966
967 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
968
969 Page = PFN_FROM_SSE(Entry);
970 FileObject = Section->FileObject;
971 if (FileObject != NULL &&
972 !(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
973 {
974
975 if ((FileOffset % PAGE_SIZE) == 0 &&
976 (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
977 {
978 NTSTATUS Status;
979 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
980 IsDirectMapped = TRUE;
981 #ifndef NEWCC
982 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty);
983 #else
984 Status = STATUS_SUCCESS;
985 #endif
986 if (!NT_SUCCESS(Status))
987 {
988 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
989 KeBugCheck(MEMORY_MANAGEMENT);
990 }
991 }
992 }
993
994 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
995 if (SavedSwapEntry == 0)
996 {
997 if (!PageOut &&
998 ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
999 (Segment->Characteristics & IMAGE_SCN_MEM_SHARED)))
1000 {
1001 /*
1002 * FIXME:
1003 * Try to page out this page and set the swap entry
1004 * within the section segment. There exist no rmap entry
1005 * for this page. The pager thread can't page out a
1006 * page without a rmap entry.
1007 */
1008 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
1009 }
1010 else
1011 {
1012 MmSetPageEntrySectionSegment(Segment, Offset, 0);
1013 if (!IsDirectMapped)
1014 {
1015 MmReleasePageMemoryConsumer(MC_USER, Page);
1016 }
1017 }
1018 }
1019 else
1020 {
1021 if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
1022 (Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
1023 {
1024 if (!PageOut)
1025 {
1026 if (Dirty)
1027 {
1028 /*
1029 * FIXME:
1030 * We hold all locks. Nobody can do something with the current
1031 * process and the current segment (also not within an other process).
1032 */
1033 NTSTATUS Status;
1034 Status = MmWriteToSwapPage(SavedSwapEntry, Page);
1035 if (!NT_SUCCESS(Status))
1036 {
1037 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status);
1038 KeBugCheck(MEMORY_MANAGEMENT);
1039 }
1040 }
1041 MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry));
1042 MmSetSavedSwapEntryPage(Page, 0);
1043 }
1044 MmReleasePageMemoryConsumer(MC_USER, Page);
1045 }
1046 else
1047 {
1048 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
1049 KeBugCheck(MEMORY_MANAGEMENT);
1050 }
1051 }
1052 }
1053 else
1054 {
1055 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
1056 }
1057 return(SHARE_COUNT_FROM_SSE(Entry) > 0);
1058 }
1059
1060 BOOLEAN MiIsPageFromCache(PMEMORY_AREA MemoryArea,
1061 ULONG SegOffset)
1062 {
1063 #ifndef NEWCC
1064 if (!(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
1065 {
1066 PBCB Bcb;
1067 PCACHE_SEGMENT CacheSeg;
1068 Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap;
1069 CacheSeg = CcRosLookupCacheSegment(Bcb, SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset);
1070 if (CacheSeg)
1071 {
1072 CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE);
1073 return TRUE;
1074 }
1075 }
1076 #endif
1077 return FALSE;
1078 }
1079
1080 NTSTATUS
1081 NTAPI
1082 MiCopyFromUserPage(PFN_NUMBER DestPage, PVOID SourceAddress)
1083 {
1084 PEPROCESS Process;
1085 KIRQL Irql;
1086 PVOID TempAddress;
1087
1088 Process = PsGetCurrentProcess();
1089 TempAddress = MiMapPageInHyperSpace(Process, DestPage, &Irql);
1090 if (TempAddress == NULL)
1091 {
1092 return(STATUS_NO_MEMORY);
1093 }
1094 memcpy(TempAddress, SourceAddress, PAGE_SIZE);
1095 MiUnmapPageInHyperSpace(Process, TempAddress, Irql);
1096 return(STATUS_SUCCESS);
1097 }
1098
1099 #ifndef NEWCC
1100 NTSTATUS
1101 NTAPI
1102 MiReadPage(PMEMORY_AREA MemoryArea,
1103 ULONG_PTR SegOffset,
1104 PPFN_NUMBER Page)
1105 /*
1106 * FUNCTION: Read a page for a section backed memory area.
1107 * PARAMETERS:
1108 * MemoryArea - Memory area to read the page for.
1109 * Offset - Offset of the page to read.
1110 * Page - Variable that receives a page contains the read data.
1111 */
1112 {
1113 ULONG BaseOffset;
1114 ULONG_PTR FileOffset;
1115 PVOID BaseAddress;
1116 BOOLEAN UptoDate;
1117 PCACHE_SEGMENT CacheSeg;
1118 PFILE_OBJECT FileObject;
1119 NTSTATUS Status;
1120 ULONG_PTR RawLength;
1121 PBCB Bcb;
1122 BOOLEAN IsImageSection;
1123 ULONG_PTR Length;
1124
1125 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
1126 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1127 RawLength = MemoryArea->Data.SectionData.Segment->RawLength;
1128 FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset;
1129 IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1130
1131 ASSERT(Bcb);
1132
1133 DPRINT("%S %x\n", FileObject->FileName.Buffer, FileOffset);
1134
1135 /*
1136 * If the file system is letting us go directly to the cache and the
1137 * memory area was mapped at an offset in the file which is page aligned
1138 * then get the related cache segment.
1139 */
1140 if ((FileOffset % PAGE_SIZE) == 0 &&
1141 (SegOffset + PAGE_SIZE <= RawLength || !IsImageSection) &&
1142 !(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
1143 {
1144
1145 /*
1146 * Get the related cache segment; we use a lower level interface than
1147 * filesystems do because it is safe for us to use an offset with a
1148 * alignment less than the file system block size.
1149 */
1150 Status = CcRosGetCacheSegment(Bcb,
1151 (ULONG)FileOffset,
1152 &BaseOffset,
1153 &BaseAddress,
1154 &UptoDate,
1155 &CacheSeg);
1156 if (!NT_SUCCESS(Status))
1157 {
1158 return(Status);
1159 }
1160 if (!UptoDate)
1161 {
1162 /*
1163 * If the cache segment isn't up to date then call the file
1164 * system to read in the data.
1165 */
1166 Status = ReadCacheSegment(CacheSeg);
1167 if (!NT_SUCCESS(Status))
1168 {
1169 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
1170 return Status;
1171 }
1172 }
1173 /*
1174 * Retrieve the page from the cache segment that we actually want.
1175 */
1176 (*Page) = MmGetPhysicalAddress((char*)BaseAddress +
1177 FileOffset - BaseOffset).LowPart >> PAGE_SHIFT;
1178
1179 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, TRUE);
1180 }
1181 else
1182 {
1183 PEPROCESS Process;
1184 KIRQL Irql;
1185 PVOID PageAddr;
1186 ULONG_PTR CacheSegOffset;
1187
1188 /*
1189 * Allocate a page, this is rather complicated by the possibility
1190 * we might have to move other things out of memory
1191 */
1192 MI_SET_USAGE(MI_USAGE_SECTION);
1193 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
1194 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
1195 if (!NT_SUCCESS(Status))
1196 {
1197 return(Status);
1198 }
1199 Status = CcRosGetCacheSegment(Bcb,
1200 (ULONG)FileOffset,
1201 &BaseOffset,
1202 &BaseAddress,
1203 &UptoDate,
1204 &CacheSeg);
1205 if (!NT_SUCCESS(Status))
1206 {
1207 return(Status);
1208 }
1209 if (!UptoDate)
1210 {
1211 /*
1212 * If the cache segment isn't up to date then call the file
1213 * system to read in the data.
1214 */
1215 Status = ReadCacheSegment(CacheSeg);
1216 if (!NT_SUCCESS(Status))
1217 {
1218 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
1219 return Status;
1220 }
1221 }
1222
1223 Process = PsGetCurrentProcess();
1224 PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql);
1225 CacheSegOffset = BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset;
1226 Length = RawLength - SegOffset;
1227 if (Length <= CacheSegOffset && Length <= PAGE_SIZE)
1228 {
1229 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, Length);
1230 }
1231 else if (CacheSegOffset >= PAGE_SIZE)
1232 {
1233 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, PAGE_SIZE);
1234 }
1235 else
1236 {
1237 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, CacheSegOffset);
1238 MiUnmapPageInHyperSpace(Process, PageAddr, Irql);
1239 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
1240 Status = CcRosGetCacheSegment(Bcb,
1241 (ULONG)(FileOffset + CacheSegOffset),
1242 &BaseOffset,
1243 &BaseAddress,
1244 &UptoDate,
1245 &CacheSeg);
1246 if (!NT_SUCCESS(Status))
1247 {
1248 return(Status);
1249 }
1250 if (!UptoDate)
1251 {
1252 /*
1253 * If the cache segment isn't up to date then call the file
1254 * system to read in the data.
1255 */
1256 Status = ReadCacheSegment(CacheSeg);
1257 if (!NT_SUCCESS(Status))
1258 {
1259 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
1260 return Status;
1261 }
1262 }
1263 PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql);
1264 if (Length < PAGE_SIZE)
1265 {
1266 memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, Length - CacheSegOffset);
1267 }
1268 else
1269 {
1270 memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, PAGE_SIZE - CacheSegOffset);
1271 }
1272 }
1273 MiUnmapPageInHyperSpace(Process, PageAddr, Irql);
1274 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
1275 }
1276 return(STATUS_SUCCESS);
1277 }
1278 #else
1279 NTSTATUS
1280 NTAPI
1281 MiReadPage(PMEMORY_AREA MemoryArea,
1282 ULONG SegOffset,
1283 PPFN_NUMBER Page)
1284 /*
1285 * FUNCTION: Read a page for a section backed memory area.
1286 * PARAMETERS:
1287 * MemoryArea - Memory area to read the page for.
1288 * Offset - Offset of the page to read.
1289 * Page - Variable that receives a page contains the read data.
1290 */
1291 {
1292 MM_REQUIRED_RESOURCES Resources = { };
1293
1294 Resources.Context = MemoryArea->Data.SectionData.Section->FileObject;
1295 Resources.FileOffset.QuadPart = SegOffset +
1296 MemoryArea->Data.SectionData.Segment->FileOffset;
1297 Resources.Consumer = MC_USER;
1298 Resources.Amount = PAGE_SIZE;
1299
1300 DPRINT1("%S, offset %x, len %d, page %x\n", ((PFILE_OBJECT)Resources.Context)->FileName.Buffer, Resources.FileOffset.LowPart, Resources.Amount, Resources.Page[0]);
1301
1302 NTSTATUS Status = MiReadFilePage(NULL, NULL, &Resources);
1303 *Page = Resources.Page[0];
1304 return Status;
1305 }
1306 #endif
1307
1308 NTSTATUS
1309 NTAPI
1310 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
1311 MEMORY_AREA* MemoryArea,
1312 PVOID Address)
1313 {
1314 ULONG Offset;
1315 PFN_NUMBER Page;
1316 NTSTATUS Status;
1317 PVOID PAddress;
1318 PROS_SECTION_OBJECT Section;
1319 PMM_SECTION_SEGMENT Segment;
1320 ULONG_PTR Entry;
1321 ULONG_PTR Entry1;
1322 ULONG Attributes;
1323 PMM_PAGEOP PageOp;
1324 PMM_REGION Region;
1325 BOOLEAN HasSwapEntry;
1326 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1327
1328 /*
1329 * There is a window between taking the page fault and locking the
1330 * address space when another thread could load the page so we check
1331 * that.
1332 */
1333 if (MmIsPagePresent(Process, Address))
1334 {
1335 return(STATUS_SUCCESS);
1336 }
1337
1338 /*
1339 * Check for the virtual memory area being deleted.
1340 */
1341 if (MemoryArea->DeleteInProgress)
1342 {
1343 return(STATUS_UNSUCCESSFUL);
1344 }
1345
1346 PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
1347 Offset = (ULONG)((ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress
1348 + MemoryArea->Data.SectionData.ViewOffset);
1349
1350 Segment = MemoryArea->Data.SectionData.Segment;
1351 Section = MemoryArea->Data.SectionData.Section;
1352 Region = MmFindRegion(MemoryArea->StartingAddress,
1353 &MemoryArea->Data.SectionData.RegionListHead,
1354 Address, NULL);
1355 /*
1356 * Lock the segment
1357 */
1358 MmLockSectionSegment(Segment);
1359
1360 /*
1361 * Check if this page needs to be mapped COW
1362 */
1363 if ((Segment->WriteCopy) &&
1364 (Region->Protect == PAGE_READWRITE ||
1365 Region->Protect == PAGE_EXECUTE_READWRITE))
1366 {
1367 Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
1368 }
1369 else
1370 {
1371 Attributes = Region->Protect;
1372 }
1373
1374 /*
1375 * Get or create a page operation descriptor
1376 */
1377 PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset, MM_PAGEOP_PAGEIN, FALSE);
1378 if (PageOp == NULL)
1379 {
1380 DPRINT1("MmGetPageOp failed\n");
1381 KeBugCheck(MEMORY_MANAGEMENT);
1382 }
1383
1384 /*
1385 * Check if someone else is already handling this fault, if so wait
1386 * for them
1387 */
1388 if (PageOp->Thread != PsGetCurrentThread())
1389 {
1390 MmUnlockSectionSegment(Segment);
1391 MmUnlockAddressSpace(AddressSpace);
1392 Status = MmspWaitForPageOpCompletionEvent(PageOp);
1393 /*
1394 * Check for various strange conditions
1395 */
1396 if (Status != STATUS_SUCCESS)
1397 {
1398 DPRINT1("Failed to wait for page op, status = %x\n", Status);
1399 KeBugCheck(MEMORY_MANAGEMENT);
1400 }
1401 if (PageOp->Status == STATUS_PENDING)
1402 {
1403 DPRINT1("Woke for page op before completion\n");
1404 KeBugCheck(MEMORY_MANAGEMENT);
1405 }
1406 MmLockAddressSpace(AddressSpace);
1407 /*
1408 * If this wasn't a pagein then restart the operation
1409 */
1410 if (PageOp->OpType != MM_PAGEOP_PAGEIN)
1411 {
1412 MmspCompleteAndReleasePageOp(PageOp);
1413 DPRINT("Address 0x%.8X\n", Address);
1414 return(STATUS_MM_RESTART_OPERATION);
1415 }
1416
1417 /*
1418 * If the thread handling this fault has failed then we don't retry
1419 */
1420 if (!NT_SUCCESS(PageOp->Status))
1421 {
1422 Status = PageOp->Status;
1423 MmspCompleteAndReleasePageOp(PageOp);
1424 DPRINT("Address 0x%.8X\n", Address);
1425 return(Status);
1426 }
1427 MmLockSectionSegment(Segment);
1428 /*
1429 * If the completed fault was for another address space then set the
1430 * page in this one.
1431 */
1432 if (!MmIsPagePresent(Process, Address))
1433 {
1434 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1435 HasSwapEntry = MmIsPageSwapEntry(Process, (PVOID)PAddress);
1436
1437 if (PAGE_FROM_SSE(Entry) == 0 || HasSwapEntry)
1438 {
1439 /*
1440 * The page was a private page in another or in our address space
1441 */
1442 MmUnlockSectionSegment(Segment);
1443 MmspCompleteAndReleasePageOp(PageOp);
1444 return(STATUS_MM_RESTART_OPERATION);
1445 }
1446
1447 Page = PFN_FROM_SSE(Entry);
1448
1449 MmSharePageEntrySectionSegment(Segment, Offset);
1450
1451 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
1452 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
1453 */
1454 Status = MmCreateVirtualMapping(Process,
1455 Address,
1456 Attributes,
1457 &Page,
1458 1);
1459 if (!NT_SUCCESS(Status))
1460 {
1461 DPRINT1("Unable to create virtual mapping\n");
1462 KeBugCheck(MEMORY_MANAGEMENT);
1463 }
1464 MmInsertRmap(Page, Process, (PVOID)PAddress);
1465 }
1466 MmUnlockSectionSegment(Segment);
1467 PageOp->Status = STATUS_SUCCESS;
1468 MmspCompleteAndReleasePageOp(PageOp);
1469 DPRINT("Address 0x%.8X\n", Address);
1470 return(STATUS_SUCCESS);
1471 }
1472
1473 HasSwapEntry = MmIsPageSwapEntry(Process, (PVOID)PAddress);
1474 if (HasSwapEntry)
1475 {
1476 /*
1477 * Must be private page we have swapped out.
1478 */
1479 SWAPENTRY SwapEntry;
1480
1481 /*
1482 * Sanity check
1483 */
1484 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
1485 {
1486 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1487 KeBugCheck(MEMORY_MANAGEMENT);
1488 }
1489
1490 MmUnlockSectionSegment(Segment);
1491 MmDeletePageFileMapping(Process, (PVOID)PAddress, &SwapEntry);
1492
1493 MmUnlockAddressSpace(AddressSpace);
1494 MI_SET_USAGE(MI_USAGE_SECTION);
1495 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1496 if (!Process) MI_SET_PROCESS2("Kernel Section");
1497 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1498 if (!NT_SUCCESS(Status))
1499 {
1500 KeBugCheck(MEMORY_MANAGEMENT);
1501 }
1502
1503 Status = MmReadFromSwapPage(SwapEntry, Page);
1504 if (!NT_SUCCESS(Status))
1505 {
1506 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
1507 KeBugCheck(MEMORY_MANAGEMENT);
1508 }
1509 MmLockAddressSpace(AddressSpace);
1510 Status = MmCreateVirtualMapping(Process,
1511 Address,
1512 Region->Protect,
1513 &Page,
1514 1);
1515 if (!NT_SUCCESS(Status))
1516 {
1517 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1518 KeBugCheck(MEMORY_MANAGEMENT);
1519 return(Status);
1520 }
1521
1522 /*
1523 * Store the swap entry for later use.
1524 */
1525 MmSetSavedSwapEntryPage(Page, SwapEntry);
1526
1527 /*
1528 * Add the page to the process's working set
1529 */
1530 MmInsertRmap(Page, Process, (PVOID)PAddress);
1531
1532 /*
1533 * Finish the operation
1534 */
1535 PageOp->Status = STATUS_SUCCESS;
1536 MmspCompleteAndReleasePageOp(PageOp);
1537 DPRINT("Address 0x%.8X\n", Address);
1538 return(STATUS_SUCCESS);
1539 }
1540
1541 /*
1542 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1543 */
1544 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1545 {
1546 MmUnlockSectionSegment(Segment);
1547 /*
1548 * Just map the desired physical page
1549 */
1550 Page = Offset >> PAGE_SHIFT;
1551 Status = MmCreateVirtualMappingUnsafe(Process,
1552 Address,
1553 Region->Protect,
1554 &Page,
1555 1);
1556 if (!NT_SUCCESS(Status))
1557 {
1558 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1559 KeBugCheck(MEMORY_MANAGEMENT);
1560 return(Status);
1561 }
1562
1563 /*
1564 * Cleanup and release locks
1565 */
1566 PageOp->Status = STATUS_SUCCESS;
1567 MmspCompleteAndReleasePageOp(PageOp);
1568 DPRINT("Address 0x%.8X\n", Address);
1569 return(STATUS_SUCCESS);
1570 }
1571
1572 /*
1573 * Map anonymous memory for BSS sections
1574 */
1575 if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
1576 {
1577 MmUnlockSectionSegment(Segment);
1578 MI_SET_USAGE(MI_USAGE_SECTION);
1579 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1580 if (!Process) MI_SET_PROCESS2("Kernel Section");
1581 Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
1582 if (!NT_SUCCESS(Status))
1583 {
1584 MmUnlockAddressSpace(AddressSpace);
1585 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1586 MmLockAddressSpace(AddressSpace);
1587 }
1588 if (!NT_SUCCESS(Status))
1589 {
1590 KeBugCheck(MEMORY_MANAGEMENT);
1591 }
1592 Status = MmCreateVirtualMapping(Process,
1593 Address,
1594 Region->Protect,
1595 &Page,
1596 1);
1597 if (!NT_SUCCESS(Status))
1598 {
1599 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1600 KeBugCheck(MEMORY_MANAGEMENT);
1601 return(Status);
1602 }
1603 MmInsertRmap(Page, Process, (PVOID)PAddress);
1604
1605 /*
1606 * Cleanup and release locks
1607 */
1608 PageOp->Status = STATUS_SUCCESS;
1609 MmspCompleteAndReleasePageOp(PageOp);
1610 DPRINT("Address 0x%.8X\n", Address);
1611 return(STATUS_SUCCESS);
1612 }
1613
1614 /*
1615 * Get the entry corresponding to the offset within the section
1616 */
1617 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1618
1619 if (Entry == 0)
1620 {
1621 /*
1622 * If the entry is zero (and it can't change because we have
1623 * locked the segment) then we need to load the page.
1624 */
1625
1626 /*
1627 * Release all our locks and read in the page from disk
1628 */
1629 MmUnlockSectionSegment(Segment);
1630 MmUnlockAddressSpace(AddressSpace);
1631
1632 if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
1633 (Offset >= PAGE_ROUND_UP(Segment->RawLength) && Section->AllocationAttributes & SEC_IMAGE))
1634 {
1635 MI_SET_USAGE(MI_USAGE_SECTION);
1636 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1637 if (!Process) MI_SET_PROCESS2("Kernel Section");
1638 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1639 if (!NT_SUCCESS(Status))
1640 {
1641 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
1642 }
1643
1644 }
1645 else
1646 {
1647 Status = MiReadPage(MemoryArea, Offset, &Page);
1648 if (!NT_SUCCESS(Status))
1649 {
1650 DPRINT1("MiReadPage failed (Status %x)\n", Status);
1651 }
1652 }
1653 if (!NT_SUCCESS(Status))
1654 {
1655 /*
1656 * FIXME: What do we know in this case?
1657 */
1658 /*
1659 * Cleanup and release locks
1660 */
1661 MmLockAddressSpace(AddressSpace);
1662 PageOp->Status = Status;
1663 MmspCompleteAndReleasePageOp(PageOp);
1664 DPRINT("Address 0x%.8X\n", Address);
1665 return(Status);
1666 }
1667 /*
1668 * Relock the address space and segment
1669 */
1670 MmLockAddressSpace(AddressSpace);
1671 MmLockSectionSegment(Segment);
1672
1673 /*
1674 * Check the entry. No one should change the status of a page
1675 * that has a pending page-in.
1676 */
1677 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
1678 if (Entry != Entry1)
1679 {
1680 DPRINT1("Someone changed ppte entry while we slept\n");
1681 KeBugCheck(MEMORY_MANAGEMENT);
1682 }
1683
1684 /*
1685 * Mark the offset within the section as having valid, in-memory
1686 * data
1687 */
1688 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1689 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
1690 MmUnlockSectionSegment(Segment);
1691
1692 Status = MmCreateVirtualMapping(Process,
1693 Address,
1694 Attributes,
1695 &Page,
1696 1);
1697 if (!NT_SUCCESS(Status))
1698 {
1699 DPRINT1("Unable to create virtual mapping\n");
1700 KeBugCheck(MEMORY_MANAGEMENT);
1701 }
1702 MmInsertRmap(Page, Process, (PVOID)PAddress);
1703
1704 PageOp->Status = STATUS_SUCCESS;
1705 MmspCompleteAndReleasePageOp(PageOp);
1706 DPRINT("Address 0x%.8X\n", Address);
1707 return(STATUS_SUCCESS);
1708 }
1709 else if (IS_SWAP_FROM_SSE(Entry))
1710 {
1711 SWAPENTRY SwapEntry;
1712
1713 SwapEntry = SWAPENTRY_FROM_SSE(Entry);
1714
1715 /*
1716 * Release all our locks and read in the page from disk
1717 */
1718 MmUnlockSectionSegment(Segment);
1719
1720 MmUnlockAddressSpace(AddressSpace);
1721 MI_SET_USAGE(MI_USAGE_SECTION);
1722 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1723 if (!Process) MI_SET_PROCESS2("Kernel Section");
1724 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1725 if (!NT_SUCCESS(Status))
1726 {
1727 KeBugCheck(MEMORY_MANAGEMENT);
1728 }
1729
1730 Status = MmReadFromSwapPage(SwapEntry, Page);
1731 if (!NT_SUCCESS(Status))
1732 {
1733 KeBugCheck(MEMORY_MANAGEMENT);
1734 }
1735
1736 /*
1737 * Relock the address space and segment
1738 */
1739 MmLockAddressSpace(AddressSpace);
1740 MmLockSectionSegment(Segment);
1741
1742 /*
1743 * Check the entry. No one should change the status of a page
1744 * that has a pending page-in.
1745 */
1746 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
1747 if (Entry != Entry1)
1748 {
1749 DPRINT1("Someone changed ppte entry while we slept\n");
1750 KeBugCheck(MEMORY_MANAGEMENT);
1751 }
1752
1753 /*
1754 * Mark the offset within the section as having valid, in-memory
1755 * data
1756 */
1757 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1758 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
1759 MmUnlockSectionSegment(Segment);
1760
1761 /*
1762 * Save the swap entry.
1763 */
1764 MmSetSavedSwapEntryPage(Page, SwapEntry);
1765 Status = MmCreateVirtualMapping(Process,
1766 Address,
1767 Region->Protect,
1768 &Page,
1769 1);
1770 if (!NT_SUCCESS(Status))
1771 {
1772 DPRINT1("Unable to create virtual mapping\n");
1773 KeBugCheck(MEMORY_MANAGEMENT);
1774 }
1775 MmInsertRmap(Page, Process, (PVOID)PAddress);
1776 PageOp->Status = STATUS_SUCCESS;
1777 MmspCompleteAndReleasePageOp(PageOp);
1778 DPRINT("Address 0x%.8X\n", Address);
1779 return(STATUS_SUCCESS);
1780 }
1781 else
1782 {
1783 /*
1784 * If the section offset is already in-memory and valid then just
1785 * take another reference to the page
1786 */
1787
1788 Page = PFN_FROM_SSE(Entry);
1789
1790 MmSharePageEntrySectionSegment(Segment, Offset);
1791 MmUnlockSectionSegment(Segment);
1792
1793 Status = MmCreateVirtualMapping(Process,
1794 Address,
1795 Attributes,
1796 &Page,
1797 1);
1798 if (!NT_SUCCESS(Status))
1799 {
1800 DPRINT1("Unable to create virtual mapping\n");
1801 KeBugCheck(MEMORY_MANAGEMENT);
1802 }
1803 MmInsertRmap(Page, Process, (PVOID)PAddress);
1804 PageOp->Status = STATUS_SUCCESS;
1805 MmspCompleteAndReleasePageOp(PageOp);
1806 DPRINT("Address 0x%.8X\n", Address);
1807 return(STATUS_SUCCESS);
1808 }
1809 }
1810
1811 NTSTATUS
1812 NTAPI
1813 MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
1814 MEMORY_AREA* MemoryArea,
1815 PVOID Address)
1816 {
1817 PMM_SECTION_SEGMENT Segment;
1818 PROS_SECTION_OBJECT Section;
1819 PFN_NUMBER OldPage;
1820 PFN_NUMBER NewPage;
1821 NTSTATUS Status;
1822 PVOID PAddress;
1823 ULONG Offset;
1824 PMM_PAGEOP PageOp;
1825 PMM_REGION Region;
1826 ULONG Entry;
1827 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1828
1829 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace, MemoryArea, Address);
1830
1831 /*
1832 * Check if the page has been paged out or has already been set readwrite
1833 */
1834 if (!MmIsPagePresent(Process, Address) ||
1835 MmGetPageProtect(Process, Address) & PAGE_READWRITE)
1836 {
1837 DPRINT("Address 0x%.8X\n", Address);
1838 return(STATUS_SUCCESS);
1839 }
1840
1841 /*
1842 * Find the offset of the page
1843 */
1844 PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
1845 Offset = (ULONG)((ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress
1846 + MemoryArea->Data.SectionData.ViewOffset);
1847
1848 Segment = MemoryArea->Data.SectionData.Segment;
1849 Section = MemoryArea->Data.SectionData.Section;
1850 Region = MmFindRegion(MemoryArea->StartingAddress,
1851 &MemoryArea->Data.SectionData.RegionListHead,
1852 Address, NULL);
1853 /*
1854 * Lock the segment
1855 */
1856 MmLockSectionSegment(Segment);
1857
1858 OldPage = MmGetPfnForProcess(NULL, Address);
1859 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1860
1861 MmUnlockSectionSegment(Segment);
1862
1863 /*
1864 * Check if we are doing COW
1865 */
1866 if (!((Segment->WriteCopy) &&
1867 (Region->Protect == PAGE_READWRITE ||
1868 Region->Protect == PAGE_EXECUTE_READWRITE)))
1869 {
1870 DPRINT("Address 0x%.8X\n", Address);
1871 return(STATUS_ACCESS_VIOLATION);
1872 }
1873
1874 if (IS_SWAP_FROM_SSE(Entry) ||
1875 PFN_FROM_SSE(Entry) != OldPage)
1876 {
1877 /* This is a private page. We must only change the page protection. */
1878 MmSetPageProtect(Process, PAddress, Region->Protect);
1879 return(STATUS_SUCCESS);
1880 }
1881
1882 /*
1883 * Get or create a pageop
1884 */
1885 PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset,
1886 MM_PAGEOP_ACCESSFAULT, FALSE);
1887 if (PageOp == NULL)
1888 {
1889 DPRINT1("MmGetPageOp failed\n");
1890 KeBugCheck(MEMORY_MANAGEMENT);
1891 }
1892
1893 /*
1894 * Wait for any other operations to complete
1895 */
1896 if (PageOp->Thread != PsGetCurrentThread())
1897 {
1898 MmUnlockAddressSpace(AddressSpace);
1899 Status = MmspWaitForPageOpCompletionEvent(PageOp);
1900 /*
1901 * Check for various strange conditions
1902 */
1903 if (Status == STATUS_TIMEOUT)
1904 {
1905 DPRINT1("Failed to wait for page op, status = %x\n", Status);
1906 KeBugCheck(MEMORY_MANAGEMENT);
1907 }
1908 if (PageOp->Status == STATUS_PENDING)
1909 {
1910 DPRINT1("Woke for page op before completion\n");
1911 KeBugCheck(MEMORY_MANAGEMENT);
1912 }
1913 /*
1914 * Restart the operation
1915 */
1916 MmLockAddressSpace(AddressSpace);
1917 MmspCompleteAndReleasePageOp(PageOp);
1918 DPRINT("Address 0x%.8X\n", Address);
1919 return(STATUS_MM_RESTART_OPERATION);
1920 }
1921
1922 /*
1923 * Release locks now we have the pageop
1924 */
1925 MmUnlockAddressSpace(AddressSpace);
1926
1927 /*
1928 * Allocate a page
1929 */
1930 MI_SET_USAGE(MI_USAGE_SECTION);
1931 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1932 if (!Process) MI_SET_PROCESS2("Kernel Section");
1933 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1934 if (!NT_SUCCESS(Status))
1935 {
1936 KeBugCheck(MEMORY_MANAGEMENT);
1937 }
1938
1939 /*
1940 * Copy the old page
1941 */
1942 MiCopyFromUserPage(NewPage, PAddress);
1943
1944 MmLockAddressSpace(AddressSpace);
1945 /*
1946 * Delete the old entry.
1947 */
1948 MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
1949
1950 /*
1951 * Set the PTE to point to the new page
1952 */
1953 Status = MmCreateVirtualMapping(Process,
1954 Address,
1955 Region->Protect,
1956 &NewPage,
1957 1);
1958 if (!NT_SUCCESS(Status))
1959 {
1960 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1961 KeBugCheck(MEMORY_MANAGEMENT);
1962 return(Status);
1963 }
1964 if (!NT_SUCCESS(Status))
1965 {
1966 DPRINT1("Unable to create virtual mapping\n");
1967 KeBugCheck(MEMORY_MANAGEMENT);
1968 }
1969
1970 /*
1971 * Unshare the old page.
1972 */
1973 MmDeleteRmap(OldPage, Process, PAddress);
1974 MmInsertRmap(NewPage, Process, PAddress);
1975 MmLockSectionSegment(Segment);
1976 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE, FALSE);
1977 MmUnlockSectionSegment(Segment);
1978
1979 PageOp->Status = STATUS_SUCCESS;
1980 MmspCompleteAndReleasePageOp(PageOp);
1981 DPRINT("Address 0x%.8X\n", Address);
1982 return(STATUS_SUCCESS);
1983 }
1984
1985 VOID
1986 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
1987 {
1988 MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1989 BOOLEAN WasDirty;
1990 PFN_NUMBER Page;
1991
1992 PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1993 if (Process)
1994 {
1995 MmLockAddressSpace(&Process->Vm);
1996 }
1997
1998 MmDeleteVirtualMapping(Process,
1999 Address,
2000 FALSE,
2001 &WasDirty,
2002 &Page);
2003 if (WasDirty)
2004 {
2005 PageOutContext->WasDirty = TRUE;
2006 }
2007 if (!PageOutContext->Private)
2008 {
2009 MmLockSectionSegment(PageOutContext->Segment);
2010 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT)PageOutContext->Section,
2011 PageOutContext->Segment,
2012 PageOutContext->Offset,
2013 PageOutContext->WasDirty,
2014 TRUE);
2015 MmUnlockSectionSegment(PageOutContext->Segment);
2016 }
2017 if (Process)
2018 {
2019 MmUnlockAddressSpace(&Process->Vm);
2020 }
2021
2022 if (PageOutContext->Private)
2023 {
2024 MmReleasePageMemoryConsumer(MC_USER, Page);
2025 }
2026
2027 DPRINT("PhysicalAddress %x, Address %x\n", Page << PAGE_SHIFT, Address);
2028 }
2029
2030 NTSTATUS
2031 NTAPI
2032 MmPageOutSectionView(PMMSUPPORT AddressSpace,
2033 MEMORY_AREA* MemoryArea,
2034 PVOID Address,
2035 PMM_PAGEOP PageOp)
2036 {
2037 PFN_NUMBER Page;
2038 MM_SECTION_PAGEOUT_CONTEXT Context;
2039 SWAPENTRY SwapEntry;
2040 ULONG Entry;
2041 ULONG FileOffset;
2042 NTSTATUS Status;
2043 PFILE_OBJECT FileObject;
2044 #ifndef NEWCC
2045 PBCB Bcb = NULL;
2046 #endif
2047 BOOLEAN DirectMapped;
2048 BOOLEAN IsImageSection;
2049 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
2050 KIRQL OldIrql;
2051
2052 Address = (PVOID)PAGE_ROUND_DOWN(Address);
2053
2054 /*
2055 * Get the segment and section.
2056 */
2057 Context.Segment = MemoryArea->Data.SectionData.Segment;
2058 Context.Section = MemoryArea->Data.SectionData.Section;
2059
2060 Context.Offset = (ULONG)((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
2061 + MemoryArea->Data.SectionData.ViewOffset);
2062 FileOffset = Context.Offset + Context.Segment->FileOffset;
2063
2064 IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
2065
2066 FileObject = Context.Section->FileObject;
2067 DirectMapped = FALSE;
2068 #ifndef NEWCC
2069 if (FileObject != NULL &&
2070 !(Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
2071 {
2072 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
2073
2074 /*
2075 * If the file system is letting us go directly to the cache and the
2076 * memory area was mapped at an offset in the file which is page aligned
2077 * then note this is a direct mapped page.
2078 */
2079 if ((FileOffset % PAGE_SIZE) == 0 &&
2080 (Context.Offset + PAGE_SIZE <= Context.Segment->RawLength || !IsImageSection))
2081 {
2082 DirectMapped = TRUE;
2083 }
2084 }
2085 #endif
2086
2087
2088 /*
2089 * This should never happen since mappings of physical memory are never
2090 * placed in the rmap lists.
2091 */
2092 if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
2093 {
2094 DPRINT1("Trying to page out from physical memory section address 0x%X "
2095 "process %d\n", Address,
2096 Process ? Process->UniqueProcessId : 0);
2097 KeBugCheck(MEMORY_MANAGEMENT);
2098 }
2099
2100 /*
2101 * Get the section segment entry and the physical address.
2102 */
2103 Entry = MmGetPageEntrySectionSegment(Context.Segment, Context.Offset);
2104 if (!MmIsPagePresent(Process, Address))
2105 {
2106 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2107 Process ? Process->UniqueProcessId : 0, Address);
2108 KeBugCheck(MEMORY_MANAGEMENT);
2109 }
2110 Page = MmGetPfnForProcess(Process, Address);
2111 SwapEntry = MmGetSavedSwapEntryPage(Page);
2112
2113 /*
2114 * Prepare the context structure for the rmap delete call.
2115 */
2116 Context.WasDirty = FALSE;
2117 if (Context.Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
2118 IS_SWAP_FROM_SSE(Entry) ||
2119 PFN_FROM_SSE(Entry) != Page)
2120 {
2121 Context.Private = TRUE;
2122 }
2123 else
2124 {
2125 Context.Private = FALSE;
2126 }
2127
2128 /*
2129 * Take an additional reference to the page or the cache segment.
2130 */
2131 if (DirectMapped && !Context.Private)
2132 {
2133 if(!MiIsPageFromCache(MemoryArea, Context.Offset))
2134 {
2135 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2136 KeBugCheck(MEMORY_MANAGEMENT);
2137 }
2138 }
2139 else
2140 {
2141 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
2142 MmReferencePage(Page);
2143 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
2144 }
2145
2146 MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping);
2147
2148 /*
2149 * If this wasn't a private page then we should have reduced the entry to
2150 * zero by deleting all the rmaps.
2151 */
2152 if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0)
2153 {
2154 if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
2155 !(Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
2156 {
2157 KeBugCheck(MEMORY_MANAGEMENT);
2158 }
2159 }
2160
2161 /*
2162 * If the page wasn't dirty then we can just free it as for a readonly page.
2163 * Since we unmapped all the mappings above we know it will not suddenly
2164 * become dirty.
2165 * If the page is from a pagefile section and has no swap entry,
2166 * we can't free the page at this point.
2167 */
2168 SwapEntry = MmGetSavedSwapEntryPage(Page);
2169 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT)
2170 {
2171 if (Context.Private)
2172 {
2173 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
2174 Context.WasDirty ? "dirty" : "clean", Address);
2175 KeBugCheck(MEMORY_MANAGEMENT);
2176 }
2177 if (!Context.WasDirty && SwapEntry != 0)
2178 {
2179 MmSetSavedSwapEntryPage(Page, 0);
2180 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2181 MmReleasePageMemoryConsumer(MC_USER, Page);
2182 PageOp->Status = STATUS_SUCCESS;
2183 MmspCompleteAndReleasePageOp(PageOp);
2184 return(STATUS_SUCCESS);
2185 }
2186 }
2187 else if (Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED)
2188 {
2189 if (Context.Private)
2190 {
2191 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2192 Context.WasDirty ? "dirty" : "clean", Address);
2193 KeBugCheck(MEMORY_MANAGEMENT);
2194 }
2195 if (!Context.WasDirty || SwapEntry != 0)
2196 {
2197 MmSetSavedSwapEntryPage(Page, 0);
2198 if (SwapEntry != 0)
2199 {
2200 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2201 }
2202 MmReleasePageMemoryConsumer(MC_USER, Page);
2203 PageOp->Status = STATUS_SUCCESS;
2204 MmspCompleteAndReleasePageOp(PageOp);
2205 return(STATUS_SUCCESS);
2206 }
2207 }
2208 else if (!Context.Private && DirectMapped)
2209 {
2210 if (SwapEntry != 0)
2211 {
2212 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2213 Address);
2214 KeBugCheck(MEMORY_MANAGEMENT);
2215 }
2216 #ifndef NEWCC
2217 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
2218 #else
2219 Status = STATUS_SUCCESS;
2220 #endif
2221 if (!NT_SUCCESS(Status))
2222 {
2223 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
2224 KeBugCheck(MEMORY_MANAGEMENT);
2225 }
2226 PageOp->Status = STATUS_SUCCESS;
2227 MmspCompleteAndReleasePageOp(PageOp);
2228 return(STATUS_SUCCESS);
2229 }
2230 else if (!Context.WasDirty && !DirectMapped && !Context.Private)
2231 {
2232 if (SwapEntry != 0)
2233 {
2234 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2235 Address);
2236 KeBugCheck(MEMORY_MANAGEMENT);
2237 }
2238 MmReleasePageMemoryConsumer(MC_USER, Page);
2239 PageOp->Status = STATUS_SUCCESS;
2240 MmspCompleteAndReleasePageOp(PageOp);
2241 return(STATUS_SUCCESS);
2242 }
2243 else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
2244 {
2245 MmSetSavedSwapEntryPage(Page, 0);
2246 MmLockAddressSpace(AddressSpace);
2247 Status = MmCreatePageFileMapping(Process,
2248 Address,
2249 SwapEntry);
2250 MmUnlockAddressSpace(AddressSpace);
2251 if (!NT_SUCCESS(Status))
2252 {
2253 KeBugCheck(MEMORY_MANAGEMENT);
2254 }
2255 MmReleasePageMemoryConsumer(MC_USER, Page);
2256 PageOp->Status = STATUS_SUCCESS;
2257 MmspCompleteAndReleasePageOp(PageOp);
2258 return(STATUS_SUCCESS);
2259 }
2260
2261 /*
2262 * If necessary, allocate an entry in the paging file for this page
2263 */
2264 if (SwapEntry == 0)
2265 {
2266 SwapEntry = MmAllocSwapPage();
2267 if (SwapEntry == 0)
2268 {
2269 MmShowOutOfSpaceMessagePagingFile();
2270 MmLockAddressSpace(AddressSpace);
2271 /*
2272 * For private pages restore the old mappings.
2273 */
2274 if (Context.Private)
2275 {
2276 Status = MmCreateVirtualMapping(Process,
2277 Address,
2278 MemoryArea->Protect,
2279 &Page,
2280 1);
2281 MmSetDirtyPage(Process, Address);
2282 MmInsertRmap(Page,
2283 Process,
2284 Address);
2285 }
2286 else
2287 {
2288 /*
2289 * For non-private pages if the page wasn't direct mapped then
2290 * set it back into the section segment entry so we don't loose
2291 * our copy. Otherwise it will be handled by the cache manager.
2292 */
2293 Status = MmCreateVirtualMapping(Process,
2294 Address,
2295 MemoryArea->Protect,
2296 &Page,
2297 1);
2298 MmSetDirtyPage(Process, Address);
2299 MmInsertRmap(Page,
2300 Process,
2301 Address);
2302 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
2303 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
2304 }
2305 MmUnlockAddressSpace(AddressSpace);
2306 PageOp->Status = STATUS_UNSUCCESSFUL;
2307 MmspCompleteAndReleasePageOp(PageOp);
2308 return(STATUS_PAGEFILE_QUOTA);
2309 }
2310 }
2311
2312 /*
2313 * Write the page to the pagefile
2314 */
2315 Status = MmWriteToSwapPage(SwapEntry, Page);
2316 if (!NT_SUCCESS(Status))
2317 {
2318 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2319 Status);
2320 /*
2321 * As above: undo our actions.
2322 * FIXME: Also free the swap page.
2323 */
2324 MmLockAddressSpace(AddressSpace);
2325 if (Context.Private)
2326 {
2327 Status = MmCreateVirtualMapping(Process,
2328 Address,
2329 MemoryArea->Protect,
2330 &Page,
2331 1);
2332 MmSetDirtyPage(Process, Address);
2333 MmInsertRmap(Page,
2334 Process,
2335 Address);
2336 }
2337 else
2338 {
2339 Status = MmCreateVirtualMapping(Process,
2340 Address,
2341 MemoryArea->Protect,
2342 &Page,
2343 1);
2344 MmSetDirtyPage(Process, Address);
2345 MmInsertRmap(Page,
2346 Process,
2347 Address);
2348 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
2349 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
2350 }
2351 MmUnlockAddressSpace(AddressSpace);
2352 PageOp->Status = STATUS_UNSUCCESSFUL;
2353 MmspCompleteAndReleasePageOp(PageOp);
2354 return(STATUS_UNSUCCESSFUL);
2355 }
2356
2357 /*
2358 * Otherwise we have succeeded.
2359 */
2360 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
2361 MmSetSavedSwapEntryPage(Page, 0);
2362 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
2363 Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED)
2364 {
2365 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2366 }
2367 else
2368 {
2369 MmReleasePageMemoryConsumer(MC_USER, Page);
2370 }
2371
2372 if (Context.Private)
2373 {
2374 MmLockAddressSpace(AddressSpace);
2375 Status = MmCreatePageFileMapping(Process,
2376 Address,
2377 SwapEntry);
2378 MmUnlockAddressSpace(AddressSpace);
2379 if (!NT_SUCCESS(Status))
2380 {
2381 KeBugCheck(MEMORY_MANAGEMENT);
2382 }
2383 }
2384 else
2385 {
2386 Entry = MAKE_SWAP_SSE(SwapEntry);
2387 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
2388 }
2389
2390 PageOp->Status = STATUS_SUCCESS;
2391 MmspCompleteAndReleasePageOp(PageOp);
2392 return(STATUS_SUCCESS);
2393 }
2394
2395 NTSTATUS
2396 NTAPI
2397 MmWritePageSectionView(PMMSUPPORT AddressSpace,
2398 PMEMORY_AREA MemoryArea,
2399 PVOID Address,
2400 PMM_PAGEOP PageOp)
2401 {
2402 ULONG_PTR Offset;
2403 PROS_SECTION_OBJECT Section;
2404 PMM_SECTION_SEGMENT Segment;
2405 PFN_NUMBER Page;
2406 SWAPENTRY SwapEntry;
2407 ULONG Entry;
2408 BOOLEAN Private;
2409 NTSTATUS Status;
2410 PFILE_OBJECT FileObject;
2411 PBCB Bcb = NULL;
2412 BOOLEAN DirectMapped;
2413 BOOLEAN IsImageSection;
2414 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
2415
2416 Address = (PVOID)PAGE_ROUND_DOWN(Address);
2417
2418 Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
2419 + MemoryArea->Data.SectionData.ViewOffset;
2420
2421 /*
2422 * Get the segment and section.
2423 */
2424 Segment = MemoryArea->Data.SectionData.Segment;
2425 Section = MemoryArea->Data.SectionData.Section;
2426 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
2427
2428 FileObject = Section->FileObject;
2429 DirectMapped = FALSE;
2430 if (FileObject != NULL &&
2431 !(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
2432 {
2433 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
2434
2435 /*
2436 * If the file system is letting us go directly to the cache and the
2437 * memory area was mapped at an offset in the file which is page aligned
2438 * then note this is a direct mapped page.
2439 */
2440 if (((Offset + Segment->FileOffset) % PAGE_SIZE) == 0 &&
2441 (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
2442 {
2443 DirectMapped = TRUE;
2444 }
2445 }
2446
2447 /*
2448 * This should never happen since mappings of physical memory are never
2449 * placed in the rmap lists.
2450 */
2451 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
2452 {
2453 DPRINT1("Trying to write back page from physical memory mapped at %X "
2454 "process %d\n", Address,
2455 Process ? Process->UniqueProcessId : 0);
2456 KeBugCheck(MEMORY_MANAGEMENT);
2457 }
2458
2459 /*
2460 * Get the section segment entry and the physical address.
2461 */
2462 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
2463 if (!MmIsPagePresent(Process, Address))
2464 {
2465 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2466 Process ? Process->UniqueProcessId : 0, Address);
2467 KeBugCheck(MEMORY_MANAGEMENT);
2468 }
2469 Page = MmGetPfnForProcess(Process, Address);
2470 SwapEntry = MmGetSavedSwapEntryPage(Page);
2471
2472 /*
2473 * Check for a private (COWed) page.
2474 */
2475 if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
2476 IS_SWAP_FROM_SSE(Entry) ||
2477 PFN_FROM_SSE(Entry) != Page)
2478 {
2479 Private = TRUE;
2480 }
2481 else
2482 {
2483 Private = FALSE;
2484 }
2485
2486 /*
2487 * Speculatively set all mappings of the page to clean.
2488 */
2489 MmSetCleanAllRmaps(Page);
2490
2491 /*
2492 * If this page was direct mapped from the cache then the cache manager
2493 * will take care of writing it back to disk.
2494 */
2495 if (DirectMapped && !Private)
2496 {
2497 ASSERT(SwapEntry == 0);
2498 #ifndef NEWCC
2499 CcRosMarkDirtyCacheSegment(Bcb, (ULONG)Offset + Segment->FileOffset);
2500 #endif
2501 PageOp->Status = STATUS_SUCCESS;
2502 MmspCompleteAndReleasePageOp(PageOp);
2503 return(STATUS_SUCCESS);
2504 }
2505
2506 /*
2507 * If necessary, allocate an entry in the paging file for this page
2508 */
2509 if (SwapEntry == 0)
2510 {
2511 SwapEntry = MmAllocSwapPage();
2512 if (SwapEntry == 0)
2513 {
2514 MmSetDirtyAllRmaps(Page);
2515 PageOp->Status = STATUS_UNSUCCESSFUL;
2516 MmspCompleteAndReleasePageOp(PageOp);
2517 return(STATUS_PAGEFILE_QUOTA);
2518 }
2519 MmSetSavedSwapEntryPage(Page, SwapEntry);
2520 }
2521
2522 /*
2523 * Write the page to the pagefile
2524 */
2525 Status = MmWriteToSwapPage(SwapEntry, Page);
2526 if (!NT_SUCCESS(Status))
2527 {
2528 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2529 Status);
2530 MmSetDirtyAllRmaps(Page);
2531 PageOp->Status = STATUS_UNSUCCESSFUL;
2532 MmspCompleteAndReleasePageOp(PageOp);
2533 return(STATUS_UNSUCCESSFUL);
2534 }
2535
2536 /*
2537 * Otherwise we have succeeded.
2538 */
2539 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
2540 PageOp->Status = STATUS_SUCCESS;
2541 MmspCompleteAndReleasePageOp(PageOp);
2542 return(STATUS_SUCCESS);
2543 }
2544
2545 static VOID
2546 MmAlterViewAttributes(PMMSUPPORT AddressSpace,
2547 PVOID BaseAddress,
2548 SIZE_T RegionSize,
2549 ULONG OldType,
2550 ULONG OldProtect,
2551 ULONG NewType,
2552 ULONG NewProtect)
2553 {
2554 PMEMORY_AREA MemoryArea;
2555 PMM_SECTION_SEGMENT Segment;
2556 BOOLEAN DoCOW = FALSE;
2557 ULONG i;
2558 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
2559
2560 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
2561 Segment = MemoryArea->Data.SectionData.Segment;
2562
2563 if ((Segment->WriteCopy) &&
2564 (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
2565 {
2566 DoCOW = TRUE;
2567 }
2568
2569 if (OldProtect != NewProtect)
2570 {
2571 for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
2572 {
2573 PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
2574 ULONG Protect = NewProtect;
2575
2576 /*
2577 * If we doing COW for this segment then check if the page is
2578 * already private.
2579 */
2580 if (DoCOW && MmIsPagePresent(Process, Address))
2581 {
2582 ULONG_PTR Offset;
2583 ULONG Entry;
2584 PFN_NUMBER Page;
2585
2586 Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
2587 + MemoryArea->Data.SectionData.ViewOffset;
2588 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
2589 Page = MmGetPfnForProcess(Process, Address);
2590
2591 Protect = PAGE_READONLY;
2592 if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
2593 IS_SWAP_FROM_SSE(Entry) ||
2594 PFN_FROM_SSE(Entry) != Page)
2595 {
2596 Protect = NewProtect;
2597 }
2598 }
2599
2600 if (MmIsPagePresent(Process, Address))
2601 {
2602 MmSetPageProtect(Process, Address,
2603 Protect);
2604 }
2605 }
2606 }
2607 }
2608
2609 NTSTATUS
2610 NTAPI
2611 MmProtectSectionView(PMMSUPPORT AddressSpace,
2612 PMEMORY_AREA MemoryArea,
2613 PVOID BaseAddress,
2614 SIZE_T Length,
2615 ULONG Protect,
2616 PULONG OldProtect)
2617 {
2618 PMM_REGION Region;
2619 NTSTATUS Status;
2620 ULONG_PTR MaxLength;
2621
2622 MaxLength = (ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)BaseAddress;
2623 if (Length > MaxLength)
2624 Length = (ULONG)MaxLength;
2625
2626 Region = MmFindRegion(MemoryArea->StartingAddress,
2627 &MemoryArea->Data.SectionData.RegionListHead,
2628 BaseAddress, NULL);
2629 if ((MemoryArea->Flags & SEC_NO_CHANGE) &&
2630 Region->Protect != Protect)
2631 {
2632 return STATUS_INVALID_PAGE_PROTECTION;
2633 }
2634
2635 *OldProtect = Region->Protect;
2636 Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress,
2637 &MemoryArea->Data.SectionData.RegionListHead,
2638 BaseAddress, Length, Region->Type, Protect,
2639 MmAlterViewAttributes);
2640
2641 return(Status);
2642 }
2643
2644 NTSTATUS NTAPI
2645 MmQuerySectionView(PMEMORY_AREA MemoryArea,
2646 PVOID Address,
2647 PMEMORY_BASIC_INFORMATION Info,
2648 PSIZE_T ResultLength)
2649 {
2650 PMM_REGION Region;
2651 PVOID RegionBaseAddress;
2652 PROS_SECTION_OBJECT Section;
2653 PMM_SECTION_SEGMENT Segment;
2654
2655 Region = MmFindRegion((PVOID)MemoryArea->StartingAddress,
2656 &MemoryArea->Data.SectionData.RegionListHead,
2657 Address, &RegionBaseAddress);
2658 if (Region == NULL)
2659 {
2660 return STATUS_UNSUCCESSFUL;
2661 }
2662
2663 Section = MemoryArea->Data.SectionData.Section;
2664 if (Section->AllocationAttributes & SEC_IMAGE)
2665 {
2666 Segment = MemoryArea->Data.SectionData.Segment;
2667 Info->AllocationBase = (PUCHAR)MemoryArea->StartingAddress - Segment->VirtualAddress;
2668 Info->Type = MEM_IMAGE;
2669 }
2670 else
2671 {
2672 Info->AllocationBase = MemoryArea->StartingAddress;
2673 Info->Type = MEM_MAPPED;
2674 }
2675 Info->BaseAddress = RegionBaseAddress;
2676 Info->AllocationProtect = MemoryArea->Protect;
2677 Info->RegionSize = Region->Length;
2678 Info->State = MEM_COMMIT;
2679 Info->Protect = Region->Protect;
2680
2681 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
2682 return(STATUS_SUCCESS);
2683 }
2684
2685 VOID
2686 NTAPI
2687 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
2688 {
2689 ULONG Length;
2690 ULONG Offset;
2691 ULONG Entry;
2692 SWAPENTRY SavedSwapEntry;
2693 PFN_NUMBER Page;
2694
2695 Page = 0;
2696
2697 Length = PAGE_ROUND_UP(Segment->Length);
2698 for (Offset = 0; Offset < Length; Offset += PAGE_SIZE)
2699 {
2700 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
2701 if (Entry)
2702 {
2703 if (IS_SWAP_FROM_SSE(Entry))
2704 {
2705 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
2706 }
2707 else
2708 {
2709 Page = PFN_FROM_SSE(Entry);
2710 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
2711 if (SavedSwapEntry != 0)
2712 {
2713 MmSetSavedSwapEntryPage(Page, 0);
2714 MmFreeSwapPage(SavedSwapEntry);
2715 }
2716 MmReleasePageMemoryConsumer(MC_USER, Page);
2717 }
2718 MmSetPageEntrySectionSegment(Segment, Offset, 0);
2719 }
2720 }
2721 }
2722
2723 VOID NTAPI
2724 MmpDeleteSection(PVOID ObjectBody)
2725 {
2726 PROS_SECTION_OBJECT Section = (PROS_SECTION_OBJECT)ObjectBody;
2727
2728 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
2729 if (Section->AllocationAttributes & SEC_IMAGE)
2730 {
2731 ULONG i;
2732 ULONG NrSegments;
2733 ULONG RefCount;
2734 PMM_SECTION_SEGMENT SectionSegments;
2735
2736 /*
2737 * NOTE: Section->ImageSection can be NULL for short time
2738 * during the section creating. If we fail for some reason
2739 * until the image section is properly initialized we shouldn't
2740 * process further here.
2741 */
2742 if (Section->ImageSection == NULL)
2743 return;
2744
2745 SectionSegments = Section->ImageSection->Segments;
2746 NrSegments = Section->ImageSection->NrSegments;
2747
2748 for (i = 0; i < NrSegments; i++)
2749 {
2750 if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
2751 {
2752 MmLockSectionSegment(&SectionSegments[i]);
2753 }
2754 RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount);
2755 if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
2756 {
2757 if (RefCount == 0)
2758 {
2759 MmpFreePageFileSegment(&SectionSegments[i]);
2760 }
2761 MmUnlockSectionSegment(&SectionSegments[i]);
2762 }
2763 }
2764 }
2765 else
2766 {
2767 /*
2768 * NOTE: Section->Segment can be NULL for short time
2769 * during the section creating.
2770 */
2771 if (Section->Segment == NULL)
2772 return;
2773
2774 if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
2775 {
2776 MmpFreePageFileSegment(Section->Segment);
2777 MmFreePageTablesSectionSegment(Section->Segment);
2778 ExFreePool(Section->Segment);
2779 Section->Segment = NULL;
2780 }
2781 else
2782 {
2783 (void)InterlockedDecrementUL(&Section->Segment->ReferenceCount);
2784 }
2785 }
2786 if (Section->FileObject != NULL)
2787 {
2788 #ifndef NEWCC
2789 CcRosDereferenceCache(Section->FileObject);
2790 #endif
2791 ObDereferenceObject(Section->FileObject);
2792 Section->FileObject = NULL;
2793 }
2794 }
2795
2796 VOID NTAPI
2797 MmpCloseSection(IN PEPROCESS Process OPTIONAL,
2798 IN PVOID Object,
2799 IN ACCESS_MASK GrantedAccess,
2800 IN ULONG ProcessHandleCount,
2801 IN ULONG SystemHandleCount)
2802 {
2803 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2804 Object, ProcessHandleCount);
2805 }
2806
2807 NTSTATUS
2808 INIT_FUNCTION
2809 NTAPI
2810 MmCreatePhysicalMemorySection(VOID)
2811 {
2812 PROS_SECTION_OBJECT PhysSection;
2813 NTSTATUS Status;
2814 OBJECT_ATTRIBUTES Obj;
2815 UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
2816 LARGE_INTEGER SectionSize;
2817 HANDLE Handle;
2818
2819 /*
2820 * Create the section mapping physical memory
2821 */
2822 SectionSize.QuadPart = 0xFFFFFFFF;
2823 InitializeObjectAttributes(&Obj,
2824 &Name,
2825 OBJ_PERMANENT,
2826 NULL,
2827 NULL);
2828 Status = MmCreateSection((PVOID)&PhysSection,
2829 SECTION_ALL_ACCESS,
2830 &Obj,
2831 &SectionSize,
2832 PAGE_EXECUTE_READWRITE,
2833 0,
2834 NULL,
2835 NULL);
2836 if (!NT_SUCCESS(Status))
2837 {
2838 DPRINT1("Failed to create PhysicalMemory section\n");
2839 KeBugCheck(MEMORY_MANAGEMENT);
2840 }
2841 Status = ObInsertObject(PhysSection,
2842 NULL,
2843 SECTION_ALL_ACCESS,
2844 0,
2845 NULL,
2846 &Handle);
2847 if (!NT_SUCCESS(Status))
2848 {
2849 ObDereferenceObject(PhysSection);
2850 }
2851 ObCloseHandle(Handle, KernelMode);
2852 PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
2853 PhysSection->Segment->Flags &= ~MM_PAGEFILE_SEGMENT;
2854
2855 return(STATUS_SUCCESS);
2856 }
2857
2858 NTSTATUS
2859 INIT_FUNCTION
2860 NTAPI
2861 MmInitSectionImplementation(VOID)
2862 {
2863 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
2864 UNICODE_STRING Name;
2865
2866 DPRINT("Creating Section Object Type\n");
2867
2868 /* Initialize the Section object type */
2869 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
2870 RtlInitUnicodeString(&Name, L"Section");
2871 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
2872 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(ROS_SECTION_OBJECT);
2873 ObjectTypeInitializer.PoolType = PagedPool;
2874 ObjectTypeInitializer.UseDefaultObject = TRUE;
2875 ObjectTypeInitializer.GenericMapping = MmpSectionMapping;
2876 ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection;
2877 ObjectTypeInitializer.CloseProcedure = MmpCloseSection;
2878 ObjectTypeInitializer.ValidAccessMask = SECTION_ALL_ACCESS;
2879 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &MmSectionObjectType);
2880
2881 MmCreatePhysicalMemorySection();
2882
2883 return(STATUS_SUCCESS);
2884 }
2885
2886 NTSTATUS
2887 NTAPI
2888 MmCreatePageFileSection(PROS_SECTION_OBJECT *SectionObject,
2889 ACCESS_MASK DesiredAccess,
2890 POBJECT_ATTRIBUTES ObjectAttributes,
2891 PLARGE_INTEGER UMaximumSize,
2892 ULONG SectionPageProtection,
2893 ULONG AllocationAttributes)
2894 /*
2895 * Create a section which is backed by the pagefile
2896 */
2897 {
2898 LARGE_INTEGER MaximumSize;
2899 PROS_SECTION_OBJECT Section;
2900 PMM_SECTION_SEGMENT Segment;
2901 NTSTATUS Status;
2902
2903 if (UMaximumSize == NULL)
2904 {
2905 return(STATUS_UNSUCCESSFUL);
2906 }
2907 MaximumSize = *UMaximumSize;
2908
2909 /*
2910 * Create the section
2911 */
2912 Status = ObCreateObject(ExGetPreviousMode(),
2913 MmSectionObjectType,
2914 ObjectAttributes,
2915 ExGetPreviousMode(),
2916 NULL,
2917 sizeof(ROS_SECTION_OBJECT),
2918 0,
2919 0,
2920 (PVOID*)(PVOID)&Section);
2921 if (!NT_SUCCESS(Status))
2922 {
2923 return(Status);
2924 }
2925
2926 /*
2927 * Initialize it
2928 */
2929 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
2930 Section->SectionPageProtection = SectionPageProtection;
2931 Section->AllocationAttributes = AllocationAttributes;
2932 Section->MaximumSize = MaximumSize;
2933 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2934 TAG_MM_SECTION_SEGMENT);
2935 if (Segment == NULL)
2936 {
2937 ObDereferenceObject(Section);
2938 return(STATUS_NO_MEMORY);
2939 }
2940 Section->Segment = Segment;
2941 Segment->ReferenceCount = 1;
2942 ExInitializeFastMutex(&Segment->Lock);
2943 Segment->FileOffset = 0;
2944 Segment->Protection = SectionPageProtection;
2945 Segment->RawLength = MaximumSize.u.LowPart;
2946 Segment->Length = PAGE_ROUND_UP(MaximumSize.u.LowPart);
2947 Segment->Flags = MM_PAGEFILE_SEGMENT;
2948 Segment->WriteCopy = FALSE;
2949 RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
2950 Segment->VirtualAddress = 0;
2951 Segment->Characteristics = 0;
2952 *SectionObject = Section;
2953 return(STATUS_SUCCESS);
2954 }
2955
2956
2957 NTSTATUS
2958 NTAPI
2959 MmCreateDataFileSection(PROS_SECTION_OBJECT *SectionObject,
2960 ACCESS_MASK DesiredAccess,
2961 POBJECT_ATTRIBUTES ObjectAttributes,
2962 PLARGE_INTEGER UMaximumSize,
2963 ULONG SectionPageProtection,
2964 ULONG AllocationAttributes,
2965 HANDLE FileHandle)
2966 /*
2967 * Create a section backed by a data file
2968 */
2969 {
2970 PROS_SECTION_OBJECT Section;
2971 NTSTATUS Status;
2972 LARGE_INTEGER MaximumSize;
2973 PFILE_OBJECT FileObject;
2974 PMM_SECTION_SEGMENT Segment;
2975 ULONG FileAccess;
2976 IO_STATUS_BLOCK Iosb;
2977 LARGE_INTEGER Offset;
2978 CHAR Buffer;
2979 FILE_STANDARD_INFORMATION FileInfo;
2980 ULONG Length;
2981
2982 /*
2983 * Create the section
2984 */
2985 Status = ObCreateObject(ExGetPreviousMode(),
2986 MmSectionObjectType,
2987 ObjectAttributes,
2988 ExGetPreviousMode(),
2989 NULL,
2990 sizeof(ROS_SECTION_OBJECT),
2991 0,
2992 0,
2993 (PVOID*)(PVOID)&Section);
2994 if (!NT_SUCCESS(Status))
2995 {
2996 return(Status);
2997 }
2998 /*
2999 * Initialize it
3000 */
3001 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
3002 Section->SectionPageProtection = SectionPageProtection;
3003 Section->AllocationAttributes = AllocationAttributes;
3004
3005 /*
3006 * Check file access required
3007 */
3008 if (SectionPageProtection & PAGE_READWRITE ||
3009 SectionPageProtection & PAGE_EXECUTE_READWRITE)
3010 {
3011 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
3012 }
3013 else
3014 {
3015 FileAccess = FILE_READ_DATA;
3016 }
3017
3018 /*
3019 * Reference the file handle
3020 */
3021 Status = ObReferenceObjectByHandle(FileHandle,
3022 FileAccess,
3023 IoFileObjectType,
3024 ExGetPreviousMode(),
3025 (PVOID*)(PVOID)&FileObject,
3026 NULL);
3027 if (!NT_SUCCESS(Status))
3028 {
3029 ObDereferenceObject(Section);
3030 return(Status);
3031 }
3032
3033 /*
3034 * FIXME: This is propably not entirely correct. We can't look into
3035 * the standard FCB header because it might not be initialized yet
3036 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
3037 * standard file information is filled on first request).
3038 */
3039 Status = IoQueryFileInformation(FileObject,
3040 FileStandardInformation,
3041 sizeof(FILE_STANDARD_INFORMATION),
3042 &FileInfo,
3043 &Length);
3044 Iosb.Information = Length;
3045 if (!NT_SUCCESS(Status))
3046 {
3047 ObDereferenceObject(Section);
3048 ObDereferenceObject(FileObject);
3049 return Status;
3050 }
3051
3052 /*
3053 * FIXME: Revise this once a locking order for file size changes is
3054 * decided
3055 */
3056 if ((UMaximumSize != NULL) && (UMaximumSize->QuadPart != 0))
3057 {
3058 MaximumSize = *UMaximumSize;
3059 }
3060 else
3061 {
3062 MaximumSize = FileInfo.EndOfFile;
3063 /* Mapping zero-sized files isn't allowed. */
3064 if (MaximumSize.QuadPart == 0)
3065 {
3066 ObDereferenceObject(Section);
3067 ObDereferenceObject(FileObject);
3068 return STATUS_FILE_INVALID;
3069 }
3070 }
3071
3072 if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart)
3073 {
3074 Status = IoSetInformation(FileObject,
3075 FileAllocationInformation,
3076 sizeof(LARGE_INTEGER),
3077 &MaximumSize);
3078 if (!NT_SUCCESS(Status))
3079 {
3080 ObDereferenceObject(Section);
3081 ObDereferenceObject(FileObject);
3082 return(STATUS_SECTION_NOT_EXTENDED);
3083 }
3084 }
3085
3086 if (FileObject->SectionObjectPointer == NULL ||
3087 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
3088 {
3089 /*
3090 * Read a bit so caching is initiated for the file object.
3091 * This is only needed because MiReadPage currently cannot
3092 * handle non-cached streams.
3093 */
3094 Offset.QuadPart = 0;
3095 Status = ZwReadFile(FileHandle,
3096 NULL,
3097 NULL,
3098 NULL,
3099 &Iosb,
3100 &Buffer,
3101 sizeof (Buffer),
3102 &Offset,
3103 0);
3104 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
3105 {
3106 ObDereferenceObject(Section);
3107 ObDereferenceObject(FileObject);
3108 return(Status);
3109 }
3110 if (FileObject->SectionObjectPointer == NULL ||
3111 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
3112 {
3113 /* FIXME: handle this situation */
3114 ObDereferenceObject(Section);
3115 ObDereferenceObject(FileObject);
3116 return STATUS_INVALID_PARAMETER;
3117 }
3118 }
3119
3120 /*
3121 * Lock the file
3122 */
3123 Status = MmspWaitForFileLock(FileObject);
3124 if (Status != STATUS_SUCCESS)
3125 {
3126 ObDereferenceObject(Section);
3127 ObDereferenceObject(FileObject);
3128 return(Status);
3129 }
3130
3131 /*
3132 * If this file hasn't been mapped as a data file before then allocate a
3133 * section segment to describe the data file mapping
3134 */
3135 if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
3136 {
3137 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
3138 TAG_MM_SECTION_SEGMENT);
3139 if (Segment == NULL)
3140 {
3141 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3142 ObDereferenceObject(Section);
3143 ObDereferenceObject(FileObject);
3144 return(STATUS_NO_MEMORY);
3145 }
3146 Section->Segment = Segment;
3147 Segment->ReferenceCount = 1;
3148 ExInitializeFastMutex(&Segment->Lock);
3149 /*
3150 * Set the lock before assigning the segment to the file object
3151 */
3152 ExAcquireFastMutex(&Segment->Lock);
3153 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
3154
3155 Segment->FileOffset = 0;
3156 Segment->Protection = SectionPageProtection;
3157 Segment->Flags = MM_DATAFILE_SEGMENT;
3158 Segment->Characteristics = 0;
3159 Segment->WriteCopy = FALSE;
3160 if (AllocationAttributes & SEC_RESERVE)
3161 {
3162 Segment->Length = Segment->RawLength = 0;
3163 }
3164 else
3165 {
3166 Segment->RawLength = MaximumSize.u.LowPart;
3167 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
3168 }
3169 Segment->VirtualAddress = 0;
3170 RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
3171 }
3172 else
3173 {
3174 /*
3175 * If the file is already mapped as a data file then we may need
3176 * to extend it
3177 */
3178 Segment =
3179 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
3180 DataSectionObject;
3181 Section->Segment = Segment;
3182 (void)InterlockedIncrementUL(&Segment->ReferenceCount);
3183 MmLockSectionSegment(Segment);
3184
3185 if (MaximumSize.u.LowPart > Segment->RawLength &&
3186 !(AllocationAttributes & SEC_RESERVE))
3187 {
3188 Segment->RawLength = MaximumSize.u.LowPart;
3189 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
3190 }
3191 }
3192 MmUnlockSectionSegment(Segment);
3193 Section->FileObject = FileObject;
3194 Section->MaximumSize = MaximumSize;
3195 #ifndef NEWCC
3196 CcRosReferenceCache(FileObject);
3197 #endif
3198 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3199 *SectionObject = Section;
3200 return(STATUS_SUCCESS);
3201 }
3202
3203 /*
3204 TODO: not that great (declaring loaders statically, having to declare all of
3205 them, having to keep them extern, etc.), will fix in the future
3206 */
3207 extern NTSTATUS NTAPI PeFmtCreateSection
3208 (
3209 IN CONST VOID * FileHeader,
3210 IN SIZE_T FileHeaderSize,
3211 IN PVOID File,
3212 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3213 OUT PULONG Flags,
3214 IN PEXEFMT_CB_READ_FILE ReadFileCb,
3215 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3216 );
3217
3218 extern NTSTATUS NTAPI ElfFmtCreateSection
3219 (
3220 IN CONST VOID * FileHeader,
3221 IN SIZE_T FileHeaderSize,
3222 IN PVOID File,
3223 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3224 OUT PULONG Flags,
3225 IN PEXEFMT_CB_READ_FILE ReadFileCb,
3226 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3227 );
3228
3229 /* TODO: this is a standard DDK/PSDK macro */
3230 #ifndef RTL_NUMBER_OF
3231 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3232 #endif
3233
3234 static PEXEFMT_LOADER ExeFmtpLoaders[] =
3235 {
3236 PeFmtCreateSection,
3237 #ifdef __ELF
3238 ElfFmtCreateSection
3239 #endif
3240 };
3241
3242 static
3243 PMM_SECTION_SEGMENT
3244 NTAPI
3245 ExeFmtpAllocateSegments(IN ULONG NrSegments)
3246 {
3247 SIZE_T SizeOfSegments;
3248 PMM_SECTION_SEGMENT Segments;
3249
3250 /* TODO: check for integer overflow */
3251 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments;
3252
3253 Segments = ExAllocatePoolWithTag(NonPagedPool,
3254 SizeOfSegments,
3255 TAG_MM_SECTION_SEGMENT);
3256
3257 if(Segments)
3258 RtlZeroMemory(Segments, SizeOfSegments);
3259
3260 return Segments;
3261 }
3262
3263 static
3264 NTSTATUS
3265 NTAPI
3266 ExeFmtpReadFile(IN PVOID File,
3267 IN PLARGE_INTEGER Offset,
3268 IN ULONG Length,
3269 OUT PVOID * Data,
3270 OUT PVOID * AllocBase,
3271 OUT PULONG ReadSize)
3272 {
3273 NTSTATUS Status;
3274 LARGE_INTEGER FileOffset;
3275 ULONG AdjustOffset;
3276 ULONG OffsetAdjustment;
3277 ULONG BufferSize;
3278 ULONG UsedSize;
3279 PVOID Buffer;
3280
3281 ASSERT_IRQL_LESS(DISPATCH_LEVEL);
3282
3283 if(Length == 0)
3284 {
3285 KeBugCheck(MEMORY_MANAGEMENT);
3286 }
3287
3288 FileOffset = *Offset;
3289
3290 /* Negative/special offset: it cannot be used in this context */
3291 if(FileOffset.u.HighPart < 0)
3292 {
3293 KeBugCheck(MEMORY_MANAGEMENT);
3294 }
3295
3296 AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart);
3297 OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset;
3298 FileOffset.u.LowPart = AdjustOffset;
3299
3300 BufferSize = Length + OffsetAdjustment;
3301 BufferSize = PAGE_ROUND_UP(BufferSize);
3302
3303 /*
3304 * It's ok to use paged pool, because this is a temporary buffer only used in
3305 * the loading of executables. The assumption is that MmCreateSection is
3306 * always called at low IRQLs and that these buffers don't survive a brief
3307 * initialization phase
3308 */
3309 Buffer = ExAllocatePoolWithTag(PagedPool,
3310 BufferSize,
3311 'rXmM');
3312 if (!Buffer)
3313 {
3314 KeBugCheck(MEMORY_MANAGEMENT);
3315 }
3316
3317 UsedSize = 0;
3318
3319 #if 0
3320 Status = MmspPageRead(File,
3321 Buffer,
3322 BufferSize,
3323 &FileOffset,
3324 &UsedSize);
3325 #else
3326 /*
3327 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
3328 * nothing will work. But using ZwReadFile is wrong, and using its side effects
3329 * to initialize internal state is even worse. Our cache manager is in need of
3330 * professional help
3331 */
3332 {
3333 IO_STATUS_BLOCK Iosb;
3334
3335 Status = ZwReadFile(File,
3336 NULL,
3337 NULL,
3338 NULL,
3339 &Iosb,
3340 Buffer,
3341 BufferSize,
3342 &FileOffset,
3343 NULL);
3344
3345 if(NT_SUCCESS(Status))
3346 {
3347 UsedSize = (ULONG)Iosb.Information;
3348 }
3349 }
3350 #endif
3351
3352 if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
3353 {
3354 Status = STATUS_IN_PAGE_ERROR;
3355 ASSERT(!NT_SUCCESS(Status));
3356 }
3357
3358 if(NT_SUCCESS(Status))
3359 {
3360 *Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment);
3361 *AllocBase = Buffer;
3362 *ReadSize = UsedSize - OffsetAdjustment;
3363 }
3364 else
3365 {
3366 ExFreePoolWithTag(Buffer, 'rXmM');
3367 }
3368
3369 return Status;
3370 }
3371
3372 #ifdef NASSERT
3373 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3374 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3375 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3376 #else
3377 static
3378 VOID
3379 NTAPI
3380 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3381 {
3382 ULONG i;
3383
3384 for( i = 1; i < ImageSectionObject->NrSegments; ++ i )
3385 {
3386 ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
3387 ImageSectionObject->Segments[i - 1].VirtualAddress);
3388 }
3389 }
3390
3391 static
3392 VOID
3393 NTAPI
3394 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3395 {
3396 ULONG i;
3397
3398 MmspAssertSegmentsSorted(ImageSectionObject);
3399
3400 for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3401 {
3402 ASSERT(ImageSectionObject->Segments[i].Length > 0);
3403
3404 if(i > 0)
3405 {
3406 ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
3407 (ImageSectionObject->Segments[i - 1].VirtualAddress +
3408 ImageSectionObject->Segments[i - 1].Length));
3409 }
3410 }
3411 }
3412
3413 static
3414 VOID
3415 NTAPI
3416 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3417 {
3418 ULONG i;
3419
3420 for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3421 {
3422 ASSERT((ImageSectionObject->Segments[i].VirtualAddress % PAGE_SIZE) == 0);
3423 ASSERT((ImageSectionObject->Segments[i].Length % PAGE_SIZE) == 0);
3424 }
3425 }
3426 #endif
3427
3428 static
3429 int
3430 __cdecl
3431 MmspCompareSegments(const void * x,
3432 const void * y)
3433 {
3434 const MM_SECTION_SEGMENT *Segment1 = (const MM_SECTION_SEGMENT *)x;
3435 const MM_SECTION_SEGMENT *Segment2 = (const MM_SECTION_SEGMENT *)y;
3436
3437 return
3438 (Segment1->VirtualAddress - Segment2->VirtualAddress) >>
3439 ((sizeof(ULONG_PTR) - sizeof(int)) * 8);
3440 }
3441
3442 /*
3443 * Ensures an image section's segments are sorted in memory
3444 */
3445 static
3446 VOID
3447 NTAPI
3448 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3449 IN ULONG Flags)
3450 {
3451 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED)
3452 {
3453 MmspAssertSegmentsSorted(ImageSectionObject);
3454 }
3455 else
3456 {
3457 qsort(ImageSectionObject->Segments,
3458 ImageSectionObject->NrSegments,
3459 sizeof(ImageSectionObject->Segments[0]),
3460 MmspCompareSegments);
3461 }
3462 }
3463
3464
3465 /*
3466 * Ensures an image section's segments don't overlap in memory and don't have
3467 * gaps and don't have a null size. We let them map to overlapping file regions,
3468 * though - that's not necessarily an error
3469 */
3470 static
3471 BOOLEAN
3472 NTAPI
3473 MmspCheckSegmentBounds
3474 (
3475 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3476 IN ULONG Flags
3477 )
3478 {
3479 ULONG i;
3480
3481 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP)
3482 {
3483 MmspAssertSegmentsNoOverlap(ImageSectionObject);
3484 return TRUE;
3485 }
3486
3487 ASSERT(ImageSectionObject->NrSegments >= 1);
3488
3489 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3490 {
3491 if(ImageSectionObject->Segments[i].Length == 0)
3492 {
3493 return FALSE;
3494 }
3495
3496 if(i > 0)
3497 {
3498 /*
3499 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3500 * page could be OK (Windows seems to be OK with them), and larger gaps
3501 * could lead to image sections spanning several discontiguous regions
3502 * (NtMapViewOfSection could then refuse to map them, and they could
3503 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3504 */
3505 if ((ImageSectionObject->Segments[i - 1].VirtualAddress +
3506 ImageSectionObject->Segments[i - 1].Length) !=
3507 ImageSectionObject->Segments[i].VirtualAddress)
3508 {
3509 return FALSE;
3510 }
3511 }
3512 }
3513
3514 return TRUE;
3515 }
3516
3517 /*
3518 * Merges and pads an image section's segments until they all are page-aligned
3519 * and have a size that is a multiple of the page size
3520 */
3521 static
3522 BOOLEAN
3523 NTAPI
3524 MmspPageAlignSegments
3525 (
3526 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3527 IN ULONG Flags
3528 )
3529 {
3530 ULONG i;
3531 ULONG LastSegment;
3532 PMM_SECTION_SEGMENT EffectiveSegment;
3533
3534 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED)
3535 {
3536 MmspAssertSegmentsPageAligned(ImageSectionObject);
3537 return TRUE;
3538 }
3539
3540 LastSegment = 0;
3541 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
3542
3543 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3544 {
3545 /*
3546 * The first segment requires special handling
3547 */
3548 if (i == 0)
3549 {
3550 ULONG_PTR VirtualAddress;
3551 ULONG_PTR VirtualOffset;
3552
3553 VirtualAddress = EffectiveSegment->VirtualAddress;
3554
3555 /* Round down the virtual address to the nearest page */
3556 EffectiveSegment->VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
3557
3558 /* Round up the virtual size to the nearest page */
3559 EffectiveSegment->Length = (ULONG)(PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length) -
3560 EffectiveSegment->VirtualAddress);
3561
3562 /* Adjust the raw address and size */
3563 VirtualOffset = VirtualAddress - EffectiveSegment->VirtualAddress;
3564
3565 if (EffectiveSegment->FileOffset < (LONG_PTR)VirtualOffset)
3566 {
3567 return FALSE;
3568 }
3569
3570 /*
3571 * Garbage in, garbage out: unaligned base addresses make the file
3572 * offset point in curious and odd places, but that's what we were
3573 * asked for
3574 */
3575 EffectiveSegment->FileOffset -= (ULONG)VirtualOffset;
3576 EffectiveSegment->RawLength += (ULONG)VirtualOffset;
3577 }
3578 else
3579 {
3580 PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
3581 ULONG_PTR EndOfEffectiveSegment;
3582
3583 EndOfEffectiveSegment = EffectiveSegment->VirtualAddress + EffectiveSegment->Length;
3584 ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
3585
3586 /*
3587 * The current segment begins exactly where the current effective
3588 * segment ended, therefore beginning a new effective segment
3589 */
3590 if (EndOfEffectiveSegment == Segment->VirtualAddress)
3591 {
3592 LastSegment ++;
3593 ASSERT(LastSegment <= i);
3594 ASSERT(LastSegment < ImageSectionObject->NrSegments);
3595
3596 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
3597
3598 if (LastSegment != i)
3599 {
3600 /*
3601 * Copy the current segment. If necessary, the effective segment
3602 * will be expanded later
3603 */
3604 *EffectiveSegment = *Segment;
3605 }
3606
3607 /*
3608 * Page-align the virtual size. We know for sure the virtual address
3609 * already is
3610 */
3611 ASSERT((EffectiveSegment->VirtualAddress % PAGE_SIZE) == 0);
3612 EffectiveSegment->Length = PAGE_ROUND_UP(EffectiveSegment->Length);
3613 }
3614 /*
3615 * The current segment is still part of the current effective segment:
3616 * extend the effective segment to reflect this
3617 */
3618 else if (EndOfEffectiveSegment > Segment->VirtualAddress)
3619 {
3620 static const ULONG FlagsToProtection[16] =
3621 {
3622 PAGE_NOACCESS,
3623 PAGE_READONLY,
3624 PAGE_READWRITE,
3625 PAGE_READWRITE,
3626 PAGE_EXECUTE_READ,
3627 PAGE_EXECUTE_READ,
3628 PAGE_EXECUTE_READWRITE,
3629 PAGE_EXECUTE_READWRITE,
3630 PAGE_WRITECOPY,
3631 PAGE_WRITECOPY,
3632 PAGE_WRITECOPY,
3633 PAGE_WRITECOPY,
3634 PAGE_EXECUTE_WRITECOPY,
3635 PAGE_EXECUTE_WRITECOPY,
3636 PAGE_EXECUTE_WRITECOPY,
3637 PAGE_EXECUTE_WRITECOPY
3638 };
3639
3640 unsigned ProtectionFlags;
3641
3642 /*
3643 * Extend the file size
3644 */
3645
3646 /* Unaligned segments must be contiguous within the file */
3647 if (Segment->FileOffset != (EffectiveSegment->FileOffset +
3648 EffectiveSegment->RawLength))
3649 {
3650 return FALSE;
3651 }
3652
3653 EffectiveSegment->RawLength += Segment->RawLength;
3654
3655 /*
3656 * Extend the virtual size
3657 */
3658 ASSERT(PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) >= EndOfEffectiveSegment);
3659
3660 EffectiveSegment->Length = (ULONG)(PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) -
3661 EffectiveSegment->VirtualAddress);
3662
3663 /*
3664 * Merge the protection
3665 */
3666 EffectiveSegment->Protection |= Segment->Protection;
3667
3668 /* Clean up redundance */
3669 ProtectionFlags = 0;
3670
3671 if(EffectiveSegment->Protection & PAGE_IS_READABLE)
3672 ProtectionFlags |= 1 << 0;
3673
3674 if(EffectiveSegment->Protection & PAGE_IS_WRITABLE)
3675 ProtectionFlags |= 1 << 1;
3676
3677 if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE)
3678 ProtectionFlags |= 1 << 2;
3679
3680 if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3681 ProtectionFlags |= 1 << 3;
3682
3683 ASSERT(ProtectionFlags < 16);
3684 EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags];
3685
3686 /* If a segment was required to be shared and cannot, fail */
3687 if(!(Segment->Protection & PAGE_IS_WRITECOPY) &&
3688 EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3689 {
3690 return FALSE;
3691 }
3692 }
3693 /*
3694 * We assume no holes between segments at this point
3695 */
3696 else
3697 {
3698 KeBugCheck(MEMORY_MANAGEMENT);
3699 }
3700 }
3701 }
3702 ImageSectionObject->NrSegments = LastSegment + 1;
3703
3704 return TRUE;
3705 }
3706
3707 NTSTATUS
3708 ExeFmtpCreateImageSection(HANDLE FileHandle,
3709 PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3710 {
3711 LARGE_INTEGER Offset;
3712 PVOID FileHeader;
3713 PVOID FileHeaderBuffer;
3714 ULONG FileHeaderSize;
3715 ULONG Flags;
3716 ULONG OldNrSegments;
3717 NTSTATUS Status;
3718 ULONG i;
3719
3720 /*
3721 * Read the beginning of the file (2 pages). Should be enough to contain
3722 * all (or most) of the headers
3723 */
3724 Offset.QuadPart = 0;
3725
3726 /* FIXME: use FileObject instead of FileHandle */
3727 Status = ExeFmtpReadFile (FileHandle,
3728 &Offset,
3729 PAGE_SIZE * 2,
3730 &FileHeader,
3731 &FileHeaderBuffer,
3732 &FileHeaderSize);
3733
3734 if (!NT_SUCCESS(Status))
3735 return Status;
3736
3737 if (FileHeaderSize == 0)
3738 {
3739 ExFreePool(FileHeaderBuffer);
3740 return STATUS_UNSUCCESSFUL;
3741 }
3742
3743 /*
3744 * Look for a loader that can handle this executable
3745 */
3746 for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i)
3747 {
3748 RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject));
3749 Flags = 0;
3750
3751 /* FIXME: use FileObject instead of FileHandle */
3752 Status = ExeFmtpLoaders[i](FileHeader,
3753 FileHeaderSize,
3754 FileHandle,
3755 ImageSectionObject,
3756 &Flags,
3757 ExeFmtpReadFile,
3758 ExeFmtpAllocateSegments);
3759
3760 if (!NT_SUCCESS(Status))
3761 {
3762 if (ImageSectionObject->Segments)
3763 {
3764 ExFreePool(ImageSectionObject->Segments);
3765 ImageSectionObject->Segments = NULL;
3766 }
3767 }
3768
3769 if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3770 break;
3771 }
3772
3773 ExFreePoolWithTag(FileHeaderBuffer, 'rXmM');
3774
3775 /*
3776 * No loader handled the format
3777 */
3778 if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3779 {
3780 Status = STATUS_INVALID_IMAGE_NOT_MZ;
3781 ASSERT(!NT_SUCCESS(Status));
3782 }
3783
3784 if (!NT_SUCCESS(Status))
3785 return Status;
3786
3787 ASSERT(ImageSectionObject->Segments != NULL);
3788
3789 /*
3790 * Some defaults
3791 */
3792 /* FIXME? are these values platform-dependent? */
3793 if(ImageSectionObject->StackReserve == 0)
3794 ImageSectionObject->StackReserve = 0x40000;
3795
3796 if(ImageSectionObject->StackCommit == 0)
3797 ImageSectionObject->StackCommit = 0x1000;
3798
3799 if(ImageSectionObject->ImageBase == 0)
3800 {
3801 if(ImageSectionObject->ImageCharacteristics & IMAGE_FILE_DLL)
3802 ImageSectionObject->ImageBase = 0x10000000;
3803 else
3804 ImageSectionObject->ImageBase = 0x00400000;
3805 }
3806
3807 /*
3808 * And now the fun part: fixing the segments
3809 */
3810
3811 /* Sort them by virtual address */
3812 MmspSortSegments(ImageSectionObject, Flags);
3813
3814 /* Ensure they don't overlap in memory */
3815 if (!MmspCheckSegmentBounds(ImageSectionObject, Flags))
3816 return STATUS_INVALID_IMAGE_FORMAT;
3817
3818 /* Ensure they are aligned */
3819 OldNrSegments = ImageSectionObject->NrSegments;
3820
3821 if (!MmspPageAlignSegments(ImageSectionObject, Flags))
3822 return STATUS_INVALID_IMAGE_FORMAT;
3823
3824 /* Trim them if the alignment phase merged some of them */
3825 if (ImageSectionObject->NrSegments < OldNrSegments)
3826 {
3827 PMM_SECTION_SEGMENT Segments;
3828 SIZE_T SizeOfSegments;
3829
3830 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments;
3831
3832 Segments = ExAllocatePoolWithTag(PagedPool,
3833 SizeOfSegments,
3834 TAG_MM_SECTION_SEGMENT);
3835
3836 if (Segments == NULL)
3837 return STATUS_INSUFFICIENT_RESOURCES;
3838
3839 RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments);
3840 ExFreePool(ImageSectionObject->Segments);
3841 ImageSectionObject->Segments = Segments;
3842 }
3843
3844 /* And finish their initialization */
3845 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3846 {
3847 ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock);
3848 ImageSectionObject->Segments[i].ReferenceCount = 1;
3849
3850 RtlZeroMemory(&ImageSectionObject->Segments[i].PageDirectory,
3851 sizeof(ImageSectionObject->Segments[i].PageDirectory));
3852 }
3853
3854 ASSERT(NT_SUCCESS(Status));
3855 return Status;
3856 }
3857
3858 NTSTATUS
3859 MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
3860 ACCESS_MASK DesiredAccess,
3861 POBJECT_ATTRIBUTES ObjectAttributes,
3862 PLARGE_INTEGER UMaximumSize,
3863 ULONG SectionPageProtection,
3864 ULONG AllocationAttributes,
3865 HANDLE FileHandle)
3866 {
3867 PROS_SECTION_OBJECT Section;
3868 NTSTATUS Status;
3869 PFILE_OBJECT FileObject;
3870 PMM_SECTION_SEGMENT SectionSegments;
3871 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3872 ULONG i;
3873 ULONG FileAccess = 0;
3874
3875 /*
3876 * Check file access required
3877 */
3878 if (SectionPageProtection & PAGE_READWRITE ||
3879 SectionPageProtection & PAGE_EXECUTE_READWRITE)
3880 {
3881 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
3882 }
3883 else
3884 {
3885 FileAccess = FILE_READ_DATA;
3886 }
3887
3888 /*
3889 * Reference the file handle
3890 */
3891 Status = ObReferenceObjectByHandle(FileHandle,
3892 FileAccess,
3893 IoFileObjectType,
3894 ExGetPreviousMode(),
3895 (PVOID*)(PVOID)&FileObject,
3896 NULL);
3897
3898 if (!NT_SUCCESS(Status))
3899 {
3900 return Status;
3901 }
3902
3903 /*
3904 * Create the section
3905 */
3906 Status = ObCreateObject (ExGetPreviousMode(),
3907 MmSectionObjectType,
3908 ObjectAttributes,
3909 ExGetPreviousMode(),
3910 NULL,
3911 sizeof(ROS_SECTION_OBJECT),
3912 0,
3913 0,
3914 (PVOID*)(PVOID)&Section);
3915 if (!NT_SUCCESS(Status))
3916 {
3917 ObDereferenceObject(FileObject);
3918 return(Status);
3919 }
3920
3921 /*
3922 * Initialize it
3923 */
3924 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
3925 Section->SectionPageProtection = SectionPageProtection;
3926 Section->AllocationAttributes = AllocationAttributes;
3927
3928 #ifndef NEWCC
3929 /*
3930 * Initialized caching for this file object if previously caching
3931 * was initialized for the same on disk file
3932 */
3933 Status = CcTryToInitializeFileCache(FileObject);
3934 #else
3935 Status = STATUS_SUCCESS;
3936 #endif
3937
3938 if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
3939 {
3940 NTSTATUS StatusExeFmt;
3941
3942 ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
3943 if (ImageSectionObject == NULL)
3944 {
3945 ObDereferenceObject(FileObject);
3946 ObDereferenceObject(Section);
3947 return(STATUS_NO_MEMORY);
3948 }
3949
3950 RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
3951
3952 StatusExeFmt = ExeFmtpCreateImageSection(FileHandle, ImageSectionObject);
3953
3954 if (!NT_SUCCESS(StatusExeFmt))
3955 {
3956 if(ImageSectionObject->Segments != NULL)
3957 ExFreePool(ImageSectionObject->Segments);
3958
3959 ExFreePool(ImageSectionObject);
3960 ObDereferenceObject(Section);
3961 ObDereferenceObject(FileObject);
3962 return(StatusExeFmt);
3963 }
3964
3965 Section->ImageSection = ImageSectionObject;
3966 ASSERT(ImageSectionObject->Segments);
3967
3968 /*
3969 * Lock the file
3970 */
3971 Status = MmspWaitForFileLock(FileObject);
3972 if (!NT_SUCCESS(Status))
3973 {
3974 ExFreePool(ImageSectionObject->Segments);
3975 ExFreePool(ImageSectionObject);
3976 ObDereferenceObject(Section);
3977 ObDereferenceObject(FileObject);
3978 return(Status);
3979 }
3980
3981 if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject,
3982 ImageSectionObject, NULL))
3983 {
3984 /*
3985 * An other thread has initialized the same image in the background
3986 */
3987 ExFreePool(ImageSectionObject->Segments);
3988 ExFreePool(ImageSectionObject);
3989 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3990 Section->ImageSection = ImageSectionObject;
3991 SectionSegments = ImageSectionObject->Segments;
3992
3993 for (i = 0; i < ImageSectionObject->NrSegments; i++)
3994 {
3995 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3996 }
3997 }
3998
3999 Status = StatusExeFmt;
4000 }
4001 else
4002 {
4003 /*
4004 * Lock the file
4005 */
4006 Status = MmspWaitForFileLock(FileObject);
4007 if (Status != STATUS_SUCCESS)
4008 {
4009 ObDereferenceObject(Section);
4010 ObDereferenceObject(FileObject);
4011 return(Status);
4012 }
4013
4014 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
4015 Section->ImageSection = ImageSectionObject;
4016 SectionSegments = ImageSectionObject->Segments;
4017
4018 /*
4019 * Otherwise just reference all the section segments
4020 */
4021 for (i = 0; i < ImageSectionObject->NrSegments; i++)
4022 {
4023 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
4024 }
4025
4026 Status = STATUS_SUCCESS;
4027 }
4028 Section->FileObject = FileObject;
4029 #ifndef NEWCC
4030 CcRosReferenceCache(FileObject);
4031 #endif
4032 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
4033 *SectionObject = Section;
4034 return(Status);
4035 }
4036
4037
4038
4039 static NTSTATUS
4040 MmMapViewOfSegment(PMMSUPPORT AddressSpace,
4041 PROS_SECTION_OBJECT Section,
4042 PMM_SECTION_SEGMENT Segment,
4043 PVOID* BaseAddress,
4044 SIZE_T ViewSize,
4045 ULONG Protect,
4046 ULONG ViewOffset,
4047 ULONG AllocationType)
4048 {
4049 PMEMORY_AREA MArea;
4050 NTSTATUS Status;
4051 PHYSICAL_ADDRESS BoundaryAddressMultiple;
4052
4053 BoundaryAddressMultiple.QuadPart = 0;
4054
4055 Status = MmCreateMemoryArea(AddressSpace,
4056 MEMORY_AREA_SECTION_VIEW,
4057 BaseAddress,
4058 ViewSize,
4059 Protect,
4060 &MArea,
4061 FALSE,
4062 AllocationType,
4063 BoundaryAddressMultiple);
4064 if (!NT_SUCCESS(Status))
4065 {
4066 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
4067 (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
4068 return(Status);
4069 }
4070
4071 ObReferenceObject((PVOID)Section);
4072
4073 MArea->Data.SectionData.Segment = Segment;
4074 MArea->Data.SectionData.Section = Section;
4075 MArea->Data.SectionData.ViewOffset = ViewOffset;
4076 MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
4077 ViewSize, 0, Protect);
4078
4079 return(STATUS_SUCCESS);
4080 }
4081
4082
4083
4084 static VOID
4085 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
4086 PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
4087 {
4088 ULONG Entry;
4089 PFILE_OBJECT FileObject;
4090 PBCB Bcb;
4091 ULONG Offset;
4092 SWAPENTRY SavedSwapEntry;
4093 PMM_PAGEOP PageOp;
4094 NTSTATUS Status;
4095 PROS_SECTION_OBJECT Section;
4096 PMM_SECTION_SEGMENT Segment;
4097 PMMSUPPORT AddressSpace;
4098 PEPROCESS Process;
4099
4100 AddressSpace = (PMMSUPPORT)Context;
4101 Process = MmGetAddressSpaceOwner(AddressSpace);
4102
4103 Address = (PVOID)PAGE_ROUND_DOWN(Address);
4104
4105 Offset = (ULONG)(((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress) +
4106 MemoryArea->Data.SectionData.ViewOffset);
4107
4108 Section = MemoryArea->Data.SectionData.Section;
4109 Segment = MemoryArea->Data.SectionData.Segment;
4110
4111 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
4112
4113 while (PageOp)
4114 {
4115 MmUnlockSectionSegment(Segment);
4116 MmUnlockAddressSpace(AddressSpace);
4117
4118 Status = MmspWaitForPageOpCompletionEvent(PageOp);
4119 if (Status != STATUS_SUCCESS)
4120 {
4121 DPRINT1("Failed to wait for page op, status = %x\n", Status);
4122 KeBugCheck(MEMORY_MANAGEMENT);
4123 }
4124
4125 MmLockAddressSpace(AddressSpace);
4126 MmLockSectionSegment(Segment);
4127 MmspCompleteAndReleasePageOp(PageOp);
4128 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
4129 }
4130
4131 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
4132
4133 /*
4134 * For a dirty, datafile, non-private page mark it as dirty in the
4135 * cache manager.
4136 */
4137 if (Segment->Flags & MM_DATAFILE_SEGMENT)
4138 {
4139 if (Page == PFN_FROM_SSE(Entry) && Dirty)
4140 {
4141 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
4142 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
4143 #ifndef NEWCC
4144 CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
4145 #endif
4146 ASSERT(SwapEntry == 0);
4147 }
4148 }
4149
4150 if (SwapEntry != 0)
4151 {
4152 /*
4153 * Sanity check
4154 */
4155 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
4156 {
4157 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4158 KeBugCheck(MEMORY_MANAGEMENT);
4159 }
4160 MmFreeSwapPage(SwapEntry);
4161 }
4162 else if (Page != 0)
4163 {
4164 if (IS_SWAP_FROM_SSE(Entry) ||
4165 Page != PFN_FROM_SSE(Entry))
4166 {
4167 /*
4168 * Sanity check
4169 */
4170 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
4171 {
4172 DPRINT1("Found a private page in a pagefile section.\n");
4173 KeBugCheck(MEMORY_MANAGEMENT);
4174 }
4175 /*
4176 * Just dereference private pages
4177 */
4178 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
4179 if (SavedSwapEntry != 0)
4180 {
4181 MmFreeSwapPage(SavedSwapEntry);
4182 MmSetSavedSwapEntryPage(Page, 0);
4183 }
4184 MmDeleteRmap(Page, Process, Address);
4185 MmReleasePageMemoryConsumer(MC_USER, Page);
4186 }
4187 else
4188 {
4189 MmDeleteRmap(Page, Process, Address);
4190 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty, FALSE);
4191 }
4192 }
4193 }
4194
4195 static NTSTATUS
4196 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace,
4197 PVOID BaseAddress)
4198 {
4199 NTSTATUS Status;
4200 PMEMORY_AREA MemoryArea;
4201 PROS_SECTION_OBJECT Section;
4202 PMM_SECTION_SEGMENT Segment;
4203 PLIST_ENTRY CurrentEntry;
4204 PMM_REGION CurrentRegion;
4205 PLIST_ENTRY RegionListHead;
4206
4207 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4208 BaseAddress);
4209 if (MemoryArea == NULL)
4210 {
4211 return(STATUS_UNSUCCESSFUL);
4212 }
4213
4214 MemoryArea->DeleteInProgress = TRUE;
4215 Section = MemoryArea->Data.SectionData.Section;
4216 Segment = MemoryArea->Data.SectionData.Segment;
4217
4218 MmLockSectionSegment(Segment);
4219
4220 RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
4221 while (!IsListEmpty(RegionListHead))
4222 {
4223 CurrentEntry = RemoveHeadList(RegionListHead);
4224 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
4225 ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION);
4226 }
4227
4228 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
4229 {
4230 Status = MmFreeMemoryArea(AddressSpace,
4231 MemoryArea,
4232 NULL,
4233 NULL);
4234 }
4235 else
4236 {
4237 Status = MmFreeMemoryArea(AddressSpace,
4238 MemoryArea,
4239 MmFreeSectionPage,
4240 AddressSpace);
4241 }
4242 MmUnlockSectionSegment(Segment);
4243 ObDereferenceObject(Section);
4244 return(Status);
4245 }
4246
4247 /*
4248 * @implemented
4249 */
4250 NTSTATUS NTAPI
4251 MmUnmapViewOfSection(PEPROCESS Process,
4252 PVOID BaseAddress)
4253 {
4254 NTSTATUS Status;
4255 PMEMORY_AREA MemoryArea;
4256 PMMSUPPORT AddressSpace;
4257 PROS_SECTION_OBJECT Section;
4258 PMM_PAGEOP PageOp;
4259 ULONG_PTR Offset;
4260 PVOID ImageBaseAddress = 0;
4261
4262 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4263 Process, BaseAddress);
4264
4265 ASSERT(Process);
4266
4267 AddressSpace = &Process->Vm;
4268
4269 MmLockAddressSpace(AddressSpace);
4270 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4271 BaseAddress);
4272 if (MemoryArea == NULL ||
4273 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW ||
4274 MemoryArea->DeleteInProgress)
4275 {
4276 MmUnlockAddressSpace(AddressSpace);
4277 return STATUS_NOT_MAPPED_VIEW;
4278 }
4279
4280 MemoryArea->DeleteInProgress = TRUE;
4281
4282 while (MemoryArea->PageOpCount)
4283 {
4284 Offset = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress);
4285
4286 while (Offset)
4287 {
4288 Offset -= PAGE_SIZE;
4289 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL,
4290 MemoryArea->Data.SectionData.Segment,
4291 (ULONG)Offset + MemoryArea->Data.SectionData.ViewOffset);
4292 if (PageOp)
4293 {
4294 MmUnlockAddressSpace(AddressSpace);
4295 Status = MmspWaitForPageOpCompletionEvent(PageOp);
4296 if (Status != STATUS_SUCCESS)
4297 {
4298 DPRINT1("Failed to wait for page op, status = %x\n", Status);
4299 KeBugCheck(MEMORY_MANAGEMENT);
4300 }
4301 MmLockAddressSpace(AddressSpace);
4302 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4303 BaseAddress);
4304 if (MemoryArea == NULL ||
4305 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
4306 {
4307 MmUnlockAddressSpace(AddressSpace);
4308 return STATUS_NOT_MAPPED_VIEW;
4309 }
4310 break;
4311 }
4312 }
4313 }
4314
4315 Section = MemoryArea->Data.SectionData.Section;
4316
4317 if (Section->AllocationAttributes & SEC_IMAGE)
4318 {
4319 ULONG i;
4320 ULONG NrSegments;
4321 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4322 PMM_SECTION_SEGMENT SectionSegments;
4323 PMM_SECTION_SEGMENT Segment;
4324
4325 Segment = MemoryArea->Data.SectionData.Segment;
4326 ImageSectionObject = Section->ImageSection;
4327 SectionSegments = ImageSectionObject->Segments;
4328 NrSegments = ImageSectionObject->NrSegments;
4329
4330 /* Search for the current segment within the section segments
4331 * and calculate the image base address */
4332 for (i = 0; i < NrSegments; i++)
4333 {
4334 if (Segment == &SectionSegments[i])
4335 {
4336 ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress;
4337 break;
4338 }
4339 }
4340 if (i >= NrSegments)
4341 {
4342 KeBugCheck(MEMORY_MANAGEMENT);
4343 }
4344
4345 for (i = 0; i < NrSegments; i++)
4346 {
4347 PVOID SBaseAddress = (PVOID)
4348 ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
4349
4350 Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
4351 }
4352 }
4353 else
4354 {
4355 Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
4356 }
4357
4358 MmUnlockAddressSpace(AddressSpace);
4359
4360 /* Notify debugger */
4361 if (ImageBaseAddress) DbgkUnMapViewOfSection(ImageBaseAddress);
4362
4363 return(STATUS_SUCCESS);
4364 }
4365
4366
4367
4368
4369 /**
4370 * Queries the information of a section object.
4371 *
4372 * @param SectionHandle
4373 * Handle to the section object. It must be opened with SECTION_QUERY
4374 * access.
4375 * @param SectionInformationClass
4376 * Index to a certain information structure. Can be either
4377 * SectionBasicInformation or SectionImageInformation. The latter
4378 * is valid only for sections that were created with the SEC_IMAGE
4379 * flag.
4380 * @param SectionInformation
4381 * Caller supplies storage for resulting information.
4382 * @param Length
4383 * Size of the supplied storage.
4384 * @param ResultLength
4385 * Data written.
4386 *
4387 * @return Status.
4388 *
4389 * @implemented
4390 */
4391 NTSTATUS NTAPI
4392 NtQuerySection(IN HANDLE SectionHandle,
4393 IN SECTION_INFORMATION_CLASS SectionInformationClass,
4394 OUT PVOID SectionInformation,
4395 IN SIZE_T SectionInformationLength,
4396 OUT PSIZE_T ResultLength OPTIONAL)
4397 {
4398 PROS_SECTION_OBJECT Section;
4399 KPROCESSOR_MODE PreviousMode;
4400 NTSTATUS Status;
4401 PAGED_CODE();
4402
4403 PreviousMode = ExGetPreviousMode();
4404
4405 Status = DefaultQueryInfoBufferCheck(SectionInformationClass,
4406 ExSectionInfoClass,
4407 sizeof(ExSectionInfoClass) / sizeof(ExSectionInfoClass[0]),
4408 SectionInformation,
4409 (ULONG)SectionInformationLength,
4410 NULL,
4411 ResultLength,
4412 PreviousMode);
4413
4414 if(!NT_SUCCESS(Status))
4415 {
4416 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status);
4417 return Status;
4418 }
4419
4420 Status = ObReferenceObjectByHandle(SectionHandle,
4421 SECTION_QUERY,
4422 MmSectionObjectType,
4423 PreviousMode,
4424 (PVOID*)(PVOID)&Section,
4425 NULL);
4426 if (NT_SUCCESS(Status))
4427 {
4428 switch (SectionInformationClass)
4429 {
4430 case SectionBasicInformation:
4431 {
4432 PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
4433
4434 _SEH2_TRY
4435 {
4436 Sbi->Attributes = Section->AllocationAttributes;
4437 if (Section->AllocationAttributes & SEC_IMAGE)
4438 {
4439 Sbi->BaseAddress = 0;
4440 Sbi->Size.QuadPart = 0;
4441 }
4442 else
4443 {
4444 Sbi->BaseAddress = (PVOID)Section->Segment->VirtualAddress;
4445 Sbi->Size.QuadPart = Section->Segment->Length;
4446 }
4447
4448 if (ResultLength != NULL)
4449 {
4450 *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
4451 }
4452 Status = STATUS_SUCCESS;
4453 }
4454 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4455 {
4456 Status = _SEH2_GetExceptionCode();
4457 }
4458 _SEH2_END;
4459
4460 break;
4461 }
4462
4463 case SectionImageInformation:
4464 {
4465 PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
4466
4467 _SEH2_TRY
4468 {
4469 memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
4470 if (Section->AllocationAttributes & SEC_IMAGE)
4471 {
4472 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4473 ImageSectionObject = Section->ImageSection;
4474
4475 Sii->TransferAddress = (PVOID)ImageSectionObject->EntryPoint;
4476 Sii->MaximumStackSize = ImageSectionObject->StackReserve;
4477 Sii->CommittedStackSize = ImageSectionObject->StackCommit;
4478 Sii->SubSystemType = ImageSectionObject->Subsystem;
4479 Sii->SubSystemMinorVersion = ImageSectionObject->MinorSubsystemVersion;
4480 Sii->SubSystemMajorVersion = ImageSectionObject->MajorSubsystemVersion;
4481 Sii->ImageCharacteristics = ImageSectionObject->ImageCharacteristics;
4482 Sii->Machine = ImageSectionObject->Machine;
4483 Sii->ImageContainsCode = ImageSectionObject->Executable;
4484 }
4485
4486 if (ResultLength != NULL)
4487 {
4488 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
4489 }
4490 Status = STATUS_SUCCESS;
4491 }
4492 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4493 {
4494 Status = _SEH2_GetExceptionCode();
4495 }
4496 _SEH2_END;
4497
4498 break;
4499 }
4500 }
4501
4502 ObDereferenceObject(Section);
4503 }
4504
4505 return(Status);
4506 }
4507
4508 /**********************************************************************
4509 * NAME EXPORTED
4510 * MmMapViewOfSection
4511 *
4512 * DESCRIPTION
4513 * Maps a view of a section into the virtual address space of a
4514 * process.
4515 *
4516 * ARGUMENTS
4517 * Section
4518 * Pointer to the section object.
4519 *
4520 * ProcessHandle
4521 * Pointer to the process.
4522 *
4523 * BaseAddress
4524 * Desired base address (or NULL) on entry;
4525 * Actual base address of the view on exit.
4526 *
4527 * ZeroBits
4528 * Number of high order address bits that must be zero.
4529 *
4530 * CommitSize
4531 * Size in bytes of the initially committed section of
4532 * the view.
4533 *
4534 * SectionOffset
4535 * Offset in bytes from the beginning of the section
4536 * to the beginning of the view.
4537 *
4538 * ViewSize
4539 * Desired length of map (or zero to map all) on entry
4540 * Actual length mapped on exit.
4541 *
4542 * InheritDisposition
4543 * Specified how the view is to be shared with
4544 * child processes.
4545 *
4546 * AllocationType
4547 * Type of allocation for the pages.
4548 *
4549 * Protect
4550 * Protection for the committed region of the view.
4551 *
4552 * RETURN VALUE
4553 * Status.
4554 *
4555 * @implemented
4556 */
4557 NTSTATUS NTAPI
4558 MmMapViewOfSection(IN PVOID SectionObject,
4559 IN PEPROCESS Process,
4560 IN OUT PVOID *BaseAddress,
4561 IN ULONG_PTR ZeroBits,
4562 IN SIZE_T CommitSize,
4563 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
4564 IN OUT PSIZE_T ViewSize,
4565 IN SECTION_INHERIT InheritDisposition,
4566 IN ULONG AllocationType,
4567 IN ULONG Protect)
4568 {
4569 PROS_SECTION_OBJECT Section;
4570 PMMSUPPORT AddressSpace;
4571 ULONG ViewOffset;
4572 NTSTATUS Status = STATUS_SUCCESS;
4573 BOOLEAN NotAtBase = FALSE;
4574
4575 if ((ULONG_PTR)SectionObject & 1)
4576 {
4577 return MmMapViewOfArm3Section((PVOID)((ULONG_PTR)SectionObject & ~1),
4578 Process,
4579 BaseAddress,
4580 ZeroBits,
4581 CommitSize,
4582 SectionOffset,
4583 ViewSize,
4584 InheritDisposition,
4585 AllocationType,
4586 Protect);
4587 }
4588
4589 ASSERT(Process);
4590
4591 if (!Protect || Protect & ~PAGE_FLAGS_VALID_FOR_SECTION)
4592 {
4593 return STATUS_INVALID_PAGE_PROTECTION;
4594 }
4595
4596
4597 Section = (PROS_SECTION_OBJECT)SectionObject;
4598 AddressSpace = &Process->Vm;
4599
4600 AllocationType |= (Section->AllocationAttributes & SEC_NO_CHANGE);
4601
4602 MmLockAddressSpace(AddressSpace);
4603
4604 if (Section->AllocationAttributes & SEC_IMAGE)
4605 {
4606 ULONG i;
4607 ULONG NrSegments;
4608 ULONG_PTR ImageBase;
4609 SIZE_T ImageSize;
4610 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4611 PMM_SECTION_SEGMENT SectionSegments;
4612
4613 ImageSectionObject = Section->ImageSection;
4614 SectionSegments = ImageSectionObject->Segments;
4615 NrSegments = ImageSectionObject->NrSegments;
4616
4617
4618 ImageBase = (ULONG_PTR)*BaseAddress;
4619 if (ImageBase == 0)
4620 {
4621 ImageBase = ImageSectionObject->ImageBase;
4622 }
4623
4624 ImageSize = 0;
4625 for (i = 0; i < NrSegments; i++)
4626 {
4627 ULONG_PTR MaxExtent;
4628 MaxExtent = (ULONG_PTR)SectionSegments[i].VirtualAddress +
4629 SectionSegments[i].Length;
4630 ImageSize = max(ImageSize, MaxExtent);
4631 }
4632
4633 ImageSectionObject->ImageSize = (ULONG)ImageSize;
4634
4635 /* Check for an illegal base address */
4636 if ((ImageBase + ImageSize) > (ULONG_PTR)MmHighestUserAddress)
4637 {
4638 ImageBase = PAGE_ROUND_DOWN((ULONG_PTR)MmHighestUserAddress - ImageSize);
4639 }
4640
4641 /* Check there is enough space to map the section at that point. */
4642 if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
4643 PAGE_ROUND_UP(ImageSize)) != NULL)
4644 {
4645 /* Fail if the user requested a fixed base address. */
4646 if ((*BaseAddress) != NULL)
4647 {
4648 MmUnlockAddressSpace(AddressSpace);
4649 return(STATUS_UNSUCCESSFUL);
4650 }
4651 /* Otherwise find a gap to map the image. */
4652 ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE);
4653 if (ImageBase == 0)
4654 {
4655 MmUnlockAddressSpace(AddressSpace);
4656 return(STATUS_UNSUCCESSFUL);
4657 }
4658 /* Remember that we loaded image at a different base address */
4659 NotAtBase = TRUE;
4660 }
4661
4662 for (i = 0; i < NrSegments; i++)
4663 {
4664 PVOID SBaseAddress = (PVOID)
4665 ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
4666 MmLockSectionSegment(&SectionSegments[i]);
4667 Status = MmMapViewOfSegment(AddressSpace,
4668 Section,
4669 &SectionSegments[i],
4670 &SBaseAddress,
4671 SectionSegments[i].Length,
4672 SectionSegments[i].Protection,
4673 0,
4674 0);
4675 MmUnlockSectionSegment(&SectionSegments[i]);
4676 if (!NT_SUCCESS(Status))
4677 {
4678 MmUnlockAddressSpace(AddressSpace);
4679 return(Status);
4680 }
4681 }
4682
4683 *BaseAddress = (PVOID)ImageBase;
4684 *ViewSize = ImageSize;
4685 }
4686 else
4687 {
4688 /* check for write access */
4689 if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) &&
4690 !(Section->SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)))
4691 {
4692 MmUnlockAddressSpace(AddressSpace);
4693 return STATUS_SECTION_PROTECTION;
4694 }
4695 /* check for read access */
4696 if ((Protect & (PAGE_READONLY|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_WRITECOPY)) &&
4697 !(Section->SectionPageProtection & (PAGE_READONLY|PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4698 {
4699 MmUnlockAddressSpace(AddressSpace);
4700 return STATUS_SECTION_PROTECTION;
4701 }
4702 /* check for execute access */
4703 if ((Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)) &&
4704 !(Section->SectionPageProtection & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4705 {
4706 MmUnlockAddressSpace(AddressSpace);
4707 return STATUS_SECTION_PROTECTION;
4708 }
4709
4710 if (ViewSize == NULL)
4711 {
4712 /* Following this pointer would lead to us to the dark side */
4713 /* What to do? Bugcheck? Return status? Do the mambo? */
4714 KeBugCheck(MEMORY_MANAGEMENT);
4715 }
4716
4717 if (SectionOffset == NULL)
4718 {
4719 ViewOffset = 0;
4720 }
4721 else
4722 {
4723 ViewOffset = SectionOffset->u.LowPart;
4724 }
4725
4726 if ((ViewOffset % PAGE_SIZE) != 0)
4727 {
4728 MmUnlockAddressSpace(AddressSpace);
4729 return(STATUS_MAPPED_ALIGNMENT);
4730 }
4731
4732 if ((*ViewSize) == 0)
4733 {
4734 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4735 }
4736 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
4737 {
4738 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4739 }
4740
4741 *ViewSize = PAGE_ROUND_UP(*ViewSize);
4742
4743 MmLockSectionSegment(Section->Segment);
4744 Status = MmMapViewOfSegment(AddressSpace,
4745 Section,
4746 Section->Segment,
4747 BaseAddress,
4748 *ViewSize,
4749 Protect,
4750 ViewOffset,
4751 AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE));
4752 MmUnlockSectionSegment(Section->Segment);
4753 if (!NT_SUCCESS(Status))
4754 {
4755 MmUnlockAddressSpace(AddressSpace);
4756 return(Status);
4757 }
4758 }
4759
4760 MmUnlockAddressSpace(AddressSpace);
4761
4762 if (NotAtBase)
4763 Status = STATUS_IMAGE_NOT_AT_BASE;
4764 else
4765 Status = STATUS_SUCCESS;
4766
4767 return Status;
4768 }
4769
4770 /*
4771 * @unimplemented
4772 */
4773 BOOLEAN NTAPI
4774 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4775 IN PLARGE_INTEGER NewFileSize)
4776 {
4777 /* Check whether an ImageSectionObject exists */
4778 if (SectionObjectPointer->ImageSectionObject != NULL)
4779 {
4780 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4781 return FALSE;
4782 }
4783
4784 if (SectionObjectPointer->DataSectionObject != NULL)
4785 {
4786 PMM_SECTION_SEGMENT Segment;
4787
4788 Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->
4789 DataSectionObject;
4790
4791 if (Segment->ReferenceCount != 0)
4792 {
4793 /* Check size of file */
4794 if (SectionObjectPointer->SharedCacheMap)
4795 {
4796 PBCB Bcb = SectionObjectPointer->SharedCacheMap;
4797 if (NewFileSize->QuadPart <= Bcb->FileSize.QuadPart)
4798 {
4799 return FALSE;
4800 }
4801 }
4802 }
4803 else
4804 {
4805 /* Something must gone wrong
4806 * how can we have a Section but no
4807 * reference? */
4808 DPRINT("ERROR: DataSectionObject without reference!\n");
4809 }
4810 }
4811
4812 DPRINT("FIXME: didn't check for outstanding write probes\n");
4813
4814 return TRUE;
4815 }
4816
4817
4818
4819
4820 /*
4821 * @implemented
4822 */
4823 BOOLEAN NTAPI
4824 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4825 IN MMFLUSH_TYPE FlushType)
4826 {
4827 switch(FlushType)
4828 {
4829 case MmFlushForDelete:
4830 if (SectionObjectPointer->ImageSectionObject ||
4831 SectionObjectPointer->DataSectionObject)
4832 {
4833 return FALSE;
4834 }
4835 #ifndef NEWCC
4836 CcRosSetRemoveOnClose(SectionObjectPointer);
4837 #endif
4838 return TRUE;
4839 case MmFlushForWrite:
4840 break;
4841 }
4842 return FALSE;
4843 }
4844
4845 /*
4846 * @implemented
4847 */
4848 NTSTATUS NTAPI
4849 MmMapViewInSystemSpace (IN PVOID SectionObject,
4850 OUT PVOID * MappedBase,
4851 IN OUT PSIZE_T ViewSize)
4852 {
4853 PROS_SECTION_OBJECT Section;
4854 PMMSUPPORT AddressSpace;
4855 NTSTATUS Status;
4856 PAGED_CODE();
4857
4858 if ((ULONG_PTR)SectionObject & 1)
4859 {
4860 extern PVOID MmSession;
4861 return MiMapViewInSystemSpace((PVOID)((ULONG_PTR)SectionObject & ~1),
4862 &MmSession,
4863 MappedBase,
4864 ViewSize);
4865 }
4866
4867 DPRINT("MmMapViewInSystemSpace() called\n");
4868
4869 Section = (PROS_SECTION_OBJECT)SectionObject;
4870 AddressSpace = MmGetKernelAddressSpace();
4871
4872 MmLockAddressSpace(AddressSpace);
4873
4874
4875 if ((*ViewSize) == 0)
4876 {
4877 (*ViewSize) = Section->MaximumSize.u.LowPart;
4878 }
4879 else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
4880 {
4881 (*ViewSize) = Section->MaximumSize.u.LowPart;
4882 }
4883
4884 MmLockSectionSegment(Section->Segment);
4885
4886
4887 Status = MmMapViewOfSegment(AddressSpace,
4888 Section,
4889 Section->Segment,
4890 MappedBase,
4891 *ViewSize,
4892 PAGE_READWRITE,
4893 0,
4894 0);
4895
4896 MmUnlockSectionSegment(Section->Segment);
4897 MmUnlockAddressSpace(AddressSpace);
4898
4899 return Status;
4900 }
4901
4902 /*
4903 * @implemented
4904 */
4905 NTSTATUS NTAPI
4906 MmUnmapViewInSystemSpace (IN PVOID MappedBase)
4907 {
4908 PMMSUPPORT AddressSpace;
4909 NTSTATUS Status;
4910
4911 DPRINT("MmUnmapViewInSystemSpace() called\n");
4912
4913 AddressSpace = MmGetKernelAddressSpace();
4914
4915 Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
4916
4917 return Status;
4918 }
4919
4920
4921 /**********************************************************************
4922 * NAME EXPORTED
4923 * MmCreateSection@
4924 *
4925 * DESCRIPTION
4926 * Creates a section object.
4927 *
4928 * ARGUMENTS
4929 * SectionObject (OUT)
4930 * Caller supplied storage for the resulting pointer
4931 * to a SECTION_OBJECT instance;
4932 *
4933 * DesiredAccess
4934 * Specifies the desired access to the section can be a
4935 * combination of:
4936 * STANDARD_RIGHTS_REQUIRED |
4937 * SECTION_QUERY |
4938 * SECTION_MAP_WRITE |
4939 * SECTION_MAP_READ |
4940 * SECTION_MAP_EXECUTE
4941 *
4942 * ObjectAttributes [OPTIONAL]
4943 * Initialized attributes for the object can be used
4944 * to create a named section;
4945 *
4946 * MaximumSize
4947 * Maximizes the size of the memory section. Must be
4948 * non-NULL for a page-file backed section.
4949 * If value specified for a mapped file and the file is
4950 * not large enough, file will be extended.
4951 *
4952 * SectionPageProtection
4953 * Can be a combination of:
4954 * PAGE_READONLY |
4955 * PAGE_READWRITE |
4956 * PAGE_WRITEONLY |
4957 * PAGE_WRITECOPY
4958 *
4959 * AllocationAttributes
4960 * Can be a combination of:
4961 * SEC_IMAGE |
4962 * SEC_RESERVE
4963 *
4964 * FileHandle
4965 * Handle to a file to create a section mapped to a file
4966 * instead of a memory backed section;
4967 *
4968 * File
4969 * Unknown.
4970 *
4971 * RETURN VALUE
4972 * Status.
4973 *
4974 * @implemented
4975 */
4976 NTSTATUS NTAPI
4977 MmCreateSection (OUT PVOID * Section,
4978 IN ACCESS_MASK DesiredAccess,
4979 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
4980 IN PLARGE_INTEGER MaximumSize,
4981 IN ULONG SectionPageProtection,
4982 IN ULONG AllocationAttributes,
4983 IN HANDLE FileHandle OPTIONAL,
4984 IN PFILE_OBJECT File OPTIONAL)
4985 {
4986 ULONG Protection;
4987 PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section;
4988
4989 /* Check if an ARM3 section is being created instead */
4990 if (AllocationAttributes & 1)
4991 {
4992 DPRINT1("arm 3 path\n");
4993 return MmCreateArm3Section(Section,
4994 DesiredAccess,
4995 ObjectAttributes,
4996 MaximumSize,
4997 SectionPageProtection,
4998 AllocationAttributes &~ 1,
4999 FileHandle,
5000 File);
5001 }
5002
5003 /*
5004 * Check the protection
5005 */
5006 Protection = SectionPageProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
5007 if (Protection != PAGE_READONLY &&
5008 Protection != PAGE_READWRITE &&
5009 Protection != PAGE_WRITECOPY &&
5010 Protection != PAGE_EXECUTE &&
5011 Protection != PAGE_EXECUTE_READ &&
5012 Protection != PAGE_EXECUTE_READWRITE &&
5013 Protection != PAGE_EXECUTE_WRITECOPY)
5014 {
5015 return STATUS_INVALID_PAGE_PROTECTION;
5016 }
5017
5018 if (AllocationAttributes & SEC_IMAGE)
5019 {
5020 return(MmCreateImageSection(SectionObject,
5021 DesiredAccess,
5022 ObjectAttributes,
5023 MaximumSize,
5024 SectionPageProtection,
5025 AllocationAttributes,
5026 FileHandle));
5027 }
5028
5029 if (FileHandle != NULL)
5030 {
5031 return(MmCreateDataFileSection(SectionObject,
5032 DesiredAccess,
5033 ObjectAttributes,
5034 MaximumSize,
5035 SectionPageProtection,
5036 AllocationAttributes,
5037 FileHandle));
5038 }
5039
5040 return(MmCreatePageFileSection(SectionObject,
5041 DesiredAccess,
5042 ObjectAttributes,
5043 MaximumSize,
5044 SectionPageProtection,
5045 AllocationAttributes));
5046 }
5047
5048
5049
5050 /* EOF */