[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / mm / section.c
1 /*
2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 *
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
22 *
23 * PROGRAMMERS: Rex Jolliff
24 * David Welch
25 * Eric Kohl
26 * Emanuele Aliberti
27 * Eugene Ingerman
28 * Casper Hornstrup
29 * KJK::Hyperion
30 * Guido de Jong
31 * Ge van Geldorp
32 * Royce Mitchell III
33 * Filip Navara
34 * Aleksey Bragin
35 * Jason Filby
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
38 * Mike Nordell
39 * Alex Ionescu
40 * Gregor Anich
41 * Steven Edwards
42 * Herve Poussineau
43 */
44
45 /* INCLUDES *****************************************************************/
46
47 #include <ntoskrnl.h>
48 #include "../cache/newcc.h"
49 #include "../cache/section/newmm.h"
50 #define NDEBUG
51 #include <debug.h>
52 #include <reactos/exeformat.h>
53
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
57 #endif
58
59 #include "ARM3/miarm.h"
60
61 #undef MmSetPageEntrySectionSegment
62 #define MmSetPageEntrySectionSegment(S,O,E) do { \
63 DPRINT("SetPageEntrySectionSegment(old,%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 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
1375 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
1376 */
1377 Status = MmCreateVirtualMapping(Process,
1378 PAddress,
1379 Attributes,
1380 &Page,
1381 1);
1382 if (!NT_SUCCESS(Status))
1383 {
1384 DPRINT1("Unable to create virtual mapping\n");
1385 KeBugCheck(MEMORY_MANAGEMENT);
1386 }
1387 MmInsertRmap(Page, Process, Address);
1388 }
1389 MmUnlockSectionSegment(Segment);
1390 PageOp->Status = STATUS_SUCCESS;
1391 MmspCompleteAndReleasePageOp(PageOp);
1392 DPRINT("Address 0x%.8X\n", Address);
1393 return(STATUS_SUCCESS);
1394 }
1395
1396 HasSwapEntry = MmIsPageSwapEntry(Process, Address);
1397 if (HasSwapEntry)
1398 {
1399 /*
1400 * Must be private page we have swapped out.
1401 */
1402 SWAPENTRY SwapEntry;
1403
1404 /*
1405 * Sanity check
1406 */
1407 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
1408 {
1409 DPRINT1("Found a swaped out private page in a pagefile section.\n");
1410 KeBugCheck(MEMORY_MANAGEMENT);
1411 }
1412
1413 MmUnlockSectionSegment(Segment);
1414 MmDeletePageFileMapping(Process, Address, &SwapEntry);
1415
1416 MmUnlockAddressSpace(AddressSpace);
1417 MI_SET_USAGE(MI_USAGE_SECTION);
1418 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1419 if (!Process) MI_SET_PROCESS2("Kernel Section");
1420 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1421 if (!NT_SUCCESS(Status))
1422 {
1423 KeBugCheck(MEMORY_MANAGEMENT);
1424 }
1425
1426 Status = MmReadFromSwapPage(SwapEntry, Page);
1427 if (!NT_SUCCESS(Status))
1428 {
1429 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
1430 KeBugCheck(MEMORY_MANAGEMENT);
1431 }
1432 MmLockAddressSpace(AddressSpace);
1433 Status = MmCreateVirtualMapping(Process,
1434 Address,
1435 Region->Protect,
1436 &Page,
1437 1);
1438 if (!NT_SUCCESS(Status))
1439 {
1440 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1441 KeBugCheck(MEMORY_MANAGEMENT);
1442 return(Status);
1443 }
1444
1445 /*
1446 * Store the swap entry for later use.
1447 */
1448 MmSetSavedSwapEntryPage(Page, SwapEntry);
1449
1450 /*
1451 * Add the page to the process's working set
1452 */
1453 MmInsertRmap(Page, Process, Address);
1454 /*
1455 * Finish the operation
1456 */
1457 PageOp->Status = STATUS_SUCCESS;
1458 MmspCompleteAndReleasePageOp(PageOp);
1459 DPRINT("Address 0x%.8X\n", Address);
1460 return(STATUS_SUCCESS);
1461 }
1462
1463 /*
1464 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1465 */
1466 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1467 {
1468 MmUnlockSectionSegment(Segment);
1469 /*
1470 * Just map the desired physical page
1471 */
1472 Page = Offset.QuadPart >> PAGE_SHIFT;
1473 Status = MmCreateVirtualMappingUnsafe(Process,
1474 PAddress,
1475 Region->Protect,
1476 &Page,
1477 1);
1478 if (!NT_SUCCESS(Status))
1479 {
1480 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1481 KeBugCheck(MEMORY_MANAGEMENT);
1482 return(Status);
1483 }
1484
1485 /*
1486 * Cleanup and release locks
1487 */
1488 PageOp->Status = STATUS_SUCCESS;
1489 MmspCompleteAndReleasePageOp(PageOp);
1490 DPRINT("Address 0x%.8X\n", Address);
1491 return(STATUS_SUCCESS);
1492 }
1493
1494 /*
1495 * Map anonymous memory for BSS sections
1496 */
1497 if (Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
1498 {
1499 MmUnlockSectionSegment(Segment);
1500 MI_SET_USAGE(MI_USAGE_SECTION);
1501 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1502 if (!Process) MI_SET_PROCESS2("Kernel Section");
1503 Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
1504 if (!NT_SUCCESS(Status))
1505 {
1506 MmUnlockAddressSpace(AddressSpace);
1507 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1508 MmLockAddressSpace(AddressSpace);
1509 }
1510 if (!NT_SUCCESS(Status))
1511 {
1512 KeBugCheck(MEMORY_MANAGEMENT);
1513 }
1514 Status = MmCreateVirtualMapping(Process,
1515 PAddress,
1516 Region->Protect,
1517 &Page,
1518 1);
1519 if (!NT_SUCCESS(Status))
1520 {
1521 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1522 KeBugCheck(MEMORY_MANAGEMENT);
1523 return(Status);
1524 }
1525 MmInsertRmap(Page, Process, Address);
1526
1527 /*
1528 * Cleanup and release locks
1529 */
1530 PageOp->Status = STATUS_SUCCESS;
1531 MmspCompleteAndReleasePageOp(PageOp);
1532 DPRINT("Address 0x%.8X\n", Address);
1533 return(STATUS_SUCCESS);
1534 }
1535
1536 /*
1537 * Get the entry corresponding to the offset within the section
1538 */
1539 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
1540
1541 if (Entry == 0)
1542 {
1543 /*
1544 * If the entry is zero (and it can't change because we have
1545 * locked the segment) then we need to load the page.
1546 */
1547
1548 /*
1549 * Release all our locks and read in the page from disk
1550 */
1551 MmUnlockSectionSegment(Segment);
1552 MmUnlockAddressSpace(AddressSpace);
1553
1554 if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
1555 (Offset.QuadPart >= PAGE_ROUND_UP(Segment->RawLength.QuadPart) && Section->AllocationAttributes & SEC_IMAGE))
1556 {
1557 MI_SET_USAGE(MI_USAGE_SECTION);
1558 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1559 if (!Process) MI_SET_PROCESS2("Kernel Section");
1560 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1561 if (!NT_SUCCESS(Status))
1562 {
1563 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
1564 }
1565
1566 }
1567 else
1568 {
1569 Status = MiReadPage(MemoryArea, Offset.QuadPart, &Page);
1570 if (!NT_SUCCESS(Status))
1571 {
1572 DPRINT1("MiReadPage failed (Status %x)\n", Status);
1573 }
1574 }
1575 if (!NT_SUCCESS(Status))
1576 {
1577 /*
1578 * FIXME: What do we know in this case?
1579 */
1580 /*
1581 * Cleanup and release locks
1582 */
1583 MmLockAddressSpace(AddressSpace);
1584 PageOp->Status = Status;
1585 MmspCompleteAndReleasePageOp(PageOp);
1586 DPRINT("Address 0x%.8X\n", Address);
1587 return(Status);
1588 }
1589 /*
1590 * Relock the address space and segment
1591 */
1592 MmLockAddressSpace(AddressSpace);
1593 MmLockSectionSegment(Segment);
1594
1595 /*
1596 * Check the entry. No one should change the status of a page
1597 * that has a pending page-in.
1598 */
1599 Entry1 = MmGetPageEntrySectionSegment(Segment, &Offset);
1600 if (Entry != Entry1)
1601 {
1602 DPRINT1("Someone changed ppte entry while we slept\n");
1603 KeBugCheck(MEMORY_MANAGEMENT);
1604 }
1605
1606 /*
1607 * Mark the offset within the section as having valid, in-memory
1608 * data
1609 */
1610 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1611 MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
1612 MmUnlockSectionSegment(Segment);
1613
1614 Status = MmCreateVirtualMapping(Process,
1615 PAddress,
1616 Attributes,
1617 &Page,
1618 1);
1619 if (!NT_SUCCESS(Status))
1620 {
1621 DPRINT1("Unable to create virtual mapping\n");
1622 KeBugCheck(MEMORY_MANAGEMENT);
1623 }
1624 MmInsertRmap(Page, Process, Address);
1625
1626 PageOp->Status = STATUS_SUCCESS;
1627 MmspCompleteAndReleasePageOp(PageOp);
1628 DPRINT("Address 0x%.8X\n", Address);
1629 return(STATUS_SUCCESS);
1630 }
1631 else if (IS_SWAP_FROM_SSE(Entry))
1632 {
1633 SWAPENTRY SwapEntry;
1634
1635 SwapEntry = SWAPENTRY_FROM_SSE(Entry);
1636
1637 /*
1638 * Release all our locks and read in the page from disk
1639 */
1640 MmUnlockSectionSegment(Segment);
1641
1642 MmUnlockAddressSpace(AddressSpace);
1643 MI_SET_USAGE(MI_USAGE_SECTION);
1644 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1645 if (!Process) MI_SET_PROCESS2("Kernel Section");
1646 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1647 if (!NT_SUCCESS(Status))
1648 {
1649 KeBugCheck(MEMORY_MANAGEMENT);
1650 }
1651
1652 Status = MmReadFromSwapPage(SwapEntry, Page);
1653 if (!NT_SUCCESS(Status))
1654 {
1655 KeBugCheck(MEMORY_MANAGEMENT);
1656 }
1657
1658 /*
1659 * Relock the address space and segment
1660 */
1661 MmLockAddressSpace(AddressSpace);
1662 MmLockSectionSegment(Segment);
1663
1664 /*
1665 * Check the entry. No one should change the status of a page
1666 * that has a pending page-in.
1667 */
1668 Entry1 = MmGetPageEntrySectionSegment(Segment, &Offset);
1669 if (Entry != Entry1)
1670 {
1671 DPRINT1("Someone changed ppte entry while we slept\n");
1672 KeBugCheck(MEMORY_MANAGEMENT);
1673 }
1674
1675 /*
1676 * Mark the offset within the section as having valid, in-memory
1677 * data
1678 */
1679 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1680 MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
1681 MmUnlockSectionSegment(Segment);
1682
1683 /*
1684 * Save the swap entry.
1685 */
1686 MmSetSavedSwapEntryPage(Page, SwapEntry);
1687 Status = MmCreateVirtualMapping(Process,
1688 PAddress,
1689 Region->Protect,
1690 &Page,
1691 1);
1692 if (!NT_SUCCESS(Status))
1693 {
1694 DPRINT1("Unable to create virtual mapping\n");
1695 KeBugCheck(MEMORY_MANAGEMENT);
1696 }
1697 MmInsertRmap(Page, Process, Address);
1698 PageOp->Status = STATUS_SUCCESS;
1699 MmspCompleteAndReleasePageOp(PageOp);
1700 DPRINT("Address 0x%.8X\n", Address);
1701 return(STATUS_SUCCESS);
1702 }
1703 else
1704 {
1705 /*
1706 * If the section offset is already in-memory and valid then just
1707 * take another reference to the page
1708 */
1709
1710 Page = PFN_FROM_SSE(Entry);
1711
1712 MmSharePageEntrySectionSegment(Segment, &Offset);
1713 MmUnlockSectionSegment(Segment);
1714
1715 Status = MmCreateVirtualMapping(Process,
1716 PAddress,
1717 Attributes,
1718 &Page,
1719 1);
1720 if (!NT_SUCCESS(Status))
1721 {
1722 DPRINT1("Unable to create virtual mapping\n");
1723 KeBugCheck(MEMORY_MANAGEMENT);
1724 }
1725 MmInsertRmap(Page, Process, Address);
1726 PageOp->Status = STATUS_SUCCESS;
1727 MmspCompleteAndReleasePageOp(PageOp);
1728 DPRINT("Address 0x%.8X\n", Address);
1729 return(STATUS_SUCCESS);
1730 }
1731 }
1732
1733 NTSTATUS
1734 NTAPI
1735 MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
1736 MEMORY_AREA* MemoryArea,
1737 PVOID Address)
1738 {
1739 PMM_SECTION_SEGMENT Segment;
1740 PROS_SECTION_OBJECT Section;
1741 PFN_NUMBER OldPage;
1742 PFN_NUMBER NewPage;
1743 NTSTATUS Status;
1744 PVOID PAddress;
1745 LARGE_INTEGER Offset;
1746 PMM_PAGEOP PageOp;
1747 PMM_REGION Region;
1748 ULONG Entry;
1749 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1750
1751 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace, MemoryArea, Address);
1752
1753 /*
1754 * Check if the page has already been set readwrite
1755 */
1756 if (MmGetPageProtect(Process, Address) & PAGE_READWRITE)
1757 {
1758 DPRINT("Address 0x%.8X\n", Address);
1759 return(STATUS_SUCCESS);
1760 }
1761
1762 /*
1763 * Find the offset of the page
1764 */
1765 PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
1766 Offset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress
1767 + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
1768
1769 Segment = MemoryArea->Data.SectionData.Segment;
1770 Section = MemoryArea->Data.SectionData.Section;
1771 Region = MmFindRegion(MemoryArea->StartingAddress,
1772 &MemoryArea->Data.SectionData.RegionListHead,
1773 Address, NULL);
1774 ASSERT(Region != NULL);
1775 /*
1776 * Lock the segment
1777 */
1778 MmLockSectionSegment(Segment);
1779
1780 OldPage = MmGetPfnForProcess(Process, Address);
1781 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
1782
1783 MmUnlockSectionSegment(Segment);
1784
1785 /*
1786 * Check if we are doing COW
1787 */
1788 if (!((Segment->WriteCopy) &&
1789 (Region->Protect == PAGE_READWRITE ||
1790 Region->Protect == PAGE_EXECUTE_READWRITE)))
1791 {
1792 DPRINT("Address 0x%.8X\n", Address);
1793 return(STATUS_ACCESS_VIOLATION);
1794 }
1795
1796 if (IS_SWAP_FROM_SSE(Entry) ||
1797 PFN_FROM_SSE(Entry) != OldPage)
1798 {
1799 /* This is a private page. We must only change the page protection. */
1800 MmSetPageProtect(Process, Address, Region->Protect);
1801 return(STATUS_SUCCESS);
1802 }
1803
1804 if(OldPage == 0)
1805 DPRINT("OldPage == 0!\n");
1806
1807 /*
1808 * Get or create a pageop
1809 */
1810 PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset.LowPart,
1811 MM_PAGEOP_ACCESSFAULT, FALSE);
1812 if (PageOp == NULL)
1813 {
1814 DPRINT1("MmGetPageOp failed\n");
1815 KeBugCheck(MEMORY_MANAGEMENT);
1816 }
1817
1818 /*
1819 * Wait for any other operations to complete
1820 */
1821 if (PageOp->Thread != PsGetCurrentThread())
1822 {
1823 MmUnlockAddressSpace(AddressSpace);
1824 Status = MmspWaitForPageOpCompletionEvent(PageOp);
1825 /*
1826 * Check for various strange conditions
1827 */
1828 if (Status == STATUS_TIMEOUT)
1829 {
1830 DPRINT1("Failed to wait for page op, status = %x\n", Status);
1831 KeBugCheck(MEMORY_MANAGEMENT);
1832 }
1833 if (PageOp->Status == STATUS_PENDING)
1834 {
1835 DPRINT1("Woke for page op before completion\n");
1836 KeBugCheck(MEMORY_MANAGEMENT);
1837 }
1838 /*
1839 * Restart the operation
1840 */
1841 MmLockAddressSpace(AddressSpace);
1842 MmspCompleteAndReleasePageOp(PageOp);
1843 DPRINT("Address 0x%.8X\n", Address);
1844 return(STATUS_MM_RESTART_OPERATION);
1845 }
1846
1847 /*
1848 * Release locks now we have the pageop
1849 */
1850 MmUnlockAddressSpace(AddressSpace);
1851
1852 /*
1853 * Allocate a page
1854 */
1855 MI_SET_USAGE(MI_USAGE_SECTION);
1856 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1857 if (!Process) MI_SET_PROCESS2("Kernel Section");
1858 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1859 if (!NT_SUCCESS(Status))
1860 {
1861 KeBugCheck(MEMORY_MANAGEMENT);
1862 }
1863
1864 /*
1865 * Copy the old page
1866 */
1867 MiCopyFromUserPage(NewPage, PAddress);
1868
1869 MmLockAddressSpace(AddressSpace);
1870 /*
1871 * Delete the old entry.
1872 */
1873 MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
1874
1875 /*
1876 * Set the PTE to point to the new page
1877 */
1878 Status = MmCreateVirtualMapping(Process,
1879 PAddress,
1880 Region->Protect,
1881 &NewPage,
1882 1);
1883 if (!NT_SUCCESS(Status))
1884 {
1885 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1886 KeBugCheck(MEMORY_MANAGEMENT);
1887 return(Status);
1888 }
1889 if (!NT_SUCCESS(Status))
1890 {
1891 DPRINT1("Unable to create virtual mapping\n");
1892 KeBugCheck(MEMORY_MANAGEMENT);
1893 }
1894
1895 /*
1896 * Unshare the old page.
1897 */
1898 MmDeleteRmap(OldPage, Process, PAddress);
1899 MmInsertRmap(NewPage, Process, PAddress);
1900 MmLockSectionSegment(Segment);
1901 MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, FALSE, FALSE);
1902 MmUnlockSectionSegment(Segment);
1903
1904 PageOp->Status = STATUS_SUCCESS;
1905 MmspCompleteAndReleasePageOp(PageOp);
1906 DPRINT("Address 0x%.8X\n", Address);
1907 return(STATUS_SUCCESS);
1908 }
1909
1910 VOID
1911 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
1912 {
1913 MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1914 BOOLEAN WasDirty;
1915 PFN_NUMBER Page;
1916
1917 PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1918 if (Process)
1919 {
1920 MmLockAddressSpace(&Process->Vm);
1921 }
1922
1923 MmDeleteVirtualMapping(Process,
1924 Address,
1925 FALSE,
1926 &WasDirty,
1927 &Page);
1928 if (WasDirty)
1929 {
1930 PageOutContext->WasDirty = TRUE;
1931 }
1932 if (!PageOutContext->Private)
1933 {
1934 MmLockSectionSegment(PageOutContext->Segment);
1935 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT)PageOutContext->Section,
1936 PageOutContext->Segment,
1937 &PageOutContext->Offset,
1938 PageOutContext->WasDirty,
1939 TRUE);
1940 MmUnlockSectionSegment(PageOutContext->Segment);
1941 }
1942 if (Process)
1943 {
1944 MmUnlockAddressSpace(&Process->Vm);
1945 }
1946
1947 if (PageOutContext->Private)
1948 {
1949 MmReleasePageMemoryConsumer(MC_USER, Page);
1950 }
1951
1952 DPRINT("PhysicalAddress %x, Address %x\n", Page << PAGE_SHIFT, Address);
1953 }
1954
1955 NTSTATUS
1956 NTAPI
1957 MmPageOutSectionView(PMMSUPPORT AddressSpace,
1958 MEMORY_AREA* MemoryArea,
1959 PVOID Address,
1960 PMM_PAGEOP PageOp)
1961 {
1962 PFN_NUMBER Page;
1963 MM_SECTION_PAGEOUT_CONTEXT Context;
1964 SWAPENTRY SwapEntry;
1965 ULONG Entry;
1966 ULONG FileOffset;
1967 NTSTATUS Status;
1968 PFILE_OBJECT FileObject;
1969 #ifndef NEWCC
1970 PBCB Bcb = NULL;
1971 #endif
1972 BOOLEAN DirectMapped;
1973 BOOLEAN IsImageSection;
1974 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
1975 KIRQL OldIrql;
1976
1977 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1978
1979 /*
1980 * Get the segment and section.
1981 */
1982 Context.Segment = MemoryArea->Data.SectionData.Segment;
1983 Context.Section = MemoryArea->Data.SectionData.Section;
1984 Context.CallingProcess = Process;
1985
1986 Context.Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
1987 + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
1988 FileOffset = Context.Offset.QuadPart + Context.Segment->Image.FileOffset;
1989
1990 IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1991
1992 FileObject = Context.Section->FileObject;
1993 DirectMapped = FALSE;
1994
1995 #ifndef NEWCC
1996 if (FileObject != NULL &&
1997 !(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
1998 {
1999 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
2000
2001 /*
2002 * If the file system is letting us go directly to the cache and the
2003 * memory area was mapped at an offset in the file which is page aligned
2004 * then note this is a direct mapped page.
2005 */
2006 if ((FileOffset % PAGE_SIZE) == 0 &&
2007 (Context.Offset.QuadPart + PAGE_SIZE <= Context.Segment->RawLength.QuadPart || !IsImageSection))
2008 {
2009 DirectMapped = TRUE;
2010 }
2011 }
2012 #endif
2013
2014
2015 /*
2016 * This should never happen since mappings of physical memory are never
2017 * placed in the rmap lists.
2018 */
2019 if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
2020 {
2021 DPRINT1("Trying to page out from physical memory section address 0x%X "
2022 "process %d\n", Address,
2023 Process ? Process->UniqueProcessId : 0);
2024 KeBugCheck(MEMORY_MANAGEMENT);
2025 }
2026
2027 /*
2028 * Get the section segment entry and the physical address.
2029 */
2030 if (!MmIsPagePresent(Process, Address))
2031 {
2032 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2033 Process ? Process->UniqueProcessId : 0, Address);
2034 KeBugCheck(MEMORY_MANAGEMENT);
2035 }
2036 Page = MmGetPfnForProcess(Process, Address);
2037 SwapEntry = MmGetSavedSwapEntryPage(Page);
2038
2039 /*
2040 * Check the reference count to ensure this page can be paged out
2041 */
2042 if (MmGetReferenceCountPage(Page) != 1)
2043 {
2044 DPRINT("Cannot page out locked section page: 0x%p (RefCount: %d)\n",
2045 Page, MmGetReferenceCountPage(Page));
2046 PageOp->Status = STATUS_UNSUCCESSFUL;
2047 MmspCompleteAndReleasePageOp(PageOp);
2048 return STATUS_UNSUCCESSFUL;
2049 }
2050
2051 /*
2052 * Prepare the context structure for the rmap delete call.
2053 */
2054 MmLockSectionSegment(Context.Segment);
2055 Entry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset);
2056 MmUnlockSectionSegment(Context.Segment);
2057 Context.WasDirty = FALSE;
2058 if (Context.Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
2059 IS_SWAP_FROM_SSE(Entry) ||
2060 PFN_FROM_SSE(Entry) != Page)
2061 {
2062 Context.Private = TRUE;
2063 }
2064 else
2065 {
2066 Context.Private = FALSE;
2067 }
2068
2069 /*
2070 * Take an additional reference to the page or the cache segment.
2071 */
2072 if (DirectMapped && !Context.Private)
2073 {
2074 if(!MiIsPageFromCache(MemoryArea, Context.Offset.LowPart))
2075 {
2076 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
2077 KeBugCheck(MEMORY_MANAGEMENT);
2078 }
2079 }
2080 else
2081 {
2082 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
2083 MmReferencePage(Page);
2084 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
2085 }
2086
2087 MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping);
2088 MmLockSectionSegment(Context.Segment);
2089 Entry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset);
2090 MmUnlockSectionSegment(Context.Segment);
2091
2092 /*
2093 * If this wasn't a private page then we should have reduced the entry to
2094 * zero by deleting all the rmaps.
2095 */
2096 if (!Context.Private && Entry != 0)
2097 {
2098 if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
2099 !(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
2100 {
2101 KeBugCheckEx(MEMORY_MANAGEMENT, Entry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
2102 }
2103 }
2104
2105 /*
2106 * If the page wasn't dirty then we can just free it as for a readonly page.
2107 * Since we unmapped all the mappings above we know it will not suddenly
2108 * become dirty.
2109 * If the page is from a pagefile section and has no swap entry,
2110 * we can't free the page at this point.
2111 */
2112 SwapEntry = MmGetSavedSwapEntryPage(Page);
2113 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT)
2114 {
2115 if (Context.Private)
2116 {
2117 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
2118 Context.WasDirty ? "dirty" : "clean", Address);
2119 KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
2120 }
2121 if (!Context.WasDirty && SwapEntry != 0)
2122 {
2123 MmSetSavedSwapEntryPage(Page, 0);
2124 MmLockSectionSegment(Context.Segment);
2125 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2126 MmUnlockSectionSegment(Context.Segment);
2127 MmReleasePageMemoryConsumer(MC_USER, Page);
2128 PageOp->Status = STATUS_SUCCESS;
2129 MmspCompleteAndReleasePageOp(PageOp);
2130 return(STATUS_SUCCESS);
2131 }
2132 }
2133 else if (Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2134 {
2135 if (Context.Private)
2136 {
2137 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
2138 Context.WasDirty ? "dirty" : "clean", Address);
2139 KeBugCheckEx(MEMORY_MANAGEMENT, Page, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
2140 }
2141 if (!Context.WasDirty || SwapEntry != 0)
2142 {
2143 MmSetSavedSwapEntryPage(Page, 0);
2144 if (SwapEntry != 0)
2145 {
2146 MmLockSectionSegment(Context.Segment);
2147 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2148 MmUnlockSectionSegment(Context.Segment);
2149 }
2150 MmReleasePageMemoryConsumer(MC_USER, Page);
2151 PageOp->Status = STATUS_SUCCESS;
2152 MmspCompleteAndReleasePageOp(PageOp);
2153 return(STATUS_SUCCESS);
2154 }
2155 }
2156 else if (!Context.Private && DirectMapped)
2157 {
2158 if (SwapEntry != 0)
2159 {
2160 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
2161 Address);
2162 KeBugCheckEx(MEMORY_MANAGEMENT, STATUS_UNSUCCESSFUL, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address);
2163 }
2164 #ifndef NEWCC
2165 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
2166 #else
2167 Status = STATUS_SUCCESS;
2168 #endif
2169 #ifndef NEWCC
2170 if (!NT_SUCCESS(Status))
2171 {
2172 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
2173 KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Bcb, FileOffset, (ULONG_PTR)Address);
2174 }
2175 #endif
2176 PageOp->Status = STATUS_SUCCESS;
2177 MmspCompleteAndReleasePageOp(PageOp);
2178 return(STATUS_SUCCESS);
2179 }
2180 else if (!Context.WasDirty && !DirectMapped && !Context.Private)
2181 {
2182 if (SwapEntry != 0)
2183 {
2184 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
2185 Address);
2186 KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, Page, (ULONG_PTR)Process, (ULONG_PTR)Address);
2187 }
2188 MmReleasePageMemoryConsumer(MC_USER, Page);
2189 PageOp->Status = STATUS_SUCCESS;
2190 MmspCompleteAndReleasePageOp(PageOp);
2191 return(STATUS_SUCCESS);
2192 }
2193 else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
2194 {
2195 DPRINT1("Not dirty and private and not swapped (%p:%p)\n", Process, Address);
2196 MmSetSavedSwapEntryPage(Page, 0);
2197 MmLockAddressSpace(AddressSpace);
2198 Status = MmCreatePageFileMapping(Process,
2199 Address,
2200 SwapEntry);
2201 MmUnlockAddressSpace(AddressSpace);
2202 if (!NT_SUCCESS(Status))
2203 {
2204 DPRINT1("Status %x Swapping out %p:%p\n", Status, Process, Address);
2205 KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry);
2206 }
2207 MmReleasePageMemoryConsumer(MC_USER, Page);
2208 PageOp->Status = STATUS_SUCCESS;
2209 MmspCompleteAndReleasePageOp(PageOp);
2210 return(STATUS_SUCCESS);
2211 }
2212
2213 /*
2214 * If necessary, allocate an entry in the paging file for this page
2215 */
2216 if (SwapEntry == 0)
2217 {
2218 SwapEntry = MmAllocSwapPage();
2219 if (SwapEntry == 0)
2220 {
2221 MmShowOutOfSpaceMessagePagingFile();
2222 MmLockAddressSpace(AddressSpace);
2223 /*
2224 * For private pages restore the old mappings.
2225 */
2226 if (Context.Private)
2227 {
2228 Status = MmCreateVirtualMapping(Process,
2229 Address,
2230 MemoryArea->Protect,
2231 &Page,
2232 1);
2233 MmSetDirtyPage(Process, Address);
2234 MmInsertRmap(Page,
2235 Process,
2236 Address);
2237 }
2238 else
2239 {
2240 LONG OldEntry;
2241 /*
2242 * For non-private pages if the page wasn't direct mapped then
2243 * set it back into the section segment entry so we don't loose
2244 * our copy. Otherwise it will be handled by the cache manager.
2245 */
2246 Status = MmCreateVirtualMapping(Process,
2247 Address,
2248 MemoryArea->Protect,
2249 &Page,
2250 1);
2251 MmSetDirtyPage(Process, Address);
2252 MmInsertRmap(Page,
2253 Process,
2254 Address);
2255 // If we got here, the previous entry should have been a wait
2256 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
2257 MmLockSectionSegment(Context.Segment);
2258 OldEntry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset);
2259 ASSERT(OldEntry == 0 || OldEntry == MAKE_SWAP_SSE(MM_WAIT_ENTRY));
2260 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2261 MmUnlockSectionSegment(Context.Segment);
2262 }
2263 MmUnlockAddressSpace(AddressSpace);
2264 PageOp->Status = STATUS_UNSUCCESSFUL;
2265 MmspCompleteAndReleasePageOp(PageOp);
2266 return(STATUS_PAGEFILE_QUOTA);
2267 }
2268 }
2269
2270 /*
2271 * Write the page to the pagefile
2272 */
2273 Status = MmWriteToSwapPage(SwapEntry, Page);
2274 if (!NT_SUCCESS(Status))
2275 {
2276 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2277 Status);
2278 /*
2279 * As above: undo our actions.
2280 * FIXME: Also free the swap page.
2281 */
2282 MmLockAddressSpace(AddressSpace);
2283 if (Context.Private)
2284 {
2285 Status = MmCreateVirtualMapping(Process,
2286 Address,
2287 MemoryArea->Protect,
2288 &Page,
2289 1);
2290 MmSetDirtyPage(Process, Address);
2291 MmInsertRmap(Page,
2292 Process,
2293 Address);
2294 }
2295 else
2296 {
2297 Status = MmCreateVirtualMapping(Process,
2298 Address,
2299 MemoryArea->Protect,
2300 &Page,
2301 1);
2302 MmSetDirtyPage(Process, Address);
2303 MmInsertRmap(Page,
2304 Process,
2305 Address);
2306 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
2307 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2308 }
2309 MmUnlockAddressSpace(AddressSpace);
2310 PageOp->Status = STATUS_UNSUCCESSFUL;
2311 MmspCompleteAndReleasePageOp(PageOp);
2312 return(STATUS_UNSUCCESSFUL);
2313 }
2314
2315 /*
2316 * Otherwise we have succeeded.
2317 */
2318 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
2319 MmLockSectionSegment(Context.Segment);
2320 MmSetSavedSwapEntryPage(Page, 0);
2321 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
2322 Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2323 {
2324 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
2325 }
2326 else
2327 {
2328 MmReleasePageMemoryConsumer(MC_USER, Page);
2329 }
2330
2331 if (Context.Private)
2332 {
2333 MmLockAddressSpace(AddressSpace);
2334 Status = MmCreatePageFileMapping(Process,
2335 Address,
2336 SwapEntry);
2337 MmUnlockAddressSpace(AddressSpace);
2338 if (!NT_SUCCESS(Status))
2339 {
2340 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status, Process, Address);
2341 KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry);
2342 }
2343 }
2344 else
2345 {
2346 Entry = MAKE_SWAP_SSE(SwapEntry);
2347 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
2348 }
2349
2350 MmUnlockSectionSegment(Context.Segment);
2351 PageOp->Status = STATUS_SUCCESS;
2352 MmspCompleteAndReleasePageOp(PageOp);
2353 return(STATUS_SUCCESS);
2354 }
2355
2356 NTSTATUS
2357 NTAPI
2358 MmWritePageSectionView(PMMSUPPORT AddressSpace,
2359 PMEMORY_AREA MemoryArea,
2360 PVOID Address,
2361 PMM_PAGEOP PageOp)
2362 {
2363 LARGE_INTEGER Offset;
2364 PROS_SECTION_OBJECT Section;
2365 PMM_SECTION_SEGMENT Segment;
2366 PFN_NUMBER Page;
2367 SWAPENTRY SwapEntry;
2368 ULONG Entry;
2369 BOOLEAN Private;
2370 NTSTATUS Status;
2371 PFILE_OBJECT FileObject;
2372 PBCB Bcb = NULL;
2373 BOOLEAN DirectMapped;
2374 BOOLEAN IsImageSection;
2375 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
2376
2377 Address = (PVOID)PAGE_ROUND_DOWN(Address);
2378
2379 Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
2380 + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
2381
2382 /*
2383 * Get the segment and section.
2384 */
2385 Segment = MemoryArea->Data.SectionData.Segment;
2386 Section = MemoryArea->Data.SectionData.Section;
2387 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
2388
2389 FileObject = Section->FileObject;
2390 DirectMapped = FALSE;
2391 if (FileObject != NULL &&
2392 !(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
2393 {
2394 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
2395
2396 /*
2397 * If the file system is letting us go directly to the cache and the
2398 * memory area was mapped at an offset in the file which is page aligned
2399 * then note this is a direct mapped page.
2400 */
2401 if (((Offset.QuadPart + Segment->Image.FileOffset) % PAGE_SIZE) == 0 &&
2402 (Offset.QuadPart + PAGE_SIZE <= Segment->RawLength.QuadPart || !IsImageSection))
2403 {
2404 DirectMapped = TRUE;
2405 }
2406 }
2407
2408 /*
2409 * This should never happen since mappings of physical memory are never
2410 * placed in the rmap lists.
2411 */
2412 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
2413 {
2414 DPRINT1("Trying to write back page from physical memory mapped at %X "
2415 "process %d\n", Address,
2416 Process ? Process->UniqueProcessId : 0);
2417 KeBugCheck(MEMORY_MANAGEMENT);
2418 }
2419
2420 /*
2421 * Get the section segment entry and the physical address.
2422 */
2423 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
2424 if (!MmIsPagePresent(Process, Address))
2425 {
2426 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
2427 Process ? Process->UniqueProcessId : 0, Address);
2428 KeBugCheck(MEMORY_MANAGEMENT);
2429 }
2430 Page = MmGetPfnForProcess(Process, Address);
2431 SwapEntry = MmGetSavedSwapEntryPage(Page);
2432
2433 /*
2434 * Check for a private (COWed) page.
2435 */
2436 if (Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
2437 IS_SWAP_FROM_SSE(Entry) ||
2438 PFN_FROM_SSE(Entry) != Page)
2439 {
2440 Private = TRUE;
2441 }
2442 else
2443 {
2444 Private = FALSE;
2445 }
2446
2447 /*
2448 * Speculatively set all mappings of the page to clean.
2449 */
2450 MmSetCleanAllRmaps(Page);
2451
2452 /*
2453 * If this page was direct mapped from the cache then the cache manager
2454 * will take care of writing it back to disk.
2455 */
2456 if (DirectMapped && !Private)
2457 {
2458 ASSERT(SwapEntry == 0);
2459 #ifndef NEWCC
2460 CcRosMarkDirtyCacheSegment(Bcb, Offset.LowPart + Segment->Image.FileOffset);
2461 #endif
2462 PageOp->Status = STATUS_SUCCESS;
2463 MmspCompleteAndReleasePageOp(PageOp);
2464 return(STATUS_SUCCESS);
2465 }
2466
2467 /*
2468 * If necessary, allocate an entry in the paging file for this page
2469 */
2470 if (SwapEntry == 0)
2471 {
2472 SwapEntry = MmAllocSwapPage();
2473 if (SwapEntry == 0)
2474 {
2475 MmSetDirtyAllRmaps(Page);
2476 PageOp->Status = STATUS_UNSUCCESSFUL;
2477 MmspCompleteAndReleasePageOp(PageOp);
2478 return(STATUS_PAGEFILE_QUOTA);
2479 }
2480 MmSetSavedSwapEntryPage(Page, SwapEntry);
2481 }
2482
2483 /*
2484 * Write the page to the pagefile
2485 */
2486 Status = MmWriteToSwapPage(SwapEntry, Page);
2487 if (!NT_SUCCESS(Status))
2488 {
2489 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2490 Status);
2491 MmSetDirtyAllRmaps(Page);
2492 PageOp->Status = STATUS_UNSUCCESSFUL;
2493 MmspCompleteAndReleasePageOp(PageOp);
2494 return(STATUS_UNSUCCESSFUL);
2495 }
2496
2497 /*
2498 * Otherwise we have succeeded.
2499 */
2500 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
2501 PageOp->Status = STATUS_SUCCESS;
2502 MmspCompleteAndReleasePageOp(PageOp);
2503 return(STATUS_SUCCESS);
2504 }
2505
2506 static VOID
2507 MmAlterViewAttributes(PMMSUPPORT AddressSpace,
2508 PVOID BaseAddress,
2509 SIZE_T RegionSize,
2510 ULONG OldType,
2511 ULONG OldProtect,
2512 ULONG NewType,
2513 ULONG NewProtect)
2514 {
2515 PMEMORY_AREA MemoryArea;
2516 PMM_SECTION_SEGMENT Segment;
2517 BOOLEAN DoCOW = FALSE;
2518 ULONG i;
2519 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
2520
2521 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
2522 ASSERT(MemoryArea != NULL);
2523 Segment = MemoryArea->Data.SectionData.Segment;
2524 MmLockSectionSegment(Segment);
2525
2526 if ((Segment->WriteCopy) &&
2527 (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
2528 {
2529 DoCOW = TRUE;
2530 }
2531
2532 if (OldProtect != NewProtect)
2533 {
2534 for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
2535 {
2536 PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
2537 ULONG Protect = NewProtect;
2538
2539 /*
2540 * If we doing COW for this segment then check if the page is
2541 * already private.
2542 */
2543 if (DoCOW && MmIsPagePresent(Process, Address))
2544 {
2545 LARGE_INTEGER Offset;
2546 ULONG Entry;
2547 PFN_NUMBER Page;
2548
2549 Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
2550 + MemoryArea->Data.SectionData.ViewOffset.QuadPart;
2551 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
2552 Page = MmGetPfnForProcess(Process, Address);
2553
2554 Protect = PAGE_READONLY;
2555 if (Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
2556 IS_SWAP_FROM_SSE(Entry) ||
2557 PFN_FROM_SSE(Entry) != Page)
2558 {
2559 Protect = NewProtect;
2560 }
2561 }
2562
2563 if (MmIsPagePresent(Process, Address))
2564 {
2565 MmSetPageProtect(Process, Address,
2566 Protect);
2567 }
2568 }
2569 }
2570
2571 MmUnlockSectionSegment(Segment);
2572 }
2573
2574 NTSTATUS
2575 NTAPI
2576 MmProtectSectionView(PMMSUPPORT AddressSpace,
2577 PMEMORY_AREA MemoryArea,
2578 PVOID BaseAddress,
2579 SIZE_T Length,
2580 ULONG Protect,
2581 PULONG OldProtect)
2582 {
2583 PMM_REGION Region;
2584 NTSTATUS Status;
2585 ULONG_PTR MaxLength;
2586
2587 MaxLength = (ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)BaseAddress;
2588 if (Length > MaxLength)
2589 Length = (ULONG)MaxLength;
2590
2591 Region = MmFindRegion(MemoryArea->StartingAddress,
2592 &MemoryArea->Data.SectionData.RegionListHead,
2593 BaseAddress, NULL);
2594 ASSERT(Region != NULL);
2595
2596 if ((MemoryArea->Flags & SEC_NO_CHANGE) &&
2597 Region->Protect != Protect)
2598 {
2599 return STATUS_INVALID_PAGE_PROTECTION;
2600 }
2601
2602 *OldProtect = Region->Protect;
2603 Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress,
2604 &MemoryArea->Data.SectionData.RegionListHead,
2605 BaseAddress, Length, Region->Type, Protect,
2606 MmAlterViewAttributes);
2607
2608 return(Status);
2609 }
2610
2611 NTSTATUS NTAPI
2612 MmQuerySectionView(PMEMORY_AREA MemoryArea,
2613 PVOID Address,
2614 PMEMORY_BASIC_INFORMATION Info,
2615 PSIZE_T ResultLength)
2616 {
2617 PMM_REGION Region;
2618 PVOID RegionBaseAddress;
2619 PROS_SECTION_OBJECT Section;
2620 PMM_SECTION_SEGMENT Segment;
2621
2622 Region = MmFindRegion((PVOID)MemoryArea->StartingAddress,
2623 &MemoryArea->Data.SectionData.RegionListHead,
2624 Address, &RegionBaseAddress);
2625 if (Region == NULL)
2626 {
2627 return STATUS_UNSUCCESSFUL;
2628 }
2629
2630 Section = MemoryArea->Data.SectionData.Section;
2631 if (Section->AllocationAttributes & SEC_IMAGE)
2632 {
2633 Segment = MemoryArea->Data.SectionData.Segment;
2634 Info->AllocationBase = (PUCHAR)MemoryArea->StartingAddress - Segment->Image.VirtualAddress;
2635 Info->Type = MEM_IMAGE;
2636 }
2637 else
2638 {
2639 Info->AllocationBase = MemoryArea->StartingAddress;
2640 Info->Type = MEM_MAPPED;
2641 }
2642 Info->BaseAddress = RegionBaseAddress;
2643 Info->AllocationProtect = MemoryArea->Protect;
2644 Info->RegionSize = Region->Length;
2645 Info->State = MEM_COMMIT;
2646 Info->Protect = Region->Protect;
2647
2648 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
2649 return(STATUS_SUCCESS);
2650 }
2651
2652 VOID
2653 NTAPI
2654 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
2655 {
2656 ULONG Length;
2657 LARGE_INTEGER Offset;
2658 ULONG Entry;
2659 SWAPENTRY SavedSwapEntry;
2660 PFN_NUMBER Page;
2661
2662 Page = 0;
2663
2664 MmLockSectionSegment(Segment);
2665
2666 Length = PAGE_ROUND_UP(Segment->Length.QuadPart);
2667 for (Offset.QuadPart = 0; Offset.QuadPart < Length; Offset.QuadPart += PAGE_SIZE)
2668 {
2669 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
2670 if (Entry)
2671 {
2672 MmSetPageEntrySectionSegment(Segment, &Offset, 0);
2673 if (IS_SWAP_FROM_SSE(Entry))
2674 {
2675 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
2676 }
2677 else
2678 {
2679 Page = PFN_FROM_SSE(Entry);
2680 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
2681 if (SavedSwapEntry != 0)
2682 {
2683 MmSetSavedSwapEntryPage(Page, 0);
2684 MmFreeSwapPage(SavedSwapEntry);
2685 }
2686 MmReleasePageMemoryConsumer(MC_USER, Page);
2687 }
2688 }
2689 }
2690
2691 MmUnlockSectionSegment(Segment);
2692 }
2693
2694 VOID NTAPI
2695 MmpDeleteSection(PVOID ObjectBody)
2696 {
2697 PROS_SECTION_OBJECT Section = (PROS_SECTION_OBJECT)ObjectBody;
2698
2699 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody);
2700 if (Section->AllocationAttributes & SEC_IMAGE)
2701 {
2702 ULONG i;
2703 ULONG NrSegments;
2704 ULONG RefCount;
2705 PMM_SECTION_SEGMENT SectionSegments;
2706
2707 /*
2708 * NOTE: Section->ImageSection can be NULL for short time
2709 * during the section creating. If we fail for some reason
2710 * until the image section is properly initialized we shouldn't
2711 * process further here.
2712 */
2713 if (Section->ImageSection == NULL)
2714 return;
2715
2716 SectionSegments = Section->ImageSection->Segments;
2717 NrSegments = Section->ImageSection->NrSegments;
2718
2719 for (i = 0; i < NrSegments; i++)
2720 {
2721 if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2722 {
2723 MmLockSectionSegment(&SectionSegments[i]);
2724 }
2725 RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount);
2726 if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED)
2727 {
2728 MmUnlockSectionSegment(&SectionSegments[i]);
2729 if (RefCount == 0)
2730 {
2731 MmpFreePageFileSegment(&SectionSegments[i]);
2732 }
2733 }
2734 }
2735 }
2736 #ifdef NEWCC
2737 else if (Section->Segment && Section->Segment->Flags & MM_DATAFILE_SEGMENT)
2738 {
2739 ULONG RefCount = 0;
2740 PMM_SECTION_SEGMENT Segment = Section->Segment;
2741
2742 if (Segment &&
2743 (RefCount = InterlockedDecrementUL(&Segment->ReferenceCount)) == 0)
2744 {
2745 DPRINT("Freeing section segment\n");
2746 Section->Segment = NULL;
2747 MmFinalizeSegment(Segment);
2748 }
2749 else
2750 {
2751 DPRINT("RefCount %d\n", RefCount);
2752 }
2753 }
2754 #endif
2755 else
2756 {
2757 /*
2758 * NOTE: Section->Segment can be NULL for short time
2759 * during the section creating.
2760 */
2761 if (Section->Segment == NULL)
2762 return;
2763
2764 if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
2765 {
2766 MmpFreePageFileSegment(Section->Segment);
2767 MmFreePageTablesSectionSegment(Section->Segment, NULL);
2768 ExFreePool(Section->Segment);
2769 Section->Segment = NULL;
2770 }
2771 else
2772 {
2773 (void)InterlockedDecrementUL(&Section->Segment->ReferenceCount);
2774 }
2775 }
2776 if (Section->FileObject != NULL)
2777 {
2778 #ifndef NEWCC
2779 CcRosDereferenceCache(Section->FileObject);
2780 #endif
2781 ObDereferenceObject(Section->FileObject);
2782 Section->FileObject = NULL;
2783 }
2784 }
2785
2786 VOID NTAPI
2787 MmpCloseSection(IN PEPROCESS Process OPTIONAL,
2788 IN PVOID Object,
2789 IN ACCESS_MASK GrantedAccess,
2790 IN ULONG ProcessHandleCount,
2791 IN ULONG SystemHandleCount)
2792 {
2793 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2794 Object, ProcessHandleCount);
2795 }
2796
2797 NTSTATUS
2798 INIT_FUNCTION
2799 NTAPI
2800 MmCreatePhysicalMemorySection(VOID)
2801 {
2802 PROS_SECTION_OBJECT PhysSection;
2803 NTSTATUS Status;
2804 OBJECT_ATTRIBUTES Obj;
2805 UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
2806 LARGE_INTEGER SectionSize;
2807 HANDLE Handle;
2808
2809 /*
2810 * Create the section mapping physical memory
2811 */
2812 SectionSize.QuadPart = 0xFFFFFFFF;
2813 InitializeObjectAttributes(&Obj,
2814 &Name,
2815 OBJ_PERMANENT,
2816 NULL,
2817 NULL);
2818 Status = MmCreateSection((PVOID)&PhysSection,
2819 SECTION_ALL_ACCESS,
2820 &Obj,
2821 &SectionSize,
2822 PAGE_EXECUTE_READWRITE,
2823 0,
2824 NULL,
2825 NULL);
2826 if (!NT_SUCCESS(Status))
2827 {
2828 DPRINT1("Failed to create PhysicalMemory section\n");
2829 KeBugCheck(MEMORY_MANAGEMENT);
2830 }
2831 Status = ObInsertObject(PhysSection,
2832 NULL,
2833 SECTION_ALL_ACCESS,
2834 0,
2835 NULL,
2836 &Handle);
2837 if (!NT_SUCCESS(Status))
2838 {
2839 ObDereferenceObject(PhysSection);
2840 }
2841 ObCloseHandle(Handle, KernelMode);
2842 PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
2843 PhysSection->Segment->Flags &= ~MM_PAGEFILE_SEGMENT;
2844
2845 return(STATUS_SUCCESS);
2846 }
2847
2848 NTSTATUS
2849 INIT_FUNCTION
2850 NTAPI
2851 MmInitSectionImplementation(VOID)
2852 {
2853 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
2854 UNICODE_STRING Name;
2855
2856 DPRINT("Creating Section Object Type\n");
2857
2858 /* Initialize the Section object type */
2859 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
2860 RtlInitUnicodeString(&Name, L"Section");
2861 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
2862 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(ROS_SECTION_OBJECT);
2863 ObjectTypeInitializer.PoolType = PagedPool;
2864 ObjectTypeInitializer.UseDefaultObject = TRUE;
2865 ObjectTypeInitializer.GenericMapping = MmpSectionMapping;
2866 ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection;
2867 ObjectTypeInitializer.CloseProcedure = MmpCloseSection;
2868 ObjectTypeInitializer.ValidAccessMask = SECTION_ALL_ACCESS;
2869 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &MmSectionObjectType);
2870
2871 MmCreatePhysicalMemorySection();
2872
2873 return(STATUS_SUCCESS);
2874 }
2875
2876 NTSTATUS
2877 NTAPI
2878 MmCreatePageFileSection(PROS_SECTION_OBJECT *SectionObject,
2879 ACCESS_MASK DesiredAccess,
2880 POBJECT_ATTRIBUTES ObjectAttributes,
2881 PLARGE_INTEGER UMaximumSize,
2882 ULONG SectionPageProtection,
2883 ULONG AllocationAttributes)
2884 /*
2885 * Create a section which is backed by the pagefile
2886 */
2887 {
2888 LARGE_INTEGER MaximumSize;
2889 PROS_SECTION_OBJECT Section;
2890 PMM_SECTION_SEGMENT Segment;
2891 NTSTATUS Status;
2892
2893 if (UMaximumSize == NULL)
2894 {
2895 return(STATUS_UNSUCCESSFUL);
2896 }
2897 MaximumSize = *UMaximumSize;
2898
2899 /*
2900 * Create the section
2901 */
2902 Status = ObCreateObject(ExGetPreviousMode(),
2903 MmSectionObjectType,
2904 ObjectAttributes,
2905 ExGetPreviousMode(),
2906 NULL,
2907 sizeof(ROS_SECTION_OBJECT),
2908 0,
2909 0,
2910 (PVOID*)(PVOID)&Section);
2911 if (!NT_SUCCESS(Status))
2912 {
2913 return(Status);
2914 }
2915
2916 /*
2917 * Initialize it
2918 */
2919 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
2920 Section->Type = 'SC';
2921 Section->Size = 'TN';
2922 Section->SectionPageProtection = SectionPageProtection;
2923 Section->AllocationAttributes = AllocationAttributes;
2924 Section->MaximumSize = MaximumSize;
2925 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2926 TAG_MM_SECTION_SEGMENT);
2927 if (Segment == NULL)
2928 {
2929 ObDereferenceObject(Section);
2930 return(STATUS_NO_MEMORY);
2931 }
2932 RtlZeroMemory(Segment, sizeof(MM_SECTION_SEGMENT));
2933 Section->Segment = Segment;
2934 Segment->ReferenceCount = 1;
2935 ExInitializeFastMutex(&Segment->Lock);
2936 Segment->Image.FileOffset = 0;
2937 Segment->Protection = SectionPageProtection;
2938 Segment->RawLength.QuadPart = MaximumSize.u.LowPart;
2939 Segment->Length.QuadPart = PAGE_ROUND_UP(MaximumSize.u.LowPart);
2940 Segment->Flags = MM_PAGEFILE_SEGMENT;
2941 Segment->WriteCopy = FALSE;
2942 Segment->Image.VirtualAddress = 0;
2943 Segment->Image.Characteristics = 0;
2944 *SectionObject = Section;
2945 MiInitializeSectionPageTable(Segment);
2946 return(STATUS_SUCCESS);
2947 }
2948
2949 NTSTATUS
2950 NTAPI
2951 MmCreateDataFileSection(PROS_SECTION_OBJECT *SectionObject,
2952 ACCESS_MASK DesiredAccess,
2953 POBJECT_ATTRIBUTES ObjectAttributes,
2954 PLARGE_INTEGER UMaximumSize,
2955 ULONG SectionPageProtection,
2956 ULONG AllocationAttributes,
2957 HANDLE FileHandle)
2958 /*
2959 * Create a section backed by a data file
2960 */
2961 {
2962 PROS_SECTION_OBJECT Section;
2963 NTSTATUS Status;
2964 LARGE_INTEGER MaximumSize;
2965 PFILE_OBJECT FileObject;
2966 PMM_SECTION_SEGMENT Segment;
2967 ULONG FileAccess;
2968 IO_STATUS_BLOCK Iosb;
2969 LARGE_INTEGER Offset;
2970 CHAR Buffer;
2971 FILE_STANDARD_INFORMATION FileInfo;
2972 ULONG Length;
2973
2974 /*
2975 * Create the section
2976 */
2977 Status = ObCreateObject(ExGetPreviousMode(),
2978 MmSectionObjectType,
2979 ObjectAttributes,
2980 ExGetPreviousMode(),
2981 NULL,
2982 sizeof(ROS_SECTION_OBJECT),
2983 0,
2984 0,
2985 (PVOID*)&Section);
2986 if (!NT_SUCCESS(Status))
2987 {
2988 return(Status);
2989 }
2990 /*
2991 * Initialize it
2992 */
2993 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
2994 Section->Type = 'SC';
2995 Section->Size = 'TN';
2996 Section->SectionPageProtection = SectionPageProtection;
2997 Section->AllocationAttributes = AllocationAttributes;
2998
2999 /*
3000 * Reference the file handle
3001 */
3002 FileAccess = MiArm3GetCorrectFileAccessMask(SectionPageProtection);
3003 Status = ObReferenceObjectByHandle(FileHandle,
3004 FileAccess,
3005 IoFileObjectType,
3006 ExGetPreviousMode(),
3007 (PVOID*)(PVOID)&FileObject,
3008 NULL);
3009 if (!NT_SUCCESS(Status))
3010 {
3011 ObDereferenceObject(Section);
3012 return(Status);
3013 }
3014
3015 /*
3016 * FIXME: This is propably not entirely correct. We can't look into
3017 * the standard FCB header because it might not be initialized yet
3018 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
3019 * standard file information is filled on first request).
3020 */
3021 Status = IoQueryFileInformation(FileObject,
3022 FileStandardInformation,
3023 sizeof(FILE_STANDARD_INFORMATION),
3024 &FileInfo,
3025 &Length);
3026 Iosb.Information = Length;
3027 if (!NT_SUCCESS(Status))
3028 {
3029 ObDereferenceObject(Section);
3030 ObDereferenceObject(FileObject);
3031 return Status;
3032 }
3033
3034 /*
3035 * FIXME: Revise this once a locking order for file size changes is
3036 * decided
3037 */
3038 if ((UMaximumSize != NULL) && (UMaximumSize->QuadPart != 0))
3039 {
3040 MaximumSize = *UMaximumSize;
3041 }
3042 else
3043 {
3044 MaximumSize = FileInfo.EndOfFile;
3045 /* Mapping zero-sized files isn't allowed. */
3046 if (MaximumSize.QuadPart == 0)
3047 {
3048 ObDereferenceObject(Section);
3049 ObDereferenceObject(FileObject);
3050 return STATUS_FILE_INVALID;
3051 }
3052 }
3053
3054 if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart)
3055 {
3056 Status = IoSetInformation(FileObject,
3057 FileAllocationInformation,
3058 sizeof(LARGE_INTEGER),
3059 &MaximumSize);
3060 if (!NT_SUCCESS(Status))
3061 {
3062 ObDereferenceObject(Section);
3063 ObDereferenceObject(FileObject);
3064 return(STATUS_SECTION_NOT_EXTENDED);
3065 }
3066 }
3067
3068 if (FileObject->SectionObjectPointer == NULL ||
3069 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
3070 {
3071 /*
3072 * Read a bit so caching is initiated for the file object.
3073 * This is only needed because MiReadPage currently cannot
3074 * handle non-cached streams.
3075 */
3076 Offset.QuadPart = 0;
3077 Status = ZwReadFile(FileHandle,
3078 NULL,
3079 NULL,
3080 NULL,
3081 &Iosb,
3082 &Buffer,
3083 sizeof (Buffer),
3084 &Offset,
3085 0);
3086 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
3087 {
3088 ObDereferenceObject(Section);
3089 ObDereferenceObject(FileObject);
3090 return(Status);
3091 }
3092 if (FileObject->SectionObjectPointer == NULL ||
3093 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
3094 {
3095 /* FIXME: handle this situation */
3096 ObDereferenceObject(Section);
3097 ObDereferenceObject(FileObject);
3098 return STATUS_INVALID_PARAMETER;
3099 }
3100 }
3101
3102 /*
3103 * Lock the file
3104 */
3105 Status = MmspWaitForFileLock(FileObject);
3106 if (Status != STATUS_SUCCESS)
3107 {
3108 ObDereferenceObject(Section);
3109 ObDereferenceObject(FileObject);
3110 return(Status);
3111 }
3112
3113 /*
3114 * If this file hasn't been mapped as a data file before then allocate a
3115 * section segment to describe the data file mapping
3116 */
3117 if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
3118 {
3119 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
3120 TAG_MM_SECTION_SEGMENT);
3121 if (Segment == NULL)
3122 {
3123 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3124 ObDereferenceObject(Section);
3125 ObDereferenceObject(FileObject);
3126 return(STATUS_NO_MEMORY);
3127 }
3128 Section->Segment = Segment;
3129 Segment->ReferenceCount = 1;
3130 ExInitializeFastMutex(&Segment->Lock);
3131 /*
3132 * Set the lock before assigning the segment to the file object
3133 */
3134 ExAcquireFastMutex(&Segment->Lock);
3135 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
3136
3137 Segment->Image.FileOffset = 0;
3138 Segment->Protection = SectionPageProtection;
3139 Segment->Flags = MM_DATAFILE_SEGMENT;
3140 Segment->Image.Characteristics = 0;
3141 Segment->WriteCopy = (SectionPageProtection & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY));
3142 if (AllocationAttributes & SEC_RESERVE)
3143 {
3144 Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0;
3145 }
3146 else
3147 {
3148 Segment->RawLength.QuadPart = MaximumSize.QuadPart;
3149 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
3150 }
3151 Segment->Image.VirtualAddress = 0;
3152 Segment->Locked = TRUE;
3153 MiInitializeSectionPageTable(Segment);
3154 }
3155 else
3156 {
3157 /*
3158 * If the file is already mapped as a data file then we may need
3159 * to extend it
3160 */
3161 Segment =
3162 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
3163 DataSectionObject;
3164 Section->Segment = Segment;
3165 (void)InterlockedIncrementUL(&Segment->ReferenceCount);
3166 MmLockSectionSegment(Segment);
3167
3168 if (MaximumSize.QuadPart > Segment->RawLength.QuadPart &&
3169 !(AllocationAttributes & SEC_RESERVE))
3170 {
3171 Segment->RawLength.QuadPart = MaximumSize.QuadPart;
3172 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
3173 }
3174 }
3175 MmUnlockSectionSegment(Segment);
3176 Section->FileObject = FileObject;
3177 Section->MaximumSize = MaximumSize;
3178 #ifndef NEWCC
3179 CcRosReferenceCache(FileObject);
3180 #endif
3181 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3182 *SectionObject = Section;
3183 return(STATUS_SUCCESS);
3184 }
3185
3186 /*
3187 TODO: not that great (declaring loaders statically, having to declare all of
3188 them, having to keep them extern, etc.), will fix in the future
3189 */
3190 extern NTSTATUS NTAPI PeFmtCreateSection
3191 (
3192 IN CONST VOID * FileHeader,
3193 IN SIZE_T FileHeaderSize,
3194 IN PVOID File,
3195 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3196 OUT PULONG Flags,
3197 IN PEXEFMT_CB_READ_FILE ReadFileCb,
3198 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3199 );
3200
3201 extern NTSTATUS NTAPI ElfFmtCreateSection
3202 (
3203 IN CONST VOID * FileHeader,
3204 IN SIZE_T FileHeaderSize,
3205 IN PVOID File,
3206 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3207 OUT PULONG Flags,
3208 IN PEXEFMT_CB_READ_FILE ReadFileCb,
3209 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
3210 );
3211
3212 /* TODO: this is a standard DDK/PSDK macro */
3213 #ifndef RTL_NUMBER_OF
3214 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
3215 #endif
3216
3217 static PEXEFMT_LOADER ExeFmtpLoaders[] =
3218 {
3219 PeFmtCreateSection,
3220 #ifdef __ELF
3221 ElfFmtCreateSection
3222 #endif
3223 };
3224
3225 static
3226 PMM_SECTION_SEGMENT
3227 NTAPI
3228 ExeFmtpAllocateSegments(IN ULONG NrSegments)
3229 {
3230 SIZE_T SizeOfSegments;
3231 PMM_SECTION_SEGMENT Segments;
3232
3233 /* TODO: check for integer overflow */
3234 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments;
3235
3236 Segments = ExAllocatePoolWithTag(NonPagedPool,
3237 SizeOfSegments,
3238 TAG_MM_SECTION_SEGMENT);
3239
3240 if(Segments)
3241 RtlZeroMemory(Segments, SizeOfSegments);
3242
3243 return Segments;
3244 }
3245
3246 static
3247 NTSTATUS
3248 NTAPI
3249 ExeFmtpReadFile(IN PVOID File,
3250 IN PLARGE_INTEGER Offset,
3251 IN ULONG Length,
3252 OUT PVOID * Data,
3253 OUT PVOID * AllocBase,
3254 OUT PULONG ReadSize)
3255 {
3256 NTSTATUS Status;
3257 LARGE_INTEGER FileOffset;
3258 ULONG AdjustOffset;
3259 ULONG OffsetAdjustment;
3260 ULONG BufferSize;
3261 ULONG UsedSize;
3262 PVOID Buffer;
3263 PFILE_OBJECT FileObject = File;
3264 IO_STATUS_BLOCK Iosb;
3265
3266 ASSERT_IRQL_LESS(DISPATCH_LEVEL);
3267
3268 if(Length == 0)
3269 {
3270 KeBugCheck(MEMORY_MANAGEMENT);
3271 }
3272
3273 FileOffset = *Offset;
3274
3275 /* Negative/special offset: it cannot be used in this context */
3276 if(FileOffset.u.HighPart < 0)
3277 {
3278 KeBugCheck(MEMORY_MANAGEMENT);
3279 }
3280
3281 AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart);
3282 OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset;
3283 FileOffset.u.LowPart = AdjustOffset;
3284
3285 BufferSize = Length + OffsetAdjustment;
3286 BufferSize = PAGE_ROUND_UP(BufferSize);
3287
3288 /*
3289 * It's ok to use paged pool, because this is a temporary buffer only used in
3290 * the loading of executables. The assumption is that MmCreateSection is
3291 * always called at low IRQLs and that these buffers don't survive a brief
3292 * initialization phase
3293 */
3294 Buffer = ExAllocatePoolWithTag(PagedPool,
3295 BufferSize,
3296 'rXmM');
3297 if (!Buffer)
3298 {
3299 KeBugCheck(MEMORY_MANAGEMENT);
3300 }
3301
3302 UsedSize = 0;
3303
3304 Status = MiSimpleRead(FileObject, &FileOffset, Buffer, BufferSize, TRUE, &Iosb);
3305
3306 UsedSize = Iosb.Information;
3307
3308 if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
3309 {
3310 Status = STATUS_IN_PAGE_ERROR;
3311 ASSERT(!NT_SUCCESS(Status));
3312 }
3313
3314 if(NT_SUCCESS(Status))
3315 {
3316 *Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment);
3317 *AllocBase = Buffer;
3318 *ReadSize = UsedSize - OffsetAdjustment;
3319 }
3320 else
3321 {
3322 ExFreePoolWithTag(Buffer, 'rXmM');
3323 }
3324
3325 return Status;
3326 }
3327
3328 #ifdef NASSERT
3329 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
3330 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
3331 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
3332 #else
3333 static
3334 VOID
3335 NTAPI
3336 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3337 {
3338 ULONG i;
3339
3340 for( i = 1; i < ImageSectionObject->NrSegments; ++ i )
3341 {
3342 ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >=
3343 ImageSectionObject->Segments[i - 1].Image.VirtualAddress);
3344 }
3345 }
3346
3347 static
3348 VOID
3349 NTAPI
3350 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3351 {
3352 ULONG i;
3353
3354 MmspAssertSegmentsSorted(ImageSectionObject);
3355
3356 for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3357 {
3358 ASSERT(ImageSectionObject->Segments[i].Length.QuadPart > 0);
3359
3360 if(i > 0)
3361 {
3362 ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >=
3363 (ImageSectionObject->Segments[i - 1].Image.VirtualAddress +
3364 ImageSectionObject->Segments[i - 1].Length.QuadPart));
3365 }
3366 }
3367 }
3368
3369 static
3370 VOID
3371 NTAPI
3372 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3373 {
3374 ULONG i;
3375
3376 for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3377 {
3378 ASSERT((ImageSectionObject->Segments[i].Image.VirtualAddress % PAGE_SIZE) == 0);
3379 ASSERT((ImageSectionObject->Segments[i].Length.QuadPart % PAGE_SIZE) == 0);
3380 }
3381 }
3382 #endif
3383
3384 static
3385 int
3386 __cdecl
3387 MmspCompareSegments(const void * x,
3388 const void * y)
3389 {
3390 const MM_SECTION_SEGMENT *Segment1 = (const MM_SECTION_SEGMENT *)x;
3391 const MM_SECTION_SEGMENT *Segment2 = (const MM_SECTION_SEGMENT *)y;
3392
3393 return
3394 (Segment1->Image.VirtualAddress - Segment2->Image.VirtualAddress) >>
3395 ((sizeof(ULONG_PTR) - sizeof(int)) * 8);
3396 }
3397
3398 /*
3399 * Ensures an image section's segments are sorted in memory
3400 */
3401 static
3402 VOID
3403 NTAPI
3404 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3405 IN ULONG Flags)
3406 {
3407 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED)
3408 {
3409 MmspAssertSegmentsSorted(ImageSectionObject);
3410 }
3411 else
3412 {
3413 qsort(ImageSectionObject->Segments,
3414 ImageSectionObject->NrSegments,
3415 sizeof(ImageSectionObject->Segments[0]),
3416 MmspCompareSegments);
3417 }
3418 }
3419
3420
3421 /*
3422 * Ensures an image section's segments don't overlap in memory and don't have
3423 * gaps and don't have a null size. We let them map to overlapping file regions,
3424 * though - that's not necessarily an error
3425 */
3426 static
3427 BOOLEAN
3428 NTAPI
3429 MmspCheckSegmentBounds
3430 (
3431 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3432 IN ULONG Flags
3433 )
3434 {
3435 ULONG i;
3436
3437 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP)
3438 {
3439 MmspAssertSegmentsNoOverlap(ImageSectionObject);
3440 return TRUE;
3441 }
3442
3443 ASSERT(ImageSectionObject->NrSegments >= 1);
3444
3445 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3446 {
3447 if(ImageSectionObject->Segments[i].Length.QuadPart == 0)
3448 {
3449 return FALSE;
3450 }
3451
3452 if(i > 0)
3453 {
3454 /*
3455 * TODO: relax the limitation on gaps. For example, gaps smaller than a
3456 * page could be OK (Windows seems to be OK with them), and larger gaps
3457 * could lead to image sections spanning several discontiguous regions
3458 * (NtMapViewOfSection could then refuse to map them, and they could
3459 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
3460 */
3461 if ((ImageSectionObject->Segments[i - 1].Image.VirtualAddress +
3462 ImageSectionObject->Segments[i - 1].Length.QuadPart) !=
3463 ImageSectionObject->Segments[i].Image.VirtualAddress)
3464 {
3465 return FALSE;
3466 }
3467 }
3468 }
3469
3470 return TRUE;
3471 }
3472
3473 /*
3474 * Merges and pads an image section's segments until they all are page-aligned
3475 * and have a size that is a multiple of the page size
3476 */
3477 static
3478 BOOLEAN
3479 NTAPI
3480 MmspPageAlignSegments
3481 (
3482 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
3483 IN ULONG Flags
3484 )
3485 {
3486 ULONG i;
3487 ULONG LastSegment;
3488 PMM_SECTION_SEGMENT EffectiveSegment;
3489
3490 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED)
3491 {
3492 MmspAssertSegmentsPageAligned(ImageSectionObject);
3493 return TRUE;
3494 }
3495
3496 LastSegment = 0;
3497 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
3498
3499 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3500 {
3501 /*
3502 * The first segment requires special handling
3503 */
3504 if (i == 0)
3505 {
3506 ULONG_PTR VirtualAddress;
3507 ULONG_PTR VirtualOffset;
3508
3509 VirtualAddress = EffectiveSegment->Image.VirtualAddress;
3510
3511 /* Round down the virtual address to the nearest page */
3512 EffectiveSegment->Image.VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
3513
3514 /* Round up the virtual size to the nearest page */
3515 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length.QuadPart) -
3516 EffectiveSegment->Image.VirtualAddress;
3517
3518 /* Adjust the raw address and size */
3519 VirtualOffset = VirtualAddress - EffectiveSegment->Image.VirtualAddress;
3520
3521 if (EffectiveSegment->Image.FileOffset < VirtualOffset)
3522 {
3523 return FALSE;
3524 }
3525
3526 /*
3527 * Garbage in, garbage out: unaligned base addresses make the file
3528 * offset point in curious and odd places, but that's what we were
3529 * asked for
3530 */
3531 EffectiveSegment->Image.FileOffset -= VirtualOffset;
3532 EffectiveSegment->RawLength.QuadPart += VirtualOffset;
3533 }
3534 else
3535 {
3536 PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
3537 ULONG_PTR EndOfEffectiveSegment;
3538
3539 EndOfEffectiveSegment = EffectiveSegment->Image.VirtualAddress + EffectiveSegment->Length.QuadPart;
3540 ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
3541
3542 /*
3543 * The current segment begins exactly where the current effective
3544 * segment ended, therefore beginning a new effective segment
3545 */
3546 if (EndOfEffectiveSegment == Segment->Image.VirtualAddress)
3547 {
3548 LastSegment ++;
3549 ASSERT(LastSegment <= i);
3550 ASSERT(LastSegment < ImageSectionObject->NrSegments);
3551
3552 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
3553
3554 if (LastSegment != i)
3555 {
3556 /*
3557 * Copy the current segment. If necessary, the effective segment
3558 * will be expanded later
3559 */
3560 *EffectiveSegment = *Segment;
3561 }
3562
3563 /*
3564 * Page-align the virtual size. We know for sure the virtual address
3565 * already is
3566 */
3567 ASSERT((EffectiveSegment->Image.VirtualAddress % PAGE_SIZE) == 0);
3568 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(EffectiveSegment->Length.QuadPart);
3569 }
3570 /*
3571 * The current segment is still part of the current effective segment:
3572 * extend the effective segment to reflect this
3573 */
3574 else if (EndOfEffectiveSegment > Segment->Image.VirtualAddress)
3575 {
3576 static const ULONG FlagsToProtection[16] =
3577 {
3578 PAGE_NOACCESS,
3579 PAGE_READONLY,
3580 PAGE_READWRITE,
3581 PAGE_READWRITE,
3582 PAGE_EXECUTE_READ,
3583 PAGE_EXECUTE_READ,
3584 PAGE_EXECUTE_READWRITE,
3585 PAGE_EXECUTE_READWRITE,
3586 PAGE_WRITECOPY,
3587 PAGE_WRITECOPY,
3588 PAGE_WRITECOPY,
3589 PAGE_WRITECOPY,
3590 PAGE_EXECUTE_WRITECOPY,
3591 PAGE_EXECUTE_WRITECOPY,
3592 PAGE_EXECUTE_WRITECOPY,
3593 PAGE_EXECUTE_WRITECOPY
3594 };
3595
3596 unsigned ProtectionFlags;
3597
3598 /*
3599 * Extend the file size
3600 */
3601
3602 /* Unaligned segments must be contiguous within the file */
3603 if (Segment->Image.FileOffset != (EffectiveSegment->Image.FileOffset +
3604 EffectiveSegment->RawLength.QuadPart))
3605 {
3606 return FALSE;
3607 }
3608
3609 EffectiveSegment->RawLength.QuadPart += Segment->RawLength.QuadPart;
3610
3611 /*
3612 * Extend the virtual size
3613 */
3614 ASSERT(PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) >= EndOfEffectiveSegment);
3615
3616 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) -
3617 EffectiveSegment->Image.VirtualAddress;
3618
3619 /*
3620 * Merge the protection
3621 */
3622 EffectiveSegment->Protection |= Segment->Protection;
3623
3624 /* Clean up redundance */
3625 ProtectionFlags = 0;
3626
3627 if(EffectiveSegment->Protection & PAGE_IS_READABLE)
3628 ProtectionFlags |= 1 << 0;
3629
3630 if(EffectiveSegment->Protection & PAGE_IS_WRITABLE)
3631 ProtectionFlags |= 1 << 1;
3632
3633 if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE)
3634 ProtectionFlags |= 1 << 2;
3635
3636 if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3637 ProtectionFlags |= 1 << 3;
3638
3639 ASSERT(ProtectionFlags < 16);
3640 EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags];
3641
3642 /* If a segment was required to be shared and cannot, fail */
3643 if(!(Segment->Protection & PAGE_IS_WRITECOPY) &&
3644 EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3645 {
3646 return FALSE;
3647 }
3648 }
3649 /*
3650 * We assume no holes between segments at this point
3651 */
3652 else
3653 {
3654 KeBugCheck(MEMORY_MANAGEMENT);
3655 }
3656 }
3657 }
3658 ImageSectionObject->NrSegments = LastSegment + 1;
3659
3660 return TRUE;
3661 }
3662
3663 NTSTATUS
3664 ExeFmtpCreateImageSection(HANDLE FileHandle,
3665 PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3666 {
3667 LARGE_INTEGER Offset;
3668 PVOID FileHeader;
3669 PVOID FileHeaderBuffer;
3670 ULONG FileHeaderSize;
3671 ULONG Flags;
3672 ULONG OldNrSegments;
3673 NTSTATUS Status;
3674 ULONG i;
3675
3676 /*
3677 * Read the beginning of the file (2 pages). Should be enough to contain
3678 * all (or most) of the headers
3679 */
3680 Offset.QuadPart = 0;
3681
3682 /* FIXME: use FileObject instead of FileHandle */
3683 Status = ExeFmtpReadFile (FileHandle,
3684 &Offset,
3685 PAGE_SIZE * 2,
3686 &FileHeader,
3687 &FileHeaderBuffer,
3688 &FileHeaderSize);
3689
3690 if (!NT_SUCCESS(Status))
3691 return Status;
3692
3693 if (FileHeaderSize == 0)
3694 {
3695 ExFreePool(FileHeaderBuffer);
3696 return STATUS_UNSUCCESSFUL;
3697 }
3698
3699 /*
3700 * Look for a loader that can handle this executable
3701 */
3702 for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i)
3703 {
3704 RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject));
3705 Flags = 0;
3706
3707 /* FIXME: use FileObject instead of FileHandle */
3708 Status = ExeFmtpLoaders[i](FileHeader,
3709 FileHeaderSize,
3710 FileHandle,
3711 ImageSectionObject,
3712 &Flags,
3713 ExeFmtpReadFile,
3714 ExeFmtpAllocateSegments);
3715
3716 if (!NT_SUCCESS(Status))
3717 {
3718 if (ImageSectionObject->Segments)
3719 {
3720 ExFreePool(ImageSectionObject->Segments);
3721 ImageSectionObject->Segments = NULL;
3722 }
3723 }
3724
3725 if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3726 break;
3727 }
3728
3729 ExFreePoolWithTag(FileHeaderBuffer, 'rXmM');
3730
3731 /*
3732 * No loader handled the format
3733 */
3734 if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3735 {
3736 Status = STATUS_INVALID_IMAGE_NOT_MZ;
3737 ASSERT(!NT_SUCCESS(Status));
3738 }
3739
3740 if (!NT_SUCCESS(Status))
3741 return Status;
3742
3743 ASSERT(ImageSectionObject->Segments != NULL);
3744
3745 /*
3746 * Some defaults
3747 */
3748 /* FIXME? are these values platform-dependent? */
3749 if(ImageSectionObject->StackReserve == 0)
3750 ImageSectionObject->StackReserve = 0x40000;
3751
3752 if(ImageSectionObject->StackCommit == 0)
3753 ImageSectionObject->StackCommit = 0x1000;
3754
3755 if(ImageSectionObject->ImageBase == 0)
3756 {
3757 if(ImageSectionObject->ImageCharacteristics & IMAGE_FILE_DLL)
3758 ImageSectionObject->ImageBase = 0x10000000;
3759 else
3760 ImageSectionObject->ImageBase = 0x00400000;
3761 }
3762
3763 /*
3764 * And now the fun part: fixing the segments
3765 */
3766
3767 /* Sort them by virtual address */
3768 MmspSortSegments(ImageSectionObject, Flags);
3769
3770 /* Ensure they don't overlap in memory */
3771 if (!MmspCheckSegmentBounds(ImageSectionObject, Flags))
3772 return STATUS_INVALID_IMAGE_FORMAT;
3773
3774 /* Ensure they are aligned */
3775 OldNrSegments = ImageSectionObject->NrSegments;
3776
3777 if (!MmspPageAlignSegments(ImageSectionObject, Flags))
3778 return STATUS_INVALID_IMAGE_FORMAT;
3779
3780 /* Trim them if the alignment phase merged some of them */
3781 if (ImageSectionObject->NrSegments < OldNrSegments)
3782 {
3783 PMM_SECTION_SEGMENT Segments;
3784 SIZE_T SizeOfSegments;
3785
3786 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments;
3787
3788 Segments = ExAllocatePoolWithTag(PagedPool,
3789 SizeOfSegments,
3790 TAG_MM_SECTION_SEGMENT);
3791
3792 if (Segments == NULL)
3793 return STATUS_INSUFFICIENT_RESOURCES;
3794
3795 RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments);
3796 ExFreePool(ImageSectionObject->Segments);
3797 ImageSectionObject->Segments = Segments;
3798 }
3799
3800 /* And finish their initialization */
3801 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3802 {
3803 ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock);
3804 ImageSectionObject->Segments[i].ReferenceCount = 1;
3805 MiInitializeSectionPageTable(&ImageSectionObject->Segments[i]);
3806 }
3807
3808 ASSERT(NT_SUCCESS(Status));
3809 return Status;
3810 }
3811
3812 NTSTATUS
3813 MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
3814 ACCESS_MASK DesiredAccess,
3815 POBJECT_ATTRIBUTES ObjectAttributes,
3816 PLARGE_INTEGER UMaximumSize,
3817 ULONG SectionPageProtection,
3818 ULONG AllocationAttributes,
3819 PFILE_OBJECT FileObject)
3820 {
3821 PROS_SECTION_OBJECT Section;
3822 NTSTATUS Status;
3823 PMM_SECTION_SEGMENT SectionSegments;
3824 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3825 ULONG i;
3826
3827 if (FileObject == NULL)
3828 return STATUS_INVALID_FILE_FOR_SECTION;
3829
3830 /*
3831 * Create the section
3832 */
3833 Status = ObCreateObject (ExGetPreviousMode(),
3834 MmSectionObjectType,
3835 ObjectAttributes,
3836 ExGetPreviousMode(),
3837 NULL,
3838 sizeof(ROS_SECTION_OBJECT),
3839 0,
3840 0,
3841 (PVOID*)(PVOID)&Section);
3842 if (!NT_SUCCESS(Status))
3843 {
3844 ObDereferenceObject(FileObject);
3845 return(Status);
3846 }
3847
3848 /*
3849 * Initialize it
3850 */
3851 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
3852 Section->Type = 'SC';
3853 Section->Size = 'TN';
3854 Section->SectionPageProtection = SectionPageProtection;
3855 Section->AllocationAttributes = AllocationAttributes;
3856
3857 #ifndef NEWCC
3858 /*
3859 * Initialized caching for this file object if previously caching
3860 * was initialized for the same on disk file
3861 */
3862 Status = CcTryToInitializeFileCache(FileObject);
3863 #else
3864 Status = STATUS_SUCCESS;
3865 #endif
3866
3867 if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
3868 {
3869 NTSTATUS StatusExeFmt;
3870
3871 ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
3872 if (ImageSectionObject == NULL)
3873 {
3874 ObDereferenceObject(FileObject);
3875 ObDereferenceObject(Section);
3876 return(STATUS_NO_MEMORY);
3877 }
3878
3879 RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
3880
3881 StatusExeFmt = ExeFmtpCreateImageSection(FileObject, ImageSectionObject);
3882
3883 if (!NT_SUCCESS(StatusExeFmt))
3884 {
3885 if(ImageSectionObject->Segments != NULL)
3886 ExFreePool(ImageSectionObject->Segments);
3887
3888 ExFreePool(ImageSectionObject);
3889 ObDereferenceObject(Section);
3890 ObDereferenceObject(FileObject);
3891 return(StatusExeFmt);
3892 }
3893
3894 Section->ImageSection = ImageSectionObject;
3895 ASSERT(ImageSectionObject->Segments);
3896
3897 /*
3898 * Lock the file
3899 */
3900 Status = MmspWaitForFileLock(FileObject);
3901 if (!NT_SUCCESS(Status))
3902 {
3903 ExFreePool(ImageSectionObject->Segments);
3904 ExFreePool(ImageSectionObject);
3905 ObDereferenceObject(Section);
3906 ObDereferenceObject(FileObject);
3907 return(Status);
3908 }
3909
3910 if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject,
3911 ImageSectionObject, NULL))
3912 {
3913 /*
3914 * An other thread has initialized the same image in the background
3915 */
3916 ExFreePool(ImageSectionObject->Segments);
3917 ExFreePool(ImageSectionObject);
3918 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3919 Section->ImageSection = ImageSectionObject;
3920 SectionSegments = ImageSectionObject->Segments;
3921
3922 for (i = 0; i < ImageSectionObject->NrSegments; i++)
3923 {
3924 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3925 }
3926 }
3927
3928 Status = StatusExeFmt;
3929 }
3930 else
3931 {
3932 /*
3933 * Lock the file
3934 */
3935 Status = MmspWaitForFileLock(FileObject);
3936 if (Status != STATUS_SUCCESS)
3937 {
3938 ObDereferenceObject(Section);
3939 ObDereferenceObject(FileObject);
3940 return(Status);
3941 }
3942
3943 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3944 Section->ImageSection = ImageSectionObject;
3945 SectionSegments = ImageSectionObject->Segments;
3946
3947 /*
3948 * Otherwise just reference all the section segments
3949 */
3950 for (i = 0; i < ImageSectionObject->NrSegments; i++)
3951 {
3952 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3953 }
3954
3955 Status = STATUS_SUCCESS;
3956 }
3957 Section->FileObject = FileObject;
3958 #ifndef NEWCC
3959 CcRosReferenceCache(FileObject);
3960 #endif
3961 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3962 *SectionObject = Section;
3963 return(Status);
3964 }
3965
3966
3967
3968 static NTSTATUS
3969 MmMapViewOfSegment(PMMSUPPORT AddressSpace,
3970 PROS_SECTION_OBJECT Section,
3971 PMM_SECTION_SEGMENT Segment,
3972 PVOID* BaseAddress,
3973 SIZE_T ViewSize,
3974 ULONG Protect,
3975 ULONG ViewOffset,
3976 ULONG AllocationType)
3977 {
3978 PMEMORY_AREA MArea;
3979 NTSTATUS Status;
3980 PHYSICAL_ADDRESS BoundaryAddressMultiple;
3981
3982 if (Segment->WriteCopy)
3983 {
3984 /* We have to do this because the not present fault
3985 * and access fault handlers depend on the protection
3986 * that should be granted AFTER the COW fault takes
3987 * place to be in Region->Protect. The not present fault
3988 * handler changes this to the correct protection for COW when
3989 * mapping the pages into the process's address space. If a COW
3990 * fault takes place, the access fault handler sets the page protection
3991 * to these values for the newly copied pages
3992 */
3993 if (Protect == PAGE_WRITECOPY)
3994 Protect = PAGE_READWRITE;
3995 else if (Protect == PAGE_EXECUTE_WRITECOPY)
3996 Protect = PAGE_EXECUTE_READWRITE;
3997 }
3998
3999 BoundaryAddressMultiple.QuadPart = 0;
4000
4001 #ifdef NEWCC
4002 if (Segment->Flags & MM_DATAFILE_SEGMENT) {
4003 LARGE_INTEGER FileOffset;
4004 FileOffset.QuadPart = ViewOffset;
4005 ObReferenceObject(Section);
4006 return _MiMapViewOfSegment(AddressSpace, Segment, BaseAddress, ViewSize, Protect, &FileOffset, AllocationType, __FILE__, __LINE__);
4007 }
4008 #endif
4009 Status = MmCreateMemoryArea(AddressSpace,
4010 MEMORY_AREA_SECTION_VIEW,
4011 BaseAddress,
4012 ViewSize,
4013 Protect,
4014 &MArea,
4015 FALSE,
4016 AllocationType,
4017 BoundaryAddressMultiple);
4018 if (!NT_SUCCESS(Status))
4019 {
4020 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
4021 (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
4022 return(Status);
4023 }
4024
4025 ObReferenceObject((PVOID)Section);
4026
4027 MArea->Data.SectionData.Segment = Segment;
4028 MArea->Data.SectionData.Section = Section;
4029 MArea->Data.SectionData.ViewOffset.QuadPart = ViewOffset;
4030 MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
4031 ViewSize, 0, Protect);
4032
4033 return(STATUS_SUCCESS);
4034 }
4035
4036
4037 static VOID
4038 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
4039 PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
4040 {
4041 ULONG Entry;
4042 PFILE_OBJECT FileObject;
4043 PBCB Bcb;
4044 LARGE_INTEGER Offset;
4045 SWAPENTRY SavedSwapEntry;
4046 PMM_PAGEOP PageOp;
4047 NTSTATUS Status;
4048 PROS_SECTION_OBJECT Section;
4049 PMM_SECTION_SEGMENT Segment;
4050 PMMSUPPORT AddressSpace;
4051 PEPROCESS Process;
4052
4053 AddressSpace = (PMMSUPPORT)Context;
4054 Process = MmGetAddressSpaceOwner(AddressSpace);
4055
4056 Address = (PVOID)PAGE_ROUND_DOWN(Address);
4057
4058 Offset.QuadPart = ((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress) +
4059 MemoryArea->Data.SectionData.ViewOffset.QuadPart;
4060
4061 Section = MemoryArea->Data.SectionData.Section;
4062 Segment = MemoryArea->Data.SectionData.Segment;
4063
4064 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset.LowPart);
4065
4066 while (PageOp)
4067 {
4068 MmUnlockSectionSegment(Segment);
4069 MmUnlockAddressSpace(AddressSpace);
4070
4071 Status = MmspWaitForPageOpCompletionEvent(PageOp);
4072 if (Status != STATUS_SUCCESS)
4073 {
4074 DPRINT1("Failed to wait for page op, status = %x\n", Status);
4075 KeBugCheck(MEMORY_MANAGEMENT);
4076 }
4077
4078 MmLockAddressSpace(AddressSpace);
4079 MmLockSectionSegment(Segment);
4080 MmspCompleteAndReleasePageOp(PageOp);
4081 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset.LowPart);
4082 }
4083
4084 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
4085
4086 /*
4087 * For a dirty, datafile, non-private page mark it as dirty in the
4088 * cache manager.
4089 */
4090 if (Segment->Flags & MM_DATAFILE_SEGMENT)
4091 {
4092 if (Page == PFN_FROM_SSE(Entry) && Dirty)
4093 {
4094 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
4095 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
4096 #ifndef NEWCC
4097 CcRosMarkDirtyCacheSegment(Bcb, Offset.QuadPart + Segment->Image.FileOffset);
4098 #endif
4099 ASSERT(SwapEntry == 0);
4100 }
4101 }
4102
4103 if (SwapEntry != 0)
4104 {
4105 /*
4106 * Sanity check
4107 */
4108 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
4109 {
4110 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4111 KeBugCheck(MEMORY_MANAGEMENT);
4112 }
4113 MmFreeSwapPage(SwapEntry);
4114 }
4115 else if (Page != 0)
4116 {
4117 if (IS_SWAP_FROM_SSE(Entry) ||
4118 Page != PFN_FROM_SSE(Entry))
4119 {
4120 /*
4121 * Sanity check
4122 */
4123 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
4124 {
4125 DPRINT1("Found a private page in a pagefile section.\n");
4126 KeBugCheck(MEMORY_MANAGEMENT);
4127 }
4128 /*
4129 * Just dereference private pages
4130 */
4131 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
4132 if (SavedSwapEntry != 0)
4133 {
4134 MmFreeSwapPage(SavedSwapEntry);
4135 MmSetSavedSwapEntryPage(Page, 0);
4136 }
4137 MmDeleteRmap(Page, Process, Address);
4138 MmReleasePageMemoryConsumer(MC_USER, Page);
4139 }
4140 else
4141 {
4142 MmDeleteRmap(Page, Process, Address);
4143 MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, Dirty, FALSE);
4144 }
4145 }
4146 }
4147
4148 static NTSTATUS
4149 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace,
4150 PVOID BaseAddress)
4151 {
4152 NTSTATUS Status;
4153 PMEMORY_AREA MemoryArea;
4154 PROS_SECTION_OBJECT Section;
4155 PMM_SECTION_SEGMENT Segment;
4156 PLIST_ENTRY CurrentEntry;
4157 PMM_REGION CurrentRegion;
4158 PLIST_ENTRY RegionListHead;
4159
4160 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4161 BaseAddress);
4162 if (MemoryArea == NULL)
4163 {
4164 return(STATUS_UNSUCCESSFUL);
4165 }
4166
4167 MemoryArea->DeleteInProgress = TRUE;
4168 Section = MemoryArea->Data.SectionData.Section;
4169 Segment = MemoryArea->Data.SectionData.Segment;
4170
4171 #ifdef NEWCC
4172 if (Segment->Flags & MM_DATAFILE_SEGMENT)
4173 return MmUnmapViewOfCacheSegment(AddressSpace, BaseAddress);
4174 #endif
4175
4176 MmLockSectionSegment(Segment);
4177
4178 RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
4179 while (!IsListEmpty(RegionListHead))
4180 {
4181 CurrentEntry = RemoveHeadList(RegionListHead);
4182 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
4183 ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION);
4184 }
4185
4186 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
4187 {
4188 Status = MmFreeMemoryArea(AddressSpace,
4189 MemoryArea,
4190 NULL,
4191 NULL);
4192 }
4193 else
4194 {
4195 Status = MmFreeMemoryArea(AddressSpace,
4196 MemoryArea,
4197 MmFreeSectionPage,
4198 AddressSpace);
4199 }
4200 MmUnlockSectionSegment(Segment);
4201 ObDereferenceObject(Section);
4202 return(Status);
4203 }
4204
4205 /*
4206 * @implemented
4207 */
4208 NTSTATUS NTAPI
4209 MmUnmapViewOfSection(PEPROCESS Process,
4210 PVOID BaseAddress)
4211 {
4212 NTSTATUS Status;
4213 PMEMORY_AREA MemoryArea;
4214 PMMSUPPORT AddressSpace;
4215 PROS_SECTION_OBJECT Section;
4216 PMM_PAGEOP PageOp;
4217 ULONG_PTR Offset;
4218 PVOID ImageBaseAddress = 0;
4219
4220 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4221 Process, BaseAddress);
4222
4223 ASSERT(Process);
4224
4225 AddressSpace = &Process->Vm;
4226
4227 MmLockAddressSpace(AddressSpace);
4228 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4229 BaseAddress);
4230 if (MemoryArea == NULL ||
4231 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW ||
4232 MemoryArea->DeleteInProgress)
4233 {
4234 MmUnlockAddressSpace(AddressSpace);
4235 return STATUS_NOT_MAPPED_VIEW;
4236 }
4237
4238 MemoryArea->DeleteInProgress = TRUE;
4239
4240 while (MemoryArea->PageOpCount)
4241 {
4242 Offset = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress);
4243
4244 while (Offset)
4245 {
4246 Offset -= PAGE_SIZE;
4247 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL,
4248 MemoryArea->Data.SectionData.Segment,
4249 Offset + MemoryArea->Data.SectionData.ViewOffset.QuadPart);
4250 if (PageOp)
4251 {
4252 MmUnlockAddressSpace(AddressSpace);
4253 Status = MmspWaitForPageOpCompletionEvent(PageOp);
4254 if (Status != STATUS_SUCCESS)
4255 {
4256 DPRINT1("Failed to wait for page op, status = %x\n", Status);
4257 KeBugCheck(MEMORY_MANAGEMENT);
4258 }
4259 MmLockAddressSpace(AddressSpace);
4260 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4261 BaseAddress);
4262 if (MemoryArea == NULL ||
4263 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
4264 {
4265 MmUnlockAddressSpace(AddressSpace);
4266 return STATUS_NOT_MAPPED_VIEW;
4267 }
4268 break;
4269 }
4270 }
4271 }
4272
4273 Section = MemoryArea->Data.SectionData.Section;
4274
4275 if (Section->AllocationAttributes & SEC_IMAGE)
4276 {
4277 ULONG i;
4278 ULONG NrSegments;
4279 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4280 PMM_SECTION_SEGMENT SectionSegments;
4281 PMM_SECTION_SEGMENT Segment;
4282
4283 Segment = MemoryArea->Data.SectionData.Segment;
4284 ImageSectionObject = Section->ImageSection;
4285 SectionSegments = ImageSectionObject->Segments;
4286 NrSegments = ImageSectionObject->NrSegments;
4287
4288 /* Search for the current segment within the section segments
4289 * and calculate the image base address */
4290 for (i = 0; i < NrSegments; i++)
4291 {
4292 if (!(SectionSegments[i].Image.Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4293 {
4294 if (Segment == &SectionSegments[i])
4295 {
4296 ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].Image.VirtualAddress;
4297 break;
4298 }
4299 }
4300 }
4301 if (i >= NrSegments)
4302 {
4303 KeBugCheck(MEMORY_MANAGEMENT);
4304 }
4305
4306 for (i = 0; i < NrSegments; i++)
4307 {
4308 if (!(SectionSegments[i].Image.Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4309 {
4310 PVOID SBaseAddress = (PVOID)
4311 ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress);
4312
4313 Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
4314 }
4315 }
4316 }
4317 else
4318 {
4319 Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
4320 }
4321
4322 MmUnlockAddressSpace(AddressSpace);
4323
4324 /* Notify debugger */
4325 if (ImageBaseAddress) DbgkUnMapViewOfSection(ImageBaseAddress);
4326
4327 return(STATUS_SUCCESS);
4328 }
4329
4330
4331
4332
4333 /**
4334 * Queries the information of a section object.
4335 *
4336 * @param SectionHandle
4337 * Handle to the section object. It must be opened with SECTION_QUERY
4338 * access.
4339 * @param SectionInformationClass
4340 * Index to a certain information structure. Can be either
4341 * SectionBasicInformation or SectionImageInformation. The latter
4342 * is valid only for sections that were created with the SEC_IMAGE
4343 * flag.
4344 * @param SectionInformation
4345 * Caller supplies storage for resulting information.
4346 * @param Length
4347 * Size of the supplied storage.
4348 * @param ResultLength
4349 * Data written.
4350 *
4351 * @return Status.
4352 *
4353 * @implemented
4354 */
4355 NTSTATUS NTAPI
4356 NtQuerySection(IN HANDLE SectionHandle,
4357 IN SECTION_INFORMATION_CLASS SectionInformationClass,
4358 OUT PVOID SectionInformation,
4359 IN SIZE_T SectionInformationLength,
4360 OUT PSIZE_T ResultLength OPTIONAL)
4361 {
4362 PROS_SECTION_OBJECT Section;
4363 KPROCESSOR_MODE PreviousMode;
4364 NTSTATUS Status;
4365 PAGED_CODE();
4366
4367 PreviousMode = ExGetPreviousMode();
4368
4369 Status = DefaultQueryInfoBufferCheck(SectionInformationClass,
4370 ExSectionInfoClass,
4371 sizeof(ExSectionInfoClass) / sizeof(ExSectionInfoClass[0]),
4372 SectionInformation,
4373 (ULONG)SectionInformationLength,
4374 NULL,
4375 ResultLength,
4376 PreviousMode);
4377
4378 if(!NT_SUCCESS(Status))
4379 {
4380 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status);
4381 return Status;
4382 }
4383
4384 Status = ObReferenceObjectByHandle(SectionHandle,
4385 SECTION_QUERY,
4386 MmSectionObjectType,
4387 PreviousMode,
4388 (PVOID*)(PVOID)&Section,
4389 NULL);
4390 if (NT_SUCCESS(Status))
4391 {
4392 switch (SectionInformationClass)
4393 {
4394 case SectionBasicInformation:
4395 {
4396 PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
4397
4398 _SEH2_TRY
4399 {
4400 Sbi->Attributes = Section->AllocationAttributes;
4401 if (Section->AllocationAttributes & SEC_IMAGE)
4402 {
4403 Sbi->BaseAddress = 0;
4404 Sbi->Size.QuadPart = 0;
4405 }
4406 else
4407 {
4408 Sbi->BaseAddress = (PVOID)Section->Segment->Image.VirtualAddress;
4409 Sbi->Size.QuadPart = Section->Segment->Length.QuadPart;
4410 }
4411
4412 if (ResultLength != NULL)
4413 {
4414 *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
4415 }
4416 Status = STATUS_SUCCESS;
4417 }
4418 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4419 {
4420 Status = _SEH2_GetExceptionCode();
4421 }
4422 _SEH2_END;
4423
4424 break;
4425 }
4426
4427 case SectionImageInformation:
4428 {
4429 PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
4430
4431 _SEH2_TRY
4432 {
4433 memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
4434 if (Section->AllocationAttributes & SEC_IMAGE)
4435 {
4436 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4437 ImageSectionObject = Section->ImageSection;
4438
4439 Sii->TransferAddress = (PVOID)ImageSectionObject->EntryPoint;
4440 Sii->MaximumStackSize = ImageSectionObject->StackReserve;
4441 Sii->CommittedStackSize = ImageSectionObject->StackCommit;
4442 Sii->SubSystemType = ImageSectionObject->Subsystem;
4443 Sii->SubSystemMinorVersion = ImageSectionObject->MinorSubsystemVersion;
4444 Sii->SubSystemMajorVersion = ImageSectionObject->MajorSubsystemVersion;
4445 Sii->ImageCharacteristics = ImageSectionObject->ImageCharacteristics;
4446 Sii->Machine = ImageSectionObject->Machine;
4447 Sii->ImageContainsCode = ImageSectionObject->Executable;
4448 }
4449
4450 if (ResultLength != NULL)
4451 {
4452 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
4453 }
4454 Status = STATUS_SUCCESS;
4455 }
4456 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4457 {
4458 Status = _SEH2_GetExceptionCode();
4459 }
4460 _SEH2_END;
4461
4462 break;
4463 }
4464 }
4465
4466 ObDereferenceObject(Section);
4467 }
4468
4469 return(Status);
4470 }
4471
4472 /**********************************************************************
4473 * NAME EXPORTED
4474 * MmMapViewOfSection
4475 *
4476 * DESCRIPTION
4477 * Maps a view of a section into the virtual address space of a
4478 * process.
4479 *
4480 * ARGUMENTS
4481 * Section
4482 * Pointer to the section object.
4483 *
4484 * ProcessHandle
4485 * Pointer to the process.
4486 *
4487 * BaseAddress
4488 * Desired base address (or NULL) on entry;
4489 * Actual base address of the view on exit.
4490 *
4491 * ZeroBits
4492 * Number of high order address bits that must be zero.
4493 *
4494 * CommitSize
4495 * Size in bytes of the initially committed section of
4496 * the view.
4497 *
4498 * SectionOffset
4499 * Offset in bytes from the beginning of the section
4500 * to the beginning of the view.
4501 *
4502 * ViewSize
4503 * Desired length of map (or zero to map all) on entry
4504 * Actual length mapped on exit.
4505 *
4506 * InheritDisposition
4507 * Specified how the view is to be shared with
4508 * child processes.
4509 *
4510 * AllocationType
4511 * Type of allocation for the pages.
4512 *
4513 * Protect
4514 * Protection for the committed region of the view.
4515 *
4516 * RETURN VALUE
4517 * Status.
4518 *
4519 * @implemented
4520 */
4521 NTSTATUS NTAPI
4522 MmMapViewOfSection(IN PVOID SectionObject,
4523 IN PEPROCESS Process,
4524 IN OUT PVOID *BaseAddress,
4525 IN ULONG_PTR ZeroBits,
4526 IN SIZE_T CommitSize,
4527 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
4528 IN OUT PSIZE_T ViewSize,
4529 IN SECTION_INHERIT InheritDisposition,
4530 IN ULONG AllocationType,
4531 IN ULONG Protect)
4532 {
4533 PROS_SECTION_OBJECT Section;
4534 PMMSUPPORT AddressSpace;
4535 ULONG ViewOffset;
4536 NTSTATUS Status = STATUS_SUCCESS;
4537 BOOLEAN NotAtBase = FALSE;
4538
4539 if (MiIsRosSectionObject(SectionObject) == FALSE)
4540 {
4541 DPRINT1("Mapping ARM3 section into %s\n", Process->ImageFileName);
4542 return MmMapViewOfArm3Section(SectionObject,
4543 Process,
4544 BaseAddress,
4545 ZeroBits,
4546 CommitSize,
4547 SectionOffset,
4548 ViewSize,
4549 InheritDisposition,
4550 AllocationType,
4551 Protect);
4552 }
4553
4554 ASSERT(Process);
4555
4556 if (!Protect || Protect & ~PAGE_FLAGS_VALID_FOR_SECTION)
4557 {
4558 return STATUS_INVALID_PAGE_PROTECTION;
4559 }
4560
4561
4562 Section = (PROS_SECTION_OBJECT)SectionObject;
4563 AddressSpace = &Process->Vm;
4564
4565 AllocationType |= (Section->AllocationAttributes & SEC_NO_CHANGE);
4566
4567 MmLockAddressSpace(AddressSpace);
4568
4569 if (Section->AllocationAttributes & SEC_IMAGE)
4570 {
4571 ULONG i;
4572 ULONG NrSegments;
4573 ULONG_PTR ImageBase;
4574 SIZE_T ImageSize;
4575 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4576 PMM_SECTION_SEGMENT SectionSegments;
4577
4578 ImageSectionObject = Section->ImageSection;
4579 SectionSegments = ImageSectionObject->Segments;
4580 NrSegments = ImageSectionObject->NrSegments;
4581
4582
4583 ImageBase = (ULONG_PTR)*BaseAddress;
4584 if (ImageBase == 0)
4585 {
4586 ImageBase = ImageSectionObject->ImageBase;
4587 }
4588
4589 ImageSize = 0;
4590 for (i = 0; i < NrSegments; i++)
4591 {
4592 if (!(SectionSegments[i].Image.Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4593 {
4594 ULONG_PTR MaxExtent;
4595 MaxExtent = (ULONG_PTR)SectionSegments[i].Image.VirtualAddress +
4596 SectionSegments[i].Length.QuadPart;
4597 ImageSize = max(ImageSize, MaxExtent);
4598 }
4599 }
4600
4601 ImageSectionObject->ImageSize = (ULONG)ImageSize;
4602
4603 /* Check for an illegal base address */
4604 if ((ImageBase + ImageSize) > (ULONG_PTR)MmHighestUserAddress)
4605 {
4606 ImageBase = PAGE_ROUND_DOWN((ULONG_PTR)MmHighestUserAddress - ImageSize);
4607 }
4608
4609 /* Check there is enough space to map the section at that point. */
4610 if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
4611 PAGE_ROUND_UP(ImageSize)) != NULL)
4612 {
4613 /* Fail if the user requested a fixed base address. */
4614 if ((*BaseAddress) != NULL)
4615 {
4616 MmUnlockAddressSpace(AddressSpace);
4617 return(STATUS_UNSUCCESSFUL);
4618 }
4619 /* Otherwise find a gap to map the image. */
4620 ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE);
4621 if (ImageBase == 0)
4622 {
4623 MmUnlockAddressSpace(AddressSpace);
4624 return(STATUS_UNSUCCESSFUL);
4625 }
4626 /* Remember that we loaded image at a different base address */
4627 NotAtBase = TRUE;
4628 }
4629
4630 for (i = 0; i < NrSegments; i++)
4631 {
4632 if (!(SectionSegments[i].Image.Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4633 {
4634 PVOID SBaseAddress = (PVOID)
4635 ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress);
4636 MmLockSectionSegment(&SectionSegments[i]);
4637 Status = MmMapViewOfSegment(AddressSpace,
4638 Section,
4639 &SectionSegments[i],
4640 &SBaseAddress,
4641 SectionSegments[i].Length.LowPart,
4642 SectionSegments[i].Protection,
4643 0,
4644 0);
4645 MmUnlockSectionSegment(&SectionSegments[i]);
4646 if (!NT_SUCCESS(Status))
4647 {
4648 MmUnlockAddressSpace(AddressSpace);
4649 return(Status);
4650 }
4651 }
4652 }
4653
4654 *BaseAddress = (PVOID)ImageBase;
4655 *ViewSize = ImageSize;
4656 }
4657 else
4658 {
4659 /* check for write access */
4660 if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) &&
4661 !(Section->SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)))
4662 {
4663 MmUnlockAddressSpace(AddressSpace);
4664 return STATUS_SECTION_PROTECTION;
4665 }
4666 /* check for read access */
4667 if ((Protect & (PAGE_READONLY|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_WRITECOPY)) &&
4668 !(Section->SectionPageProtection & (PAGE_READONLY|PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4669 {
4670 MmUnlockAddressSpace(AddressSpace);
4671 return STATUS_SECTION_PROTECTION;
4672 }
4673 /* check for execute access */
4674 if ((Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)) &&
4675 !(Section->SectionPageProtection & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4676 {
4677 MmUnlockAddressSpace(AddressSpace);
4678 return STATUS_SECTION_PROTECTION;
4679 }
4680
4681 if (ViewSize == NULL)
4682 {
4683 /* Following this pointer would lead to us to the dark side */
4684 /* What to do? Bugcheck? Return status? Do the mambo? */
4685 KeBugCheck(MEMORY_MANAGEMENT);
4686 }
4687
4688 if (SectionOffset == NULL)
4689 {
4690 ViewOffset = 0;
4691 }
4692 else
4693 {
4694 ViewOffset = SectionOffset->u.LowPart;
4695 }
4696
4697 if ((ViewOffset % PAGE_SIZE) != 0)
4698 {
4699 MmUnlockAddressSpace(AddressSpace);
4700 return(STATUS_MAPPED_ALIGNMENT);
4701 }
4702
4703 if ((*ViewSize) == 0)
4704 {
4705 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4706 }
4707 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
4708 {
4709 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4710 }
4711
4712 *ViewSize = PAGE_ROUND_UP(*ViewSize);
4713
4714 MmLockSectionSegment(Section->Segment);
4715 Status = MmMapViewOfSegment(AddressSpace,
4716 Section,
4717 Section->Segment,
4718 BaseAddress,
4719 *ViewSize,
4720 Protect,
4721 ViewOffset,
4722 AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE));
4723 MmUnlockSectionSegment(Section->Segment);
4724 if (!NT_SUCCESS(Status))
4725 {
4726 MmUnlockAddressSpace(AddressSpace);
4727 return(Status);
4728 }
4729 }
4730
4731 MmUnlockAddressSpace(AddressSpace);
4732
4733 if (NotAtBase)
4734 Status = STATUS_IMAGE_NOT_AT_BASE;
4735 else
4736 Status = STATUS_SUCCESS;
4737
4738 return Status;
4739 }
4740
4741 /*
4742 * @unimplemented
4743 */
4744 BOOLEAN NTAPI
4745 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4746 IN PLARGE_INTEGER NewFileSize)
4747 {
4748 /* Check whether an ImageSectionObject exists */
4749 if (SectionObjectPointer->ImageSectionObject != NULL)
4750 {
4751 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4752 return FALSE;
4753 }
4754
4755 if (SectionObjectPointer->DataSectionObject != NULL)
4756 {
4757 PMM_SECTION_SEGMENT Segment;
4758
4759 Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->
4760 DataSectionObject;
4761
4762 if (Segment->ReferenceCount != 0)
4763 {
4764 #ifdef NEWCC
4765 CC_FILE_SIZES FileSizes;
4766 CcpLock();
4767 if (SectionObjectPointer->SharedCacheMap && (Segment->ReferenceCount > CcpCountCacheSections((PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap)))
4768 {
4769 CcpUnlock();
4770 /* Check size of file */
4771 if (SectionObjectPointer->SharedCacheMap)
4772 {
4773 if (!CcGetFileSizes(Segment->FileObject, &FileSizes))
4774 {
4775 return FALSE;
4776 }
4777
4778 if (NewFileSize->QuadPart <= FileSizes.FileSize.QuadPart)
4779 {
4780 return FALSE;
4781 }
4782 }
4783 }
4784 else
4785 CcpUnlock();
4786 #else
4787 /* Check size of file */
4788 if (SectionObjectPointer->SharedCacheMap)
4789 {
4790 PBCB Bcb = SectionObjectPointer->SharedCacheMap;
4791 if (NewFileSize->QuadPart <= Bcb->FileSize.QuadPart)
4792 {
4793 return FALSE;
4794 }
4795 }
4796 #endif
4797 }
4798 else
4799 {
4800 /* Something must gone wrong
4801 * how can we have a Section but no
4802 * reference? */
4803 DPRINT("ERROR: DataSectionObject without reference!\n");
4804 }
4805 }
4806
4807 DPRINT("FIXME: didn't check for outstanding write probes\n");
4808
4809 return TRUE;
4810 }
4811
4812
4813
4814
4815 /*
4816 * @implemented
4817 */
4818 BOOLEAN NTAPI
4819 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4820 IN MMFLUSH_TYPE FlushType)
4821 {
4822 BOOLEAN Result = TRUE;
4823 #ifdef NEWCC
4824 PMM_SECTION_SEGMENT Segment;
4825 #endif
4826
4827 switch(FlushType)
4828 {
4829 case MmFlushForDelete:
4830 if (SectionObjectPointer->ImageSectionObject ||
4831 SectionObjectPointer->DataSectionObject)
4832 {
4833 return FALSE;
4834 }
4835 #ifndef NEWCC
4836 CcRosSetRemoveOnClose(SectionObjectPointer);
4837 #endif
4838 return TRUE;
4839 case MmFlushForWrite:
4840 {
4841 DPRINT("MmFlushImageSection(%d)\n", FlushType);
4842 #ifdef NEWCC
4843 Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->DataSectionObject;
4844 #endif
4845
4846 if (SectionObjectPointer->ImageSectionObject) {
4847 DPRINT1("SectionObject has ImageSection\n");
4848 return FALSE;
4849 }
4850
4851 #ifdef NEWCC
4852 CcpLock();
4853 Result = !SectionObjectPointer->SharedCacheMap || (Segment->ReferenceCount == CcpCountCacheSections((PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap));
4854 CcpUnlock();
4855 DPRINT("Result %d\n", Result);
4856 #endif
4857 return Result;
4858 }
4859 }
4860 return FALSE;
4861 }
4862
4863 /*
4864 * @implemented
4865 */
4866 NTSTATUS NTAPI
4867 MmMapViewInSystemSpace (IN PVOID SectionObject,
4868 OUT PVOID * MappedBase,
4869 IN OUT PSIZE_T ViewSize)
4870 {
4871 PROS_SECTION_OBJECT Section;
4872 PMMSUPPORT AddressSpace;
4873 NTSTATUS Status;
4874 PAGED_CODE();
4875
4876 if (MiIsRosSectionObject(SectionObject) == FALSE)
4877 {
4878 DPRINT1("ARM3 System Mapping\n");
4879 return MiMapViewInSystemSpace(SectionObject,
4880 &MmSession,
4881 MappedBase,
4882 ViewSize);
4883 }
4884
4885 DPRINT("MmMapViewInSystemSpace() called\n");
4886
4887 Section = (PROS_SECTION_OBJECT)SectionObject;
4888 AddressSpace = MmGetKernelAddressSpace();
4889
4890 MmLockAddressSpace(AddressSpace);
4891
4892
4893 if ((*ViewSize) == 0)
4894 {
4895 (*ViewSize) = Section->MaximumSize.u.LowPart;
4896 }
4897 else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
4898 {
4899 (*ViewSize) = Section->MaximumSize.u.LowPart;
4900 }
4901
4902 MmLockSectionSegment(Section->Segment);
4903
4904
4905 Status = MmMapViewOfSegment(AddressSpace,
4906 Section,
4907 Section->Segment,
4908 MappedBase,
4909 *ViewSize,
4910 PAGE_READWRITE,
4911 0,
4912 0);
4913
4914 MmUnlockSectionSegment(Section->Segment);
4915 MmUnlockAddressSpace(AddressSpace);
4916
4917 return Status;
4918 }
4919
4920 /*
4921 * @implemented
4922 */
4923 NTSTATUS NTAPI
4924 MmUnmapViewInSystemSpace (IN PVOID MappedBase)
4925 {
4926 PMMSUPPORT AddressSpace;
4927 NTSTATUS Status;
4928
4929 DPRINT("MmUnmapViewInSystemSpace() called\n");
4930
4931 AddressSpace = MmGetKernelAddressSpace();
4932
4933 MmLockAddressSpace(AddressSpace);
4934
4935 Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
4936
4937 MmUnlockAddressSpace(AddressSpace);
4938
4939 return Status;
4940 }
4941
4942
4943 /**********************************************************************
4944 * NAME EXPORTED
4945 * MmCreateSection@
4946 *
4947 * DESCRIPTION
4948 * Creates a section object.
4949 *
4950 * ARGUMENTS
4951 * SectionObject (OUT)
4952 * Caller supplied storage for the resulting pointer
4953 * to a SECTION_OBJECT instance;
4954 *
4955 * DesiredAccess
4956 * Specifies the desired access to the section can be a
4957 * combination of:
4958 * STANDARD_RIGHTS_REQUIRED |
4959 * SECTION_QUERY |
4960 * SECTION_MAP_WRITE |
4961 * SECTION_MAP_READ |
4962 * SECTION_MAP_EXECUTE
4963 *
4964 * ObjectAttributes [OPTIONAL]
4965 * Initialized attributes for the object can be used
4966 * to create a named section;
4967 *
4968 * MaximumSize
4969 * Maximizes the size of the memory section. Must be
4970 * non-NULL for a page-file backed section.
4971 * If value specified for a mapped file and the file is
4972 * not large enough, file will be extended.
4973 *
4974 * SectionPageProtection
4975 * Can be a combination of:
4976 * PAGE_READONLY |
4977 * PAGE_READWRITE |
4978 * PAGE_WRITEONLY |
4979 * PAGE_WRITECOPY
4980 *
4981 * AllocationAttributes
4982 * Can be a combination of:
4983 * SEC_IMAGE |
4984 * SEC_RESERVE
4985 *
4986 * FileHandle
4987 * Handle to a file to create a section mapped to a file
4988 * instead of a memory backed section;
4989 *
4990 * File
4991 * Unknown.
4992 *
4993 * RETURN VALUE
4994 * Status.
4995 *
4996 * @implemented
4997 */
4998 NTSTATUS NTAPI
4999 MmCreateSection (OUT PVOID * Section,
5000 IN ACCESS_MASK DesiredAccess,
5001 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
5002 IN PLARGE_INTEGER MaximumSize,
5003 IN ULONG SectionPageProtection,
5004 IN ULONG AllocationAttributes,
5005 IN HANDLE FileHandle OPTIONAL,
5006 IN PFILE_OBJECT FileObject OPTIONAL)
5007 {
5008 NTSTATUS Status;
5009 ULONG Protection, FileAccess;
5010 PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section;
5011
5012 /* Check if an ARM3 section is being created instead */
5013 if (AllocationAttributes & 1)
5014 {
5015 DPRINT1("Creating ARM3 section\n");
5016 return MmCreateArm3Section(Section,
5017 DesiredAccess,
5018 ObjectAttributes,
5019 MaximumSize,
5020 SectionPageProtection,
5021 AllocationAttributes &~ 1,
5022 FileHandle,
5023 FileObject);
5024 }
5025
5026 /*
5027 * Check the protection
5028 */
5029 Protection = SectionPageProtection & ~(PAGE_GUARD | PAGE_NOCACHE);
5030 if (Protection != PAGE_READONLY &&
5031 Protection != PAGE_READWRITE &&
5032 Protection != PAGE_WRITECOPY &&
5033 Protection != PAGE_EXECUTE &&
5034 Protection != PAGE_EXECUTE_READ &&
5035 Protection != PAGE_EXECUTE_READWRITE &&
5036 Protection != PAGE_EXECUTE_WRITECOPY)
5037 {
5038 return STATUS_INVALID_PAGE_PROTECTION;
5039 }
5040
5041 if ((DesiredAccess & SECTION_MAP_WRITE) &&
5042 (Protection == PAGE_READWRITE ||
5043 Protection == PAGE_EXECUTE_READWRITE) &&
5044 !(AllocationAttributes & SEC_IMAGE))
5045 {
5046 DPRINT("Creating a section with WRITE access\n");
5047 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE;
5048 }
5049 else
5050 {
5051 DPRINT("Creating a section with READ access\n");
5052 FileAccess = FILE_READ_DATA | SYNCHRONIZE;
5053 }
5054
5055 /* FIXME: somehow combine this with the above checks */
5056 if (AllocationAttributes & SEC_IMAGE)
5057 FileAccess = MiArm3GetCorrectFileAccessMask(SectionPageProtection);
5058
5059 if (!FileObject && FileHandle)
5060 {
5061 Status = ObReferenceObjectByHandle(FileHandle,
5062 FileAccess,
5063 IoFileObjectType,
5064 ExGetPreviousMode(),
5065 (PVOID *)&FileObject,
5066 NULL);
5067 if (!NT_SUCCESS(Status))
5068 {
5069 DPRINT("Failed: 0x%08lx\n", Status);
5070 return Status;
5071 }
5072 }
5073 else if (FileObject)
5074 ObReferenceObject(FileObject);
5075
5076 #ifndef NEWCC // A hack for initializing caching.
5077 // This is needed only in the old case.
5078 if (FileHandle)
5079 {
5080 IO_STATUS_BLOCK Iosb;
5081 NTSTATUS Status;
5082 CHAR Buffer;
5083 LARGE_INTEGER ByteOffset;
5084 ByteOffset.QuadPart = 0;
5085 Status = ZwReadFile(FileHandle,
5086 NULL,
5087 NULL,
5088 NULL,
5089 &Iosb,
5090 &Buffer,
5091 sizeof(Buffer),
5092 &ByteOffset,
5093 NULL);
5094 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
5095 return Status;
5096 // Caching is initialized...
5097 }
5098 #endif
5099
5100 if (AllocationAttributes & SEC_IMAGE)
5101 {
5102 Status = MmCreateImageSection(SectionObject,
5103 DesiredAccess,
5104 ObjectAttributes,
5105 MaximumSize,
5106 SectionPageProtection,
5107 AllocationAttributes,
5108 FileObject);
5109 }
5110 #ifndef NEWCC
5111 else if (FileHandle != NULL)
5112 {
5113 Status = MmCreateDataFileSection(SectionObject,
5114 DesiredAccess,
5115 ObjectAttributes,
5116 MaximumSize,
5117 SectionPageProtection,
5118 AllocationAttributes,
5119 FileHandle);
5120 if (FileObject)
5121 ObDereferenceObject(FileObject);
5122 }
5123 #else
5124 else if (FileHandle != NULL || FileObject != NULL)
5125 {
5126 Status = MmCreateCacheSection(SectionObject,
5127 DesiredAccess,
5128 ObjectAttributes,
5129 MaximumSize,
5130 SectionPageProtection,
5131 AllocationAttributes,
5132 FileObject);
5133 }
5134 #endif
5135 else
5136 {
5137 Status = MmCreatePageFileSection(SectionObject,
5138 DesiredAccess,
5139 ObjectAttributes,
5140 MaximumSize,
5141 SectionPageProtection,
5142 AllocationAttributes);
5143 }
5144
5145 return Status;
5146 }
5147
5148 VOID
5149 MmModifyAttributes(IN PMMSUPPORT AddressSpace,
5150 IN PVOID BaseAddress,
5151 IN SIZE_T RegionSize,
5152 IN ULONG OldType,
5153 IN ULONG OldProtect,
5154 IN ULONG NewType,
5155 IN ULONG NewProtect)
5156 {
5157 //
5158 // This function is deprecated but remains in order to support VirtualAlloc
5159 // calls with MEM_COMMIT on top of MapViewOfFile calls with SEC_RESERVE.
5160 //
5161 // Win32k's shared user heap, for example, uses that mechanism. The two
5162 // conditions when this function needs to do something are ASSERTed for,
5163 // because they should not arise.
5164 //
5165 if (NewType == MEM_RESERVE && OldType == MEM_COMMIT)
5166 {
5167 ASSERT(FALSE);
5168 }
5169
5170 if ((NewType == MEM_COMMIT) && (OldType == MEM_COMMIT))
5171 {
5172 ASSERT(OldProtect == NewProtect);
5173 }
5174 }
5175
5176 NTSTATUS
5177 NTAPI
5178 MiRosAllocateVirtualMemory(IN HANDLE ProcessHandle,
5179 IN PEPROCESS Process,
5180 IN PMEMORY_AREA MemoryArea,
5181 IN PMMSUPPORT AddressSpace,
5182 IN OUT PVOID* UBaseAddress,
5183 IN BOOLEAN Attached,
5184 IN OUT PSIZE_T URegionSize,
5185 IN ULONG AllocationType,
5186 IN ULONG Protect)
5187 {
5188 ULONG_PTR PRegionSize;
5189 ULONG Type, RegionSize;
5190 NTSTATUS Status;
5191 PVOID PBaseAddress, BaseAddress;
5192 KAPC_STATE ApcState;
5193
5194 PBaseAddress = *UBaseAddress;
5195 PRegionSize = *URegionSize;
5196
5197 BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress);
5198 RegionSize = PAGE_ROUND_UP((ULONG_PTR)PBaseAddress + PRegionSize) -
5199 PAGE_ROUND_DOWN(PBaseAddress);
5200 Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE;
5201
5202 ASSERT(PBaseAddress != 0);
5203 ASSERT(Type == MEM_COMMIT);
5204 ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW);
5205 ASSERT(((ULONG_PTR)BaseAddress + RegionSize) <= (ULONG_PTR)MemoryArea->EndingAddress);
5206 ASSERT(((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress) >= RegionSize);
5207 ASSERT(MemoryArea->Data.SectionData.RegionListHead.Flink);
5208
5209 Status = MmAlterRegion(AddressSpace,
5210 MemoryArea->StartingAddress,
5211 &MemoryArea->Data.SectionData.RegionListHead,
5212 BaseAddress,
5213 RegionSize,
5214 Type,
5215 Protect,
5216 MmModifyAttributes);
5217
5218 MmUnlockAddressSpace(AddressSpace);
5219 if (Attached) KeUnstackDetachProcess(&ApcState);
5220 if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
5221 if (NT_SUCCESS(Status))
5222 {
5223 *UBaseAddress = BaseAddress;
5224 *URegionSize = RegionSize;
5225 }
5226
5227 return Status;
5228 }
5229
5230 NTSTATUS
5231 NTAPI
5232 MiRosProtectVirtualMemory(IN PEPROCESS Process,
5233 IN OUT PVOID *BaseAddress,
5234 IN OUT PSIZE_T NumberOfBytesToProtect,
5235 IN ULONG NewAccessProtection,
5236 OUT PULONG OldAccessProtection OPTIONAL)
5237 {
5238 PMEMORY_AREA MemoryArea;
5239 PMMSUPPORT AddressSpace;
5240 ULONG OldAccessProtection_;
5241 NTSTATUS Status;
5242
5243 *NumberOfBytesToProtect = PAGE_ROUND_UP((ULONG_PTR)(*BaseAddress) + (*NumberOfBytesToProtect)) - PAGE_ROUND_DOWN(*BaseAddress);
5244 *BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress);
5245
5246 AddressSpace = &Process->Vm;
5247 MmLockAddressSpace(AddressSpace);
5248 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress);
5249 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
5250 {
5251 MmUnlockAddressSpace(AddressSpace);
5252 return STATUS_UNSUCCESSFUL;
5253 }
5254
5255 if (OldAccessProtection == NULL) OldAccessProtection = &OldAccessProtection_;
5256
5257 if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
5258 {
5259 Status = MmProtectSectionView(AddressSpace,
5260 MemoryArea,
5261 *BaseAddress,
5262 *NumberOfBytesToProtect,
5263 NewAccessProtection,
5264 OldAccessProtection);
5265 }
5266 else
5267 {
5268 /* FIXME: Should we return failure or success in this case? */
5269 Status = STATUS_CONFLICTING_ADDRESSES;
5270 }
5271
5272 MmUnlockAddressSpace(AddressSpace);
5273
5274 return Status;
5275 }
5276
5277 /* EOF */