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