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