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