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