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