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