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