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