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