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