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