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