ReactOS 0.4.15-dev-6054-gbddd8b0
section.c
Go to the documentation of this file.
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#include "ARM3/miarm.h"
55
56#undef MmSetPageEntrySectionSegment
57#define MmSetPageEntrySectionSegment(S,O,E) do { \
58 DPRINT("SetPageEntrySectionSegment(old,%p,%x,%x)\n",(S),(O)->LowPart,E); \
59 _MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__); \
60 } while (0)
61
62extern MMSESSION MmSession;
63
64static LARGE_INTEGER TinyTime = {{-1L, -1L}};
65
66#ifndef NEWCC
68
69VOID
72{
73 //DPRINT("MmLockSectionSegment(%p,%s:%d)\n", Segment, file, line);
75 Segment->Locked = TRUE;
76}
77
78VOID
81{
82 ASSERT(Segment->Locked);
83 Segment->Locked = FALSE;
85 //DPRINT("MmUnlockSectionSegment(%p,%s:%d)\n", Segment, file, line);
86}
87#endif
88
89static
92{
93 KIRQL OldIrql = MiAcquirePfnLock();
95
96 while (TRUE)
97 {
98 Segment = SectionObjectPointer->DataSectionObject;
99 if (!Segment)
100 break;
101
103 {
104 MiReleasePfnLock(OldIrql);
106 OldIrql = MiAcquirePfnLock();
107 continue;
108 }
109
112 break;
113 }
114
115 MiReleasePfnLock(OldIrql);
116
117 return Segment;
118}
119
120/* Somewhat grotesque, but eh... */
122{
123 ASSERT((Segment->SegFlags & MM_DATAFILE_SEGMENT) == 0);
124
125 return CONTAINING_RECORD(Segment->ReferenceCount, MM_IMAGE_SECTION_OBJECT, RefCount);
126}
127
130 IN PVOID Session,
134
136NTAPI
140 IN PLARGE_INTEGER InputMaximumSize,
145
147NTAPI
158
159//
160// PeFmtCreateSection depends on the following:
161//
164
168
178
179/* TYPES *********************************************************************/
180
181typedef struct
182{
190}
192
193/* GLOBALS *******************************************************************/
194
196
198
200{
201 PAGE_NOACCESS, /* 0 = NONE */
202 PAGE_NOACCESS, /* 1 = SHARED */
203 PAGE_EXECUTE, /* 2 = EXECUTABLE */
204 PAGE_EXECUTE, /* 3 = EXECUTABLE, SHARED */
205 PAGE_READONLY, /* 4 = READABLE */
206 PAGE_READONLY, /* 5 = READABLE, SHARED */
207 PAGE_EXECUTE_READ, /* 6 = READABLE, EXECUTABLE */
208 PAGE_EXECUTE_READ, /* 7 = READABLE, EXECUTABLE, SHARED */
209 /*
210 * FIXME? do we really need the WriteCopy field in segments? can't we use
211 * PAGE_WRITECOPY here?
212 */
213 PAGE_READWRITE, /* 8 = WRITABLE */
214 PAGE_READWRITE, /* 9 = WRITABLE, SHARED */
215 PAGE_EXECUTE_READWRITE, /* 10 = WRITABLE, EXECUTABLE */
216 PAGE_EXECUTE_READWRITE, /* 11 = WRITABLE, EXECUTABLE, SHARED */
217 PAGE_READWRITE, /* 12 = WRITABLE, READABLE */
218 PAGE_READWRITE, /* 13 = WRITABLE, READABLE, SHARED */
219 PAGE_EXECUTE_READWRITE, /* 14 = WRITABLE, READABLE, EXECUTABLE */
220 PAGE_EXECUTE_READWRITE, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
221};
222
225{
230};
231
232
233/* FUNCTIONS *****************************************************************/
234
235
236
238NTAPI
240 LONGLONG SegOffset,
242/*
243 * FUNCTION: write a page for a section backed memory area.
244 * PARAMETERS:
245 * MemoryArea - Memory area to write the page for.
246 * Offset - Offset of the page to write.
247 * Page - Page which contains the data to write.
248 */
249{
253 UCHAR MdlBase[sizeof(MDL) + sizeof(PFN_NUMBER)];
254 PMDL Mdl = (PMDL)MdlBase;
255 PFILE_OBJECT FileObject = Segment->FileObject;
257
258 FileOffset.QuadPart = Segment->Image.FileOffset + SegOffset;
259
260 RtlZeroMemory(MdlBase, sizeof(MdlBase));
263 Mdl->MdlFlags |= MDL_PAGES_LOCKED;
264
267 if (Status == STATUS_PENDING)
268 {
270 Status = IoStatus.Status;
271 }
272 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
273 {
274 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
275 }
276
277 return Status;
278}
279
280
281/*
282 References:
283 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
284 File Format Specification", revision 6.0 (February 1999)
285*/
287 IN SIZE_T FileHeaderSize,
288 IN PVOID File,
289 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
291 IN PEXEFMT_CB_READ_FILE ReadFileCb,
292 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb)
293{
294 NTSTATUS nStatus;
295 ULONG cbFileHeaderOffsetSize = 0;
296 ULONG cbSectionHeadersOffset = 0;
297 ULONG cbSectionHeadersSize;
298 ULONG cbSectionHeadersOffsetSize = 0;
299 ULONG cbOptHeaderSize;
300 ULONG cbHeadersSize = 0;
301 ULONG nSectionAlignment;
302 ULONG nFileAlignment;
303 ULONG_PTR ImageBase = 0;
304 const IMAGE_DOS_HEADER * pidhDosHeader;
305 const IMAGE_NT_HEADERS32 * pinhNtHeader;
306 const IMAGE_OPTIONAL_HEADER32 * piohOptHeader;
307 const IMAGE_SECTION_HEADER * pishSectionHeaders;
308 PMM_SECTION_SEGMENT pssSegments;
309 LARGE_INTEGER lnOffset;
311 SIZE_T nPrevVirtualEndOfSegment = 0;
312 ULONG nFileSizeOfHeaders = 0;
313 ULONG i;
314 ULONG AlignedLength;
315
316 ASSERT(FileHeader);
317 ASSERT(FileHeaderSize > 0);
318 ASSERT(File);
319 ASSERT(ImageSectionObject);
320 ASSERT(ReadFileCb);
321 ASSERT(AllocateSegmentsCb);
322
323 ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize));
324
325 ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0);
326
327#define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
328
329 pBuffer = NULL;
330 pidhDosHeader = FileHeader;
331
332 /* DOS HEADER */
334
335 /* image too small to be an MZ executable */
336 if(FileHeaderSize < sizeof(IMAGE_DOS_HEADER))
337 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize));
338
339 /* no MZ signature */
340 if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
341 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic));
342
343 /* NT HEADER */
345
346 /* not a Windows executable */
347 if(pidhDosHeader->e_lfanew <= 0)
348 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew));
349
350 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize, pidhDosHeader->e_lfanew, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader)))
351 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
352
353 if(FileHeaderSize < cbFileHeaderOffsetSize)
354 pinhNtHeader = NULL;
355 else
356 {
357 /*
358 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
359 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
360 */
361 ASSERT(Intsafe_CanOffsetPointer(FileHeader, pidhDosHeader->e_lfanew));
362 pinhNtHeader = (PVOID)((UINT_PTR)FileHeader + pidhDosHeader->e_lfanew);
363 }
364
365 /*
366 * the buffer doesn't contain the NT file header, or the alignment is wrong: we
367 * need to read the header from the file
368 */
369 if(FileHeaderSize < cbFileHeaderOffsetSize ||
370 (UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
371 {
372 ULONG cbNtHeaderSize;
373 ULONG cbReadSize;
374 PVOID pData;
375
376l_ReadHeaderFromFile:
377 cbNtHeaderSize = 0;
378 lnOffset.QuadPart = pidhDosHeader->e_lfanew;
379
380 /* read the header from the file */
381 nStatus = ReadFileCb(File, &lnOffset, sizeof(IMAGE_NT_HEADERS64), &pData, &pBuffer, &cbReadSize);
382
383 if(!NT_SUCCESS(nStatus))
384 {
385 NTSTATUS ReturnedStatus = nStatus;
386
387 /* If it attempted to read past the end of the file, it means e_lfanew is invalid */
388 if (ReturnedStatus == STATUS_END_OF_FILE) nStatus = STATUS_INVALID_IMAGE_PROTECT;
389
390 DIE(("ReadFile failed, status %08X\n", ReturnedStatus));
391 }
392
393 ASSERT(pData);
395 ASSERT(cbReadSize > 0);
396
398
399 /* the buffer doesn't contain the file header */
400 if(cbReadSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader))
401 DIE(("The file doesn't contain the PE file header\n"));
402
403 pinhNtHeader = pData;
404
405 /* object still not aligned: copy it to the beginning of the buffer */
406 if((UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
407 {
409 RtlMoveMemory(pBuffer, pData, cbReadSize);
410 pinhNtHeader = pBuffer;
411 }
412
413 /* invalid NT header */
415
416 if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
417 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
418
420
421 if(!Intsafe_AddULong32(&cbNtHeaderSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
422 DIE(("The full NT header is too large\n"));
423
424 /* the buffer doesn't contain the whole NT header */
425 if(cbReadSize < cbNtHeaderSize)
426 DIE(("The file doesn't contain the full NT header\n"));
427 }
428 else
429 {
430 ULONG cbOptHeaderOffsetSize = 0;
431
433
434 /* don't trust an invalid NT header */
435 if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
436 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
437
438 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
439 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
440
442
443 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, cbOptHeaderOffsetSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
444 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader->FileHeader.SizeOfOptionalHeader));
445
446 /* the buffer doesn't contain the whole NT header: read it from the file */
447 if(cbOptHeaderOffsetSize > FileHeaderSize)
448 goto l_ReadHeaderFromFile;
449 }
450
451 /* read information from the NT header */
452 piohOptHeader = &pinhNtHeader->OptionalHeader;
453 cbOptHeaderSize = pinhNtHeader->FileHeader.SizeOfOptionalHeader;
454
456
457 if(!RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Magic))
458 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize));
459
460 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
461
462 switch(piohOptHeader->Magic)
463 {
465#ifndef _WIN64
467 DIE(("Win64 optional header, unsupported\n"));
468#else
469 // Fall through.
470#endif
472 break;
473 default:
474 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader->Magic));
475 }
476
477 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SectionAlignment) &&
478 RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, FileAlignment))
479 {
480 /* See [1], section 3.4.2 */
481 if(piohOptHeader->SectionAlignment < PAGE_SIZE)
482 {
483 if(piohOptHeader->FileAlignment != piohOptHeader->SectionAlignment)
484 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
485 }
486 else if(piohOptHeader->SectionAlignment < piohOptHeader->FileAlignment)
487 DIE(("The section alignment is smaller than the file alignment\n"));
488
489 nSectionAlignment = piohOptHeader->SectionAlignment;
490 nFileAlignment = piohOptHeader->FileAlignment;
491
492 if(!IsPowerOf2(nSectionAlignment) || !IsPowerOf2(nFileAlignment))
493 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment, nFileAlignment));
494 }
495 else
496 {
497 nSectionAlignment = PAGE_SIZE;
498 nFileAlignment = PAGE_SIZE;
499 }
500
501 ASSERT(IsPowerOf2(nSectionAlignment));
502 ASSERT(IsPowerOf2(nFileAlignment));
503
504 switch(piohOptHeader->Magic)
505 {
506 /* PE32 */
508 {
509 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, ImageBase))
510 ImageBase = piohOptHeader->ImageBase;
511
512 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfImage))
513 ImageSectionObject->ImageInformation.ImageFileSize = piohOptHeader->SizeOfImage;
514
515 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackReserve))
516 ImageSectionObject->ImageInformation.MaximumStackSize = piohOptHeader->SizeOfStackReserve;
517
518 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackCommit))
519 ImageSectionObject->ImageInformation.CommittedStackSize = piohOptHeader->SizeOfStackCommit;
520
521 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Subsystem))
522 {
523 ImageSectionObject->ImageInformation.SubSystemType = piohOptHeader->Subsystem;
524
525 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MinorSubsystemVersion) &&
526 RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MajorSubsystemVersion))
527 {
528 ImageSectionObject->ImageInformation.SubSystemMinorVersion = piohOptHeader->MinorSubsystemVersion;
529 ImageSectionObject->ImageInformation.SubSystemMajorVersion = piohOptHeader->MajorSubsystemVersion;
530 }
531 }
532
533 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
534 {
535 ImageSectionObject->ImageInformation.TransferAddress = (PVOID) (ImageBase +
536 piohOptHeader->AddressOfEntryPoint);
537 }
538
539 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfCode))
540 ImageSectionObject->ImageInformation.ImageContainsCode = piohOptHeader->SizeOfCode != 0;
541 else
542 ImageSectionObject->ImageInformation.ImageContainsCode = TRUE;
543
544 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
545 {
546 if (piohOptHeader->AddressOfEntryPoint == 0)
547 {
548 ImageSectionObject->ImageInformation.ImageContainsCode = FALSE;
549 }
550 }
551
552 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, LoaderFlags))
553 ImageSectionObject->ImageInformation.LoaderFlags = piohOptHeader->LoaderFlags;
554
555 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, DllCharacteristics))
556 {
557 ImageSectionObject->ImageInformation.DllCharacteristics = piohOptHeader->DllCharacteristics;
558
559 /*
560 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
561 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS
562 * magic to any binary.
563 *
564 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
565 * but honestly that's not tested. It will also break them when running no ReactOS once we implement
566 * the SxS support -- at which point, duh, this should be removed.
567 *
568 * But right now, any app depending on SxS is already broken anyway, so this flag only helps.
569 */
570 ImageSectionObject->ImageInformation.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION;
571 }
572
573 break;
574 }
575#ifdef _WIN64
576 /* PE64 */
578 {
579 const IMAGE_OPTIONAL_HEADER64 * pioh64OptHeader;
580
581 pioh64OptHeader = (const IMAGE_OPTIONAL_HEADER64 *)piohOptHeader;
582
583 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, ImageBase))
584 {
585 ImageBase = pioh64OptHeader->ImageBase;
586 if(pioh64OptHeader->ImageBase > MAXULONG_PTR)
587 DIE(("ImageBase exceeds the address space\n"));
588 }
589
590 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfImage))
591 {
592 if(pioh64OptHeader->SizeOfImage > MAXULONG_PTR)
593 DIE(("SizeOfImage exceeds the address space\n"));
594
595 ImageSectionObject->ImageInformation.ImageFileSize = pioh64OptHeader->SizeOfImage;
596 }
597
598 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackReserve))
599 {
600 if(pioh64OptHeader->SizeOfStackReserve > MAXULONG_PTR)
601 DIE(("SizeOfStackReserve exceeds the address space\n"));
602
603 ImageSectionObject->ImageInformation.MaximumStackSize = (ULONG_PTR) pioh64OptHeader->SizeOfStackReserve;
604 }
605
606 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackCommit))
607 {
608 if(pioh64OptHeader->SizeOfStackCommit > MAXULONG_PTR)
609 DIE(("SizeOfStackCommit exceeds the address space\n"));
610
611 ImageSectionObject->ImageInformation.CommittedStackSize = (ULONG_PTR) pioh64OptHeader->SizeOfStackCommit;
612 }
613
614 if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, Subsystem))
615 {
616 ImageSectionObject->ImageInformation.SubSystemType = pioh64OptHeader->Subsystem;
617
618 if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, MinorSubsystemVersion) &&
619 RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, MajorSubsystemVersion))
620 {
621 ImageSectionObject->ImageInformation.SubSystemMinorVersion = pioh64OptHeader->MinorSubsystemVersion;
622 ImageSectionObject->ImageInformation.SubSystemMajorVersion = pioh64OptHeader->MajorSubsystemVersion;
623 }
624 }
625
626 if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, AddressOfEntryPoint))
627 {
628 ImageSectionObject->ImageInformation.TransferAddress = (PVOID) (ImageBase +
629 pioh64OptHeader->AddressOfEntryPoint);
630 }
631
632 if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfCode))
633 ImageSectionObject->ImageInformation.ImageContainsCode = pioh64OptHeader->SizeOfCode != 0;
634 else
635 ImageSectionObject->ImageInformation.ImageContainsCode = TRUE;
636
637 if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, AddressOfEntryPoint))
638 {
639 if (pioh64OptHeader->AddressOfEntryPoint == 0)
640 {
641 ImageSectionObject->ImageInformation.ImageContainsCode = FALSE;
642 }
643 }
644
645 if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, LoaderFlags))
646 ImageSectionObject->ImageInformation.LoaderFlags = pioh64OptHeader->LoaderFlags;
647
648 if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, DllCharacteristics))
649 ImageSectionObject->ImageInformation.DllCharacteristics = pioh64OptHeader->DllCharacteristics;
650
651 break;
652 }
653#endif // _WIN64
654 }
655
656 /* [1], section 3.4.2 */
657 if((ULONG_PTR)ImageBase % 0x10000)
658 DIE(("ImageBase is not aligned on a 64KB boundary"));
659
660 ImageSectionObject->ImageInformation.ImageCharacteristics = pinhNtHeader->FileHeader.Characteristics;
661 ImageSectionObject->ImageInformation.Machine = pinhNtHeader->FileHeader.Machine;
662 ImageSectionObject->ImageInformation.GpValue = 0;
663 ImageSectionObject->ImageInformation.ZeroBits = 0;
664 ImageSectionObject->BasedAddress = (PVOID)ImageBase;
665
666 /* SECTION HEADERS */
668
669 /* see [1], section 3.3 */
670 if(pinhNtHeader->FileHeader.NumberOfSections > 96)
671 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader->FileHeader.NumberOfSections));
672
673 /*
674 * the additional segment is for the file's headers. They need to be present for
675 * the benefit of the dynamic loader (to locate exports, defaults for thread
676 * parameters, resources, etc.)
677 */
678 ImageSectionObject->NrSegments = pinhNtHeader->FileHeader.NumberOfSections + 1;
679
680 /* file offset for the section headers */
681 if(!Intsafe_AddULong32(&cbSectionHeadersOffset, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
682 DIE(("Offset overflow\n"));
683
684 if(!Intsafe_AddULong32(&cbSectionHeadersOffset, cbSectionHeadersOffset, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
685 DIE(("Offset overflow\n"));
686
687 /* size of the section headers */
689 cbSectionHeadersSize = pinhNtHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
690
691 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize, cbSectionHeadersOffset, cbSectionHeadersSize))
692 DIE(("Section headers too large\n"));
693
694 /* size of the executable's headers */
695 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfHeaders))
696 {
697// if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
698// DIE(("SizeOfHeaders is not aligned\n"));
699
700 if(cbSectionHeadersSize > piohOptHeader->SizeOfHeaders)
701 DIE(("The section headers overflow SizeOfHeaders\n"));
702
703 cbHeadersSize = piohOptHeader->SizeOfHeaders;
704 }
705 else if(!AlignUp(&cbHeadersSize, cbSectionHeadersOffsetSize, nFileAlignment))
706 DIE(("Overflow aligning the size of headers\n"));
707
708 if(pBuffer)
709 {
711 pBuffer = NULL;
712 }
713 /* WARNING: pinhNtHeader IS NO LONGER USABLE */
714 /* WARNING: piohOptHeader IS NO LONGER USABLE */
715 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
716
717 if(FileHeaderSize < cbSectionHeadersOffsetSize)
718 pishSectionHeaders = NULL;
719 else
720 {
721 /*
722 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
723 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
724 */
725 ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbSectionHeadersOffset));
726 pishSectionHeaders = (PVOID)((UINT_PTR)FileHeader + cbSectionHeadersOffset);
727 }
728
729 /*
730 * the buffer doesn't contain the section headers, or the alignment is wrong:
731 * read the headers from the file
732 */
733 if(FileHeaderSize < cbSectionHeadersOffsetSize ||
734 (UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
735 {
736 PVOID pData;
737 ULONG cbReadSize;
738
739 lnOffset.QuadPart = cbSectionHeadersOffset;
740
741 /* read the header from the file */
742 nStatus = ReadFileCb(File, &lnOffset, cbSectionHeadersSize, &pData, &pBuffer, &cbReadSize);
743
744 if(!NT_SUCCESS(nStatus))
745 DIE(("ReadFile failed with status %08X\n", nStatus));
746
747 ASSERT(pData);
749 ASSERT(cbReadSize > 0);
750
752
753 /* the buffer doesn't contain all the section headers */
754 if(cbReadSize < cbSectionHeadersSize)
755 DIE(("The file doesn't contain all of the section headers\n"));
756
757 pishSectionHeaders = pData;
758
759 /* object still not aligned: copy it to the beginning of the buffer */
760 if((UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
761 {
763 RtlMoveMemory(pBuffer, pData, cbReadSize);
764 pishSectionHeaders = pBuffer;
765 }
766 }
767
768 /* SEGMENTS */
769 /* allocate the segments */
771 ImageSectionObject->Segments = AllocateSegmentsCb(ImageSectionObject->NrSegments);
772
773 if(ImageSectionObject->Segments == NULL)
774 DIE(("AllocateSegments failed\n"));
775
776 /* initialize the headers segment */
777 pssSegments = ImageSectionObject->Segments;
778
779// ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
780
781 if(!AlignUp(&nFileSizeOfHeaders, cbHeadersSize, nFileAlignment))
782 DIE(("Cannot align the size of the section headers\n"));
783
784 nPrevVirtualEndOfSegment = ALIGN_UP_BY(cbHeadersSize, nSectionAlignment);
785 if (nPrevVirtualEndOfSegment < cbHeadersSize)
786 DIE(("Cannot align the size of the section headers\n"));
787
788 pssSegments[0].Image.FileOffset = 0;
789 pssSegments[0].Protection = PAGE_READONLY;
790 pssSegments[0].Length.QuadPart = nPrevVirtualEndOfSegment;
791 pssSegments[0].RawLength.QuadPart = nFileSizeOfHeaders;
792 pssSegments[0].Image.VirtualAddress = 0;
793 pssSegments[0].Image.Characteristics = 0;
794 pssSegments[0].WriteCopy = TRUE;
795
796 /* skip the headers segment */
797 ++ pssSegments;
798
800
801 ASSERT(ImageSectionObject->RefCount > 0);
802
803 /* convert the executable sections into segments. See also [1], section 4 */
804 for(i = 0; i < ImageSectionObject->NrSegments - 1; ++ i)
805 {
806 ULONG nCharacteristics;
807
808 /* validate the alignment */
809 if(!IsAligned(pishSectionHeaders[i].VirtualAddress, nSectionAlignment))
810 DIE(("Image.VirtualAddress[%u] is not aligned\n", i));
811
812 /* sections must be contiguous, ordered by base address and non-overlapping */
813 if(pishSectionHeaders[i].VirtualAddress != nPrevVirtualEndOfSegment)
814 DIE(("Memory gap between section %u and the previous\n", i));
815
816 /* ignore explicit BSS sections */
817 if(pishSectionHeaders[i].PointerToRawData != 0 && pishSectionHeaders[i].SizeOfRawData != 0)
818 {
819 /* validate the alignment */
820#if 0
821 /* Yes, this should be a multiple of FileAlignment, but there's
822 * stuff out there that isn't. We can cope with that
823 */
824 if(!IsAligned(pishSectionHeaders[i].SizeOfRawData, nFileAlignment))
825 DIE(("SizeOfRawData[%u] is not aligned\n", i));
826#endif
827
828// if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
829// DIE(("PointerToRawData[%u] is not aligned\n", i));
830
831 if(!Intsafe_CanAddULong32(pishSectionHeaders[i].PointerToRawData, pishSectionHeaders[i].SizeOfRawData))
832 DIE(("SizeOfRawData[%u] too large\n", i));
833
834 /* conversion */
835 pssSegments[i].Image.FileOffset = pishSectionHeaders[i].PointerToRawData;
836 pssSegments[i].RawLength.QuadPart = pishSectionHeaders[i].SizeOfRawData;
837 }
838 else
839 {
840 /* FIXME: Should reset PointerToRawData to 0 in the image mapping */
841 ASSERT(pssSegments[i].Image.FileOffset == 0);
842 ASSERT(pssSegments[i].RawLength.QuadPart == 0);
843 }
844
845 ASSERT(Intsafe_CanAddLong64(pssSegments[i].Image.FileOffset, pssSegments[i].RawLength.QuadPart));
846
847 nCharacteristics = pishSectionHeaders[i].Characteristics;
848
849 /* no explicit protection */
850 if((nCharacteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == 0)
851 {
852 if(nCharacteristics & IMAGE_SCN_CNT_CODE)
853 nCharacteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
854
855 if(nCharacteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
856 nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
857
858 if(nCharacteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
859 nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
860 }
861
862 /* see table above */
863 pssSegments[i].Protection = SectionCharacteristicsToProtect[nCharacteristics >> 28];
864 pssSegments[i].WriteCopy = !(nCharacteristics & IMAGE_SCN_MEM_SHARED);
865
866 if(pishSectionHeaders[i].Misc.VirtualSize == 0)
867 pssSegments[i].Length.QuadPart = pishSectionHeaders[i].SizeOfRawData;
868 else
869 pssSegments[i].Length.QuadPart = pishSectionHeaders[i].Misc.VirtualSize;
870
871 AlignedLength = ALIGN_UP_BY(pssSegments[i].Length.LowPart, nSectionAlignment);
872 if(AlignedLength < pssSegments[i].Length.LowPart)
873 DIE(("Cannot align the virtual size of section %u\n", i));
874
875 pssSegments[i].Length.LowPart = AlignedLength;
876
877 if(pssSegments[i].Length.QuadPart == 0)
878 DIE(("Virtual size of section %u is null\n", i));
879
880 pssSegments[i].Image.VirtualAddress = pishSectionHeaders[i].VirtualAddress;
881 pssSegments[i].Image.Characteristics = pishSectionHeaders[i].Characteristics;
882
883 /* ensure the memory image is no larger than 4GB */
884 nPrevVirtualEndOfSegment = (ULONG_PTR)(pssSegments[i].Image.VirtualAddress + pssSegments[i].Length.QuadPart);
885 if (nPrevVirtualEndOfSegment < pssSegments[i].Image.VirtualAddress)
886 DIE(("The image is too large\n"));
887 }
888
889 if(nSectionAlignment >= PAGE_SIZE)
891
892 /* Success */
893 nStatus = STATUS_SUCCESS;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
894
895l_Return:
896 if(pBuffer)
898
899 return nStatus;
900}
901
902/*
903 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
904 * ARGUMENTS: PFILE_OBJECT to wait for.
905 * RETURNS: Status of the wait.
906 */
909{
910 return STATUS_SUCCESS;
911 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
912}
913
914
915
916VOID
917NTAPI
919{
923 SWAPENTRY SavedSwapEntry;
925
926 Page = 0;
927
929
930 Length = PAGE_ROUND_UP(Segment->Length.QuadPart);
931 for (Offset.QuadPart = 0; Offset.QuadPart < Length; Offset.QuadPart += PAGE_SIZE)
932 {
934 if (Entry)
935 {
938 {
940 }
941 else
942 {
944 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
945 if (SavedSwapEntry != 0)
946 {
948 MmFreeSwapPage(SavedSwapEntry);
949 }
951 }
952 }
953 }
954
956}
957
958static
959VOID
960NTAPI
962{
965
967
969
971
972 /* This must be either a valid entry or nothing */
974
975 /* There should be no reference anymore */
977
979 /* If there is a page, this must be because it's still dirty */
980 ASSERT(Page != 0);
981
982 /* Write the page */
983 if (IS_DIRTY_SSE(Entry))
984 MiWritePage(Segment, Offset->QuadPart, Page);
985
987}
988
994VOID
995NTAPI
996MmDereferenceSegmentWithLock(
999{
1000 /* Lock the PFN lock because we mess around with SectionObjectPointers */
1001 if (OldIrql == MM_NOIRQL)
1002 {
1003 OldIrql = MiAcquirePfnLock();
1004 }
1005
1006 if (InterlockedDecrement64(Segment->ReferenceCount) > 0)
1007 {
1008 /* Nothing to do yet */
1009 MiReleasePfnLock(OldIrql);
1010 return;
1011 }
1012
1013 *Segment->Flags |= MM_SEGMENT_INDELETE;
1014
1015 /* Flush the segment */
1016 if (*Segment->Flags & MM_DATAFILE_SEGMENT)
1017 {
1018 MiReleasePfnLock(OldIrql);
1019 /* Free the page table. This will flush any remaining dirty data */
1021
1022 OldIrql = MiAcquirePfnLock();
1023 /* Delete the pointer on the file */
1024 ASSERT(Segment->FileObject->SectionObjectPointer->DataSectionObject == Segment);
1025 Segment->FileObject->SectionObjectPointer->DataSectionObject = NULL;
1026 MiReleasePfnLock(OldIrql);
1027 ObDereferenceObject(Segment->FileObject);
1028
1030 }
1031 else
1032 {
1033 /* Most grotesque thing ever */
1034 PMM_IMAGE_SECTION_OBJECT ImageSectionObject = CONTAINING_RECORD(Segment->ReferenceCount, MM_IMAGE_SECTION_OBJECT, RefCount);
1035 PMM_SECTION_SEGMENT SectionSegments;
1036 ULONG NrSegments;
1037 ULONG i;
1038
1039 /* Delete the pointer on the file */
1040 ASSERT(ImageSectionObject->FileObject->SectionObjectPointer->ImageSectionObject == ImageSectionObject);
1041 ImageSectionObject->FileObject->SectionObjectPointer->ImageSectionObject = NULL;
1042 MiReleasePfnLock(OldIrql);
1043
1044 ObDereferenceObject(ImageSectionObject->FileObject);
1045
1046 NrSegments = ImageSectionObject->NrSegments;
1047 SectionSegments = ImageSectionObject->Segments;
1048 for (i = 0; i < NrSegments; i++)
1049 {
1050 if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED)
1051 {
1052 MmpFreePageFileSegment(&SectionSegments[i]);
1053 }
1054
1055 MmFreePageTablesSectionSegment(&SectionSegments[i], NULL);
1056 }
1057
1059 ExFreePoolWithTag(ImageSectionObject, TAG_MM_SECTION_SEGMENT);
1060 }
1061}
1062
1063VOID
1064NTAPI
1067{
1069
1071 if (Entry == 0)
1072 {
1073 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
1074 KeBugCheck(MEMORY_MANAGEMENT);
1075 }
1077 {
1078 DPRINT1("Maximum share count reached\n");
1079 KeBugCheck(MEMORY_MANAGEMENT);
1080 }
1082 {
1083 KeBugCheck(MEMORY_MANAGEMENT);
1084 }
1086}
1087
1088BOOLEAN
1089NTAPI
1093 BOOLEAN Dirty,
1095 ULONG_PTR *InEntry)
1096{
1099 BOOLEAN IsDataMap = BooleanFlagOn(*Segment->Flags, MM_DATAFILE_SEGMENT);
1100 SWAPENTRY SwapEntry;
1101
1102 if (Entry == 0)
1103 {
1104 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
1105 KeBugCheck(MEMORY_MANAGEMENT);
1106 }
1107 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
1108 {
1109 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment, Offset->LowPart, PFN_FROM_SSE(Entry));
1110 KeBugCheck(MEMORY_MANAGEMENT);
1111 }
1113 {
1114 KeBugCheck(MEMORY_MANAGEMENT);
1115 }
1117 if (Dirty) Entry = DIRTY_SSE(Entry);
1118
1119 /* If we are paging-out, pruning the page for real will be taken care of in MmCheckDirtySegment */
1120 if ((SHARE_COUNT_FROM_SSE(Entry) > 0) || PageOut)
1121 {
1122 /* Update the page mapping in the segment and we're done */
1124 return FALSE;
1125 }
1126
1127 /* We are pruning the last mapping on this page. See if we can keep it a bit more. */
1128 ASSERT(!PageOut);
1129
1130 if (IsDataMap)
1131 {
1132 /* We can always keep memory in for data maps */
1134 return FALSE;
1135 }
1136
1137 if (!FlagOn(Segment->Image.Characteristics, IMAGE_SCN_MEM_SHARED))
1138 {
1139 ASSERT(Segment->WriteCopy);
1142 /* So this must have been a read-only page. Keep it ! */
1144 return FALSE;
1145 }
1146
1147 /*
1148 * So this is a page for a shared section of a DLL.
1149 * We can keep it if it is not dirty.
1150 */
1151 SwapEntry = MmGetSavedSwapEntryPage(Page);
1152 if ((SwapEntry == 0) && !IS_DIRTY_SSE(Entry))
1153 {
1155 return FALSE;
1156 }
1157
1158 /* No more processes are referencing this shared dirty page. Ditch it. */
1159 if (SwapEntry)
1160 {
1162 MmFreeSwapPage(SwapEntry);
1163 }
1166 return TRUE;
1167}
1168
1169static
1171MiCopyFromUserPage(PFN_NUMBER DestPage, const VOID *SrcAddress)
1172{
1174 KIRQL Irql;
1175 PVOID DestAddress;
1176
1178 DestAddress = MiMapPageInHyperSpace(Process, DestPage, &Irql);
1179 if (DestAddress == NULL)
1180 {
1181 return STATUS_NO_MEMORY;
1182 }
1183 ASSERT((ULONG_PTR)DestAddress % PAGE_SIZE == 0);
1184 ASSERT((ULONG_PTR)SrcAddress % PAGE_SIZE == 0);
1185 RtlCopyMemory(DestAddress, SrcAddress, PAGE_SIZE);
1186 MiUnmapPageInHyperSpace(Process, DestAddress, Irql);
1187 return STATUS_SUCCESS;
1188}
1189
1190static
1192NTAPI
1197 _In_opt_ PLARGE_INTEGER ValidDataLength,
1198 _In_ BOOLEAN SetDirty)
1199{
1200 /* Let's use a 64K granularity. */
1201 LONGLONG RangeStart, RangeEnd;
1203 PFILE_OBJECT FileObject = Segment->FileObject;
1204
1205 /* Calculate our range, aligned on 64K if possible. */
1206 Status = RtlLongLongAdd(Offset, Length, &RangeEnd);
1208 if (!NT_SUCCESS(Status))
1209 return Status;
1210
1211 /* If the file is not random access and we are not the page out thread
1212 * read a 64K Chunk. */
1214 && !FlagOn(FileObject->Flags, FO_RANDOM_ACCESS))
1215 {
1216 RangeStart = Offset - (Offset % _64K);
1217 if (RangeEnd % _64K)
1218 RangeEnd += _64K - (RangeEnd % _64K);
1219 }
1220 else
1221 {
1222 RangeStart = Offset - (Offset % PAGE_SIZE);
1223 if (RangeEnd % PAGE_SIZE)
1224 RangeEnd += PAGE_SIZE - (RangeEnd % PAGE_SIZE);
1225 }
1226
1227 /* Clamp if needed */
1228 if (!FlagOn(*Segment->Flags, MM_DATAFILE_SEGMENT))
1229 {
1230 if (RangeEnd > Segment->RawLength.QuadPart)
1231 RangeEnd = Segment->RawLength.QuadPart;
1232 }
1233
1234 /* Let's gooooooooo */
1235 for ( ; RangeStart < RangeEnd; RangeStart += _64K)
1236 {
1237 /* First take a look at where we miss pages */
1238 ULONG ToReadPageBits = 0;
1239 LONGLONG ChunkEnd = RangeStart + _64K;
1240
1241 if (ChunkEnd > RangeEnd)
1242 ChunkEnd = RangeEnd;
1243
1245 for (LONGLONG ChunkOffset = RangeStart; ChunkOffset < ChunkEnd; ChunkOffset += PAGE_SIZE)
1246 {
1247 LARGE_INTEGER CurrentOffset;
1248
1249 CurrentOffset.QuadPart = ChunkOffset;
1251
1252 /* Let any pending read proceed */
1253 while (MM_IS_WAIT_PTE(Entry))
1254 {
1256
1258
1260 Entry = MmGetPageEntrySectionSegment(Segment, &CurrentOffset);
1261 }
1262
1263 if (Entry != 0)
1264 {
1265 /* Dirtify it if it's a resident page and we're asked to */
1266 if (SetDirty && !IS_SWAP_FROM_SSE(Entry))
1268 continue;
1269 }
1270
1271 ToReadPageBits |= 1UL << ((ChunkOffset - RangeStart) >> PAGE_SHIFT);
1272
1273 /* Put a wait entry here */
1274 MmSetPageEntrySectionSegment(Segment, &CurrentOffset, MAKE_SWAP_SSE(MM_WAIT_ENTRY));
1275 }
1277
1278 if (ToReadPageBits == 0)
1279 {
1280 /* Nothing to do for this chunk */
1281 continue;
1282 }
1283
1284 /* Now perform the actual read */
1285 LONGLONG ChunkOffset = RangeStart;
1286 while (ChunkOffset < ChunkEnd)
1287 {
1288 /* Move forward if there is a hole */
1289 ULONG BitSet;
1290 if (!_BitScanForward(&BitSet, ToReadPageBits))
1291 {
1292 /* Nothing more to read */
1293 break;
1294 }
1295 ToReadPageBits >>= BitSet;
1296 ChunkOffset += BitSet * PAGE_SIZE;
1297 ASSERT(ChunkOffset < ChunkEnd);
1298
1299 /* Get the range we have to read */
1300 _BitScanForward(&BitSet, ~ToReadPageBits);
1301 ULONG ReadLength = BitSet * PAGE_SIZE;
1302
1304
1305 /* Clamp (This is for image mappings */
1306 if ((ChunkOffset + ReadLength) > ChunkEnd)
1307 ReadLength = ChunkEnd - ChunkOffset;
1308
1309 ASSERT(ReadLength != 0);
1310
1311 /* Allocate a MDL */
1313 if (!Mdl)
1314 {
1315 /* Damn. Roll-back. */
1317 while (ChunkOffset < ChunkEnd)
1318 {
1319 if (ToReadPageBits & 1)
1320 {
1321 LARGE_INTEGER CurrentOffset;
1322 CurrentOffset.QuadPart = ChunkOffset;
1324 MmSetPageEntrySectionSegment(Segment, &CurrentOffset, 0);
1325 }
1326 ToReadPageBits >>= 1;
1327 ChunkOffset += PAGE_SIZE;
1328 }
1331 }
1332
1333 /* Get our pages */
1336 for (UINT i = 0; i < BYTES_TO_PAGES(ReadLength); i++)
1337 {
1338 /* MmRequestPageMemoryConsumer succeeds or bugchecks */
1340 }
1341 Mdl->MdlFlags |= MDL_PAGES_LOCKED | MDL_IO_PAGE_READ;
1342
1344 FileOffset.QuadPart = Segment->Image.FileOffset + ChunkOffset;
1345
1346 /* Clamp to VDL */
1347 if (ValidDataLength && ((FileOffset.QuadPart + ReadLength) > ValidDataLength->QuadPart))
1348 {
1349 if (FileOffset.QuadPart > ValidDataLength->QuadPart)
1350 {
1351 /* Great, nothing to read. */
1352 goto AssignPagesToSegment;
1353 }
1354
1355 Mdl->Size = (FileOffset.QuadPart + ReadLength) - ValidDataLength->QuadPart;
1356 }
1357
1358 KEVENT Event;
1360
1361 /* Disable APCs */
1362 KIRQL OldIrql;
1364
1367 if (Status == STATUS_PENDING)
1368 {
1370 Status = Iosb.Status;
1371 }
1372
1373 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
1374 {
1375 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
1376 }
1377
1379
1381 {
1382 DPRINT1("Got STATUS_END_OF_FILE at offset %I64d for file %wZ.\n", FileOffset.QuadPart, &FileObject->FileName);
1384 }
1385
1386 if (!NT_SUCCESS(Status))
1387 {
1388 /* Damn. Roll back. */
1389 for (UINT i = 0; i < BYTES_TO_PAGES(ReadLength); i++)
1391
1393 while (ChunkOffset < ChunkEnd)
1394 {
1395 if (ToReadPageBits & 1)
1396 {
1397 LARGE_INTEGER CurrentOffset;
1398 CurrentOffset.QuadPart = ChunkOffset;
1400 MmSetPageEntrySectionSegment(Segment, &CurrentOffset, 0);
1401 }
1402 ToReadPageBits >>= 1;
1403 ChunkOffset += PAGE_SIZE;
1404 }
1406 IoFreeMdl(Mdl);;
1407 return Status;
1408 }
1409
1410AssignPagesToSegment:
1412
1413 for (UINT i = 0; i < BYTES_TO_PAGES(ReadLength); i++)
1414 {
1415 ULONG_PTR Entry = MAKE_SSE(Pages[i] << PAGE_SHIFT, 0);
1416 LARGE_INTEGER CurrentOffset;
1417 CurrentOffset.QuadPart = ChunkOffset + (i * PAGE_SIZE);
1418
1420
1421 if (SetDirty)
1423
1424 MmSetPageEntrySectionSegment(Segment, &CurrentOffset, Entry);
1425 }
1426
1428
1429 IoFreeMdl(Mdl);
1430 ToReadPageBits >>= BitSet;
1431 ChunkOffset += BitSet * PAGE_SIZE;
1432 }
1433 }
1434
1435 return STATUS_SUCCESS;
1436}
1437
1438static VOID
1442 ULONG OldType,
1443 ULONG OldProtect,
1444 ULONG NewType,
1446{
1449 BOOLEAN DoCOW = FALSE;
1450 ULONG i;
1452
1455 Segment = MemoryArea->SectionData.Segment;
1457
1458 if ((Segment->WriteCopy) &&
1460 {
1461 DoCOW = TRUE;
1462 }
1463
1464 if (OldProtect != NewProtect)
1465 {
1466 for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
1467 {
1468 SWAPENTRY SwapEntry;
1469 PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
1471
1472 /* Wait for a wait entry to disappear */
1473 do
1474 {
1475 MmGetPageFileMapping(Process, Address, &SwapEntry);
1476 if (SwapEntry != MM_WAIT_ENTRY)
1477 break;
1483 }
1484 while (TRUE);
1485
1486 /*
1487 * If we doing COW for this segment then check if the page is
1488 * already private.
1489 */
1491 {
1495
1497 + MemoryArea->SectionData.ViewOffset;
1499 /*
1500 * An MM_WAIT_ENTRY is ok in this case... It'll just count as
1501 * IS_SWAP_FROM_SSE and we'll do the right thing.
1502 */
1504
1507 {
1509 }
1510 }
1511
1513 {
1515 Protect);
1516 }
1517 }
1518 }
1519
1521}
1522
1524NTAPI
1527 PVOID Address,
1529{
1535 ULONG_PTR Entry1;
1538 BOOLEAN HasSwapEntry;
1539 PVOID PAddress;
1541 SWAPENTRY SwapEntry;
1542
1543 ASSERT(Locked);
1544
1545 /*
1546 * There is a window between taking the page fault and locking the
1547 * address space when another thread could load the page so we check
1548 * that.
1549 */
1551 {
1552 return STATUS_SUCCESS;
1553 }
1554
1556 {
1558 }
1559
1560 /*
1561 * Check for the virtual memory area being deleted.
1562 */
1564 {
1565 return STATUS_UNSUCCESSFUL;
1566 }
1567
1568 PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
1569 Offset.QuadPart = (ULONG_PTR)PAddress - MA_GetStartingAddress(MemoryArea)
1570 + MemoryArea->SectionData.ViewOffset;
1571
1572 Segment = MemoryArea->SectionData.Segment;
1574 &MemoryArea->SectionData.RegionListHead,
1575 Address, NULL);
1576 ASSERT(Region != NULL);
1577
1578 /* Check for a NOACCESS mapping */
1579 if (Region->Protect & PAGE_NOACCESS)
1580 {
1582 }
1583
1584 if (Region->Protect & PAGE_GUARD)
1585 {
1586 /* Remove it */
1588 &MemoryArea->SectionData.RegionListHead,
1589 Address, PAGE_SIZE, Region->Type, Region->Protect & ~PAGE_GUARD,
1591
1592 if (!NT_SUCCESS(Status))
1593 {
1594 DPRINT1("Removing PAGE_GUARD protection failed : 0x%08x.\n", Status);
1595 }
1596
1598 }
1599
1600 HasSwapEntry = MmIsPageSwapEntry(Process, Address);
1601
1602 /* See if we should use a private page */
1603 if (HasSwapEntry)
1604 {
1605 SWAPENTRY DummyEntry;
1606
1607 MmGetPageFileMapping(Process, Address, &SwapEntry);
1608 if (SwapEntry == MM_WAIT_ENTRY)
1609 {
1614 }
1615
1616 /*
1617 * Must be private page we have swapped out.
1618 */
1619
1620 /*
1621 * Sanity check
1622 */
1624 ASSERT(DummyEntry == SwapEntry);
1625
1626 /* Tell everyone else we are serving the fault. */
1627 MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY);
1628
1631 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1632 if (!Process) MI_SET_PROCESS2("Kernel Section");
1634 if (!NT_SUCCESS(Status))
1635 {
1636 KeBugCheck(MEMORY_MANAGEMENT);
1637 }
1638
1639 Status = MmReadFromSwapPage(SwapEntry, Page);
1640 if (!NT_SUCCESS(Status))
1641 {
1642 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
1643 KeBugCheck(MEMORY_MANAGEMENT);
1644 }
1645
1647 MmDeletePageFileMapping(Process, PAddress, &DummyEntry);
1648 ASSERT(DummyEntry == MM_WAIT_ENTRY);
1649
1651 PAddress,
1652 Region->Protect,
1653 Page);
1654 if (!NT_SUCCESS(Status))
1655 {
1656 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1657 KeBugCheck(MEMORY_MANAGEMENT);
1658 return Status;
1659 }
1660
1661 /*
1662 * Store the swap entry for later use.
1663 */
1664 MmSetSavedSwapEntryPage(Page, SwapEntry);
1665
1666 /*
1667 * Add the page to the process's working set
1668 */
1670 /*
1671 * Finish the operation
1672 */
1673 DPRINT("Address 0x%p\n", Address);
1674 return STATUS_SUCCESS;
1675 }
1676
1677 /*
1678 * Lock the segment
1679 */
1681
1682 /*
1683 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1684 */
1685 if ((*Segment->Flags) & MM_PHYSICALMEMORY_SEGMENT)
1686 {
1688 /*
1689 * Just map the desired physical page
1690 */
1691 Page = (PFN_NUMBER)(Offset.QuadPart >> PAGE_SHIFT);
1693 PAddress,
1694 Region->Protect,
1695 Page);
1696 if (!NT_SUCCESS(Status))
1697 {
1698 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1699 KeBugCheck(MEMORY_MANAGEMENT);
1700 return Status;
1701 }
1702
1703 /*
1704 * Cleanup and release locks
1705 */
1706 DPRINT("Address 0x%p\n", Address);
1707 return STATUS_SUCCESS;
1708 }
1709
1710 /*
1711 * Check if this page needs to be mapped COW
1712 */
1713 if ((Segment->WriteCopy) &&
1714 (Region->Protect == PAGE_READWRITE || Region->Protect == PAGE_EXECUTE_READWRITE))
1715 {
1717 }
1718 else
1719 {
1720 Attributes = Region->Protect;
1721 }
1722
1723
1724 /*
1725 * Get the entry corresponding to the offset within the section
1726 */
1728 if (Entry == 0)
1729 {
1730 /*
1731 * If the entry is zero, then we need to load the page.
1732 */
1733 if ((Offset.QuadPart >= (LONGLONG)PAGE_ROUND_UP(Segment->RawLength.QuadPart)) && (MemoryArea->VadNode.u.VadFlags.VadType == VadImageMap))
1734 {
1735 /* We are beyond the data which is on file. Just get a new page. */
1737 if (Process) MI_SET_PROCESS2(Process->ImageFileName);
1738 if (!Process) MI_SET_PROCESS2("Kernel Section");
1742
1744 if (!NT_SUCCESS(Status))
1745 {
1746 DPRINT1("Unable to create virtual mapping\n");
1747 KeBugCheck(MEMORY_MANAGEMENT);
1748 }
1749 ASSERT(MmIsPagePresent(Process, PAddress));
1750 if (Process)
1752
1753 DPRINT("Address 0x%p\n", Address);
1754 return STATUS_SUCCESS;
1755 }
1756
1759
1760 /* The data must be paged in. Lock the file, so that the VDL doesn't get updated behind us. */
1762
1763 PFSRTL_COMMON_FCB_HEADER FcbHeader = Segment->FileObject->FsContext;
1764
1766
1767 FsRtlReleaseFile(Segment->FileObject);
1768
1769 /* Lock address space again */
1771 if (!NT_SUCCESS(Status))
1772 {
1773 /* Damn */
1774 DPRINT1("Failed to page data in!\n");
1775 return STATUS_IN_PAGE_ERROR;
1776 }
1777
1778 /* Everything went fine. Restart the operation */
1780 }
1781 else if (IS_SWAP_FROM_SSE(Entry))
1782 {
1783 SWAPENTRY SwapEntry;
1784
1785 SwapEntry = SWAPENTRY_FROM_SSE(Entry);
1786
1787 /* See if a page op is running on this segment. */
1788 if (SwapEntry == MM_WAIT_ENTRY)
1789 {
1795 }
1796
1797 /*
1798 * Release all our locks and read in the page from disk
1799 */
1802
1805 if (!NT_SUCCESS(Status))
1806 {
1807 KeBugCheck(MEMORY_MANAGEMENT);
1808 }
1809
1810 Status = MmReadFromSwapPage(SwapEntry, Page);
1811 if (!NT_SUCCESS(Status))
1812 {
1813 KeBugCheck(MEMORY_MANAGEMENT);
1814 }
1815
1816 /*
1817 * Relock the address space and segment
1818 */
1821
1822 /*
1823 * Check the entry. No one should change the status of a page
1824 * that has a pending page-in.
1825 */
1827 if (Entry1 != MAKE_SWAP_SSE(MM_WAIT_ENTRY))
1828 {
1829 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry, Entry1);
1830 KeBugCheck(MEMORY_MANAGEMENT);
1831 }
1832
1833 /*
1834 * Save the swap entry.
1835 */
1836 MmSetSavedSwapEntryPage(Page, SwapEntry);
1837
1838 /* Map the page into the process address space */
1840 PAddress,
1841 Attributes,
1842 Page);
1843 if (!NT_SUCCESS(Status))
1844 {
1845 DPRINT1("Unable to create virtual mapping\n");
1846 KeBugCheck(MEMORY_MANAGEMENT);
1847 }
1848 if (Process)
1850
1851 /*
1852 * Mark the offset within the section as having valid, in-memory
1853 * data
1854 */
1855 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1858
1859 DPRINT("Address 0x%p\n", Address);
1860 return STATUS_SUCCESS;
1861 }
1862 else
1863 {
1864 /* We already have a page on this section offset. Map it into the process address space. */
1866
1868 PAddress,
1869 Attributes,
1870 Page);
1871 if (!NT_SUCCESS(Status))
1872 {
1873 DPRINT1("Unable to create virtual mapping\n");
1874 KeBugCheck(MEMORY_MANAGEMENT);
1875 }
1876
1877 if (Process)
1879
1880 /* Take a reference on it */
1883
1884 DPRINT("Address 0x%p\n", Address);
1885 return STATUS_SUCCESS;
1886 }
1887}
1888
1890NTAPI
1893 PVOID Address,
1895{
1897 PFN_NUMBER OldPage;
1898 PFN_NUMBER NewPage;
1899 PFN_NUMBER UnmappedPage;
1900 PVOID PAddress;
1905 BOOLEAN Cow = FALSE;
1907 BOOLEAN Unmapped;
1908
1909 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace, MemoryArea, Address);
1910
1911 /* Get the region for this address */
1913 &MemoryArea->SectionData.RegionListHead,
1914 Address, NULL);
1915 ASSERT(Region != NULL);
1916 if (!(Region->Protect & PAGE_IS_WRITABLE))
1918
1919 /* Make sure we have a page mapping for this address. */
1921 {
1923 if (!NT_SUCCESS(Status))
1924 {
1925 /* This is invalid access ! */
1926 return Status;
1927 }
1928 }
1929
1930 /*
1931 * Check if the page has already been set readwrite
1932 */
1934 {
1935 DPRINT("Address 0x%p\n", Address);
1936 return STATUS_SUCCESS;
1937 }
1938
1939 /* Check if we are doing Copy-On-Write */
1940 Segment = MemoryArea->SectionData.Segment;
1941 Cow = Segment->WriteCopy || (Region->Protect & PAGE_IS_WRITECOPY);
1942
1943 if (!Cow)
1944 {
1945 /* Simply update page protection and we're done */
1947 return STATUS_SUCCESS;
1948 }
1949
1950 /* Calculate the new protection & check if we should update the region */
1951 NewProtect = Region->Protect;
1953 {
1954 NewProtect &= ~PAGE_IS_WRITECOPY;
1955 if (Region->Protect & PAGE_IS_EXECUTABLE)
1957 else
1960 &MemoryArea->SectionData.RegionListHead,
1963 }
1964
1965 /*
1966 * Find the offset of the page
1967 */
1968 PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
1969 Offset.QuadPart = (ULONG_PTR)PAddress - MA_GetStartingAddress(MemoryArea)
1970 + MemoryArea->SectionData.ViewOffset;
1971
1972 /* Get the page mapping this section offset. */
1975
1976 /* Get the current page mapping for the process */
1977 ASSERT(MmIsPagePresent(Process, PAddress));
1978 OldPage = MmGetPfnForProcess(Process, PAddress);
1979 ASSERT(OldPage != 0);
1980
1981 if (IS_SWAP_FROM_SSE(Entry) ||
1982 PFN_FROM_SSE(Entry) != OldPage)
1983 {
1985 /* This is a private page. We must only change the page protection. */
1987 return STATUS_SUCCESS;
1988 }
1989
1990 /*
1991 * Allocate a page
1992 */
1994 {
1995 KeBugCheck(MEMORY_MANAGEMENT);
1996 }
1997
1998 /*
1999 * Copy the old page
2000 */
2001 NT_VERIFY(NT_SUCCESS(MiCopyFromUserPage(NewPage, PAddress)));
2002
2003 /*
2004 * Unshare the old page.
2005 */
2006 DPRINT("Swapping page (Old %x New %x)\n", OldPage, NewPage);
2007 Unmapped = MmDeleteVirtualMapping(Process, PAddress, NULL, &UnmappedPage);
2008 if (!Unmapped || (UnmappedPage != OldPage))
2009 {
2010 /* Uh , we had a page just before, but suddenly it changes. Someone corrupted us. */
2011 KeBugCheckEx(MEMORY_MANAGEMENT,
2013 (ULONG_PTR)PAddress,
2014 (ULONG_PTR)__FILE__,
2015 __LINE__);
2016 }
2017
2018 if (Process)
2019 MmDeleteRmap(OldPage, Process, PAddress);
2022
2023 /*
2024 * Set the PTE to point to the new page
2025 */
2026 if (!NT_SUCCESS(MmCreateVirtualMapping(Process, PAddress, NewProtect, NewPage)))
2027 {
2028 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
2029 KeBugCheck(MEMORY_MANAGEMENT);
2030 }
2031
2032 if (Process)
2033 MmInsertRmap(NewPage, Process, PAddress);
2034
2035 DPRINT("Address 0x%p\n", Address);
2036 return STATUS_SUCCESS;
2037}
2038
2040NTAPI
2044 SIZE_T Length,
2045 ULONG Protect,
2046 PULONG OldProtect)
2047{
2050 ULONG_PTR MaxLength;
2051
2053 if (Length > MaxLength)
2054 Length = (ULONG)MaxLength;
2055
2057 &MemoryArea->SectionData.RegionListHead,
2058 BaseAddress, NULL);
2059 ASSERT(Region != NULL);
2060
2061 if ((MemoryArea->Flags & SEC_NO_CHANGE) &&
2062 Region->Protect != Protect)
2063 {
2065 }
2066
2067 *OldProtect = Region->Protect;
2069 &MemoryArea->SectionData.RegionListHead,
2072
2073 return Status;
2074}
2075
2078 PVOID Address,
2081{
2083 PVOID RegionBaseAddress;
2085
2087 &MemoryArea->SectionData.RegionListHead,
2088 Address, &RegionBaseAddress);
2089 if (Region == NULL)
2090 {
2091 return STATUS_UNSUCCESSFUL;
2092 }
2093
2095 {
2096 Segment = MemoryArea->SectionData.Segment;
2097 Info->AllocationBase = (PUCHAR)MA_GetStartingAddress(MemoryArea) - Segment->Image.VirtualAddress;
2098 Info->Type = MEM_IMAGE;
2099 }
2100 else
2101 {
2102 Info->AllocationBase = (PVOID)MA_GetStartingAddress(MemoryArea);
2103 Info->Type = MEM_MAPPED;
2104 }
2105 Info->BaseAddress = RegionBaseAddress;
2107 Info->RegionSize = Region->Length;
2108 Info->State = MEM_COMMIT;
2109 Info->Protect = Region->Protect;
2110
2112 return STATUS_SUCCESS;
2113}
2114
2115VOID NTAPI
2117{
2118 PSECTION Section = ObjectBody;
2119
2120 /* Check if it's an ARM3, or ReactOS section */
2121 if (!MiIsRosSectionObject(Section))
2122 {
2123 MiDeleteARM3Section(ObjectBody);
2124 return;
2125 }
2126
2127 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody);
2128 if (Section->u.Flags.Image)
2129 {
2130 PMM_IMAGE_SECTION_OBJECT ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)Section->Segment;
2131
2132 /*
2133 * NOTE: Section->ImageSection can be NULL for short time
2134 * during the section creating. If we fail for some reason
2135 * until the image section is properly initialized we shouldn't
2136 * process further here.
2137 */
2138 if (Section->Segment == NULL)
2139 return;
2140
2141 KIRQL OldIrql = MiAcquirePfnLock();
2142 ImageSectionObject->SectionCount--;
2143
2144 /* We just dereference the first segment */
2145 ASSERT(ImageSectionObject->RefCount > 0);
2146 /* MmDereferenceSegmentWithLock releases PFN lock */
2147 MmDereferenceSegmentWithLock(ImageSectionObject->Segments, OldIrql);
2148 }
2149 else
2150 {
2152
2153 /*
2154 * NOTE: Section->Segment can be NULL for short time
2155 * during the section creating.
2156 */
2157 if (Segment == NULL)
2158 return;
2159
2160 KIRQL OldIrql = MiAcquirePfnLock();
2161 Segment->SectionCount--;
2162
2163 /* MmDereferenceSegmentWithLock releases PFN lock */
2164 MmDereferenceSegmentWithLock(Segment, OldIrql);
2165 }
2166}
2167
2168VOID NTAPI
2170 IN PVOID Object,
2173 IN ULONG SystemHandleCount)
2174{
2175 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object, ProcessHandleCount);
2176}
2177
2178CODE_SEG("INIT")
2180NTAPI
2182{
2183 PSECTION PhysSection;
2186 UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
2187 LARGE_INTEGER SectionSize;
2188 HANDLE Handle;
2190
2191 /*
2192 * Create the section mapping physical memory
2193 */
2196 &Name,
2198 NULL,
2199 NULL);
2200 /*
2201 * Create the Object
2202 */
2205 &Obj,
2207 NULL,
2208 sizeof(*PhysSection),
2209 0,
2210 0,
2211 (PVOID*)&PhysSection);
2212 if (!NT_SUCCESS(Status))
2213 {
2214 DPRINT1("MmCreatePhysicalMemorySection: failed to create object (0x%lx)\n", Status);
2215 return Status;
2216 }
2217
2218 /*
2219 * Initialize it
2220 */
2221 RtlZeroMemory(PhysSection, sizeof(*PhysSection));
2222
2223 /* Mark this as a "ROS Section" */
2224 PhysSection->u.Flags.filler = 1;
2226 PhysSection->u.Flags.PhysicalMemory = 1;
2227 PhysSection->SizeOfSection = SectionSize;
2230 if (Segment == NULL)
2231 {
2232 ObDereferenceObject(PhysSection);
2233 return STATUS_NO_MEMORY;
2234 }
2236 PhysSection->Segment = (PSEGMENT)Segment;
2237 Segment->RefCount = 1;
2238
2239 Segment->ReferenceCount = &Segment->RefCount;
2240 Segment->Flags = &Segment->SegFlags;
2241
2243 Segment->Image.FileOffset = 0;
2244 Segment->Protection = PAGE_EXECUTE_READWRITE;
2245 Segment->RawLength = SectionSize;
2246 Segment->Length = SectionSize;
2248 Segment->WriteCopy = FALSE;
2249 Segment->Image.VirtualAddress = 0;
2250 Segment->Image.Characteristics = 0;
2252
2253 Status = ObInsertObject(PhysSection,
2254 NULL,
2256 0,
2257 NULL,
2258 &Handle);
2259 if (!NT_SUCCESS(Status))
2260 {
2261 ObDereferenceObject(PhysSection);
2262 return Status;
2263 }
2265
2266 return STATUS_SUCCESS;
2267}
2268
2269CODE_SEG("INIT")
2271NTAPI
2273{
2274 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
2276
2277 DPRINT("Creating Section Object Type\n");
2278
2279 /* Initialize the section based root */
2282
2283 /* Initialize the Section object type */
2284 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
2285 RtlInitUnicodeString(&Name, L"Section");
2286 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
2287 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(SECTION);
2288 ObjectTypeInitializer.PoolType = PagedPool;
2289 ObjectTypeInitializer.UseDefaultObject = TRUE;
2290 ObjectTypeInitializer.GenericMapping = MmpSectionMapping;
2291 ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection;
2292 ObjectTypeInitializer.CloseProcedure = MmpCloseSection;
2293 ObjectTypeInitializer.ValidAccessMask = SECTION_ALL_ACCESS;
2294 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
2295 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &MmSectionObjectType);
2296
2298
2299 return STATUS_SUCCESS;
2300}
2301
2302static
2304NTAPI
2308 PLARGE_INTEGER UMaximumSize,
2312 BOOLEAN GotFileHandle)
2313/*
2314 * Create a section backed by a data file
2315 */
2316{
2317 PSECTION Section;
2321 KIRQL OldIrql;
2322
2323 /*
2324 * Create the section
2325 */
2330 NULL,
2331 sizeof(*Section),
2332 0,
2333 0,
2334 (PVOID*)&Section);
2335 if (!NT_SUCCESS(Status))
2336 {
2337 return Status;
2338 }
2339 /*
2340 * Initialize it
2341 */
2342 RtlZeroMemory(Section, sizeof(*Section));
2343
2344 /* Mark this as a "ROS" section */
2345 Section->u.Flags.filler = 1;
2347 Section->u.Flags.File = 1;
2348
2350 Section->u.Flags.NoChange = 1;
2352 Section->u.Flags.Reserve = 1;
2353
2354 if (!GotFileHandle)
2355 {
2356 ASSERT(UMaximumSize != NULL);
2357 // ASSERT(UMaximumSize->QuadPart != 0);
2358 MaximumSize = *UMaximumSize;
2359 }
2360 else
2361 {
2364 if (!NT_SUCCESS(Status))
2365 {
2366 ObDereferenceObject(Section);
2367 return Status;
2368 }
2369
2370 /*
2371 * FIXME: Revise this once a locking order for file size changes is
2372 * decided
2373 */
2374 if ((UMaximumSize != NULL) && (UMaximumSize->QuadPart != 0))
2375 {
2376 MaximumSize = *UMaximumSize;
2377 }
2378 else
2379 {
2381 /* Mapping zero-sized files isn't allowed. */
2382 if (MaximumSize.QuadPart == 0)
2383 {
2384 ObDereferenceObject(Section);
2386 }
2387 }
2388
2389 if (MaximumSize.QuadPart > FileSize.QuadPart)
2390 {
2393 sizeof(LARGE_INTEGER),
2394 &MaximumSize);
2395 if (!NT_SUCCESS(Status))
2396 {
2397 ObDereferenceObject(Section);
2399 }
2400 }
2401 }
2402
2403 if (FileObject->SectionObjectPointer == NULL)
2404 {
2405 ObDereferenceObject(Section);
2407 }
2408
2409 /*
2410 * Lock the file
2411 */
2413 if (Status != STATUS_SUCCESS)
2414 {
2415 ObDereferenceObject(Section);
2416 return Status;
2417 }
2418
2419 /* Lock the PFN lock while messing with Section Object pointers */
2420grab_segment:
2421 OldIrql = MiAcquirePfnLock();
2422 Segment = FileObject->SectionObjectPointer->DataSectionObject;
2423
2424 while (Segment && (Segment->SegFlags & (MM_SEGMENT_INDELETE | MM_SEGMENT_INCREATE)))
2425 {
2426 MiReleasePfnLock(OldIrql);
2428 OldIrql = MiAcquirePfnLock();
2429 Segment = FileObject->SectionObjectPointer->DataSectionObject;
2430 }
2431
2432 /*
2433 * If this file hasn't been mapped as a data file before then allocate a
2434 * section segment to describe the data file mapping
2435 */
2436 if (Segment == NULL)
2437 {
2438 /* Release the lock. ExAllocatePoolWithTag might acquire it */
2439 MiReleasePfnLock(OldIrql);
2440
2443 if (Segment == NULL)
2444 {
2445 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2446 ObDereferenceObject(Section);
2447 return STATUS_NO_MEMORY;
2448 }
2449
2450 /* We are creating it */
2451 RtlZeroMemory(Segment, sizeof(*Segment));
2453 Segment->RefCount = 1;
2454
2455 /* Acquire lock again */
2456 OldIrql = MiAcquirePfnLock();
2457
2458 if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
2459 {
2460 /* Well that's bad luck. Restart it all over */
2461 MiReleasePfnLock(OldIrql);
2463 goto grab_segment;
2464 }
2465
2466 FileObject->SectionObjectPointer->DataSectionObject = Segment;
2467
2468 /* We're safe to release the lock now */
2469 MiReleasePfnLock(OldIrql);
2470
2471 Section->Segment = (PSEGMENT)Segment;
2472
2473 /* Self-referencing segment */
2474 Segment->Flags = &Segment->SegFlags;
2475 Segment->ReferenceCount = &Segment->RefCount;
2476
2477 Segment->SectionCount = 1;
2478
2480 Segment->FileObject = FileObject;
2482
2483 Segment->Image.FileOffset = 0;
2484 Segment->Protection = SectionPageProtection;
2485
2486 Segment->Image.Characteristics = 0;
2489 {
2490 Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0;
2491 }
2492 else
2493 {
2494 Segment->RawLength.QuadPart = MaximumSize.QuadPart;
2495 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
2496 }
2497 Segment->Image.VirtualAddress = 0;
2499
2500 /* We're good to use it now */
2501 OldIrql = MiAcquirePfnLock();
2502 Segment->SegFlags &= ~MM_SEGMENT_INCREATE;
2503 MiReleasePfnLock(OldIrql);
2504 }
2505 else
2506 {
2507 Section->Segment = (PSEGMENT)Segment;
2508 InterlockedIncrement64(&Segment->RefCount);
2509 InterlockedIncrementUL(&Segment->SectionCount);
2510
2511 MiReleasePfnLock(OldIrql);
2512
2514
2515 if (MaximumSize.QuadPart > Segment->RawLength.QuadPart &&
2517 {
2518 Segment->RawLength.QuadPart = MaximumSize.QuadPart;
2519 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
2520 }
2521
2523 }
2524 Section->SizeOfSection = MaximumSize;
2525
2526 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2527 *SectionObject = Section;
2528 return STATUS_SUCCESS;
2529}
2530
2531/*
2532 TODO: not that great (declaring loaders statically, having to declare all of
2533 them, having to keep them extern, etc.), will fix in the future
2534*/
2536(
2537 IN CONST VOID * FileHeader,
2538 IN SIZE_T FileHeaderSize,
2539 IN PVOID File,
2540 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
2542 IN PEXEFMT_CB_READ_FILE ReadFileCb,
2543 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2544);
2545
2547(
2548 IN CONST VOID * FileHeader,
2549 IN SIZE_T FileHeaderSize,
2550 IN PVOID File,
2551 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
2553 IN PEXEFMT_CB_READ_FILE ReadFileCb,
2554 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2555);
2556
2558{
2560#ifdef __ELF
2562#endif
2563};
2564
2565static
2567NTAPI
2569{
2570 SIZE_T SizeOfSegments;
2571 PMM_SECTION_SEGMENT Segments;
2572
2573 /* TODO: check for integer overflow */
2574 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments;
2575
2577 SizeOfSegments,
2579
2580 if(Segments)
2581 RtlZeroMemory(Segments, SizeOfSegments);
2582
2583 return Segments;
2584}
2585static
2587NTAPI
2590 IN ULONG Length,
2591 OUT PVOID * Data,
2592 OUT PVOID * AllocBase,
2593 OUT PULONG ReadSize)
2594{
2597 ULONG AdjustOffset;
2598 ULONG OffsetAdjustment;
2600 ULONG UsedSize;
2601 PVOID Buffer;
2604
2606
2607 if(Length == 0)
2608 {
2609 KeBugCheck(MEMORY_MANAGEMENT);
2610 }
2611
2612 FileOffset = *Offset;
2613
2614 /* Negative/special offset: it cannot be used in this context */
2615 if(FileOffset.u.HighPart < 0)
2616 {
2617 KeBugCheck(MEMORY_MANAGEMENT);
2618 }
2619
2620 AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart);
2621 OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset;
2622 FileOffset.u.LowPart = AdjustOffset;
2623
2624 BufferSize = Length + OffsetAdjustment;
2626
2627 /*
2628 * It's ok to use paged pool, because this is a temporary buffer only used in
2629 * the loading of executables. The assumption is that MmCreateSection is
2630 * always called at low IRQLs and that these buffers don't survive a brief
2631 * initialization phase
2632 */
2634 if (!Buffer)
2635 {
2637 }
2638
2640
2641 UsedSize = (ULONG)Iosb.Information;
2642
2643 if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
2644 {
2647 }
2648
2649 if(NT_SUCCESS(Status))
2650 {
2651 *Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment);
2652 *AllocBase = Buffer;
2653 *ReadSize = UsedSize - OffsetAdjustment;
2654 }
2655 else
2656 {
2657 ExFreePoolWithTag(Buffer, 'rXmM');
2658 }
2659
2660 return Status;
2661}
2662
2663#ifdef NASSERT
2664# define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2665# define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2666# define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2667#else
2668static
2669VOID
2670NTAPI
2672{
2673 ULONG i;
2674
2675 for( i = 1; i < ImageSectionObject->NrSegments; ++ i )
2676 {
2677 ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >=
2678 ImageSectionObject->Segments[i - 1].Image.VirtualAddress);
2679 }
2680}
2681
2682static
2683VOID
2684NTAPI
2686{
2687 ULONG i;
2688
2689 MmspAssertSegmentsSorted(ImageSectionObject);
2690
2691 for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
2692 {
2693 ASSERT(ImageSectionObject->Segments[i].Length.QuadPart > 0);
2694
2695 if(i > 0)
2696 {
2697 ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >=
2698 (ImageSectionObject->Segments[i - 1].Image.VirtualAddress +
2699 ImageSectionObject->Segments[i - 1].Length.QuadPart));
2700 }
2701 }
2702}
2703
2704static
2705VOID
2706NTAPI
2708{
2709 ULONG i;
2710
2711 for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
2712 {
2713 ASSERT((ImageSectionObject->Segments[i].Image.VirtualAddress % PAGE_SIZE) == 0);
2714 ASSERT((ImageSectionObject->Segments[i].Length.QuadPart % PAGE_SIZE) == 0);
2715 }
2716}
2717#endif
2718
2719static
2720int
2721__cdecl
2723 const void * y)
2724{
2725 const MM_SECTION_SEGMENT *Segment1 = (const MM_SECTION_SEGMENT *)x;
2726 const MM_SECTION_SEGMENT *Segment2 = (const MM_SECTION_SEGMENT *)y;
2727
2728 if (Segment1->Image.VirtualAddress > Segment2->Image.VirtualAddress)
2729 return 1;
2730 else if (Segment1->Image.VirtualAddress < Segment2->Image.VirtualAddress)
2731 return -1;
2732 else
2733 return 0;
2734}
2735
2736/*
2737 * Ensures an image section's segments are sorted in memory
2738 */
2739static
2740VOID
2741NTAPI
2743 IN ULONG Flags)
2744{
2746 {
2747 MmspAssertSegmentsSorted(ImageSectionObject);
2748 }
2749 else
2750 {
2751 qsort(ImageSectionObject->Segments,
2752 ImageSectionObject->NrSegments,
2753 sizeof(ImageSectionObject->Segments[0]),
2755 }
2756}
2757
2758
2759/*
2760 * Ensures an image section's segments don't overlap in memory and don't have
2761 * gaps and don't have a null size. We let them map to overlapping file regions,
2762 * though - that's not necessarily an error
2763 */
2764static
2765BOOLEAN
2766NTAPI
2768(
2769 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
2770 IN ULONG Flags
2771)
2772{
2773 ULONG i;
2774
2776 {
2777 MmspAssertSegmentsNoOverlap(ImageSectionObject);
2778 return TRUE;
2779 }
2780
2781 ASSERT(ImageSectionObject->NrSegments >= 1);
2782
2783 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
2784 {
2785 if(ImageSectionObject->Segments[i].Length.QuadPart == 0)
2786 {
2787 return FALSE;
2788 }
2789
2790 if(i > 0)
2791 {
2792 /*
2793 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2794 * page could be OK (Windows seems to be OK with them), and larger gaps
2795 * could lead to image sections spanning several discontiguous regions
2796 * (NtMapViewOfSection could then refuse to map them, and they could
2797 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2798 */
2799 if ((ImageSectionObject->Segments[i - 1].Image.VirtualAddress +
2800 ImageSectionObject->Segments[i - 1].Length.QuadPart) !=
2801 ImageSectionObject->Segments[i].Image.VirtualAddress)
2802 {
2803 return FALSE;
2804 }
2805 }
2806 }
2807
2808 return TRUE;
2809}
2810
2811/*
2812 * Merges and pads an image section's segments until they all are page-aligned
2813 * and have a size that is a multiple of the page size
2814 */
2815static
2816BOOLEAN
2817NTAPI
2819(
2820 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
2821 IN ULONG Flags
2822)
2823{
2824 ULONG i;
2825 ULONG LastSegment;
2826 PMM_SECTION_SEGMENT EffectiveSegment;
2827
2829 {
2830 MmspAssertSegmentsPageAligned(ImageSectionObject);
2831 return TRUE;
2832 }
2833
2834 LastSegment = 0;
2835 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
2836
2837 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
2838 {
2839 /*
2840 * The first segment requires special handling
2841 */
2842 if (i == 0)
2843 {
2845 ULONG_PTR VirtualOffset;
2846
2847 VirtualAddress = EffectiveSegment->Image.VirtualAddress;
2848
2849 /* Round down the virtual address to the nearest page */
2850 EffectiveSegment->Image.VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
2851
2852 /* Round up the virtual size to the nearest page */
2853 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length.QuadPart) -
2854 EffectiveSegment->Image.VirtualAddress;
2855
2856 /* Adjust the raw address and size */
2857 VirtualOffset = VirtualAddress - EffectiveSegment->Image.VirtualAddress;
2858
2859 if (EffectiveSegment->Image.FileOffset < VirtualOffset)
2860 {
2861 return FALSE;
2862 }
2863
2864 /*
2865 * Garbage in, garbage out: unaligned base addresses make the file
2866 * offset point in curious and odd places, but that's what we were
2867 * asked for
2868 */
2869 EffectiveSegment->Image.FileOffset -= VirtualOffset;
2870 EffectiveSegment->RawLength.QuadPart += VirtualOffset;
2871 }
2872 else
2873 {
2874 PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
2875 ULONG_PTR EndOfEffectiveSegment;
2876
2877 EndOfEffectiveSegment = (ULONG_PTR)(EffectiveSegment->Image.VirtualAddress + EffectiveSegment->Length.QuadPart);
2878 ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
2879
2880 /*
2881 * The current segment begins exactly where the current effective
2882 * segment ended, therefore beginning a new effective segment
2883 */
2884 if (EndOfEffectiveSegment == Segment->Image.VirtualAddress)
2885 {
2886 LastSegment ++;
2887 ASSERT(LastSegment <= i);
2888 ASSERT(LastSegment < ImageSectionObject->NrSegments);
2889
2890 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
2891
2892 if (LastSegment != i)
2893 {
2894 /*
2895 * Copy the current segment. If necessary, the effective segment
2896 * will be expanded later
2897 */
2898 *EffectiveSegment = *Segment;
2899 }
2900
2901 /*
2902 * Page-align the virtual size. We know for sure the virtual address
2903 * already is
2904 */
2905 ASSERT((EffectiveSegment->Image.VirtualAddress % PAGE_SIZE) == 0);
2906 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(EffectiveSegment->Length.QuadPart);
2907 }
2908 /*
2909 * The current segment is still part of the current effective segment:
2910 * extend the effective segment to reflect this
2911 */
2912 else if (EndOfEffectiveSegment > Segment->Image.VirtualAddress)
2913 {
2914 static const ULONG FlagsToProtection[16] =
2915 {
2932 };
2933
2934 unsigned ProtectionFlags;
2935
2936 /*
2937 * Extend the file size
2938 */
2939
2940 /* Unaligned segments must be contiguous within the file */
2941 if (Segment->Image.FileOffset != (EffectiveSegment->Image.FileOffset +
2942 EffectiveSegment->RawLength.QuadPart))
2943 {
2944 return FALSE;
2945 }
2946
2947 EffectiveSegment->RawLength.QuadPart += Segment->RawLength.QuadPart;
2948
2949 /*
2950 * Extend the virtual size
2951 */
2952 ASSERT(PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) >= EndOfEffectiveSegment);
2953
2954 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) -
2955 EffectiveSegment->Image.VirtualAddress;
2956
2957 /*
2958 * Merge the protection
2959 */
2960 EffectiveSegment->Protection |= Segment->Protection;
2961
2962 /* Clean up redundance */
2963 ProtectionFlags = 0;
2964
2965 if(EffectiveSegment->Protection & PAGE_IS_READABLE)
2966 ProtectionFlags |= 1 << 0;
2967
2968 if(EffectiveSegment->Protection & PAGE_IS_WRITABLE)
2969 ProtectionFlags |= 1 << 1;
2970
2971 if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE)
2972 ProtectionFlags |= 1 << 2;
2973
2974 if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
2975 ProtectionFlags |= 1 << 3;
2976
2977 ASSERT(ProtectionFlags < 16);
2978 EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags];
2979
2980 /* If a segment was required to be shared and cannot, fail */
2981 if(!(Segment->Protection & PAGE_IS_WRITECOPY) &&
2982 EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
2983 {
2984 return FALSE;
2985 }
2986 }
2987 /*
2988 * We assume no holes between segments at this point
2989 */
2990 else
2991 {
2992 KeBugCheck(MEMORY_MANAGEMENT);
2993 }
2994 }
2995 }
2996 ImageSectionObject->NrSegments = LastSegment + 1;
2997
2998 return TRUE;
2999}
3000
3003 PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3004{
3006 PVOID FileHeader;
3007 PVOID FileHeaderBuffer;
3008 ULONG FileHeaderSize;
3009 ULONG Flags;
3010 ULONG OldNrSegments;
3012 ULONG i;
3013
3014 /*
3015 * Read the beginning of the file (2 pages). Should be enough to contain
3016 * all (or most) of the headers
3017 */
3018 Offset.QuadPart = 0;
3019
3021 &Offset,
3022 PAGE_SIZE * 2,
3023 &FileHeader,
3024 &FileHeaderBuffer,
3025 &FileHeaderSize);
3026
3027 if (!NT_SUCCESS(Status))
3028 return Status;
3029
3030 if (FileHeaderSize == 0)
3031 {
3032 ExFreePool(FileHeaderBuffer);
3033 return STATUS_UNSUCCESSFUL;
3034 }
3035
3036 /*
3037 * Look for a loader that can handle this executable
3038 */
3039 for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i)
3040 {
3041 Flags = 0;
3042
3043 Status = ExeFmtpLoaders[i](FileHeader,
3044 FileHeaderSize,
3045 FileObject,
3046 ImageSectionObject,
3047 &Flags,
3050
3051 if (!NT_SUCCESS(Status))
3052 {
3053 if (ImageSectionObject->Segments)
3054 {
3055 ExFreePool(ImageSectionObject->Segments);
3056 ImageSectionObject->Segments = NULL;
3057 }
3058 }
3059
3061 break;
3062 }
3063
3064 ExFreePoolWithTag(FileHeaderBuffer, 'rXmM');
3065
3066 /*
3067 * No loader handled the format
3068 */
3070 {
3073 }
3074
3075 if (!NT_SUCCESS(Status))
3076 return Status;
3077
3078 ASSERT(ImageSectionObject->Segments != NULL);
3079 ASSERT(ImageSectionObject->RefCount > 0);
3080
3081 /*
3082 * Some defaults
3083 */
3084 /* FIXME? are these values platform-dependent? */
3085 if (ImageSectionObject->ImageInformation.MaximumStackSize == 0)
3086 ImageSectionObject->ImageInformation.MaximumStackSize = 0x40000;
3087
3088 if(ImageSectionObject->ImageInformation.CommittedStackSize == 0)
3089 ImageSectionObject->ImageInformation.CommittedStackSize = 0x1000;
3090
3091 if(ImageSectionObject->BasedAddress == NULL)
3092 {
3093 if(ImageSectionObject->ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL)
3094 ImageSectionObject->BasedAddress = (PVOID)0x10000000;
3095 else
3096 ImageSectionObject->BasedAddress = (PVOID)0x00400000;
3097 }
3098
3099 /*
3100 * And now the fun part: fixing the segments
3101 */
3102
3103 /* Sort them by virtual address */
3104 MmspSortSegments(ImageSectionObject, Flags);
3105
3106 /* Ensure they don't overlap in memory */
3107 if (!MmspCheckSegmentBounds(ImageSectionObject, Flags))
3109
3110 /* Ensure they are aligned */
3111 OldNrSegments = ImageSectionObject->NrSegments;
3112
3113 if (!MmspPageAlignSegments(ImageSectionObject, Flags))
3115
3116 /* Trim them if the alignment phase merged some of them */
3117 if (ImageSectionObject->NrSegments < OldNrSegments)
3118 {
3119 PMM_SECTION_SEGMENT Segments;
3120 SIZE_T SizeOfSegments;
3121
3122 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments;
3123
3125 SizeOfSegments,
3127
3128 if (Segments == NULL)
3130
3131 RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments);
3132 ExFreePool(ImageSectionObject->Segments);
3133 ImageSectionObject->Segments = Segments;
3134 }
3135
3136 /* And finish their initialization */
3137 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3138 {
3139 ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock);
3140 ImageSectionObject->Segments[i].ReferenceCount = &ImageSectionObject->RefCount;
3141 ImageSectionObject->Segments[i].Flags = &ImageSectionObject->SegFlags;
3142 MiInitializeSectionPageTable(&ImageSectionObject->Segments[i]);
3143 ImageSectionObject->Segments[i].FileObject = FileObject;
3144 }
3145
3146 ASSERT(ImageSectionObject->RefCount > 0);
3147
3148 ImageSectionObject->FileObject = FileObject;
3149
3151 return Status;
3152}
3153
3158 PLARGE_INTEGER UMaximumSize,
3162{
3163 PSECTION Section;
3165 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3166 KIRQL OldIrql;
3167
3168
3169 if (FileObject == NULL)
3171
3172 if (FileObject->SectionObjectPointer == NULL)
3173 {
3174 DPRINT1("Denying section creation due to missing cache initialization\n");
3176 }
3177
3178 /*
3179 * Create the section
3180 */
3185 NULL,
3186 sizeof(*Section),
3187 0,
3188 0,
3189 (PVOID*)(PVOID)&Section);
3190 if (!NT_SUCCESS(Status))
3191 {
3192 return Status;
3193 }
3194
3195 /*
3196 * Initialize it
3197 */
3198 RtlZeroMemory(Section, sizeof(*Section));
3199
3200 /* Mark this as a "ROS" Section */
3201 Section->u.Flags.filler = 1;
3202
3204 Section->u.Flags.File = 1;
3205 Section->u.Flags.Image = 1;
3207 Section->u.Flags.NoChange = 1;
3208
3209grab_image_section_object:
3210 OldIrql = MiAcquirePfnLock();
3211
3212 /* Wait for it to be properly created or deleted */
3213 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3214 while(ImageSectionObject && (ImageSectionObject->SegFlags & (MM_SEGMENT_INDELETE | MM_SEGMENT_INCREATE)))
3215 {
3216 MiReleasePfnLock(OldIrql);
3217
3219
3220 OldIrql = MiAcquirePfnLock();
3221 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3222 }
3223
3224 if (ImageSectionObject == NULL)
3225 {
3226 NTSTATUS StatusExeFmt;
3227
3228 /* Release the lock because ExAllocatePoolWithTag could need to acquire it */
3229 MiReleasePfnLock(OldIrql);
3230
3231 ImageSectionObject = ExAllocatePoolZero(NonPagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
3232 if (ImageSectionObject == NULL)
3233 {
3234 ObDereferenceObject(Section);
3235 return STATUS_NO_MEMORY;
3236 }
3237
3238 ImageSectionObject->SegFlags = MM_SEGMENT_INCREATE;
3239 ImageSectionObject->RefCount = 1;
3240 ImageSectionObject->SectionCount = 1;
3241
3242 OldIrql = MiAcquirePfnLock();
3243 if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
3244 {
3245 MiReleasePfnLock(OldIrql);
3246 /* Bad luck. Start over */
3247 ExFreePoolWithTag(ImageSectionObject, TAG_MM_SECTION_SEGMENT);
3248 goto grab_image_section_object;
3249 }
3250
3251 FileObject->SectionObjectPointer->ImageSectionObject = ImageSectionObject;
3252
3253 MiReleasePfnLock(OldIrql);
3254
3255 /* Purge the cache */
3256 CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, NULL);
3257
3258 StatusExeFmt = ExeFmtpCreateImageSection(FileObject, ImageSectionObject);
3259
3260 if (!NT_SUCCESS(StatusExeFmt))
3261 {
3262 /* Unset */
3263 OldIrql = MiAcquirePfnLock();
3264 FileObject->SectionObjectPointer->ImageSectionObject = NULL;
3265 MiReleasePfnLock(OldIrql);
3266
3267 if(ImageSectionObject->Segments != NULL)
3268 ExFreePool(ImageSectionObject->Segments);
3269
3270 /*
3271 * If image file is empty, then return that the file is invalid for section
3272 */
3273 Status = StatusExeFmt;
3274 if (StatusExeFmt == STATUS_END_OF_FILE)
3275 {
3277 }
3278
3279 ExFreePoolWithTag(ImageSectionObject, TAG_MM_SECTION_SEGMENT);
3280 ObDereferenceObject(Section);
3281 return Status;
3282 }
3283
3284 Section->Segment = (PSEGMENT)ImageSectionObject;
3285 ASSERT(ImageSectionObject->Segments);
3286 ASSERT(ImageSectionObject->RefCount > 0);
3287
3288 /*
3289 * Lock the file
3290 */
3292 if (!NT_SUCCESS(Status))
3293 {
3294 /* Unset */
3295 OldIrql = MiAcquirePfnLock();
3296 FileObject->SectionObjectPointer->ImageSectionObject = NULL;
3297 MiReleasePfnLock(OldIrql);
3298
3299 ExFreePool(ImageSectionObject->Segments);
3300 ExFreePool(ImageSectionObject);
3301 ObDereferenceObject(Section);
3302 return Status;
3303 }
3304
3305 OldIrql = MiAcquirePfnLock();
3306 ImageSectionObject->SegFlags &= ~MM_SEGMENT_INCREATE;
3307
3308 /* Take a ref on the file on behalf of the newly created structure */
3310
3311 MiReleasePfnLock(OldIrql);
3312
3313 Status = StatusExeFmt;
3314 }
3315 else
3316 {
3317 /* If FS driver called for delete, tell them it's not possible anymore. */
3318 ImageSectionObject->SegFlags &= ~MM_IMAGE_SECTION_FLUSH_DELETE;
3319
3320 /* Take one ref */
3321 InterlockedIncrement64(&ImageSectionObject->RefCount);
3322 ImageSectionObject->SectionCount++;
3323
3324 MiReleasePfnLock(OldIrql);
3325
3326 Section->Segment = (PSEGMENT)ImageSectionObject;
3327
3329 }
3330 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3331 *SectionObject = Section;
3332 ASSERT(ImageSectionObject->RefCount > 0);
3333
3334 return Status;
3335}
3336
3337
3338
3339static NTSTATUS
3342 BOOLEAN AsImage,
3346 ULONG Protect,
3347 LONGLONG ViewOffset,
3349{
3350 PMEMORY_AREA MArea;
3352 ULONG Granularity;
3353
3354 ASSERT(ViewSize != 0);
3355
3356 if (Segment->WriteCopy)
3357 {
3358 /* We have to do this because the not present fault
3359 * and access fault handlers depend on the protection
3360 * that should be granted AFTER the COW fault takes
3361 * place to be in Region->Protect. The not present fault
3362 * handler changes this to the correct protection for COW when
3363 * mapping the pages into the process's address space. If a COW
3364 * fault takes place, the access fault handler sets the page protection
3365 * to these values for the newly copied pages
3366 */
3367 if (Protect == PAGE_WRITECOPY)
3369 else if (Protect == PAGE_EXECUTE_WRITECOPY)
3371 }
3372
3373 if (*BaseAddress == NULL)
3374 Granularity = MM_ALLOCATION_GRANULARITY;
3375 else
3376 Granularity = PAGE_SIZE;
3377
3378#ifdef NEWCC
3379 if (Segment->Flags & MM_DATAFILE_SEGMENT)
3380 {
3382 FileOffset.QuadPart = ViewOffset;
3383 ObReferenceObject(Section);
3385 }
3386#endif
3390 ViewSize,
3391 Protect,
3392 &MArea,
3394 Granularity);
3395 if (!NT_SUCCESS(Status))
3396 {
3397 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
3398 (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
3399 return Status;
3400 }
3401
3402 InterlockedIncrement64(Segment->ReferenceCount);
3403
3404 MArea->SectionData.Segment = Segment;
3405 MArea->SectionData.ViewOffset = ViewOffset;
3406 if (AsImage)
3407 {
3409 }
3410
3411 MmInitializeRegion(&MArea->SectionData.RegionListHead,
3412 ViewSize, 0, Protect);
3413
3414 return STATUS_SUCCESS;
3415}
3416
3417
3418static VOID
3420 PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
3421{
3424 SWAPENTRY SavedSwapEntry;
3428
3431
3433
3435 MemoryArea->SectionData.ViewOffset;
3436
3437 Segment = MemoryArea->SectionData.Segment;
3438
3440 while (Entry && MM_IS_WAIT_PTE(Entry))
3441 {
3444
3446
3450 }
3451
3452 /*
3453 * For a dirty, datafile, non-private page, there shoulkd be no swap entry
3454 */
3455 if (*Segment->Flags & MM_DATAFILE_SEGMENT)
3456 {
3457 if (Page == PFN_FROM_SSE(Entry) && Dirty)
3458 {
3459 ASSERT(SwapEntry == 0);
3460 }
3461 }
3462
3463 if (SwapEntry != 0)
3464 {
3465 /*
3466 * Sanity check
3467 */
3468 MmFreeSwapPage(SwapEntry);
3469 }
3470 else if (Page != 0)
3471 {
3472 if (IS_SWAP_FROM_SSE(Entry) ||
3474 {
3475 ASSERT(Process != NULL);
3476
3477 /*
3478 * Just dereference private pages
3479 */
3480 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
3481 if (SavedSwapEntry != 0)
3482 {
3483 MmFreeSwapPage(SavedSwapEntry);
3485 }
3488 }
3489 else
3490 {
3491 if (Process)
3492 {
3494 }
3495
3496 /* We don't dirtify for System Space Maps. We let Cc manage that */
3498 }
3499 }
3500}
3501
3502static NTSTATUS
3505{
3509 PLIST_ENTRY CurrentEntry;
3510 PMM_REGION CurrentRegion;
3511 PLIST_ENTRY RegionListHead;
3512
3514 BaseAddress);
3515 if (MemoryArea == NULL)
3516 {
3517 return STATUS_UNSUCCESSFUL;
3518 }
3519
3520 Segment = MemoryArea->SectionData.Segment;
3521
3522#ifdef NEWCC
3523 if (Segment->Flags & MM_DATAFILE_SEGMENT)
3524 {
3528
3529 return Status;
3530 }
3531#endif
3532
3534
3536
3537 RegionListHead = &MemoryArea->SectionData.RegionListHead;
3538 while (!IsListEmpty(RegionListHead))
3539 {
3540 CurrentEntry = RemoveHeadList(RegionListHead);
3541 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
3542 ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION);
3543 }
3544
3545 if ((*Segment->Flags) & MM_PHYSICALMEMORY_SEGMENT)
3546 {
3548 MemoryArea,
3549 NULL,
3550 NULL);
3551 }
3552 else
3553 {
3555 MemoryArea,
3557 AddressSpace);
3558 }
3560 MmDereferenceSegment(Segment);
3561 return Status;
3562}
3563
3564/* This functions must be called with a locked address space */
3566NTAPI
3569 IN BOOLEAN SkipDebuggerNotify)
3570{
3574 PVOID ImageBaseAddress = 0;
3575
3576 DPRINT("Opening memory area Process %p BaseAddress %p\n",
3578
3579 ASSERT(Process);
3580
3581 AddressSpace = &Process->Vm;
3582
3584 BaseAddress);
3585 if (MemoryArea == NULL ||
3586#ifdef NEWCC
3587 ((MemoryArea->Type != MEMORY_AREA_SECTION_VIEW) && (MemoryArea->Type != MEMORY_AREA_CACHE)) ||
3588#else
3590#endif
3592
3593 {
3595
3596 DPRINT1("Unable to find memory area at address %p.\n", BaseAddress);
3598 }
3599
3601 {
3602 ULONG i;
3603 ULONG NrSegments;
3604 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3605 PMM_SECTION_SEGMENT SectionSegments;
3607
3608 Segment = MemoryArea->SectionData.Segment;
3609 ImageSectionObject = ImageSectionObjectFromSegment(Segment);
3610 SectionSegments = ImageSectionObject->Segments;
3611 NrSegments = ImageSectionObject->NrSegments;
3612
3614
3615 /* Search for the current segment within the section segments
3616 * and calculate the image base address */
3617 for (i = 0; i < NrSegments; i++)
3618 {
3619 if (Segment == &SectionSegments[i])
3620 {
3621 ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].Image.VirtualAddress;
3622 break;
3623 }
3624 }
3625 if (i >= NrSegments)
3626 {
3627 KeBugCheck(MEMORY_MANAGEMENT);
3628 }
3629
3630 for (i = 0; i < NrSegments; i++)
3631 {
3632 PVOID SBaseAddress = (PVOID)
3633 ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress);
3634
3635 Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
3636 if (!NT_SUCCESS(Status))
3637 {
3638 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
3639 SBaseAddress, Process, Status);
3641 }
3642 }
3643 DPRINT("One mapping less for %p\n", ImageSectionObject->FileObject->SectionObjectPointer);
3644 InterlockedDecrement(&ImageSectionObject->MapCount);
3645 }
3646 else
3647 {
3649 PMMVAD Vad = &MemoryArea->VadNode;
3652 LARGE_INTEGER ViewOffset;
3653 ViewOffset.QuadPart = MemoryArea->SectionData.ViewOffset;
3654
3655 InterlockedIncrement64(Segment->ReferenceCount);
3656
3658 if (!NT_SUCCESS(Status))
3659 {
3660 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
3663 }
3664
3666 {
3667 /* Don't bother */
3668 MmDereferenceSegment(Segment);
3669 return STATUS_SUCCESS;
3670 }
3672
3673 FileObject = Segment->FileObject;
3675
3676 /* Don't bother for auto-delete closed file. */
3678 {
3680 MmDereferenceSegment(Segment);
3681 return STATUS_SUCCESS;
3682 }
3683
3684 /*
3685 * Flush only when last mapping is deleted.
3686 * FIXME: Why Vad->ControlArea == NULL?
3687 */
3688 if (Vad->ControlArea == NULL || Vad->ControlArea->NumberOfMappedViews == 1)
3689 {
3690 ViewSize = PAGE_SIZE + ((Vad->EndingVpn - Vad->StartingVpn) << PAGE_SHIFT);
3691 while (ViewSize > 0)
3692 {
3693 ULONG FlushSize = min(ViewSize, PAGE_ROUND_DOWN(MAXULONG));
3694 MmFlushSegment(FileObject->SectionObjectPointer,
3695 &ViewOffset,
3696 FlushSize,
3697 NULL);
3698 ViewSize -= FlushSize;
3699 ViewOffset.QuadPart += FlushSize;
3700 }
3701 }
3702
3704 MmDereferenceSegment(Segment);
3705 }
3706
3707 /* Notify debugger */
3708 if (ImageBaseAddress && !SkipDebuggerNotify) DbgkUnMapViewOfSection(ImageBaseAddress);
3709
3710 return STATUS_SUCCESS;
3711}
3712
3713
3714
3715
3739NTAPI
3741 _In_ HANDLE SectionHandle,
3742 _In_ SECTION_INFORMATION_CLASS SectionInformationClass,
3743 _Out_ PVOID SectionInformation,
3744 _In_ SIZE_T SectionInformationLength,
3746{
3747 PSECTION Section;
3750 PAGED_CODE();
3751
3753 if (PreviousMode != KernelMode)
3754 {
3755 _SEH2_TRY
3756 {
3757 ProbeForWrite(SectionInformation,
3758 SectionInformationLength,
3759 __alignof(ULONG));
3760 if (ResultLength != NULL)
3761 {
3763 sizeof(*ResultLength),
3764 __alignof(SIZE_T));
3765 }
3766 }
3768 {
3770 }
3771 _SEH2_END;
3772 }
3773
3774 if (SectionInformationClass == SectionBasicInformation)
3775 {
3776 if (SectionInformationLength < sizeof(SECTION_BASIC_INFORMATION))
3777 {
3779 }
3780 }
3781 else if (SectionInformationClass == SectionImageInformation)
3782 {
3783 if (SectionInformationLength < sizeof(SECTION_IMAGE_INFORMATION))
3784 {
3786 }
3787 }
3788 else
3789 {
3791 }
3792
3793 Status = ObReferenceObjectByHandle(SectionHandle,
3797 (PVOID*)(PVOID)&Section,
3798 NULL);
3799 if (!NT_SUCCESS(Status))
3800 {
3801 DPRINT1("Failed to reference section: 0x%lx\n", Status);
3802 return Status;
3803 }
3804
3805 switch(SectionInformationClass)
3806 {
3808 {
3810
3811 Sbi.Size = Section->SizeOfSection;
3812 Sbi.BaseAddress = (PVOID)Section->Address.StartingVpn;
3813
3814 Sbi.Attributes = 0;
3815 if (Section->u.Flags.File)
3816 Sbi.Attributes |= SEC_FILE;
3817 if (Section->u.Flags.Image)
3818 Sbi.Attributes |= SEC_IMAGE;
3819
3820 /* Those are not set *************
3821 if (Section->u.Flags.Commit)
3822 Sbi.Attributes |= SEC_COMMIT;
3823 if (Section->u.Flags.Reserve)
3824 Sbi.Attributes |= SEC_RESERVE;
3825 **********************************/
3826
3827 if (Section->u.Flags.Image)
3828 {
3829 if (MiIsRosSectionObject(Section))
3830 {
3831 PMM_IMAGE_SECTION_OBJECT ImageSectionObject = ((PMM_IMAGE_SECTION_OBJECT)Section->Segment);
3832 Sbi.BaseAddress = 0;
3833 Sbi.Size.QuadPart = ImageSectionObject->ImageInformation.ImageFileSize;
3834 }
3835 else
3836 {
3837 /* Not supported yet */
3838 ASSERT(FALSE);
3839 }
3840 }
3841 else if (MiIsRosSectionObject(Section))
3842 {
3843 Sbi.BaseAddress = (PVOID)((PMM_SECTION_SEGMENT)Section->Segment)->Image.VirtualAddress;
3844 Sbi.Size.QuadPart = ((PMM_SECTION_SEGMENT)Section->Segment)->RawLength.QuadPart;
3845 }
3846 else
3847 {
3848 DPRINT1("Unimplemented code path!");
3849 }
3850
3851 _SEH2_TRY
3852 {
3853 *((SECTION_BASIC_INFORMATION*)SectionInformation) = Sbi;
3854 if (ResultLength != NULL)
3855 {
3856 *ResultLength = sizeof(Sbi);
3857 }
3858 }
3860 {
3862 }
3863 _SEH2_END;
3864 break;
3865 }
3867 {
3868 if (!Section->u.Flags.Image)
3869 {
3871 }
3872 else if (MiIsRosSectionObject(Section))
3873 {
3874 PMM_IMAGE_SECTION_OBJECT ImageSectionObject = ((PMM_IMAGE_SECTION_OBJECT)Section->Segment);
3875
3876 _SEH2_TRY
3877 {
3879 *Sii = ImageSectionObject->ImageInformation;
3880 if (ResultLength != NULL)
3881 {
3882 *ResultLength = sizeof(*Sii);
3883 }
3884 }
3886 {
3888 }
3889 _SEH2_END;
3890 }
3891 else
3892 {
3893 _SEH2_TRY
3894 {
3896 *Sii = *Section->Segment->u2.ImageInformation;
3897 if (ResultLength != NULL)
3898 *ResultLength = sizeof(*Sii);
3899 }
3901 {
3903 }
3904 _SEH2_END;
3905 }
3906 break;
3907 }
3908 default:
3909 DPRINT1("Unknown SectionInformationClass: %d\n", SectionInformationClass);
3911 }
3912
3913 ObDereferenceObject(Section);
3914
3915 return Status;
3916}
3917
3918/**********************************************************************
3919 * NAME EXPORTED
3920 * MmMapViewOfSection
3921 *
3922 * DESCRIPTION
3923 * Maps a view of a section into the virtual address space of a
3924 * process.
3925 *
3926 * ARGUMENTS
3927 * Section
3928 * Pointer to the section object.
3929 *
3930 * ProcessHandle
3931 * Pointer to the process.
3932 *
3933 * BaseAddress
3934 * Desired base address (or NULL) on entry;
3935 * Actual base address of the view on exit.
3936 *
3937 * ZeroBits
3938 * Number of high order address bits that must be zero.
3939 *
3940 * CommitSize
3941 * Size in bytes of the initially committed section of
3942 * the view.
3943 *
3944 * SectionOffset
3945 * Offset in bytes from the beginning of the section
3946 * to the beginning of the view.
3947 *
3948 * ViewSize
3949 * Desired length of map (or zero to map all) on entry
3950 * Actual length mapped on exit.
3951 *
3952 * InheritDisposition
3953 * Specified how the view is to be shared with
3954 * child processes.
3955 *
3956 * AllocationType
3957 * Type of allocation for the pages.
3958 *
3959 * Protect
3960 * Protection for the committed region of the view.
3961 *
3962 * RETURN VALUE
3963 * Status.
3964 *
3965 * @implemented
3966 */
3978{
3979 PSECTION Section;
3982 BOOLEAN NotAtBase = FALSE;
3983
3985 {
3986 DPRINT("Mapping ARM3 section into %s\n", Process->ImageFileName);
3988 Process,
3990 ZeroBits,
3991 CommitSize,
3993 ViewSize,
3996 Protect);
3997 }
3998
3999 ASSERT(Process);
4000
4002 {
4004 }
4005
4006 /* FIXME: We should keep this, but it would break code checking equality */
4007 Protect &= ~PAGE_NOCACHE;
4008
4009 Section = SectionObject;
4010 AddressSpace = &Process->Vm;
4011
4012 if (Section->u.Flags.NoChange)
4014
4016
4017 if (Section->u.Flags.Image)
4018 {
4019 ULONG i;
4020 ULONG NrSegments;
4021 ULONG_PTR ImageBase;
4022 SIZE_T ImageSize;
4023 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4024 PMM_SECTION_SEGMENT SectionSegments;
4025
4026 ImageSectionObject = ((PMM_IMAGE_SECTION_OBJECT)Section->Segment);
4027 SectionSegments = ImageSectionObject->Segments;
4028 NrSegments = ImageSectionObject->NrSegments;
4029
4030 ASSERT(ImageSectionObject->RefCount > 0);
4031
4032 ImageBase = (ULONG_PTR)*BaseAddress;
4033 if (ImageBase == 0)
4034 {
4035 ImageBase = (ULONG_PTR)ImageSectionObject->BasedAddress;
4036 }
4037
4038 ImageSize = 0;
4039 for (i = 0; i < NrSegments; i++)
4040 {
4041 ULONG_PTR MaxExtent;
4042 MaxExtent = (ULONG_PTR)(SectionSegments[i].Image.VirtualAddress +
4043 SectionSegments[i].Length.QuadPart);
4044 ImageSize = max(ImageSize, MaxExtent);
4045 }
4046
4047 ImageSectionObject->ImageInformation.ImageFileSize = (ULONG)ImageSize;
4048
4049 /* Check for an illegal base address */
4050 if (((ImageBase + ImageSize) > (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS) ||
4051 ((ImageBase + ImageSize) < ImageSize))
4052 {
4053 ASSERT(*BaseAddress == NULL);
4054 ImageBase = ALIGN_DOWN_BY((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - ImageSize,
4056 NotAtBase = TRUE;
4057 }
4058 else if (ImageBase != ALIGN_DOWN_BY(ImageBase, MM_VIRTMEM_GRANULARITY))
4059 {
4060 ASSERT(*BaseAddress == NULL);
4061 ImageBase = ALIGN_DOWN_BY(ImageBase, MM_VIRTMEM_GRANULARITY);
4062 NotAtBase = TRUE;
4063 }
4064
4065 /* Check there is enough space to map the section at that point. */
4067 PAGE_ROUND_UP(ImageSize)) != NULL)
4068 {
4069 /* Fail if the user requested a fixed base address. */
4070 if ((*BaseAddress) != NULL)
4071 {
4074 }
4075 /* Otherwise find a gap to map the image. */
4077 if (ImageBase == 0)
4078 {
4081 }
4082 /* Remember that we loaded image at a different base address */
4083 NotAtBase = TRUE;
4084 }
4085
4086 for (i = 0; i < NrSegments; i++)
4087 {
4088 PVOID SBaseAddress = (PVOID)
4089 ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress);
4090 MmLockSectionSegment(&SectionSegments[i]);
4092 TRUE,
4093 &SectionSegments[i],
4094 &SBaseAddress,
4095 SectionSegments[i].Length.QuadPart,
4096 SectionSegments[i].Protection,
4097 0,
4098 0);
4099 MmUnlockSectionSegment(&SectionSegments[i]);
4100 if (!NT_SUCCESS(Status))
4101 {
4102 /* roll-back */
4103 while (i--)
4104 {
4105 SBaseAddress = ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress);
4106 MmLockSectionSegment(&SectionSegments[i]);
4107 MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
4108 MmUnlockSectionSegment(&SectionSegments[i]);
4109 }
4110
4112 return Status;
4113 }
4114 }
4115
4116 *BaseAddress = (PVOID)ImageBase;
4117 *ViewSize = ImageSize;
4118
4119 DPRINT("Mapped %p for section pointer %p\n", ImageSectionObject, ImageSectionObject->FileObject->SectionObjectPointer);
4120
4121 /* One more map */
4122 InterlockedIncrement(&ImageSectionObject->MapCount);
4123 }
4124 else
4125 {
4127 LONGLONG ViewOffset;
4128
4129 ASSERT(Segment->RefCount > 0);
4130
4131 /* check for write access */
4134 {
4137 }
4138 /* check for read access */
4141 {
4144 }
4145 /* check for execute access */
4148 {
4151 }
4152
4153 if (SectionOffset == NULL)
4154 {
4155 ViewOffset = 0;
4156 }
4157 else
4158 {
4159 ViewOffset = SectionOffset->QuadPart;
4160 }
4161
4162 if ((ViewOffset % PAGE_SIZE) != 0)
4163 {
4166 }
4167
4168 if ((*ViewSize) == 0)
4169 {
4170 (*ViewSize) = Section->SizeOfSection.QuadPart - ViewOffset;
4171 }
4172 else if ((ExGetPreviousMode() == UserMode) &&
4173 (((*ViewSize)+ViewOffset) > Section->SizeOfSection.QuadPart) &&
4174 (!Section->u.Flags.Reserve))
4175 {
4176 /* Dubious */
4177 (*ViewSize) = MIN(Section->SizeOfSection.QuadPart - ViewOffset, SIZE_T_MAX - PAGE_SIZE);
4178 }
4179
4181
4184 FALSE,
4185 Segment,
4187 *ViewSize,
4188 Protect,
4189 ViewOffset,
4192 if (!NT_SUCCESS(Status))
4193 {
4195 return Status;
4196 }
4197 }
4198
4200
4201 if (NotAtBase)
4203 else
4205
4206 return Status;
4207}
4208
4209/*
4210 * @unimplemented
4211 */
4212BOOLEAN
4213NTAPI
4217{
4218 BOOLEAN Ret;
4220
4221 /* Check whether an ImageSectionObject exists */
4222 if (SectionObjectPointer->ImageSectionObject != NULL)
4223 {
4224 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4225 return FALSE;
4226 }
4227
4229 if (!Segment)
4230 {
4231 /* There is no data section. It's fine to do anything. */
4232 return TRUE;
4233 }
4234
4236 if ((Segment->SectionCount == 0) ||
4237 ((Segment->SectionCount == 1) && (SectionObjectPointer->SharedCacheMap != NULL)))
4238 {
4239 /* If the cache is the only one holding a reference to the segment, then it's fine to resize */
4240 Ret = TRUE;
4241 }
4242 else if (NewFileSize != NULL)
4243 {
4244 /* We can't shrink, but we can extend */
4245 Ret = NewFileSize->QuadPart >= Segment->RawLength.QuadPart;
4246#if DBG
4247 if (!Ret)
4248 {
4249 DPRINT1("Cannot truncate data: New Size %I64d, Segment Size %I64d\n", NewFileSize->QuadPart, Segment->RawLength.QuadPart);
4250 }
4251#endif
4252 }
4253 else
4254 {
4255 DPRINT1("ERROR: File can't be truncated because it has references held to its data section\n");
4256 Ret = FALSE;
4257 }
4258
4260 MmDereferenceSegment(Segment);
4261
4262 DPRINT("FIXME: didn't check for outstanding write probes\n");
4263
4264 return Ret;
4265}
4266
4267static
4268BOOLEAN
4270{
4272
4274
4275 /* Loop over all entries */
4276 for (PageTable = RtlEnumerateGenericTable(&Segment->PageTable, TRUE);
4277 PageTable != NULL;
4279 {
4280 for (ULONG i = 0; i < _countof(PageTable->PageEntries); i++)
4281 {
4282 ULONG_PTR Entry = PageTable->PageEntries[i];
4284
4285 if (!Entry)
4286 continue;
4287
4289 {
4290 /* I/O ongoing or swap entry. Someone mapped this file as we were not looking */
4292 return FALSE;
4293 }
4294
4295 /* Regular entry */
4298
4299 /* Properly remove using the used API */
4300 Offset.QuadPart = PageTable->FileOffset.QuadPart + (i << PAGE_SHIFT);
4303 }
4304 }
4305
4307
4308 return TRUE;
4309}
4310
4311/*
4312 * @implemented
4313 */
4317{
4318 switch(FlushType)
4319 {
4320 case MmFlushForDelete:
4321 {
4322 /*
4323 * FIXME: Check for outstanding write probes on Data section.
4324 * How do we do that ?
4325 */
4326 }
4327 /* Fall-through */
4328 case MmFlushForWrite:
4329 {
4330 KIRQL OldIrql = MiAcquirePfnLock();
4331 PMM_IMAGE_SECTION_OBJECT ImageSectionObject = SectionObjectPointer->ImageSectionObject;
4332
4333 DPRINT("Deleting or modifying %p\n", SectionObjectPointer);
4334
4335 /* Wait for concurrent creation or deletion of image to be done */
4336 ImageSectionObject = SectionObjectPointer->ImageSectionObject;
4337 while (ImageSectionObject && (ImageSectionObject->SegFlags & (MM_SEGMENT_INCREATE | MM_SEGMENT_INDELETE)))
4338 {
4339 MiReleasePfnLock(OldIrql);
4341 OldIrql = MiAcquirePfnLock();
4342 ImageSectionObject = SectionObjectPointer->ImageSectionObject;
4343 }
4344
4345 if (!ImageSectionObject)
4346 {
4347 DPRINT("No image section object. Accepting\n");
4348 /* Nothing to do */
4349 MiReleasePfnLock(OldIrql);
4350 return TRUE;
4351 }
4352
4353 /* Do we have open sections or mappings on it ? */
4354 if ((ImageSectionObject->SectionCount) || (ImageSectionObject->MapCount))
4355 {
4356 /* We do. No way to delete it */
4357 MiReleasePfnLock(OldIrql);
4358 DPRINT("Denying. There are mappings open\n");
4359 return FALSE;
4360 }
4361
4362 /* There are no sections open on it, but we must still have pages around. Discard everything */<