[NTOSKRNL/MM]
[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 already been set readwrite
1833 */
1834 if (MmGetPageProtect(Process, Address) & PAGE_READWRITE)
1835 {
1836 DPRINT("Address 0x%.8X\n", Address);
1837 return(STATUS_SUCCESS);
1838 }
1839
1840 /*
1841 * Find the offset of the page
1842 */
1843 PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
1844 Offset = (ULONG)((ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress
1845 + MemoryArea->Data.SectionData.ViewOffset);
1846
1847 Segment = MemoryArea->Data.SectionData.Segment;
1848 Section = MemoryArea->Data.SectionData.Section;
1849 Region = MmFindRegion(MemoryArea->StartingAddress,
1850 &MemoryArea->Data.SectionData.RegionListHead,
1851 Address, NULL);
1852 /*
1853 * Lock the segment
1854 */
1855 MmLockSectionSegment(Segment);
1856
1857 OldPage = MmGetPfnForProcess(Process, Address);
1858 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1859
1860 MmUnlockSectionSegment(Segment);
1861
1862 /*
1863 * Check if we are doing COW
1864 */
1865 if (!((Segment->WriteCopy) &&
1866 (Region->Protect == PAGE_READWRITE ||
1867 Region->Protect == PAGE_EXECUTE_READWRITE)))
1868 {
1869 DPRINT("Address 0x%.8X\n", Address);
1870 return(STATUS_ACCESS_VIOLATION);
1871 }
1872
1873 if (IS_SWAP_FROM_SSE(Entry) ||
1874 PFN_FROM_SSE(Entry) != OldPage)
1875 {
1876 /* This is a private page. We must only change the page protection. */
1877 MmSetPageProtect(Process, PAddress, Region->Protect);
1878 return(STATUS_SUCCESS);
1879 }
1880
1881 /*
1882 * Get or create a pageop
1883 */
1884 PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset,
1885 MM_PAGEOP_ACCESSFAULT, FALSE);
1886 if (PageOp == NULL)
1887 {
1888 DPRINT1("MmGetPageOp failed\n");
1889 KeBugCheck(MEMORY_MANAGEMENT);
1890 }
1891
1892 /*
1893 * Wait for any other operations to complete
1894 */
1895 if (PageOp->Thread != PsGetCurrentThread())
1896 {
1897 MmUnlockAddressSpace(AddressSpace);
1898 Status = MmspWaitForPageOpCompletionEvent(PageOp);
1899 /*
1900 * Check for various strange conditions
1901 */
1902 if (Status == STATUS_TIMEOUT)
1903 {
1904 DPRINT1("Failed to wait for page op, status = %x\n", Status);
1905 KeBugCheck(MEMORY_MANAGEMENT);
1906 }
1907 if (PageOp->Status == STATUS_PENDING)
1908 {
1909 DPRINT1("Woke for page op before completion\n");
1910 KeBugCheck(MEMORY_MANAGEMENT);
1911 }
1912 /*
1913 * Restart the operation
1914 */
1915 MmLockAddressSpace(AddressSpace);
1916 MmspCompleteAndReleasePageOp(PageOp);
1917 DPRINT("Address 0x%.8X\n", Address);
1918 return(STATUS_MM_RESTART_OPERATION);
1919 }
1920
1921 /*
1922 * Release locks now we have the pageop
1923 */
1924 MmUnlockAddressSpace(AddressSpace);
1925
1926 /*
1927 * Allocate a page
1928 */
1929 MI_SET_USAGE(MI_USAGE_SECTION);
1930 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1931 if (!Process) MI_SET_PROCESS2("Kernel Section");
1932 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1933 if (!NT_SUCCESS(Status))
1934 {
1935 KeBugCheck(MEMORY_MANAGEMENT);
1936 }
1937
1938 /*
1939 * Copy the old page
1940 */
1941 MiCopyFromUserPage(NewPage, PAddress);
1942
1943 MmLockAddressSpace(AddressSpace);
1944 /*
1945 * Delete the old entry.
1946 */
1947 MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
1948
1949 /*
1950 * Set the PTE to point to the new page
1951 */
1952 Status = MmCreateVirtualMapping(Process,
1953 Address,
1954 Region->Protect,
1955 &NewPage,
1956 1);
1957 if (!NT_SUCCESS(Status))
1958 {
1959 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1960 KeBugCheck(MEMORY_MANAGEMENT);
1961 return(Status);
1962 }
1963 if (!NT_SUCCESS(Status))
1964 {
1965 DPRINT1("Unable to create virtual mapping\n");
1966 KeBugCheck(MEMORY_MANAGEMENT);
1967 }
1968
1969 /*
1970 * Unshare the old page.
1971 */
1972 MmDeleteRmap(OldPage, Process, PAddress);
1973 MmInsertRmap(NewPage, Process, PAddress);
1974 MmLockSectionSegment(Segment);
1975 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE, FALSE);
1976 MmUnlockSectionSegment(Segment);
1977
1978 PageOp->Status = STATUS_SUCCESS;
1979 MmspCompleteAndReleasePageOp(PageOp);
1980 DPRINT("Address 0x%.8X\n", Address);
1981 return(STATUS_SUCCESS);
1982 }
1983
1984 VOID
1985 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
1986 {
1987 MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1988 BOOLEAN WasDirty;
1989 PFN_NUMBER Page;
1990
1991 PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1992 if (Process)
1993 {
1994 MmLockAddressSpace(&Process->Vm);
1995 }
1996
1997 MmDeleteVirtualMapping(Process,
1998 Address,
1999 FALSE,
2000 &WasDirty,
2001 &Page);
2002 if (WasDirty)
2003 {
2004 PageOutContext->WasDirty = TRUE;
2005 }
2006 if (!PageOutContext->Private)
2007 {
2008 MmLockSectionSegment(PageOutContext->Segment);
2009 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT)PageOutContext->Section,
2010 PageOutContext->Segment,
2011 PageOutContext->Offset,
2012 PageOutContext->WasDirty,
2013 TRUE);
2014 MmUnlockSectionSegment(PageOutContext->Segment);
2015 }
2016 if (Process)
2017 {
2018 MmUnlockAddressSpace(&Process->Vm);
2019 }
2020
2021 if (PageOutContext->Private)
2022 {
2023 MmReleasePageMemoryConsumer(MC_USER, Page);
2024 }
2025
2026 DPRINT("PhysicalAddress %x, Address %x\n", Page << PAGE_SHIFT, Address);
2027 }
2028
2029 NTSTATUS
2030 NTAPI
2031 MmPageOutSectionView(PMMSUPPORT AddressSpace,
2032 MEMORY_AREA* MemoryArea,
2033 PVOID Address,
2034 PMM_PAGEOP PageOp)
2035 {
2036 PFN_NUMBER Page;
2037 MM_SECTION_PAGEOUT_CONTEXT Context;
2038 SWAPENTRY SwapEntry;
2039 ULONG Entry;
2040 ULONG FileOffset;
2041 NTSTATUS Status;
2042 PFILE_OBJECT FileObject;
2043 #ifndef NEWCC
2044 PBCB Bcb = NULL;
2045 #endif
2046 BOOLEAN DirectMapped;
2047 BOOLEAN IsImageSection;
2048 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
2049 KIRQL OldIrql;
2050
2051 Address = (PVOID)PAGE_ROUND_DOWN(Address);
2052
2053 /*
2054 * Get the segment and section.
2055 */
2056 Context.Segment = MemoryArea->Data.SectionData.Segment;
2057 Context.Section = MemoryArea->Data.SectionData.Section;
2058
2059 Context.Offset = (ULONG)((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
2060 + MemoryArea->Data.SectionData.ViewOffset);
2061 FileOffset = Context.Offset + Context.Segment->FileOffset;
2062
2063 IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
2064
2065 FileObject = Context.Section->FileObject;
2066 DirectMapped = FALSE;
2067 #ifndef NEWCC
2068 if (FileObject != NULL &&
2069 !(Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
2070 {
2071 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
2072
2073 /*
2074 * If the file system is letting us go directly to the cache and the
2075 * memory area was mapped at an offset in the file which is page aligned
2076 * then note this is a direct mapped page.
2077 */
2078 if ((FileOffset % PAGE_SIZE) == 0 &&
2079 (Context.Offset + PAGE_SIZE <= Context.Segment->RawLength || !IsImageSection))
2080 {
2081 DirectMapped = TRUE;
2082 }
2083 }
2084 #endif
2085
2086
2087 /*
2088 * This should never happen since mappings of physical memory are never
2089 * placed in the rmap lists.
2090 */
2091 if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
2092 {
2093 DPRINT1("Trying to page out from physical memory section address 0x%X "
2094 "process %d\n", Address,
2095 Process ? Process->UniqueProcessId : 0);
2096 KeBugCheck(MEMORY_MANAGEMENT);
2097 }
2098
2099 /*
2100 * Get the section segment entry and the physical address.
2101 */
2102 Entry = MmGetPageEntrySectionSegment(Context.Segment, Context.Offset);
2103 if (!MmIsPagePresent(Process, Address))
2104 {
2105 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2106 Process ? Process->UniqueProcessId : 0, Address);
2107 KeBugCheck(MEMORY_MANAGEMENT);
2108 }
2109 Page = MmGetPfnForProcess(Process, Address);
2110 SwapEntry = MmGetSavedSwapEntryPage(Page);
2111
2112 /*
2113 * Prepare the context structure for the rmap delete call.
2114 */
2115 Context.WasDirty = FALSE;
2116 if (Context.Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
2117 IS_SWAP_FROM_SSE(Entry) ||
2118 PFN_FROM_SSE(Entry) != Page)
2119 {
2120 Context.Private = TRUE;
2121 }
2122 else
2123 {
2124 Context.Private = FALSE;
2125 }
2126
2127 /*
2128 * Take an additional reference to the page or the cache segment.
2129 */
2130 if (DirectMapped && !Context.Private)
2131 {
2132 if(!MiIsPageFromCache(MemoryArea, Context.Offset))
2133 {
2134 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2135 KeBugCheck(MEMORY_MANAGEMENT);
2136 }
2137 }
2138 else
2139 {
2140 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
2141 MmReferencePage(Page);
2142 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
2143 }
2144
2145 MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping);
2146
2147 /*
2148 * If this wasn't a private page then we should have reduced the entry to
2149 * zero by deleting all the rmaps.
2150 */
2151 if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0)
2152 {
2153 if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
2154 !(Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
2155 {
2156 KeBugCheck(MEMORY_MANAGEMENT);
2157 }
2158 }
2159
2160 /*
2161 * If the page wasn't dirty then we can just free it as for a readonly page.
2162 * Since we unmapped all the mappings above we know it will not suddenly
2163 * become dirty.
2164 * If the page is from a pagefile section and has no swap entry,
2165 * we can't free the page at this point.
2166 */
2167 SwapEntry = MmGetSavedSwapEntryPage(Page);
2168 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT)
2169 {
2170 if (Context.Private)
2171 {
2172 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
2173 Context.WasDirty ? "dirty" : "clean", Address);
2174 KeBugCheck(MEMORY_MANAGEMENT);
2175 }
2176 if (!Context.WasDirty && SwapEntry != 0)
2177 {
2178 MmSetSavedSwapEntryPage(Page, 0);
2179 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2180 MmReleasePageMemoryConsumer(MC_USER, Page);
2181 PageOp->Status = STATUS_SUCCESS;
2182 MmspCompleteAndReleasePageOp(PageOp);
2183 return(STATUS_SUCCESS);
2184 }
2185 }
2186 else if (Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED)
2187 {
2188 if (Context.Private)
2189 {
2190 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2191 Context.WasDirty ? "dirty" : "clean", Address);
2192 KeBugCheck(MEMORY_MANAGEMENT);
2193 }
2194 if (!Context.WasDirty || SwapEntry != 0)
2195 {
2196 MmSetSavedSwapEntryPage(Page, 0);
2197 if (SwapEntry != 0)
2198 {
2199 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2200 }
2201 MmReleasePageMemoryConsumer(MC_USER, Page);
2202 PageOp->Status = STATUS_SUCCESS;
2203 MmspCompleteAndReleasePageOp(PageOp);
2204 return(STATUS_SUCCESS);
2205 }
2206 }
2207 else if (!Context.Private && DirectMapped)
2208 {
2209 if (SwapEntry != 0)
2210 {
2211 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2212 Address);
2213 KeBugCheck(MEMORY_MANAGEMENT);
2214 }
2215 #ifndef NEWCC
2216 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
2217 #else
2218 Status = STATUS_SUCCESS;
2219 #endif
2220 if (!NT_SUCCESS(Status))
2221 {
2222 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
2223 KeBugCheck(MEMORY_MANAGEMENT);
2224 }
2225 PageOp->Status = STATUS_SUCCESS;
2226 MmspCompleteAndReleasePageOp(PageOp);
2227 return(STATUS_SUCCESS);
2228 }
2229 else if (!Context.WasDirty && !DirectMapped && !Context.Private)
2230 {
2231 if (SwapEntry != 0)
2232 {
2233 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2234 Address);
2235 KeBugCheck(MEMORY_MANAGEMENT);
2236 }
2237 MmReleasePageMemoryConsumer(MC_USER, Page);
2238 PageOp->Status = STATUS_SUCCESS;
2239 MmspCompleteAndReleasePageOp(PageOp);
2240 return(STATUS_SUCCESS);
2241 }
2242 else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
2243 {
2244 MmSetSavedSwapEntryPage(Page, 0);
2245 MmLockAddressSpace(AddressSpace);
2246 Status = MmCreatePageFileMapping(Process,
2247 Address,
2248 SwapEntry);
2249 MmUnlockAddressSpace(AddressSpace);
2250 if (!NT_SUCCESS(Status))
2251 {
2252 KeBugCheck(MEMORY_MANAGEMENT);
2253 }
2254 MmReleasePageMemoryConsumer(MC_USER, Page);
2255 PageOp->Status = STATUS_SUCCESS;
2256 MmspCompleteAndReleasePageOp(PageOp);
2257 return(STATUS_SUCCESS);
2258 }
2259
2260 /*
2261 * If necessary, allocate an entry in the paging file for this page
2262 */
2263 if (SwapEntry == 0)
2264 {
2265 SwapEntry = MmAllocSwapPage();
2266 if (SwapEntry == 0)
2267 {
2268 MmShowOutOfSpaceMessagePagingFile();
2269 MmLockAddressSpace(AddressSpace);
2270 /*
2271 * For private pages restore the old mappings.
2272 */
2273 if (Context.Private)
2274 {
2275 Status = MmCreateVirtualMapping(Process,
2276 Address,
2277 MemoryArea->Protect,
2278 &Page,
2279 1);
2280 MmSetDirtyPage(Process, Address);
2281 MmInsertRmap(Page,
2282 Process,
2283 Address);
2284 }
2285 else
2286 {
2287 /*
2288 * For non-private pages if the page wasn't direct mapped then
2289 * set it back into the section segment entry so we don't loose
2290 * our copy. Otherwise it will be handled by the cache manager.
2291 */
2292 Status = MmCreateVirtualMapping(Process,
2293 Address,
2294 MemoryArea->Protect,
2295 &Page,
2296 1);
2297 MmSetDirtyPage(Process, Address);
2298 MmInsertRmap(Page,
2299 Process,
2300 Address);
2301 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
2302 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
2303 }
2304 MmUnlockAddressSpace(AddressSpace);
2305 PageOp->Status = STATUS_UNSUCCESSFUL;
2306 MmspCompleteAndReleasePageOp(PageOp);
2307 return(STATUS_PAGEFILE_QUOTA);
2308 }
2309 }
2310
2311 /*
2312 * Write the page to the pagefile
2313 */
2314 Status = MmWriteToSwapPage(SwapEntry, Page);
2315 if (!NT_SUCCESS(Status))
2316 {
2317 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2318 Status);
2319 /*
2320 * As above: undo our actions.
2321 * FIXME: Also free the swap page.
2322 */
2323 MmLockAddressSpace(AddressSpace);
2324 if (Context.Private)
2325 {
2326 Status = MmCreateVirtualMapping(Process,
2327 Address,
2328 MemoryArea->Protect,
2329 &Page,
2330 1);
2331 MmSetDirtyPage(Process, Address);
2332 MmInsertRmap(Page,
2333 Process,
2334 Address);
2335 }
2336 else
2337 {
2338 Status = MmCreateVirtualMapping(Process,
2339 Address,
2340 MemoryArea->Protect,
2341 &Page,
2342 1);
2343 MmSetDirtyPage(Process, Address);
2344 MmInsertRmap(Page,
2345 Process,
2346 Address);
2347 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
2348 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
2349 }
2350 MmUnlockAddressSpace(AddressSpace);
2351 PageOp->Status = STATUS_UNSUCCESSFUL;
2352 MmspCompleteAndReleasePageOp(PageOp);
2353 return(STATUS_UNSUCCESSFUL);
2354 }
2355
2356 /*
2357 * Otherwise we have succeeded.
2358 */
2359 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
2360 MmSetSavedSwapEntryPage(Page, 0);
2361 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
2362 Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED)
2363 {
2364 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2365 }
2366 else
2367 {
2368 MmReleasePageMemoryConsumer(MC_USER, Page);
2369 }
2370
2371 if (Context.Private)
2372 {
2373 MmLockAddressSpace(AddressSpace);
2374 Status = MmCreatePageFileMapping(Process,
2375 Address,
2376 SwapEntry);
2377 MmUnlockAddressSpace(AddressSpace);
2378 if (!NT_SUCCESS(Status))
2379 {
2380 KeBugCheck(MEMORY_MANAGEMENT);
2381 }
2382 }
2383 else
2384 {
2385 Entry = MAKE_SWAP_SSE(SwapEntry);
2386 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
2387 }
2388
2389 PageOp->Status = STATUS_SUCCESS;
2390 MmspCompleteAndReleasePageOp(PageOp);
2391 return(STATUS_SUCCESS);
2392 }
2393
2394 NTSTATUS
2395 NTAPI
2396 MmWritePageSectionView(PMMSUPPORT AddressSpace,
2397 PMEMORY_AREA MemoryArea,
2398 PVOID Address,
2399 PMM_PAGEOP PageOp)
2400 {
2401 ULONG_PTR Offset;
2402 PROS_SECTION_OBJECT Section;
2403 PMM_SECTION_SEGMENT Segment;
2404 PFN_NUMBER Page;
2405 SWAPENTRY SwapEntry;
2406 ULONG Entry;
2407 BOOLEAN Private;
2408 NTSTATUS Status;
2409 PFILE_OBJECT FileObject;
2410 PBCB Bcb = NULL;
2411 BOOLEAN DirectMapped;
2412 BOOLEAN IsImageSection;
2413 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
2414
2415 Address = (PVOID)PAGE_ROUND_DOWN(Address);
2416
2417 Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
2418 + MemoryArea->Data.SectionData.ViewOffset;
2419
2420 /*
2421 * Get the segment and section.
2422 */
2423 Segment = MemoryArea->Data.SectionData.Segment;
2424 Section = MemoryArea->Data.SectionData.Section;
2425 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
2426
2427 FileObject = Section->FileObject;
2428 DirectMapped = FALSE;
2429 if (FileObject != NULL &&
2430 !(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
2431 {
2432 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
2433
2434 /*
2435 * If the file system is letting us go directly to the cache and the
2436 * memory area was mapped at an offset in the file which is page aligned
2437 * then note this is a direct mapped page.
2438 */
2439 if (((Offset + Segment->FileOffset) % PAGE_SIZE) == 0 &&
2440 (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
2441 {
2442 DirectMapped = TRUE;
2443 }
2444 }
2445
2446 /*
2447 * This should never happen since mappings of physical memory are never
2448 * placed in the rmap lists.
2449 */
2450 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
2451 {
2452 DPRINT1("Trying to write back page from physical memory mapped at %X "
2453 "process %d\n", Address,
2454 Process ? Process->UniqueProcessId : 0);
2455 KeBugCheck(MEMORY_MANAGEMENT);
2456 }
2457
2458 /*
2459 * Get the section segment entry and the physical address.
2460 */
2461 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
2462 if (!MmIsPagePresent(Process, Address))
2463 {
2464 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2465 Process ? Process->UniqueProcessId : 0, Address);
2466 KeBugCheck(MEMORY_MANAGEMENT);
2467 }
2468 Page = MmGetPfnForProcess(Process, Address);
2469 SwapEntry = MmGetSavedSwapEntryPage(Page);
2470
2471 /*
2472 * Check for a private (COWed) page.
2473 */
2474 if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
2475 IS_SWAP_FROM_SSE(Entry) ||
2476 PFN_FROM_SSE(Entry) != Page)
2477 {
2478 Private = TRUE;
2479 }
2480 else
2481 {
2482 Private = FALSE;
2483 }
2484
2485 /*
2486 * Speculatively set all mappings of the page to clean.
2487 */
2488 MmSetCleanAllRmaps(Page);
2489
2490 /*
2491 * If this page was direct mapped from the cache then the cache manager
2492 * will take care of writing it back to disk.
2493 */
2494 if (DirectMapped && !Private)
2495 {
2496 ASSERT(SwapEntry == 0);
2497 #ifndef NEWCC
2498 CcRosMarkDirtyCacheSegment(Bcb, (ULONG)Offset + Segment->FileOffset);
2499 #endif
2500 PageOp->Status = STATUS_SUCCESS;
2501 MmspCompleteAndReleasePageOp(PageOp);
2502 return(STATUS_SUCCESS);
2503 }
2504
2505 /*
2506 * If necessary, allocate an entry in the paging file for this page
2507 */
2508 if (SwapEntry == 0)
2509 {
2510 SwapEntry = MmAllocSwapPage();
2511 if (SwapEntry == 0)
2512 {
2513 MmSetDirtyAllRmaps(Page);
2514 PageOp->Status = STATUS_UNSUCCESSFUL;
2515 MmspCompleteAndReleasePageOp(PageOp);
2516 return(STATUS_PAGEFILE_QUOTA);
2517 }
2518 MmSetSavedSwapEntryPage(Page, SwapEntry);
2519 }
2520
2521 /*
2522 * Write the page to the pagefile
2523 */
2524 Status = MmWriteToSwapPage(SwapEntry, Page);
2525 if (!NT_SUCCESS(Status))
2526 {
2527 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2528 Status);
2529 MmSetDirtyAllRmaps(Page);
2530 PageOp->Status = STATUS_UNSUCCESSFUL;
2531 MmspCompleteAndReleasePageOp(PageOp);
2532 return(STATUS_UNSUCCESSFUL);
2533 }
2534
2535 /*
2536 * Otherwise we have succeeded.
2537 */
2538 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
2539 PageOp->Status = STATUS_SUCCESS;
2540 MmspCompleteAndReleasePageOp(PageOp);
2541 return(STATUS_SUCCESS);
2542 }
2543
2544 static VOID
2545 MmAlterViewAttributes(PMMSUPPORT AddressSpace,
2546 PVOID BaseAddress,
2547 SIZE_T RegionSize,
2548 ULONG OldType,
2549 ULONG OldProtect,
2550 ULONG NewType,
2551 ULONG NewProtect)
2552 {
2553 PMEMORY_AREA MemoryArea;
2554 PMM_SECTION_SEGMENT Segment;
2555 BOOLEAN DoCOW = FALSE;
2556 ULONG i;
2557 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
2558
2559 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
2560 Segment = MemoryArea->Data.SectionData.Segment;
2561
2562 if ((Segment->WriteCopy) &&
2563 (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
2564 {
2565 DoCOW = TRUE;
2566 }
2567
2568 if (OldProtect != NewProtect)
2569 {
2570 for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
2571 {
2572 PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
2573 ULONG Protect = NewProtect;
2574
2575 /*
2576 * If we doing COW for this segment then check if the page is
2577 * already private.
2578 */
2579 if (DoCOW && MmIsPagePresent(Process, Address))
2580 {
2581 ULONG_PTR Offset;
2582 ULONG Entry;
2583 PFN_NUMBER Page;
2584
2585 Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
2586 + MemoryArea->Data.SectionData.ViewOffset;
2587 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
2588 Page = MmGetPfnForProcess(Process, Address);
2589
2590 Protect = PAGE_READONLY;
2591 if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
2592 IS_SWAP_FROM_SSE(Entry) ||
2593 PFN_FROM_SSE(Entry) != Page)
2594 {
2595 Protect = NewProtect;
2596 }
2597 }
2598
2599 if (MmIsPagePresent(Process, Address))
2600 {
2601 MmSetPageProtect(Process, Address,
2602 Protect);
2603 }
2604 }
2605 }
2606 }
2607
2608 NTSTATUS
2609 NTAPI
2610 MmProtectSectionView(PMMSUPPORT AddressSpace,
2611 PMEMORY_AREA MemoryArea,
2612 PVOID BaseAddress,
2613 SIZE_T Length,
2614 ULONG Protect,
2615 PULONG OldProtect)
2616 {
2617 PMM_REGION Region;
2618 NTSTATUS Status;
2619 ULONG_PTR MaxLength;
2620
2621 MaxLength = (ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)BaseAddress;
2622 if (Length > MaxLength)
2623 Length = (ULONG)MaxLength;
2624
2625 Region = MmFindRegion(MemoryArea->StartingAddress,
2626 &MemoryArea->Data.SectionData.RegionListHead,
2627 BaseAddress, NULL);
2628 if ((MemoryArea->Flags & SEC_NO_CHANGE) &&
2629 Region->Protect != Protect)
2630 {
2631 return STATUS_INVALID_PAGE_PROTECTION;
2632 }
2633
2634 *OldProtect = Region->Protect;
2635 Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress,
2636 &MemoryArea->Data.SectionData.RegionListHead,
2637 BaseAddress, Length, Region->Type, Protect,
2638 MmAlterViewAttributes);
2639
2640 return(Status);
2641 }
2642
2643 NTSTATUS NTAPI
2644 MmQuerySectionView(PMEMORY_AREA MemoryArea,
2645 PVOID Address,
2646 PMEMORY_BASIC_INFORMATION Info,
2647 PSIZE_T ResultLength)
2648 {
2649 PMM_REGION Region;
2650 PVOID RegionBaseAddress;
2651 PROS_SECTION_OBJECT Section;
2652 PMM_SECTION_SEGMENT Segment;
2653
2654 Region = MmFindRegion((PVOID)MemoryArea->StartingAddress,
2655 &MemoryArea->Data.SectionData.RegionListHead,
2656 Address, &RegionBaseAddress);
2657 if (Region == NULL)
2658 {
2659 return STATUS_UNSUCCESSFUL;
2660 }
2661
2662 Section = MemoryArea->Data.SectionData.Section;
2663 if (Section->AllocationAttributes & SEC_IMAGE)
2664 {
2665 Segment = MemoryArea->Data.SectionData.Segment;
2666 Info->AllocationBase = (PUCHAR)MemoryArea->StartingAddress - Segment->VirtualAddress;
2667 Info->Type = MEM_IMAGE;
2668 }
2669 else
2670 {
2671 Info->AllocationBase = MemoryArea->StartingAddress;
2672 Info->Type = MEM_MAPPED;
2673 }
2674 Info->BaseAddress = RegionBaseAddress;
2675 Info->AllocationProtect = MemoryArea->Protect;
2676 Info->RegionSize = Region->Length;
2677 Info->State = MEM_COMMIT;
2678 Info->Protect = Region->Protect;
2679
2680 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
2681 return(STATUS_SUCCESS);
2682 }
2683
2684 VOID
2685 NTAPI
2686 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
2687 {
2688 ULONG Length;
2689 ULONG Offset;
2690 ULONG Entry;
2691 SWAPENTRY SavedSwapEntry;
2692 PFN_NUMBER Page;
2693
2694 Page = 0;
2695
2696 Length = PAGE_ROUND_UP(Segment->Length);
2697 for (Offset = 0; Offset < Length; Offset += PAGE_SIZE)
2698 {
2699 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
2700 if (Entry)
2701 {
2702 if (IS_SWAP_FROM_SSE(Entry))
2703 {
2704 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
2705 }
2706 else
2707 {
2708 Page = PFN_FROM_SSE(Entry);
2709 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
2710 if (SavedSwapEntry != 0)
2711 {
2712 MmSetSavedSwapEntryPage(Page, 0);
2713 MmFreeSwapPage(SavedSwapEntry);
2714 }
2715 MmReleasePageMemoryConsumer(MC_USER, Page);
2716 }
2717 MmSetPageEntrySectionSegment(Segment, Offset, 0);
2718 }
2719 }
2720 }
2721
2722 VOID NTAPI
2723 MmpDeleteSection(PVOID ObjectBody)
2724 {
2725 PROS_SECTION_OBJECT Section = (PROS_SECTION_OBJECT)ObjectBody;
2726
2727 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
2728 if (Section->AllocationAttributes & SEC_IMAGE)
2729 {
2730 ULONG i;
2731 ULONG NrSegments;
2732 ULONG RefCount;
2733 PMM_SECTION_SEGMENT SectionSegments;
2734
2735 /*
2736 * NOTE: Section->ImageSection can be NULL for short time
2737 * during the section creating. If we fail for some reason
2738 * until the image section is properly initialized we shouldn't
2739 * process further here.
2740 */
2741 if (Section->ImageSection == NULL)
2742 return;
2743
2744 SectionSegments = Section->ImageSection->Segments;
2745 NrSegments = Section->ImageSection->NrSegments;
2746
2747 for (i = 0; i < NrSegments; i++)
2748 {
2749 if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
2750 {
2751 MmLockSectionSegment(&SectionSegments[i]);
2752 }
2753 RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount);
2754 if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
2755 {
2756 if (RefCount == 0)
2757 {
2758 MmpFreePageFileSegment(&SectionSegments[i]);
2759 }
2760 MmUnlockSectionSegment(&SectionSegments[i]);
2761 }
2762 }
2763 }
2764 else
2765 {
2766 /*
2767 * NOTE: Section->Segment can be NULL for short time
2768 * during the section creating.
2769 */
2770 if (Section->Segment == NULL)
2771 return;
2772
2773 if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
2774 {
2775 MmpFreePageFileSegment(Section->Segment);
2776 MmFreePageTablesSectionSegment(Section->Segment);
2777 ExFreePool(Section->Segment);
2778 Section->Segment = NULL;
2779 }
2780 else
2781 {
2782 (void)InterlockedDecrementUL(&Section->Segment->ReferenceCount);
2783 }
2784 }
2785 if (Section->FileObject != NULL)
2786 {
2787 #ifndef NEWCC
2788 CcRosDereferenceCache(Section->FileObject);
2789 #endif
2790 ObDereferenceObject(Section->FileObject);
2791 Section->FileObject = NULL;
2792 }
2793 }
2794
2795 VOID NTAPI
2796 MmpCloseSection(IN PEPROCESS Process OPTIONAL,
2797 IN PVOID Object,
2798 IN ACCESS_MASK GrantedAccess,
2799 IN ULONG ProcessHandleCount,
2800 IN ULONG SystemHandleCount)
2801 {
2802 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2803 Object, ProcessHandleCount);
2804 }
2805
2806 NTSTATUS
2807 INIT_FUNCTION
2808 NTAPI
2809 MmCreatePhysicalMemorySection(VOID)
2810 {
2811 PROS_SECTION_OBJECT PhysSection;
2812 NTSTATUS Status;
2813 OBJECT_ATTRIBUTES Obj;
2814 UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
2815 LARGE_INTEGER SectionSize;
2816 HANDLE Handle;
2817
2818 /*
2819 * Create the section mapping physical memory
2820 */
2821 SectionSize.QuadPart = 0xFFFFFFFF;
2822 InitializeObjectAttributes(&Obj,
2823 &Name,
2824 OBJ_PERMANENT,
2825 NULL,
2826 NULL);
2827 Status = MmCreateSection((PVOID)&PhysSection,
2828 SECTION_ALL_ACCESS,
2829 &Obj,
2830 &SectionSize,
2831 PAGE_EXECUTE_READWRITE,
2832 0,
2833 NULL,
2834 NULL);
2835 if (!NT_SUCCESS(Status))
2836 {
2837 DPRINT1("Failed to create PhysicalMemory section\n");
2838 KeBugCheck(MEMORY_MANAGEMENT);
2839 }
2840 Status = ObInsertObject(PhysSection,
2841 NULL,
2842 SECTION_ALL_ACCESS,
2843 0,
2844 NULL,
2845 &Handle);
2846 if (!NT_SUCCESS(Status))
2847 {
2848 ObDereferenceObject(PhysSection);
2849 }
2850 ObCloseHandle(Handle, KernelMode);
2851 PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
2852 PhysSection->Segment->Flags &= ~MM_PAGEFILE_SEGMENT;
2853
2854 return(STATUS_SUCCESS);
2855 }
2856
2857 NTSTATUS
2858 INIT_FUNCTION
2859 NTAPI
2860 MmInitSectionImplementation(VOID)
2861 {
2862 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
2863 UNICODE_STRING Name;
2864
2865 DPRINT("Creating Section Object Type\n");
2866
2867 /* Initialize the Section object type */
2868 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
2869 RtlInitUnicodeString(&Name, L"Section");
2870 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
2871 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(ROS_SECTION_OBJECT);
2872 ObjectTypeInitializer.PoolType = PagedPool;
2873 ObjectTypeInitializer.UseDefaultObject = TRUE;
2874 ObjectTypeInitializer.GenericMapping = MmpSectionMapping;
2875 ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection;
2876 ObjectTypeInitializer.CloseProcedure = MmpCloseSection;
2877 ObjectTypeInitializer.ValidAccessMask = SECTION_ALL_ACCESS;
2878 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &MmSectionObjectType);
2879
2880 MmCreatePhysicalMemorySection();
2881
2882 return(STATUS_SUCCESS);
2883 }
2884
2885 NTSTATUS
2886 NTAPI
2887 MmCreatePageFileSection(PROS_SECTION_OBJECT *SectionObject,
2888 ACCESS_MASK DesiredAccess,
2889 POBJECT_ATTRIBUTES ObjectAttributes,
2890 PLARGE_INTEGER UMaximumSize,
2891 ULONG SectionPageProtection,
2892 ULONG AllocationAttributes)
2893 /*
2894 * Create a section which is backed by the pagefile
2895 */
2896 {
2897 LARGE_INTEGER MaximumSize;
2898 PROS_SECTION_OBJECT Section;
2899 PMM_SECTION_SEGMENT Segment;
2900 NTSTATUS Status;
2901
2902 if (UMaximumSize == NULL)
2903 {
2904 return(STATUS_UNSUCCESSFUL);
2905 }
2906 MaximumSize = *UMaximumSize;
2907
2908 /*
2909 * Create the section
2910 */
2911 Status = ObCreateObject(ExGetPreviousMode(),
2912 MmSectionObjectType,
2913 ObjectAttributes,
2914 ExGetPreviousMode(),
2915 NULL,
2916 sizeof(ROS_SECTION_OBJECT),
2917 0,
2918 0,
2919 (PVOID*)(PVOID)&Section);
2920 if (!NT_SUCCESS(Status))
2921 {
2922 return(Status);
2923 }
2924
2925 /*
2926 * Initialize it
2927 */
2928 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
2929 Section->SectionPageProtection = SectionPageProtection;
2930 Section->AllocationAttributes = AllocationAttributes;
2931 Section->MaximumSize = MaximumSize;
2932 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2933 TAG_MM_SECTION_SEGMENT);
2934 if (Segment == NULL)
2935 {
2936 ObDereferenceObject(Section);
2937 return(STATUS_NO_MEMORY);
2938 }
2939 Section->Segment = Segment;
2940 Segment->ReferenceCount = 1;
2941 ExInitializeFastMutex(&Segment->Lock);
2942 Segment->FileOffset = 0;
2943 Segment->Protection = SectionPageProtection;
2944 Segment->RawLength = MaximumSize.u.LowPart;
2945 Segment->Length = PAGE_ROUND_UP(MaximumSize.u.LowPart);
2946 Segment->Flags = MM_PAGEFILE_SEGMENT;
2947 Segment->WriteCopy = FALSE;
2948 RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
2949 Segment->VirtualAddress = 0;
2950 Segment->Characteristics = 0;
2951 *SectionObject = Section;
2952 return(STATUS_SUCCESS);
2953 }
2954
2955
2956 NTSTATUS
2957 NTAPI
2958 MmCreateDataFileSection(PROS_SECTION_OBJECT *SectionObject,
2959 ACCESS_MASK DesiredAccess,
2960 POBJECT_ATTRIBUTES ObjectAttributes,
2961 PLARGE_INTEGER UMaximumSize,
2962 ULONG SectionPageProtection,
2963 ULONG AllocationAttributes,
2964 HANDLE FileHandle)
2965 /*
2966 * Create a section backed by a data file
2967 */
2968 {
2969 PROS_SECTION_OBJECT Section;
2970 NTSTATUS Status;
2971 LARGE_INTEGER MaximumSize;
2972 PFILE_OBJECT FileObject;
2973 PMM_SECTION_SEGMENT Segment;
2974 ULONG FileAccess;
2975 IO_STATUS_BLOCK Iosb;
2976 LARGE_INTEGER Offset;
2977 CHAR Buffer;
2978 FILE_STANDARD_INFORMATION FileInfo;
2979 ULONG Length;
2980
2981 /*
2982 * Create the section
2983 */
2984 Status = ObCreateObject(ExGetPreviousMode(),
2985 MmSectionObjectType,
2986 ObjectAttributes,
2987 ExGetPreviousMode(),
2988 NULL,
2989 sizeof(ROS_SECTION_OBJECT),
2990 0,
2991 0,
2992 (PVOID*)(PVOID)&Section);
2993 if (!NT_SUCCESS(Status))
2994 {
2995 return(Status);
2996 }
2997 /*
2998 * Initialize it
2999 */
3000 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
3001 Section->SectionPageProtection = SectionPageProtection;
3002 Section->AllocationAttributes = AllocationAttributes;
3003
3004 /*
3005 * Check file access required
3006 */
3007 if (SectionPageProtection & PAGE_READWRITE ||
3008 SectionPageProtection & PAGE_EXECUTE_READWRITE)
3009 {
3010 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
3011 }
3012 else
3013 {
3014 FileAccess = FILE_READ_DATA;
3015 }
3016
3017 /*
3018 * Reference the file handle
3019 */
3020 Status = ObReferenceObjectByHandle(FileHandle,
3021 FileAccess,
3022 IoFileObjectType,
3023 ExGetPreviousMode(),
3024 (PVOID*)(PVOID)&FileObject,
3025 NULL);
3026 if (!NT_SUCCESS(Status))
3027 {
3028 ObDereferenceObject(Section);
3029 return(Status);
3030 }
3031
3032 /*
3033 * FIXME: This is propably not entirely correct. We can't look into
3034 * the standard FCB header because it might not be initialized yet
3035 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
3036 * standard file information is filled on first request).
3037 */
3038 Status = IoQueryFileInformation(FileObject,
3039 FileStandardInformation,
3040 sizeof(FILE_STANDARD_INFORMATION),
3041 &FileInfo,
3042 &Length);
3043 Iosb.Information = Length;
3044 if (!NT_SUCCESS(Status))
3045 {
3046 ObDereferenceObject(Section);
3047 ObDereferenceObject(FileObject);
3048 return Status;
3049 }
3050
3051 /*
3052 * FIXME: Revise this once a locking order for file size changes is
3053 * decided
3054 */
3055 if ((UMaximumSize != NULL) && (UMaximumSize->QuadPart != 0))
3056 {
3057 MaximumSize = *UMaximumSize;
3058 }
3059 else
3060 {
3061 MaximumSize = FileInfo.EndOfFile;
3062 /* Mapping zero-sized files isn't allowed. */
3063 if (MaximumSize.QuadPart == 0)
3064 {
3065 ObDereferenceObject(Section);
3066 ObDereferenceObject(FileObject);
3067 return STATUS_FILE_INVALID;
3068 }
3069 }
3070
3071 if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart)
3072 {
3073 Status = IoSetInformation(FileObject,
3074 FileAllocationInformation,
3075 sizeof(LARGE_INTEGER),
3076 &MaximumSize);
3077 if (!NT_SUCCESS(Status))
3078 {
3079 ObDereferenceObject(Section);
3080 ObDereferenceObject(FileObject);
3081 return(STATUS_SECTION_NOT_EXTENDED);
3082 }
3083 }
3084
3085 if (FileObject->SectionObjectPointer == NULL ||
3086 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
3087 {
3088 /*
3089 * Read a bit so caching is initiated for the file object.
3090 * This is only needed because MiReadPage currently cannot
3091 * handle non-cached streams.
3092 */
3093 Offset.QuadPart = 0;
3094 Status = ZwReadFile(FileHandle,
3095 NULL,
3096 NULL,
3097 NULL,
3098 &Iosb,
3099 &Buffer,
3100 sizeof (Buffer),
3101 &Offset,
3102 0);
3103 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
3104 {
3105 ObDereferenceObject(Section);
3106 ObDereferenceObject(FileObject);
3107 return(Status);
3108 }
3109 if (FileObject->SectionObjectPointer == NULL ||
3110 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
3111 {
3112 /* FIXME: handle this situation */
3113 ObDereferenceObject(Section);
3114 ObDereferenceObject(FileObject);
3115 return STATUS_INVALID_PARAMETER;
3116 }
3117 }
3118
3119 /*
3120 * Lock the file
3121 */
3122 Status = MmspWaitForFileLock(FileObject);
3123 if (Status != STATUS_SUCCESS)
3124 {
3125 ObDereferenceObject(Section);
3126 ObDereferenceObject(FileObject);
3127 return(Status);
3128 }
3129
3130 /*
3131 * If this file hasn't been mapped as a data file before then allocate a
3132 * section segment to describe the data file mapping
3133 */
3134 if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
3135 {
3136 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
3137 TAG_MM_SECTION_SEGMENT);
3138 if (Segment == NULL)
3139 {
3140 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3141 ObDereferenceObject(Section);
3142 ObDereferenceObject(FileObject);
3143 return(STATUS_NO_MEMORY);
3144 }
3145 Section->Segment = Segment;
3146 Segment->ReferenceCount = 1;
3147 ExInitializeFastMutex(&Segment->Lock);
3148 /*
3149 * Set the lock before assigning the segment to the file object
3150 */
3151 ExAcquireFastMutex(&Segment->Lock);
3152 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
3153
3154 Segment->FileOffset = 0;
3155 Segment->Protection = SectionPageProtection;
3156 Segment->Flags = MM_DATAFILE_SEGMENT;
3157 Segment->Characteristics = 0;
3158 Segment->WriteCopy = FALSE;
3159 if (AllocationAttributes & SEC_RESERVE)
3160 {
3161 Segment->Length = Segment->RawLength = 0;
3162 }
3163 else
3164 {
3165 Segment->RawLength = MaximumSize.u.LowPart;
3166 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
3167 }
3168 Segment->VirtualAddress = 0;
3169 RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
3170 }
3171 else
3172 {
3173 /*
3174 * If the file is already mapped as a data file then we may need
3175 * to extend it
3176 */
3177 Segment =
3178 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
3179 DataSectionObject;
3180 Section->Segment = Segment;
3181 (void)InterlockedIncrementUL(&Segment->ReferenceCount);
3182 MmLockSectionSegment(Segment);
3183
3184 if (MaximumSize.u.LowPart > Segment->RawLength &&
3185 !(AllocationAttributes & SEC_RESERVE))
3186 {
3187 Segment->RawLength = MaximumSize.u.LowPart;
3188 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
3189 }
3190 }
3191 MmUnlockSectionSegment(Segment);
3192 Section->FileObject = FileObject;
3193 Section->MaximumSize = MaximumSize;
3194 #ifndef NEWCC
3195 CcRosReferenceCache(FileObject);
3196 #endif
3197 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3198 *SectionObject = Section;
3199 return(STATUS_SUCCESS);
3200 }
3201
3202 /*
3203 TODO: not that great (declaring loaders statically, having to declare all of
3204 them, having to keep them extern, etc.), will fix in the future
3205 */
3206 extern NTSTATUS NTAPI PeFmtCreateSection
3207 (
3208 IN CONST VOID * FileHeader,
3209 IN SIZE_T FileHeaderSize,
3210 IN PVOID File,
3211 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3212 OUT PULONG Flags,
3213 IN PEXEFMT_CB_READ_FILE ReadFileCb,
3214 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3215 );
3216
3217 extern NTSTATUS NTAPI ElfFmtCreateSection
3218 (
3219 IN CONST VOID * FileHeader,
3220 IN SIZE_T FileHeaderSize,
3221 IN PVOID File,
3222 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3223 OUT PULONG Flags,
3224 IN PEXEFMT_CB_READ_FILE ReadFileCb,
3225 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3226 );
3227
3228 /* TODO: this is a standard DDK/PSDK macro */
3229 #ifndef RTL_NUMBER_OF
3230 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3231 #endif
3232
3233 static PEXEFMT_LOADER ExeFmtpLoaders[] =
3234 {
3235 PeFmtCreateSection,
3236 #ifdef __ELF
3237 ElfFmtCreateSection
3238 #endif
3239 };
3240
3241 static
3242 PMM_SECTION_SEGMENT
3243 NTAPI
3244 ExeFmtpAllocateSegments(IN ULONG NrSegments)
3245 {
3246 SIZE_T SizeOfSegments;
3247 PMM_SECTION_SEGMENT Segments;
3248
3249 /* TODO: check for integer overflow */
3250 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments;
3251
3252 Segments = ExAllocatePoolWithTag(NonPagedPool,
3253 SizeOfSegments,
3254 TAG_MM_SECTION_SEGMENT);
3255
3256 if(Segments)
3257 RtlZeroMemory(Segments, SizeOfSegments);
3258
3259 return Segments;
3260 }
3261
3262 static
3263 NTSTATUS
3264 NTAPI
3265 ExeFmtpReadFile(IN PVOID File,
3266 IN PLARGE_INTEGER Offset,
3267 IN ULONG Length,
3268 OUT PVOID * Data,
3269 OUT PVOID * AllocBase,
3270 OUT PULONG ReadSize)
3271 {
3272 NTSTATUS Status;
3273 LARGE_INTEGER FileOffset;
3274 ULONG AdjustOffset;
3275 ULONG OffsetAdjustment;
3276 ULONG BufferSize;
3277 ULONG UsedSize;
3278 PVOID Buffer;
3279
3280 ASSERT_IRQL_LESS(DISPATCH_LEVEL);
3281
3282 if(Length == 0)
3283 {
3284 KeBugCheck(MEMORY_MANAGEMENT);
3285 }
3286
3287 FileOffset = *Offset;
3288
3289 /* Negative/special offset: it cannot be used in this context */
3290 if(FileOffset.u.HighPart < 0)
3291 {
3292 KeBugCheck(MEMORY_MANAGEMENT);
3293 }
3294
3295 AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart);
3296 OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset;
3297 FileOffset.u.LowPart = AdjustOffset;
3298
3299 BufferSize = Length + OffsetAdjustment;
3300 BufferSize = PAGE_ROUND_UP(BufferSize);
3301
3302 /*
3303 * It's ok to use paged pool, because this is a temporary buffer only used in
3304 * the loading of executables. The assumption is that MmCreateSection is
3305 * always called at low IRQLs and that these buffers don't survive a brief
3306 * initialization phase
3307 */
3308 Buffer = ExAllocatePoolWithTag(PagedPool,
3309 BufferSize,
3310 'rXmM');
3311 if (!Buffer)
3312 {
3313 KeBugCheck(MEMORY_MANAGEMENT);
3314 }
3315
3316 UsedSize = 0;
3317
3318 #if 0
3319 Status = MmspPageRead(File,
3320 Buffer,
3321 BufferSize,
3322 &FileOffset,
3323 &UsedSize);
3324 #else
3325 /*
3326 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
3327 * nothing will work. But using ZwReadFile is wrong, and using its side effects
3328 * to initialize internal state is even worse. Our cache manager is in need of
3329 * professional help
3330 */
3331 {
3332 IO_STATUS_BLOCK Iosb;
3333
3334 Status = ZwReadFile(File,
3335 NULL,
3336 NULL,
3337 NULL,
3338 &Iosb,
3339 Buffer,
3340 BufferSize,
3341 &FileOffset,
3342 NULL);
3343
3344 if(NT_SUCCESS(Status))
3345 {
3346 UsedSize = (ULONG)Iosb.Information;
3347 }
3348 }
3349 #endif
3350
3351 if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
3352 {
3353 Status = STATUS_IN_PAGE_ERROR;
3354 ASSERT(!NT_SUCCESS(Status));
3355 }
3356
3357 if(NT_SUCCESS(Status))
3358 {
3359 *Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment);
3360 *AllocBase = Buffer;
3361 *ReadSize = UsedSize - OffsetAdjustment;
3362 }
3363 else
3364 {
3365 ExFreePoolWithTag(Buffer, 'rXmM');
3366 }
3367
3368 return Status;
3369 }
3370
3371 #ifdef NASSERT
3372 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3373 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3374 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3375 #else
3376 static
3377 VOID
3378 NTAPI
3379 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3380 {
3381 ULONG i;
3382
3383 for( i = 1; i < ImageSectionObject->NrSegments; ++ i )
3384 {
3385 ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
3386 ImageSectionObject->Segments[i - 1].VirtualAddress);
3387 }
3388 }
3389
3390 static
3391 VOID
3392 NTAPI
3393 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3394 {
3395 ULONG i;
3396
3397 MmspAssertSegmentsSorted(ImageSectionObject);
3398
3399 for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3400 {
3401 ASSERT(ImageSectionObject->Segments[i].Length > 0);
3402
3403 if(i > 0)
3404 {
3405 ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
3406 (ImageSectionObject->Segments[i - 1].VirtualAddress +
3407 ImageSectionObject->Segments[i - 1].Length));
3408 }
3409 }
3410 }
3411
3412 static
3413 VOID
3414 NTAPI
3415 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3416 {
3417 ULONG i;
3418
3419 for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3420 {
3421 ASSERT((ImageSectionObject->Segments[i].VirtualAddress % PAGE_SIZE) == 0);
3422 ASSERT((ImageSectionObject->Segments[i].Length % PAGE_SIZE) == 0);
3423 }
3424 }
3425 #endif
3426
3427 static
3428 int
3429 __cdecl
3430 MmspCompareSegments(const void * x,
3431 const void * y)
3432 {
3433 const MM_SECTION_SEGMENT *Segment1 = (const MM_SECTION_SEGMENT *)x;
3434 const MM_SECTION_SEGMENT *Segment2 = (const MM_SECTION_SEGMENT *)y;
3435
3436 return
3437 (Segment1->VirtualAddress - Segment2->VirtualAddress) >>
3438 ((sizeof(ULONG_PTR) - sizeof(int)) * 8);
3439 }
3440
3441 /*
3442 * Ensures an image section's segments are sorted in memory
3443 */
3444 static
3445 VOID
3446 NTAPI
3447 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3448 IN ULONG Flags)
3449 {
3450 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED)
3451 {
3452 MmspAssertSegmentsSorted(ImageSectionObject);
3453 }
3454 else
3455 {
3456 qsort(ImageSectionObject->Segments,
3457 ImageSectionObject->NrSegments,
3458 sizeof(ImageSectionObject->Segments[0]),
3459 MmspCompareSegments);
3460 }
3461 }
3462
3463
3464 /*
3465 * Ensures an image section's segments don't overlap in memory and don't have
3466 * gaps and don't have a null size. We let them map to overlapping file regions,
3467 * though - that's not necessarily an error
3468 */
3469 static
3470 BOOLEAN
3471 NTAPI
3472 MmspCheckSegmentBounds
3473 (
3474 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3475 IN ULONG Flags
3476 )
3477 {
3478 ULONG i;
3479
3480 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP)
3481 {
3482 MmspAssertSegmentsNoOverlap(ImageSectionObject);
3483 return TRUE;
3484 }
3485
3486 ASSERT(ImageSectionObject->NrSegments >= 1);
3487
3488 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3489 {
3490 if(ImageSectionObject->Segments[i].Length == 0)
3491 {
3492 return FALSE;
3493 }
3494
3495 if(i > 0)
3496 {
3497 /*
3498 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3499 * page could be OK (Windows seems to be OK with them), and larger gaps
3500 * could lead to image sections spanning several discontiguous regions
3501 * (NtMapViewOfSection could then refuse to map them, and they could
3502 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3503 */
3504 if ((ImageSectionObject->Segments[i - 1].VirtualAddress +
3505 ImageSectionObject->Segments[i - 1].Length) !=
3506 ImageSectionObject->Segments[i].VirtualAddress)
3507 {
3508 return FALSE;
3509 }
3510 }
3511 }
3512
3513 return TRUE;
3514 }
3515
3516 /*
3517 * Merges and pads an image section's segments until they all are page-aligned
3518 * and have a size that is a multiple of the page size
3519 */
3520 static
3521 BOOLEAN
3522 NTAPI
3523 MmspPageAlignSegments
3524 (
3525 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3526 IN ULONG Flags
3527 )
3528 {
3529 ULONG i;
3530 ULONG LastSegment;
3531 PMM_SECTION_SEGMENT EffectiveSegment;
3532
3533 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED)
3534 {
3535 MmspAssertSegmentsPageAligned(ImageSectionObject);
3536 return TRUE;
3537 }
3538
3539 LastSegment = 0;
3540 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
3541
3542 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3543 {
3544 /*
3545 * The first segment requires special handling
3546 */
3547 if (i == 0)
3548 {
3549 ULONG_PTR VirtualAddress;
3550 ULONG_PTR VirtualOffset;
3551
3552 VirtualAddress = EffectiveSegment->VirtualAddress;
3553
3554 /* Round down the virtual address to the nearest page */
3555 EffectiveSegment->VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
3556
3557 /* Round up the virtual size to the nearest page */
3558 EffectiveSegment->Length = (ULONG)(PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length) -
3559 EffectiveSegment->VirtualAddress);
3560
3561 /* Adjust the raw address and size */
3562 VirtualOffset = VirtualAddress - EffectiveSegment->VirtualAddress;
3563
3564 if (EffectiveSegment->FileOffset < (LONG_PTR)VirtualOffset)
3565 {
3566 return FALSE;
3567 }
3568
3569 /*
3570 * Garbage in, garbage out: unaligned base addresses make the file
3571 * offset point in curious and odd places, but that's what we were
3572 * asked for
3573 */
3574 EffectiveSegment->FileOffset -= (ULONG)VirtualOffset;
3575 EffectiveSegment->RawLength += (ULONG)VirtualOffset;
3576 }
3577 else
3578 {
3579 PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
3580 ULONG_PTR EndOfEffectiveSegment;
3581
3582 EndOfEffectiveSegment = EffectiveSegment->VirtualAddress + EffectiveSegment->Length;
3583 ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
3584
3585 /*
3586 * The current segment begins exactly where the current effective
3587 * segment ended, therefore beginning a new effective segment
3588 */
3589 if (EndOfEffectiveSegment == Segment->VirtualAddress)
3590 {
3591 LastSegment ++;
3592 ASSERT(LastSegment <= i);
3593 ASSERT(LastSegment < ImageSectionObject->NrSegments);
3594
3595 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
3596
3597 if (LastSegment != i)
3598 {
3599 /*
3600 * Copy the current segment. If necessary, the effective segment
3601 * will be expanded later
3602 */
3603 *EffectiveSegment = *Segment;
3604 }
3605
3606 /*
3607 * Page-align the virtual size. We know for sure the virtual address
3608 * already is
3609 */
3610 ASSERT((EffectiveSegment->VirtualAddress % PAGE_SIZE) == 0);
3611 EffectiveSegment->Length = PAGE_ROUND_UP(EffectiveSegment->Length);
3612 }
3613 /*
3614 * The current segment is still part of the current effective segment:
3615 * extend the effective segment to reflect this
3616 */
3617 else if (EndOfEffectiveSegment > Segment->VirtualAddress)
3618 {
3619 static const ULONG FlagsToProtection[16] =
3620 {
3621 PAGE_NOACCESS,
3622 PAGE_READONLY,
3623 PAGE_READWRITE,
3624 PAGE_READWRITE,
3625 PAGE_EXECUTE_READ,
3626 PAGE_EXECUTE_READ,
3627 PAGE_EXECUTE_READWRITE,
3628 PAGE_EXECUTE_READWRITE,
3629 PAGE_WRITECOPY,
3630 PAGE_WRITECOPY,
3631 PAGE_WRITECOPY,
3632 PAGE_WRITECOPY,
3633 PAGE_EXECUTE_WRITECOPY,
3634 PAGE_EXECUTE_WRITECOPY,
3635 PAGE_EXECUTE_WRITECOPY,
3636 PAGE_EXECUTE_WRITECOPY
3637 };
3638
3639 unsigned ProtectionFlags;
3640
3641 /*
3642 * Extend the file size
3643 */
3644
3645 /* Unaligned segments must be contiguous within the file */
3646 if (Segment->FileOffset != (EffectiveSegment->FileOffset +
3647 EffectiveSegment->RawLength))
3648 {
3649 return FALSE;
3650 }
3651
3652 EffectiveSegment->RawLength += Segment->RawLength;
3653
3654 /*
3655 * Extend the virtual size
3656 */
3657 ASSERT(PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) >= EndOfEffectiveSegment);
3658
3659 EffectiveSegment->Length = (ULONG)(PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) -
3660 EffectiveSegment->VirtualAddress);
3661
3662 /*
3663 * Merge the protection
3664 */
3665 EffectiveSegment->Protection |= Segment->Protection;
3666
3667 /* Clean up redundance */
3668 ProtectionFlags = 0;
3669
3670 if(EffectiveSegment->Protection & PAGE_IS_READABLE)
3671 ProtectionFlags |= 1 << 0;
3672
3673 if(EffectiveSegment->Protection & PAGE_IS_WRITABLE)
3674 ProtectionFlags |= 1 << 1;
3675
3676 if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE)
3677 ProtectionFlags |= 1 << 2;
3678
3679 if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3680 ProtectionFlags |= 1 << 3;
3681
3682 ASSERT(ProtectionFlags < 16);
3683 EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags];
3684
3685 /* If a segment was required to be shared and cannot, fail */
3686 if(!(Segment->Protection & PAGE_IS_WRITECOPY) &&
3687 EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3688 {
3689 return FALSE;
3690 }
3691 }
3692 /*
3693 * We assume no holes between segments at this point
3694 */
3695 else
3696 {
3697 KeBugCheck(MEMORY_MANAGEMENT);
3698 }
3699 }
3700 }
3701 ImageSectionObject->NrSegments = LastSegment + 1;
3702
3703 return TRUE;
3704 }
3705
3706 NTSTATUS
3707 ExeFmtpCreateImageSection(HANDLE FileHandle,
3708 PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3709 {
3710 LARGE_INTEGER Offset;
3711 PVOID FileHeader;
3712 PVOID FileHeaderBuffer;
3713 ULONG FileHeaderSize;
3714 ULONG Flags;
3715 ULONG OldNrSegments;
3716 NTSTATUS Status;
3717 ULONG i;
3718
3719 /*
3720 * Read the beginning of the file (2 pages). Should be enough to contain
3721 * all (or most) of the headers
3722 */
3723 Offset.QuadPart = 0;
3724
3725 /* FIXME: use FileObject instead of FileHandle */
3726 Status = ExeFmtpReadFile (FileHandle,
3727 &Offset,
3728 PAGE_SIZE * 2,
3729 &FileHeader,
3730 &FileHeaderBuffer,
3731 &FileHeaderSize);
3732
3733 if (!NT_SUCCESS(Status))
3734 return Status;
3735
3736 if (FileHeaderSize == 0)
3737 {
3738 ExFreePool(FileHeaderBuffer);
3739 return STATUS_UNSUCCESSFUL;
3740 }
3741
3742 /*
3743 * Look for a loader that can handle this executable
3744 */
3745 for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i)
3746 {
3747 RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject));
3748 Flags = 0;
3749
3750 /* FIXME: use FileObject instead of FileHandle */
3751 Status = ExeFmtpLoaders[i](FileHeader,
3752 FileHeaderSize,
3753 FileHandle,
3754 ImageSectionObject,
3755 &Flags,
3756 ExeFmtpReadFile,
3757 ExeFmtpAllocateSegments);
3758
3759 if (!NT_SUCCESS(Status))
3760 {
3761 if (ImageSectionObject->Segments)
3762 {
3763 ExFreePool(ImageSectionObject->Segments);
3764 ImageSectionObject->Segments = NULL;
3765 }
3766 }
3767
3768 if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3769 break;
3770 }
3771
3772 ExFreePoolWithTag(FileHeaderBuffer, 'rXmM');
3773
3774 /*
3775 * No loader handled the format
3776 */
3777 if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3778 {
3779 Status = STATUS_INVALID_IMAGE_NOT_MZ;
3780 ASSERT(!NT_SUCCESS(Status));
3781 }
3782
3783 if (!NT_SUCCESS(Status))
3784 return Status;
3785
3786 ASSERT(ImageSectionObject->Segments != NULL);
3787
3788 /*
3789 * Some defaults
3790 */
3791 /* FIXME? are these values platform-dependent? */
3792 if(ImageSectionObject->StackReserve == 0)
3793 ImageSectionObject->StackReserve = 0x40000;
3794
3795 if(ImageSectionObject->StackCommit == 0)
3796 ImageSectionObject->StackCommit = 0x1000;
3797
3798 if(ImageSectionObject->ImageBase == 0)
3799 {
3800 if(ImageSectionObject->ImageCharacteristics & IMAGE_FILE_DLL)
3801 ImageSectionObject->ImageBase = 0x10000000;
3802 else
3803 ImageSectionObject->ImageBase = 0x00400000;
3804 }
3805
3806 /*
3807 * And now the fun part: fixing the segments
3808 */
3809
3810 /* Sort them by virtual address */
3811 MmspSortSegments(ImageSectionObject, Flags);
3812
3813 /* Ensure they don't overlap in memory */
3814 if (!MmspCheckSegmentBounds(ImageSectionObject, Flags))
3815 return STATUS_INVALID_IMAGE_FORMAT;
3816
3817 /* Ensure they are aligned */
3818 OldNrSegments = ImageSectionObject->NrSegments;
3819
3820 if (!MmspPageAlignSegments(ImageSectionObject, Flags))
3821 return STATUS_INVALID_IMAGE_FORMAT;
3822
3823 /* Trim them if the alignment phase merged some of them */
3824 if (ImageSectionObject->NrSegments < OldNrSegments)
3825 {
3826 PMM_SECTION_SEGMENT Segments;
3827 SIZE_T SizeOfSegments;
3828
3829 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments;
3830
3831 Segments = ExAllocatePoolWithTag(PagedPool,
3832 SizeOfSegments,
3833 TAG_MM_SECTION_SEGMENT);
3834
3835 if (Segments == NULL)
3836 return STATUS_INSUFFICIENT_RESOURCES;
3837
3838 RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments);
3839 ExFreePool(ImageSectionObject->Segments);
3840 ImageSectionObject->Segments = Segments;
3841 }
3842
3843 /* And finish their initialization */
3844 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3845 {
3846 ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock);
3847 ImageSectionObject->Segments[i].ReferenceCount = 1;
3848
3849 RtlZeroMemory(&ImageSectionObject->Segments[i].PageDirectory,
3850 sizeof(ImageSectionObject->Segments[i].PageDirectory));
3851 }
3852
3853 ASSERT(NT_SUCCESS(Status));
3854 return Status;
3855 }
3856
3857 NTSTATUS
3858 MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
3859 ACCESS_MASK DesiredAccess,
3860 POBJECT_ATTRIBUTES ObjectAttributes,
3861 PLARGE_INTEGER UMaximumSize,
3862 ULONG SectionPageProtection,
3863 ULONG AllocationAttributes,
3864 HANDLE FileHandle)
3865 {
3866 PROS_SECTION_OBJECT Section;
3867 NTSTATUS Status;
3868 PFILE_OBJECT FileObject;
3869 PMM_SECTION_SEGMENT SectionSegments;
3870 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3871 ULONG i;
3872 ULONG FileAccess = 0;
3873
3874 /*
3875 * Check file access required
3876 */
3877 if (SectionPageProtection & PAGE_READWRITE ||
3878 SectionPageProtection & PAGE_EXECUTE_READWRITE)
3879 {
3880 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
3881 }
3882 else
3883 {
3884 FileAccess = FILE_READ_DATA;
3885 }
3886
3887 /*
3888 * Reference the file handle
3889 */
3890 Status = ObReferenceObjectByHandle(FileHandle,
3891 FileAccess,
3892 IoFileObjectType,
3893 ExGetPreviousMode(),
3894 (PVOID*)(PVOID)&FileObject,
3895 NULL);
3896
3897 if (!NT_SUCCESS(Status))
3898 {
3899 return Status;
3900 }
3901
3902 /*
3903 * Create the section
3904 */
3905 Status = ObCreateObject (ExGetPreviousMode(),
3906 MmSectionObjectType,
3907 ObjectAttributes,
3908 ExGetPreviousMode(),
3909 NULL,
3910 sizeof(ROS_SECTION_OBJECT),
3911 0,
3912 0,
3913 (PVOID*)(PVOID)&Section);
3914 if (!NT_SUCCESS(Status))
3915 {
3916 ObDereferenceObject(FileObject);
3917 return(Status);
3918 }
3919
3920 /*
3921 * Initialize it
3922 */
3923 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
3924 Section->SectionPageProtection = SectionPageProtection;
3925 Section->AllocationAttributes = AllocationAttributes;
3926
3927 #ifndef NEWCC
3928 /*
3929 * Initialized caching for this file object if previously caching
3930 * was initialized for the same on disk file
3931 */
3932 Status = CcTryToInitializeFileCache(FileObject);
3933 #else
3934 Status = STATUS_SUCCESS;
3935 #endif
3936
3937 if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
3938 {
3939 NTSTATUS StatusExeFmt;
3940
3941 ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
3942 if (ImageSectionObject == NULL)
3943 {
3944 ObDereferenceObject(FileObject);
3945 ObDereferenceObject(Section);
3946 return(STATUS_NO_MEMORY);
3947 }
3948
3949 RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
3950
3951 StatusExeFmt = ExeFmtpCreateImageSection(FileHandle, ImageSectionObject);
3952
3953 if (!NT_SUCCESS(StatusExeFmt))
3954 {
3955 if(ImageSectionObject->Segments != NULL)
3956 ExFreePool(ImageSectionObject->Segments);
3957
3958 ExFreePool(ImageSectionObject);
3959 ObDereferenceObject(Section);
3960 ObDereferenceObject(FileObject);
3961 return(StatusExeFmt);
3962 }
3963
3964 Section->ImageSection = ImageSectionObject;
3965 ASSERT(ImageSectionObject->Segments);
3966
3967 /*
3968 * Lock the file
3969 */
3970 Status = MmspWaitForFileLock(FileObject);
3971 if (!NT_SUCCESS(Status))
3972 {
3973 ExFreePool(ImageSectionObject->Segments);
3974 ExFreePool(ImageSectionObject);
3975 ObDereferenceObject(Section);
3976 ObDereferenceObject(FileObject);
3977 return(Status);
3978 }
3979
3980 if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject,
3981 ImageSectionObject, NULL))
3982 {
3983 /*
3984 * An other thread has initialized the same image in the background
3985 */
3986 ExFreePool(ImageSectionObject->Segments);
3987 ExFreePool(ImageSectionObject);
3988 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3989 Section->ImageSection = ImageSectionObject;
3990 SectionSegments = ImageSectionObject->Segments;
3991
3992 for (i = 0; i < ImageSectionObject->NrSegments; i++)
3993 {
3994 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3995 }
3996 }
3997
3998 Status = StatusExeFmt;
3999 }
4000 else
4001 {
4002 /*
4003 * Lock the file
4004 */
4005 Status = MmspWaitForFileLock(FileObject);
4006 if (Status != STATUS_SUCCESS)
4007 {
4008 ObDereferenceObject(Section);
4009 ObDereferenceObject(FileObject);
4010 return(Status);
4011 }
4012
4013 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
4014 Section->ImageSection = ImageSectionObject;
4015 SectionSegments = ImageSectionObject->Segments;
4016
4017 /*
4018 * Otherwise just reference all the section segments
4019 */
4020 for (i = 0; i < ImageSectionObject->NrSegments; i++)
4021 {
4022 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
4023 }
4024
4025 Status = STATUS_SUCCESS;
4026 }
4027 Section->FileObject = FileObject;
4028 #ifndef NEWCC
4029 CcRosReferenceCache(FileObject);
4030 #endif
4031 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
4032 *SectionObject = Section;
4033 return(Status);
4034 }
4035
4036
4037
4038 static NTSTATUS
4039 MmMapViewOfSegment(PMMSUPPORT AddressSpace,
4040 PROS_SECTION_OBJECT Section,
4041 PMM_SECTION_SEGMENT Segment,
4042 PVOID* BaseAddress,
4043 SIZE_T ViewSize,
4044 ULONG Protect,
4045 ULONG ViewOffset,
4046 ULONG AllocationType)
4047 {
4048 PMEMORY_AREA MArea;
4049 NTSTATUS Status;
4050 PHYSICAL_ADDRESS BoundaryAddressMultiple;
4051
4052 BoundaryAddressMultiple.QuadPart = 0;
4053
4054 Status = MmCreateMemoryArea(AddressSpace,
4055 MEMORY_AREA_SECTION_VIEW,
4056 BaseAddress,
4057 ViewSize,
4058 Protect,
4059 &MArea,
4060 FALSE,
4061 AllocationType,
4062 BoundaryAddressMultiple);
4063 if (!NT_SUCCESS(Status))
4064 {
4065 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
4066 (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
4067 return(Status);
4068 }
4069
4070 ObReferenceObject((PVOID)Section);
4071
4072 MArea->Data.SectionData.Segment = Segment;
4073 MArea->Data.SectionData.Section = Section;
4074 MArea->Data.SectionData.ViewOffset = ViewOffset;
4075 MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
4076 ViewSize, 0, Protect);
4077
4078 return(STATUS_SUCCESS);
4079 }
4080
4081
4082
4083 static VOID
4084 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
4085 PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
4086 {
4087 ULONG Entry;
4088 PFILE_OBJECT FileObject;
4089 PBCB Bcb;
4090 ULONG Offset;
4091 SWAPENTRY SavedSwapEntry;
4092 PMM_PAGEOP PageOp;
4093 NTSTATUS Status;
4094 PROS_SECTION_OBJECT Section;
4095 PMM_SECTION_SEGMENT Segment;
4096 PMMSUPPORT AddressSpace;
4097 PEPROCESS Process;
4098
4099 AddressSpace = (PMMSUPPORT)Context;
4100 Process = MmGetAddressSpaceOwner(AddressSpace);
4101
4102 Address = (PVOID)PAGE_ROUND_DOWN(Address);
4103
4104 Offset = (ULONG)(((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress) +
4105 MemoryArea->Data.SectionData.ViewOffset);
4106
4107 Section = MemoryArea->Data.SectionData.Section;
4108 Segment = MemoryArea->Data.SectionData.Segment;
4109
4110 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
4111
4112 while (PageOp)
4113 {
4114 MmUnlockSectionSegment(Segment);
4115 MmUnlockAddressSpace(AddressSpace);
4116
4117 Status = MmspWaitForPageOpCompletionEvent(PageOp);
4118 if (Status != STATUS_SUCCESS)
4119 {
4120 DPRINT1("Failed to wait for page op, status = %x\n", Status);
4121 KeBugCheck(MEMORY_MANAGEMENT);
4122 }
4123
4124 MmLockAddressSpace(AddressSpace);
4125 MmLockSectionSegment(Segment);
4126 MmspCompleteAndReleasePageOp(PageOp);
4127 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
4128 }
4129
4130 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
4131
4132 /*
4133 * For a dirty, datafile, non-private page mark it as dirty in the
4134 * cache manager.
4135 */
4136 if (Segment->Flags & MM_DATAFILE_SEGMENT)
4137 {
4138 if (Page == PFN_FROM_SSE(Entry) && Dirty)
4139 {
4140 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
4141 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
4142 #ifndef NEWCC
4143 CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
4144 #endif
4145 ASSERT(SwapEntry == 0);
4146 }
4147 }
4148
4149 if (SwapEntry != 0)
4150 {
4151 /*
4152 * Sanity check
4153 */
4154 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
4155 {
4156 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4157 KeBugCheck(MEMORY_MANAGEMENT);
4158 }
4159 MmFreeSwapPage(SwapEntry);
4160 }
4161 else if (Page != 0)
4162 {
4163 if (IS_SWAP_FROM_SSE(Entry) ||
4164 Page != PFN_FROM_SSE(Entry))
4165 {
4166 /*
4167 * Sanity check
4168 */
4169 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
4170 {
4171 DPRINT1("Found a private page in a pagefile section.\n");
4172 KeBugCheck(MEMORY_MANAGEMENT);
4173 }
4174 /*
4175 * Just dereference private pages
4176 */
4177 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
4178 if (SavedSwapEntry != 0)
4179 {
4180 MmFreeSwapPage(SavedSwapEntry);
4181 MmSetSavedSwapEntryPage(Page, 0);
4182 }
4183 MmDeleteRmap(Page, Process, Address);
4184 MmReleasePageMemoryConsumer(MC_USER, Page);
4185 }
4186 else
4187 {
4188 MmDeleteRmap(Page, Process, Address);
4189 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty, FALSE);
4190 }
4191 }
4192 }
4193
4194 static NTSTATUS
4195 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace,
4196 PVOID BaseAddress)
4197 {
4198 NTSTATUS Status;
4199 PMEMORY_AREA MemoryArea;
4200 PROS_SECTION_OBJECT Section;
4201 PMM_SECTION_SEGMENT Segment;
4202 PLIST_ENTRY CurrentEntry;
4203 PMM_REGION CurrentRegion;
4204 PLIST_ENTRY RegionListHead;
4205
4206 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4207 BaseAddress);
4208 if (MemoryArea == NULL)
4209 {
4210 return(STATUS_UNSUCCESSFUL);
4211 }
4212
4213 MemoryArea->DeleteInProgress = TRUE;
4214 Section = MemoryArea->Data.SectionData.Section;
4215 Segment = MemoryArea->Data.SectionData.Segment;
4216
4217 MmLockSectionSegment(Segment);
4218
4219 RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
4220 while (!IsListEmpty(RegionListHead))
4221 {
4222 CurrentEntry = RemoveHeadList(RegionListHead);
4223 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
4224 ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION);
4225 }
4226
4227 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
4228 {
4229 Status = MmFreeMemoryArea(AddressSpace,
4230 MemoryArea,
4231 NULL,
4232 NULL);
4233 }
4234 else
4235 {
4236 Status = MmFreeMemoryArea(AddressSpace,
4237 MemoryArea,
4238 MmFreeSectionPage,
4239 AddressSpace);
4240 }
4241 MmUnlockSectionSegment(Segment);
4242 ObDereferenceObject(Section);
4243 return(Status);
4244 }
4245
4246 /*
4247 * @implemented
4248 */
4249 NTSTATUS NTAPI
4250 MmUnmapViewOfSection(PEPROCESS Process,
4251 PVOID BaseAddress)
4252 {
4253 NTSTATUS Status;
4254 PMEMORY_AREA MemoryArea;
4255 PMMSUPPORT AddressSpace;
4256 PROS_SECTION_OBJECT Section;
4257 PMM_PAGEOP PageOp;
4258 ULONG_PTR Offset;
4259 PVOID ImageBaseAddress = 0;
4260
4261 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4262 Process, BaseAddress);
4263
4264 ASSERT(Process);
4265
4266 AddressSpace = &Process->Vm;
4267
4268 MmLockAddressSpace(AddressSpace);
4269 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4270 BaseAddress);
4271 if (MemoryArea == NULL ||
4272 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW ||
4273 MemoryArea->DeleteInProgress)
4274 {
4275 MmUnlockAddressSpace(AddressSpace);
4276 return STATUS_NOT_MAPPED_VIEW;
4277 }
4278
4279 MemoryArea->DeleteInProgress = TRUE;
4280
4281 while (MemoryArea->PageOpCount)
4282 {
4283 Offset = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress);
4284
4285 while (Offset)
4286 {
4287 Offset -= PAGE_SIZE;
4288 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL,
4289 MemoryArea->Data.SectionData.Segment,
4290 (ULONG)Offset + MemoryArea->Data.SectionData.ViewOffset);
4291 if (PageOp)
4292 {
4293 MmUnlockAddressSpace(AddressSpace);
4294 Status = MmspWaitForPageOpCompletionEvent(PageOp);
4295 if (Status != STATUS_SUCCESS)
4296 {
4297 DPRINT1("Failed to wait for page op, status = %x\n", Status);
4298 KeBugCheck(MEMORY_MANAGEMENT);
4299 }
4300 MmLockAddressSpace(AddressSpace);
4301 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4302 BaseAddress);
4303 if (MemoryArea == NULL ||
4304 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
4305 {
4306 MmUnlockAddressSpace(AddressSpace);
4307 return STATUS_NOT_MAPPED_VIEW;
4308 }
4309 break;
4310 }
4311 }
4312 }
4313
4314 Section = MemoryArea->Data.SectionData.Section;
4315
4316 if (Section->AllocationAttributes & SEC_IMAGE)
4317 {
4318 ULONG i;
4319 ULONG NrSegments;
4320 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4321 PMM_SECTION_SEGMENT SectionSegments;
4322 PMM_SECTION_SEGMENT Segment;
4323
4324 Segment = MemoryArea->Data.SectionData.Segment;
4325 ImageSectionObject = Section->ImageSection;
4326 SectionSegments = ImageSectionObject->Segments;
4327 NrSegments = ImageSectionObject->NrSegments;
4328
4329 /* Search for the current segment within the section segments
4330 * and calculate the image base address */
4331 for (i = 0; i < NrSegments; i++)
4332 {
4333 if (Segment == &SectionSegments[i])
4334 {
4335 ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress;
4336 break;
4337 }
4338 }
4339 if (i >= NrSegments)
4340 {
4341 KeBugCheck(MEMORY_MANAGEMENT);
4342 }
4343
4344 for (i = 0; i < NrSegments; i++)
4345 {
4346 PVOID SBaseAddress = (PVOID)
4347 ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
4348
4349 Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
4350 }
4351 }
4352 else
4353 {
4354 Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
4355 }
4356
4357 MmUnlockAddressSpace(AddressSpace);
4358
4359 /* Notify debugger */
4360 if (ImageBaseAddress) DbgkUnMapViewOfSection(ImageBaseAddress);
4361
4362 return(STATUS_SUCCESS);
4363 }
4364
4365
4366
4367
4368 /**
4369 * Queries the information of a section object.
4370 *
4371 * @param SectionHandle
4372 * Handle to the section object. It must be opened with SECTION_QUERY
4373 * access.
4374 * @param SectionInformationClass
4375 * Index to a certain information structure. Can be either
4376 * SectionBasicInformation or SectionImageInformation. The latter
4377 * is valid only for sections that were created with the SEC_IMAGE
4378 * flag.
4379 * @param SectionInformation
4380 * Caller supplies storage for resulting information.
4381 * @param Length
4382 * Size of the supplied storage.
4383 * @param ResultLength
4384 * Data written.
4385 *
4386 * @return Status.
4387 *
4388 * @implemented
4389 */
4390 NTSTATUS NTAPI
4391 NtQuerySection(IN HANDLE SectionHandle,
4392 IN SECTION_INFORMATION_CLASS SectionInformationClass,
4393 OUT PVOID SectionInformation,
4394 IN SIZE_T SectionInformationLength,
4395 OUT PSIZE_T ResultLength OPTIONAL)
4396 {
4397 PROS_SECTION_OBJECT Section;
4398 KPROCESSOR_MODE PreviousMode;
4399 NTSTATUS Status;
4400 PAGED_CODE();
4401
4402 PreviousMode = ExGetPreviousMode();
4403
4404 Status = DefaultQueryInfoBufferCheck(SectionInformationClass,
4405 ExSectionInfoClass,
4406 sizeof(ExSectionInfoClass) / sizeof(ExSectionInfoClass[0]),
4407 SectionInformation,
4408 (ULONG)SectionInformationLength,
4409 NULL,
4410 ResultLength,
4411 PreviousMode);
4412
4413 if(!NT_SUCCESS(Status))
4414 {
4415 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status);
4416 return Status;
4417 }
4418
4419 Status = ObReferenceObjectByHandle(SectionHandle,
4420 SECTION_QUERY,
4421 MmSectionObjectType,
4422 PreviousMode,
4423 (PVOID*)(PVOID)&Section,
4424 NULL);
4425 if (NT_SUCCESS(Status))
4426 {
4427 switch (SectionInformationClass)
4428 {
4429 case SectionBasicInformation:
4430 {
4431 PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
4432
4433 _SEH2_TRY
4434 {
4435 Sbi->Attributes = Section->AllocationAttributes;
4436 if (Section->AllocationAttributes & SEC_IMAGE)
4437 {
4438 Sbi->BaseAddress = 0;
4439 Sbi->Size.QuadPart = 0;
4440 }
4441 else
4442 {
4443 Sbi->BaseAddress = (PVOID)Section->Segment->VirtualAddress;
4444 Sbi->Size.QuadPart = Section->Segment->Length;
4445 }
4446
4447 if (ResultLength != NULL)
4448 {
4449 *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
4450 }
4451 Status = STATUS_SUCCESS;
4452 }
4453 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4454 {
4455 Status = _SEH2_GetExceptionCode();
4456 }
4457 _SEH2_END;
4458
4459 break;
4460 }
4461
4462 case SectionImageInformation:
4463 {
4464 PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
4465
4466 _SEH2_TRY
4467 {
4468 memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
4469 if (Section->AllocationAttributes & SEC_IMAGE)
4470 {
4471 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4472 ImageSectionObject = Section->ImageSection;
4473
4474 Sii->TransferAddress = (PVOID)ImageSectionObject->EntryPoint;
4475 Sii->MaximumStackSize = ImageSectionObject->StackReserve;
4476 Sii->CommittedStackSize = ImageSectionObject->StackCommit;
4477 Sii->SubSystemType = ImageSectionObject->Subsystem;
4478 Sii->SubSystemMinorVersion = ImageSectionObject->MinorSubsystemVersion;
4479 Sii->SubSystemMajorVersion = ImageSectionObject->MajorSubsystemVersion;
4480 Sii->ImageCharacteristics = ImageSectionObject->ImageCharacteristics;
4481 Sii->Machine = ImageSectionObject->Machine;
4482 Sii->ImageContainsCode = ImageSectionObject->Executable;
4483 }
4484
4485 if (ResultLength != NULL)
4486 {
4487 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
4488 }
4489 Status = STATUS_SUCCESS;
4490 }
4491 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4492 {
4493 Status = _SEH2_GetExceptionCode();
4494 }
4495 _SEH2_END;
4496
4497 break;
4498 }
4499 }
4500
4501 ObDereferenceObject(Section);
4502 }
4503
4504 return(Status);
4505 }
4506
4507 /**********************************************************************
4508 * NAME EXPORTED
4509 * MmMapViewOfSection
4510 *
4511 * DESCRIPTION
4512 * Maps a view of a section into the virtual address space of a
4513 * process.
4514 *
4515 * ARGUMENTS
4516 * Section
4517 * Pointer to the section object.
4518 *
4519 * ProcessHandle
4520 * Pointer to the process.
4521 *
4522 * BaseAddress
4523 * Desired base address (or NULL) on entry;
4524 * Actual base address of the view on exit.
4525 *
4526 * ZeroBits
4527 * Number of high order address bits that must be zero.
4528 *
4529 * CommitSize
4530 * Size in bytes of the initially committed section of
4531 * the view.
4532 *
4533 * SectionOffset
4534 * Offset in bytes from the beginning of the section
4535 * to the beginning of the view.
4536 *
4537 * ViewSize
4538 * Desired length of map (or zero to map all) on entry
4539 * Actual length mapped on exit.
4540 *
4541 * InheritDisposition
4542 * Specified how the view is to be shared with
4543 * child processes.
4544 *
4545 * AllocationType
4546 * Type of allocation for the pages.
4547 *
4548 * Protect
4549 * Protection for the committed region of the view.
4550 *
4551 * RETURN VALUE
4552 * Status.
4553 *
4554 * @implemented
4555 */
4556 NTSTATUS NTAPI
4557 MmMapViewOfSection(IN PVOID SectionObject,
4558 IN PEPROCESS Process,
4559 IN OUT PVOID *BaseAddress,
4560 IN ULONG_PTR ZeroBits,
4561 IN SIZE_T CommitSize,
4562 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
4563 IN OUT PSIZE_T ViewSize,
4564 IN SECTION_INHERIT InheritDisposition,
4565 IN ULONG AllocationType,
4566 IN ULONG Protect)
4567 {
4568 PROS_SECTION_OBJECT Section;
4569 PMMSUPPORT AddressSpace;
4570 ULONG ViewOffset;
4571 NTSTATUS Status = STATUS_SUCCESS;
4572 BOOLEAN NotAtBase = FALSE;
4573
4574 if ((ULONG_PTR)SectionObject & 1)
4575 {
4576 return MmMapViewOfArm3Section((PVOID)((ULONG_PTR)SectionObject & ~1),
4577 Process,
4578 BaseAddress,
4579 ZeroBits,
4580 CommitSize,
4581 SectionOffset,
4582 ViewSize,
4583 InheritDisposition,
4584 AllocationType,
4585 Protect);
4586 }
4587
4588 ASSERT(Process);
4589
4590 if (!Protect || Protect & ~PAGE_FLAGS_VALID_FOR_SECTION)
4591 {
4592 return STATUS_INVALID_PAGE_PROTECTION;
4593 }
4594
4595
4596 Section = (PROS_SECTION_OBJECT)SectionObject;
4597 AddressSpace = &Process->Vm;
4598
4599 AllocationType |= (Section->AllocationAttributes & SEC_NO_CHANGE);
4600
4601 MmLockAddressSpace(AddressSpace);
4602
4603 if (Section->AllocationAttributes & SEC_IMAGE)
4604 {
4605 ULONG i;
4606 ULONG NrSegments;
4607 ULONG_PTR ImageBase;
4608 SIZE_T ImageSize;
4609 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4610 PMM_SECTION_SEGMENT SectionSegments;
4611
4612 ImageSectionObject = Section->ImageSection;
4613 SectionSegments = ImageSectionObject->Segments;
4614 NrSegments = ImageSectionObject->NrSegments;
4615
4616
4617 ImageBase = (ULONG_PTR)*BaseAddress;
4618 if (ImageBase == 0)
4619 {
4620 ImageBase = ImageSectionObject->ImageBase;
4621 }
4622
4623 ImageSize = 0;
4624 for (i = 0; i < NrSegments; i++)
4625 {
4626 ULONG_PTR MaxExtent;
4627 MaxExtent = (ULONG_PTR)SectionSegments[i].VirtualAddress +
4628 SectionSegments[i].Length;
4629 ImageSize = max(ImageSize, MaxExtent);
4630 }
4631
4632 ImageSectionObject->ImageSize = (ULONG)ImageSize;
4633
4634 /* Check for an illegal base address */
4635 if ((ImageBase + ImageSize) > (ULONG_PTR)MmHighestUserAddress)
4636 {
4637 ImageBase = PAGE_ROUND_DOWN((ULONG_PTR)MmHighestUserAddress - ImageSize);
4638 }
4639
4640 /* Check there is enough space to map the section at that point. */
4641 if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
4642 PAGE_ROUND_UP(ImageSize)) != NULL)
4643 {
4644 /* Fail if the user requested a fixed base address. */
4645 if ((*BaseAddress) != NULL)
4646 {
4647 MmUnlockAddressSpace(AddressSpace);
4648 return(STATUS_UNSUCCESSFUL);
4649 }
4650 /* Otherwise find a gap to map the image. */
4651 ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE);
4652 if (ImageBase == 0)
4653 {
4654 MmUnlockAddressSpace(AddressSpace);
4655 return(STATUS_UNSUCCESSFUL);
4656 }
4657 /* Remember that we loaded image at a different base address */
4658 NotAtBase = TRUE;
4659 }
4660
4661 for (i = 0; i < NrSegments; i++)
4662 {
4663 PVOID SBaseAddress = (PVOID)
4664 ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
4665 MmLockSectionSegment(&SectionSegments[i]);
4666 Status = MmMapViewOfSegment(AddressSpace,
4667 Section,
4668 &SectionSegments[i],
4669 &SBaseAddress,
4670 SectionSegments[i].Length,
4671 SectionSegments[i].Protection,
4672 0,
4673 0);
4674 MmUnlockSectionSegment(&SectionSegments[i]);
4675 if (!NT_SUCCESS(Status))
4676 {
4677 MmUnlockAddressSpace(AddressSpace);
4678 return(Status);
4679 }
4680 }
4681
4682 *BaseAddress = (PVOID)ImageBase;
4683 *ViewSize = ImageSize;
4684 }
4685 else
4686 {
4687 /* check for write access */
4688 if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) &&
4689 !(Section->SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)))
4690 {
4691 MmUnlockAddressSpace(AddressSpace);
4692 return STATUS_SECTION_PROTECTION;
4693 }
4694 /* check for read access */
4695 if ((Protect & (PAGE_READONLY|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_WRITECOPY)) &&
4696 !(Section->SectionPageProtection & (PAGE_READONLY|PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4697 {
4698 MmUnlockAddressSpace(AddressSpace);
4699 return STATUS_SECTION_PROTECTION;
4700 }
4701 /* check for execute access */
4702 if ((Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)) &&
4703 !(Section->SectionPageProtection & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4704 {
4705 MmUnlockAddressSpace(AddressSpace);
4706 return STATUS_SECTION_PROTECTION;
4707 }
4708
4709 if (ViewSize == NULL)
4710 {
4711 /* Following this pointer would lead to us to the dark side */
4712 /* What to do? Bugcheck? Return status? Do the mambo? */
4713 KeBugCheck(MEMORY_MANAGEMENT);
4714 }
4715
4716 if (SectionOffset == NULL)
4717 {
4718 ViewOffset = 0;
4719 }
4720 else
4721 {
4722 ViewOffset = SectionOffset->u.LowPart;
4723 }
4724
4725 if ((ViewOffset % PAGE_SIZE) != 0)
4726 {
4727 MmUnlockAddressSpace(AddressSpace);
4728 return(STATUS_MAPPED_ALIGNMENT);
4729 }
4730
4731 if ((*ViewSize) == 0)
4732 {
4733 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4734 }
4735 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
4736 {
4737 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4738 }
4739
4740 *ViewSize = PAGE_ROUND_UP(*ViewSize);
4741
4742 MmLockSectionSegment(Section->Segment);
4743 Status = MmMapViewOfSegment(AddressSpace,
4744 Section,
4745 Section->Segment,
4746 BaseAddress,
4747 *ViewSize,
4748 Protect,
4749 ViewOffset,
4750 AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE));
4751 MmUnlockSectionSegment(Section->Segment);
4752 if (!NT_SUCCESS(Status))
4753 {
4754 MmUnlockAddressSpace(AddressSpace);
4755 return(Status);
4756 }
4757 }
4758
4759 MmUnlockAddressSpace(AddressSpace);
4760
4761 if (NotAtBase)
4762 Status = STATUS_IMAGE_NOT_AT_BASE;
4763 else
4764 Status = STATUS_SUCCESS;
4765
4766 return Status;
4767 }
4768
4769 /*
4770 * @unimplemented
4771 */
4772 BOOLEAN NTAPI
4773 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4774 IN PLARGE_INTEGER NewFileSize)
4775 {
4776 /* Check whether an ImageSectionObject exists */
4777 if (SectionObjectPointer->ImageSectionObject != NULL)
4778 {
4779 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4780 return FALSE;
4781 }
4782
4783 if (SectionObjectPointer->DataSectionObject != NULL)
4784 {
4785 PMM_SECTION_SEGMENT Segment;
4786
4787 Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->
4788 DataSectionObject;
4789
4790 if (Segment->ReferenceCount != 0)
4791 {
4792 /* Check size of file */
4793 if (SectionObjectPointer->SharedCacheMap)
4794 {
4795 PBCB Bcb = SectionObjectPointer->SharedCacheMap;
4796 if (NewFileSize->QuadPart <= Bcb->FileSize.QuadPart)
4797 {
4798 return FALSE;
4799 }
4800 }
4801 }
4802 else
4803 {
4804 /* Something must gone wrong
4805 * how can we have a Section but no
4806 * reference? */
4807 DPRINT("ERROR: DataSectionObject without reference!\n");
4808 }
4809 }
4810
4811 DPRINT("FIXME: didn't check for outstanding write probes\n");
4812
4813 return TRUE;
4814 }
4815
4816
4817
4818
4819 /*
4820 * @implemented
4821 */
4822 BOOLEAN NTAPI
4823 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4824 IN MMFLUSH_TYPE FlushType)
4825 {
4826 switch(FlushType)
4827 {
4828 case MmFlushForDelete:
4829 if (SectionObjectPointer->ImageSectionObject ||
4830 SectionObjectPointer->DataSectionObject)
4831 {
4832 return FALSE;
4833 }
4834 #ifndef NEWCC
4835 CcRosSetRemoveOnClose(SectionObjectPointer);
4836 #endif
4837 return TRUE;
4838 case MmFlushForWrite:
4839 break;
4840 }
4841 return FALSE;
4842 }
4843
4844 /*
4845 * @implemented
4846 */
4847 NTSTATUS NTAPI
4848 MmMapViewInSystemSpace (IN PVOID SectionObject,
4849 OUT PVOID * MappedBase,
4850 IN OUT PSIZE_T ViewSize)
4851 {
4852 PROS_SECTION_OBJECT Section;
4853 PMMSUPPORT AddressSpace;
4854 NTSTATUS Status;
4855 PAGED_CODE();
4856
4857 if ((ULONG_PTR)SectionObject & 1)
4858 {
4859 extern PVOID MmSession;
4860 return MiMapViewInSystemSpace((PVOID)((ULONG_PTR)SectionObject & ~1),
4861 &MmSession,
4862 MappedBase,
4863 ViewSize);
4864 }
4865
4866 DPRINT("MmMapViewInSystemSpace() called\n");
4867
4868 Section = (PROS_SECTION_OBJECT)SectionObject;
4869 AddressSpace = MmGetKernelAddressSpace();
4870
4871 MmLockAddressSpace(AddressSpace);
4872
4873
4874 if ((*ViewSize) == 0)
4875 {
4876 (*ViewSize) = Section->MaximumSize.u.LowPart;
4877 }
4878 else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
4879 {
4880 (*ViewSize) = Section->MaximumSize.u.LowPart;
4881 }
4882
4883 MmLockSectionSegment(Section->Segment);
4884
4885
4886 Status = MmMapViewOfSegment(AddressSpace,
4887 Section,
4888 Section->Segment,
4889 MappedBase,
4890 *ViewSize,
4891 PAGE_READWRITE,
4892 0,
4893 0);
4894
4895 MmUnlockSectionSegment(Section->Segment);
4896 MmUnlockAddressSpace(AddressSpace);
4897
4898 return Status;
4899 }
4900
4901 /*
4902 * @implemented
4903 */
4904 NTSTATUS NTAPI
4905 MmUnmapViewInSystemSpace (IN PVOID MappedBase)
4906 {
4907 PMMSUPPORT AddressSpace;
4908 NTSTATUS Status;
4909
4910 DPRINT("MmUnmapViewInSystemSpace() called\n");
4911
4912 AddressSpace = MmGetKernelAddressSpace();
4913
4914 MmLockAddressSpace(AddressSpace);
4915
4916 Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
4917
4918 MmUnlockAddressSpace(AddressSpace);
4919
4920 return Status;
4921 }
4922
4923
4924 /**********************************************************************
4925 * NAME EXPORTED
4926 * MmCreateSection@
4927 *
4928 * DESCRIPTION
4929 * Creates a section object.
4930 *
4931 * ARGUMENTS
4932 * SectionObject (OUT)
4933 * Caller supplied storage for the resulting pointer
4934 * to a SECTION_OBJECT instance;
4935 *
4936 * DesiredAccess
4937 * Specifies the desired access to the section can be a
4938 * combination of:
4939 * STANDARD_RIGHTS_REQUIRED |
4940 * SECTION_QUERY |
4941 * SECTION_MAP_WRITE |
4942 * SECTION_MAP_READ |
4943 * SECTION_MAP_EXECUTE
4944 *
4945 * ObjectAttributes [OPTIONAL]
4946 * Initialized attributes for the object can be used
4947 * to create a named section;
4948 *
4949 * MaximumSize
4950 * Maximizes the size of the memory section. Must be
4951 * non-NULL for a page-file backed section.
4952 * If value specified for a mapped file and the file is
4953 * not large enough, file will be extended.
4954 *
4955 * SectionPageProtection
4956 * Can be a combination of:
4957 * PAGE_READONLY |
4958 * PAGE_READWRITE |
4959 * PAGE_WRITEONLY |
4960 * PAGE_WRITECOPY
4961 *
4962 * AllocationAttributes
4963 * Can be a combination of:
4964 * SEC_IMAGE |
4965 * SEC_RESERVE
4966 *
4967 * FileHandle
4968 * Handle to a file to create a section mapped to a file
4969 * instead of a memory backed section;
4970 *
4971 * File
4972 * Unknown.
4973 *
4974 * RETURN VALUE
4975 * Status.
4976 *
4977 * @implemented
4978 */
4979 NTSTATUS NTAPI
4980 MmCreateSection (OUT PVOID * Section,
4981 IN ACCESS_MASK DesiredAccess,
4982 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
4983 IN PLARGE_INTEGER MaximumSize,
4984 IN ULONG SectionPageProtection,
4985 IN ULONG AllocationAttributes,
4986 IN HANDLE FileHandle OPTIONAL,
4987 IN PFILE_OBJECT File OPTIONAL)
4988 {
4989 ULONG Protection;
4990 PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section;
4991
4992 /* Check if an ARM3 section is being created instead */
4993 if (AllocationAttributes & 1)
4994 {
4995 DPRINT1("arm 3 path\n");
4996 return MmCreateArm3Section(Section,
4997 DesiredAccess,
4998 ObjectAttributes,
4999 MaximumSize,
5000 SectionPageProtection,
5001 AllocationAttributes &~ 1,
5002 FileHandle,
5003 File);
5004 }
5005
5006 /*
5007 * Check the protection
5008 */
5009 Protection = SectionPageProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
5010 if (Protection != PAGE_READONLY &&
5011 Protection != PAGE_READWRITE &&
5012 Protection != PAGE_WRITECOPY &&
5013 Protection != PAGE_EXECUTE &&
5014 Protection != PAGE_EXECUTE_READ &&
5015 Protection != PAGE_EXECUTE_READWRITE &&
5016 Protection != PAGE_EXECUTE_WRITECOPY)
5017 {
5018 return STATUS_INVALID_PAGE_PROTECTION;
5019 }
5020
5021 if (AllocationAttributes & SEC_IMAGE)
5022 {
5023 return(MmCreateImageSection(SectionObject,
5024 DesiredAccess,
5025 ObjectAttributes,
5026 MaximumSize,
5027 SectionPageProtection,
5028 AllocationAttributes,
5029 FileHandle));
5030 }
5031
5032 if (FileHandle != NULL)
5033 {
5034 return(MmCreateDataFileSection(SectionObject,
5035 DesiredAccess,
5036 ObjectAttributes,
5037 MaximumSize,
5038 SectionPageProtection,
5039 AllocationAttributes,
5040 FileHandle));
5041 }
5042
5043 return(MmCreatePageFileSection(SectionObject,
5044 DesiredAccess,
5045 ObjectAttributes,
5046 MaximumSize,
5047 SectionPageProtection,
5048 AllocationAttributes));
5049 }
5050
5051
5052
5053 /* EOF */