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