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