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