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