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