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