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