25c46a4290adf46b437e016edf7ce811bb63b284
[reactos.git] / reactos / ntoskrnl / mm / section.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (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., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: section.c,v 1.165 2004/10/09 12:17:54 gvg Exp $
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/section.c
23 * PURPOSE: Implements section objects
24 * PROGRAMMER: David Welch (welch@mcmail.com)
25 * UPDATE HISTORY:
26 * Created 22/05/98
27 */
28
29 /* INCLUDES *****************************************************************/
30
31 #include <ntoskrnl.h>
32 #define NDEBUG
33 #include <internal/debug.h>
34
35 /* TYPES *********************************************************************/
36
37 typedef struct
38 {
39 PSECTION_OBJECT Section;
40 PMM_SECTION_SEGMENT Segment;
41 ULONG Offset;
42 BOOLEAN WasDirty;
43 BOOLEAN Private;
44 }
45 MM_SECTION_PAGEOUT_CONTEXT;
46
47 /* GLOBALS *******************************************************************/
48
49 POBJECT_TYPE EXPORTED MmSectionObjectType = NULL;
50
51 static GENERIC_MAPPING MmpSectionMapping = {
52 STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
53 STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
54 STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
55 SECTION_ALL_ACCESS};
56
57 #define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
58 #define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
59
60 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
61 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
62 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
63 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
64 #define MAX_SHARE_COUNT 0x7FF
65 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
66 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
67 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
68
69 /* FUNCTIONS *****************************************************************/
70
71 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
72
73 /*
74 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
75 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
76 * RETURNS: Status of the wait.
77 */
78 static NTSTATUS
79 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp)
80 {
81 LARGE_INTEGER Timeout;
82 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
83
84 Timeout.QuadPart = -100000000LL; // 10 sec
85 #else
86
87 Timeout.QuadPart = -100000000; // 10 sec
88 #endif
89
90 return KeWaitForSingleObject(&PageOp->CompletionEvent, 0, KernelMode, FALSE, &Timeout);
91 }
92
93
94 /*
95 * FUNCTION: Sets the page op completion event and releases the page op.
96 * ARGUMENTS: PMM_PAGEOP.
97 * RETURNS: In shorter time than it takes you to even read this
98 * description, so don't even think about geting a mug of coffee.
99 */
100 static void
101 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp)
102 {
103 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
104 MmReleasePageOp(PageOp);
105 }
106
107
108 /*
109 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
110 * ARGUMENTS: PFILE_OBJECT to wait for.
111 * RETURNS: Status of the wait.
112 */
113 static NTSTATUS
114 MmspWaitForFileLock(PFILE_OBJECT File)
115 {
116 return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
117 }
118
119
120 VOID
121 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment)
122 {
123 ULONG i;
124 if (Segment->Length > NR_SECTION_PAGE_TABLES * PAGE_SIZE)
125 {
126 for (i = 0; i < NR_SECTION_PAGE_TABLES; i++)
127 {
128 if (Segment->PageDirectory.PageTables[i] != NULL)
129 {
130 ExFreePool(Segment->PageDirectory.PageTables[i]);
131 }
132 }
133 }
134 }
135
136 VOID
137 MmFreeSectionSegments(PFILE_OBJECT FileObject)
138 {
139 if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
140 {
141 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
142 PMM_SECTION_SEGMENT SectionSegments;
143 ULONG NrSegments;
144 ULONG i;
145
146 ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject;
147 NrSegments = ImageSectionObject->NrSegments;
148 SectionSegments = ImageSectionObject->Segments;
149 for (i = 0; i < NrSegments; i++)
150 {
151 if (SectionSegments[i].ReferenceCount != 0)
152 {
153 DPRINT1("Image segment %d still referenced (was %d)\n", i,
154 SectionSegments[i].ReferenceCount);
155 KEBUGCHECK(0);
156 }
157 MmFreePageTablesSectionSegment(&SectionSegments[i]);
158 }
159 ExFreePool(ImageSectionObject);
160 FileObject->SectionObjectPointer->ImageSectionObject = NULL;
161 }
162 if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
163 {
164 PMM_SECTION_SEGMENT Segment;
165
166 Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
167 DataSectionObject;
168
169 if (Segment->ReferenceCount != 0)
170 {
171 DPRINT1("Data segment still referenced\n");
172 KEBUGCHECK(0);
173 }
174 MmFreePageTablesSectionSegment(Segment);
175 ExFreePool(Segment);
176 FileObject->SectionObjectPointer->DataSectionObject = NULL;
177 }
178 }
179
180 VOID
181 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment)
182 {
183 ExAcquireFastMutex(&Segment->Lock);
184 }
185
186 VOID
187 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment)
188 {
189 ExReleaseFastMutex(&Segment->Lock);
190 }
191
192 VOID
193 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
194 ULONG Offset,
195 ULONG Entry)
196 {
197 PSECTION_PAGE_TABLE Table;
198 ULONG DirectoryOffset;
199 ULONG TableOffset;
200
201 if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
202 {
203 Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
204 }
205 else
206 {
207 DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
208 Table = Segment->PageDirectory.PageTables[DirectoryOffset];
209 if (Table == NULL)
210 {
211 Table =
212 Segment->PageDirectory.PageTables[DirectoryOffset] =
213 ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_PAGE_TABLE),
214 TAG_SECTION_PAGE_TABLE);
215 if (Table == NULL)
216 {
217 KEBUGCHECK(0);
218 }
219 memset(Table, 0, sizeof(SECTION_PAGE_TABLE));
220 DPRINT("Table %x\n", Table);
221 }
222 }
223 TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
224 Table->Entry[TableOffset] = Entry;
225 }
226
227
228 ULONG
229 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
230 ULONG Offset)
231 {
232 PSECTION_PAGE_TABLE Table;
233 ULONG Entry;
234 ULONG DirectoryOffset;
235 ULONG TableOffset;
236
237 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset);
238
239 if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
240 {
241 Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
242 }
243 else
244 {
245 DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
246 Table = Segment->PageDirectory.PageTables[DirectoryOffset];
247 DPRINT("Table %x\n", Table);
248 if (Table == NULL)
249 {
250 return(0);
251 }
252 }
253 TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
254 Entry = Table->Entry[TableOffset];
255 return(Entry);
256 }
257
258 VOID
259 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
260 ULONG Offset)
261 {
262 ULONG Entry;
263
264 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
265 if (Entry == 0)
266 {
267 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
268 KEBUGCHECK(0);
269 }
270 if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
271 {
272 DPRINT1("Maximum share count reached\n");
273 KEBUGCHECK(0);
274 }
275 if (IS_SWAP_FROM_SSE(Entry))
276 {
277 KEBUGCHECK(0);
278 }
279 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1);
280 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
281 }
282
283 BOOLEAN
284 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
285 PMM_SECTION_SEGMENT Segment,
286 ULONG Offset,
287 BOOLEAN Dirty,
288 BOOLEAN PageOut)
289 {
290 ULONG Entry;
291 BOOLEAN IsDirectMapped = FALSE;
292
293 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
294 if (Entry == 0)
295 {
296 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
297 KEBUGCHECK(0);
298 }
299 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
300 {
301 DPRINT1("Zero share count for unshare\n");
302 KEBUGCHECK(0);
303 }
304 if (IS_SWAP_FROM_SSE(Entry))
305 {
306 KEBUGCHECK(0);
307 }
308 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1);
309 /*
310 * If we reducing the share count of this entry to zero then set the entry
311 * to zero and tell the cache the page is no longer mapped.
312 */
313 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
314 {
315 PFILE_OBJECT FileObject;
316 PBCB Bcb;
317 SWAPENTRY SavedSwapEntry;
318 PFN_TYPE Page;
319 BOOLEAN IsImageSection;
320 ULONG FileOffset;
321
322 FileOffset = Offset + Segment->FileOffset;
323
324 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
325
326 Page = PFN_FROM_SSE(Entry);
327 FileObject = Section->FileObject;
328 if (FileObject != NULL &&
329 !(Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
330 {
331
332 if ((FileOffset % PAGE_SIZE) == 0 &&
333 (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
334 {
335 NTSTATUS Status;
336 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
337 IsDirectMapped = TRUE;
338 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty);
339 if (!NT_SUCCESS(Status))
340 {
341 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
342 KEBUGCHECK(0);
343 }
344 }
345 }
346
347 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
348 if (SavedSwapEntry == 0)
349 {
350 if (!PageOut &&
351 ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
352 (Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED)))
353 {
354 /*
355 * FIXME:
356 * Try to page out this page and set the swap entry
357 * within the section segment. There exist no rmap entry
358 * for this page. The pager thread can't page out a
359 * page without a rmap entry.
360 */
361 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
362 }
363 else
364 {
365 MmSetPageEntrySectionSegment(Segment, Offset, 0);
366 if (!IsDirectMapped)
367 {
368 MmReleasePageMemoryConsumer(MC_USER, Page);
369 }
370 }
371 }
372 else
373 {
374 if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
375 (Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
376 {
377 if (!PageOut)
378 {
379 if (Dirty)
380 {
381 /*
382 * FIXME:
383 * We hold all locks. Nobody can do something with the current
384 * process and the current segment (also not within an other process).
385 */
386 NTSTATUS Status;
387 Status = MmWriteToSwapPage(SavedSwapEntry, Page);
388 if (!NT_SUCCESS(Status))
389 {
390 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status);
391 KEBUGCHECK(0);
392 }
393 }
394 MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry));
395 MmSetSavedSwapEntryPage(Page, 0);
396 }
397 MmReleasePageMemoryConsumer(MC_USER, Page);
398 }
399 else
400 {
401 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
402 KEBUGCHECK(0);
403 }
404 }
405 }
406 else
407 {
408 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
409 }
410 return(SHARE_COUNT_FROM_SSE(Entry) > 0);
411 }
412
413 BOOL MiIsPageFromCache(PMEMORY_AREA MemoryArea,
414 ULONG SegOffset)
415 {
416 if (!(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
417 {
418 PBCB Bcb;
419 PCACHE_SEGMENT CacheSeg;
420 Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap;
421 CacheSeg = CcRosLookupCacheSegment(Bcb, SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset);
422 if (CacheSeg)
423 {
424 CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE);
425 return TRUE;
426 }
427 }
428 return FALSE;
429 }
430
431 NTSTATUS
432 MiReadPage(PMEMORY_AREA MemoryArea,
433 ULONG SegOffset,
434 PPFN_TYPE Page)
435 /*
436 * FUNCTION: Read a page for a section backed memory area.
437 * PARAMETERS:
438 * MemoryArea - Memory area to read the page for.
439 * Offset - Offset of the page to read.
440 * Page - Variable that receives a page contains the read data.
441 */
442 {
443 ULONG BaseOffset;
444 ULONG FileOffset;
445 PVOID BaseAddress;
446 BOOLEAN UptoDate;
447 PCACHE_SEGMENT CacheSeg;
448 PFILE_OBJECT FileObject;
449 NTSTATUS Status;
450 ULONG RawLength;
451 PBCB Bcb;
452 BOOLEAN IsImageSection;
453 ULONG Length;
454
455 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
456 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
457 RawLength = MemoryArea->Data.SectionData.Segment->RawLength;
458 FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset;
459 IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
460
461 assert(Bcb);
462
463 DPRINT("%S %x\n", FileObject->FileName.Buffer, FileOffset);
464
465 /*
466 * If the file system is letting us go directly to the cache and the
467 * memory area was mapped at an offset in the file which is page aligned
468 * then get the related cache segment.
469 */
470 if ((FileOffset % PAGE_SIZE) == 0 &&
471 (SegOffset + PAGE_SIZE <= RawLength || !IsImageSection) &&
472 !(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
473 {
474
475 /*
476 * Get the related cache segment; we use a lower level interface than
477 * filesystems do because it is safe for us to use an offset with a
478 * alignment less than the file system block size.
479 */
480 Status = CcRosGetCacheSegment(Bcb,
481 FileOffset,
482 &BaseOffset,
483 &BaseAddress,
484 &UptoDate,
485 &CacheSeg);
486 if (!NT_SUCCESS(Status))
487 {
488 return(Status);
489 }
490 if (!UptoDate)
491 {
492 /*
493 * If the cache segment isn't up to date then call the file
494 * system to read in the data.
495 */
496 Status = ReadCacheSegment(CacheSeg);
497 if (!NT_SUCCESS(Status))
498 {
499 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
500 return Status;
501 }
502 }
503 /*
504 * Retrieve the page from the cache segment that we actually want.
505 */
506 (*Page) = MmGetPhysicalAddress((char*)BaseAddress +
507 FileOffset - BaseOffset).QuadPart >> PAGE_SHIFT;
508
509 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, TRUE);
510 }
511 else
512 {
513 PVOID PageAddr;
514 ULONG CacheSegOffset;
515 /*
516 * Allocate a page, this is rather complicated by the possibility
517 * we might have to move other things out of memory
518 */
519 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
520 if (!NT_SUCCESS(Status))
521 {
522 return(Status);
523 }
524 Status = CcRosGetCacheSegment(Bcb,
525 FileOffset,
526 &BaseOffset,
527 &BaseAddress,
528 &UptoDate,
529 &CacheSeg);
530 if (!NT_SUCCESS(Status))
531 {
532 return(Status);
533 }
534 if (!UptoDate)
535 {
536 /*
537 * If the cache segment isn't up to date then call the file
538 * system to read in the data.
539 */
540 Status = ReadCacheSegment(CacheSeg);
541 if (!NT_SUCCESS(Status))
542 {
543 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
544 return Status;
545 }
546 }
547 PageAddr = ExAllocatePageWithPhysPage(*Page);
548 CacheSegOffset = BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset;
549 Length = RawLength - SegOffset;
550 if (Length <= CacheSegOffset && Length <= PAGE_SIZE)
551 {
552 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, Length);
553 }
554 else if (CacheSegOffset >= PAGE_SIZE)
555 {
556 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, PAGE_SIZE);
557 }
558 else
559 {
560 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, CacheSegOffset);
561 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
562 Status = CcRosGetCacheSegment(Bcb,
563 FileOffset + CacheSegOffset,
564 &BaseOffset,
565 &BaseAddress,
566 &UptoDate,
567 &CacheSeg);
568 if (!NT_SUCCESS(Status))
569 {
570 ExUnmapPage(PageAddr);
571 return(Status);
572 }
573 if (!UptoDate)
574 {
575 /*
576 * If the cache segment isn't up to date then call the file
577 * system to read in the data.
578 */
579 Status = ReadCacheSegment(CacheSeg);
580 if (!NT_SUCCESS(Status))
581 {
582 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
583 ExUnmapPage(PageAddr);
584 return Status;
585 }
586 }
587 if (Length < PAGE_SIZE)
588 {
589 memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, Length - CacheSegOffset);
590 }
591 else
592 {
593 memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, PAGE_SIZE - CacheSegOffset);
594 }
595 }
596 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
597 ExUnmapPage(PageAddr);
598 }
599 return(STATUS_SUCCESS);
600 }
601
602 NTSTATUS
603 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
604 MEMORY_AREA* MemoryArea,
605 PVOID Address,
606 BOOLEAN Locked)
607 {
608 ULONG Offset;
609 PFN_TYPE Page;
610 NTSTATUS Status;
611 ULONG PAddress;
612 PSECTION_OBJECT Section;
613 PMM_SECTION_SEGMENT Segment;
614 ULONG Entry;
615 ULONG Entry1;
616 ULONG Attributes;
617 PMM_PAGEOP PageOp;
618 PMM_REGION Region;
619 BOOL HasSwapEntry;
620
621 /*
622 * There is a window between taking the page fault and locking the
623 * address space when another thread could load the page so we check
624 * that.
625 */
626 if (MmIsPagePresent(AddressSpace->Process, Address))
627 {
628 if (Locked)
629 {
630 MmLockPage(MmGetPfnForProcess(AddressSpace->Process, Address));
631 }
632 return(STATUS_SUCCESS);
633 }
634
635 PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
636 Offset = PAddress - (ULONG)MemoryArea->BaseAddress;
637
638 Segment = MemoryArea->Data.SectionData.Segment;
639 Section = MemoryArea->Data.SectionData.Section;
640 Region = MmFindRegion(MemoryArea->BaseAddress,
641 &MemoryArea->Data.SectionData.RegionListHead,
642 Address, NULL);
643 /*
644 * Lock the segment
645 */
646 MmLockSectionSegment(Segment);
647
648 /*
649 * Check if this page needs to be mapped COW
650 */
651 if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
652 (Region->Protect == PAGE_READWRITE ||
653 Region->Protect == PAGE_EXECUTE_READWRITE))
654 {
655 Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
656 }
657 else
658 {
659 Attributes = Region->Protect;
660 }
661
662 /*
663 * Get or create a page operation descriptor
664 */
665 PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset, MM_PAGEOP_PAGEIN, FALSE);
666 if (PageOp == NULL)
667 {
668 DPRINT1("MmGetPageOp failed\n");
669 KEBUGCHECK(0);
670 }
671
672 /*
673 * Check if someone else is already handling this fault, if so wait
674 * for them
675 */
676 if (PageOp->Thread != PsGetCurrentThread())
677 {
678 MmUnlockSectionSegment(Segment);
679 MmUnlockAddressSpace(AddressSpace);
680 Status = MmspWaitForPageOpCompletionEvent(PageOp);
681 /*
682 * Check for various strange conditions
683 */
684 if (Status != STATUS_SUCCESS)
685 {
686 DPRINT1("Failed to wait for page op, status = %x\n", Status);
687 KEBUGCHECK(0);
688 }
689 if (PageOp->Status == STATUS_PENDING)
690 {
691 DPRINT1("Woke for page op before completion\n");
692 KEBUGCHECK(0);
693 }
694 MmLockAddressSpace(AddressSpace);
695 /*
696 * If this wasn't a pagein then restart the operation
697 */
698 if (PageOp->OpType != MM_PAGEOP_PAGEIN)
699 {
700 MmspCompleteAndReleasePageOp(PageOp);
701 DPRINT("Address 0x%.8X\n", Address);
702 return(STATUS_MM_RESTART_OPERATION);
703 }
704
705 /*
706 * If the thread handling this fault has failed then we don't retry
707 */
708 if (!NT_SUCCESS(PageOp->Status))
709 {
710 Status = PageOp->Status;
711 MmspCompleteAndReleasePageOp(PageOp);
712 DPRINT("Address 0x%.8X\n", Address);
713 return(Status);
714 }
715 MmLockSectionSegment(Segment);
716 /*
717 * If the completed fault was for another address space then set the
718 * page in this one.
719 */
720 if (!MmIsPagePresent(AddressSpace->Process, Address))
721 {
722 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
723 HasSwapEntry = MmIsPageSwapEntry(AddressSpace->Process, (PVOID)PAddress);
724
725 if (PAGE_FROM_SSE(Entry) == 0 || HasSwapEntry)
726 {
727 /*
728 * The page was a private page in another or in our address space
729 */
730 MmUnlockSectionSegment(Segment);
731 MmspCompleteAndReleasePageOp(PageOp);
732 return(STATUS_MM_RESTART_OPERATION);
733 }
734
735 Page = PFN_FROM_SSE(Entry);
736
737 MmSharePageEntrySectionSegment(Segment, Offset);
738
739 Status = MmCreateVirtualMapping(MemoryArea->Process,
740 Address,
741 Attributes,
742 &Page,
743 1);
744 if (!NT_SUCCESS(Status))
745 {
746 DbgPrint("Unable to create virtual mapping\n");
747 KEBUGCHECK(0);
748 }
749 MmInsertRmap(Page, MemoryArea->Process, (PVOID)PAddress);
750 }
751 if (Locked)
752 {
753 MmLockPage(Page);
754 }
755 MmUnlockSectionSegment(Segment);
756 PageOp->Status = STATUS_SUCCESS;
757 MmspCompleteAndReleasePageOp(PageOp);
758 DPRINT("Address 0x%.8X\n", Address);
759 return(STATUS_SUCCESS);
760 }
761
762 HasSwapEntry = MmIsPageSwapEntry(AddressSpace->Process, (PVOID)PAddress);
763 if (HasSwapEntry)
764 {
765 /*
766 * Must be private page we have swapped out.
767 */
768 SWAPENTRY SwapEntry;
769
770 /*
771 * Sanity check
772 */
773 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
774 {
775 DPRINT1("Found a swaped out private page in a pagefile section.\n");
776 KEBUGCHECK(0);
777 }
778
779 MmUnlockSectionSegment(Segment);
780 MmDeletePageFileMapping(AddressSpace->Process, (PVOID)PAddress, &SwapEntry);
781
782 MmUnlockAddressSpace(AddressSpace);
783 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
784 if (!NT_SUCCESS(Status))
785 {
786 KEBUGCHECK(0);
787 }
788
789 Status = MmReadFromSwapPage(SwapEntry, Page);
790 if (!NT_SUCCESS(Status))
791 {
792 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
793 KEBUGCHECK(0);
794 }
795 MmLockAddressSpace(AddressSpace);
796 Status = MmCreateVirtualMapping(AddressSpace->Process,
797 Address,
798 Region->Protect,
799 &Page,
800 1);
801 if (!NT_SUCCESS(Status))
802 {
803 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
804 KEBUGCHECK(0);
805 return(Status);
806 }
807
808 /*
809 * Store the swap entry for later use.
810 */
811 MmSetSavedSwapEntryPage(Page, SwapEntry);
812
813 /*
814 * Add the page to the process's working set
815 */
816 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
817
818 /*
819 * Finish the operation
820 */
821 if (Locked)
822 {
823 MmLockPage(Page);
824 }
825 PageOp->Status = STATUS_SUCCESS;
826 MmspCompleteAndReleasePageOp(PageOp);
827 DPRINT("Address 0x%.8X\n", Address);
828 return(STATUS_SUCCESS);
829 }
830
831 /*
832 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
833 */
834 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
835 {
836 MmUnlockSectionSegment(Segment);
837 /*
838 * Just map the desired physical page
839 */
840 Page = (Offset + MemoryArea->Data.SectionData.ViewOffset) >> PAGE_SHIFT;
841 Status = MmCreateVirtualMapping(AddressSpace->Process,
842 Address,
843 Region->Protect,
844 &Page,
845 1);
846 if (!NT_SUCCESS(Status))
847 {
848 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
849 KEBUGCHECK(0);
850 return(Status);
851 }
852 /*
853 * Don't add an rmap entry since the page mapped could be for
854 * anything.
855 */
856 if (Locked)
857 {
858 MmLockPage(Page);
859 }
860
861 /*
862 * Cleanup and release locks
863 */
864 PageOp->Status = STATUS_SUCCESS;
865 MmspCompleteAndReleasePageOp(PageOp);
866 DPRINT("Address 0x%.8X\n", Address);
867 return(STATUS_SUCCESS);
868 }
869
870 /*
871 * Map anonymous memory for BSS sections
872 */
873 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS)
874 {
875 MmUnlockSectionSegment(Segment);
876 Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
877 if (!NT_SUCCESS(Status))
878 {
879 MmUnlockAddressSpace(AddressSpace);
880 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
881 MmLockAddressSpace(AddressSpace);
882 }
883 if (!NT_SUCCESS(Status))
884 {
885 KEBUGCHECK(0);
886 }
887 Status = MmCreateVirtualMapping(AddressSpace->Process,
888 Address,
889 Region->Protect,
890 &Page,
891 1);
892 if (!NT_SUCCESS(Status))
893 {
894 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
895 KEBUGCHECK(0);
896 return(Status);
897 }
898 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
899 if (Locked)
900 {
901 MmLockPage(Page);
902 }
903
904 /*
905 * Cleanup and release locks
906 */
907 PageOp->Status = STATUS_SUCCESS;
908 MmspCompleteAndReleasePageOp(PageOp);
909 DPRINT("Address 0x%.8X\n", Address);
910 return(STATUS_SUCCESS);
911 }
912
913 /*
914 * Get the entry corresponding to the offset within the section
915 */
916 Offset += MemoryArea->Data.SectionData.ViewOffset;
917 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
918
919 if (Entry == 0)
920 {
921 /*
922 * If the entry is zero (and it can't change because we have
923 * locked the segment) then we need to load the page.
924 */
925
926 /*
927 * Release all our locks and read in the page from disk
928 */
929 MmUnlockSectionSegment(Segment);
930 MmUnlockAddressSpace(AddressSpace);
931
932 if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
933 (Offset >= PAGE_ROUND_UP(Segment->RawLength) && Section->AllocationAttributes & SEC_IMAGE))
934 {
935 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
936 if (!NT_SUCCESS(Status))
937 {
938 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
939 }
940 }
941 else
942 {
943 Status = MiReadPage(MemoryArea, Offset, &Page);
944 if (!NT_SUCCESS(Status))
945 {
946 DPRINT1("MiReadPage failed (Status %x)\n", Status);
947 }
948 }
949 if (!NT_SUCCESS(Status))
950 {
951 /*
952 * FIXME: What do we know in this case?
953 */
954 /*
955 * Cleanup and release locks
956 */
957 MmLockAddressSpace(AddressSpace);
958 PageOp->Status = Status;
959 MmspCompleteAndReleasePageOp(PageOp);
960 DPRINT("Address 0x%.8X\n", Address);
961 return(Status);
962 }
963 /*
964 * Relock the address space and segment
965 */
966 MmLockAddressSpace(AddressSpace);
967 MmLockSectionSegment(Segment);
968
969 /*
970 * Check the entry. No one should change the status of a page
971 * that has a pending page-in.
972 */
973 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
974 if (Entry != Entry1)
975 {
976 DbgPrint("Someone changed ppte entry while we slept\n");
977 KEBUGCHECK(0);
978 }
979
980 /*
981 * Mark the offset within the section as having valid, in-memory
982 * data
983 */
984 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
985 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
986 MmUnlockSectionSegment(Segment);
987
988 Status = MmCreateVirtualMapping(AddressSpace->Process,
989 Address,
990 Attributes,
991 &Page,
992 1);
993 if (!NT_SUCCESS(Status))
994 {
995 DbgPrint("Unable to create virtual mapping\n");
996 KEBUGCHECK(0);
997 }
998 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
999
1000 if (Locked)
1001 {
1002 MmLockPage(Page);
1003 }
1004 PageOp->Status = STATUS_SUCCESS;
1005 MmspCompleteAndReleasePageOp(PageOp);
1006 DPRINT("Address 0x%.8X\n", Address);
1007 return(STATUS_SUCCESS);
1008 }
1009 else if (IS_SWAP_FROM_SSE(Entry))
1010 {
1011 SWAPENTRY SwapEntry;
1012
1013 SwapEntry = SWAPENTRY_FROM_SSE(Entry);
1014
1015 /*
1016 * Release all our locks and read in the page from disk
1017 */
1018 MmUnlockSectionSegment(Segment);
1019
1020 MmUnlockAddressSpace(AddressSpace);
1021
1022 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1023 if (!NT_SUCCESS(Status))
1024 {
1025 KEBUGCHECK(0);
1026 }
1027
1028 Status = MmReadFromSwapPage(SwapEntry, Page);
1029 if (!NT_SUCCESS(Status))
1030 {
1031 KEBUGCHECK(0);
1032 }
1033
1034 /*
1035 * Relock the address space and segment
1036 */
1037 MmLockAddressSpace(AddressSpace);
1038 MmLockSectionSegment(Segment);
1039
1040 /*
1041 * Check the entry. No one should change the status of a page
1042 * that has a pending page-in.
1043 */
1044 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
1045 if (Entry != Entry1)
1046 {
1047 DbgPrint("Someone changed ppte entry while we slept\n");
1048 KEBUGCHECK(0);
1049 }
1050
1051 /*
1052 * Mark the offset within the section as having valid, in-memory
1053 * data
1054 */
1055 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1056 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
1057 MmUnlockSectionSegment(Segment);
1058
1059 /*
1060 * Save the swap entry.
1061 */
1062 MmSetSavedSwapEntryPage(Page, SwapEntry);
1063 Status = MmCreateVirtualMapping(AddressSpace->Process,
1064 Address,
1065 Region->Protect,
1066 &Page,
1067 1);
1068 if (!NT_SUCCESS(Status))
1069 {
1070 DbgPrint("Unable to create virtual mapping\n");
1071 KEBUGCHECK(0);
1072 }
1073 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
1074 if (Locked)
1075 {
1076 MmLockPage(Page);
1077 }
1078 PageOp->Status = STATUS_SUCCESS;
1079 MmspCompleteAndReleasePageOp(PageOp);
1080 DPRINT("Address 0x%.8X\n", Address);
1081 return(STATUS_SUCCESS);
1082 }
1083 else
1084 {
1085 /*
1086 * If the section offset is already in-memory and valid then just
1087 * take another reference to the page
1088 */
1089
1090 Page = PFN_FROM_SSE(Entry);
1091
1092 MmSharePageEntrySectionSegment(Segment, Offset);
1093 MmUnlockSectionSegment(Segment);
1094
1095 Status = MmCreateVirtualMapping(AddressSpace->Process,
1096 Address,
1097 Attributes,
1098 &Page,
1099 1);
1100 if (!NT_SUCCESS(Status))
1101 {
1102 DbgPrint("Unable to create virtual mapping\n");
1103 KEBUGCHECK(0);
1104 }
1105 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
1106 if (Locked)
1107 {
1108 MmLockPage(Page);
1109 }
1110 PageOp->Status = STATUS_SUCCESS;
1111 MmspCompleteAndReleasePageOp(PageOp);
1112 DPRINT("Address 0x%.8X\n", Address);
1113 return(STATUS_SUCCESS);
1114 }
1115 }
1116
1117 NTSTATUS
1118 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
1119 MEMORY_AREA* MemoryArea,
1120 PVOID Address,
1121 BOOLEAN Locked)
1122 {
1123 PMM_SECTION_SEGMENT Segment;
1124 PSECTION_OBJECT Section;
1125 PFN_TYPE OldPage;
1126 PFN_TYPE NewPage;
1127 PVOID NewAddress;
1128 NTSTATUS Status;
1129 ULONG PAddress;
1130 ULONG Offset;
1131 PMM_PAGEOP PageOp;
1132 PMM_REGION Region;
1133 ULONG Entry;
1134
1135 /*
1136 * Check if the page has been paged out or has already been set readwrite
1137 */
1138 if (!MmIsPagePresent(AddressSpace->Process, Address) ||
1139 MmGetPageProtect(AddressSpace->Process, Address) & PAGE_READWRITE)
1140 {
1141 DPRINT("Address 0x%.8X\n", Address);
1142 return(STATUS_SUCCESS);
1143 }
1144
1145 /*
1146 * Find the offset of the page
1147 */
1148 PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
1149 Offset = PAddress - (ULONG)MemoryArea->BaseAddress;
1150
1151 Segment = MemoryArea->Data.SectionData.Segment;
1152 Section = MemoryArea->Data.SectionData.Section;
1153 Region = MmFindRegion(MemoryArea->BaseAddress,
1154 &MemoryArea->Data.SectionData.RegionListHead,
1155 Address, NULL);
1156 /*
1157 * Lock the segment
1158 */
1159 MmLockSectionSegment(Segment);
1160
1161 OldPage = MmGetPfnForProcess(NULL, Address);
1162 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1163
1164 MmUnlockSectionSegment(Segment);
1165
1166 /*
1167 * Check if we are doing COW
1168 */
1169 if (!((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1170 (Region->Protect == PAGE_READWRITE ||
1171 Region->Protect == PAGE_EXECUTE_READWRITE)))
1172 {
1173 DPRINT("Address 0x%.8X\n", Address);
1174 return(STATUS_UNSUCCESSFUL);
1175 }
1176
1177 if (IS_SWAP_FROM_SSE(Entry) ||
1178 PFN_FROM_SSE(Entry) != OldPage)
1179 {
1180 /* This is a private page. We must only change the page protection. */
1181 MmSetPageProtect(AddressSpace->Process, (PVOID)PAddress, Region->Protect);
1182 return(STATUS_SUCCESS);
1183 }
1184
1185 /*
1186 * Get or create a pageop
1187 */
1188 PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset,
1189 MM_PAGEOP_ACCESSFAULT, FALSE);
1190 if (PageOp == NULL)
1191 {
1192 DPRINT1("MmGetPageOp failed\n");
1193 KEBUGCHECK(0);
1194 }
1195
1196 /*
1197 * Wait for any other operations to complete
1198 */
1199 if (PageOp->Thread != PsGetCurrentThread())
1200 {
1201 MmUnlockAddressSpace(AddressSpace);
1202 Status = MmspWaitForPageOpCompletionEvent(PageOp);
1203 /*
1204 * Check for various strange conditions
1205 */
1206 if (Status == STATUS_TIMEOUT)
1207 {
1208 DPRINT1("Failed to wait for page op, status = %x\n", Status);
1209 KEBUGCHECK(0);
1210 }
1211 if (PageOp->Status == STATUS_PENDING)
1212 {
1213 DPRINT1("Woke for page op before completion\n");
1214 KEBUGCHECK(0);
1215 }
1216 /*
1217 * Restart the operation
1218 */
1219 MmLockAddressSpace(AddressSpace);
1220 MmspCompleteAndReleasePageOp(PageOp);
1221 DPRINT("Address 0x%.8X\n", Address);
1222 return(STATUS_MM_RESTART_OPERATION);
1223 }
1224
1225 /*
1226 * Release locks now we have the pageop
1227 */
1228 MmUnlockAddressSpace(AddressSpace);
1229
1230 /*
1231 * Allocate a page
1232 */
1233 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1234 if (!NT_SUCCESS(Status))
1235 {
1236 KEBUGCHECK(0);
1237 }
1238
1239 /*
1240 * Copy the old page
1241 */
1242
1243 NewAddress = ExAllocatePageWithPhysPage(NewPage);
1244 memcpy(NewAddress, (PVOID)PAddress, PAGE_SIZE);
1245 ExUnmapPage(NewAddress);
1246
1247 /*
1248 * Delete the old entry.
1249 */
1250 MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
1251
1252 /*
1253 * Set the PTE to point to the new page
1254 */
1255 MmLockAddressSpace(AddressSpace);
1256 Status = MmCreateVirtualMapping(AddressSpace->Process,
1257 Address,
1258 Region->Protect,
1259 &NewPage,
1260 1);
1261 if (!NT_SUCCESS(Status))
1262 {
1263 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1264 KEBUGCHECK(0);
1265 return(Status);
1266 }
1267 MmInsertRmap(NewPage, AddressSpace->Process, (PVOID)PAddress);
1268 if (!NT_SUCCESS(Status))
1269 {
1270 DbgPrint("Unable to create virtual mapping\n");
1271 KEBUGCHECK(0);
1272 }
1273 if (Locked)
1274 {
1275 MmLockPage(NewPage);
1276 MmUnlockPage(OldPage);
1277 }
1278
1279 /*
1280 * Unshare the old page.
1281 */
1282 MmDeleteRmap(OldPage, AddressSpace->Process, (PVOID)PAddress);
1283 MmLockSectionSegment(Segment);
1284 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE, FALSE);
1285 MmUnlockSectionSegment(Segment);
1286
1287 PageOp->Status = STATUS_SUCCESS;
1288 MmspCompleteAndReleasePageOp(PageOp);
1289 DPRINT("Address 0x%.8X\n", Address);
1290 return(STATUS_SUCCESS);
1291 }
1292
1293 VOID
1294 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
1295 {
1296 MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1297 BOOL WasDirty;
1298 PFN_TYPE Page;
1299
1300 PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1301 MmDeleteVirtualMapping(Process,
1302 Address,
1303 FALSE,
1304 &WasDirty,
1305 &Page);
1306 if (WasDirty)
1307 {
1308 PageOutContext->WasDirty = TRUE;
1309 }
1310 if (!PageOutContext->Private)
1311 {
1312 MmUnsharePageEntrySectionSegment(PageOutContext->Section,
1313 PageOutContext->Segment,
1314 PageOutContext->Offset,
1315 PageOutContext->WasDirty,
1316 TRUE);
1317 }
1318 else
1319 {
1320 MmReleasePageMemoryConsumer(MC_USER, Page);
1321 }
1322
1323 DPRINT("PhysicalAddress %I64x, Address %x\n", Page, Address);
1324 }
1325
1326 NTSTATUS
1327 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
1328 MEMORY_AREA* MemoryArea,
1329 PVOID Address,
1330 PMM_PAGEOP PageOp)
1331 {
1332 PFN_TYPE Page;
1333 MM_SECTION_PAGEOUT_CONTEXT Context;
1334 SWAPENTRY SwapEntry;
1335 ULONG Entry;
1336 ULONG FileOffset;
1337 NTSTATUS Status;
1338 PFILE_OBJECT FileObject;
1339 PBCB Bcb = NULL;
1340 BOOLEAN DirectMapped;
1341 BOOLEAN IsImageSection;
1342
1343 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1344
1345 /*
1346 * Get the segment and section.
1347 */
1348 Context.Segment = MemoryArea->Data.SectionData.Segment;
1349 Context.Section = MemoryArea->Data.SectionData.Section;
1350
1351 Context.Offset = (ULONG)((char*)Address - (ULONG)MemoryArea->BaseAddress);
1352 FileOffset = Context.Offset + Context.Segment->FileOffset;
1353
1354 IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1355
1356 FileObject = Context.Section->FileObject;
1357 DirectMapped = FALSE;
1358 if (FileObject != NULL &&
1359 !(Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
1360 {
1361 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1362
1363 /*
1364 * If the file system is letting us go directly to the cache and the
1365 * memory area was mapped at an offset in the file which is page aligned
1366 * then note this is a direct mapped page.
1367 */
1368 if ((FileOffset % PAGE_SIZE) == 0 &&
1369 (Context.Offset + PAGE_SIZE <= Context.Segment->RawLength || !IsImageSection))
1370 {
1371 DirectMapped = TRUE;
1372 }
1373 }
1374
1375
1376 /*
1377 * This should never happen since mappings of physical memory are never
1378 * placed in the rmap lists.
1379 */
1380 if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1381 {
1382 DPRINT1("Trying to page out from physical memory section address 0x%X "
1383 "process %d\n", Address,
1384 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
1385 KEBUGCHECK(0);
1386 }
1387
1388 /*
1389 * Get the section segment entry and the physical address.
1390 */
1391 Entry = MmGetPageEntrySectionSegment(Context.Segment, Context.Offset);
1392 if (!MmIsPagePresent(AddressSpace->Process, Address))
1393 {
1394 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1395 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
1396 KEBUGCHECK(0);
1397 }
1398 Page = MmGetPfnForProcess(AddressSpace->Process, Address);
1399 SwapEntry = MmGetSavedSwapEntryPage(Page);
1400
1401 /*
1402 * Prepare the context structure for the rmap delete call.
1403 */
1404 Context.WasDirty = FALSE;
1405 if (Context.Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1406 IS_SWAP_FROM_SSE(Entry) ||
1407 PFN_FROM_SSE(Entry) != Page)
1408 {
1409 Context.Private = TRUE;
1410 }
1411 else
1412 {
1413 Context.Private = FALSE;
1414 }
1415
1416 /*
1417 * Take an additional reference to the page or the cache segment.
1418 */
1419 if (DirectMapped && !Context.Private)
1420 {
1421 if(!MiIsPageFromCache(MemoryArea, Context.Offset))
1422 {
1423 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1424 KEBUGCHECK(0);
1425 }
1426 }
1427 else
1428 {
1429 MmReferencePage(Page);
1430 }
1431
1432 MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping);
1433
1434 /*
1435 * If this wasn't a private page then we should have reduced the entry to
1436 * zero by deleting all the rmaps.
1437 */
1438 if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0)
1439 {
1440 if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
1441 !(Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
1442 {
1443 KEBUGCHECK(0);
1444 }
1445 }
1446
1447 /*
1448 * If the page wasn't dirty then we can just free it as for a readonly page.
1449 * Since we unmapped all the mappings above we know it will not suddenly
1450 * become dirty.
1451 * If the page is from a pagefile section and has no swap entry,
1452 * we can't free the page at this point.
1453 */
1454 SwapEntry = MmGetSavedSwapEntryPage(Page);
1455 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT)
1456 {
1457 if (Context.Private)
1458 {
1459 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1460 Context.WasDirty ? "dirty" : "clean", Address);
1461 KEBUGCHECK(0);
1462 }
1463 if (!Context.WasDirty && SwapEntry != 0)
1464 {
1465 MmSetSavedSwapEntryPage(Page, 0);
1466 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
1467 MmReleasePageMemoryConsumer(MC_USER, Page);
1468 PageOp->Status = STATUS_SUCCESS;
1469 MmspCompleteAndReleasePageOp(PageOp);
1470 return(STATUS_SUCCESS);
1471 }
1472 }
1473 else if (Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED)
1474 {
1475 if (Context.Private)
1476 {
1477 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1478 Context.WasDirty ? "dirty" : "clean", Address);
1479 KEBUGCHECK(0);
1480 }
1481 if (!Context.WasDirty || SwapEntry != 0)
1482 {
1483 MmSetSavedSwapEntryPage(Page, 0);
1484 if (SwapEntry != 0)
1485 {
1486 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
1487 }
1488 MmReleasePageMemoryConsumer(MC_USER, Page);
1489 PageOp->Status = STATUS_SUCCESS;
1490 MmspCompleteAndReleasePageOp(PageOp);
1491 return(STATUS_SUCCESS);
1492 }
1493 }
1494 else if (!Context.Private && DirectMapped)
1495 {
1496 if (SwapEntry != 0)
1497 {
1498 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1499 Address);
1500 KEBUGCHECK(0);
1501 }
1502 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
1503 if (!NT_SUCCESS(Status))
1504 {
1505 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
1506 KEBUGCHECK(0);
1507 }
1508 PageOp->Status = STATUS_SUCCESS;
1509 MmspCompleteAndReleasePageOp(PageOp);
1510 return(STATUS_SUCCESS);
1511 }
1512 else if (!Context.WasDirty && !DirectMapped && !Context.Private)
1513 {
1514 if (SwapEntry != 0)
1515 {
1516 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1517 Address);
1518 KEBUGCHECK(0);
1519 }
1520 MmReleasePageMemoryConsumer(MC_USER, Page);
1521 PageOp->Status = STATUS_SUCCESS;
1522 MmspCompleteAndReleasePageOp(PageOp);
1523 return(STATUS_SUCCESS);
1524 }
1525 else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
1526 {
1527 MmSetSavedSwapEntryPage(Page, 0);
1528 Status = MmCreatePageFileMapping(AddressSpace->Process,
1529 Address,
1530 SwapEntry);
1531 if (!NT_SUCCESS(Status))
1532 {
1533 KEBUGCHECK(0);
1534 }
1535 MmReleasePageMemoryConsumer(MC_USER, Page);
1536 PageOp->Status = STATUS_SUCCESS;
1537 MmspCompleteAndReleasePageOp(PageOp);
1538 return(STATUS_SUCCESS);
1539 }
1540
1541 /*
1542 * If necessary, allocate an entry in the paging file for this page
1543 */
1544 if (SwapEntry == 0)
1545 {
1546 SwapEntry = MmAllocSwapPage();
1547 if (SwapEntry == 0)
1548 {
1549 MmShowOutOfSpaceMessagePagingFile();
1550
1551 /*
1552 * For private pages restore the old mappings.
1553 */
1554 if (Context.Private)
1555 {
1556 Status = MmCreateVirtualMapping(MemoryArea->Process,
1557 Address,
1558 MemoryArea->Attributes,
1559 &Page,
1560 1);
1561 MmSetDirtyPage(MemoryArea->Process, Address);
1562 MmInsertRmap(Page,
1563 MemoryArea->Process,
1564 Address);
1565 }
1566 else
1567 {
1568 /*
1569 * For non-private pages if the page wasn't direct mapped then
1570 * set it back into the section segment entry so we don't loose
1571 * our copy. Otherwise it will be handled by the cache manager.
1572 */
1573 Status = MmCreateVirtualMapping(MemoryArea->Process,
1574 Address,
1575 MemoryArea->Attributes,
1576 &Page,
1577 1);
1578 MmSetDirtyPage(MemoryArea->Process, Address);
1579 MmInsertRmap(Page,
1580 MemoryArea->Process,
1581 Address);
1582 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1583 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1584 }
1585 PageOp->Status = STATUS_UNSUCCESSFUL;
1586 MmspCompleteAndReleasePageOp(PageOp);
1587 return(STATUS_PAGEFILE_QUOTA);
1588 }
1589 }
1590
1591 /*
1592 * Write the page to the pagefile
1593 */
1594 Status = MmWriteToSwapPage(SwapEntry, Page);
1595 if (!NT_SUCCESS(Status))
1596 {
1597 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1598 Status);
1599 /*
1600 * As above: undo our actions.
1601 * FIXME: Also free the swap page.
1602 */
1603 if (Context.Private)
1604 {
1605 Status = MmCreateVirtualMapping(MemoryArea->Process,
1606 Address,
1607 MemoryArea->Attributes,
1608 &Page,
1609 1);
1610 MmSetDirtyPage(MemoryArea->Process, Address);
1611 MmInsertRmap(Page,
1612 MemoryArea->Process,
1613 Address);
1614 }
1615 else
1616 {
1617 Status = MmCreateVirtualMapping(MemoryArea->Process,
1618 Address,
1619 MemoryArea->Attributes,
1620 &Page,
1621 1);
1622 MmSetDirtyPage(MemoryArea->Process, Address);
1623 MmInsertRmap(Page,
1624 MemoryArea->Process,
1625 Address);
1626 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1627 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1628 }
1629 PageOp->Status = STATUS_UNSUCCESSFUL;
1630 MmspCompleteAndReleasePageOp(PageOp);
1631 return(STATUS_UNSUCCESSFUL);
1632 }
1633
1634 /*
1635 * Otherwise we have succeeded.
1636 */
1637 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
1638 MmSetSavedSwapEntryPage(Page, 0);
1639 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
1640 Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED)
1641 {
1642 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
1643 }
1644 else
1645 {
1646 MmReleasePageMemoryConsumer(MC_USER, Page);
1647 }
1648
1649 if (Context.Private)
1650 {
1651 Status = MmCreatePageFileMapping(MemoryArea->Process,
1652 Address,
1653 SwapEntry);
1654 if (!NT_SUCCESS(Status))
1655 {
1656 KEBUGCHECK(0);
1657 }
1658 }
1659 else
1660 {
1661 Entry = MAKE_SWAP_SSE(SwapEntry);
1662 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1663 }
1664
1665 PageOp->Status = STATUS_SUCCESS;
1666 MmspCompleteAndReleasePageOp(PageOp);
1667 return(STATUS_SUCCESS);
1668 }
1669
1670 NTSTATUS
1671 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
1672 PMEMORY_AREA MemoryArea,
1673 PVOID Address,
1674 PMM_PAGEOP PageOp)
1675 {
1676 ULONG Offset;
1677 PSECTION_OBJECT Section;
1678 PMM_SECTION_SEGMENT Segment;
1679 PFN_TYPE Page;
1680 SWAPENTRY SwapEntry;
1681 ULONG Entry;
1682 BOOLEAN Private;
1683 NTSTATUS Status;
1684 PFILE_OBJECT FileObject;
1685 PBCB Bcb = NULL;
1686 BOOLEAN DirectMapped;
1687 BOOLEAN IsImageSection;
1688
1689 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1690
1691 Offset = (ULONG)((char*)Address - (ULONG)MemoryArea->BaseAddress);
1692
1693 /*
1694 * Get the segment and section.
1695 */
1696 Segment = MemoryArea->Data.SectionData.Segment;
1697 Section = MemoryArea->Data.SectionData.Section;
1698 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1699
1700 FileObject = Section->FileObject;
1701 DirectMapped = FALSE;
1702 if (FileObject != NULL &&
1703 !(Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
1704 {
1705 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1706
1707 /*
1708 * If the file system is letting us go directly to the cache and the
1709 * memory area was mapped at an offset in the file which is page aligned
1710 * then note this is a direct mapped page.
1711 */
1712 if ((Offset + MemoryArea->Data.SectionData.ViewOffset % PAGE_SIZE) == 0 &&
1713 (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
1714 {
1715 DirectMapped = TRUE;
1716 }
1717 }
1718
1719 /*
1720 * This should never happen since mappings of physical memory are never
1721 * placed in the rmap lists.
1722 */
1723 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1724 {
1725 DPRINT1("Trying to write back page from physical memory mapped at %X "
1726 "process %d\n", Address,
1727 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
1728 KEBUGCHECK(0);
1729 }
1730
1731 /*
1732 * Get the section segment entry and the physical address.
1733 */
1734 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1735 if (!MmIsPagePresent(AddressSpace->Process, Address))
1736 {
1737 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1738 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
1739 KEBUGCHECK(0);
1740 }
1741 Page = MmGetPfnForProcess(AddressSpace->Process, Address);
1742 SwapEntry = MmGetSavedSwapEntryPage(Page);
1743
1744 /*
1745 * Check for a private (COWed) page.
1746 */
1747 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1748 IS_SWAP_FROM_SSE(Entry) ||
1749 PFN_FROM_SSE(Entry) != Page)
1750 {
1751 Private = TRUE;
1752 }
1753 else
1754 {
1755 Private = FALSE;
1756 }
1757
1758 /*
1759 * Speculatively set all mappings of the page to clean.
1760 */
1761 MmSetCleanAllRmaps(Page);
1762
1763 /*
1764 * If this page was direct mapped from the cache then the cache manager
1765 * will take care of writing it back to disk.
1766 */
1767 if (DirectMapped && !Private)
1768 {
1769 assert(SwapEntry == 0);
1770 CcRosMarkDirtyCacheSegment(Bcb, Offset + MemoryArea->Data.SectionData.ViewOffset);
1771 PageOp->Status = STATUS_SUCCESS;
1772 MmspCompleteAndReleasePageOp(PageOp);
1773 return(STATUS_SUCCESS);
1774 }
1775
1776 /*
1777 * If necessary, allocate an entry in the paging file for this page
1778 */
1779 if (SwapEntry == 0)
1780 {
1781 SwapEntry = MmAllocSwapPage();
1782 if (SwapEntry == 0)
1783 {
1784 MmSetDirtyAllRmaps(Page);
1785 PageOp->Status = STATUS_UNSUCCESSFUL;
1786 MmspCompleteAndReleasePageOp(PageOp);
1787 return(STATUS_PAGEFILE_QUOTA);
1788 }
1789 MmSetSavedSwapEntryPage(Page, SwapEntry);
1790 }
1791
1792 /*
1793 * Write the page to the pagefile
1794 */
1795 Status = MmWriteToSwapPage(SwapEntry, Page);
1796 if (!NT_SUCCESS(Status))
1797 {
1798 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1799 Status);
1800 MmSetDirtyAllRmaps(Page);
1801 PageOp->Status = STATUS_UNSUCCESSFUL;
1802 MmspCompleteAndReleasePageOp(PageOp);
1803 return(STATUS_UNSUCCESSFUL);
1804 }
1805
1806 /*
1807 * Otherwise we have succeeded.
1808 */
1809 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
1810 PageOp->Status = STATUS_SUCCESS;
1811 MmspCompleteAndReleasePageOp(PageOp);
1812 return(STATUS_SUCCESS);
1813 }
1814
1815 VOID STATIC
1816 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace,
1817 PVOID BaseAddress,
1818 ULONG RegionSize,
1819 ULONG OldType,
1820 ULONG OldProtect,
1821 ULONG NewType,
1822 ULONG NewProtect)
1823 {
1824 PMEMORY_AREA MemoryArea;
1825 PMM_SECTION_SEGMENT Segment;
1826 BOOL DoCOW = FALSE;
1827 ULONG i;
1828
1829 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, BaseAddress);
1830 Segment = MemoryArea->Data.SectionData.Segment;
1831
1832 if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1833 (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
1834 {
1835 DoCOW = TRUE;
1836 }
1837
1838 if (OldProtect != NewProtect)
1839 {
1840 for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
1841 {
1842 PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
1843 ULONG Protect = NewProtect;
1844
1845 /*
1846 * If we doing COW for this segment then check if the page is
1847 * already private.
1848 */
1849 if (DoCOW && MmIsPagePresent(AddressSpace->Process, Address))
1850 {
1851 ULONG Offset;
1852 ULONG Entry;
1853 PFN_TYPE Page;
1854
1855 Offset = (ULONG)Address - (ULONG)MemoryArea->BaseAddress;
1856 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1857 Page = MmGetPfnForProcess(AddressSpace->Process, Address);
1858
1859 Protect = PAGE_READONLY;
1860 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1861 IS_SWAP_FROM_SSE(Entry) ||
1862 PFN_FROM_SSE(Entry) != Page)
1863 {
1864 Protect = NewProtect;
1865 }
1866 }
1867
1868 if (MmIsPagePresent(AddressSpace->Process, Address))
1869 {
1870 MmSetPageProtect(AddressSpace->Process, Address,
1871 Protect);
1872 }
1873 }
1874 }
1875 }
1876
1877 NTSTATUS
1878 MmProtectSectionView(PMADDRESS_SPACE AddressSpace,
1879 PMEMORY_AREA MemoryArea,
1880 PVOID BaseAddress,
1881 ULONG Length,
1882 ULONG Protect,
1883 PULONG OldProtect)
1884 {
1885 PMM_REGION Region;
1886 NTSTATUS Status;
1887
1888 Length =
1889 min(Length, (ULONG) ((char*)MemoryArea->BaseAddress + MemoryArea->Length - (char*)BaseAddress));
1890 Region = MmFindRegion(MemoryArea->BaseAddress,
1891 &MemoryArea->Data.SectionData.RegionListHead,
1892 BaseAddress, NULL);
1893 *OldProtect = Region->Protect;
1894 Status = MmAlterRegion(AddressSpace, MemoryArea->BaseAddress,
1895 &MemoryArea->Data.SectionData.RegionListHead,
1896 BaseAddress, Length, Region->Type, Protect,
1897 MmAlterViewAttributes);
1898
1899 return(Status);
1900 }
1901
1902 NTSTATUS STDCALL
1903 MmQuerySectionView(PMEMORY_AREA MemoryArea,
1904 PVOID Address,
1905 PMEMORY_BASIC_INFORMATION Info,
1906 PULONG ResultLength)
1907 {
1908 PMM_REGION Region;
1909 PVOID RegionBaseAddress;
1910 PSECTION_OBJECT Section;
1911 PLIST_ENTRY CurrentEntry;
1912 PMEMORY_AREA CurrentMArea;
1913 KIRQL oldIrql;
1914
1915 Region = MmFindRegion(MemoryArea->BaseAddress,
1916 &MemoryArea->Data.SectionData.RegionListHead,
1917 Address, &RegionBaseAddress);
1918 if (Region == NULL)
1919 {
1920 return STATUS_UNSUCCESSFUL;
1921 }
1922 Section = MemoryArea->Data.SectionData.Section;
1923 if (Section->AllocationAttributes & SEC_IMAGE)
1924 {
1925 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
1926 CurrentEntry = Section->ViewListHead.Flink;
1927 Info->AllocationBase = NULL;
1928 while (CurrentEntry != &Section->ViewListHead)
1929 {
1930 CurrentMArea = CONTAINING_RECORD(CurrentEntry, MEMORY_AREA, Data.SectionData.ViewListEntry);
1931 CurrentEntry = CurrentEntry->Flink;
1932 if (Info->AllocationBase == NULL)
1933 {
1934 Info->AllocationBase = CurrentMArea->BaseAddress;
1935 }
1936 else if (CurrentMArea->BaseAddress < Info->AllocationBase)
1937 {
1938 Info->AllocationBase = CurrentMArea->BaseAddress;
1939 }
1940 }
1941 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
1942 Info->BaseAddress = RegionBaseAddress;
1943 Info->AllocationProtect = MemoryArea->Attributes;
1944 Info->Type = MEM_IMAGE;
1945 }
1946 else
1947 {
1948 Info->BaseAddress = RegionBaseAddress;
1949 Info->AllocationBase = MemoryArea->BaseAddress;
1950 Info->AllocationProtect = MemoryArea->Attributes;
1951 Info->Type = MEM_MAPPED;
1952 }
1953 Info->RegionSize = PAGE_ROUND_UP(MemoryArea->Length);
1954 Info->State = MEM_COMMIT;
1955 Info->Protect = Region->Protect;
1956
1957 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
1958 return(STATUS_SUCCESS);
1959 }
1960
1961 VOID
1962 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
1963 {
1964 ULONG Length;
1965 ULONG Offset;
1966 ULONG Entry;
1967 ULONG SavedSwapEntry;
1968 PFN_TYPE Page;
1969
1970 Page = 0;
1971
1972 Length = PAGE_ROUND_UP(Segment->Length);
1973 for (Offset = 0; Offset < Length; Offset += PAGE_SIZE)
1974 {
1975 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1976 if (Entry)
1977 {
1978 if (IS_SWAP_FROM_SSE(Entry))
1979 {
1980 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
1981 }
1982 else
1983 {
1984 Page = PFN_FROM_SSE(Entry);
1985 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
1986 if (SavedSwapEntry != 0)
1987 {
1988 MmSetSavedSwapEntryPage(Page, 0);
1989 MmFreeSwapPage(SavedSwapEntry);
1990 }
1991 MmReleasePageMemoryConsumer(MC_USER, Page);
1992 }
1993 MmSetPageEntrySectionSegment(Segment, Offset, 0);
1994 }
1995 }
1996 }
1997
1998 VOID STDCALL
1999 MmpDeleteSection(PVOID ObjectBody)
2000 {
2001 PSECTION_OBJECT Section = (PSECTION_OBJECT)ObjectBody;
2002
2003 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
2004 if (Section->AllocationAttributes & SEC_IMAGE)
2005 {
2006 ULONG i;
2007 ULONG NrSegments;
2008 ULONG RefCount;
2009 PMM_SECTION_SEGMENT SectionSegments;
2010
2011 /*
2012 * NOTE: Section->ImageSection can be NULL for short time
2013 * during the section creating. If we fail for some reason
2014 * until the image section is properly initialized we shouldn't
2015 * process further here.
2016 */
2017 if (Section->ImageSection == NULL)
2018 return;
2019
2020 SectionSegments = Section->ImageSection->Segments;
2021 NrSegments = Section->ImageSection->NrSegments;
2022
2023 for (i = 0; i < NrSegments; i++)
2024 {
2025 if (SectionSegments[i].Characteristics & IMAGE_SECTION_CHAR_SHARED)
2026 {
2027 MmLockSectionSegment(&SectionSegments[i]);
2028 }
2029 RefCount = InterlockedDecrement((LONG *)&SectionSegments[i].ReferenceCount);
2030 if (SectionSegments[i].Characteristics & IMAGE_SECTION_CHAR_SHARED)
2031 {
2032 if (RefCount == 0)
2033 {
2034 MmpFreePageFileSegment(&SectionSegments[i]);
2035 }
2036 MmUnlockSectionSegment(&SectionSegments[i]);
2037 }
2038 }
2039 }
2040 else
2041 {
2042 /*
2043 * NOTE: Section->Segment can be NULL for short time
2044 * during the section creating.
2045 */
2046 if (Section->Segment == NULL)
2047 return;
2048
2049 if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
2050 {
2051 MmpFreePageFileSegment(Section->Segment);
2052 MmFreePageTablesSectionSegment(Section->Segment);
2053 ExFreePool(Section->Segment);
2054 Section->Segment = NULL;
2055 }
2056 else
2057 {
2058 InterlockedDecrement((LONG *)&Section->Segment->ReferenceCount);
2059 }
2060 }
2061 if (Section->FileObject != NULL)
2062 {
2063 CcRosDereferenceCache(Section->FileObject);
2064 ObDereferenceObject(Section->FileObject);
2065 Section->FileObject = NULL;
2066 }
2067 }
2068
2069 VOID STDCALL
2070 MmpCloseSection(PVOID ObjectBody,
2071 ULONG HandleCount)
2072 {
2073 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2074 ObjectBody, HandleCount, ObGetObjectPointerCount(ObjectBody));
2075 }
2076
2077 NTSTATUS STDCALL
2078 MmpCreateSection(PVOID ObjectBody,
2079 PVOID Parent,
2080 PWSTR RemainingPath,
2081 POBJECT_ATTRIBUTES ObjectAttributes)
2082 {
2083 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2084 ObjectBody, Parent, RemainingPath);
2085
2086 if (RemainingPath == NULL)
2087 {
2088 return(STATUS_SUCCESS);
2089 }
2090
2091 if (wcschr(RemainingPath+1, L'\\') != NULL)
2092 {
2093 return(STATUS_UNSUCCESSFUL);
2094 }
2095 return(STATUS_SUCCESS);
2096 }
2097
2098 NTSTATUS INIT_FUNCTION
2099 MmCreatePhysicalMemorySection(VOID)
2100 {
2101 PSECTION_OBJECT PhysSection;
2102 NTSTATUS Status;
2103 OBJECT_ATTRIBUTES Obj;
2104 UNICODE_STRING Name = ROS_STRING_INITIALIZER(L"\\Device\\PhysicalMemory");
2105 LARGE_INTEGER SectionSize;
2106
2107 /*
2108 * Create the section mapping physical memory
2109 */
2110 SectionSize.QuadPart = 0xFFFFFFFF;
2111 InitializeObjectAttributes(&Obj,
2112 &Name,
2113 0,
2114 NULL,
2115 NULL);
2116 Status = MmCreateSection(&PhysSection,
2117 SECTION_ALL_ACCESS,
2118 &Obj,
2119 &SectionSize,
2120 PAGE_EXECUTE_READWRITE,
2121 0,
2122 NULL,
2123 NULL);
2124 if (!NT_SUCCESS(Status))
2125 {
2126 DbgPrint("Failed to create PhysicalMemory section\n");
2127 KEBUGCHECK(0);
2128 }
2129 PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
2130
2131 return(STATUS_SUCCESS);
2132 }
2133
2134 NTSTATUS INIT_FUNCTION
2135 MmInitSectionImplementation(VOID)
2136 {
2137 MmSectionObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
2138
2139 RtlRosInitUnicodeStringFromLiteral(&MmSectionObjectType->TypeName, L"Section");
2140
2141 MmSectionObjectType->Tag = TAG('S', 'E', 'C', 'T');
2142 MmSectionObjectType->TotalObjects = 0;
2143 MmSectionObjectType->TotalHandles = 0;
2144 MmSectionObjectType->MaxObjects = ULONG_MAX;
2145 MmSectionObjectType->MaxHandles = ULONG_MAX;
2146 MmSectionObjectType->PagedPoolCharge = 0;
2147 MmSectionObjectType->NonpagedPoolCharge = sizeof(SECTION_OBJECT);
2148 MmSectionObjectType->Mapping = &MmpSectionMapping;
2149 MmSectionObjectType->Dump = NULL;
2150 MmSectionObjectType->Open = NULL;
2151 MmSectionObjectType->Close = MmpCloseSection;
2152 MmSectionObjectType->Delete = MmpDeleteSection;
2153 MmSectionObjectType->Parse = NULL;
2154 MmSectionObjectType->Security = NULL;
2155 MmSectionObjectType->QueryName = NULL;
2156 MmSectionObjectType->OkayToClose = NULL;
2157 MmSectionObjectType->Create = MmpCreateSection;
2158 MmSectionObjectType->DuplicationNotify = NULL;
2159
2160 /*
2161 * NOTE: Do not register the section object type here because
2162 * the object manager it not initialized yet!
2163 * The section object type will be created in ObInit().
2164 */
2165 ObpCreateTypeObject(MmSectionObjectType);
2166
2167 return(STATUS_SUCCESS);
2168 }
2169
2170 NTSTATUS
2171 MmCreatePageFileSection(PSECTION_OBJECT *SectionObject,
2172 ACCESS_MASK DesiredAccess,
2173 POBJECT_ATTRIBUTES ObjectAttributes,
2174 PLARGE_INTEGER UMaximumSize,
2175 ULONG SectionPageProtection,
2176 ULONG AllocationAttributes)
2177 /*
2178 * Create a section which is backed by the pagefile
2179 */
2180 {
2181 LARGE_INTEGER MaximumSize;
2182 PSECTION_OBJECT Section;
2183 PMM_SECTION_SEGMENT Segment;
2184 NTSTATUS Status;
2185
2186 if (UMaximumSize == NULL)
2187 {
2188 return(STATUS_UNSUCCESSFUL);
2189 }
2190 MaximumSize = *UMaximumSize;
2191
2192 /*
2193 * Create the section
2194 */
2195 Status = ObCreateObject(ExGetPreviousMode(),
2196 MmSectionObjectType,
2197 ObjectAttributes,
2198 ExGetPreviousMode(),
2199 NULL,
2200 sizeof(SECTION_OBJECT),
2201 0,
2202 0,
2203 (PVOID*)(PVOID)&Section);
2204 if (!NT_SUCCESS(Status))
2205 {
2206 return(Status);
2207 }
2208
2209 /*
2210 * Initialize it
2211 */
2212 Section->SectionPageProtection = SectionPageProtection;
2213 Section->AllocationAttributes = AllocationAttributes;
2214 Section->Segment = NULL;
2215 InitializeListHead(&Section->ViewListHead);
2216 KeInitializeSpinLock(&Section->ViewListLock);
2217 Section->FileObject = NULL;
2218 Section->MaximumSize = MaximumSize;
2219 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2220 TAG_MM_SECTION_SEGMENT);
2221 if (Segment == NULL)
2222 {
2223 ObDereferenceObject(Section);
2224 return(STATUS_NO_MEMORY);
2225 }
2226 Section->Segment = Segment;
2227 Segment->ReferenceCount = 1;
2228 ExInitializeFastMutex(&Segment->Lock);
2229 Segment->FileOffset = 0;
2230 Segment->Protection = SectionPageProtection;
2231 Segment->Attributes = AllocationAttributes;
2232 Segment->RawLength = MaximumSize.u.LowPart;
2233 Segment->Length = PAGE_ROUND_UP(MaximumSize.u.LowPart);
2234 Segment->Flags = MM_PAGEFILE_SEGMENT;
2235 Segment->WriteCopy = FALSE;
2236 RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
2237 Segment->VirtualAddress = 0;
2238 Segment->Characteristics = 0;
2239 *SectionObject = Section;
2240 return(STATUS_SUCCESS);
2241 }
2242
2243
2244 NTSTATUS
2245 MmCreateDataFileSection(PSECTION_OBJECT *SectionObject,
2246 ACCESS_MASK DesiredAccess,
2247 POBJECT_ATTRIBUTES ObjectAttributes,
2248 PLARGE_INTEGER UMaximumSize,
2249 ULONG SectionPageProtection,
2250 ULONG AllocationAttributes,
2251 HANDLE FileHandle)
2252 /*
2253 * Create a section backed by a data file
2254 */
2255 {
2256 PSECTION_OBJECT Section;
2257 NTSTATUS Status;
2258 LARGE_INTEGER MaximumSize;
2259 PFILE_OBJECT FileObject;
2260 PMM_SECTION_SEGMENT Segment;
2261 ULONG FileAccess;
2262 IO_STATUS_BLOCK Iosb;
2263 LARGE_INTEGER Offset;
2264 CHAR Buffer;
2265 FILE_STANDARD_INFORMATION FileInfo;
2266
2267 /*
2268 * Create the section
2269 */
2270 Status = ObCreateObject(ExGetPreviousMode(),
2271 MmSectionObjectType,
2272 ObjectAttributes,
2273 ExGetPreviousMode(),
2274 NULL,
2275 sizeof(SECTION_OBJECT),
2276 0,
2277 0,
2278 (PVOID*)(PVOID)&Section);
2279 if (!NT_SUCCESS(Status))
2280 {
2281 return(Status);
2282 }
2283
2284 /*
2285 * Initialize it
2286 */
2287 Section->SectionPageProtection = SectionPageProtection;
2288 Section->AllocationAttributes = AllocationAttributes;
2289 Section->Segment = NULL;
2290 InitializeListHead(&Section->ViewListHead);
2291 KeInitializeSpinLock(&Section->ViewListLock);
2292
2293 /*
2294 * Check file access required
2295 */
2296 if (SectionPageProtection & PAGE_READWRITE ||
2297 SectionPageProtection & PAGE_EXECUTE_READWRITE)
2298 {
2299 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2300 }
2301 else
2302 {
2303 FileAccess = FILE_READ_DATA;
2304 }
2305
2306 /*
2307 * Reference the file handle
2308 */
2309 Status = ObReferenceObjectByHandle(FileHandle,
2310 FileAccess,
2311 IoFileObjectType,
2312 UserMode,
2313 (PVOID*)(PVOID)&FileObject,
2314 NULL);
2315 if (!NT_SUCCESS(Status))
2316 {
2317 ObDereferenceObject(Section);
2318 return(Status);
2319 }
2320
2321 /*
2322 * FIXME: This is propably not entirely correct. We can't look into
2323 * the standard FCB header because it might not be initialized yet
2324 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2325 * standard file information is filled on first request).
2326 */
2327 Status = NtQueryInformationFile(FileHandle,
2328 &Iosb,
2329 &FileInfo,
2330 sizeof(FILE_STANDARD_INFORMATION),
2331 FileStandardInformation);
2332 if (!NT_SUCCESS(Status))
2333 {
2334 ObDereferenceObject(Section);
2335 ObDereferenceObject(FileObject);
2336 return Status;
2337 }
2338
2339 /*
2340 * FIXME: Revise this once a locking order for file size changes is
2341 * decided
2342 */
2343 if (UMaximumSize != NULL)
2344 {
2345 MaximumSize = *UMaximumSize;
2346 }
2347 else
2348 {
2349 MaximumSize = FileInfo.EndOfFile;
2350 /* Mapping zero-sized files isn't allowed. */
2351 if (MaximumSize.QuadPart == 0)
2352 {
2353 ObDereferenceObject(Section);
2354 ObDereferenceObject(FileObject);
2355 return STATUS_FILE_INVALID;
2356 }
2357 }
2358
2359 if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart)
2360 {
2361 Status = NtSetInformationFile(FileHandle,
2362 &Iosb,
2363 &MaximumSize,
2364 sizeof(LARGE_INTEGER),
2365 FileAllocationInformation);
2366 if (!NT_SUCCESS(Status))
2367 {
2368 ObDereferenceObject(Section);
2369 ObDereferenceObject(FileObject);
2370 return(STATUS_SECTION_NOT_EXTENDED);
2371 }
2372 }
2373
2374 if (FileObject->SectionObjectPointer == NULL ||
2375 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
2376 {
2377 /*
2378 * Read a bit so caching is initiated for the file object.
2379 * This is only needed because MiReadPage currently cannot
2380 * handle non-cached streams.
2381 */
2382 Offset.QuadPart = 0;
2383 Status = ZwReadFile(FileHandle,
2384 NULL,
2385 NULL,
2386 NULL,
2387 &Iosb,
2388 &Buffer,
2389 sizeof (Buffer),
2390 &Offset,
2391 0);
2392 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
2393 {
2394 ObDereferenceObject(Section);
2395 ObDereferenceObject(FileObject);
2396 return(Status);
2397 }
2398 if (FileObject->SectionObjectPointer == NULL ||
2399 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
2400 {
2401 /* FIXME: handle this situation */
2402 ObDereferenceObject(Section);
2403 ObDereferenceObject(FileObject);
2404 return STATUS_INVALID_PARAMETER;
2405 }
2406 }
2407
2408 /*
2409 * Lock the file
2410 */
2411 Status = MmspWaitForFileLock(FileObject);
2412 if (Status != STATUS_SUCCESS)
2413 {
2414 ObDereferenceObject(Section);
2415 ObDereferenceObject(FileObject);
2416 return(Status);
2417 }
2418
2419 /*
2420 * If this file hasn't been mapped as a data file before then allocate a
2421 * section segment to describe the data file mapping
2422 */
2423 if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
2424 {
2425 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2426 TAG_MM_SECTION_SEGMENT);
2427 if (Segment == NULL)
2428 {
2429 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2430 ObDereferenceObject(Section);
2431 ObDereferenceObject(FileObject);
2432 return(STATUS_NO_MEMORY);
2433 }
2434 Section->Segment = Segment;
2435 Segment->ReferenceCount = 1;
2436 ExInitializeFastMutex(&Segment->Lock);
2437 /*
2438 * Set the lock before assigning the segment to the file object
2439 */
2440 ExAcquireFastMutex(&Segment->Lock);
2441 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
2442
2443 Segment->FileOffset = 0;
2444 Segment->Protection = SectionPageProtection;
2445 Segment->Attributes = 0;
2446 Segment->Flags = MM_DATAFILE_SEGMENT;
2447 Segment->Characteristics = 0;
2448 Segment->WriteCopy = FALSE;
2449 if (AllocationAttributes & SEC_RESERVE)
2450 {
2451 Segment->Length = Segment->RawLength = 0;
2452 }
2453 else
2454 {
2455 Segment->RawLength = MaximumSize.u.LowPart;
2456 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
2457 }
2458 Segment->VirtualAddress = NULL;
2459 RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
2460 }
2461 else
2462 {
2463 /*
2464 * If the file is already mapped as a data file then we may need
2465 * to extend it
2466 */
2467 Segment =
2468 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
2469 DataSectionObject;
2470 Section->Segment = Segment;
2471 InterlockedIncrement((PLONG)&Segment->ReferenceCount);
2472 MmLockSectionSegment(Segment);
2473
2474 if (MaximumSize.u.LowPart > Segment->RawLength &&
2475 !(AllocationAttributes & SEC_RESERVE))
2476 {
2477 Segment->RawLength = MaximumSize.u.LowPart;
2478 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
2479 }
2480 }
2481 MmUnlockSectionSegment(Segment);
2482 Section->FileObject = FileObject;
2483 Section->MaximumSize = MaximumSize;
2484 CcRosReferenceCache(FileObject);
2485 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2486 *SectionObject = Section;
2487 return(STATUS_SUCCESS);
2488 }
2489
2490 static ULONG SectionCharacteristicsToProtect[16] =
2491 {
2492 PAGE_NOACCESS, // 0 = NONE
2493 PAGE_NOACCESS, // 1 = SHARED
2494 PAGE_EXECUTE, // 2 = EXECUTABLE
2495 PAGE_EXECUTE, // 3 = EXECUTABLE, SHARED
2496 PAGE_READONLY, // 4 = READABLE
2497 PAGE_READONLY, // 5 = READABLE, SHARED
2498 PAGE_EXECUTE_READ, // 6 = READABLE, EXECUTABLE
2499 PAGE_EXECUTE_READ, // 7 = READABLE, EXECUTABLE, SHARED
2500 PAGE_READWRITE, // 8 = WRITABLE
2501 PAGE_READWRITE, // 9 = WRITABLE, SHARED
2502 PAGE_EXECUTE_READWRITE, // 10 = WRITABLE, EXECUTABLE
2503 PAGE_EXECUTE_READWRITE, // 11 = WRITABLE, EXECUTABLE, SHARED
2504 PAGE_READWRITE, // 12 = WRITABLE, READABLE
2505 PAGE_READWRITE, // 13 = WRITABLE, READABLE, SHARED
2506 PAGE_EXECUTE_READWRITE, // 14 = WRITABLE, READABLE, EXECUTABLE,
2507 PAGE_EXECUTE_READWRITE, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2508 };
2509
2510 NTSTATUS
2511 MmCreateImageSection(PSECTION_OBJECT *SectionObject,
2512 ACCESS_MASK DesiredAccess,
2513 POBJECT_ATTRIBUTES ObjectAttributes,
2514 PLARGE_INTEGER UMaximumSize,
2515 ULONG SectionPageProtection,
2516 ULONG AllocationAttributes,
2517 HANDLE FileHandle)
2518 {
2519 PSECTION_OBJECT Section;
2520 NTSTATUS Status;
2521 PFILE_OBJECT FileObject;
2522 IMAGE_DOS_HEADER DosHeader;
2523 IO_STATUS_BLOCK Iosb;
2524 LARGE_INTEGER Offset;
2525 IMAGE_NT_HEADERS PEHeader;
2526 PMM_SECTION_SEGMENT SectionSegments;
2527 ULONG NrSegments;
2528 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
2529 ULONG i;
2530 ULONG Size;
2531 ULONG Characteristics;
2532 ULONG FileAccess = 0;
2533
2534 /*
2535 * Specifying a maximum size is meaningless for an image section
2536 */
2537 if (UMaximumSize != NULL)
2538 {
2539 return(STATUS_INVALID_PARAMETER_4);
2540 }
2541
2542 /*
2543 * Reference the file handle
2544 */
2545 Status = ObReferenceObjectByHandle(FileHandle,
2546 FileAccess,
2547 IoFileObjectType,
2548 UserMode,
2549 (PVOID*)(PVOID)&FileObject,
2550 NULL);
2551 if (!NT_SUCCESS(Status))
2552 {
2553 return Status;
2554 }
2555
2556 /*
2557 * Initialized caching for this file object if previously caching
2558 * was initialized for the same on disk file
2559 */
2560 Status = CcTryToInitializeFileCache(FileObject);
2561
2562 if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
2563 {
2564 PIMAGE_SECTION_HEADER ImageSections;
2565 /*
2566 * Read the dos header and check the DOS signature
2567 */
2568 Offset.QuadPart = 0;
2569 Status = ZwReadFile(FileHandle,
2570 NULL,
2571 NULL,
2572 NULL,
2573 &Iosb,
2574 &DosHeader,
2575 sizeof(DosHeader),
2576 &Offset,
2577 NULL);
2578 if (!NT_SUCCESS(Status))
2579 {
2580 ObDereferenceObject(FileObject);
2581 return(Status);
2582 }
2583
2584 /*
2585 * Check the DOS signature
2586 */
2587 if (Iosb.Information != sizeof(DosHeader) ||
2588 DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
2589 {
2590 ObDereferenceObject(FileObject);
2591 return(STATUS_INVALID_IMAGE_FORMAT);
2592 }
2593
2594 /*
2595 * Read the PE header
2596 */
2597 Offset.QuadPart = DosHeader.e_lfanew;
2598 Status = ZwReadFile(FileHandle,
2599 NULL,
2600 NULL,
2601 NULL,
2602 &Iosb,
2603 &PEHeader,
2604 sizeof(PEHeader),
2605 &Offset,
2606 NULL);
2607 if (!NT_SUCCESS(Status))
2608 {
2609 ObDereferenceObject(FileObject);
2610 return(Status);
2611 }
2612
2613 /*
2614 * Check the signature
2615 */
2616 if (Iosb.Information != sizeof(PEHeader) ||
2617 PEHeader.Signature != IMAGE_NT_SIGNATURE)
2618 {
2619 ObDereferenceObject(FileObject);
2620 return(STATUS_INVALID_IMAGE_FORMAT);
2621 }
2622
2623 /*
2624 * Read in the section headers
2625 */
2626 Offset.QuadPart = DosHeader.e_lfanew + sizeof(PEHeader);
2627 ImageSections = ExAllocatePool(NonPagedPool,
2628 PEHeader.FileHeader.NumberOfSections *
2629 sizeof(IMAGE_SECTION_HEADER));
2630 if (ImageSections == NULL)
2631 {
2632 ObDereferenceObject(FileObject);
2633 return(STATUS_NO_MEMORY);
2634 }
2635
2636 Status = ZwReadFile(FileHandle,
2637 NULL,
2638 NULL,
2639 NULL,
2640 &Iosb,
2641 ImageSections,
2642 PEHeader.FileHeader.NumberOfSections *
2643 sizeof(IMAGE_SECTION_HEADER),
2644 &Offset,
2645 0);
2646 if (!NT_SUCCESS(Status))
2647 {
2648 ObDereferenceObject(FileObject);
2649 ExFreePool(ImageSections);
2650 return(Status);
2651 }
2652 if (Iosb.Information != (PEHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
2653 {
2654 ObDereferenceObject(FileObject);
2655 ExFreePool(ImageSections);
2656 return(STATUS_INVALID_IMAGE_FORMAT);
2657 }
2658
2659 /*
2660 * Create the section
2661 */
2662 Status = ObCreateObject (ExGetPreviousMode(),
2663 MmSectionObjectType,
2664 ObjectAttributes,
2665 ExGetPreviousMode(),
2666 NULL,
2667 sizeof(SECTION_OBJECT),
2668 0,
2669 0,
2670 (PVOID*)(PVOID)&Section);
2671 if (!NT_SUCCESS(Status))
2672 {
2673 ObDereferenceObject(FileObject);
2674 ExFreePool(ImageSections);
2675 return(Status);
2676 }
2677
2678 /*
2679 * Initialize it
2680 */
2681 Section->SectionPageProtection = SectionPageProtection;
2682 Section->AllocationAttributes = AllocationAttributes;
2683 Section->ImageSection = NULL;
2684 InitializeListHead(&Section->ViewListHead);
2685 KeInitializeSpinLock(&Section->ViewListLock);
2686
2687 /*
2688 * Check file access required
2689 */
2690 if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
2691 {
2692 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2693 }
2694 else
2695 {
2696 FileAccess = FILE_READ_DATA;
2697 }
2698
2699 /*
2700 * Lock the file
2701 */
2702 Status = MmspWaitForFileLock(FileObject);
2703 if (Status != STATUS_SUCCESS)
2704 {
2705 ObDereferenceObject(Section);
2706 ObDereferenceObject(FileObject);
2707 ExFreePool(ImageSections);
2708 return(Status);
2709 }
2710
2711 /*
2712 * allocate the section segments to describe the mapping
2713 */
2714 NrSegments = PEHeader.FileHeader.NumberOfSections + 1;
2715 Size = sizeof(MM_IMAGE_SECTION_OBJECT) + sizeof(MM_SECTION_SEGMENT) * NrSegments;
2716 ImageSectionObject = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MM_SECTION_SEGMENT);
2717 if (ImageSectionObject == NULL)
2718 {
2719 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2720 ObDereferenceObject(Section);
2721 ObDereferenceObject(FileObject);
2722 ExFreePool(ImageSections);
2723 return(STATUS_NO_MEMORY);
2724 }
2725 Section->ImageSection = ImageSectionObject;
2726 ImageSectionObject->NrSegments = NrSegments;
2727 ImageSectionObject->ImageBase = (PVOID)PEHeader.OptionalHeader.ImageBase;
2728 ImageSectionObject->EntryPoint = (PVOID)PEHeader.OptionalHeader.AddressOfEntryPoint;
2729 ImageSectionObject->StackReserve = PEHeader.OptionalHeader.SizeOfStackReserve;
2730 ImageSectionObject->StackCommit = PEHeader.OptionalHeader.SizeOfStackCommit;
2731 ImageSectionObject->Subsystem = PEHeader.OptionalHeader.Subsystem;
2732 ImageSectionObject->MinorSubsystemVersion = PEHeader.OptionalHeader.MinorSubsystemVersion;
2733 ImageSectionObject->MajorSubsystemVersion = PEHeader.OptionalHeader.MajorSubsystemVersion;
2734 ImageSectionObject->ImageCharacteristics = PEHeader.FileHeader.Characteristics;
2735 ImageSectionObject->Machine = PEHeader.FileHeader.Machine;
2736 ImageSectionObject->Executable = (PEHeader.OptionalHeader.SizeOfCode != 0);
2737
2738 SectionSegments = ImageSectionObject->Segments;
2739 SectionSegments[0].FileOffset = 0;
2740 SectionSegments[0].Characteristics = IMAGE_SECTION_CHAR_DATA;
2741 SectionSegments[0].Protection = PAGE_READONLY;
2742 SectionSegments[0].RawLength = PAGE_SIZE;
2743 SectionSegments[0].Length = PAGE_SIZE;
2744 SectionSegments[0].Flags = 0;
2745 SectionSegments[0].ReferenceCount = 1;
2746 SectionSegments[0].VirtualAddress = 0;
2747 SectionSegments[0].WriteCopy = TRUE;
2748 SectionSegments[0].Attributes = 0;
2749 ExInitializeFastMutex(&SectionSegments[0].Lock);
2750 RtlZeroMemory(&SectionSegments[0].PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
2751 for (i = 1; i < NrSegments; i++)
2752 {
2753 SectionSegments[i].FileOffset = ImageSections[i-1].PointerToRawData;
2754 SectionSegments[i].Characteristics = ImageSections[i-1].Characteristics;
2755
2756 /*
2757 * Set up the protection and write copy variables.
2758 */
2759 Characteristics = ImageSections[i - 1].Characteristics;
2760 if (Characteristics & (IMAGE_SECTION_CHAR_READABLE|IMAGE_SECTION_CHAR_WRITABLE|IMAGE_SECTION_CHAR_EXECUTABLE))
2761 {
2762 SectionSegments[i].Protection = SectionCharacteristicsToProtect[Characteristics >> 28];
2763 SectionSegments[i].WriteCopy = !(Characteristics & IMAGE_SECTION_CHAR_SHARED);
2764 }
2765 else if (Characteristics & IMAGE_SECTION_CHAR_CODE)
2766 {
2767 SectionSegments[i].Protection = PAGE_EXECUTE_READ;
2768 SectionSegments[i].WriteCopy = TRUE;
2769 }
2770 else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
2771 {
2772 SectionSegments[i].Protection = PAGE_READWRITE;
2773 SectionSegments[i].WriteCopy = TRUE;
2774 }
2775 else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
2776 {
2777 SectionSegments[i].Protection = PAGE_READWRITE;
2778 SectionSegments[i].WriteCopy = TRUE;
2779 }
2780 else
2781 {
2782 SectionSegments[i].Protection = PAGE_NOACCESS;
2783 SectionSegments[i].WriteCopy = TRUE;
2784 }
2785
2786 /*
2787 * Set up the attributes.
2788 */
2789 if (Characteristics & IMAGE_SECTION_CHAR_CODE)
2790 {
2791 SectionSegments[i].Attributes = 0;
2792 }
2793 else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
2794 {
2795 SectionSegments[i].Attributes = 0;
2796 }
2797 else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
2798 {
2799 SectionSegments[i].Attributes = MM_SECTION_SEGMENT_BSS;
2800 }
2801 else
2802 {
2803 SectionSegments[i].Attributes = 0;
2804 }
2805
2806 SectionSegments[i].RawLength = ImageSections[i-1].SizeOfRawData;
2807 if (ImageSections[i-1].Misc.VirtualSize != 0)
2808 {
2809 SectionSegments[i].Length = ImageSections[i-1].Misc.VirtualSize;
2810 }
2811 else
2812 {
2813 SectionSegments[i].Length = ImageSections[i-1].SizeOfRawData;
2814 }
2815 SectionSegments[i].Flags = 0;
2816 SectionSegments[i].ReferenceCount = 1;
2817 SectionSegments[i].VirtualAddress = (PVOID)ImageSections[i-1].VirtualAddress;
2818 ExInitializeFastMutex(&SectionSegments[i].Lock);
2819 RtlZeroMemory(&SectionSegments[i].PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
2820 }
2821 if (0 != InterlockedCompareExchange((PLONG)&FileObject->SectionObjectPointer->ImageSectionObject,
2822 (LONG)ImageSectionObject, 0))
2823 {
2824 /*
2825 * An other thread has initialized the some image in the background
2826 */
2827 ExFreePool(ImageSectionObject);
2828 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
2829 Section->ImageSection = ImageSectionObject;
2830 SectionSegments = ImageSectionObject->Segments;
2831
2832 for (i = 0; i < NrSegments; i++)
2833 {
2834 InterlockedIncrement((LONG *)&SectionSegments[i].ReferenceCount);
2835 }
2836 }
2837 ExFreePool(ImageSections);
2838 }
2839 else
2840 {
2841 /*
2842 * Create the section
2843 */
2844 Status = ObCreateObject (ExGetPreviousMode(),
2845 MmSectionObjectType,
2846 ObjectAttributes,
2847 ExGetPreviousMode(),
2848 NULL,
2849 sizeof(SECTION_OBJECT),
2850 0,
2851 0,
2852 (PVOID*)(PVOID)&Section);
2853 if (!NT_SUCCESS(Status))
2854 {
2855 ObDereferenceObject(FileObject);
2856 return(Status);
2857 }
2858
2859 /*
2860 * Initialize it
2861 */
2862 Section->SectionPageProtection = SectionPageProtection;
2863 Section->AllocationAttributes = AllocationAttributes;
2864 InitializeListHead(&Section->ViewListHead);
2865 KeInitializeSpinLock(&Section->ViewListLock);
2866
2867 /*
2868 * Check file access required
2869 */
2870 if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
2871 {
2872 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2873 }
2874 else
2875 {
2876 FileAccess = FILE_READ_DATA;
2877 }
2878
2879 /*
2880 * Lock the file
2881 */
2882 Status = MmspWaitForFileLock(FileObject);
2883 if (Status != STATUS_SUCCESS)
2884 {
2885 ObDereferenceObject(Section);
2886 ObDereferenceObject(FileObject);
2887 return(Status);
2888 }
2889
2890 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
2891 Section->ImageSection = ImageSectionObject;
2892 SectionSegments = ImageSectionObject->Segments;
2893 NrSegments = ImageSectionObject->NrSegments;
2894
2895 /*
2896 * Otherwise just reference all the section segments
2897 */
2898 for (i = 0; i < NrSegments; i++)
2899 {
2900 InterlockedIncrement((LONG *)&SectionSegments[i].ReferenceCount);
2901 }
2902
2903 }
2904 Section->FileObject = FileObject;
2905 CcRosReferenceCache(FileObject);
2906 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2907 *SectionObject = Section;
2908 return(STATUS_SUCCESS);
2909 }
2910
2911 /*
2912 * @implemented
2913 */
2914 NTSTATUS STDCALL
2915 NtCreateSection (OUT PHANDLE SectionHandle,
2916 IN ACCESS_MASK DesiredAccess,
2917 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
2918 IN PLARGE_INTEGER MaximumSize OPTIONAL,
2919 IN ULONG SectionPageProtection OPTIONAL,
2920 IN ULONG AllocationAttributes,
2921 IN HANDLE FileHandle OPTIONAL)
2922 {
2923 PSECTION_OBJECT SectionObject;
2924 NTSTATUS Status;
2925
2926 /*
2927 * Check the protection
2928 */
2929 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
2930 SectionPageProtection)
2931 {
2932 return(STATUS_INVALID_PAGE_PROTECTION);
2933 }
2934
2935 Status = MmCreateSection(&SectionObject,
2936 DesiredAccess,
2937 ObjectAttributes,
2938 MaximumSize,
2939 SectionPageProtection,
2940 AllocationAttributes,
2941 FileHandle,
2942 NULL);
2943
2944 if (NT_SUCCESS(Status))
2945 {
2946 Status = ObInsertObject ((PVOID)SectionObject,
2947 NULL,
2948 DesiredAccess,
2949 0,
2950 NULL,
2951 SectionHandle);
2952 ObDereferenceObject(SectionObject);
2953 }
2954
2955 return Status;
2956 }
2957
2958
2959 /**********************************************************************
2960 * NAME
2961 * NtOpenSection
2962 *
2963 * DESCRIPTION
2964 *
2965 * ARGUMENTS
2966 * SectionHandle
2967 *
2968 * DesiredAccess
2969 *
2970 * ObjectAttributes
2971 *
2972 * RETURN VALUE
2973 *
2974 * REVISIONS
2975 */
2976 NTSTATUS STDCALL
2977 NtOpenSection(PHANDLE SectionHandle,
2978 ACCESS_MASK DesiredAccess,
2979 POBJECT_ATTRIBUTES ObjectAttributes)
2980 {
2981 NTSTATUS Status;
2982
2983 *SectionHandle = 0;
2984
2985 Status = ObOpenObjectByName(ObjectAttributes,
2986 MmSectionObjectType,
2987 NULL,
2988 UserMode,
2989 DesiredAccess,
2990 NULL,
2991 SectionHandle);
2992
2993 return(Status);
2994 }
2995
2996 NTSTATUS STATIC
2997 MmMapViewOfSegment(PEPROCESS Process,
2998 PMADDRESS_SPACE AddressSpace,
2999 PSECTION_OBJECT Section,
3000 PMM_SECTION_SEGMENT Segment,
3001 PVOID* BaseAddress,
3002 ULONG ViewSize,
3003 ULONG Protect,
3004 ULONG ViewOffset,
3005 BOOL TopDown)
3006 {
3007 PMEMORY_AREA MArea;
3008 NTSTATUS Status;
3009 KIRQL oldIrql;
3010 PHYSICAL_ADDRESS BoundaryAddressMultiple;
3011
3012 BoundaryAddressMultiple.QuadPart = 0;
3013
3014 Status = MmCreateMemoryArea(Process,
3015 AddressSpace,
3016 MEMORY_AREA_SECTION_VIEW,
3017 BaseAddress,
3018 ViewSize,
3019 Protect,
3020 &MArea,
3021 FALSE,
3022 TopDown,
3023 BoundaryAddressMultiple);
3024 if (!NT_SUCCESS(Status))
3025 {
3026 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
3027 (*BaseAddress), (char*)(*BaseAddress) + ViewSize);
3028 return(Status);
3029 }
3030
3031 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
3032 InsertTailList(&Section->ViewListHead,
3033 &MArea->Data.SectionData.ViewListEntry);
3034 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
3035
3036 ObReferenceObjectByPointer((PVOID)Section,
3037 SECTION_MAP_READ,
3038 NULL,
3039 ExGetPreviousMode());
3040 MArea->Data.SectionData.Segment = Segment;
3041 MArea->Data.SectionData.Section = Section;
3042 MArea->Data.SectionData.ViewOffset = ViewOffset;
3043 MArea->Data.SectionData.WriteCopyView = FALSE;
3044 MmInitialiseRegion(&MArea->Data.SectionData.RegionListHead,
3045 ViewSize, 0, Protect);
3046
3047 return(STATUS_SUCCESS);
3048 }
3049
3050
3051 /**********************************************************************
3052 * NAME EXPORTED
3053 * NtMapViewOfSection
3054 *
3055 * DESCRIPTION
3056 * Maps a view of a section into the virtual address space of a
3057 * process.
3058 *
3059 * ARGUMENTS
3060 * SectionHandle
3061 * Handle of the section.
3062 *
3063 * ProcessHandle
3064 * Handle of the process.
3065 *
3066 * BaseAddress
3067 * Desired base address (or NULL) on entry;
3068 * Actual base address of the view on exit.
3069 *
3070 * ZeroBits
3071 * Number of high order address bits that must be zero.
3072 *
3073 * CommitSize
3074 * Size in bytes of the initially committed section of
3075 * the view.
3076 *
3077 * SectionOffset
3078 * Offset in bytes from the beginning of the section
3079 * to the beginning of the view.
3080 *
3081 * ViewSize
3082 * Desired length of map (or zero to map all) on entry
3083 * Actual length mapped on exit.
3084 *
3085 * InheritDisposition
3086 * Specified how the view is to be shared with
3087 * child processes.
3088 *
3089 * AllocateType
3090 * Type of allocation for the pages.
3091 *
3092 * Protect
3093 * Protection for the committed region of the view.
3094 *
3095 * RETURN VALUE
3096 * Status.
3097 *
3098 * @implemented
3099 */
3100 NTSTATUS STDCALL
3101 NtMapViewOfSection(HANDLE SectionHandle,
3102 HANDLE ProcessHandle,
3103 PVOID* BaseAddress,
3104 ULONG ZeroBits,
3105 ULONG CommitSize,
3106 PLARGE_INTEGER SectionOffset,
3107 PULONG ViewSize,
3108 SECTION_INHERIT InheritDisposition,
3109 ULONG AllocationType,
3110 ULONG Protect)
3111 {
3112 PSECTION_OBJECT Section;
3113 PEPROCESS Process;
3114 NTSTATUS Status;
3115 PMADDRESS_SPACE AddressSpace;
3116
3117 Status = ObReferenceObjectByHandle(ProcessHandle,
3118 PROCESS_VM_OPERATION,
3119 PsProcessType,
3120 UserMode,
3121 (PVOID*)(PVOID)&Process,
3122 NULL);
3123 if (!NT_SUCCESS(Status))
3124 {
3125 return(Status);
3126 }
3127
3128 AddressSpace = &Process->AddressSpace;
3129
3130 Status = ObReferenceObjectByHandle(SectionHandle,
3131 SECTION_MAP_READ,
3132 MmSectionObjectType,
3133 UserMode,
3134 (PVOID*)(PVOID)&Section,
3135 NULL);
3136 if (!(NT_SUCCESS(Status)))
3137 {
3138 DPRINT("ObReference failed rc=%x\n",Status);
3139 ObDereferenceObject(Process);
3140 return(Status);
3141 }
3142
3143 Status = MmMapViewOfSection(Section,
3144 Process,
3145 BaseAddress,
3146 ZeroBits,
3147 CommitSize,
3148 SectionOffset,
3149 ViewSize,
3150 InheritDisposition,
3151 AllocationType,
3152 Protect);
3153
3154 ObDereferenceObject(Section);
3155 ObDereferenceObject(Process);
3156
3157 return(Status);
3158 }
3159
3160 VOID STATIC
3161 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
3162 PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
3163 {
3164 PMEMORY_AREA MArea;
3165 ULONG Entry;
3166 PFILE_OBJECT FileObject;
3167 PBCB Bcb;
3168 ULONG Offset;
3169 SWAPENTRY SavedSwapEntry;
3170 PMM_PAGEOP PageOp;
3171 NTSTATUS Status;
3172 PSECTION_OBJECT Section;
3173 PMM_SECTION_SEGMENT Segment;
3174
3175 MArea = (PMEMORY_AREA)Context;
3176
3177 Address = (PVOID)PAGE_ROUND_DOWN(Address);
3178
3179 Offset = ((ULONG_PTR)Address - (ULONG_PTR)MArea->BaseAddress) +
3180 MemoryArea->Data.SectionData.ViewOffset;
3181
3182 Section = MArea->Data.SectionData.Section;
3183 Segment = MArea->Data.SectionData.Segment;
3184
3185 PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset);
3186
3187 while (PageOp)
3188 {
3189 MmUnlockSectionSegment(Segment);
3190 MmUnlockAddressSpace(&MArea->Process->AddressSpace);
3191
3192 Status = MmspWaitForPageOpCompletionEvent(PageOp);
3193 if (Status != STATUS_SUCCESS)
3194 {
3195 DPRINT1("Failed to wait for page op, status = %x\n", Status);
3196 KEBUGCHECK(0);
3197 }
3198
3199 MmLockAddressSpace(&MArea->Process->AddressSpace);
3200 MmLockSectionSegment(Segment);
3201 MmspCompleteAndReleasePageOp(PageOp);
3202 PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset);
3203 }
3204
3205 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
3206
3207 /*
3208 * For a dirty, datafile, non-private page mark it as dirty in the
3209 * cache manager.
3210 */
3211 if (Segment->Flags & MM_DATAFILE_SEGMENT)
3212 {
3213 if (Page == PFN_FROM_SSE(Entry) && Dirty)
3214 {
3215 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
3216 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
3217 CcRosMarkDirtyCacheSegment(Bcb, Offset);
3218 assert(SwapEntry == 0);
3219 }
3220 }
3221
3222 if (SwapEntry != 0)
3223 {
3224 /*
3225 * Sanity check
3226 */
3227 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3228 {
3229 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3230 KEBUGCHECK(0);
3231 }
3232 MmFreeSwapPage(SwapEntry);
3233 }
3234 else if (Page != 0)
3235 {
3236 if (IS_SWAP_FROM_SSE(Entry) ||
3237 Page != PFN_FROM_SSE(Entry))
3238 {
3239 /*
3240 * Sanity check
3241 */
3242 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3243 {
3244 DPRINT1("Found a private page in a pagefile section.\n");
3245 KEBUGCHECK(0);
3246 }
3247 /*
3248 * Just dereference private pages
3249 */
3250 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
3251 if (SavedSwapEntry != 0)
3252 {
3253 MmFreeSwapPage(SavedSwapEntry);
3254 MmSetSavedSwapEntryPage(Page, 0);
3255 }
3256 MmDeleteRmap(Page, MArea->Process, Address);
3257 MmReleasePageMemoryConsumer(MC_USER, Page);
3258 }
3259 else
3260 {
3261 MmDeleteRmap(Page, MArea->Process, Address);
3262 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty, FALSE);
3263 }
3264 }
3265 }
3266
3267 NTSTATUS
3268 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace,
3269 PVOID BaseAddress)
3270 {
3271 NTSTATUS Status;
3272 PMEMORY_AREA MemoryArea;
3273 PSECTION_OBJECT Section;
3274 PMM_SECTION_SEGMENT Segment;
3275 KIRQL oldIrql;
3276 PLIST_ENTRY CurrentEntry;
3277 PMM_REGION CurrentRegion;
3278 PLIST_ENTRY RegionListHead;
3279
3280 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
3281 BaseAddress);
3282 if (MemoryArea == NULL)
3283 {
3284 return(STATUS_UNSUCCESSFUL);
3285 }
3286
3287 MemoryArea->DeleteInProgress = TRUE;
3288 Section = MemoryArea->Data.SectionData.Section;
3289 Segment = MemoryArea->Data.SectionData.Segment;
3290
3291 MmLockSectionSegment(Segment);
3292 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
3293 RemoveEntryList(&MemoryArea->Data.SectionData.ViewListEntry);
3294 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
3295
3296 RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
3297 while (!IsListEmpty(RegionListHead))
3298 {
3299 CurrentEntry = RemoveHeadList(RegionListHead);
3300 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
3301 ExFreePool(CurrentRegion);
3302 }
3303
3304 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
3305 {
3306 Status = MmFreeMemoryArea(AddressSpace,
3307 BaseAddress,
3308 0,
3309 NULL,
3310 NULL);
3311 }
3312 else
3313 {
3314 Status = MmFreeMemoryArea(AddressSpace,
3315 BaseAddress,
3316 0,
3317 MmFreeSectionPage,
3318 MemoryArea);
3319 }
3320 MmUnlockSectionSegment(Segment);
3321 ObDereferenceObject(Section);
3322 return(STATUS_SUCCESS);
3323 }
3324
3325 /*
3326 * @implemented
3327 */
3328 NTSTATUS STDCALL
3329 MmUnmapViewOfSection(PEPROCESS Process,
3330 PVOID BaseAddress)
3331 {
3332 NTSTATUS Status;
3333 PMEMORY_AREA MemoryArea;
3334 PMADDRESS_SPACE AddressSpace;
3335 PSECTION_OBJECT Section;
3336
3337 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3338 Process, BaseAddress);
3339
3340 assert(Process);
3341
3342 AddressSpace = &Process->AddressSpace;
3343 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
3344 BaseAddress);
3345 if (MemoryArea == NULL ||
3346 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW ||
3347 MemoryArea->DeleteInProgress)
3348 {
3349 return STATUS_NOT_MAPPED_VIEW;
3350 }
3351
3352 Section = MemoryArea->Data.SectionData.Section;
3353
3354 if (Section->AllocationAttributes & SEC_IMAGE)
3355 {
3356 ULONG i;
3357 ULONG NrSegments;
3358 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3359 PMM_SECTION_SEGMENT SectionSegments;
3360 PVOID ImageBaseAddress = 0;
3361 PMM_SECTION_SEGMENT Segment;
3362
3363 Segment = MemoryArea->Data.SectionData.Segment;
3364 ImageSectionObject = Section->ImageSection;
3365 SectionSegments = ImageSectionObject->Segments;
3366 NrSegments = ImageSectionObject->NrSegments;
3367
3368 /* Search for the current segment within the section segments
3369 * and calculate the image base address */
3370 for (i = 0; i < NrSegments; i++)
3371 {
3372 if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3373 {
3374 if (Segment == &SectionSegments[i])
3375 {
3376 ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress;
3377 break;
3378 }
3379 }
3380 }
3381 if (i >= NrSegments)
3382 {
3383 KEBUGCHECK(0);
3384 }
3385
3386 for (i = 0; i < NrSegments; i++)
3387 {
3388 if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3389 {
3390 PVOID SBaseAddress = (PVOID)
3391 ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
3392
3393 Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
3394 }
3395 }
3396 }
3397 else
3398 {
3399 Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
3400 }
3401 return(STATUS_SUCCESS);
3402 }
3403
3404 /**********************************************************************
3405 * NAME EXPORTED
3406 * NtUnmapViewOfSection
3407 *
3408 * DESCRIPTION
3409 *
3410 * ARGUMENTS
3411 * ProcessHandle
3412 *
3413 * BaseAddress
3414 *
3415 * RETURN VALUE
3416 * Status.
3417 *
3418 * REVISIONS
3419 */
3420 NTSTATUS STDCALL
3421 NtUnmapViewOfSection (HANDLE ProcessHandle,
3422 PVOID BaseAddress)
3423 {
3424 PEPROCESS Process;
3425 NTSTATUS Status;
3426
3427 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3428 ProcessHandle, BaseAddress);
3429
3430 DPRINT("Referencing process\n");
3431 Status = ObReferenceObjectByHandle(ProcessHandle,
3432 PROCESS_VM_OPERATION,
3433 PsProcessType,
3434 UserMode,
3435 (PVOID*)(PVOID)&Process,
3436 NULL);
3437 if (!NT_SUCCESS(Status))
3438 {
3439 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
3440 return(Status);
3441 }
3442
3443 MmLockAddressSpace(&Process->AddressSpace);
3444 Status = MmUnmapViewOfSection(Process, BaseAddress);
3445 MmUnlockAddressSpace(&Process->AddressSpace);
3446
3447 ObDereferenceObject(Process);
3448
3449 return Status;
3450 }
3451
3452
3453 /**
3454 * Queries the information of a section object.
3455 *
3456 * @param SectionHandle
3457 * Handle to the section object. It must be opened with SECTION_QUERY
3458 * access.
3459 * @param SectionInformationClass
3460 * Index to a certain information structure. Can be either
3461 * SectionBasicInformation or SectionImageInformation. The latter
3462 * is valid only for sections that were created with the SEC_IMAGE
3463 * flag.
3464 * @param SectionInformation
3465 * Caller supplies storage for resulting information.
3466 * @param Length
3467 * Size of the supplied storage.
3468 * @param ResultLength
3469 * Data written.
3470 *
3471 * @return Status.
3472 *
3473 * @todo Guard by SEH.
3474 * @implemented
3475 */
3476 NTSTATUS STDCALL
3477 NtQuerySection(IN HANDLE SectionHandle,
3478 IN CINT SectionInformationClass,
3479 OUT PVOID SectionInformation,
3480 IN ULONG Length,
3481 OUT PULONG ResultLength)
3482 {
3483 PSECTION_OBJECT Section;
3484 NTSTATUS Status;
3485
3486 Status = ObReferenceObjectByHandle(SectionHandle,
3487 SECTION_QUERY,
3488 MmSectionObjectType,
3489 UserMode,
3490 (PVOID*)(PVOID)&Section,
3491 NULL);
3492 if (!(NT_SUCCESS(Status)))
3493 {
3494 return(Status);
3495 }
3496
3497 switch (SectionInformationClass)
3498 {
3499 case SectionBasicInformation:
3500 {
3501 PSECTION_BASIC_INFORMATION Sbi;
3502
3503 if (Length != sizeof(SECTION_BASIC_INFORMATION))
3504 {
3505 ObDereferenceObject(Section);
3506 return(STATUS_INFO_LENGTH_MISMATCH);
3507 }
3508
3509 Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
3510
3511 Sbi->Attributes = Section->AllocationAttributes;
3512 if (Section->AllocationAttributes & SEC_IMAGE)
3513 {
3514 Sbi->BaseAddress = 0;
3515 Sbi->Size.QuadPart = 0;
3516 }
3517 else
3518 {
3519 Sbi->BaseAddress = Section->Segment->VirtualAddress;
3520 Sbi->Size.QuadPart = Section->Segment->Length;
3521 }
3522
3523 *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
3524 Status = STATUS_SUCCESS;
3525 break;
3526 }
3527
3528 case SectionImageInformation:
3529 {
3530 PSECTION_IMAGE_INFORMATION Sii;
3531
3532 if (Length != sizeof(SECTION_IMAGE_INFORMATION))
3533 {
3534 ObDereferenceObject(Section);
3535 return(STATUS_INFO_LENGTH_MISMATCH);
3536 }
3537
3538 Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
3539 memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
3540 if (Section->AllocationAttributes & SEC_IMAGE)
3541 {
3542 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3543 ImageSectionObject = Section->ImageSection;
3544
3545 Sii->EntryPoint = ImageSectionObject->EntryPoint;
3546 Sii->StackReserve = ImageSectionObject->StackReserve;
3547 Sii->StackCommit = ImageSectionObject->StackCommit;
3548 Sii->Subsystem = ImageSectionObject->Subsystem;
3549 Sii->MinorSubsystemVersion = (USHORT)ImageSectionObject->MinorSubsystemVersion;
3550 Sii->MajorSubsystemVersion = (USHORT)ImageSectionObject->MajorSubsystemVersion;
3551 Sii->Characteristics = ImageSectionObject->ImageCharacteristics;
3552 Sii->ImageNumber = ImageSectionObject->Machine;
3553 Sii->Executable = ImageSectionObject->Executable;
3554 }
3555 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
3556 Status = STATUS_SUCCESS;
3557 break;
3558 }
3559
3560 default:
3561 *ResultLength = 0;
3562 Status = STATUS_INVALID_INFO_CLASS;
3563 }
3564 ObDereferenceObject(Section);
3565 return(Status);
3566 }
3567
3568
3569 /**
3570 * Extends size of file backed section.
3571 *
3572 * @param SectionHandle
3573 * Handle to the section object. It must be opened with
3574 * SECTION_EXTEND_SIZE access.
3575 * @param NewMaximumSize
3576 * New maximum size of the section in bytes.
3577 *
3578 * @return Status.
3579 *
3580 * @todo Guard by SEH.
3581 * @todo Move the actual code to internal function MmExtendSection.
3582 * @unimplemented
3583 */
3584 NTSTATUS STDCALL
3585 NtExtendSection(IN HANDLE SectionHandle,
3586 IN PLARGE_INTEGER NewMaximumSize)
3587 {
3588 PSECTION_OBJECT Section;
3589 NTSTATUS Status;
3590
3591 Status = ObReferenceObjectByHandle(SectionHandle,
3592 SECTION_EXTEND_SIZE,
3593 MmSectionObjectType,
3594 UserMode,
3595 (PVOID*)&Section,
3596 NULL);
3597 if (!NT_SUCCESS(Status))
3598 {
3599 return Status;
3600 }
3601
3602 if (!(Section->AllocationAttributes & SEC_FILE))
3603 {
3604 ObfDereferenceObject(Section);
3605 return STATUS_INVALID_PARAMETER;
3606 }
3607
3608 /*
3609 * - Acquire file extneding resource.
3610 * - Check if we're not resizing the section below it's actual size!
3611 * - Extend segments if needed.
3612 * - Set file information (FileAllocationInformation) to the new size.
3613 * - Release file extending resource.
3614 */
3615
3616 ObDereferenceObject(Section);
3617
3618 return STATUS_NOT_IMPLEMENTED;
3619 }
3620
3621
3622 /**********************************************************************
3623 * NAME INTERNAL
3624 * MmAllocateSection@4
3625 *
3626 * DESCRIPTION
3627 *
3628 * ARGUMENTS
3629 * Length
3630 *
3631 * RETURN VALUE
3632 *
3633 * NOTE
3634 * Code taken from ntoskrnl/mm/special.c.
3635 *
3636 * REVISIONS
3637 */
3638 PVOID STDCALL
3639 MmAllocateSection (IN ULONG Length, PVOID BaseAddress)
3640 {
3641 PVOID Result;
3642 MEMORY_AREA* marea;
3643 NTSTATUS Status;
3644 ULONG i;
3645 PMADDRESS_SPACE AddressSpace;
3646 PHYSICAL_ADDRESS BoundaryAddressMultiple;
3647
3648 DPRINT("MmAllocateSection(Length %x)\n",Length);
3649
3650 BoundaryAddressMultiple.QuadPart = 0;
3651
3652 AddressSpace = MmGetKernelAddressSpace();
3653 Result = BaseAddress;
3654 MmLockAddressSpace(AddressSpace);
3655 Status = MmCreateMemoryArea (NULL,
3656 AddressSpace,
3657 MEMORY_AREA_SYSTEM,
3658 &Result,
3659 Length,
3660 0,
3661 &marea,
3662 FALSE,
3663 FALSE,
3664 BoundaryAddressMultiple);
3665 MmUnlockAddressSpace(AddressSpace);
3666
3667 if (!NT_SUCCESS(Status))
3668 {
3669 return (NULL);
3670 }
3671 DPRINT("Result %p\n",Result);
3672 for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
3673 {
3674 PFN_TYPE Page;
3675
3676 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page);
3677 if (!NT_SUCCESS(Status))
3678 {
3679 DbgPrint("Unable to allocate page\n");
3680 KEBUGCHECK(0);
3681 }
3682 Status = MmCreateVirtualMapping (NULL,
3683 ((char*)Result + (i * PAGE_SIZE)),
3684 PAGE_READWRITE,
3685 &Page,
3686 1);
3687 if (!NT_SUCCESS(Status))
3688 {
3689 DbgPrint("Unable to create virtual mapping\n");
3690 KEBUGCHECK(0);
3691 }
3692 }
3693 return ((PVOID)Result);
3694 }
3695
3696
3697 /**********************************************************************
3698 * NAME EXPORTED
3699 * MmMapViewOfSection
3700 *
3701 * DESCRIPTION
3702 * Maps a view of a section into the virtual address space of a
3703 * process.
3704 *
3705 * ARGUMENTS
3706 * Section
3707 * Pointer to the section object.
3708 *
3709 * ProcessHandle
3710 * Pointer to the process.
3711 *
3712 * BaseAddress
3713 * Desired base address (or NULL) on entry;
3714 * Actual base address of the view on exit.
3715 *
3716 * ZeroBits
3717 * Number of high order address bits that must be zero.
3718 *
3719 * CommitSize
3720 * Size in bytes of the initially committed section of
3721 * the view.
3722 *
3723 * SectionOffset
3724 * Offset in bytes from the beginning of the section
3725 * to the beginning of the view.
3726 *
3727 * ViewSize
3728 * Desired length of map (or zero to map all) on entry
3729 * Actual length mapped on exit.
3730 *
3731 * InheritDisposition
3732 * Specified how the view is to be shared with
3733 * child processes.
3734 *
3735 * AllocationType
3736 * Type of allocation for the pages.
3737 *
3738 * Protect
3739 * Protection for the committed region of the view.
3740 *
3741 * RETURN VALUE
3742 * Status.
3743 *
3744 * @implemented
3745 */
3746 NTSTATUS STDCALL
3747 MmMapViewOfSection(IN PVOID SectionObject,
3748 IN PEPROCESS Process,
3749 IN OUT PVOID *BaseAddress,
3750 IN ULONG ZeroBits,
3751 IN ULONG CommitSize,
3752 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
3753 IN OUT PULONG ViewSize,
3754 IN SECTION_INHERIT InheritDisposition,
3755 IN ULONG AllocationType,
3756 IN ULONG Protect)
3757 {
3758 PSECTION_OBJECT Section;
3759 PMADDRESS_SPACE AddressSpace;
3760 ULONG ViewOffset;
3761 NTSTATUS Status = STATUS_SUCCESS;
3762
3763 assert(Process);
3764
3765 Section = (PSECTION_OBJECT)SectionObject;
3766 AddressSpace = &Process->AddressSpace;
3767
3768 MmLockAddressSpace(AddressSpace);
3769
3770 if (Section->AllocationAttributes & SEC_IMAGE)
3771 {
3772 ULONG i;
3773 ULONG NrSegments;
3774 PVOID ImageBase;
3775 ULONG ImageSize;
3776 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3777 PMM_SECTION_SEGMENT SectionSegments;
3778
3779 ImageSectionObject = Section->ImageSection;
3780 SectionSegments = ImageSectionObject->Segments;
3781 NrSegments = ImageSectionObject->NrSegments;
3782
3783
3784 ImageBase = *BaseAddress;
3785 if (ImageBase == NULL)
3786 {
3787 ImageBase = ImageSectionObject->ImageBase;
3788 }
3789
3790 ImageSize = 0;
3791 for (i = 0; i < NrSegments; i++)
3792 {
3793 if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3794 {
3795 ULONG MaxExtent;
3796 MaxExtent = (ULONG)((char*)SectionSegments[i].VirtualAddress +
3797 SectionSegments[i].Length);
3798 ImageSize = max(ImageSize, MaxExtent);
3799 }
3800 }
3801
3802 /* Check there is enough space to map the section at that point. */
3803 if (MmOpenMemoryAreaByRegion(AddressSpace, ImageBase,
3804 PAGE_ROUND_UP(ImageSize)) != NULL)
3805 {
3806 /* Fail if the user requested a fixed base address. */
3807 if ((*BaseAddress) != NULL)
3808 {
3809 MmUnlockAddressSpace(AddressSpace);
3810 return(STATUS_UNSUCCESSFUL);
3811 }
3812 /* Otherwise find a gap to map the image. */
3813 ImageBase = MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE);
3814 if (ImageBase == NULL)
3815 {
3816 MmUnlockAddressSpace(AddressSpace);
3817 return(STATUS_UNSUCCESSFUL);
3818 }
3819 }
3820
3821 for (i = 0; i < NrSegments; i++)
3822 {
3823 if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3824 {
3825 PVOID SBaseAddress = (PVOID)
3826 ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
3827 MmLockSectionSegment(&SectionSegments[i]);
3828 Status = MmMapViewOfSegment(Process,
3829 AddressSpace,
3830 Section,
3831 &SectionSegments[i],
3832 &SBaseAddress,
3833 SectionSegments[i].Length,
3834 SectionSegments[i].Protection,
3835 0,
3836 FALSE);
3837 MmUnlockSectionSegment(&SectionSegments[i]);
3838 if (!NT_SUCCESS(Status))
3839 {
3840 MmUnlockAddressSpace(AddressSpace);
3841 return(Status);
3842 }
3843 }
3844 }
3845
3846 *BaseAddress = ImageBase;
3847 }
3848 else
3849 {
3850 if (ViewSize == NULL)
3851 {
3852 /* Following this pointer would lead to us to the dark side */
3853 /* What to do? Bugcheck? Return status? Do the mambo? */
3854 KEBUGCHECK(MEMORY_MANAGEMENT);
3855 }
3856
3857 if (SectionOffset == NULL)
3858 {
3859 ViewOffset = 0;
3860 }
3861 else
3862 {
3863 ViewOffset = SectionOffset->u.LowPart;
3864 }
3865
3866 if ((ViewOffset % PAGE_SIZE) != 0)
3867 {
3868 MmUnlockAddressSpace(AddressSpace);
3869 return(STATUS_MAPPED_ALIGNMENT);
3870 }
3871
3872 if ((*ViewSize) == 0)
3873 {
3874 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3875 }
3876 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
3877 {
3878 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3879 }
3880
3881 MmLockSectionSegment(Section->Segment);
3882 Status = MmMapViewOfSegment(Process,
3883 AddressSpace,
3884 Section,
3885 Section->Segment,
3886 BaseAddress,
3887 *ViewSize,
3888 Protect,
3889 ViewOffset,
3890 (AllocationType & MEM_TOP_DOWN));
3891 MmUnlockSectionSegment(Section->Segment);
3892 if (!NT_SUCCESS(Status))
3893 {
3894 MmUnlockAddressSpace(AddressSpace);
3895 return(Status);
3896 }
3897 }
3898
3899 MmUnlockAddressSpace(AddressSpace);
3900
3901 return(STATUS_SUCCESS);
3902 }
3903
3904 /*
3905 * @unimplemented
3906 */
3907 BOOLEAN STDCALL
3908 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
3909 IN PLARGE_INTEGER NewFileSize)
3910 {
3911 UNIMPLEMENTED;
3912 return (FALSE);
3913 }
3914
3915
3916 /*
3917 * @unimplemented
3918 */
3919 BOOLEAN STDCALL
3920 MmDisableModifiedWriteOfSection (DWORD Unknown0)
3921 {
3922 UNIMPLEMENTED;
3923 return (FALSE);
3924 }
3925
3926 /*
3927 * @implemented
3928 */
3929 BOOLEAN STDCALL
3930 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
3931 IN MMFLUSH_TYPE FlushType)
3932 {
3933 switch(FlushType)
3934 {
3935 case MmFlushForDelete:
3936 if (SectionObjectPointer->ImageSectionObject ||
3937 SectionObjectPointer->DataSectionObject)
3938 {
3939 return FALSE;
3940 }
3941 CcRosSetRemoveOnClose(SectionObjectPointer);
3942 return TRUE;
3943 case MmFlushForWrite:
3944 break;
3945 }
3946 return FALSE;
3947 }
3948