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