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