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