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