2004-08-15 Casper S. Hornstrup <chorns@users.sourceforge.net>
[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.158 2004/08/15 16:39:08 chorns 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 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
917
918 if (Entry == 0)
919 {
920 /*
921 * If the entry is zero (and it can't change because we have
922 * locked the segment) then we need to load the page.
923 */
924
925 /*
926 * Release all our locks and read in the page from disk
927 */
928 MmUnlockSectionSegment(Segment);
929 MmUnlockAddressSpace(AddressSpace);
930
931 if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
932 (Offset >= PAGE_ROUND_UP(Segment->RawLength) && Section->AllocationAttributes & SEC_IMAGE))
933 {
934 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
935 if (!NT_SUCCESS(Status))
936 {
937 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
938 }
939 }
940 else
941 {
942 Status = MiReadPage(MemoryArea, Offset, &Page);
943 if (!NT_SUCCESS(Status))
944 {
945 DPRINT1("MiReadPage failed (Status %x)\n", Status);
946 }
947 }
948 if (!NT_SUCCESS(Status))
949 {
950 /*
951 * FIXME: What do we know in this case?
952 */
953 /*
954 * Cleanup and release locks
955 */
956 MmLockAddressSpace(AddressSpace);
957 PageOp->Status = Status;
958 MmspCompleteAndReleasePageOp(PageOp);
959 DPRINT("Address 0x%.8X\n", Address);
960 return(Status);
961 }
962 /*
963 * Relock the address space and segment
964 */
965 MmLockAddressSpace(AddressSpace);
966 MmLockSectionSegment(Segment);
967
968 /*
969 * Check the entry. No one should change the status of a page
970 * that has a pending page-in.
971 */
972 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
973 if (Entry != Entry1)
974 {
975 DbgPrint("Someone changed ppte entry while we slept\n");
976 KEBUGCHECK(0);
977 }
978
979 /*
980 * Mark the offset within the section as having valid, in-memory
981 * data
982 */
983 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
984 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
985 MmUnlockSectionSegment(Segment);
986
987 Status = MmCreateVirtualMapping(AddressSpace->Process,
988 Address,
989 Attributes,
990 &Page,
991 1);
992 if (!NT_SUCCESS(Status))
993 {
994 DbgPrint("Unable to create virtual mapping\n");
995 KEBUGCHECK(0);
996 }
997 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
998
999 if (Locked)
1000 {
1001 MmLockPage(Page);
1002 }
1003 PageOp->Status = STATUS_SUCCESS;
1004 MmspCompleteAndReleasePageOp(PageOp);
1005 DPRINT("Address 0x%.8X\n", Address);
1006 return(STATUS_SUCCESS);
1007 }
1008 else if (IS_SWAP_FROM_SSE(Entry))
1009 {
1010 SWAPENTRY SwapEntry;
1011
1012 SwapEntry = SWAPENTRY_FROM_SSE(Entry);
1013
1014 /*
1015 * Release all our locks and read in the page from disk
1016 */
1017 MmUnlockSectionSegment(Segment);
1018
1019 MmUnlockAddressSpace(AddressSpace);
1020
1021 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1022 if (!NT_SUCCESS(Status))
1023 {
1024 KEBUGCHECK(0);
1025 }
1026
1027 Status = MmReadFromSwapPage(SwapEntry, Page);
1028 if (!NT_SUCCESS(Status))
1029 {
1030 KEBUGCHECK(0);
1031 }
1032
1033 /*
1034 * Relock the address space and segment
1035 */
1036 MmLockAddressSpace(AddressSpace);
1037 MmLockSectionSegment(Segment);
1038
1039 /*
1040 * Check the entry. No one should change the status of a page
1041 * that has a pending page-in.
1042 */
1043 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
1044 if (Entry != Entry1)
1045 {
1046 DbgPrint("Someone changed ppte entry while we slept\n");
1047 KEBUGCHECK(0);
1048 }
1049
1050 /*
1051 * Mark the offset within the section as having valid, in-memory
1052 * data
1053 */
1054 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1055 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
1056 MmUnlockSectionSegment(Segment);
1057
1058 /*
1059 * Save the swap entry.
1060 */
1061 MmSetSavedSwapEntryPage(Page, SwapEntry);
1062 Status = MmCreateVirtualMapping(AddressSpace->Process,
1063 Address,
1064 Region->Protect,
1065 &Page,
1066 1);
1067 if (!NT_SUCCESS(Status))
1068 {
1069 DbgPrint("Unable to create virtual mapping\n");
1070 KEBUGCHECK(0);
1071 }
1072 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
1073 if (Locked)
1074 {
1075 MmLockPage(Page);
1076 }
1077 PageOp->Status = STATUS_SUCCESS;
1078 MmspCompleteAndReleasePageOp(PageOp);
1079 DPRINT("Address 0x%.8X\n", Address);
1080 return(STATUS_SUCCESS);
1081 }
1082 else
1083 {
1084 /*
1085 * If the section offset is already in-memory and valid then just
1086 * take another reference to the page
1087 */
1088
1089 Page = PFN_FROM_SSE(Entry);
1090
1091 MmSharePageEntrySectionSegment(Segment, Offset);
1092 MmUnlockSectionSegment(Segment);
1093
1094 Status = MmCreateVirtualMapping(AddressSpace->Process,
1095 Address,
1096 Attributes,
1097 &Page,
1098 1);
1099 if (!NT_SUCCESS(Status))
1100 {
1101 DbgPrint("Unable to create virtual mapping\n");
1102 KEBUGCHECK(0);
1103 }
1104 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
1105 if (Locked)
1106 {
1107 MmLockPage(Page);
1108 }
1109 PageOp->Status = STATUS_SUCCESS;
1110 MmspCompleteAndReleasePageOp(PageOp);
1111 DPRINT("Address 0x%.8X\n", Address);
1112 return(STATUS_SUCCESS);
1113 }
1114 }
1115
1116 NTSTATUS
1117 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
1118 MEMORY_AREA* MemoryArea,
1119 PVOID Address,
1120 BOOLEAN Locked)
1121 {
1122 PMM_SECTION_SEGMENT Segment;
1123 PSECTION_OBJECT Section;
1124 PFN_TYPE OldPage;
1125 PFN_TYPE NewPage;
1126 PVOID NewAddress;
1127 NTSTATUS Status;
1128 ULONG PAddress;
1129 ULONG Offset;
1130 PMM_PAGEOP PageOp;
1131 PMM_REGION Region;
1132 ULONG Entry;
1133
1134 /*
1135 * Check if the page has been paged out or has already been set readwrite
1136 */
1137 if (!MmIsPagePresent(AddressSpace->Process, Address) ||
1138 MmGetPageProtect(AddressSpace->Process, Address) & PAGE_READWRITE)
1139 {
1140 DPRINT("Address 0x%.8X\n", Address);
1141 return(STATUS_SUCCESS);
1142 }
1143
1144 /*
1145 * Find the offset of the page
1146 */
1147 PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
1148 Offset = PAddress - (ULONG)MemoryArea->BaseAddress;
1149
1150 Segment = MemoryArea->Data.SectionData.Segment;
1151 Section = MemoryArea->Data.SectionData.Section;
1152 Region = MmFindRegion(MemoryArea->BaseAddress,
1153 &MemoryArea->Data.SectionData.RegionListHead,
1154 Address, NULL);
1155 /*
1156 * Lock the segment
1157 */
1158 MmLockSectionSegment(Segment);
1159
1160 OldPage = MmGetPfnForProcess(NULL, Address);
1161 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1162
1163 MmUnlockSectionSegment(Segment);
1164
1165 /*
1166 * Check if we are doing COW
1167 */
1168 if (!((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1169 (Region->Protect == PAGE_READWRITE ||
1170 Region->Protect == PAGE_EXECUTE_READWRITE)))
1171 {
1172 DPRINT("Address 0x%.8X\n", Address);
1173 return(STATUS_UNSUCCESSFUL);
1174 }
1175
1176 if (IS_SWAP_FROM_SSE(Entry) ||
1177 PFN_FROM_SSE(Entry) != OldPage)
1178 {
1179 /* This is a private page. We must only change the page protection. */
1180 MmSetPageProtect(AddressSpace->Process, (PVOID)PAddress, Region->Protect);
1181 return(STATUS_SUCCESS);
1182 }
1183
1184 /*
1185 * Get or create a pageop
1186 */
1187 PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset,
1188 MM_PAGEOP_ACCESSFAULT, FALSE);
1189 if (PageOp == NULL)
1190 {
1191 DPRINT1("MmGetPageOp failed\n");
1192 KEBUGCHECK(0);
1193 }
1194
1195 /*
1196 * Wait for any other operations to complete
1197 */
1198 if (PageOp->Thread != PsGetCurrentThread())
1199 {
1200 MmUnlockAddressSpace(AddressSpace);
1201 Status = MmspWaitForPageOpCompletionEvent(PageOp);
1202 /*
1203 * Check for various strange conditions
1204 */
1205 if (Status == STATUS_TIMEOUT)
1206 {
1207 DPRINT1("Failed to wait for page op, status = %x\n", Status);
1208 KEBUGCHECK(0);
1209 }
1210 if (PageOp->Status == STATUS_PENDING)
1211 {
1212 DPRINT1("Woke for page op before completion\n");
1213 KEBUGCHECK(0);
1214 }
1215 /*
1216 * Restart the operation
1217 */
1218 MmLockAddressSpace(AddressSpace);
1219 MmspCompleteAndReleasePageOp(PageOp);
1220 DPRINT("Address 0x%.8X\n", Address);
1221 return(STATUS_MM_RESTART_OPERATION);
1222 }
1223
1224 /*
1225 * Release locks now we have the pageop
1226 */
1227 MmUnlockAddressSpace(AddressSpace);
1228
1229 /*
1230 * Allocate a page
1231 */
1232 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1233 if (!NT_SUCCESS(Status))
1234 {
1235 KEBUGCHECK(0);
1236 }
1237
1238 /*
1239 * Copy the old page
1240 */
1241
1242 NewAddress = ExAllocatePageWithPhysPage(NewPage);
1243 memcpy(NewAddress, (PVOID)PAddress, PAGE_SIZE);
1244 ExUnmapPage(NewAddress);
1245
1246 /*
1247 * Delete the old entry.
1248 */
1249 MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
1250
1251 /*
1252 * Set the PTE to point to the new page
1253 */
1254 MmLockAddressSpace(AddressSpace);
1255 Status = MmCreateVirtualMapping(AddressSpace->Process,
1256 Address,
1257 Region->Protect,
1258 &NewPage,
1259 1);
1260 if (!NT_SUCCESS(Status))
1261 {
1262 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1263 KEBUGCHECK(0);
1264 return(Status);
1265 }
1266 MmInsertRmap(NewPage, AddressSpace->Process, (PVOID)PAddress);
1267 if (!NT_SUCCESS(Status))
1268 {
1269 DbgPrint("Unable to create virtual mapping\n");
1270 KEBUGCHECK(0);
1271 }
1272 if (Locked)
1273 {
1274 MmLockPage(NewPage);
1275 MmUnlockPage(OldPage);
1276 }
1277
1278 /*
1279 * Unshare the old page.
1280 */
1281 MmDeleteRmap(OldPage, AddressSpace->Process, (PVOID)PAddress);
1282 MmLockSectionSegment(Segment);
1283 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE, FALSE);
1284 MmUnlockSectionSegment(Segment);
1285
1286 PageOp->Status = STATUS_SUCCESS;
1287 MmspCompleteAndReleasePageOp(PageOp);
1288 DPRINT("Address 0x%.8X\n", Address);
1289 return(STATUS_SUCCESS);
1290 }
1291
1292 VOID
1293 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
1294 {
1295 MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1296 BOOL WasDirty;
1297 PFN_TYPE Page;
1298
1299 PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1300 MmDeleteVirtualMapping(Process,
1301 Address,
1302 FALSE,
1303 &WasDirty,
1304 &Page);
1305 if (WasDirty)
1306 {
1307 PageOutContext->WasDirty = TRUE;
1308 }
1309 if (!PageOutContext->Private)
1310 {
1311 MmUnsharePageEntrySectionSegment(PageOutContext->Section,
1312 PageOutContext->Segment,
1313 PageOutContext->Offset,
1314 PageOutContext->WasDirty,
1315 TRUE);
1316 }
1317 else
1318 {
1319 MmReleasePageMemoryConsumer(MC_USER, Page);
1320 }
1321
1322 DPRINT("PhysicalAddress %I64x, Address %x\n", Page, Address);
1323 }
1324
1325 NTSTATUS
1326 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
1327 MEMORY_AREA* MemoryArea,
1328 PVOID Address,
1329 PMM_PAGEOP PageOp)
1330 {
1331 PFN_TYPE Page;
1332 MM_SECTION_PAGEOUT_CONTEXT Context;
1333 SWAPENTRY SwapEntry;
1334 ULONG Entry;
1335 ULONG FileOffset;
1336 NTSTATUS Status;
1337 PFILE_OBJECT FileObject;
1338 PBCB Bcb = NULL;
1339 BOOLEAN DirectMapped;
1340 BOOLEAN IsImageSection;
1341
1342 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1343
1344 /*
1345 * Get the segment and section.
1346 */
1347 Context.Segment = MemoryArea->Data.SectionData.Segment;
1348 Context.Section = MemoryArea->Data.SectionData.Section;
1349
1350 Context.Offset = (ULONG)((char*)Address - (ULONG)MemoryArea->BaseAddress);
1351 FileOffset = Context.Offset + Context.Segment->FileOffset;
1352
1353 IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1354
1355 FileObject = Context.Section->FileObject;
1356 DirectMapped = FALSE;
1357 if (FileObject != NULL &&
1358 !(Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
1359 {
1360 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1361
1362 /*
1363 * If the file system is letting us go directly to the cache and the
1364 * memory area was mapped at an offset in the file which is page aligned
1365 * then note this is a direct mapped page.
1366 */
1367 if ((FileOffset % PAGE_SIZE) == 0 &&
1368 (Context.Offset + PAGE_SIZE <= Context.Segment->RawLength || !IsImageSection))
1369 {
1370 DirectMapped = TRUE;
1371 }
1372 }
1373
1374
1375 /*
1376 * This should never happen since mappings of physical memory are never
1377 * placed in the rmap lists.
1378 */
1379 if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1380 {
1381 DPRINT1("Trying to page out from physical memory section address 0x%X "
1382 "process %d\n", Address,
1383 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
1384 KEBUGCHECK(0);
1385 }
1386
1387 /*
1388 * Get the section segment entry and the physical address.
1389 */
1390 Entry = MmGetPageEntrySectionSegment(Context.Segment, Context.Offset);
1391 if (!MmIsPagePresent(AddressSpace->Process, Address))
1392 {
1393 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1394 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
1395 KEBUGCHECK(0);
1396 }
1397 Page = MmGetPfnForProcess(AddressSpace->Process, Address);
1398 SwapEntry = MmGetSavedSwapEntryPage(Page);
1399
1400 /*
1401 * Prepare the context structure for the rmap delete call.
1402 */
1403 Context.WasDirty = FALSE;
1404 if (Context.Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1405 IS_SWAP_FROM_SSE(Entry) ||
1406 PFN_FROM_SSE(Entry) != Page)
1407 {
1408 Context.Private = TRUE;
1409 }
1410 else
1411 {
1412 Context.Private = FALSE;
1413 }
1414
1415 /*
1416 * Take an additional reference to the page or the cache segment.
1417 */
1418 if (DirectMapped && !Context.Private)
1419 {
1420 if(!MiIsPageFromCache(MemoryArea, Context.Offset))
1421 {
1422 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1423 KEBUGCHECK(0);
1424 }
1425 }
1426 else
1427 {
1428 MmReferencePage(Page);
1429 }
1430
1431 MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping);
1432
1433 /*
1434 * If this wasn't a private page then we should have reduced the entry to
1435 * zero by deleting all the rmaps.
1436 */
1437 if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0)
1438 {
1439 if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
1440 !(Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
1441 {
1442 KEBUGCHECK(0);
1443 }
1444 }
1445
1446 /*
1447 * If the page wasn't dirty then we can just free it as for a readonly page.
1448 * Since we unmapped all the mappings above we know it will not suddenly
1449 * become dirty.
1450 * If the page is from a pagefile section and has no swap entry,
1451 * we can't free the page at this point.
1452 */
1453 SwapEntry = MmGetSavedSwapEntryPage(Page);
1454 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT)
1455 {
1456 if (Context.Private)
1457 {
1458 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1459 Context.WasDirty ? "dirty" : "clean", Address);
1460 KEBUGCHECK(0);
1461 }
1462 if (!Context.WasDirty && SwapEntry != 0)
1463 {
1464 MmSetSavedSwapEntryPage(Page, 0);
1465 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
1466 MmReleasePageMemoryConsumer(MC_USER, Page);
1467 PageOp->Status = STATUS_SUCCESS;
1468 MmspCompleteAndReleasePageOp(PageOp);
1469 return(STATUS_SUCCESS);
1470 }
1471 }
1472 else if (Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED)
1473 {
1474 if (Context.Private)
1475 {
1476 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1477 Context.WasDirty ? "dirty" : "clean", Address);
1478 KEBUGCHECK(0);
1479 }
1480 if (!Context.WasDirty || SwapEntry != 0)
1481 {
1482 MmSetSavedSwapEntryPage(Page, 0);
1483 if (SwapEntry != 0)
1484 {
1485 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
1486 }
1487 MmReleasePageMemoryConsumer(MC_USER, Page);
1488 PageOp->Status = STATUS_SUCCESS;
1489 MmspCompleteAndReleasePageOp(PageOp);
1490 return(STATUS_SUCCESS);
1491 }
1492 }
1493 else if (!Context.Private && DirectMapped)
1494 {
1495 if (SwapEntry != 0)
1496 {
1497 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1498 Address);
1499 KEBUGCHECK(0);
1500 }
1501 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
1502 if (!NT_SUCCESS(Status))
1503 {
1504 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
1505 KEBUGCHECK(0);
1506 }
1507 PageOp->Status = STATUS_SUCCESS;
1508 MmspCompleteAndReleasePageOp(PageOp);
1509 return(STATUS_SUCCESS);
1510 }
1511 else if (!Context.WasDirty && !DirectMapped && !Context.Private)
1512 {
1513 if (SwapEntry != 0)
1514 {
1515 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1516 Address);
1517 KEBUGCHECK(0);
1518 }
1519 MmReleasePageMemoryConsumer(MC_USER, Page);
1520 PageOp->Status = STATUS_SUCCESS;
1521 MmspCompleteAndReleasePageOp(PageOp);
1522 return(STATUS_SUCCESS);
1523 }
1524 else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
1525 {
1526 MmSetSavedSwapEntryPage(Page, 0);
1527 Status = MmCreatePageFileMapping(AddressSpace->Process,
1528 Address,
1529 SwapEntry);
1530 if (!NT_SUCCESS(Status))
1531 {
1532 KEBUGCHECK(0);
1533 }
1534 MmReleasePageMemoryConsumer(MC_USER, Page);
1535 PageOp->Status = STATUS_SUCCESS;
1536 MmspCompleteAndReleasePageOp(PageOp);
1537 return(STATUS_SUCCESS);
1538 }
1539
1540 /*
1541 * If necessary, allocate an entry in the paging file for this page
1542 */
1543 if (SwapEntry == 0)
1544 {
1545 SwapEntry = MmAllocSwapPage();
1546 if (SwapEntry == 0)
1547 {
1548 MmShowOutOfSpaceMessagePagingFile();
1549
1550 /*
1551 * For private pages restore the old mappings.
1552 */
1553 if (Context.Private)
1554 {
1555 Status = MmCreateVirtualMapping(MemoryArea->Process,
1556 Address,
1557 MemoryArea->Attributes,
1558 &Page,
1559 1);
1560 MmSetDirtyPage(MemoryArea->Process, Address);
1561 MmInsertRmap(Page,
1562 MemoryArea->Process,
1563 Address);
1564 }
1565 else
1566 {
1567 /*
1568 * For non-private pages if the page wasn't direct mapped then
1569 * set it back into the section segment entry so we don't loose
1570 * our copy. Otherwise it will be handled by the cache manager.
1571 */
1572 Status = MmCreateVirtualMapping(MemoryArea->Process,
1573 Address,
1574 MemoryArea->Attributes,
1575 &Page,
1576 1);
1577 MmSetDirtyPage(MemoryArea->Process, Address);
1578 MmInsertRmap(Page,
1579 MemoryArea->Process,
1580 Address);
1581 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1582 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1583 }
1584 PageOp->Status = STATUS_UNSUCCESSFUL;
1585 MmspCompleteAndReleasePageOp(PageOp);
1586 return(STATUS_PAGEFILE_QUOTA);
1587 }
1588 }
1589
1590 /*
1591 * Write the page to the pagefile
1592 */
1593 Status = MmWriteToSwapPage(SwapEntry, Page);
1594 if (!NT_SUCCESS(Status))
1595 {
1596 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1597 Status);
1598 /*
1599 * As above: undo our actions.
1600 * FIXME: Also free the swap page.
1601 */
1602 if (Context.Private)
1603 {
1604 Status = MmCreateVirtualMapping(MemoryArea->Process,
1605 Address,
1606 MemoryArea->Attributes,
1607 &Page,
1608 1);
1609 MmSetDirtyPage(MemoryArea->Process, Address);
1610 MmInsertRmap(Page,
1611 MemoryArea->Process,
1612 Address);
1613 }
1614 else
1615 {
1616 Status = MmCreateVirtualMapping(MemoryArea->Process,
1617 Address,
1618 MemoryArea->Attributes,
1619 &Page,
1620 1);
1621 MmSetDirtyPage(MemoryArea->Process, Address);
1622 MmInsertRmap(Page,
1623 MemoryArea->Process,
1624 Address);
1625 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1626 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1627 }
1628 PageOp->Status = STATUS_UNSUCCESSFUL;
1629 MmspCompleteAndReleasePageOp(PageOp);
1630 return(STATUS_UNSUCCESSFUL);
1631 }
1632
1633 /*
1634 * Otherwise we have succeeded.
1635 */
1636 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
1637 MmSetSavedSwapEntryPage(Page, 0);
1638 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
1639 Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED)
1640 {
1641 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
1642 }
1643 else
1644 {
1645 MmReleasePageMemoryConsumer(MC_USER, Page);
1646 }
1647
1648 if (Context.Private)
1649 {
1650 Status = MmCreatePageFileMapping(MemoryArea->Process,
1651 Address,
1652 SwapEntry);
1653 if (!NT_SUCCESS(Status))
1654 {
1655 KEBUGCHECK(0);
1656 }
1657 }
1658 else
1659 {
1660 Entry = MAKE_SWAP_SSE(SwapEntry);
1661 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1662 }
1663
1664 PageOp->Status = STATUS_SUCCESS;
1665 MmspCompleteAndReleasePageOp(PageOp);
1666 return(STATUS_SUCCESS);
1667 }
1668
1669 NTSTATUS
1670 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
1671 PMEMORY_AREA MemoryArea,
1672 PVOID Address,
1673 PMM_PAGEOP PageOp)
1674 {
1675 ULONG Offset;
1676 PSECTION_OBJECT Section;
1677 PMM_SECTION_SEGMENT Segment;
1678 PFN_TYPE Page;
1679 SWAPENTRY SwapEntry;
1680 ULONG Entry;
1681 BOOLEAN Private;
1682 NTSTATUS Status;
1683 PFILE_OBJECT FileObject;
1684 PBCB Bcb = NULL;
1685 BOOLEAN DirectMapped;
1686 BOOLEAN IsImageSection;
1687
1688 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1689
1690 Offset = (ULONG)((char*)Address - (ULONG)MemoryArea->BaseAddress);
1691
1692 /*
1693 * Get the segment and section.
1694 */
1695 Segment = MemoryArea->Data.SectionData.Segment;
1696 Section = MemoryArea->Data.SectionData.Section;
1697 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1698
1699 FileObject = Section->FileObject;
1700 DirectMapped = FALSE;
1701 if (FileObject != NULL &&
1702 !(Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
1703 {
1704 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1705
1706 /*
1707 * If the file system is letting us go directly to the cache and the
1708 * memory area was mapped at an offset in the file which is page aligned
1709 * then note this is a direct mapped page.
1710 */
1711 if ((Offset + MemoryArea->Data.SectionData.ViewOffset % PAGE_SIZE) == 0 &&
1712 (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
1713 {
1714 DirectMapped = TRUE;
1715 }
1716 }
1717
1718 /*
1719 * This should never happen since mappings of physical memory are never
1720 * placed in the rmap lists.
1721 */
1722 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1723 {
1724 DPRINT1("Trying to write back page from physical memory mapped at %X "
1725 "process %d\n", Address,
1726 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
1727 KEBUGCHECK(0);
1728 }
1729
1730 /*
1731 * Get the section segment entry and the physical address.
1732 */
1733 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1734 if (!MmIsPagePresent(AddressSpace->Process, Address))
1735 {
1736 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1737 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
1738 KEBUGCHECK(0);
1739 }
1740 Page = MmGetPfnForProcess(AddressSpace->Process, Address);
1741 SwapEntry = MmGetSavedSwapEntryPage(Page);
1742
1743 /*
1744 * Check for a private (COWed) page.
1745 */
1746 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1747 IS_SWAP_FROM_SSE(Entry) ||
1748 PFN_FROM_SSE(Entry) != Page)
1749 {
1750 Private = TRUE;
1751 }
1752 else
1753 {
1754 Private = FALSE;
1755 }
1756
1757 /*
1758 * Speculatively set all mappings of the page to clean.
1759 */
1760 MmSetCleanAllRmaps(Page);
1761
1762 /*
1763 * If this page was direct mapped from the cache then the cache manager
1764 * will take care of writing it back to disk.
1765 */
1766 if (DirectMapped && !Private)
1767 {
1768 assert(SwapEntry == 0);
1769 CcRosMarkDirtyCacheSegment(Bcb, Offset + MemoryArea->Data.SectionData.ViewOffset);
1770 PageOp->Status = STATUS_SUCCESS;
1771 MmspCompleteAndReleasePageOp(PageOp);
1772 return(STATUS_SUCCESS);
1773 }
1774
1775 /*
1776 * If necessary, allocate an entry in the paging file for this page
1777 */
1778 if (SwapEntry == 0)
1779 {
1780 SwapEntry = MmAllocSwapPage();
1781 if (SwapEntry == 0)
1782 {
1783 MmSetDirtyAllRmaps(Page);
1784 PageOp->Status = STATUS_UNSUCCESSFUL;
1785 MmspCompleteAndReleasePageOp(PageOp);
1786 return(STATUS_PAGEFILE_QUOTA);
1787 }
1788 MmSetSavedSwapEntryPage(Page, SwapEntry);
1789 }
1790
1791 /*
1792 * Write the page to the pagefile
1793 */
1794 Status = MmWriteToSwapPage(SwapEntry, Page);
1795 if (!NT_SUCCESS(Status))
1796 {
1797 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1798 Status);
1799 MmSetDirtyAllRmaps(Page);
1800 PageOp->Status = STATUS_UNSUCCESSFUL;
1801 MmspCompleteAndReleasePageOp(PageOp);
1802 return(STATUS_UNSUCCESSFUL);
1803 }
1804
1805 /*
1806 * Otherwise we have succeeded.
1807 */
1808 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
1809 PageOp->Status = STATUS_SUCCESS;
1810 MmspCompleteAndReleasePageOp(PageOp);
1811 return(STATUS_SUCCESS);
1812 }
1813
1814 VOID STATIC
1815 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace,
1816 PVOID BaseAddress,
1817 ULONG RegionSize,
1818 ULONG OldType,
1819 ULONG OldProtect,
1820 ULONG NewType,
1821 ULONG NewProtect)
1822 {
1823 PMEMORY_AREA MemoryArea;
1824 PMM_SECTION_SEGMENT Segment;
1825 BOOL DoCOW = FALSE;
1826 ULONG i;
1827
1828 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, BaseAddress);
1829 Segment = MemoryArea->Data.SectionData.Segment;
1830
1831 if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1832 (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
1833 {
1834 DoCOW = TRUE;
1835 }
1836
1837 if (OldProtect != NewProtect)
1838 {
1839 for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
1840 {
1841 PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
1842 ULONG Protect = NewProtect;
1843
1844 /*
1845 * If we doing COW for this segment then check if the page is
1846 * already private.
1847 */
1848 if (DoCOW && MmIsPagePresent(AddressSpace->Process, Address))
1849 {
1850 ULONG Offset;
1851 ULONG Entry;
1852 PFN_TYPE Page;
1853
1854 Offset = (ULONG)Address - (ULONG)MemoryArea->BaseAddress;
1855 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1856 Page = MmGetPfnForProcess(AddressSpace->Process, Address);
1857
1858 Protect = PAGE_READONLY;
1859 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1860 IS_SWAP_FROM_SSE(Entry) ||
1861 PFN_FROM_SSE(Entry) != Page)
1862 {
1863 Protect = NewProtect;
1864 }
1865 }
1866
1867 if (MmIsPagePresent(AddressSpace->Process, Address))
1868 {
1869 MmSetPageProtect(AddressSpace->Process, Address,
1870 Protect);
1871 }
1872 }
1873 }
1874 }
1875
1876 NTSTATUS
1877 MmProtectSectionView(PMADDRESS_SPACE AddressSpace,
1878 PMEMORY_AREA MemoryArea,
1879 PVOID BaseAddress,
1880 ULONG Length,
1881 ULONG Protect,
1882 PULONG OldProtect)
1883 {
1884 PMM_REGION Region;
1885 NTSTATUS Status;
1886
1887 Length =
1888 min(Length, (ULONG) ((char*)MemoryArea->BaseAddress + MemoryArea->Length - (char*)BaseAddress));
1889 Region = MmFindRegion(MemoryArea->BaseAddress,
1890 &MemoryArea->Data.SectionData.RegionListHead,
1891 BaseAddress, NULL);
1892 *OldProtect = Region->Protect;
1893 Status = MmAlterRegion(AddressSpace, MemoryArea->BaseAddress,
1894 &MemoryArea->Data.SectionData.RegionListHead,
1895 BaseAddress, Length, Region->Type, Protect,
1896 MmAlterViewAttributes);
1897
1898 return(Status);
1899 }
1900
1901 NTSTATUS STDCALL
1902 MmQuerySectionView(PMEMORY_AREA MemoryArea,
1903 PVOID Address,
1904 PMEMORY_BASIC_INFORMATION Info,
1905 PULONG ResultLength)
1906 {
1907 PMM_REGION Region;
1908 PVOID RegionBaseAddress;
1909 PSECTION_OBJECT Section;
1910 PLIST_ENTRY CurrentEntry;
1911 PMEMORY_AREA CurrentMArea;
1912 KIRQL oldIrql;
1913
1914 Region = MmFindRegion(MemoryArea->BaseAddress,
1915 &MemoryArea->Data.SectionData.RegionListHead,
1916 Address, &RegionBaseAddress);
1917 if (Region == NULL)
1918 {
1919 return STATUS_UNSUCCESSFUL;
1920 }
1921 Section = MemoryArea->Data.SectionData.Section;
1922 if (Section->AllocationAttributes & SEC_IMAGE)
1923 {
1924 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
1925 CurrentEntry = Section->ViewListHead.Flink;
1926 Info->AllocationBase = NULL;
1927 while (CurrentEntry != &Section->ViewListHead)
1928 {
1929 CurrentMArea = CONTAINING_RECORD(CurrentEntry, MEMORY_AREA, Data.SectionData.ViewListEntry);
1930 CurrentEntry = CurrentEntry->Flink;
1931 if (Info->AllocationBase == NULL)
1932 {
1933 Info->AllocationBase = CurrentMArea->BaseAddress;
1934 }
1935 else if (CurrentMArea->BaseAddress < Info->AllocationBase)
1936 {
1937 Info->AllocationBase = CurrentMArea->BaseAddress;
1938 }
1939 }
1940 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
1941 Info->BaseAddress = RegionBaseAddress;
1942 Info->AllocationProtect = MemoryArea->Attributes;
1943 Info->Type = MEM_IMAGE;
1944 }
1945 else
1946 {
1947 Info->BaseAddress = RegionBaseAddress;
1948 Info->AllocationBase = MemoryArea->BaseAddress;
1949 Info->AllocationProtect = MemoryArea->Attributes;
1950 Info->Type = MEM_MAPPED;
1951 }
1952 Info->RegionSize = PAGE_ROUND_UP(MemoryArea->Length);
1953 Info->State = MEM_COMMIT;
1954 Info->Protect = Region->Protect;
1955
1956 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
1957 return(STATUS_SUCCESS);
1958 }
1959
1960 VOID
1961 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
1962 {
1963 ULONG Length;
1964 ULONG Offset;
1965 ULONG Entry;
1966 ULONG SavedSwapEntry;
1967 PFN_TYPE Page;
1968
1969 Page = 0;
1970
1971 Length = PAGE_ROUND_UP(Segment->Length);
1972 for (Offset = 0; Offset < Length; Offset += PAGE_SIZE)
1973 {
1974 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1975 if (Entry)
1976 {
1977 if (IS_SWAP_FROM_SSE(Entry))
1978 {
1979 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
1980 }
1981 else
1982 {
1983 Page = PFN_FROM_SSE(Entry);
1984 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
1985 if (SavedSwapEntry != 0)
1986 {
1987 MmSetSavedSwapEntryPage(Page, 0);
1988 MmFreeSwapPage(SavedSwapEntry);
1989 }
1990 MmReleasePageMemoryConsumer(MC_USER, Page);
1991 }
1992 MmSetPageEntrySectionSegment(Segment, Offset, 0);
1993 }
1994 }
1995 }
1996
1997 VOID STDCALL
1998 MmpDeleteSection(PVOID ObjectBody)
1999 {
2000 PSECTION_OBJECT Section = (PSECTION_OBJECT)ObjectBody;
2001
2002 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
2003 if (Section->AllocationAttributes & SEC_IMAGE)
2004 {
2005 ULONG i;
2006 ULONG NrSegments;
2007 ULONG RefCount;
2008 PMM_SECTION_SEGMENT SectionSegments;
2009
2010 SectionSegments = Section->ImageSection->Segments;
2011 NrSegments = Section->ImageSection->NrSegments;
2012
2013 for (i = 0; i < NrSegments; i++)
2014 {
2015 if (SectionSegments[i].Characteristics & IMAGE_SECTION_CHAR_SHARED)
2016 {
2017 MmLockSectionSegment(&SectionSegments[i]);
2018 }
2019 RefCount = InterlockedDecrement((LONG *)&SectionSegments[i].ReferenceCount);
2020 if (SectionSegments[i].Characteristics & IMAGE_SECTION_CHAR_SHARED)
2021 {
2022 if (RefCount == 0)
2023 {
2024 MmpFreePageFileSegment(&SectionSegments[i]);
2025 }
2026 MmUnlockSectionSegment(&SectionSegments[i]);
2027 }
2028 }
2029 }
2030 else
2031 {
2032 if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
2033 {
2034 MmpFreePageFileSegment(Section->Segment);
2035 MmFreePageTablesSectionSegment(Section->Segment);
2036 ExFreePool(Section->Segment);
2037 Section->Segment = NULL;
2038 }
2039 else
2040 {
2041 InterlockedDecrement((LONG *)&Section->Segment->ReferenceCount);
2042 }
2043 }
2044 if (Section->FileObject != NULL)
2045 {
2046 CcRosDereferenceCache(Section->FileObject);
2047 ObDereferenceObject(Section->FileObject);
2048 Section->FileObject = NULL;
2049 }
2050 }
2051
2052 VOID STDCALL
2053 MmpCloseSection(PVOID ObjectBody,
2054 ULONG HandleCount)
2055 {
2056 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2057 ObjectBody, HandleCount, ObGetObjectPointerCount(ObjectBody));
2058 }
2059
2060 NTSTATUS STDCALL
2061 MmpCreateSection(PVOID ObjectBody,
2062 PVOID Parent,
2063 PWSTR RemainingPath,
2064 POBJECT_ATTRIBUTES ObjectAttributes)
2065 {
2066 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2067 ObjectBody, Parent, RemainingPath);
2068
2069 if (RemainingPath == NULL)
2070 {
2071 return(STATUS_SUCCESS);
2072 }
2073
2074 if (wcschr(RemainingPath+1, L'\\') != NULL)
2075 {
2076 return(STATUS_UNSUCCESSFUL);
2077 }
2078 return(STATUS_SUCCESS);
2079 }
2080
2081 NTSTATUS INIT_FUNCTION
2082 MmCreatePhysicalMemorySection(VOID)
2083 {
2084 PSECTION_OBJECT PhysSection;
2085 NTSTATUS Status;
2086 OBJECT_ATTRIBUTES Obj;
2087 UNICODE_STRING Name = ROS_STRING_INITIALIZER(L"\\Device\\PhysicalMemory");
2088 LARGE_INTEGER SectionSize;
2089
2090 /*
2091 * Create the section mapping physical memory
2092 */
2093 SectionSize.QuadPart = 0xFFFFFFFF;
2094 InitializeObjectAttributes(&Obj,
2095 &Name,
2096 0,
2097 NULL,
2098 NULL);
2099 Status = MmCreateSection(&PhysSection,
2100 SECTION_ALL_ACCESS,
2101 &Obj,
2102 &SectionSize,
2103 PAGE_EXECUTE_READWRITE,
2104 0,
2105 NULL,
2106 NULL);
2107 if (!NT_SUCCESS(Status))
2108 {
2109 DbgPrint("Failed to create PhysicalMemory section\n");
2110 KEBUGCHECK(0);
2111 }
2112 PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
2113
2114 return(STATUS_SUCCESS);
2115 }
2116
2117 NTSTATUS INIT_FUNCTION
2118 MmInitSectionImplementation(VOID)
2119 {
2120 MmSectionObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
2121
2122 RtlRosInitUnicodeStringFromLiteral(&MmSectionObjectType->TypeName, L"Section");
2123
2124 MmSectionObjectType->Tag = TAG('S', 'E', 'C', 'T');
2125 MmSectionObjectType->TotalObjects = 0;
2126 MmSectionObjectType->TotalHandles = 0;
2127 MmSectionObjectType->MaxObjects = ULONG_MAX;
2128 MmSectionObjectType->MaxHandles = ULONG_MAX;
2129 MmSectionObjectType->PagedPoolCharge = 0;
2130 MmSectionObjectType->NonpagedPoolCharge = sizeof(SECTION_OBJECT);
2131 MmSectionObjectType->Mapping = &MmpSectionMapping;
2132 MmSectionObjectType->Dump = NULL;
2133 MmSectionObjectType->Open = NULL;
2134 MmSectionObjectType->Close = MmpCloseSection;
2135 MmSectionObjectType->Delete = MmpDeleteSection;
2136 MmSectionObjectType->Parse = NULL;
2137 MmSectionObjectType->Security = NULL;
2138 MmSectionObjectType->QueryName = NULL;
2139 MmSectionObjectType->OkayToClose = NULL;
2140 MmSectionObjectType->Create = MmpCreateSection;
2141 MmSectionObjectType->DuplicationNotify = NULL;
2142
2143 /*
2144 * NOTE: Do not register the section object type here because
2145 * the object manager it not initialized yet!
2146 * The section object type will be created in ObInit().
2147 */
2148 ObpCreateTypeObject(MmSectionObjectType);
2149
2150 return(STATUS_SUCCESS);
2151 }
2152
2153 NTSTATUS
2154 MmCreatePageFileSection(PSECTION_OBJECT *SectionObject,
2155 ACCESS_MASK DesiredAccess,
2156 POBJECT_ATTRIBUTES ObjectAttributes,
2157 PLARGE_INTEGER UMaximumSize,
2158 ULONG SectionPageProtection,
2159 ULONG AllocationAttributes)
2160 /*
2161 * Create a section which is backed by the pagefile
2162 */
2163 {
2164 LARGE_INTEGER MaximumSize;
2165 PSECTION_OBJECT Section;
2166 PMM_SECTION_SEGMENT Segment;
2167 NTSTATUS Status;
2168
2169 if (UMaximumSize == NULL)
2170 {
2171 return(STATUS_UNSUCCESSFUL);
2172 }
2173 MaximumSize = *UMaximumSize;
2174
2175 /*
2176 * Check the protection
2177 */
2178 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
2179 SectionPageProtection)
2180 {
2181 return(STATUS_INVALID_PAGE_PROTECTION);
2182 }
2183
2184 /*
2185 * Create the section
2186 */
2187 Status = ObCreateObject(ExGetPreviousMode(),
2188 MmSectionObjectType,
2189 ObjectAttributes,
2190 ExGetPreviousMode(),
2191 NULL,
2192 sizeof(SECTION_OBJECT),
2193 0,
2194 0,
2195 (PVOID*)&Section);
2196 if (!NT_SUCCESS(Status))
2197 {
2198 return(Status);
2199 }
2200
2201 /*
2202 * Initialize it
2203 */
2204 Section->SectionPageProtection = SectionPageProtection;
2205 Section->AllocationAttributes = AllocationAttributes;
2206 InitializeListHead(&Section->ViewListHead);
2207 KeInitializeSpinLock(&Section->ViewListLock);
2208 Section->FileObject = NULL;
2209 Section->MaximumSize = MaximumSize;
2210 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2211 TAG_MM_SECTION_SEGMENT);
2212 if (Segment == NULL)
2213 {
2214 ObDereferenceObject(Section);
2215 return(STATUS_NO_MEMORY);
2216 }
2217 Section->Segment = Segment;
2218 Segment->ReferenceCount = 1;
2219 ExInitializeFastMutex(&Segment->Lock);
2220 Segment->FileOffset = 0;
2221 Segment->Protection = SectionPageProtection;
2222 Segment->Attributes = AllocationAttributes;
2223 Segment->RawLength = MaximumSize.u.LowPart;
2224 Segment->Length = PAGE_ROUND_UP(MaximumSize.u.LowPart);
2225 Segment->Flags = MM_PAGEFILE_SEGMENT;
2226 Segment->WriteCopy = FALSE;
2227 RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
2228 Segment->VirtualAddress = 0;
2229 Segment->Characteristics = 0;
2230 *SectionObject = Section;
2231 return(STATUS_SUCCESS);
2232 }
2233
2234
2235 NTSTATUS
2236 MmCreateDataFileSection(PSECTION_OBJECT *SectionObject,
2237 ACCESS_MASK DesiredAccess,
2238 POBJECT_ATTRIBUTES ObjectAttributes,
2239 PLARGE_INTEGER UMaximumSize,
2240 ULONG SectionPageProtection,
2241 ULONG AllocationAttributes,
2242 HANDLE FileHandle)
2243 /*
2244 * Create a section backed by a data file
2245 */
2246 {
2247 PSECTION_OBJECT Section;
2248 NTSTATUS Status;
2249 LARGE_INTEGER MaximumSize;
2250 PFILE_OBJECT FileObject;
2251 PMM_SECTION_SEGMENT Segment;
2252 ULONG FileAccess;
2253 IO_STATUS_BLOCK Iosb;
2254 LARGE_INTEGER Offset;
2255 CHAR Buffer;
2256
2257 /*
2258 * Check the protection
2259 */
2260 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
2261 SectionPageProtection)
2262 {
2263 return(STATUS_INVALID_PAGE_PROTECTION);
2264 }
2265 /*
2266 * Create the section
2267 */
2268 Status = ObCreateObject(ExGetPreviousMode(),
2269 MmSectionObjectType,
2270 ObjectAttributes,
2271 ExGetPreviousMode(),
2272 NULL,
2273 sizeof(SECTION_OBJECT),
2274 0,
2275 0,
2276 (PVOID*)&Section);
2277 if (!NT_SUCCESS(Status))
2278 {
2279 return(Status);
2280 }
2281
2282 /*
2283 * Initialize it
2284 */
2285 Section->SectionPageProtection = SectionPageProtection;
2286 Section->AllocationAttributes = AllocationAttributes;
2287 InitializeListHead(&Section->ViewListHead);
2288 KeInitializeSpinLock(&Section->ViewListLock);
2289
2290 /*
2291 * Check file access required
2292 */
2293 if (SectionPageProtection & PAGE_READWRITE ||
2294 SectionPageProtection & PAGE_EXECUTE_READWRITE)
2295 {
2296 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2297 }
2298 else
2299 {
2300 FileAccess = FILE_READ_DATA;
2301 }
2302
2303 /*
2304 * Reference the file handle
2305 */
2306 Status = ObReferenceObjectByHandle(FileHandle,
2307 FileAccess,
2308 IoFileObjectType,
2309 UserMode,
2310 (PVOID*)&FileObject,
2311 NULL);
2312 if (!NT_SUCCESS(Status))
2313 {
2314 ObDereferenceObject(Section);
2315 return(Status);
2316 }
2317
2318 /*
2319 * We can't do memory mappings if the file system doesn't support the
2320 * standard FCB
2321 */
2322 if (!(FileObject->Flags & FO_FCB_IS_VALID))
2323 {
2324 ObDereferenceObject(Section);
2325 ObDereferenceObject(FileObject);
2326 return(STATUS_INVALID_FILE_FOR_SECTION);
2327 }
2328
2329 /*
2330 * FIXME: Revise this once a locking order for file size changes is
2331 * decided
2332 */
2333 if (UMaximumSize != NULL)
2334 {
2335 MaximumSize = *UMaximumSize;
2336 }
2337 else
2338 {
2339 MaximumSize =
2340 ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize;
2341 }
2342
2343 if (MaximumSize.QuadPart >
2344 ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize.QuadPart)
2345 {
2346 Status = NtSetInformationFile(FileHandle,
2347 &Iosb,
2348 &MaximumSize,
2349 sizeof(LARGE_INTEGER),
2350 FileAllocationInformation);
2351 if (!NT_SUCCESS(Status))
2352 {
2353 ObDereferenceObject(Section);
2354 ObDereferenceObject(FileObject);
2355 return(STATUS_SECTION_NOT_EXTENDED);
2356 }
2357 }
2358
2359 if (FileObject->SectionObjectPointer == NULL ||
2360 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
2361 {
2362 /*
2363 * Read a bit so caching is initiated for the file object.
2364 * This is only needed because MiReadPage currently cannot
2365 * handle non-cached streams.
2366 */
2367 Offset.QuadPart = 0;
2368 Status = ZwReadFile(FileHandle,
2369 NULL,
2370 NULL,
2371 NULL,
2372 &Iosb,
2373 &Buffer,
2374 sizeof (Buffer),
2375 &Offset,
2376 0);
2377 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
2378 {
2379 ObDereferenceObject(Section);
2380 ObDereferenceObject(FileObject);
2381 return(Status);
2382 }
2383 if (FileObject->SectionObjectPointer == NULL ||
2384 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
2385 {
2386 /* FIXME: handle this situation */
2387 ObDereferenceObject(Section);
2388 ObDereferenceObject(FileObject);
2389 return STATUS_INVALID_PARAMETER;
2390 }
2391 }
2392
2393 /*
2394 * Lock the file
2395 */
2396 Status = MmspWaitForFileLock(FileObject);
2397 if (Status != STATUS_SUCCESS)
2398 {
2399 ObDereferenceObject(Section);
2400 ObDereferenceObject(FileObject);
2401 return(Status);
2402 }
2403
2404 /*
2405 * If this file hasn't been mapped as a data file before then allocate a
2406 * section segment to describe the data file mapping
2407 */
2408 if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
2409 {
2410 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2411 TAG_MM_SECTION_SEGMENT);
2412 if (Segment == NULL)
2413 {
2414 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2415 ObDereferenceObject(Section);
2416 ObDereferenceObject(FileObject);
2417 return(STATUS_NO_MEMORY);
2418 }
2419 Section->Segment = Segment;
2420 Segment->ReferenceCount = 1;
2421 ExInitializeFastMutex(&Segment->Lock);
2422 /*
2423 * Set the lock before assigning the segment to the file object
2424 */
2425 ExAcquireFastMutex(&Segment->Lock);
2426 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
2427
2428 Segment->FileOffset = 0;
2429 Segment->Protection = SectionPageProtection;
2430 Segment->Attributes = 0;
2431 Segment->Flags = MM_DATAFILE_SEGMENT;
2432 Segment->Characteristics = 0;
2433 Segment->WriteCopy = FALSE;
2434 if (AllocationAttributes & SEC_RESERVE)
2435 {
2436 Segment->Length = Segment->RawLength = 0;
2437 }
2438 else
2439 {
2440 Segment->RawLength = MaximumSize.u.LowPart;
2441 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
2442 }
2443 Segment->VirtualAddress = NULL;
2444 RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
2445 }
2446 else
2447 {
2448 /*
2449 * If the file is already mapped as a data file then we may need
2450 * to extend it
2451 */
2452 Segment =
2453 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
2454 DataSectionObject;
2455 Section->Segment = Segment;
2456 InterlockedIncrement((PLONG)&Segment->ReferenceCount);
2457 MmLockSectionSegment(Segment);
2458
2459 if (MaximumSize.u.LowPart > Segment->RawLength &&
2460 !(AllocationAttributes & SEC_RESERVE))
2461 {
2462 Segment->RawLength = MaximumSize.u.LowPart;
2463 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
2464 }
2465 }
2466 MmUnlockSectionSegment(Segment);
2467 Section->FileObject = FileObject;
2468 Section->MaximumSize = MaximumSize;
2469 CcRosReferenceCache(FileObject);
2470 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2471 *SectionObject = Section;
2472 return(STATUS_SUCCESS);
2473 }
2474
2475 static ULONG SectionCharacteristicsToProtect[16] =
2476 {
2477 PAGE_NOACCESS, // 0 = NONE
2478 PAGE_NOACCESS, // 1 = SHARED
2479 PAGE_EXECUTE, // 2 = EXECUTABLE
2480 PAGE_EXECUTE, // 3 = EXECUTABLE, SHARED
2481 PAGE_READONLY, // 4 = READABLE
2482 PAGE_READONLY, // 5 = READABLE, SHARED
2483 PAGE_EXECUTE_READ, // 6 = READABLE, EXECUTABLE
2484 PAGE_EXECUTE_READ, // 7 = READABLE, EXECUTABLE, SHARED
2485 PAGE_READWRITE, // 8 = WRITABLE
2486 PAGE_READWRITE, // 9 = WRITABLE, SHARED
2487 PAGE_EXECUTE_READWRITE, // 10 = WRITABLE, EXECUTABLE
2488 PAGE_EXECUTE_READWRITE, // 11 = WRITABLE, EXECUTABLE, SHARED
2489 PAGE_READWRITE, // 12 = WRITABLE, READABLE
2490 PAGE_READWRITE, // 13 = WRITABLE, READABLE, SHARED
2491 PAGE_EXECUTE_READWRITE, // 14 = WRITABLE, READABLE, EXECUTABLE,
2492 PAGE_EXECUTE_READWRITE, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2493 };
2494
2495 NTSTATUS
2496 MmCreateImageSection(PSECTION_OBJECT *SectionObject,
2497 ACCESS_MASK DesiredAccess,
2498 POBJECT_ATTRIBUTES ObjectAttributes,
2499 PLARGE_INTEGER UMaximumSize,
2500 ULONG SectionPageProtection,
2501 ULONG AllocationAttributes,
2502 HANDLE FileHandle)
2503 {
2504 PSECTION_OBJECT Section;
2505 NTSTATUS Status;
2506 PFILE_OBJECT FileObject;
2507 IMAGE_DOS_HEADER DosHeader;
2508 IO_STATUS_BLOCK Iosb;
2509 LARGE_INTEGER Offset;
2510 IMAGE_NT_HEADERS PEHeader;
2511 PMM_SECTION_SEGMENT SectionSegments;
2512 ULONG NrSegments;
2513 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
2514 ULONG i;
2515 ULONG Size;
2516 ULONG Characteristics;
2517 ULONG FileAccess = 0;
2518 /*
2519 * Check the protection
2520 */
2521 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
2522 SectionPageProtection)
2523 {
2524 return(STATUS_INVALID_PAGE_PROTECTION);
2525 }
2526
2527 /*
2528 * Specifying a maximum size is meaningless for an image section
2529 */
2530 if (UMaximumSize != NULL)
2531 {
2532 return(STATUS_INVALID_PARAMETER_4);
2533 }
2534
2535 /*
2536 * Reference the file handle
2537 */
2538 Status = ObReferenceObjectByHandle(FileHandle,
2539 FileAccess,
2540 IoFileObjectType,
2541 UserMode,
2542 (PVOID*)&FileObject,
2543 NULL);
2544 if (!NT_SUCCESS(Status))
2545 {
2546 return Status;
2547 }
2548
2549 /*
2550 * Initialized caching for this file object if previously caching
2551 * was initialized for the same on disk file
2552 */
2553 Status = CcTryToInitializeFileCache(FileObject);
2554
2555 if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
2556 {
2557 PIMAGE_SECTION_HEADER ImageSections;
2558 /*
2559 * Read the dos header and check the DOS signature
2560 */
2561 Offset.QuadPart = 0;
2562 Status = ZwReadFile(FileHandle,
2563 NULL,
2564 NULL,
2565 NULL,
2566 &Iosb,
2567 &DosHeader,
2568 sizeof(DosHeader),
2569 &Offset,
2570 NULL);
2571 if (!NT_SUCCESS(Status))
2572 {
2573 ObDereferenceObject(FileObject);
2574 return(Status);
2575 }
2576
2577 /*
2578 * Check the DOS signature
2579 */
2580 if (Iosb.Information != sizeof(DosHeader) ||
2581 DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
2582 {
2583 ObDereferenceObject(FileObject);
2584 return(STATUS_INVALID_IMAGE_FORMAT);
2585 }
2586
2587 /*
2588 * Read the PE header
2589 */
2590 Offset.QuadPart = DosHeader.e_lfanew;
2591 Status = ZwReadFile(FileHandle,
2592 NULL,
2593 NULL,
2594 NULL,
2595 &Iosb,
2596 &PEHeader,
2597 sizeof(PEHeader),
2598 &Offset,
2599 NULL);
2600 if (!NT_SUCCESS(Status))
2601 {
2602 ObDereferenceObject(FileObject);
2603 return(Status);
2604 }
2605
2606 /*
2607 * Check the signature
2608 */
2609 if (Iosb.Information != sizeof(PEHeader) ||
2610 PEHeader.Signature != IMAGE_NT_SIGNATURE)
2611 {
2612 ObDereferenceObject(FileObject);
2613 return(STATUS_INVALID_IMAGE_FORMAT);
2614 }
2615
2616 /*
2617 * Read in the section headers
2618 */
2619 Offset.QuadPart = DosHeader.e_lfanew + sizeof(PEHeader);
2620 ImageSections = ExAllocatePool(NonPagedPool,
2621 PEHeader.FileHeader.NumberOfSections *
2622 sizeof(IMAGE_SECTION_HEADER));
2623 if (ImageSections == NULL)
2624 {
2625 ObDereferenceObject(FileObject);
2626 return(STATUS_NO_MEMORY);
2627 }
2628
2629 Status = ZwReadFile(FileHandle,
2630 NULL,
2631 NULL,
2632 NULL,
2633 &Iosb,
2634 ImageSections,
2635 PEHeader.FileHeader.NumberOfSections *
2636 sizeof(IMAGE_SECTION_HEADER),
2637 &Offset,
2638 0);
2639 if (!NT_SUCCESS(Status))
2640 {
2641 ObDereferenceObject(FileObject);
2642 ExFreePool(ImageSections);
2643 return(Status);
2644 }
2645 if (Iosb.Information != (PEHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
2646 {
2647 ObDereferenceObject(FileObject);
2648 ExFreePool(ImageSections);
2649 return(STATUS_INVALID_IMAGE_FORMAT);
2650 }
2651
2652 /*
2653 * Create the section
2654 */
2655 Status = ObCreateObject (ExGetPreviousMode(),
2656 MmSectionObjectType,
2657 ObjectAttributes,
2658 ExGetPreviousMode(),
2659 NULL,
2660 sizeof(SECTION_OBJECT),
2661 0,
2662 0,
2663 (PVOID*)&Section);
2664 if (!NT_SUCCESS(Status))
2665 {
2666 ObDereferenceObject(FileObject);
2667 ExFreePool(ImageSections);
2668 return(Status);
2669 }
2670
2671 /*
2672 * Initialize it
2673 */
2674 Section->SectionPageProtection = SectionPageProtection;
2675 Section->AllocationAttributes = AllocationAttributes;
2676 InitializeListHead(&Section->ViewListHead);
2677 KeInitializeSpinLock(&Section->ViewListLock);
2678
2679 /*
2680 * Check file access required
2681 */
2682 if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
2683 {
2684 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2685 }
2686 else
2687 {
2688 FileAccess = FILE_READ_DATA;
2689 }
2690
2691 /*
2692 * We can't do memory mappings if the file system doesn't support the
2693 * standard FCB
2694 */
2695 if (!(FileObject->Flags & FO_FCB_IS_VALID))
2696 {
2697 ObDereferenceObject(Section);
2698 ObDereferenceObject(FileObject);
2699 ExFreePool(ImageSections);
2700 return(STATUS_INVALID_FILE_FOR_SECTION);
2701 }
2702
2703 /*
2704 * Lock the file
2705 */
2706 Status = MmspWaitForFileLock(FileObject);
2707 if (Status != STATUS_SUCCESS)
2708 {
2709 ObDereferenceObject(Section);
2710 ObDereferenceObject(FileObject);
2711 ExFreePool(ImageSections);
2712 return(Status);
2713 }
2714
2715 /*
2716 * allocate the section segments to describe the mapping
2717 */
2718 NrSegments = PEHeader.FileHeader.NumberOfSections + 1;
2719 Size = sizeof(MM_IMAGE_SECTION_OBJECT) + sizeof(MM_SECTION_SEGMENT) * NrSegments;
2720 ImageSectionObject = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MM_SECTION_SEGMENT);
2721 if (ImageSectionObject == NULL)
2722 {
2723 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2724 ObDereferenceObject(Section);
2725 ObDereferenceObject(FileObject);
2726 ExFreePool(ImageSections);
2727 return(STATUS_NO_MEMORY);
2728 }
2729 Section->ImageSection = ImageSectionObject;
2730 ImageSectionObject->NrSegments = NrSegments;
2731 ImageSectionObject->ImageBase = (PVOID)PEHeader.OptionalHeader.ImageBase;
2732 ImageSectionObject->EntryPoint = (PVOID)PEHeader.OptionalHeader.AddressOfEntryPoint;
2733 ImageSectionObject->StackReserve = PEHeader.OptionalHeader.SizeOfStackReserve;
2734 ImageSectionObject->StackCommit = PEHeader.OptionalHeader.SizeOfStackCommit;
2735 ImageSectionObject->Subsystem = PEHeader.OptionalHeader.Subsystem;
2736 ImageSectionObject->MinorSubsystemVersion = PEHeader.OptionalHeader.MinorSubsystemVersion;
2737 ImageSectionObject->MajorSubsystemVersion = PEHeader.OptionalHeader.MajorSubsystemVersion;
2738 ImageSectionObject->ImageCharacteristics = PEHeader.FileHeader.Characteristics;
2739 ImageSectionObject->Machine = PEHeader.FileHeader.Machine;
2740 ImageSectionObject->Executable = (PEHeader.OptionalHeader.SizeOfCode != 0);
2741
2742 SectionSegments = ImageSectionObject->Segments;
2743 SectionSegments[0].FileOffset = 0;
2744 SectionSegments[0].Characteristics = IMAGE_SECTION_CHAR_DATA;
2745 SectionSegments[0].Protection = PAGE_READONLY;
2746 SectionSegments[0].RawLength = PAGE_SIZE;
2747 SectionSegments[0].Length = PAGE_SIZE;
2748 SectionSegments[0].Flags = 0;
2749 SectionSegments[0].ReferenceCount = 1;
2750 SectionSegments[0].VirtualAddress = 0;
2751 SectionSegments[0].WriteCopy = TRUE;
2752 SectionSegments[0].Attributes = 0;
2753 ExInitializeFastMutex(&SectionSegments[0].Lock);
2754 RtlZeroMemory(&SectionSegments[0].PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
2755 for (i = 1; i < NrSegments; i++)
2756 {
2757 SectionSegments[i].FileOffset = ImageSections[i-1].PointerToRawData;
2758 SectionSegments[i].Characteristics = ImageSections[i-1].Characteristics;
2759
2760 /*
2761 * Set up the protection and write copy variables.
2762 */
2763 Characteristics = ImageSections[i - 1].Characteristics;
2764 if (Characteristics & (IMAGE_SECTION_CHAR_READABLE|IMAGE_SECTION_CHAR_WRITABLE|IMAGE_SECTION_CHAR_EXECUTABLE))
2765 {
2766 SectionSegments[i].Protection = SectionCharacteristicsToProtect[Characteristics >> 28];
2767 SectionSegments[i].WriteCopy = !(Characteristics & IMAGE_SECTION_CHAR_SHARED);
2768 }
2769 else if (Characteristics & IMAGE_SECTION_CHAR_CODE)
2770 {
2771 SectionSegments[i].Protection = PAGE_EXECUTE_READ;
2772 SectionSegments[i].WriteCopy = TRUE;
2773 }
2774 else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
2775 {
2776 SectionSegments[i].Protection = PAGE_READWRITE;
2777 SectionSegments[i].WriteCopy = TRUE;
2778 }
2779 else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
2780 {
2781 SectionSegments[i].Protection = PAGE_READWRITE;
2782 SectionSegments[i].WriteCopy = TRUE;
2783 }
2784 else
2785 {
2786 SectionSegments[i].Protection = PAGE_NOACCESS;
2787 SectionSegments[i].WriteCopy = TRUE;
2788 }
2789
2790 /*
2791 * Set up the attributes.
2792 */
2793 if (Characteristics & IMAGE_SECTION_CHAR_CODE)
2794 {
2795 SectionSegments[i].Attributes = 0;
2796 }
2797 else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
2798 {
2799 SectionSegments[i].Attributes = 0;
2800 }
2801 else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
2802 {
2803 SectionSegments[i].Attributes = MM_SECTION_SEGMENT_BSS;
2804 }
2805 else
2806 {
2807 SectionSegments[i].Attributes = 0;
2808 }
2809
2810 SectionSegments[i].RawLength = ImageSections[i-1].SizeOfRawData;
2811 if (ImageSections[i-1].Misc.VirtualSize != 0)
2812 {
2813 SectionSegments[i].Length = ImageSections[i-1].Misc.VirtualSize;
2814 }
2815 else
2816 {
2817 SectionSegments[i].Length = ImageSections[i-1].SizeOfRawData;
2818 }
2819 SectionSegments[i].Flags = 0;
2820 SectionSegments[i].ReferenceCount = 1;
2821 SectionSegments[i].VirtualAddress = (PVOID)ImageSections[i-1].VirtualAddress;
2822 ExInitializeFastMutex(&SectionSegments[i].Lock);
2823 RtlZeroMemory(&SectionSegments[i].PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
2824 }
2825 if (0 != InterlockedCompareExchange((PLONG)&FileObject->SectionObjectPointer->ImageSectionObject,
2826 (LONG)ImageSectionObject, 0))
2827 {
2828 /*
2829 * An other thread has initialized the some image in the background
2830 */
2831 ExFreePool(ImageSectionObject);
2832 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
2833 Section->ImageSection = ImageSectionObject;
2834 SectionSegments = ImageSectionObject->Segments;
2835
2836 for (i = 0; i < NrSegments; i++)
2837 {
2838 InterlockedIncrement((LONG *)&SectionSegments[i].ReferenceCount);
2839 }
2840 }
2841 ExFreePool(ImageSections);
2842 }
2843 else
2844 {
2845 /*
2846 * Create the section
2847 */
2848 Status = ObCreateObject (ExGetPreviousMode(),
2849 MmSectionObjectType,
2850 ObjectAttributes,
2851 ExGetPreviousMode(),
2852 NULL,
2853 sizeof(SECTION_OBJECT),
2854 0,
2855 0,
2856 (PVOID*)&Section);
2857 if (!NT_SUCCESS(Status))
2858 {
2859 ObDereferenceObject(FileObject);
2860 return(Status);
2861 }
2862
2863 /*
2864 * Initialize it
2865 */
2866 Section->SectionPageProtection = SectionPageProtection;
2867 Section->AllocationAttributes = AllocationAttributes;
2868 InitializeListHead(&Section->ViewListHead);
2869 KeInitializeSpinLock(&Section->ViewListLock);
2870
2871 /*
2872 * Check file access required
2873 */
2874 if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
2875 {
2876 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2877 }
2878 else
2879 {
2880 FileAccess = FILE_READ_DATA;
2881 }
2882
2883 /*
2884 * Lock the file
2885 */
2886 Status = MmspWaitForFileLock(FileObject);
2887 if (Status != STATUS_SUCCESS)
2888 {
2889 ObDereferenceObject(Section);
2890 ObDereferenceObject(FileObject);
2891 return(Status);
2892 }
2893
2894 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
2895 Section->ImageSection = ImageSectionObject;
2896 SectionSegments = ImageSectionObject->Segments;
2897 NrSegments = ImageSectionObject->NrSegments;
2898
2899 /*
2900 * Otherwise just reference all the section segments
2901 */
2902 for (i = 0; i < NrSegments; i++)
2903 {
2904 InterlockedIncrement((LONG *)&SectionSegments[i].ReferenceCount);
2905 }
2906
2907 }
2908 Section->FileObject = FileObject;
2909 CcRosReferenceCache(FileObject);
2910 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2911 *SectionObject = Section;
2912 return(STATUS_SUCCESS);
2913 }
2914
2915 /*
2916 * @implemented
2917 */
2918 NTSTATUS STDCALL
2919 NtCreateSection (OUT PHANDLE SectionHandle,
2920 IN ACCESS_MASK DesiredAccess,
2921 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
2922 IN PLARGE_INTEGER MaximumSize OPTIONAL,
2923 IN ULONG SectionPageProtection OPTIONAL,
2924 IN ULONG AllocationAttributes,
2925 IN HANDLE FileHandle OPTIONAL)
2926 {
2927 PSECTION_OBJECT SectionObject;
2928 NTSTATUS Status;
2929
2930 Status = MmCreateSection(&SectionObject,
2931 DesiredAccess,
2932 ObjectAttributes,
2933 MaximumSize,
2934 SectionPageProtection,
2935 AllocationAttributes,
2936 FileHandle,
2937 NULL);
2938
2939 if (NT_SUCCESS(Status))
2940 {
2941 Status = ObInsertObject ((PVOID)SectionObject,
2942 NULL,
2943 DesiredAccess,
2944 0,
2945 NULL,
2946 SectionHandle);
2947 ObDereferenceObject(SectionObject);
2948 }
2949
2950 return Status;
2951 }
2952
2953
2954 /**********************************************************************
2955 * NAME
2956 * NtOpenSection
2957 *
2958 * DESCRIPTION
2959 *
2960 * ARGUMENTS
2961 * SectionHandle
2962 *
2963 * DesiredAccess
2964 *
2965 * ObjectAttributes
2966 *
2967 * RETURN VALUE
2968 *
2969 * REVISIONS
2970 */
2971 NTSTATUS STDCALL
2972 NtOpenSection(PHANDLE SectionHandle,
2973 ACCESS_MASK DesiredAccess,
2974 POBJECT_ATTRIBUTES ObjectAttributes)
2975 {
2976 NTSTATUS Status;
2977
2978 *SectionHandle = 0;
2979
2980 Status = ObOpenObjectByName(ObjectAttributes,
2981 MmSectionObjectType,
2982 NULL,
2983 UserMode,
2984 DesiredAccess,
2985 NULL,
2986 SectionHandle);
2987
2988 return(Status);
2989 }
2990
2991 NTSTATUS STATIC
2992 MmMapViewOfSegment(PEPROCESS Process,
2993 PMADDRESS_SPACE AddressSpace,
2994 PSECTION_OBJECT Section,
2995 PMM_SECTION_SEGMENT Segment,
2996 PVOID* BaseAddress,
2997 ULONG ViewSize,
2998 ULONG Protect,
2999 ULONG ViewOffset,
3000 BOOL TopDown)
3001 {
3002 PMEMORY_AREA MArea;
3003 NTSTATUS Status;
3004 KIRQL oldIrql;
3005 PHYSICAL_ADDRESS BoundaryAddressMultiple;
3006
3007 BoundaryAddressMultiple.QuadPart = 0;
3008
3009 Status = MmCreateMemoryArea(Process,
3010 AddressSpace,
3011 MEMORY_AREA_SECTION_VIEW,
3012 BaseAddress,
3013 ViewSize,
3014 Protect,
3015 &MArea,
3016 FALSE,
3017 TopDown,
3018 BoundaryAddressMultiple);
3019 if (!NT_SUCCESS(Status))
3020 {
3021 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
3022 (*BaseAddress), (char*)(*BaseAddress) + ViewSize);
3023 return(Status);
3024 }
3025
3026 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
3027 InsertTailList(&Section->ViewListHead,
3028 &MArea->Data.SectionData.ViewListEntry);
3029 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
3030
3031 ObReferenceObjectByPointer((PVOID)Section,
3032 SECTION_MAP_READ,
3033 NULL,
3034 ExGetPreviousMode());
3035 MArea->Data.SectionData.Segment = Segment;
3036 MArea->Data.SectionData.Section = Section;
3037 MArea->Data.SectionData.ViewOffset = ViewOffset;
3038 MArea->Data.SectionData.WriteCopyView = FALSE;
3039 MmInitialiseRegion(&MArea->Data.SectionData.RegionListHead,
3040 ViewSize, 0, Protect);
3041
3042 return(STATUS_SUCCESS);
3043 }
3044
3045
3046 /**********************************************************************
3047 * NAME EXPORTED
3048 * NtMapViewOfSection
3049 *
3050 * DESCRIPTION
3051 * Maps a view of a section into the virtual address space of a
3052 * process.
3053 *
3054 * ARGUMENTS
3055 * SectionHandle
3056 * Handle of the section.
3057 *
3058 * ProcessHandle
3059 * Handle of the process.
3060 *
3061 * BaseAddress
3062 * Desired base address (or NULL) on entry;
3063 * Actual base address of the view on exit.
3064 *
3065 * ZeroBits
3066 * Number of high order address bits that must be zero.
3067 *
3068 * CommitSize
3069 * Size in bytes of the initially committed section of
3070 * the view.
3071 *
3072 * SectionOffset
3073 * Offset in bytes from the beginning of the section
3074 * to the beginning of the view.
3075 *
3076 * ViewSize
3077 * Desired length of map (or zero to map all) on entry
3078 * Actual length mapped on exit.
3079 *
3080 * InheritDisposition
3081 * Specified how the view is to be shared with
3082 * child processes.
3083 *
3084 * AllocateType
3085 * Type of allocation for the pages.
3086 *
3087 * Protect
3088 * Protection for the committed region of the view.
3089 *
3090 * RETURN VALUE
3091 * Status.
3092 *
3093 * @implemented
3094 */
3095 NTSTATUS STDCALL
3096 NtMapViewOfSection(HANDLE SectionHandle,
3097 HANDLE ProcessHandle,
3098 PVOID* BaseAddress,
3099 ULONG ZeroBits,
3100 ULONG CommitSize,
3101 PLARGE_INTEGER SectionOffset,
3102 PULONG ViewSize,
3103 SECTION_INHERIT InheritDisposition,
3104 ULONG AllocationType,
3105 ULONG Protect)
3106 {
3107 PSECTION_OBJECT Section;
3108 PEPROCESS Process;
3109 NTSTATUS Status;
3110 PMADDRESS_SPACE AddressSpace;
3111
3112 Status = ObReferenceObjectByHandle(ProcessHandle,
3113 PROCESS_VM_OPERATION,
3114 PsProcessType,
3115 UserMode,
3116 (PVOID*)&Process,
3117 NULL);
3118 if (!NT_SUCCESS(Status))
3119 {
3120 return(Status);
3121 }
3122
3123 AddressSpace = &Process->AddressSpace;
3124
3125 Status = ObReferenceObjectByHandle(SectionHandle,
3126 SECTION_MAP_READ,
3127 MmSectionObjectType,
3128 UserMode,
3129 (PVOID*)&Section,
3130 NULL);
3131 if (!(NT_SUCCESS(Status)))
3132 {
3133 DPRINT("ObReference failed rc=%x\n",Status);
3134 ObDereferenceObject(Process);
3135 return(Status);
3136 }
3137
3138 Status = MmMapViewOfSection(Section,
3139 Process,
3140 BaseAddress,
3141 ZeroBits,
3142 CommitSize,
3143 SectionOffset,
3144 ViewSize,
3145 InheritDisposition,
3146 AllocationType,
3147 Protect);
3148
3149 ObDereferenceObject(Section);
3150 ObDereferenceObject(Process);
3151
3152 return(Status);
3153 }
3154
3155 VOID STATIC
3156 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
3157 PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
3158 {
3159 PMEMORY_AREA MArea;
3160 ULONG Entry;
3161 PFILE_OBJECT FileObject;
3162 PBCB Bcb;
3163 ULONG Offset;
3164 SWAPENTRY SavedSwapEntry;
3165 PMM_PAGEOP PageOp;
3166 NTSTATUS Status;
3167 PSECTION_OBJECT Section;
3168 PMM_SECTION_SEGMENT Segment;
3169
3170 MArea = (PMEMORY_AREA)Context;
3171
3172 Address = (PVOID)PAGE_ROUND_DOWN(Address);
3173
3174 Offset = ((ULONG)Address - (ULONG)MArea->BaseAddress);
3175
3176 Section = MArea->Data.SectionData.Section;
3177 Segment = MArea->Data.SectionData.Segment;
3178
3179
3180 PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset);
3181
3182 while (PageOp)
3183 {
3184 MmUnlockSectionSegment(Segment);
3185 MmUnlockAddressSpace(&MArea->Process->AddressSpace);
3186
3187 Status = MmspWaitForPageOpCompletionEvent(PageOp);
3188 if (Status != STATUS_SUCCESS)
3189 {
3190 DPRINT1("Failed to wait for page op, status = %x\n", Status);
3191 KEBUGCHECK(0);
3192 }
3193
3194 MmLockAddressSpace(&MArea->Process->AddressSpace);
3195 MmLockSectionSegment(Segment);
3196 MmspCompleteAndReleasePageOp(PageOp);
3197 PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset);
3198 }
3199
3200 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
3201
3202 /*
3203 * For a dirty, datafile, non-private page mark it as dirty in the
3204 * cache manager.
3205 */
3206 if (Segment->Flags & MM_DATAFILE_SEGMENT)
3207 {
3208 if (Page == PFN_FROM_SSE(Entry) && Dirty)
3209 {
3210 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
3211 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
3212 CcRosMarkDirtyCacheSegment(Bcb, Offset);
3213 assert(SwapEntry == 0);
3214 }
3215 }
3216
3217 if (SwapEntry != 0)
3218 {
3219 /*
3220 * Sanity check
3221 */
3222 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3223 {
3224 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3225 KEBUGCHECK(0);
3226 }
3227 MmFreeSwapPage(SwapEntry);
3228 }
3229 else if (Page != 0)
3230 {
3231 if (IS_SWAP_FROM_SSE(Entry) ||
3232 Page != PFN_FROM_SSE(Entry))
3233 {
3234 /*
3235 * Sanity check
3236 */
3237 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3238 {
3239 DPRINT1("Found a private page in a pagefile section.\n");
3240 KEBUGCHECK(0);
3241 }
3242 /*
3243 * Just dereference private pages
3244 */
3245 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
3246 if (SavedSwapEntry != 0)
3247 {
3248 MmFreeSwapPage(SavedSwapEntry);
3249 MmSetSavedSwapEntryPage(Page, 0);
3250 }
3251 MmDeleteRmap(Page, MArea->Process, Address);
3252 MmReleasePageMemoryConsumer(MC_USER, Page);
3253 }
3254 else
3255 {
3256 MmDeleteRmap(Page, MArea->Process, Address);
3257 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty, FALSE);
3258 }
3259 }
3260 }
3261
3262 NTSTATUS
3263 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace,
3264 PVOID BaseAddress)
3265 {
3266 NTSTATUS Status;
3267 PMEMORY_AREA MemoryArea;
3268 PSECTION_OBJECT Section;
3269 PMM_SECTION_SEGMENT Segment;
3270 KIRQL oldIrql;
3271 PLIST_ENTRY CurrentEntry;
3272 PMM_REGION CurrentRegion;
3273 PLIST_ENTRY RegionListHead;
3274
3275 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
3276 BaseAddress);
3277 if (MemoryArea == NULL)
3278 {
3279 return(STATUS_UNSUCCESSFUL);
3280 }
3281
3282 MemoryArea->DeleteInProgress = TRUE;
3283 Section = MemoryArea->Data.SectionData.Section;
3284 Segment = MemoryArea->Data.SectionData.Segment;
3285
3286 MmLockSectionSegment(Segment);
3287 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
3288 RemoveEntryList(&MemoryArea->Data.SectionData.ViewListEntry);
3289 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
3290
3291 RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
3292 while (!IsListEmpty(RegionListHead))
3293 {
3294 CurrentEntry = RemoveHeadList(RegionListHead);
3295 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
3296 ExFreePool(CurrentRegion);
3297 }
3298
3299 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
3300 {
3301 Status = MmFreeMemoryArea(AddressSpace,
3302 BaseAddress,
3303 0,
3304 NULL,
3305 NULL);
3306 }
3307 else
3308 {
3309 Status = MmFreeMemoryArea(AddressSpace,
3310 BaseAddress,
3311 0,
3312 MmFreeSectionPage,
3313 MemoryArea);
3314 }
3315 MmUnlockSectionSegment(Segment);
3316 ObDereferenceObject(Section);
3317 return(STATUS_SUCCESS);
3318 }
3319
3320 /*
3321 * @implemented
3322 */
3323 NTSTATUS STDCALL
3324 MmUnmapViewOfSection(PEPROCESS Process,
3325 PVOID BaseAddress)
3326 {
3327 NTSTATUS Status;
3328 PMEMORY_AREA MemoryArea;
3329 PMADDRESS_SPACE AddressSpace;
3330 PSECTION_OBJECT Section;
3331
3332 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3333 Process, BaseAddress);
3334
3335 assert(Process);
3336
3337 AddressSpace = &Process->AddressSpace;
3338 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
3339 BaseAddress);
3340 if (MemoryArea == NULL)
3341 {
3342 return(STATUS_UNSUCCESSFUL);
3343 }
3344
3345 Section = MemoryArea->Data.SectionData.Section;
3346
3347 if (Section->AllocationAttributes & SEC_IMAGE)
3348 {
3349 ULONG i;
3350 ULONG NrSegments;
3351 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3352 PMM_SECTION_SEGMENT SectionSegments;
3353 PVOID ImageBaseAddress = 0;
3354 PMM_SECTION_SEGMENT Segment;
3355
3356 Segment = MemoryArea->Data.SectionData.Segment;
3357 ImageSectionObject = Section->ImageSection;
3358 SectionSegments = ImageSectionObject->Segments;
3359 NrSegments = ImageSectionObject->NrSegments;
3360
3361 /* Search for the current segment within the section segments
3362 * and calculate the image base address */
3363 for (i = 0; i < NrSegments; i++)
3364 {
3365 if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3366 {
3367 if (Segment == &SectionSegments[i])
3368 {
3369 ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress;
3370 break;
3371 }
3372 }
3373 }
3374 if (i >= NrSegments)
3375 {
3376 KEBUGCHECK(0);
3377 }
3378
3379 for (i = 0; i < NrSegments; i++)
3380 {
3381 if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3382 {
3383 PVOID SBaseAddress = (PVOID)
3384 ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
3385
3386 Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
3387 }
3388 }
3389 }
3390 else
3391 {
3392 Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
3393 }
3394 return(STATUS_SUCCESS);
3395 }
3396
3397 /**********************************************************************
3398 * NAME EXPORTED
3399 * NtUnmapViewOfSection
3400 *
3401 * DESCRIPTION
3402 *
3403 * ARGUMENTS
3404 * ProcessHandle
3405 *
3406 * BaseAddress
3407 *
3408 * RETURN VALUE
3409 * Status.
3410 *
3411 * REVISIONS
3412 */
3413 NTSTATUS STDCALL
3414 NtUnmapViewOfSection (HANDLE ProcessHandle,
3415 PVOID BaseAddress)
3416 {
3417 PEPROCESS Process;
3418 NTSTATUS Status;
3419
3420 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3421 ProcessHandle, BaseAddress);
3422
3423 DPRINT("Referencing process\n");
3424 Status = ObReferenceObjectByHandle(ProcessHandle,
3425 PROCESS_VM_OPERATION,
3426 PsProcessType,
3427 UserMode,
3428 (PVOID*)&Process,
3429 NULL);
3430 if (!NT_SUCCESS(Status))
3431 {
3432 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
3433 return(Status);
3434 }
3435
3436 MmLockAddressSpace(&Process->AddressSpace);
3437 Status = MmUnmapViewOfSection(Process, BaseAddress);
3438 MmUnlockAddressSpace(&Process->AddressSpace);
3439
3440 ObDereferenceObject(Process);
3441
3442 return Status;
3443 }
3444
3445
3446 NTSTATUS STDCALL
3447 NtQuerySection (IN HANDLE SectionHandle,
3448 IN CINT SectionInformationClass,
3449 OUT PVOID SectionInformation,
3450 IN ULONG Length,
3451 OUT PULONG ResultLength)
3452 /*
3453 * FUNCTION: Queries the information of a section object.
3454 * ARGUMENTS:
3455 * SectionHandle = Handle to the section link object
3456 * SectionInformationClass = Index to a certain information structure
3457 * SectionInformation (OUT)= Caller supplies storage for resulting
3458 * information
3459 * Length = Size of the supplied storage
3460 * ResultLength = Data written
3461 * RETURNS: Status
3462 *
3463 */
3464 {
3465 PSECTION_OBJECT Section;
3466 NTSTATUS Status;
3467
3468 Status = ObReferenceObjectByHandle(SectionHandle,
3469 SECTION_MAP_READ,
3470 MmSectionObjectType,
3471 UserMode,
3472 (PVOID*)&Section,
3473 NULL);
3474 if (!(NT_SUCCESS(Status)))
3475 {
3476 return(Status);
3477 }
3478
3479 switch (SectionInformationClass)
3480 {
3481 case SectionBasicInformation:
3482 {
3483 PSECTION_BASIC_INFORMATION Sbi;
3484
3485 if (Length != sizeof(SECTION_BASIC_INFORMATION))
3486 {
3487 ObDereferenceObject(Section);
3488 return(STATUS_INFO_LENGTH_MISMATCH);
3489 }
3490
3491 Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
3492
3493 Sbi->BaseAddress = 0;
3494 Sbi->Attributes = 0;
3495 Sbi->Size.QuadPart = 0;
3496
3497 *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
3498 Status = STATUS_SUCCESS;
3499 break;
3500 }
3501
3502 case SectionImageInformation:
3503 {
3504 PSECTION_IMAGE_INFORMATION Sii;
3505
3506 if (Length != sizeof(SECTION_IMAGE_INFORMATION))
3507 {
3508 ObDereferenceObject(Section);
3509 return(STATUS_INFO_LENGTH_MISMATCH);
3510 }
3511
3512 Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
3513 memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
3514 if (Section->AllocationAttributes & SEC_IMAGE)
3515 {
3516 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3517 ImageSectionObject = Section->ImageSection;
3518
3519 Sii->EntryPoint = ImageSectionObject->EntryPoint;
3520 Sii->StackReserve = ImageSectionObject->StackReserve;
3521 Sii->StackCommit = ImageSectionObject->StackCommit;
3522 Sii->Subsystem = ImageSectionObject->Subsystem;
3523 Sii->MinorSubsystemVersion = (USHORT)ImageSectionObject->MinorSubsystemVersion;
3524 Sii->MajorSubsystemVersion = (USHORT)ImageSectionObject->MajorSubsystemVersion;
3525 Sii->Characteristics = ImageSectionObject->ImageCharacteristics;
3526 Sii->ImageNumber = ImageSectionObject->Machine;
3527 Sii->Executable = ImageSectionObject->Executable;
3528 }
3529 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
3530 Status = STATUS_SUCCESS;
3531 break;
3532 }
3533
3534 default:
3535 *ResultLength = 0;
3536 Status = STATUS_INVALID_INFO_CLASS;
3537 }
3538 ObDereferenceObject(Section);
3539 return(Status);
3540 }
3541
3542
3543 NTSTATUS STDCALL
3544 NtExtendSection(IN HANDLE SectionHandle,
3545 IN ULONG NewMaximumSize)
3546 {
3547 UNIMPLEMENTED;
3548 return(STATUS_NOT_IMPLEMENTED);
3549 }
3550
3551
3552 /**********************************************************************
3553 * NAME INTERNAL
3554 * MmAllocateSection@4
3555 *
3556 * DESCRIPTION
3557 *
3558 * ARGUMENTS
3559 * Length
3560 *
3561 * RETURN VALUE
3562 *
3563 * NOTE
3564 * Code taken from ntoskrnl/mm/special.c.
3565 *
3566 * REVISIONS
3567 */
3568 PVOID STDCALL
3569 MmAllocateSection (IN ULONG Length)
3570 {
3571 PVOID Result;
3572 MEMORY_AREA* marea;
3573 NTSTATUS Status;
3574 ULONG i;
3575 PMADDRESS_SPACE AddressSpace;
3576 PHYSICAL_ADDRESS BoundaryAddressMultiple;
3577
3578 DPRINT("MmAllocateSection(Length %x)\n",Length);
3579
3580 BoundaryAddressMultiple.QuadPart = 0;
3581
3582 AddressSpace = MmGetKernelAddressSpace();
3583 Result = NULL;
3584 MmLockAddressSpace(AddressSpace);
3585 Status = MmCreateMemoryArea (NULL,
3586 AddressSpace,
3587 MEMORY_AREA_SYSTEM,
3588 &Result,
3589 Length,
3590 0,
3591 &marea,
3592 FALSE,
3593 FALSE,
3594 BoundaryAddressMultiple);
3595 MmUnlockAddressSpace(AddressSpace);
3596
3597 if (!NT_SUCCESS(Status))
3598 {
3599 return (NULL);
3600 }
3601 DPRINT("Result %p\n",Result);
3602 for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
3603 {
3604 PFN_TYPE Page;
3605
3606 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page);
3607 if (!NT_SUCCESS(Status))
3608 {
3609 DbgPrint("Unable to allocate page\n");
3610 KEBUGCHECK(0);
3611 }
3612 Status = MmCreateVirtualMapping (NULL,
3613 ((char*)Result + (i * PAGE_SIZE)),
3614 PAGE_READWRITE,
3615 &Page,
3616 1);
3617 if (!NT_SUCCESS(Status))
3618 {
3619 DbgPrint("Unable to create virtual mapping\n");
3620 KEBUGCHECK(0);
3621 }
3622 }
3623 return ((PVOID)Result);
3624 }
3625
3626
3627 /**********************************************************************
3628 * NAME EXPORTED
3629 * MmMapViewOfSection
3630 *
3631 * DESCRIPTION
3632 * Maps a view of a section into the virtual address space of a
3633 * process.
3634 *
3635 * ARGUMENTS
3636 * Section
3637 * Pointer to the section object.
3638 *
3639 * ProcessHandle
3640 * Pointer to the process.
3641 *
3642 * BaseAddress
3643 * Desired base address (or NULL) on entry;
3644 * Actual base address of the view on exit.
3645 *
3646 * ZeroBits
3647 * Number of high order address bits that must be zero.
3648 *
3649 * CommitSize
3650 * Size in bytes of the initially committed section of
3651 * the view.
3652 *
3653 * SectionOffset
3654 * Offset in bytes from the beginning of the section
3655 * to the beginning of the view.
3656 *
3657 * ViewSize
3658 * Desired length of map (or zero to map all) on entry
3659 * Actual length mapped on exit.
3660 *
3661 * InheritDisposition
3662 * Specified how the view is to be shared with
3663 * child processes.
3664 *
3665 * AllocationType
3666 * Type of allocation for the pages.
3667 *
3668 * Protect
3669 * Protection for the committed region of the view.
3670 *
3671 * RETURN VALUE
3672 * Status.
3673 *
3674 * @implemented
3675 */
3676 NTSTATUS STDCALL
3677 MmMapViewOfSection(IN PVOID SectionObject,
3678 IN PEPROCESS Process,
3679 IN OUT PVOID *BaseAddress,
3680 IN ULONG ZeroBits,
3681 IN ULONG CommitSize,
3682 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
3683 IN OUT PULONG ViewSize,
3684 IN SECTION_INHERIT InheritDisposition,
3685 IN ULONG AllocationType,
3686 IN ULONG Protect)
3687 {
3688 PSECTION_OBJECT Section;
3689 PMADDRESS_SPACE AddressSpace;
3690 ULONG ViewOffset;
3691 NTSTATUS Status = STATUS_SUCCESS;
3692
3693 assert(Process);
3694
3695 Section = (PSECTION_OBJECT)SectionObject;
3696 AddressSpace = &Process->AddressSpace;
3697
3698 MmLockAddressSpace(AddressSpace);
3699
3700 if (Section->AllocationAttributes & SEC_IMAGE)
3701 {
3702 ULONG i;
3703 ULONG NrSegments;
3704 PVOID ImageBase;
3705 ULONG ImageSize;
3706 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3707 PMM_SECTION_SEGMENT SectionSegments;
3708
3709 ImageSectionObject = Section->ImageSection;
3710 SectionSegments = ImageSectionObject->Segments;
3711 NrSegments = ImageSectionObject->NrSegments;
3712
3713
3714 ImageBase = *BaseAddress;
3715 if (ImageBase == NULL)
3716 {
3717 ImageBase = ImageSectionObject->ImageBase;
3718 }
3719
3720 ImageSize = 0;
3721 for (i = 0; i < NrSegments; i++)
3722 {
3723 if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3724 {
3725 ULONG MaxExtent;
3726 MaxExtent = (ULONG)((char*)SectionSegments[i].VirtualAddress +
3727 SectionSegments[i].Length);
3728 ImageSize = max(ImageSize, MaxExtent);
3729 }
3730 }
3731
3732 /* Check there is enough space to map the section at that point. */
3733 if (MmOpenMemoryAreaByRegion(AddressSpace, ImageBase,
3734 PAGE_ROUND_UP(ImageSize)) != NULL)
3735 {
3736 /* Fail if the user requested a fixed base address. */
3737 if ((*BaseAddress) != NULL)
3738 {
3739 MmUnlockAddressSpace(AddressSpace);
3740 return(STATUS_UNSUCCESSFUL);
3741 }
3742 /* Otherwise find a gap to map the image. */
3743 ImageBase = MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), FALSE);
3744 if (ImageBase == NULL)
3745 {
3746 MmUnlockAddressSpace(AddressSpace);
3747 return(STATUS_UNSUCCESSFUL);
3748 }
3749 }
3750
3751 for (i = 0; i < NrSegments; i++)
3752 {
3753 if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3754 {
3755 PVOID SBaseAddress = (PVOID)
3756 ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
3757 MmLockSectionSegment(&SectionSegments[i]);
3758 Status = MmMapViewOfSegment(Process,
3759 AddressSpace,
3760 Section,
3761 &SectionSegments[i],
3762 &SBaseAddress,
3763 SectionSegments[i].Length,
3764 SectionSegments[i].Protection,
3765 (ULONG_PTR)SectionSegments[i].VirtualAddress,
3766 FALSE);
3767 MmUnlockSectionSegment(&SectionSegments[i]);
3768 if (!NT_SUCCESS(Status))
3769 {
3770 MmUnlockAddressSpace(AddressSpace);
3771 return(Status);
3772 }
3773 }
3774 }
3775
3776 *BaseAddress = ImageBase;
3777 }
3778 else
3779 {
3780 if (ViewSize == NULL)
3781 {
3782 /* Following this pointer would lead to us to the dark side */
3783 /* What to do? Bugcheck? Return status? Do the mambo? */
3784 KEBUGCHECK(MEMORY_MANAGEMENT);
3785 }
3786
3787 if (SectionOffset == NULL)
3788 {
3789 ViewOffset = 0;
3790 }
3791 else
3792 {
3793 ViewOffset = SectionOffset->u.LowPart;
3794 }
3795
3796 if ((ViewOffset % PAGE_SIZE) != 0)
3797 {
3798 MmUnlockAddressSpace(AddressSpace);
3799 return(STATUS_MAPPED_ALIGNMENT);
3800 }
3801
3802 if ((*ViewSize) == 0)
3803 {
3804 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3805 }
3806 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
3807 {
3808 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3809 }
3810
3811 MmLockSectionSegment(Section->Segment);
3812 Status = MmMapViewOfSegment(Process,
3813 AddressSpace,
3814 Section,
3815 Section->Segment,
3816 BaseAddress,
3817 *ViewSize,
3818 Protect,
3819 ViewOffset,
3820 (AllocationType & MEM_TOP_DOWN));
3821 MmUnlockSectionSegment(Section->Segment);
3822 if (!NT_SUCCESS(Status))
3823 {
3824 MmUnlockAddressSpace(AddressSpace);
3825 return(Status);
3826 }
3827 }
3828
3829 MmUnlockAddressSpace(AddressSpace);
3830
3831 return(STATUS_SUCCESS);
3832 }
3833
3834 /*
3835 * @unimplemented
3836 */
3837 BOOLEAN STDCALL
3838 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
3839 IN PLARGE_INTEGER NewFileSize)
3840 {
3841 UNIMPLEMENTED;
3842 return (FALSE);
3843 }
3844
3845
3846 /*
3847 * @unimplemented
3848 */
3849 BOOLEAN STDCALL
3850 MmDisableModifiedWriteOfSection (DWORD Unknown0)
3851 {
3852 UNIMPLEMENTED;
3853 return (FALSE);
3854 }
3855
3856 /*
3857 * @implemented
3858 */
3859 BOOLEAN STDCALL
3860 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
3861 IN MMFLUSH_TYPE FlushType)
3862 {
3863 switch(FlushType)
3864 {
3865 case MmFlushForDelete:
3866 if (SectionObjectPointer->ImageSectionObject ||
3867 SectionObjectPointer->DataSectionObject)
3868 {
3869 return FALSE;
3870 }
3871 CcRosSetRemoveOnClose(SectionObjectPointer);
3872 return TRUE;
3873 case MmFlushForWrite:
3874 break;
3875 }
3876 return FALSE;
3877 }
3878
3879 /*
3880 * @unimplemented
3881 */
3882 BOOLEAN STDCALL
3883 MmForceSectionClosed (DWORD Unknown0,
3884 DWORD Unknown1)
3885 {
3886 UNIMPLEMENTED;
3887 return (FALSE);
3888 }
3889
3890
3891 /*
3892 * @implemented
3893 */
3894 NTSTATUS STDCALL
3895 MmMapViewInSystemSpace (IN PVOID SectionObject,
3896 OUT PVOID * MappedBase,
3897 IN OUT PULONG ViewSize)
3898 {
3899 PSECTION_OBJECT Section;
3900 PMADDRESS_SPACE AddressSpace;
3901 NTSTATUS Status;
3902
3903 DPRINT("MmMapViewInSystemSpace() called\n");
3904
3905 Section = (PSECTION_OBJECT)SectionObject;
3906 AddressSpace = MmGetKernelAddressSpace();
3907
3908 MmLockAddressSpace(AddressSpace);
3909
3910
3911 if ((*ViewSize) == 0)
3912 {
3913 (*ViewSize) = Section->MaximumSize.u.LowPart;
3914 }
3915 else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
3916 {
3917 (*ViewSize) = Section->MaximumSize.u.LowPart;
3918 }
3919
3920 MmLockSectionSegment(Section->Segment);
3921
3922
3923 Status = MmMapViewOfSegment(NULL,
3924 AddressSpace,
3925 Section,
3926 Section->Segment,
3927 MappedBase,
3928 *ViewSize,
3929 PAGE_READWRITE,
3930 0,
3931 FALSE);
3932
3933 MmUnlockSectionSegment(Section->Segment);
3934 MmUnlockAddressSpace(AddressSpace);
3935
3936 return Status;
3937 }
3938
3939 /*
3940 * @unimplemented
3941 */
3942 NTSTATUS
3943 STDCALL
3944 MmMapViewInSessionSpace (
3945 IN PVOID Section,
3946 OUT PVOID *MappedBase,
3947 IN OUT PSIZE_T ViewSize
3948 )
3949 {
3950 UNIMPLEMENTED;
3951 return STATUS_NOT_IMPLEMENTED;
3952 }
3953
3954
3955 /*
3956 * @implemented
3957 */
3958 NTSTATUS STDCALL
3959 MmUnmapViewInSystemSpace (IN PVOID MappedBase)
3960 {
3961 PMADDRESS_SPACE AddressSpace;
3962 NTSTATUS Status;
3963
3964 DPRINT("MmUnmapViewInSystemSpace() called\n");
3965
3966 AddressSpace = MmGetKernelAddressSpace();
3967
3968 Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
3969
3970 return Status;
3971 }
3972
3973 /*
3974 * @unimplemented
3975 */
3976 NTSTATUS
3977 STDCALL
3978 MmUnmapViewInSessionSpace (
3979 IN PVOID MappedBase
3980 )
3981 {
3982 UNIMPLEMENTED;
3983 return STATUS_NOT_IMPLEMENTED;
3984 }
3985
3986 /*
3987 * @unimplemented
3988 */
3989 NTSTATUS STDCALL
3990 MmSetBankedSection (DWORD Unknown0,
3991 DWORD Unknown1,
3992 DWORD Unknown2,
3993 DWORD Unknown3,
3994 DWORD Unknown4,
3995 DWORD Unknown5)
3996 {
3997 UNIMPLEMENTED;
3998 return (STATUS_NOT_IMPLEMENTED);
3999 }
4000
4001
4002 /**********************************************************************
4003 * NAME EXPORTED
4004 * MmCreateSection@
4005 *
4006 * DESCRIPTION
4007 * Creates a section object.
4008 *
4009 * ARGUMENTS
4010 * SectionObject (OUT)
4011 * Caller supplied storage for the resulting pointer
4012 * to a SECTION_OBJECT instance;
4013 *
4014 * DesiredAccess
4015 * Specifies the desired access to the section can be a
4016 * combination of:
4017 * STANDARD_RIGHTS_REQUIRED |
4018 * SECTION_QUERY |
4019 * SECTION_MAP_WRITE |
4020 * SECTION_MAP_READ |
4021 * SECTION_MAP_EXECUTE
4022 *
4023 * ObjectAttributes [OPTIONAL]
4024 * Initialized attributes for the object can be used
4025 * to create a named section;
4026 *
4027 * MaximumSize
4028 * Maximizes the size of the memory section. Must be
4029 * non-NULL for a page-file backed section.
4030 * If value specified for a mapped file and the file is
4031 * not large enough, file will be extended.
4032 *
4033 * SectionPageProtection
4034 * Can be a combination of:
4035 * PAGE_READONLY |
4036 * PAGE_READWRITE |
4037 * PAGE_WRITEONLY |
4038 * PAGE_WRITECOPY
4039 *
4040 * AllocationAttributes
4041 * Can be a combination of:
4042 * SEC_IMAGE |
4043 * SEC_RESERVE
4044 *
4045 * FileHandle
4046 * Handle to a file to create a section mapped to a file
4047 * instead of a memory backed section;
4048 *
4049 * File
4050 * Unknown.
4051 *
4052 * RETURN VALUE
4053 * Status.
4054 *
4055 * @implemented
4056 */
4057 NTSTATUS STDCALL
4058 MmCreateSection (OUT PSECTION_OBJECT * SectionObject,
4059 IN ACCESS_MASK DesiredAccess,
4060 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
4061 IN PLARGE_INTEGER MaximumSize,
4062 IN ULONG SectionPageProtection,
4063 IN ULONG AllocationAttributes,
4064 IN HANDLE FileHandle OPTIONAL,
4065 IN PFILE_OBJECT File OPTIONAL)
4066 {
4067 if (AllocationAttributes & SEC_IMAGE)
4068 {
4069 return(MmCreateImageSection(SectionObject,
4070 DesiredAccess,
4071 ObjectAttributes,
4072 MaximumSize,
4073 SectionPageProtection,
4074 AllocationAttributes,
4075 FileHandle));
4076 }
4077
4078 if (FileHandle != NULL)
4079 {
4080 return(MmCreateDataFileSection(SectionObject,
4081 DesiredAccess,
4082 ObjectAttributes,
4083 MaximumSize,
4084 SectionPageProtection,
4085 AllocationAttributes,
4086 FileHandle));
4087 }
4088
4089 return(MmCreatePageFileSection(SectionObject,
4090 DesiredAccess,
4091 ObjectAttributes,
4092 MaximumSize,
4093 SectionPageProtection,
4094 AllocationAttributes));
4095 }
4096
4097 /* EOF */