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